extension_test_message_listener.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. #ifndef EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_
  5. #define EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_
  6. #include <string>
  7. #include "base/callback.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/memory/ref_counted.h"
  10. #include "base/scoped_observation.h"
  11. #include "extensions/browser/api/test/test_api_observer.h"
  12. #include "extensions/browser/api/test/test_api_observer_registry.h"
  13. #include "extensions/common/extension_id.h"
  14. #include "third_party/abseil-cpp/absl/types/optional.h"
  15. namespace content {
  16. class BrowserContext;
  17. }
  18. namespace extensions {
  19. class TestSendMessageFunction;
  20. }
  21. // This class helps us wait for incoming messages sent from javascript via
  22. // chrome.test.sendMessage(). A sample usage would be:
  23. //
  24. // ExtensionTestMessageListener listener("foo");
  25. // ... do some work
  26. // ASSERT_TRUE(listener.WaitUntilSatisfied());
  27. //
  28. // It is also possible to have the extension wait for our reply. This is
  29. // useful for coordinating multiple pages/processes and having them wait on
  30. // each other. Example:
  31. //
  32. // ExtensionTestMessageListener listener1("foo1", ReplyBehavior::kWillReply);
  33. // ExtensionTestMessageListener listener2("foo2", ReplyBehavior::kWillReply);
  34. // ASSERT_TRUE(listener1.WaitUntilSatisfied());
  35. // ASSERT_TRUE(listener2.WaitUntilSatisfied());
  36. // ... do some work
  37. // listener1.Reply("foo2 is ready");
  38. // listener2.Reply("foo1 is ready");
  39. //
  40. // Further, we can use this to listen for a success and failure message:
  41. //
  42. // ExtensionTestMessageListener listener("success", will_reply);
  43. // listener.set_failure_message("failure");
  44. // ASSERT_TRUE(listener.WaitUntilSatisfied());
  45. // if (listener.message() == "success") {
  46. // HandleSuccess();
  47. // } else {
  48. // ASSERT_EQ("failure", listener.message());
  49. // HandleFailure();
  50. // }
  51. //
  52. // Or, use it to listen to any arbitrary message:
  53. //
  54. // ExtensionTestMessageListener listener(will_reply);
  55. // ASSERT_TRUE(listener.WaitUntilSatisfied());
  56. // if (listener.message() == "foo")
  57. // HandleFoo();
  58. // else if (listener.message() == "bar")
  59. // HandleBar();
  60. // else if (listener.message() == "baz")
  61. // HandleBaz();
  62. // else
  63. // NOTREACHED();
  64. //
  65. // You can also use the class to listen for messages from a specified extension:
  66. //
  67. // ExtensionTestMessageListener listener(will_reply);
  68. // listener.set_extension_id(extension->id());
  69. // ASSERT_TRUE(listener.WaitUntilSatisfied());
  70. // ... do some work.
  71. //
  72. // A callback can be set to react to a message from an extension, instead of
  73. // manually waiting.
  74. //
  75. // ExtensionTestMessageListener listener("do_something");
  76. // listener.SetOnSatisfied(base::BindOnce(&DoSomething));
  77. // ... run test
  78. // // SetOnRepeatedlySatisfied could be used if the message is expected
  79. // // multiple times.
  80. //
  81. // Finally, you can reset the listener to reuse it.
  82. //
  83. // ExtensionTestMessageListener listener(ReplyBehavior::kWillReply);
  84. // ASSERT_TRUE(listener.WaitUntilSatisfied());
  85. // while (listener.message() != "end") {
  86. // Handle(listener.message());
  87. // listener.Reply("bar");
  88. // listener.Reset();
  89. // ASSERT_TRUE(listener.WaitUntilSatisfied());
  90. // }
  91. //
  92. // Note that when using it in browser tests, you need to make sure it gets
  93. // destructed *before* the browser gets torn down. Two common patterns are to
  94. // either make it a local variable inside your test body, or if it's a member
  95. // variable of a ExtensionBrowserTest subclass, override the
  96. // BrowserTestBase::TearDownOnMainThread() method and clean it up there.
  97. // The behavior specifying whether the listener will reply to the
  98. // incoming message. This is defined outside the class simply to save authors
  99. // from typing out ReplyBehavior::kWillReply.
  100. enum class ReplyBehavior {
  101. // The listener will reply. The extension API callback will not be
  102. // triggered until `ExtensionTestMessageListener::Reply()` is called.
  103. kWillReply,
  104. // The listener won't reply with a custom message. The extension API
  105. // callback is triggered automatically.
  106. kWontReply,
  107. };
  108. class ExtensionTestMessageListener : public extensions::TestApiObserver {
  109. public:
  110. // Listen for the `expected_message` with the specified `reply_behavior`.
  111. // TODO(devlin): Possibly update this to just take a StringPiece, once the
  112. // enum conversions highlighted below are done?
  113. explicit ExtensionTestMessageListener(
  114. const std::string& expected_message,
  115. ReplyBehavior reply_behavior = ReplyBehavior::kWontReply);
  116. // Construct a message listener which will listen for any message with
  117. // the specified `reply_behavior`.
  118. explicit ExtensionTestMessageListener(
  119. ReplyBehavior reply_behavior = ReplyBehavior::kWontReply);
  120. ~ExtensionTestMessageListener() override;
  121. // This returns true immediately if we've already gotten the expected
  122. // message, or waits until it arrives. Once this returns true, message() and
  123. // extension_id_for_message() accessors can be used.
  124. // Returns false if the wait is interrupted and we still haven't gotten the
  125. // message, or if the message was equal to |failure_message_|.
  126. [[nodiscard]] bool WaitUntilSatisfied();
  127. // Send the given message as a reply. It is only valid to call this after
  128. // WaitUntilSatisfied has returned true, and if will_reply is true.
  129. void Reply(const std::string& message);
  130. // Convenience method that formats int as a string and sends it.
  131. void Reply(int message);
  132. void ReplyWithError(const std::string& error);
  133. // Reset the listener to listen again. No settings (such as messages to
  134. // listen for) are modified.
  135. void Reset();
  136. // Getters and setters.
  137. bool was_satisfied() const { return satisfied_; }
  138. void set_failure_message(const std::string& failure_message) {
  139. failure_message_ = failure_message;
  140. }
  141. using OnSatisfiedSignature = void(const std::string&);
  142. void SetOnSatisfied(base::OnceCallback<OnSatisfiedSignature> on_satisfied) {
  143. on_satisfied_ = std::move(on_satisfied);
  144. }
  145. void SetOnRepeatedlySatisfied(
  146. base::RepeatingCallback<OnSatisfiedSignature> on_repeatedly_satisfied) {
  147. on_repeatedly_satisfied_ = on_repeatedly_satisfied;
  148. }
  149. void set_extension_id(const std::string& extension_id) {
  150. extension_id_ = extension_id;
  151. }
  152. void set_browser_context(const content::BrowserContext* browser_context) {
  153. browser_context_ = browser_context;
  154. }
  155. const std::string& message() const { return message_; }
  156. const extensions::ExtensionId& extension_id_for_message() const {
  157. return extension_id_for_message_;
  158. }
  159. bool had_user_gesture() const { return had_user_gesture_; }
  160. private:
  161. // extensions::TestApiObserver:
  162. bool OnTestMessage(extensions::TestSendMessageFunction* function,
  163. const std::string& message) override;
  164. // The message we're expecting. If empty, we will wait for any message,
  165. // regardless of contents.
  166. const absl::optional<std::string> expected_message_;
  167. // The last message we received.
  168. std::string message_;
  169. // Whether we've seen expected_message_ yet.
  170. bool satisfied_ = false;
  171. // Holds the quit Closure for the RunLoop during WaitUntilSatisfied().
  172. base::OnceClosure quit_wait_closure_;
  173. // Notifies when the expected message is received.
  174. base::OnceCallback<OnSatisfiedSignature> on_satisfied_;
  175. base::RepeatingCallback<OnSatisfiedSignature> on_repeatedly_satisfied_;
  176. // Whether the listener will send an explicit reply via `Reply()`.
  177. const ReplyBehavior reply_behavior_;
  178. // The extension id that we listen for, or empty.
  179. std::string extension_id_;
  180. // If non-null, we listen to messages only from this BrowserContext.
  181. raw_ptr<const content::BrowserContext> browser_context_ = nullptr;
  182. // The message that signals failure.
  183. absl::optional<std::string> failure_message_;
  184. // If we received a message that was the failure message.
  185. bool failed_ = false;
  186. // The extension id from which |message_| was received.
  187. extensions::ExtensionId extension_id_for_message_;
  188. // Whether the ExtensionFunction handling the message had an active user
  189. // gesture.
  190. bool had_user_gesture_ = false;
  191. // The function we need to reply to.
  192. scoped_refptr<extensions::TestSendMessageFunction> function_;
  193. base::ScopedObservation<extensions::TestApiObserverRegistry,
  194. extensions::TestApiObserver>
  195. test_api_observation_{this};
  196. };
  197. #endif // EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_