[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / devtools / protocol / devtools_protocol_browsertest.cc
blob12491215fe430534fc02b9cee96d2c6413a462e3
1 // Copyright 2013 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.
5 #include "base/base64.h"
6 #include "base/command_line.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/values.h"
10 #include "content/public/browser/devtools_agent_host.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/common/url_constants.h"
14 #include "content/public/test/browser_test_utils.h"
15 #include "content/public/test/content_browser_test.h"
16 #include "content/public/test/content_browser_test_utils.h"
17 #include "content/public/test/test_navigation_observer.h"
18 #include "content/shell/browser/shell.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/test/embedded_test_server/embedded_test_server.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/compositor/compositor_switches.h"
23 #include "ui/gfx/codec/png_codec.h"
25 namespace content {
27 namespace {
29 const char kIdParam[] = "id";
30 const char kMethodParam[] = "method";
31 const char kParamsParam[] = "params";
35 class DevToolsProtocolTest : public ContentBrowserTest,
36 public DevToolsAgentHostClient {
37 public:
38 DevToolsProtocolTest()
39 : last_sent_id_(0),
40 waiting_for_notifications_count_(0),
41 in_dispatch_(false) {
44 protected:
45 void SendCommand(const std::string& method,
46 scoped_ptr<base::DictionaryValue> params) {
47 SendCommand(method, params.Pass(), true);
50 void SendCommand(const std::string& method,
51 scoped_ptr<base::DictionaryValue> params,
52 bool wait) {
53 in_dispatch_ = true;
54 base::DictionaryValue command;
55 command.SetInteger(kIdParam, ++last_sent_id_);
56 command.SetString(kMethodParam, method);
57 if (params)
58 command.Set(kParamsParam, params.release());
60 std::string json_command;
61 base::JSONWriter::Write(command, &json_command);
62 agent_host_->DispatchProtocolMessage(json_command);
63 // Some messages are dispatched synchronously.
64 // Only run loop if we are not finished yet.
65 if (in_dispatch_ && wait)
66 base::MessageLoop::current()->Run();
67 in_dispatch_ = false;
70 bool HasValue(const std::string& path) {
71 base::Value* value = 0;
72 return result_->Get(path, &value);
75 bool HasListItem(const std::string& path_to_list,
76 const std::string& name,
77 const std::string& value) {
78 base::ListValue* list;
79 if (!result_->GetList(path_to_list, &list))
80 return false;
82 for (size_t i = 0; i != list->GetSize(); i++) {
83 base::DictionaryValue* item;
84 if (!list->GetDictionary(i, &item))
85 return false;
86 std::string id;
87 if (!item->GetString(name, &id))
88 return false;
89 if (id == value)
90 return true;
92 return false;
95 void Attach() {
96 agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
97 agent_host_->AttachClient(this);
100 void TearDownOnMainThread() override {
101 if (agent_host_) {
102 agent_host_->DetachClient();
103 agent_host_ = nullptr;
107 void WaitForNotifications(int count) {
108 waiting_for_notifications_count_ = count;
109 RunMessageLoop();
112 scoped_ptr<base::DictionaryValue> result_;
113 scoped_refptr<DevToolsAgentHost> agent_host_;
114 int last_sent_id_;
115 std::vector<int> result_ids_;
116 std::vector<std::string> notifications_;
118 private:
119 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
120 const std::string& message) override {
121 scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>(
122 base::JSONReader::Read(message).release()));
123 int id;
124 if (root->GetInteger("id", &id)) {
125 result_ids_.push_back(id);
126 base::DictionaryValue* result;
127 EXPECT_TRUE(root->GetDictionary("result", &result));
128 result_.reset(result->DeepCopy());
129 in_dispatch_ = false;
130 if (base::MessageLoop::current()->is_running())
131 base::MessageLoop::current()->QuitNow();
132 } else {
133 std::string notification;
134 EXPECT_TRUE(root->GetString("method", &notification));
135 notifications_.push_back(notification);
136 if (waiting_for_notifications_count_) {
137 waiting_for_notifications_count_--;
138 if (!waiting_for_notifications_count_)
139 base::MessageLoop::current()->QuitNow();
144 void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
145 EXPECT_TRUE(false);
148 int waiting_for_notifications_count_;
149 bool in_dispatch_;
152 class SyntheticKeyEventTest : public DevToolsProtocolTest {
153 protected:
154 void SendKeyEvent(const std::string& type,
155 int modifier,
156 int windowsKeyCode,
157 int nativeKeyCode) {
158 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
159 params->SetString("type", type);
160 params->SetInteger("modifiers", modifier);
161 params->SetInteger("windowsVirtualKeyCode", windowsKeyCode);
162 params->SetInteger("nativeVirtualKeyCode", nativeKeyCode);
163 SendCommand("Input.dispatchKeyEvent", params.Pass());
167 IN_PROC_BROWSER_TEST_F(SyntheticKeyEventTest, KeyEventSynthesizeKeyIdentifier) {
168 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
169 Attach();
170 ASSERT_TRUE(content::ExecuteScript(
171 shell()->web_contents()->GetRenderViewHost(),
172 "function handleKeyEvent(event) {"
173 "domAutomationController.setAutomationId(0);"
174 "domAutomationController.send(event.keyIdentifier);"
176 "document.body.addEventListener('keydown', handleKeyEvent);"
177 "document.body.addEventListener('keyup', handleKeyEvent);"));
179 DOMMessageQueue dom_message_queue;
181 // Send enter (keycode 13).
182 SendKeyEvent("rawKeyDown", 0, 13, 13);
183 SendKeyEvent("keyUp", 0, 13, 13);
185 std::string key_identifier;
186 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
187 EXPECT_EQ("\"Enter\"", key_identifier);
188 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
189 EXPECT_EQ("\"Enter\"", key_identifier);
191 // Send escape (keycode 27).
192 SendKeyEvent("rawKeyDown", 0, 27, 27);
193 SendKeyEvent("keyUp", 0, 27, 27);
195 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
196 EXPECT_EQ("\"U+001B\"", key_identifier);
197 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
198 EXPECT_EQ("\"U+001B\"", key_identifier);
201 class CaptureScreenshotTest : public DevToolsProtocolTest {
202 private:
203 #if !defined(OS_ANDROID)
204 void SetUpCommandLine(base::CommandLine* command_line) override {
205 command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
207 #endif
210 // Does not link on Android
211 #if defined(OS_ANDROID)
212 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
213 #elif defined(OS_MACOSX) // Fails on 10.9. http://crbug.com/430620
214 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
215 #elif defined(MEMORY_SANITIZER)
216 // Also fails under MSAN. http://crbug.com/423583
217 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
218 #else
219 #define MAYBE_CaptureScreenshot CaptureScreenshot
220 #endif
221 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, MAYBE_CaptureScreenshot) {
222 shell()->LoadURL(GURL("about:blank"));
223 Attach();
224 EXPECT_TRUE(content::ExecuteScript(
225 shell()->web_contents()->GetRenderViewHost(),
226 "document.body.style.background = '#123456'"));
227 SendCommand("Page.captureScreenshot", nullptr);
228 std::string base64;
229 EXPECT_TRUE(result_->GetString("data", &base64));
230 std::string png;
231 EXPECT_TRUE(base::Base64Decode(base64, &png));
232 SkBitmap bitmap;
233 gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(png.data()),
234 png.size(), &bitmap);
235 SkColor color(bitmap.getColor(0, 0));
236 EXPECT_TRUE(std::abs(0x12-(int)SkColorGetR(color)) <= 1);
237 EXPECT_TRUE(std::abs(0x34-(int)SkColorGetG(color)) <= 1);
238 EXPECT_TRUE(std::abs(0x56-(int)SkColorGetB(color)) <= 1);
241 #if defined(OS_ANDROID)
242 // Disabled, see http://crbug.com/469947.
243 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizePinchGesture) {
244 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
245 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
246 Attach();
248 int old_width;
249 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
250 shell()->web_contents(),
251 "domAutomationController.send(window.innerWidth)", &old_width));
253 int old_height;
254 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
255 shell()->web_contents(),
256 "domAutomationController.send(window.innerHeight)", &old_height));
258 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
259 params->SetInteger("x", old_width / 2);
260 params->SetInteger("y", old_height / 2);
261 params->SetDouble("scaleFactor", 2.0);
262 SendCommand("Input.synthesizePinchGesture", params.Pass());
264 int new_width;
265 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
266 shell()->web_contents(),
267 "domAutomationController.send(window.innerWidth)", &new_width));
268 ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_width) / new_width);
270 int new_height;
271 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
272 shell()->web_contents(),
273 "domAutomationController.send(window.innerHeight)", &new_height));
274 ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_height) / new_height);
277 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeScrollGesture) {
278 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
279 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
280 Attach();
282 int scroll_top;
283 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
284 shell()->web_contents(),
285 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
286 ASSERT_EQ(0, scroll_top);
288 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
289 params->SetInteger("x", 0);
290 params->SetInteger("y", 0);
291 params->SetInteger("xDistance", 0);
292 params->SetInteger("yDistance", -100);
293 SendCommand("Input.synthesizeScrollGesture", params.Pass());
295 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
296 shell()->web_contents(),
297 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
298 ASSERT_EQ(100, scroll_top);
301 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeTapGesture) {
302 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
303 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
304 Attach();
306 int scroll_top;
307 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
308 shell()->web_contents(),
309 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
310 ASSERT_EQ(0, scroll_top);
312 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
313 params->SetInteger("x", 16);
314 params->SetInteger("y", 16);
315 params->SetString("gestureSourceType", "touch");
316 SendCommand("Input.synthesizeTapGesture", params.Pass());
318 // The link that we just tapped should take us to the bottom of the page. The
319 // new value of |document.body.scrollTop| will depend on the screen dimensions
320 // of the device that we're testing on, but in any case it should be greater
321 // than 0.
322 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
323 shell()->web_contents(),
324 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
325 ASSERT_GT(scroll_top, 0);
327 #endif // defined(OS_ANDROID)
329 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, NavigationPreservesMessages) {
330 ASSERT_TRUE(test_server()->Start());
331 GURL test_url = test_server()->GetURL("files/devtools/navigation.html");
332 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
333 Attach();
334 SendCommand("Page.enable", nullptr, false);
336 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
337 test_url = GetTestUrl("devtools", "navigation.html");
338 params->SetString("url", test_url.spec());
339 SendCommand("Page.navigate", params.Pass(), true);
341 bool enough_results = result_ids_.size() >= 2u;
342 EXPECT_TRUE(enough_results);
343 if (enough_results) {
344 EXPECT_EQ(1, result_ids_[0]); // Page.enable
345 EXPECT_EQ(2, result_ids_[1]); // Page.navigate
348 enough_results = notifications_.size() >= 1u;
349 EXPECT_TRUE(enough_results);
350 bool found_frame_notification = false;
351 for (const std::string& notification : notifications_) {
352 if (notification == "Page.frameStartedLoading")
353 found_frame_notification = true;
355 EXPECT_TRUE(found_frame_notification);
358 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CrossSiteNoDetach) {
359 host_resolver()->AddRule("*", "127.0.0.1");
360 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
361 content::SetupCrossSiteRedirector(embedded_test_server());
363 GURL test_url1 = embedded_test_server()->GetURL(
364 "A.com", "/devtools/navigation.html");
365 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url1, 1);
366 Attach();
368 GURL test_url2 = embedded_test_server()->GetURL(
369 "B.com", "/devtools/navigation.html");
370 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url2, 1);
372 EXPECT_EQ(0u, notifications_.size());
375 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReconnectPreservesState) {
376 ASSERT_TRUE(test_server()->Start());
377 GURL test_url = test_server()->GetURL("files/devtools/navigation.html");
378 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
380 Shell* second = CreateBrowser();
381 NavigateToURLBlockUntilNavigationsComplete(second, test_url, 1);
383 Attach();
384 SendCommand("Runtime.enable", nullptr);
386 size_t notification_count = notifications_.size();
387 agent_host_->DisconnectWebContents();
388 agent_host_->ConnectWebContents(second->web_contents());
389 WaitForNotifications(1);
391 bool found_notification = false;
392 for (size_t i = notification_count; i < notifications_.size(); ++i) {
393 if (notifications_[i] == "Runtime.executionContextsCleared")
394 found_notification = true;
396 EXPECT_TRUE(found_notification);
399 } // namespace content