// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_MESSAGE_LISTENER_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_MESSAGE_LISTENER_H_ #include <string> #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" namespace extensions { class TestSendMessageFunction; } // This class helps us wait for incoming messages sent from javascript via // chrome.test.sendMessage(). A sample usage would be: // // ExtensionTestMessageListener listener("foo", false); // won't reply // ... do some work // ASSERT_TRUE(listener.WaitUntilSatisfied()); // // It is also possible to have the extension wait for our reply. This is // useful for coordinating multiple pages/processes and having them wait on // each other. Example: // // ExtensionTestMessageListener listener1("foo1", true); // will reply // ExtensionTestMessageListener listener2("foo2", true); // will reply // ASSERT_TRUE(listener1.WaitUntilSatisfied()); // ASSERT_TRUE(listener2.WaitUntilSatisfied()); // ... do some work // listener1.Reply("foo2 is ready"); // listener2.Reply("foo1 is ready"); // // Further, we can use this to listen for a success and failure message: // // ExtensionTestMessageListener listener("success", will_reply); // listener.set_failure_message("failure"); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // if (listener.message() == "success") { // HandleSuccess(); // } else { // ASSERT_EQ("failure", listener.message()); // HandleFailure(); // } // // Or, use it to listen to any arbitrary message: // // ExtensionTestMessageListener listener(will_reply); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // if (listener.message() == "foo") // HandleFoo(); // else if (listener.message() == "bar") // HandleBar(); // else if (listener.message() == "baz") // HandleBaz(); // else // NOTREACHED(); // // You can also use the class to listen for messages from a specified extension: // // ExtensionTestMessageListener listener(will_reply); // listener.set_extension_id(extension->id()); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // ... do some work. // // Finally, you can reset the listener to reuse it. // // ExtensionTestMessageListener listener(true); // will reply // ASSERT_TRUE(listener.WaitUntilSatisfied()); // while (listener.message() != "end") { // Handle(listener.message()); // listener.Reply("bar"); // listener.Reset(); // ASSERT_TRUE(listener.WaitUntilSatisfied()); // } // // Note that when using it in browser tests, you need to make sure it gets // destructed *before* the browser gets torn down. Two common patterns are to // either make it a local variable inside your test body, or if it's a member // variable of a ExtensionBrowserTest subclass, override the // InProcessBrowserTest::CleanUpOnMainThread() method and clean it up there. class ExtensionTestMessageListener : public content::NotificationObserver { public: // We immediately start listening for |expected_message|. ExtensionTestMessageListener(const std::string& expected_message, bool will_reply); // Construct a message listener which will listen for any message. explicit ExtensionTestMessageListener(bool will_reply); virtual ~ExtensionTestMessageListener(); // This returns true immediately if we've already gotten the expected // message, or waits until it arrives. // Returns false if the wait is interrupted and we still haven't gotten the // message, or if the message was equal to |failure_message_|. bool WaitUntilSatisfied(); // Send the given message as a reply. It is only valid to call this after // WaitUntilSatisfied has returned true, and if will_reply is true. void Reply(const std::string& message); // Convenience method that formats int as a string and sends it. void Reply(int message); // Reset the listener to listen again. No settings (such as messages to // listen for) are modified. void Reset(); // Getters and setters. bool was_satisfied() const { return satisfied_; } void set_failure_message(const std::string& failure_message) { failure_message_ = failure_message; } const std::string& extension_id() const { return extension_id_; } void set_extension_id(const std::string& extension_id) { extension_id_ = extension_id; } const std::string& message() const { return message_; } private: // Implements the content::NotificationObserver interface. virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; content::NotificationRegistrar registrar_; // The message we're expecting. std::string expected_message_; // The last message we received. std::string message_; // Whether we've seen expected_message_ yet. bool satisfied_; // If we're waiting, then we want to post a quit task when the expected // message arrives. bool waiting_; // Whether or not we will wait for any message, regardless of contents. bool wait_for_any_message_; // If true, we expect the calling code to manually send a reply. Otherwise, // we send an automatic empty reply to the extension. bool will_reply_; // Whether or not we have already replied (we can only reply once). bool replied_; // The extension id that we listen for, or empty. std::string extension_id_; // The message that signals failure. std::string failure_message_; // If we received a message that was the failure message. bool failed_; // The function we need to reply to. scoped_refptr<extensions::TestSendMessageFunction> function_; }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_MESSAGE_LISTENER_H_