Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / content / browser / devtools / protocol / devtools_protocol_browsertest.cc
blobd3181be6e9138c5ce1cbd49e1ef679a1416670cf
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/web_contents.h"
12 #include "content/public/test/browser_test_utils.h"
13 #include "content/public/test/content_browser_test.h"
14 #include "content/public/test/content_browser_test_utils.h"
15 #include "content/public/test/test_navigation_observer.h"
16 #include "content/shell/browser/shell.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "ui/compositor/compositor_switches.h"
19 #include "ui/gfx/codec/png_codec.h"
21 namespace content {
23 namespace {
25 const char kIdParam[] = "id";
26 const char kMethodParam[] = "method";
27 const char kParamsParam[] = "params";
31 class DevToolsProtocolTest : public ContentBrowserTest,
32 public DevToolsAgentHostClient {
33 public:
34 DevToolsProtocolTest()
35 : last_sent_id_(0),
36 in_dispatch_(false) {
39 protected:
40 void SendCommand(const std::string& method,
41 scoped_ptr<base::DictionaryValue> params) {
42 SendCommand(method, params.Pass(), true);
45 void SendCommand(const std::string& method,
46 scoped_ptr<base::DictionaryValue> params,
47 bool wait) {
48 in_dispatch_ = true;
49 base::DictionaryValue command;
50 command.SetInteger(kIdParam, ++last_sent_id_);
51 command.SetString(kMethodParam, method);
52 if (params)
53 command.Set(kParamsParam, params.release());
55 std::string json_command;
56 base::JSONWriter::Write(command, &json_command);
57 agent_host_->DispatchProtocolMessage(json_command);
58 // Some messages are dispatched synchronously.
59 // Only run loop if we are not finished yet.
60 if (in_dispatch_ && wait)
61 base::MessageLoop::current()->Run();
62 in_dispatch_ = false;
65 bool HasValue(const std::string& path) {
66 base::Value* value = 0;
67 return result_->Get(path, &value);
70 bool HasListItem(const std::string& path_to_list,
71 const std::string& name,
72 const std::string& value) {
73 base::ListValue* list;
74 if (!result_->GetList(path_to_list, &list))
75 return false;
77 for (size_t i = 0; i != list->GetSize(); i++) {
78 base::DictionaryValue* item;
79 if (!list->GetDictionary(i, &item))
80 return false;
81 std::string id;
82 if (!item->GetString(name, &id))
83 return false;
84 if (id == value)
85 return true;
87 return false;
90 void Attach() {
91 agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
92 agent_host_->AttachClient(this);
95 void TearDownOnMainThread() override {
96 if (agent_host_) {
97 agent_host_->DetachClient();
98 agent_host_ = nullptr;
102 scoped_ptr<base::DictionaryValue> result_;
103 scoped_refptr<DevToolsAgentHost> agent_host_;
104 int last_sent_id_;
105 std::vector<int> result_ids_;
106 std::vector<std::string> notifications_;
108 private:
109 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
110 const std::string& message) override {
111 scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>(
112 base::JSONReader::DeprecatedRead(message)));
113 int id;
114 if (root->GetInteger("id", &id)) {
115 result_ids_.push_back(id);
116 base::DictionaryValue* result;
117 EXPECT_TRUE(root->GetDictionary("result", &result));
118 result_.reset(result->DeepCopy());
119 in_dispatch_ = false;
120 if (base::MessageLoop::current()->is_running())
121 base::MessageLoop::current()->QuitNow();
122 } else {
123 std::string notification;
124 EXPECT_TRUE(root->GetString("method", &notification));
125 notifications_.push_back(notification);
129 void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
130 EXPECT_TRUE(false);
133 bool in_dispatch_;
136 class SyntheticKeyEventTest : public DevToolsProtocolTest {
137 protected:
138 void SendKeyEvent(const std::string& type,
139 int modifier,
140 int windowsKeyCode,
141 int nativeKeyCode) {
142 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
143 params->SetString("type", type);
144 params->SetInteger("modifiers", modifier);
145 params->SetInteger("windowsVirtualKeyCode", windowsKeyCode);
146 params->SetInteger("nativeVirtualKeyCode", nativeKeyCode);
147 SendCommand("Input.dispatchKeyEvent", params.Pass());
151 IN_PROC_BROWSER_TEST_F(SyntheticKeyEventTest, KeyEventSynthesizeKeyIdentifier) {
152 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
153 Attach();
154 ASSERT_TRUE(content::ExecuteScript(
155 shell()->web_contents()->GetRenderViewHost(),
156 "function handleKeyEvent(event) {"
157 "domAutomationController.setAutomationId(0);"
158 "domAutomationController.send(event.keyIdentifier);"
160 "document.body.addEventListener('keydown', handleKeyEvent);"
161 "document.body.addEventListener('keyup', handleKeyEvent);"));
163 DOMMessageQueue dom_message_queue;
165 // Send enter (keycode 13).
166 SendKeyEvent("rawKeyDown", 0, 13, 13);
167 SendKeyEvent("keyUp", 0, 13, 13);
169 std::string key_identifier;
170 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
171 EXPECT_EQ("\"Enter\"", key_identifier);
172 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
173 EXPECT_EQ("\"Enter\"", key_identifier);
175 // Send escape (keycode 27).
176 SendKeyEvent("rawKeyDown", 0, 27, 27);
177 SendKeyEvent("keyUp", 0, 27, 27);
179 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
180 EXPECT_EQ("\"U+001B\"", key_identifier);
181 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
182 EXPECT_EQ("\"U+001B\"", key_identifier);
185 class CaptureScreenshotTest : public DevToolsProtocolTest {
186 private:
187 #if !defined(OS_ANDROID)
188 void SetUpCommandLine(base::CommandLine* command_line) override {
189 command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
191 #endif
194 // Does not link on Android
195 #if defined(OS_ANDROID)
196 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
197 #elif defined(OS_MACOSX) // Fails on 10.9. http://crbug.com/430620
198 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
199 #elif defined(MEMORY_SANITIZER)
200 // Also fails under MSAN. http://crbug.com/423583
201 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
202 #else
203 #define MAYBE_CaptureScreenshot CaptureScreenshot
204 #endif
205 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, MAYBE_CaptureScreenshot) {
206 shell()->LoadURL(GURL("about:blank"));
207 Attach();
208 EXPECT_TRUE(content::ExecuteScript(
209 shell()->web_contents()->GetRenderViewHost(),
210 "document.body.style.background = '#123456'"));
211 SendCommand("Page.captureScreenshot", nullptr);
212 std::string base64;
213 EXPECT_TRUE(result_->GetString("data", &base64));
214 std::string png;
215 EXPECT_TRUE(base::Base64Decode(base64, &png));
216 SkBitmap bitmap;
217 gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(png.data()),
218 png.size(), &bitmap);
219 SkColor color(bitmap.getColor(0, 0));
220 EXPECT_TRUE(std::abs(0x12-(int)SkColorGetR(color)) <= 1);
221 EXPECT_TRUE(std::abs(0x34-(int)SkColorGetG(color)) <= 1);
222 EXPECT_TRUE(std::abs(0x56-(int)SkColorGetB(color)) <= 1);
225 #if defined(OS_ANDROID)
226 // Disabled, see http://crbug.com/469947.
227 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizePinchGesture) {
228 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
229 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
230 Attach();
232 int old_width;
233 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
234 shell()->web_contents(),
235 "domAutomationController.send(window.innerWidth)", &old_width));
237 int old_height;
238 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
239 shell()->web_contents(),
240 "domAutomationController.send(window.innerHeight)", &old_height));
242 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
243 params->SetInteger("x", old_width / 2);
244 params->SetInteger("y", old_height / 2);
245 params->SetDouble("scaleFactor", 2.0);
246 SendCommand("Input.synthesizePinchGesture", params.Pass());
248 int new_width;
249 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
250 shell()->web_contents(),
251 "domAutomationController.send(window.innerWidth)", &new_width));
252 ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_width) / new_width);
254 int new_height;
255 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
256 shell()->web_contents(),
257 "domAutomationController.send(window.innerHeight)", &new_height));
258 ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_height) / new_height);
261 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeScrollGesture) {
262 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
263 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
264 Attach();
266 int scroll_top;
267 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
268 shell()->web_contents(),
269 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
270 ASSERT_EQ(0, scroll_top);
272 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
273 params->SetInteger("x", 0);
274 params->SetInteger("y", 0);
275 params->SetInteger("xDistance", 0);
276 params->SetInteger("yDistance", -100);
277 SendCommand("Input.synthesizeScrollGesture", params.Pass());
279 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
280 shell()->web_contents(),
281 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
282 ASSERT_EQ(100, scroll_top);
285 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeTapGesture) {
286 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
287 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
288 Attach();
290 int scroll_top;
291 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
292 shell()->web_contents(),
293 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
294 ASSERT_EQ(0, scroll_top);
296 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
297 params->SetInteger("x", 16);
298 params->SetInteger("y", 16);
299 params->SetString("gestureSourceType", "touch");
300 SendCommand("Input.synthesizeTapGesture", params.Pass());
302 // The link that we just tapped should take us to the bottom of the page. The
303 // new value of |document.body.scrollTop| will depend on the screen dimensions
304 // of the device that we're testing on, but in any case it should be greater
305 // than 0.
306 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
307 shell()->web_contents(),
308 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
309 ASSERT_GT(scroll_top, 0);
311 #endif // defined(OS_ANDROID)
313 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, NavigationPreservesMessages) {
314 ASSERT_TRUE(test_server()->Start());
315 GURL test_url = test_server()->GetURL("files/devtools/navigation.html");
316 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
317 Attach();
318 SendCommand("Page.enable", nullptr, false);
320 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
321 test_url = GetTestUrl("devtools", "navigation.html");
322 params->SetString("url", test_url.spec());
323 SendCommand("Page.navigate", params.Pass(), true);
325 bool enough_results = result_ids_.size() >= 2u;
326 EXPECT_TRUE(enough_results);
327 if (enough_results) {
328 EXPECT_EQ(1, result_ids_[0]); // Page.enable
329 EXPECT_EQ(2, result_ids_[1]); // Page.navigate
332 enough_results = notifications_.size() >= 1u;
333 EXPECT_TRUE(enough_results);
334 bool found_frame_notification = false;
335 for (const std::string& notification : notifications_) {
336 if (notification == "Page.frameStartedLoading")
337 found_frame_notification = true;
339 EXPECT_TRUE(found_frame_notification);
342 } // namespace content