1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_ 6#define EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_ 7 8#include <string> 9 10#include "base/compiler_specific.h" 11#include "base/memory/ref_counted.h" 12#include "content/public/browser/notification_observer.h" 13#include "content/public/browser/notification_registrar.h" 14 15namespace extensions { 16class TestSendMessageFunction; 17} 18 19// This class helps us wait for incoming messages sent from javascript via 20// chrome.test.sendMessage(). A sample usage would be: 21// 22// ExtensionTestMessageListener listener("foo", false); // won't reply 23// ... do some work 24// ASSERT_TRUE(listener.WaitUntilSatisfied()); 25// 26// It is also possible to have the extension wait for our reply. This is 27// useful for coordinating multiple pages/processes and having them wait on 28// each other. Example: 29// 30// ExtensionTestMessageListener listener1("foo1", true); // will reply 31// ExtensionTestMessageListener listener2("foo2", true); // will reply 32// ASSERT_TRUE(listener1.WaitUntilSatisfied()); 33// ASSERT_TRUE(listener2.WaitUntilSatisfied()); 34// ... do some work 35// listener1.Reply("foo2 is ready"); 36// listener2.Reply("foo1 is ready"); 37// 38// Further, we can use this to listen for a success and failure message: 39// 40// ExtensionTestMessageListener listener("success", will_reply); 41// listener.set_failure_message("failure"); 42// ASSERT_TRUE(listener.WaitUntilSatisfied()); 43// if (listener.message() == "success") { 44// HandleSuccess(); 45// } else { 46// ASSERT_EQ("failure", listener.message()); 47// HandleFailure(); 48// } 49// 50// Or, use it to listen to any arbitrary message: 51// 52// ExtensionTestMessageListener listener(will_reply); 53// ASSERT_TRUE(listener.WaitUntilSatisfied()); 54// if (listener.message() == "foo") 55// HandleFoo(); 56// else if (listener.message() == "bar") 57// HandleBar(); 58// else if (listener.message() == "baz") 59// HandleBaz(); 60// else 61// NOTREACHED(); 62// 63// You can also use the class to listen for messages from a specified extension: 64// 65// ExtensionTestMessageListener listener(will_reply); 66// listener.set_extension_id(extension->id()); 67// ASSERT_TRUE(listener.WaitUntilSatisfied()); 68// ... do some work. 69// 70// Finally, you can reset the listener to reuse it. 71// 72// ExtensionTestMessageListener listener(true); // will reply 73// ASSERT_TRUE(listener.WaitUntilSatisfied()); 74// while (listener.message() != "end") { 75// Handle(listener.message()); 76// listener.Reply("bar"); 77// listener.Reset(); 78// ASSERT_TRUE(listener.WaitUntilSatisfied()); 79// } 80// 81// Note that when using it in browser tests, you need to make sure it gets 82// destructed *before* the browser gets torn down. Two common patterns are to 83// either make it a local variable inside your test body, or if it's a member 84// variable of a ExtensionBrowserTest subclass, override the 85// BrowserTestBase::TearDownOnMainThread() method and clean it up there. 86class ExtensionTestMessageListener : public content::NotificationObserver { 87 public: 88 // We immediately start listening for |expected_message|. 89 ExtensionTestMessageListener(const std::string& expected_message, 90 bool will_reply); 91 // Construct a message listener which will listen for any message. 92 explicit ExtensionTestMessageListener(bool will_reply); 93 94 virtual ~ExtensionTestMessageListener(); 95 96 // This returns true immediately if we've already gotten the expected 97 // message, or waits until it arrives. 98 // Returns false if the wait is interrupted and we still haven't gotten the 99 // message, or if the message was equal to |failure_message_|. 100 bool WaitUntilSatisfied(); 101 102 // Send the given message as a reply. It is only valid to call this after 103 // WaitUntilSatisfied has returned true, and if will_reply is true. 104 void Reply(const std::string& message); 105 106 // Convenience method that formats int as a string and sends it. 107 void Reply(int message); 108 109 void ReplyWithError(const std::string& error); 110 111 // Reset the listener to listen again. No settings (such as messages to 112 // listen for) are modified. 113 void Reset(); 114 115 // Getters and setters. 116 117 bool was_satisfied() const { return satisfied_; } 118 119 void set_failure_message(const std::string& failure_message) { 120 failure_message_ = failure_message; 121 } 122 123 const std::string& extension_id() const { return extension_id_; } 124 void set_extension_id(const std::string& extension_id) { 125 extension_id_ = extension_id; 126 } 127 128 const std::string& message() const { return message_; } 129 130 private: 131 // Implements the content::NotificationObserver interface. 132 virtual void Observe(int type, 133 const content::NotificationSource& source, 134 const content::NotificationDetails& details) OVERRIDE; 135 136 content::NotificationRegistrar registrar_; 137 138 // The message we're expecting. 139 std::string expected_message_; 140 141 // The last message we received. 142 std::string message_; 143 144 // Whether we've seen expected_message_ yet. 145 bool satisfied_; 146 147 // If we're waiting, then we want to post a quit task when the expected 148 // message arrives. 149 bool waiting_; 150 151 // Whether or not we will wait for any message, regardless of contents. 152 bool wait_for_any_message_; 153 154 // If true, we expect the calling code to manually send a reply. Otherwise, 155 // we send an automatic empty reply to the extension. 156 bool will_reply_; 157 158 // Whether or not we have already replied (we can only reply once). 159 bool replied_; 160 161 // The extension id that we listen for, or empty. 162 std::string extension_id_; 163 164 // The message that signals failure. 165 std::string failure_message_; 166 167 // If we received a message that was the failure message. 168 bool failed_; 169 170 // The function we need to reply to. 171 scoped_refptr<extensions::TestSendMessageFunction> function_; 172}; 173 174#endif // EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_ 175