Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(544)

Side by Side Diff: chrome/browser/extensions/extension_uitest.cc

Issue 468013: Get rid of ExternalTabAutomationProxy by switching the extension UI... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/test/automation/automation_proxy_uitest.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/command_line.h" 5 #include "base/command_line.h"
6 #include "base/gfx/rect.h" 6 #include "base/gfx/rect.h"
7 #include "base/json/json_reader.h" 7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h" 8 #include "base/json/json_writer.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "chrome/browser/automation/extension_automation_constants.h" 10 #include "chrome/browser/automation/extension_automation_constants.h"
11 #include "chrome/browser/extensions/extension_tabs_module_constants.h" 11 #include "chrome/browser/extensions/extension_tabs_module_constants.h"
12 #include "chrome/common/chrome_switches.h" 12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/extensions/extension.h" 13 #include "chrome/common/extensions/extension.h"
14 #include "chrome/test/automation/automation_messages.h" 14 #include "chrome/test/automation/automation_messages.h"
15 #include "chrome/test/automation/automation_proxy_uitest.h" 15 #include "chrome/test/automation/automation_proxy_uitest.h"
16 #include "chrome/test/automation/tab_proxy.h" 16 #include "chrome/test/automation/tab_proxy.h"
17 #include "chrome/test/ui/ui_test.h" 17 #include "chrome/test/ui/ui_test.h"
18 #include "chrome/test/ui_test_utils.h"
18 #include "googleurl/src/gurl.h" 19 #include "googleurl/src/gurl.h"
20 #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
21 #include "testing/gmock_mutant.h"
19 22
20 namespace { 23 namespace {
21 24
25 using testing::_;
26 using testing::CreateFunctor;
27 using testing::DoAll;
28 using testing::Invoke;
29 using testing::InvokeWithoutArgs;
30 using testing::SaveArg;
31 using testing::WithArgs;
32
33 using ui_test_utils::TimedMessageLoopRunner;
34
22 static const char kTestDirectorySimpleApiCall[] = 35 static const char kTestDirectorySimpleApiCall[] =
23 "extensions/uitest/simple_api_call"; 36 "extensions/uitest/simple_api_call";
24 static const char kTestDirectoryRoundtripApiCall[] = 37 static const char kTestDirectoryRoundtripApiCall[] =
25 "extensions/uitest/roundtrip_api_call"; 38 "extensions/uitest/roundtrip_api_call";
26 static const char kTestDirectoryBrowserEvent[] = 39 static const char kTestDirectoryBrowserEvent[] =
27 "extensions/uitest/event_sink"; 40 "extensions/uitest/event_sink";
28 41
42 // TODO(port) Once external tab stuff is ported.
43 #if defined(OS_WIN)
44
29 // Base class to test extensions almost end-to-end by including browser 45 // Base class to test extensions almost end-to-end by including browser
30 // startup, manifest parsing, and the actual process model in the 46 // startup, manifest parsing, and the actual process model in the
31 // equation. This would also let you write UITests that test individual 47 // equation. This would also let you write UITests that test individual
32 // Chrome Extensions as running in Chrome. Takes over implementation of 48 // Chrome Extensions as running in Chrome. Takes over implementation of
33 // extension API calls so that behavior can be tested deterministically 49 // extension API calls so that behavior can be tested deterministically
34 // through code, instead of having to contort the browser into a state 50 // through code, instead of having to contort the browser into a state
35 // suitable for testing. 51 // suitable for testing.
36 // 52 //
37 // By default, makes Chrome forward all Chrome Extension API function calls 53 // By default, makes Chrome forward all Chrome Extension API function calls
38 // via the automation interface. To override this, call set_functions_enabled() 54 // via the automation interface. To override this, call set_functions_enabled()
39 // with a list of function names that should be forwarded, 55 // with a list of function names that should be forwarded,
40 template <class ParentTestType> 56 class ExtensionUITest : public ExternalTabUITest {
41 class ExtensionUITest : public ParentTestType {
42 public: 57 public:
43 explicit ExtensionUITest(const std::string& extension_path) { 58 explicit ExtensionUITest(const std::string& extension_path)
59 : loop_(MessageLoop::current()) {
44 FilePath filename(test_data_directory_); 60 FilePath filename(test_data_directory_);
45 filename = filename.AppendASCII(extension_path); 61 filename = filename.AppendASCII(extension_path);
46 launch_arguments_.AppendSwitchWithValue(switches::kLoadExtension, 62 launch_arguments_.AppendSwitchWithValue(switches::kLoadExtension,
47 filename.value()); 63 filename.value());
48 functions_enabled_.push_back("*"); 64 functions_enabled_.push_back("*");
49 } 65 }
50 66
51 void set_functions_enabled( 67 void set_functions_enabled(
52 const std::vector<std::string>& functions_enabled) { 68 const std::vector<std::string>& functions_enabled) {
53 functions_enabled_ = functions_enabled; 69 functions_enabled_ = functions_enabled;
54 } 70 }
55 71
56 void SetUp() { 72 void SetUp() {
57 ParentTestType::SetUp(); 73 ExternalTabUITest::SetUp();
58 74 tab_ = mock_->CreateTabWithUrl(GURL());
59 AutomationProxyForExternalTab* proxy =
60 static_cast<AutomationProxyForExternalTab*>(automation());
61 HWND external_tab_container = NULL;
62 HWND tab_wnd = NULL;
63 tab_ = proxy->CreateTabWithHostWindow(false,
64 GURL(), &external_tab_container, &tab_wnd);
65
66 tab_->SetEnableExtensionAutomation(functions_enabled_); 75 tab_->SetEnableExtensionAutomation(functions_enabled_);
67 } 76 }
68 77
69 void TearDown() { 78 void TearDown() {
70 tab_->SetEnableExtensionAutomation(std::vector<std::string>()); 79 tab_->SetEnableExtensionAutomation(std::vector<std::string>());
71 80 tab_ = NULL;
72 AutomationProxyForExternalTab* proxy = 81 EXPECT_TRUE(mock_->HostWindowExists()) <<
73 static_cast<AutomationProxyForExternalTab*>(automation()); 82 "You shouldn't DestroyHostWindow yourself, or extension automation "
74 proxy->DestroyHostWindow(); 83 "won't be correctly reset. Just exit your message loop.";
75 proxy->WaitForTabCleanup(tab_, action_max_timeout_ms()); 84 mock_->DestroyHostWindow();
76 EXPECT_FALSE(tab_->is_valid()); 85 ExternalTabUITest::TearDown();
77 tab_.release();
78
79 ParentTestType::TearDown();
80 }
81
82 void TestWithURL(const GURL& url) {
83 EXPECT_TRUE(tab_->is_valid());
84 if (tab_) {
85 AutomationProxyForExternalTab* proxy =
86 static_cast<AutomationProxyForExternalTab*>(automation());
87
88 // Enter a message loop to allow the tab to be created
89 proxy->WaitForNavigation(2000);
90 DoAdditionalPreNavigateSetup(tab_.get());
91
92 // We explicitly do not make this a toolstrip in the extension manifest,
93 // so that the test can control when it gets loaded, and so that we test
94 // the intended behavior that tabs should be able to show extension pages
95 // (useful for development etc.)
96 tab_->NavigateInExternalTab(url, GURL());
97 EXPECT_TRUE(proxy->WaitForMessage(action_max_timeout_ms()));
98 }
99 }
100
101 // Override if you need additional stuff before we navigate the page.
102 virtual void DoAdditionalPreNavigateSetup(TabProxy* tab) {
103 } 86 }
104 87
105 protected: 88 protected:
106 // Extension API functions that we want to take over. Defaults to all. 89 // Extension API functions that we want to take over. Defaults to all.
107 std::vector<std::string> functions_enabled_; 90 std::vector<std::string> functions_enabled_;
91
92 // Message loop for running the async bits of your test.
93 TimedMessageLoopRunner loop_;
94
95 // The external tab.
108 scoped_refptr<TabProxy> tab_; 96 scoped_refptr<TabProxy> tab_;
109 97
110 private: 98 private:
111 DISALLOW_COPY_AND_ASSIGN(ExtensionUITest); 99 DISALLOW_COPY_AND_ASSIGN(ExtensionUITest);
112 }; 100 };
113 101
114 // For tests that only need to check for a single postMessage
115 // being received from the tab in Chrome. These tests can send a message
116 // to the tab before receiving the new message, but there will not be
117 // a chance to respond by sending a message from the test to the tab after
118 // the postMessage is received.
119 typedef ExtensionUITest<ExternalTabTestType> SingleMessageExtensionUITest;
120
121 // A test that loads a basic extension that makes an API call that does 102 // A test that loads a basic extension that makes an API call that does
122 // not require a response. 103 // not require a response.
123 class SimpleApiCallExtensionTest : public SingleMessageExtensionUITest { 104 class ExtensionTestSimpleApiCall : public ExtensionUITest {
124 public: 105 public:
125 SimpleApiCallExtensionTest() 106 ExtensionTestSimpleApiCall()
126 : SingleMessageExtensionUITest(kTestDirectorySimpleApiCall) { 107 : ExtensionUITest(kTestDirectorySimpleApiCall) {
127 } 108 }
128 109
129 void SetUp() { 110 void SetUp() {
130 // Set just this one function explicitly to be forwarded, as a test of 111 // Set just this one function explicitly to be forwarded, as a test of
131 // the selective forwarding. The next test will leave the default to test 112 // the selective forwarding. The next test will leave the default to test
132 // universal forwarding. 113 // universal forwarding.
133 functions_enabled_.clear(); 114 functions_enabled_.clear();
134 functions_enabled_.push_back("tabs.remove"); 115 functions_enabled_.push_back("tabs.remove");
135 SingleMessageExtensionUITest::SetUp(); 116 ExtensionUITest::SetUp();
136 } 117 }
137 118
138 private: 119 private:
139 DISALLOW_COPY_AND_ASSIGN(SimpleApiCallExtensionTest); 120 DISALLOW_COPY_AND_ASSIGN(ExtensionTestSimpleApiCall);
140 }; 121 };
141 122
142 // TODO(port) Should become portable once ExternalTabMessageLoop is ported. 123 TEST_F(ExtensionTestSimpleApiCall, RunTest) {
143 #if defined(OS_WIN)
144 TEST_F(SimpleApiCallExtensionTest, RunTest) {
145 namespace keys = extension_automation_constants; 124 namespace keys = extension_automation_constants;
146 125
147 TestWithURL(GURL( 126 ASSERT_THAT(mock_, testing::NotNull());
148 "chrome-extension://pmgpglkggjdpkpghhdmbdhababjpcohk/test.html")); 127 EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
149 AutomationProxyForExternalTab* proxy =
150 static_cast<AutomationProxyForExternalTab*>(automation());
151 ASSERT_GT(proxy->messages_received(), 0);
152 128
153 // Using EXPECT_TRUE rather than EXPECT_EQ as the compiler (VC++) isn't 129 std::string message_received;
154 // finding the right match for EqHelper. 130 EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
155 EXPECT_TRUE(proxy->origin() == keys::kAutomationOrigin); 131 _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
156 EXPECT_TRUE(proxy->target() == keys::kAutomationRequestTarget); 132 .WillOnce(DoAll(
133 SaveArg<1>(&message_received),
134 InvokeWithoutArgs(
135 CreateFunctor(&loop_, &TimedMessageLoopRunner::Quit))));
157 136
158 scoped_ptr<Value> message_value(base::JSONReader::Read(proxy->message(), 137 EXPECT_CALL(*mock_, HandleClosed(_));
138
139 ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab_->NavigateInExternalTab(
140 GURL("chrome-extension://pmgpglkggjdpkpghhdmbdhababjpcohk/test.html"),
141 GURL("")));
142
143 loop_.RunFor(2 * action_max_timeout_ms());
144 ASSERT_FALSE(message_received.empty());
145
146 scoped_ptr<Value> message_value(base::JSONReader::Read(message_received,
159 false)); 147 false));
160 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY)); 148 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
161 DictionaryValue* message_dict = 149 DictionaryValue* message_dict =
162 reinterpret_cast<DictionaryValue*>(message_value.get()); 150 reinterpret_cast<DictionaryValue*>(message_value.get());
163 std::string result; 151 std::string result;
164 ASSERT_TRUE(message_dict->GetString(keys::kAutomationNameKey, &result)); 152 ASSERT_TRUE(message_dict->GetString(keys::kAutomationNameKey, &result));
165 EXPECT_EQ(result, "tabs.remove"); 153 EXPECT_EQ(result, "tabs.remove");
166 154
167 result = ""; 155 result = "";
168 ASSERT_TRUE(message_dict->GetString(keys::kAutomationArgsKey, &result)); 156 ASSERT_TRUE(message_dict->GetString(keys::kAutomationArgsKey, &result));
169 EXPECT_NE(result, ""); 157 EXPECT_NE(result, "");
170 158
171 int callback_id = 0xBAADF00D; 159 int callback_id = 0xBAADF00D;
172 message_dict->GetInteger(keys::kAutomationRequestIdKey, &callback_id); 160 message_dict->GetInteger(keys::kAutomationRequestIdKey, &callback_id);
173 EXPECT_NE(callback_id, 0xBAADF00D); 161 EXPECT_NE(callback_id, 0xBAADF00D);
174 162
175 bool has_callback = true; 163 bool has_callback = true;
176 EXPECT_TRUE(message_dict->GetBoolean(keys::kAutomationHasCallbackKey, 164 EXPECT_TRUE(message_dict->GetBoolean(keys::kAutomationHasCallbackKey,
177 &has_callback)); 165 &has_callback));
178 EXPECT_FALSE(has_callback); 166 EXPECT_FALSE(has_callback);
179 } 167 }
180 #endif // defined(OS_WIN)
181 168
182 // A base class for an automation proxy that checks several messages in 169 // A test that loads a basic extension that makes an API call that does
183 // a row. 170 // not require a response.
184 class MultiMessageAutomationProxy : public AutomationProxyForExternalTab { 171 class ExtensionTestRoundtripApiCall : public ExtensionUITest {
185 public: 172 public:
186 explicit MultiMessageAutomationProxy(int execution_timeout) 173 ExtensionTestRoundtripApiCall()
187 : AutomationProxyForExternalTab(execution_timeout) { 174 : ExtensionUITest(kTestDirectoryRoundtripApiCall),
175 messages_received_(0) {
188 } 176 }
189 177
190 // Call when testing with the current tab is finished. 178 void SetUp() {
191 void Quit() { 179 // Set just this one function explicitly to be forwarded, as a test of
192 PostQuitMessage(0); 180 // the selective forwarding. The next test will leave the default to test
181 // universal forwarding.
182 functions_enabled_.clear();
183 functions_enabled_.push_back("tabs.getSelected");
184 functions_enabled_.push_back("tabs.remove");
185 ExtensionUITest::SetUp();
193 } 186 }
194 187
195 protected: 188 void CheckAndSendResponse(const std::string& message) {
196 virtual void OnMessageReceived(const IPC::Message& msg) {
197 IPC_BEGIN_MESSAGE_MAP(MultiMessageAutomationProxy, msg)
198 IPC_MESSAGE_HANDLER(AutomationMsg_DidNavigate,
199 AutomationProxyForExternalTab::OnDidNavigate)
200 IPC_MESSAGE_HANDLER(AutomationMsg_ForwardMessageToExternalHost,
201 OnForwardMessageToExternalHost)
202 IPC_END_MESSAGE_MAP()
203 }
204
205 void OnForwardMessageToExternalHost(int handle,
206 const std::string& message,
207 const std::string& origin,
208 const std::string& target) {
209 messages_received_++;
210 message_ = message;
211 origin_ = origin;
212 target_ = target;
213 HandleMessageFromChrome();
214 }
215
216 // Override to do your custom checking and initiate any custom actions
217 // needed in your particular unit test.
218 virtual void HandleMessageFromChrome() = 0;
219 };
220
221 // This proxy is specific to RoundtripApiCallExtensionTest.
222 class RoundtripAutomationProxy : public MultiMessageAutomationProxy {
223 public:
224 explicit RoundtripAutomationProxy(int execution_timeout)
225 : MultiMessageAutomationProxy(execution_timeout),
226 tab_(NULL) {
227 }
228
229 // Must set before initiating test.
230 TabProxy* tab_;
231
232 protected:
233 virtual void HandleMessageFromChrome() {
234 namespace keys = extension_automation_constants; 189 namespace keys = extension_automation_constants;
190 ++messages_received_;
235 191
236 ASSERT_TRUE(tab_ != NULL); 192 ASSERT_TRUE(tab_ != NULL);
237 ASSERT_TRUE(messages_received_ == 1 || messages_received_ == 2); 193 ASSERT_TRUE(messages_received_ == 1 || messages_received_ == 2);
238 194
239 // Using EXPECT_TRUE rather than EXPECT_EQ as the compiler (VC++) isn't 195 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false));
240 // finding the right match for EqHelper.
241 EXPECT_TRUE(origin_ == keys::kAutomationOrigin);
242 EXPECT_TRUE(target_ == keys::kAutomationRequestTarget);
243
244 scoped_ptr<Value> message_value(base::JSONReader::Read(message_, false));
245 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY)); 196 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
246 DictionaryValue* request_dict = 197 DictionaryValue* request_dict =
247 static_cast<DictionaryValue*>(message_value.get()); 198 static_cast<DictionaryValue*>(message_value.get());
248 std::string function_name; 199 std::string function_name;
249 ASSERT_TRUE(request_dict->GetString(keys::kAutomationNameKey, 200 ASSERT_TRUE(request_dict->GetString(keys::kAutomationNameKey,
250 &function_name)); 201 &function_name));
251 int request_id = -2; 202 int request_id = -2;
252 EXPECT_TRUE(request_dict->GetInteger(keys::kAutomationRequestIdKey, 203 EXPECT_TRUE(request_dict->GetInteger(keys::kAutomationRequestIdKey,
253 &request_id)); 204 &request_id));
254 bool has_callback = false; 205 bool has_callback = false;
255 EXPECT_TRUE(request_dict->GetBoolean(keys::kAutomationHasCallbackKey, 206 EXPECT_TRUE(request_dict->GetBoolean(keys::kAutomationHasCallbackKey,
256 &has_callback)); 207 &has_callback));
257 208
258 if (messages_received_ == 1) { 209 if (messages_received_ == 1) {
259 EXPECT_EQ(function_name, "tabs.getSelected"); 210 EXPECT_EQ(function_name, "tabs.getSelected");
260 EXPECT_GE(request_id, 0); 211 EXPECT_GE(request_id, 0);
261 EXPECT_TRUE(has_callback); 212 EXPECT_TRUE(has_callback);
262 213
263 DictionaryValue response_dict; 214 DictionaryValue response_dict;
264 response_dict.SetInteger(keys::kAutomationRequestIdKey, request_id); 215 response_dict.SetInteger(keys::kAutomationRequestIdKey, request_id);
265 DictionaryValue tab_dict; 216 DictionaryValue tab_dict;
266 tab_dict.SetInteger(extension_tabs_module_constants::kIdKey, 42); 217 tab_dict.SetInteger(extension_tabs_module_constants::kIdKey, 42);
267 tab_dict.SetInteger(extension_tabs_module_constants::kIndexKey, 1); 218 tab_dict.SetInteger(extension_tabs_module_constants::kIndexKey, 1);
268 tab_dict.SetInteger(extension_tabs_module_constants::kWindowIdKey, 1); 219 tab_dict.SetInteger(extension_tabs_module_constants::kWindowIdKey, 1);
269 tab_dict.SetBoolean(extension_tabs_module_constants::kSelectedKey, true); 220 tab_dict.SetBoolean(extension_tabs_module_constants::kSelectedKey, true);
270 tab_dict.SetString(extension_tabs_module_constants::kUrlKey, 221 tab_dict.SetString(extension_tabs_module_constants::kUrlKey,
271 "http://www.google.com"); 222 "http://www.google.com");
272 223
273 std::string tab_json; 224 std::string tab_json;
274 base::JSONWriter::Write(&tab_dict, false, &tab_json); 225 base::JSONWriter::Write(&tab_dict, false, &tab_json);
275 226
276 response_dict.SetString(keys::kAutomationResponseKey, tab_json); 227 response_dict.SetString(keys::kAutomationResponseKey, tab_json);
277 228
278 std::string response_json; 229 std::string response_json;
279 base::JSONWriter::Write(&response_dict, false, &response_json); 230 base::JSONWriter::Write(&response_dict, false, &response_json);
280 231
281 tab_->HandleMessageFromExternalHost( 232 tab_->HandleMessageFromExternalHost(
282 response_json, 233 response_json,
283 keys::kAutomationOrigin, 234 keys::kAutomationOrigin,
284 keys::kAutomationResponseTarget); 235 keys::kAutomationResponseTarget);
285 } else if (messages_received_ == 2) { 236 } else if (messages_received_ == 2) {
286 EXPECT_EQ(function_name, "tabs.remove"); 237 EXPECT_EQ(function_name, "tabs.remove");
287 EXPECT_FALSE(has_callback); 238 EXPECT_FALSE(has_callback);
288 239
289 std::string args; 240 std::string args;
290 EXPECT_TRUE(request_dict->GetString(keys::kAutomationArgsKey, &args)); 241 EXPECT_TRUE(request_dict->GetString(keys::kAutomationArgsKey, &args));
291 EXPECT_NE(args.find("42"), -1); 242 EXPECT_NE(args.find("42"), -1);
292 243 loop_.Quit();
293 Quit();
294 } else { 244 } else {
295 Quit();
296 FAIL(); 245 FAIL();
246 loop_.Quit();
297 } 247 }
298 } 248 }
249
250 private:
251 int messages_received_;
252 DISALLOW_COPY_AND_ASSIGN(ExtensionTestRoundtripApiCall);
299 }; 253 };
300 254
301 class RoundtripApiCallExtensionTest 255 TEST_F(ExtensionTestRoundtripApiCall, RunTest) {
302 : public ExtensionUITest< 256 namespace keys = extension_automation_constants;
303 CustomAutomationProxyTest<RoundtripAutomationProxy>> { 257
258 ASSERT_THAT(mock_, testing::NotNull());
259 EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
260
261 EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
262 _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
263 .Times(2)
264 .WillRepeatedly(WithArgs<1>(Invoke(
265 CreateFunctor(this,
266 &ExtensionTestRoundtripApiCall::CheckAndSendResponse))));
267
268 EXPECT_CALL(*mock_, HandleClosed(_));
269
270 ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab_->NavigateInExternalTab(
271 GURL("chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html"),
272 GURL("")));
273
274 // CheckAndSendResponse (called by OnForwardMessageToExternalHost)
275 // will end the loop once it has received both of our expected messages.
276 loop_.RunFor(2 * action_max_timeout_ms());
277 }
278
279 class ExtensionTestBrowserEvents : public ExtensionUITest {
304 public: 280 public:
305 RoundtripApiCallExtensionTest() 281 ExtensionTestBrowserEvents()
306 : ExtensionUITest< 282 : ExtensionUITest(kTestDirectoryBrowserEvent),
307 CustomAutomationProxyTest< 283 response_count_(0) {
308 RoundtripAutomationProxy> >(kTestDirectoryRoundtripApiCall) {
309 } 284 }
310 285
311 void DoAdditionalPreNavigateSetup(TabProxy* tab) { 286 void SetUp() {
312 RoundtripAutomationProxy* proxy = 287 // Set just this one function explicitly to be forwarded, as a test of
313 static_cast<RoundtripAutomationProxy*>(automation()); 288 // the selective forwarding. The next test will leave the default to test
314 proxy->tab_ = tab; 289 // universal forwarding.
290 functions_enabled_.clear();
291 functions_enabled_.push_back("windows.getCurrent");
292 ExtensionUITest::SetUp();
315 } 293 }
316 294
317 private: 295 // Fire an event of the given name to the test extension.
318 DISALLOW_COPY_AND_ASSIGN(RoundtripApiCallExtensionTest); 296 void FireEvent(const char* event_name) {
319 }; 297 namespace keys = extension_automation_constants;
320 298
321 // TODO(port) Should become portable once 299 ASSERT_TRUE(tab_ != NULL);
322 // ExternalTabMessageLoop is ported.
323 #if defined(OS_WIN)
324 TEST_F(RoundtripApiCallExtensionTest, RunTest) {
325 TestWithURL(GURL(
326 "chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html"));
327 RoundtripAutomationProxy* proxy =
328 static_cast<RoundtripAutomationProxy*>(automation());
329 300
330 // Validation is done in the RoundtripAutomationProxy, so we just check 301 // Build the event message to send to the extension. The only important
331 // something basic here. 302 // part is the name, as the payload is not used by the test extension.
332 EXPECT_EQ(proxy->messages_received(), 2); 303 std::string message;
333 } 304 message += event_name;
334 #endif // defined(OS_WIN)
335 305
336 // This proxy is specific to BrowserEventExtensionTest. 306 tab_->HandleMessageFromExternalHost(
337 class BrowserEventAutomationProxy : public MultiMessageAutomationProxy { 307 message,
338 public: 308 keys::kAutomationOrigin,
339 explicit BrowserEventAutomationProxy(int execution_timeout) 309 keys::kAutomationBrowserEventRequestTarget);
340 : MultiMessageAutomationProxy(execution_timeout),
341 tab_(NULL) {
342 } 310 }
343 311
344 // Must set before initiating test. 312 void HandleMessageFromChrome(const std::string& message,
345 TabProxy* tab_; 313 const std::string& target);
346 314
315 protected:
347 // Counts the number of times we got a given event. 316 // Counts the number of times we got a given event.
348 std::map<std::string, int> event_count_; 317 std::map<std::string, int> event_count_;
349 318
350 // Array containing the names of the events to fire to the extension. 319 // Array containing the names of the events to fire to the extension.
351 static const char* events_[]; 320 static const char* events_[];
352 321
353 protected: 322 // Number of events extension has told us it received.
354 // Process a message received from the test extension. 323 int response_count_;
355 virtual void HandleMessageFromChrome();
356 324
357 // Fire an event of the given name to the test extension. 325 DISALLOW_COPY_AND_ASSIGN(ExtensionTestBrowserEvents);
358 void FireEvent(const char* event_name);
359 }; 326 };
360 327
361 const char* BrowserEventAutomationProxy::events_[] = { 328 const char* ExtensionTestBrowserEvents::events_[] = {
362 // Window events. 329 // Window events.
363 "[\"windows.onCreated\", \"[{'id':42,'focused':true,'top':0,'left':0," 330 "[\"windows.onCreated\", \"[{'id':42,'focused':true,'top':0,'left':0,"
364 "'width':100,'height':100}]\"]", 331 "'width':100,'height':100}]\"]",
365 332
366 "[\"windows.onRemoved\", \"[42]\"]", 333 "[\"windows.onRemoved\", \"[42]\"]",
367 334
368 "[\"windows.onFocusChanged\", \"[42]\"]", 335 "[\"windows.onFocusChanged\", \"[42]\"]",
369 336
370 // Tab events. 337 // Tab events.
371 "[\"tabs.onCreated\", \"[{'id\':42,'index':1,'windowId':1," 338 "[\"tabs.onCreated\", \"[{'id\':42,'index':1,'windowId':1,"
(...skipping 20 matching lines...) Expand all
392 359
393 "[\"bookmarks.onChanged\", \"['42', {'title':'foo'}]\"]", 360 "[\"bookmarks.onChanged\", \"['42', {'title':'foo'}]\"]",
394 361
395 "[\"bookmarks.onMoved\", \"['42', {'parentId':'2','index':1," 362 "[\"bookmarks.onMoved\", \"['42', {'parentId':'2','index':1,"
396 "'oldParentId':'3','oldIndex':2}]\"]", 363 "'oldParentId':'3','oldIndex':2}]\"]",
397 364
398 "[\"bookmarks.onChildrenReordered\", \"['32', " 365 "[\"bookmarks.onChildrenReordered\", \"['32', "
399 "{'childIds':['1', '2', '3']}]\"]" 366 "{'childIds':['1', '2', '3']}]\"]"
400 }; 367 };
401 368
402 void BrowserEventAutomationProxy::HandleMessageFromChrome() { 369 void ExtensionTestBrowserEvents::HandleMessageFromChrome(
370 const std::string& message,
371 const std::string& target) {
403 namespace keys = extension_automation_constants; 372 namespace keys = extension_automation_constants;
404 ASSERT_TRUE(tab_ != NULL); 373 ASSERT_TRUE(tab_ != NULL);
405 374
406 std::string message(message());
407 std::string origin(origin());
408 std::string target(target());
409
410 ASSERT_TRUE(message.length() > 0); 375 ASSERT_TRUE(message.length() > 0);
411 ASSERT_STREQ(keys::kAutomationOrigin, origin.c_str());
412 376
413 if (target == keys::kAutomationRequestTarget) { 377 if (target == keys::kAutomationRequestTarget) {
414 // This should be a request for the current window. We don't need to 378 // This should be a request for the current window. We don't need to
415 // respond, as this is used only as an indication that the extension 379 // respond, as this is used only as an indication that the extension
416 // page is now loaded. 380 // page is now loaded.
417 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false)); 381 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false));
418 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY)); 382 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
419 DictionaryValue* message_dict = 383 DictionaryValue* message_dict =
420 reinterpret_cast<DictionaryValue*>(message_value.get()); 384 reinterpret_cast<DictionaryValue*>(message_value.get());
421 385
(...skipping 23 matching lines...) Expand all
445 // 409 //
446 // There is a special message "ACK" which means that the extension 410 // There is a special message "ACK" which means that the extension
447 // received the port connection. This is not an event response and 411 // received the port connection. This is not an event response and
448 // should happen before all events. 412 // should happen before all events.
449 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false)); 413 scoped_ptr<Value> message_value(base::JSONReader::Read(message, false));
450 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY)); 414 ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
451 DictionaryValue* message_dict = 415 DictionaryValue* message_dict =
452 reinterpret_cast<DictionaryValue*>(message_value.get()); 416 reinterpret_cast<DictionaryValue*>(message_value.get());
453 417
454 std::string event_name; 418 std::string event_name;
455 ASSERT_TRUE(message_dict->GetString(L"data", &event_name)); 419 message_dict->GetString(keys::kAutomationMessageDataKey, &event_name);
456 if (event_name == "\"ACK\"") { 420 if (event_name == "\"ACK\"") {
457 ASSERT_EQ(0, event_count_.size()); 421 ASSERT_EQ(0, event_count_.size());
422 } else if (event_name.empty()) {
423 // This must be the post disconnect.
424 int request_id = -1;
425 message_dict->GetInteger(keys::kAutomationRequestIdKey, &request_id);
426 ASSERT_EQ(keys::CHANNEL_CLOSED, request_id);
458 } else { 427 } else {
459 ++event_count_[event_name]; 428 ++event_count_[event_name];
460 } 429 }
430
431 // Check if we're done.
432 if (event_count_.size() == arraysize(events_)) {
433 loop_.Quit();
434 }
461 } 435 }
462 } 436 }
463 437
464 void BrowserEventAutomationProxy::FireEvent(const char* event) { 438 TEST_F(ExtensionTestBrowserEvents, RunTest) {
465 namespace keys = extension_automation_constants;
466
467 // Build the event message to send to the extension. The only important
468 // part is the name, as the payload is not used by the test extension.
469 std::string message;
470 message += event;
471
472 tab_->HandleMessageFromExternalHost(
473 message,
474 keys::kAutomationOrigin,
475 keys::kAutomationBrowserEventRequestTarget);
476 }
477
478 class BrowserEventExtensionTest
479 : public ExtensionUITest<
480 CustomAutomationProxyTest<BrowserEventAutomationProxy>> {
481 public:
482 BrowserEventExtensionTest()
483 : ExtensionUITest<
484 CustomAutomationProxyTest<
485 BrowserEventAutomationProxy> >(kTestDirectoryBrowserEvent) {
486 }
487
488 void DoAdditionalPreNavigateSetup(TabProxy* tab) {
489 BrowserEventAutomationProxy* proxy =
490 static_cast<BrowserEventAutomationProxy*>(automation());
491 proxy->tab_ = tab;
492 }
493
494 private:
495
496 DISALLOW_COPY_AND_ASSIGN(BrowserEventExtensionTest);
497 };
498
499 // TODO(port) Should become portable once
500 // ExternalTabMessageLoop is ported.
501 #if defined(OS_WIN)
502 TEST_F(BrowserEventExtensionTest, RunTest) {
503 // This test loads an HTML file that tries to add listeners to a bunch of 439 // This test loads an HTML file that tries to add listeners to a bunch of
504 // chrome.* events and upon adding a listener it posts the name of the event 440 // chrome.* events and upon adding a listener it posts the name of the event
505 // to the automation layer, which we'll count to make sure the events work. 441 // to the automation layer, which we'll count to make sure the events work.
506 TestWithURL(GURL( 442 namespace keys = extension_automation_constants;
507 "chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html")); 443
508 BrowserEventAutomationProxy* proxy = 444 ASSERT_THAT(mock_, testing::NotNull());
509 static_cast<BrowserEventAutomationProxy*>(automation()); 445 EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
446
447 EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
448 _, _, keys::kAutomationOrigin, _))
449 .WillRepeatedly(WithArgs<1, 3>(Invoke(
450 CreateFunctor(this,
451 &ExtensionTestBrowserEvents::HandleMessageFromChrome))));
452
453 EXPECT_CALL(*mock_, HandleClosed(_));
454
455 ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab_->NavigateInExternalTab(
456 GURL("chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html"),
457 GURL("")));
458
459 // HandleMessageFromChrome (called by OnForwardMessageToExternalHost) ends
460 // the loop when we've received the number of response messages we expect.
461 loop_.RunFor(2 * action_max_timeout_ms());
510 462
511 // If this assert hits and the actual size is 0 then you need to look at: 463 // If this assert hits and the actual size is 0 then you need to look at:
512 // src\chrome\test\data\extensions\uitest\event_sink\test.html and see if 464 // src\chrome\test\data\extensions\uitest\event_sink\test.html and see if
513 // all the events we are attaching to are valid. Also compare the list against 465 // all the events we are attaching to are valid. Also compare the list against
514 // the event_names_ string array above. 466 // the event_names_ string array above.
515 EXPECT_EQ(arraysize(BrowserEventAutomationProxy::events_), 467 ASSERT_EQ(arraysize(events_), event_count_.size());
516 proxy->event_count_.size()); 468 for (std::map<std::string, int>::iterator i = event_count_.begin();
517 for (std::map<std::string, int>::iterator i = proxy->event_count_.begin(); 469 i != event_count_.end(); ++i) {
518 i != proxy->event_count_.end(); ++i) {
519 const std::pair<std::string, int>& value = *i; 470 const std::pair<std::string, int>& value = *i;
520 ASSERT_EQ(1, value.second); 471 EXPECT_EQ(1, value.second);
521 } 472 }
522 } 473 }
523 #endif // defined(OS_WIN) 474 #endif // defined(OS_WIN)
524 475
525 } // namespace 476 } // namespace
OLDNEW
« no previous file with comments | « no previous file | chrome/test/automation/automation_proxy_uitest.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698