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.
4
5 #include "content/shell/browser/webkit_test_controller.h"
6
7 #include <iostream>
8
9 #include "base/base64.h"
10 #include "base/command_line.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "content/public/browser/devtools_agent_host.h"
16 #include "content/public/browser/dom_storage_context.h"
17 #include "content/public/browser/gpu_data_manager.h"
18 #include "content/public/browser/navigation_controller.h"
19 #include "content/public/browser/navigation_entry.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/render_widget_host_view.h"
25 #include "content/public/browser/storage_partition.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/common/url_constants.h"
29 #include "content/shell/browser/shell.h"
30 #include "content/shell/browser/shell_browser_context.h"
31 #include "content/shell/browser/shell_content_browser_client.h"
32 #include "content/shell/browser/shell_devtools_frontend.h"
33 #include "content/shell/common/shell_messages.h"
34 #include "content/shell/common/shell_switches.h"
35 #include "content/shell/common/webkit_test_helpers.h"
36 #include "ui/gfx/codec/png_codec.h"
37
38 namespace content {
39
40 const int kTestSVGWindowWidthDip = 480;
41 const int kTestSVGWindowHeightDip = 360;
42
43 // WebKitTestResultPrinter ----------------------------------------------------
44
WebKitTestResultPrinter(std::ostream * output,std::ostream * error)45 WebKitTestResultPrinter::WebKitTestResultPrinter(
46 std::ostream* output, std::ostream* error)
47 : state_(DURING_TEST),
48 capture_text_only_(false),
49 encode_binary_data_(false),
50 output_(output),
51 error_(error) {
52 }
53
~WebKitTestResultPrinter()54 WebKitTestResultPrinter::~WebKitTestResultPrinter() {
55 }
56
PrintTextHeader()57 void WebKitTestResultPrinter::PrintTextHeader() {
58 if (state_ != DURING_TEST)
59 return;
60 if (!capture_text_only_)
61 *output_ << "Content-Type: text/plain\n";
62 state_ = IN_TEXT_BLOCK;
63 }
64
PrintTextBlock(const std::string & block)65 void WebKitTestResultPrinter::PrintTextBlock(const std::string& block) {
66 if (state_ != IN_TEXT_BLOCK)
67 return;
68 *output_ << block;
69 }
70
PrintTextFooter()71 void WebKitTestResultPrinter::PrintTextFooter() {
72 if (state_ != IN_TEXT_BLOCK)
73 return;
74 if (!capture_text_only_) {
75 *output_ << "#EOF\n";
76 output_->flush();
77 }
78 state_ = IN_IMAGE_BLOCK;
79 }
80
PrintImageHeader(const std::string & actual_hash,const std::string & expected_hash)81 void WebKitTestResultPrinter::PrintImageHeader(
82 const std::string& actual_hash,
83 const std::string& expected_hash) {
84 if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
85 return;
86 *output_ << "\nActualHash: " << actual_hash << "\n";
87 if (!expected_hash.empty())
88 *output_ << "\nExpectedHash: " << expected_hash << "\n";
89 }
90
PrintImageBlock(const std::vector<unsigned char> & png_image)91 void WebKitTestResultPrinter::PrintImageBlock(
92 const std::vector<unsigned char>& png_image) {
93 if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
94 return;
95 *output_ << "Content-Type: image/png\n";
96 if (encode_binary_data_) {
97 PrintEncodedBinaryData(png_image);
98 return;
99 }
100
101 *output_ << "Content-Length: " << png_image.size() << "\n";
102 output_->write(
103 reinterpret_cast<const char*>(&png_image[0]), png_image.size());
104 }
105
PrintImageFooter()106 void WebKitTestResultPrinter::PrintImageFooter() {
107 if (state_ != IN_IMAGE_BLOCK)
108 return;
109 if (!capture_text_only_) {
110 *output_ << "#EOF\n";
111 output_->flush();
112 }
113 state_ = AFTER_TEST;
114 }
115
PrintAudioHeader()116 void WebKitTestResultPrinter::PrintAudioHeader() {
117 DCHECK_EQ(state_, DURING_TEST);
118 if (!capture_text_only_)
119 *output_ << "Content-Type: audio/wav\n";
120 state_ = IN_AUDIO_BLOCK;
121 }
122
PrintAudioBlock(const std::vector<unsigned char> & audio_data)123 void WebKitTestResultPrinter::PrintAudioBlock(
124 const std::vector<unsigned char>& audio_data) {
125 if (state_ != IN_AUDIO_BLOCK || capture_text_only_)
126 return;
127 if (encode_binary_data_) {
128 PrintEncodedBinaryData(audio_data);
129 return;
130 }
131
132 *output_ << "Content-Length: " << audio_data.size() << "\n";
133 output_->write(
134 reinterpret_cast<const char*>(&audio_data[0]), audio_data.size());
135 }
136
PrintAudioFooter()137 void WebKitTestResultPrinter::PrintAudioFooter() {
138 if (state_ != IN_AUDIO_BLOCK)
139 return;
140 if (!capture_text_only_) {
141 *output_ << "#EOF\n";
142 output_->flush();
143 }
144 state_ = IN_IMAGE_BLOCK;
145 }
146
AddMessage(const std::string & message)147 void WebKitTestResultPrinter::AddMessage(const std::string& message) {
148 AddMessageRaw(message + "\n");
149 }
150
AddMessageRaw(const std::string & message)151 void WebKitTestResultPrinter::AddMessageRaw(const std::string& message) {
152 if (state_ != DURING_TEST)
153 return;
154 *output_ << message;
155 }
156
AddErrorMessage(const std::string & message)157 void WebKitTestResultPrinter::AddErrorMessage(const std::string& message) {
158 if (!capture_text_only_)
159 *error_ << message << "\n";
160 if (state_ != DURING_TEST)
161 return;
162 PrintTextHeader();
163 *output_ << message << "\n";
164 PrintTextFooter();
165 PrintImageFooter();
166 }
167
PrintEncodedBinaryData(const std::vector<unsigned char> & data)168 void WebKitTestResultPrinter::PrintEncodedBinaryData(
169 const std::vector<unsigned char>& data) {
170 *output_ << "Content-Transfer-Encoding: base64\n";
171
172 std::string data_base64;
173 base::Base64Encode(
174 base::StringPiece(reinterpret_cast<const char*>(&data[0]), data.size()),
175 &data_base64);
176
177 *output_ << "Content-Length: " << data_base64.length() << "\n";
178 output_->write(data_base64.c_str(), data_base64.length());
179 }
180
CloseStderr()181 void WebKitTestResultPrinter::CloseStderr() {
182 if (state_ != AFTER_TEST)
183 return;
184 if (!capture_text_only_) {
185 *error_ << "#EOF\n";
186 error_->flush();
187 }
188 }
189
190
191 // WebKitTestController -------------------------------------------------------
192
193 WebKitTestController* WebKitTestController::instance_ = NULL;
194
195 // static
Get()196 WebKitTestController* WebKitTestController::Get() {
197 DCHECK(instance_);
198 return instance_;
199 }
200
WebKitTestController()201 WebKitTestController::WebKitTestController()
202 : main_window_(NULL),
203 test_phase_(BETWEEN_TESTS),
204 is_leak_detection_enabled_(CommandLine::ForCurrentProcess()->HasSwitch(
205 switches::kEnableLeakDetection)),
206 crash_when_leak_found_(false) {
207 CHECK(!instance_);
208 instance_ = this;
209
210 if (is_leak_detection_enabled_) {
211 std::string switchValue =
212 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
213 switches::kEnableLeakDetection);
214 crash_when_leak_found_ = switchValue == switches::kCrashOnFailure;
215 }
216
217 printer_.reset(new WebKitTestResultPrinter(&std::cout, &std::cerr));
218 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEncodeBinary))
219 printer_->set_encode_binary_data(true);
220 registrar_.Add(this,
221 NOTIFICATION_RENDERER_PROCESS_CREATED,
222 NotificationService::AllSources());
223 GpuDataManager::GetInstance()->AddObserver(this);
224 ResetAfterLayoutTest();
225 }
226
~WebKitTestController()227 WebKitTestController::~WebKitTestController() {
228 DCHECK(CalledOnValidThread());
229 CHECK(instance_ == this);
230 CHECK(test_phase_ == BETWEEN_TESTS);
231 GpuDataManager::GetInstance()->RemoveObserver(this);
232 DiscardMainWindow();
233 instance_ = NULL;
234 }
235
PrepareForLayoutTest(const GURL & test_url,const base::FilePath & current_working_directory,bool enable_pixel_dumping,const std::string & expected_pixel_hash)236 bool WebKitTestController::PrepareForLayoutTest(
237 const GURL& test_url,
238 const base::FilePath& current_working_directory,
239 bool enable_pixel_dumping,
240 const std::string& expected_pixel_hash) {
241 DCHECK(CalledOnValidThread());
242 test_phase_ = DURING_TEST;
243 current_working_directory_ = current_working_directory;
244 enable_pixel_dumping_ = enable_pixel_dumping;
245 expected_pixel_hash_ = expected_pixel_hash;
246 test_url_ = test_url;
247 printer_->reset();
248 ShellBrowserContext* browser_context =
249 ShellContentBrowserClient::Get()->browser_context();
250 if (test_url.spec().find("compositing/") != std::string::npos)
251 is_compositing_test_ = true;
252 initial_size_ = gfx::Size(
253 Shell::kDefaultTestWindowWidthDip, Shell::kDefaultTestWindowHeightDip);
254 // The W3C SVG layout tests use a different size than the other layout tests.
255 if (test_url.spec().find("W3C-SVG-1.1") != std::string::npos)
256 initial_size_ = gfx::Size(kTestSVGWindowWidthDip, kTestSVGWindowHeightDip);
257 if (!main_window_) {
258 main_window_ = content::Shell::CreateNewWindow(
259 browser_context,
260 GURL(),
261 NULL,
262 MSG_ROUTING_NONE,
263 initial_size_);
264 WebContentsObserver::Observe(main_window_->web_contents());
265 send_configuration_to_next_host_ = true;
266 current_pid_ = base::kNullProcessId;
267 main_window_->LoadURL(test_url);
268 } else {
269 #if defined(OS_MACOSX)
270 // Shell::SizeTo is not implemented on all platforms.
271 main_window_->SizeTo(initial_size_);
272 #endif
273 main_window_->web_contents()->GetRenderViewHost()->GetView()
274 ->SetSize(initial_size_);
275 main_window_->web_contents()->GetRenderViewHost()->WasResized();
276 RenderViewHost* render_view_host =
277 main_window_->web_contents()->GetRenderViewHost();
278 WebPreferences prefs = render_view_host->GetWebkitPreferences();
279 OverrideWebkitPrefs(&prefs);
280 render_view_host->UpdateWebkitPreferences(prefs);
281 SendTestConfiguration();
282
283 NavigationController::LoadURLParams params(test_url);
284 params.transition_type = ui::PageTransitionFromInt(
285 ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
286 params.should_clear_history_list = true;
287 main_window_->web_contents()->GetController().LoadURLWithParams(params);
288 main_window_->web_contents()->Focus();
289 }
290 main_window_->web_contents()->GetRenderViewHost()->SetActive(true);
291 main_window_->web_contents()->GetRenderViewHost()->Focus();
292 return true;
293 }
294
ResetAfterLayoutTest()295 bool WebKitTestController::ResetAfterLayoutTest() {
296 DCHECK(CalledOnValidThread());
297 printer_->PrintTextFooter();
298 printer_->PrintImageFooter();
299 printer_->CloseStderr();
300 send_configuration_to_next_host_ = false;
301 test_phase_ = BETWEEN_TESTS;
302 is_compositing_test_ = false;
303 enable_pixel_dumping_ = false;
304 expected_pixel_hash_.clear();
305 test_url_ = GURL();
306 prefs_ = WebPreferences();
307 should_override_prefs_ = false;
308
309 #if defined(OS_ANDROID)
310 // Re-using the shell's main window on Android causes issues with networking
311 // requests never succeeding. See http://crbug.com/277652.
312 DiscardMainWindow();
313 #endif
314 return true;
315 }
316
SetTempPath(const base::FilePath & temp_path)317 void WebKitTestController::SetTempPath(const base::FilePath& temp_path) {
318 temp_path_ = temp_path;
319 }
320
RendererUnresponsive()321 void WebKitTestController::RendererUnresponsive() {
322 DCHECK(CalledOnValidThread());
323 LOG(WARNING) << "renderer unresponsive";
324 }
325
WorkerCrashed()326 void WebKitTestController::WorkerCrashed() {
327 DCHECK(CalledOnValidThread());
328 printer_->AddErrorMessage("#CRASHED - worker");
329 DiscardMainWindow();
330 }
331
OverrideWebkitPrefs(WebPreferences * prefs)332 void WebKitTestController::OverrideWebkitPrefs(WebPreferences* prefs) {
333 if (should_override_prefs_) {
334 *prefs = prefs_;
335 } else {
336 ApplyLayoutTestDefaultPreferences(prefs);
337 if (is_compositing_test_) {
338 CommandLine& command_line = *CommandLine::ForCurrentProcess();
339 if (!command_line.HasSwitch(switches::kDisableGpu))
340 prefs->accelerated_2d_canvas_enabled = true;
341 prefs->mock_scrollbars_enabled = true;
342 }
343 }
344 }
345
OpenURL(const GURL & url)346 void WebKitTestController::OpenURL(const GURL& url) {
347 if (test_phase_ != DURING_TEST)
348 return;
349
350 Shell::CreateNewWindow(main_window_->web_contents()->GetBrowserContext(),
351 url,
352 main_window_->web_contents()->GetSiteInstance(),
353 MSG_ROUTING_NONE,
354 gfx::Size());
355 }
356
TestFinishedInSecondaryWindow()357 void WebKitTestController::TestFinishedInSecondaryWindow() {
358 RenderViewHost* render_view_host =
359 main_window_->web_contents()->GetRenderViewHost();
360 render_view_host->Send(
361 new ShellViewMsg_NotifyDone(render_view_host->GetRoutingID()));
362 }
363
IsMainWindow(WebContents * web_contents) const364 bool WebKitTestController::IsMainWindow(WebContents* web_contents) const {
365 return main_window_ && web_contents == main_window_->web_contents();
366 }
367
OnMessageReceived(const IPC::Message & message)368 bool WebKitTestController::OnMessageReceived(const IPC::Message& message) {
369 DCHECK(CalledOnValidThread());
370 bool handled = true;
371 IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message)
372 IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage, OnPrintMessage)
373 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump)
374 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump)
375 IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump, OnAudioDump)
376 IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences,
377 OnOverridePreferences)
378 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished, OnTestFinished)
379 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ClearDevToolsLocalStorage,
380 OnClearDevToolsLocalStorage)
381 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools, OnShowDevTools)
382 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools, OnCloseDevTools)
383 IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset, OnGoToOffset)
384 IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload, OnReload)
385 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame, OnLoadURLForFrame)
386 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory,
387 OnCaptureSessionHistory)
388 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows,
389 OnCloseRemainingWindows)
390 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone)
391 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LeakDetectionDone, OnLeakDetectionDone)
392 IPC_MESSAGE_UNHANDLED(handled = false)
393 IPC_END_MESSAGE_MAP()
394
395 return handled;
396 }
397
PluginCrashed(const base::FilePath & plugin_path,base::ProcessId plugin_pid)398 void WebKitTestController::PluginCrashed(const base::FilePath& plugin_path,
399 base::ProcessId plugin_pid) {
400 DCHECK(CalledOnValidThread());
401 printer_->AddErrorMessage(
402 base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid));
403 base::MessageLoop::current()->PostTask(
404 FROM_HERE,
405 base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow),
406 base::Unretained(this)));
407 }
408
RenderViewCreated(RenderViewHost * render_view_host)409 void WebKitTestController::RenderViewCreated(RenderViewHost* render_view_host) {
410 DCHECK(CalledOnValidThread());
411 // Might be kNullProcessHandle, in which case we will receive a notification
412 // later when the RenderProcessHost was created.
413 if (render_view_host->GetProcess()->GetHandle() != base::kNullProcessHandle)
414 current_pid_ = base::GetProcId(render_view_host->GetProcess()->GetHandle());
415 if (!send_configuration_to_next_host_)
416 return;
417 send_configuration_to_next_host_ = false;
418 SendTestConfiguration();
419 }
420
RenderProcessGone(base::TerminationStatus status)421 void WebKitTestController::RenderProcessGone(base::TerminationStatus status) {
422 DCHECK(CalledOnValidThread());
423 if (current_pid_ != base::kNullProcessId) {
424 printer_->AddErrorMessage(std::string("#CRASHED - renderer (pid ") +
425 base::IntToString(current_pid_) + ")");
426 } else {
427 printer_->AddErrorMessage("#CRASHED - renderer");
428 }
429 DiscardMainWindow();
430 }
431
DevToolsProcessCrashed()432 void WebKitTestController::DevToolsProcessCrashed() {
433 DCHECK(CalledOnValidThread());
434 printer_->AddErrorMessage("#CRASHED - devtools");
435 DiscardMainWindow();
436 }
437
WebContentsDestroyed()438 void WebKitTestController::WebContentsDestroyed() {
439 DCHECK(CalledOnValidThread());
440 printer_->AddErrorMessage("FAIL: main window was destroyed");
441 DiscardMainWindow();
442 }
443
Observe(int type,const NotificationSource & source,const NotificationDetails & details)444 void WebKitTestController::Observe(int type,
445 const NotificationSource& source,
446 const NotificationDetails& details) {
447 DCHECK(CalledOnValidThread());
448 switch (type) {
449 case NOTIFICATION_RENDERER_PROCESS_CREATED: {
450 if (!main_window_)
451 return;
452 RenderViewHost* render_view_host =
453 main_window_->web_contents()->GetRenderViewHost();
454 if (!render_view_host)
455 return;
456 RenderProcessHost* render_process_host =
457 Source<RenderProcessHost>(source).ptr();
458 if (render_process_host != render_view_host->GetProcess())
459 return;
460 current_pid_ = base::GetProcId(render_process_host->GetHandle());
461 break;
462 }
463 default:
464 NOTREACHED();
465 }
466 }
467
OnGpuProcessCrashed(base::TerminationStatus exit_code)468 void WebKitTestController::OnGpuProcessCrashed(
469 base::TerminationStatus exit_code) {
470 DCHECK(CalledOnValidThread());
471 printer_->AddErrorMessage("#CRASHED - gpu");
472 DiscardMainWindow();
473 }
474
DiscardMainWindow()475 void WebKitTestController::DiscardMainWindow() {
476 // If we're running a test, we need to close all windows and exit the message
477 // loop. Otherwise, we're already outside of the message loop, and we just
478 // discard the main window.
479 WebContentsObserver::Observe(NULL);
480 if (test_phase_ != BETWEEN_TESTS) {
481 Shell::CloseAllWindows();
482 base::MessageLoop::current()->PostTask(FROM_HERE,
483 base::MessageLoop::QuitClosure());
484 test_phase_ = CLEAN_UP;
485 } else if (main_window_) {
486 main_window_->Close();
487 }
488 main_window_ = NULL;
489 current_pid_ = base::kNullProcessId;
490 }
491
SendTestConfiguration()492 void WebKitTestController::SendTestConfiguration() {
493 RenderViewHost* render_view_host =
494 main_window_->web_contents()->GetRenderViewHost();
495 ShellTestConfiguration params;
496 params.current_working_directory = current_working_directory_;
497 params.temp_path = temp_path_;
498 params.test_url = test_url_;
499 params.enable_pixel_dumping = enable_pixel_dumping_;
500 params.allow_external_pages = CommandLine::ForCurrentProcess()->HasSwitch(
501 switches::kAllowExternalPages);
502 params.expected_pixel_hash = expected_pixel_hash_;
503 params.initial_size = initial_size_;
504 render_view_host->Send(new ShellViewMsg_SetTestConfiguration(
505 render_view_host->GetRoutingID(), params));
506 }
507
OnTestFinished()508 void WebKitTestController::OnTestFinished() {
509 test_phase_ = CLEAN_UP;
510 if (!printer_->output_finished())
511 printer_->PrintImageFooter();
512 RenderViewHost* render_view_host =
513 main_window_->web_contents()->GetRenderViewHost();
514 base::MessageLoop::current()->PostTask(
515 FROM_HERE,
516 base::Bind(base::IgnoreResult(&WebKitTestController::Send),
517 base::Unretained(this),
518 new ShellViewMsg_Reset(render_view_host->GetRoutingID())));
519 }
520
OnImageDump(const std::string & actual_pixel_hash,const SkBitmap & image)521 void WebKitTestController::OnImageDump(
522 const std::string& actual_pixel_hash,
523 const SkBitmap& image) {
524 SkAutoLockPixels image_lock(image);
525
526 printer_->PrintImageHeader(actual_pixel_hash, expected_pixel_hash_);
527
528 // Only encode and dump the png if the hashes don't match. Encoding the
529 // image is really expensive.
530 if (actual_pixel_hash != expected_pixel_hash_) {
531 std::vector<unsigned char> png;
532
533 // Only the expected PNGs for Mac have a valid alpha channel.
534 #if defined(OS_MACOSX)
535 bool discard_transparency = false;
536 #else
537 bool discard_transparency = true;
538 #endif
539 if (CommandLine::ForCurrentProcess()->HasSwitch(
540 switches::kEnableOverlayFullscreenVideo))
541 discard_transparency = false;
542
543 std::vector<gfx::PNGCodec::Comment> comments;
544 comments.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash));
545 bool success = gfx::PNGCodec::Encode(
546 static_cast<const unsigned char*>(image.getPixels()),
547 gfx::PNGCodec::FORMAT_BGRA,
548 gfx::Size(image.width(), image.height()),
549 static_cast<int>(image.rowBytes()),
550 discard_transparency,
551 comments,
552 &png);
553 if (success)
554 printer_->PrintImageBlock(png);
555 }
556 printer_->PrintImageFooter();
557 }
558
OnAudioDump(const std::vector<unsigned char> & dump)559 void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) {
560 printer_->PrintAudioHeader();
561 printer_->PrintAudioBlock(dump);
562 printer_->PrintAudioFooter();
563 }
564
OnTextDump(const std::string & dump)565 void WebKitTestController::OnTextDump(const std::string& dump) {
566 printer_->PrintTextHeader();
567 printer_->PrintTextBlock(dump);
568 printer_->PrintTextFooter();
569 }
570
OnPrintMessage(const std::string & message)571 void WebKitTestController::OnPrintMessage(const std::string& message) {
572 printer_->AddMessageRaw(message);
573 }
574
OnOverridePreferences(const WebPreferences & prefs)575 void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) {
576 should_override_prefs_ = true;
577 prefs_ = prefs;
578 }
579
OnClearDevToolsLocalStorage()580 void WebKitTestController::OnClearDevToolsLocalStorage() {
581 ShellBrowserContext* browser_context =
582 ShellContentBrowserClient::Get()->browser_context();
583 StoragePartition* storage_partition =
584 BrowserContext::GetStoragePartition(browser_context, NULL);
585 storage_partition->GetDOMStorageContext()->DeleteLocalStorage(
586 content::GetDevToolsPathAsURL("", "").GetOrigin());
587 }
588
OnShowDevTools(const std::string & settings,const std::string & frontend_url)589 void WebKitTestController::OnShowDevTools(const std::string& settings,
590 const std::string& frontend_url) {
591 main_window_->ShowDevToolsForTest(settings, frontend_url);
592 }
593
OnCloseDevTools()594 void WebKitTestController::OnCloseDevTools() {
595 main_window_->CloseDevTools();
596 }
597
OnGoToOffset(int offset)598 void WebKitTestController::OnGoToOffset(int offset) {
599 main_window_->GoBackOrForward(offset);
600 }
601
OnReload()602 void WebKitTestController::OnReload() {
603 main_window_->Reload();
604 }
605
OnLoadURLForFrame(const GURL & url,const std::string & frame_name)606 void WebKitTestController::OnLoadURLForFrame(const GURL& url,
607 const std::string& frame_name) {
608 main_window_->LoadURLForFrame(url, frame_name);
609 }
610
OnCaptureSessionHistory()611 void WebKitTestController::OnCaptureSessionHistory() {
612 std::vector<int> routing_ids;
613 std::vector<std::vector<PageState> > session_histories;
614 std::vector<unsigned> current_entry_indexes;
615
616 RenderViewHost* render_view_host =
617 main_window_->web_contents()->GetRenderViewHost();
618
619 for (std::vector<Shell*>::iterator window = Shell::windows().begin();
620 window != Shell::windows().end();
621 ++window) {
622 WebContents* web_contents = (*window)->web_contents();
623 // Only capture the history from windows in the same process as the main
624 // window. During layout tests, we only use two processes when an
625 // devtools window is open. This should not happen during history navigation
626 // tests.
627 if (render_view_host->GetProcess() !=
628 web_contents->GetRenderViewHost()->GetProcess()) {
629 NOTREACHED();
630 continue;
631 }
632 routing_ids.push_back(web_contents->GetRenderViewHost()->GetRoutingID());
633 current_entry_indexes.push_back(
634 web_contents->GetController().GetCurrentEntryIndex());
635 std::vector<PageState> history;
636 for (int entry = 0; entry < web_contents->GetController().GetEntryCount();
637 ++entry) {
638 PageState state = web_contents->GetController().GetEntryAtIndex(entry)->
639 GetPageState();
640 if (!state.IsValid()) {
641 state = PageState::CreateFromURL(
642 web_contents->GetController().GetEntryAtIndex(entry)->GetURL());
643 }
644 history.push_back(state);
645 }
646 session_histories.push_back(history);
647 }
648
649 Send(new ShellViewMsg_SessionHistory(render_view_host->GetRoutingID(),
650 routing_ids,
651 session_histories,
652 current_entry_indexes));
653 }
654
OnCloseRemainingWindows()655 void WebKitTestController::OnCloseRemainingWindows() {
656 DevToolsAgentHost::DetachAllClients();
657 std::vector<Shell*> open_windows(Shell::windows());
658 for (size_t i = 0; i < open_windows.size(); ++i) {
659 if (open_windows[i] != main_window_)
660 open_windows[i]->Close();
661 }
662 base::MessageLoop::current()->RunUntilIdle();
663 }
664
OnResetDone()665 void WebKitTestController::OnResetDone() {
666 if (is_leak_detection_enabled_) {
667 if (main_window_ && main_window_->web_contents()) {
668 RenderViewHost* render_view_host =
669 main_window_->web_contents()->GetRenderViewHost();
670 render_view_host->Send(
671 new ShellViewMsg_TryLeakDetection(render_view_host->GetRoutingID()));
672 }
673 return;
674 }
675
676 base::MessageLoop::current()->PostTask(FROM_HERE,
677 base::MessageLoop::QuitClosure());
678 }
679
OnLeakDetectionDone(const LeakDetectionResult & result)680 void WebKitTestController::OnLeakDetectionDone(
681 const LeakDetectionResult& result) {
682 if (!result.leaked) {
683 base::MessageLoop::current()->PostTask(FROM_HERE,
684 base::MessageLoop::QuitClosure());
685 return;
686 }
687
688 printer_->AddErrorMessage(
689 base::StringPrintf("#LEAK - renderer pid %d (%s)", current_pid_,
690 result.detail.c_str()));
691 CHECK(!crash_when_leak_found_);
692
693 DiscardMainWindow();
694 }
695
696 } // namespace content
697