1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
// 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 EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_
#define EXTENSIONS_TEST_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
// BrowserTestBase::TearDownOnMainThread() 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);
~ExtensionTestMessageListener() override;
// 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);
void ReplyWithError(const std::string& error);
// 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.
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 // EXTENSIONS_TEST_EXTENSION_TEST_MESSAGE_LISTENER_H_
|