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 "content/shell/browser/webkit_test_controller.h"
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/layout_test/layout_test_devtools_frontend.h"
30 #include "content/shell/browser/shell.h"
31 #include "content/shell/browser/shell_browser_context.h"
32 #include "content/shell/browser/shell_content_browser_client.h"
33 #include "content/shell/browser/shell_devtools_frontend.h"
34 #include "content/shell/common/shell_messages.h"
35 #include "content/shell/common/shell_switches.h"
36 #include "content/shell/common/webkit_test_helpers.h"
37 #include "ui/gfx/codec/png_codec.h"
41 const int kTestSVGWindowWidthDip
= 480;
42 const int kTestSVGWindowHeightDip
= 360;
44 // WebKitTestResultPrinter ----------------------------------------------------
46 WebKitTestResultPrinter::WebKitTestResultPrinter(
47 std::ostream
* output
, std::ostream
* error
)
48 : state_(DURING_TEST
),
49 capture_text_only_(false),
50 encode_binary_data_(false),
55 WebKitTestResultPrinter::~WebKitTestResultPrinter() {
58 void WebKitTestResultPrinter::PrintTextHeader() {
59 if (state_
!= DURING_TEST
)
61 if (!capture_text_only_
)
62 *output_
<< "Content-Type: text/plain\n";
63 state_
= IN_TEXT_BLOCK
;
66 void WebKitTestResultPrinter::PrintTextBlock(const std::string
& block
) {
67 if (state_
!= IN_TEXT_BLOCK
)
72 void WebKitTestResultPrinter::PrintTextFooter() {
73 if (state_
!= IN_TEXT_BLOCK
)
75 if (!capture_text_only_
) {
79 state_
= IN_IMAGE_BLOCK
;
82 void WebKitTestResultPrinter::PrintImageHeader(
83 const std::string
& actual_hash
,
84 const std::string
& expected_hash
) {
85 if (state_
!= IN_IMAGE_BLOCK
|| capture_text_only_
)
87 *output_
<< "\nActualHash: " << actual_hash
<< "\n";
88 if (!expected_hash
.empty())
89 *output_
<< "\nExpectedHash: " << expected_hash
<< "\n";
92 void WebKitTestResultPrinter::PrintImageBlock(
93 const std::vector
<unsigned char>& png_image
) {
94 if (state_
!= IN_IMAGE_BLOCK
|| capture_text_only_
)
96 *output_
<< "Content-Type: image/png\n";
97 if (encode_binary_data_
) {
98 PrintEncodedBinaryData(png_image
);
102 *output_
<< "Content-Length: " << png_image
.size() << "\n";
104 reinterpret_cast<const char*>(&png_image
[0]), png_image
.size());
107 void WebKitTestResultPrinter::PrintImageFooter() {
108 if (state_
!= IN_IMAGE_BLOCK
)
110 if (!capture_text_only_
) {
111 *output_
<< "#EOF\n";
117 void WebKitTestResultPrinter::PrintAudioHeader() {
118 DCHECK_EQ(state_
, DURING_TEST
);
119 if (!capture_text_only_
)
120 *output_
<< "Content-Type: audio/wav\n";
121 state_
= IN_AUDIO_BLOCK
;
124 void WebKitTestResultPrinter::PrintAudioBlock(
125 const std::vector
<unsigned char>& audio_data
) {
126 if (state_
!= IN_AUDIO_BLOCK
|| capture_text_only_
)
128 if (encode_binary_data_
) {
129 PrintEncodedBinaryData(audio_data
);
133 *output_
<< "Content-Length: " << audio_data
.size() << "\n";
135 reinterpret_cast<const char*>(&audio_data
[0]), audio_data
.size());
138 void WebKitTestResultPrinter::PrintAudioFooter() {
139 if (state_
!= IN_AUDIO_BLOCK
)
141 if (!capture_text_only_
) {
142 *output_
<< "#EOF\n";
145 state_
= IN_IMAGE_BLOCK
;
148 void WebKitTestResultPrinter::AddMessage(const std::string
& message
) {
149 AddMessageRaw(message
+ "\n");
152 void WebKitTestResultPrinter::AddMessageRaw(const std::string
& message
) {
153 if (state_
!= DURING_TEST
)
158 void WebKitTestResultPrinter::AddErrorMessage(const std::string
& message
) {
159 if (!capture_text_only_
)
160 *error_
<< message
<< "\n";
161 if (state_
!= DURING_TEST
)
164 *output_
<< message
<< "\n";
169 void WebKitTestResultPrinter::PrintEncodedBinaryData(
170 const std::vector
<unsigned char>& data
) {
171 *output_
<< "Content-Transfer-Encoding: base64\n";
173 std::string data_base64
;
175 base::StringPiece(reinterpret_cast<const char*>(&data
[0]), data
.size()),
178 *output_
<< "Content-Length: " << data_base64
.length() << "\n";
179 output_
->write(data_base64
.c_str(), data_base64
.length());
182 void WebKitTestResultPrinter::CloseStderr() {
183 if (state_
!= AFTER_TEST
)
185 if (!capture_text_only_
) {
192 // WebKitTestController -------------------------------------------------------
194 WebKitTestController
* WebKitTestController::instance_
= NULL
;
197 WebKitTestController
* WebKitTestController::Get() {
202 WebKitTestController::WebKitTestController()
203 : main_window_(NULL
),
204 test_phase_(BETWEEN_TESTS
),
205 is_leak_detection_enabled_(
206 base::CommandLine::ForCurrentProcess()->HasSwitch(
207 switches::kEnableLeakDetection
)),
208 crash_when_leak_found_(false),
209 devtools_frontend_(NULL
) {
213 if (is_leak_detection_enabled_
) {
214 std::string switchValue
=
215 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
216 switches::kEnableLeakDetection
);
217 crash_when_leak_found_
= switchValue
== switches::kCrashOnFailure
;
220 printer_
.reset(new WebKitTestResultPrinter(&std::cout
, &std::cerr
));
221 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
222 switches::kEncodeBinary
))
223 printer_
->set_encode_binary_data(true);
225 NOTIFICATION_RENDERER_PROCESS_CREATED
,
226 NotificationService::AllSources());
227 GpuDataManager::GetInstance()->AddObserver(this);
228 ResetAfterLayoutTest();
231 WebKitTestController::~WebKitTestController() {
232 DCHECK(CalledOnValidThread());
233 CHECK(instance_
== this);
234 CHECK(test_phase_
== BETWEEN_TESTS
);
235 GpuDataManager::GetInstance()->RemoveObserver(this);
240 bool WebKitTestController::PrepareForLayoutTest(
241 const GURL
& test_url
,
242 const base::FilePath
& current_working_directory
,
243 bool enable_pixel_dumping
,
244 const std::string
& expected_pixel_hash
) {
245 DCHECK(CalledOnValidThread());
246 test_phase_
= DURING_TEST
;
247 current_working_directory_
= current_working_directory
;
248 enable_pixel_dumping_
= enable_pixel_dumping
;
249 expected_pixel_hash_
= expected_pixel_hash
;
250 test_url_
= test_url
;
252 ShellBrowserContext
* browser_context
=
253 ShellContentBrowserClient::Get()->browser_context();
254 if (test_url
.spec().find("compositing/") != std::string::npos
)
255 is_compositing_test_
= true;
256 initial_size_
= Shell::GetShellDefaultSize();
257 // The W3C SVG layout tests use a different size than the other layout tests.
258 if (test_url
.spec().find("W3C-SVG-1.1") != std::string::npos
)
259 initial_size_
= gfx::Size(kTestSVGWindowWidthDip
, kTestSVGWindowHeightDip
);
261 main_window_
= content::Shell::CreateNewWindow(
266 WebContentsObserver::Observe(main_window_
->web_contents());
267 send_configuration_to_next_host_
= true;
268 current_pid_
= base::kNullProcessId
;
269 main_window_
->LoadURL(test_url
);
271 #if defined(OS_MACOSX)
272 // Shell::SizeTo is not implemented on all platforms.
273 main_window_
->SizeTo(initial_size_
);
275 main_window_
->web_contents()->GetRenderViewHost()->GetView()
276 ->SetSize(initial_size_
);
277 main_window_
->web_contents()->GetRenderViewHost()->WasResized();
278 RenderViewHost
* render_view_host
=
279 main_window_
->web_contents()->GetRenderViewHost();
280 WebPreferences prefs
= render_view_host
->GetWebkitPreferences();
281 OverrideWebkitPrefs(&prefs
);
282 render_view_host
->UpdateWebkitPreferences(prefs
);
283 SendTestConfiguration();
285 NavigationController::LoadURLParams
params(test_url
);
286 params
.transition_type
= ui::PageTransitionFromInt(
287 ui::PAGE_TRANSITION_TYPED
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
);
288 params
.should_clear_history_list
= true;
289 main_window_
->web_contents()->GetController().LoadURLWithParams(params
);
290 main_window_
->web_contents()->Focus();
292 main_window_
->web_contents()->GetRenderViewHost()->SetActive(true);
293 main_window_
->web_contents()->GetRenderViewHost()->Focus();
297 bool WebKitTestController::ResetAfterLayoutTest() {
298 DCHECK(CalledOnValidThread());
299 printer_
->PrintTextFooter();
300 printer_
->PrintImageFooter();
301 printer_
->CloseStderr();
302 send_configuration_to_next_host_
= false;
303 test_phase_
= BETWEEN_TESTS
;
304 is_compositing_test_
= false;
305 enable_pixel_dumping_
= false;
306 expected_pixel_hash_
.clear();
308 prefs_
= WebPreferences();
309 should_override_prefs_
= false;
311 #if defined(OS_ANDROID)
312 // Re-using the shell's main window on Android causes issues with networking
313 // requests never succeeding. See http://crbug.com/277652.
319 void WebKitTestController::SetTempPath(const base::FilePath
& temp_path
) {
320 temp_path_
= temp_path
;
323 void WebKitTestController::RendererUnresponsive() {
324 DCHECK(CalledOnValidThread());
325 LOG(WARNING
) << "renderer unresponsive";
328 void WebKitTestController::WorkerCrashed() {
329 DCHECK(CalledOnValidThread());
330 printer_
->AddErrorMessage("#CRASHED - worker");
334 void WebKitTestController::OverrideWebkitPrefs(WebPreferences
* prefs
) {
335 if (should_override_prefs_
) {
338 ApplyLayoutTestDefaultPreferences(prefs
);
339 if (is_compositing_test_
) {
340 base::CommandLine
& command_line
= *base::CommandLine::ForCurrentProcess();
341 if (!command_line
.HasSwitch(switches::kDisableGpu
))
342 prefs
->accelerated_2d_canvas_enabled
= true;
343 prefs
->mock_scrollbars_enabled
= true;
348 void WebKitTestController::OpenURL(const GURL
& url
) {
349 if (test_phase_
!= DURING_TEST
)
352 Shell::CreateNewWindow(main_window_
->web_contents()->GetBrowserContext(),
354 main_window_
->web_contents()->GetSiteInstance(),
358 void WebKitTestController::TestFinishedInSecondaryWindow() {
359 RenderViewHost
* render_view_host
=
360 main_window_
->web_contents()->GetRenderViewHost();
361 render_view_host
->Send(
362 new ShellViewMsg_NotifyDone(render_view_host
->GetRoutingID()));
365 bool WebKitTestController::IsMainWindow(WebContents
* web_contents
) const {
366 return main_window_
&& web_contents
== main_window_
->web_contents();
369 bool WebKitTestController::OnMessageReceived(const IPC::Message
& message
) {
370 DCHECK(CalledOnValidThread());
372 IPC_BEGIN_MESSAGE_MAP(WebKitTestController
, message
)
373 IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage
, OnPrintMessage
)
374 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump
, OnTextDump
)
375 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump
, OnImageDump
)
376 IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump
, OnAudioDump
)
377 IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences
,
378 OnOverridePreferences
)
379 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished
, OnTestFinished
)
380 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ClearDevToolsLocalStorage
,
381 OnClearDevToolsLocalStorage
)
382 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools
, OnShowDevTools
)
383 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools
, OnCloseDevTools
)
384 IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset
, OnGoToOffset
)
385 IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload
, OnReload
)
386 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame
, OnLoadURLForFrame
)
387 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory
,
388 OnCaptureSessionHistory
)
389 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows
,
390 OnCloseRemainingWindows
)
391 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone
, OnResetDone
)
392 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LeakDetectionDone
, OnLeakDetectionDone
)
393 IPC_MESSAGE_UNHANDLED(handled
= false)
394 IPC_END_MESSAGE_MAP()
399 void WebKitTestController::PluginCrashed(const base::FilePath
& plugin_path
,
400 base::ProcessId plugin_pid
) {
401 DCHECK(CalledOnValidThread());
402 printer_
->AddErrorMessage(
403 base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid
));
404 base::MessageLoop::current()->PostTask(
406 base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow
),
407 base::Unretained(this)));
410 void WebKitTestController::RenderViewCreated(RenderViewHost
* render_view_host
) {
411 DCHECK(CalledOnValidThread());
412 // Might be kNullProcessHandle, in which case we will receive a notification
413 // later when the RenderProcessHost was created.
414 if (render_view_host
->GetProcess()->GetHandle() != base::kNullProcessHandle
)
415 current_pid_
= base::GetProcId(render_view_host
->GetProcess()->GetHandle());
416 if (!send_configuration_to_next_host_
)
418 send_configuration_to_next_host_
= false;
419 SendTestConfiguration();
422 void WebKitTestController::RenderProcessGone(base::TerminationStatus status
) {
423 DCHECK(CalledOnValidThread());
424 if (current_pid_
!= base::kNullProcessId
) {
425 printer_
->AddErrorMessage(std::string("#CRASHED - renderer (pid ") +
426 base::IntToString(current_pid_
) + ")");
428 printer_
->AddErrorMessage("#CRASHED - renderer");
433 void WebKitTestController::DevToolsProcessCrashed() {
434 DCHECK(CalledOnValidThread());
435 printer_
->AddErrorMessage("#CRASHED - devtools");
436 if (devtools_frontend_
)
437 devtools_frontend_
->Close();
438 devtools_frontend_
= NULL
;
441 void WebKitTestController::WebContentsDestroyed() {
442 DCHECK(CalledOnValidThread());
443 printer_
->AddErrorMessage("FAIL: main window was destroyed");
447 void WebKitTestController::Observe(int type
,
448 const NotificationSource
& source
,
449 const NotificationDetails
& details
) {
450 DCHECK(CalledOnValidThread());
452 case NOTIFICATION_RENDERER_PROCESS_CREATED
: {
455 RenderViewHost
* render_view_host
=
456 main_window_
->web_contents()->GetRenderViewHost();
457 if (!render_view_host
)
459 RenderProcessHost
* render_process_host
=
460 Source
<RenderProcessHost
>(source
).ptr();
461 if (render_process_host
!= render_view_host
->GetProcess())
463 current_pid_
= base::GetProcId(render_process_host
->GetHandle());
471 void WebKitTestController::OnGpuProcessCrashed(
472 base::TerminationStatus exit_code
) {
473 DCHECK(CalledOnValidThread());
474 printer_
->AddErrorMessage("#CRASHED - gpu");
478 void WebKitTestController::DiscardMainWindow() {
479 // If we're running a test, we need to close all windows and exit the message
480 // loop. Otherwise, we're already outside of the message loop, and we just
481 // discard the main window.
482 WebContentsObserver::Observe(NULL
);
483 if (test_phase_
!= BETWEEN_TESTS
) {
484 Shell::CloseAllWindows();
485 base::MessageLoop::current()->PostTask(FROM_HERE
,
486 base::MessageLoop::QuitClosure());
487 test_phase_
= CLEAN_UP
;
488 } else if (main_window_
) {
489 main_window_
->Close();
492 current_pid_
= base::kNullProcessId
;
495 void WebKitTestController::SendTestConfiguration() {
496 RenderViewHost
* render_view_host
=
497 main_window_
->web_contents()->GetRenderViewHost();
498 ShellTestConfiguration params
;
499 params
.current_working_directory
= current_working_directory_
;
500 params
.temp_path
= temp_path_
;
501 params
.test_url
= test_url_
;
502 params
.enable_pixel_dumping
= enable_pixel_dumping_
;
503 params
.allow_external_pages
=
504 base::CommandLine::ForCurrentProcess()->HasSwitch(
505 switches::kAllowExternalPages
);
506 params
.expected_pixel_hash
= expected_pixel_hash_
;
507 params
.initial_size
= initial_size_
;
508 render_view_host
->Send(new ShellViewMsg_SetTestConfiguration(
509 render_view_host
->GetRoutingID(), params
));
512 void WebKitTestController::OnTestFinished() {
513 test_phase_
= CLEAN_UP
;
514 if (!printer_
->output_finished())
515 printer_
->PrintImageFooter();
516 RenderViewHost
* render_view_host
=
517 main_window_
->web_contents()->GetRenderViewHost();
518 main_window_
->web_contents()->ExitFullscreen();
519 base::MessageLoop::current()->PostTask(
521 base::Bind(base::IgnoreResult(&WebKitTestController::Send
),
522 base::Unretained(this),
523 new ShellViewMsg_Reset(render_view_host
->GetRoutingID())));
526 void WebKitTestController::OnImageDump(
527 const std::string
& actual_pixel_hash
,
528 const SkBitmap
& image
) {
529 SkAutoLockPixels
image_lock(image
);
531 printer_
->PrintImageHeader(actual_pixel_hash
, expected_pixel_hash_
);
533 // Only encode and dump the png if the hashes don't match. Encoding the
534 // image is really expensive.
535 if (actual_pixel_hash
!= expected_pixel_hash_
) {
536 std::vector
<unsigned char> png
;
538 bool discard_transparency
= true;
539 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
540 switches::kEnableOverlayFullscreenVideo
))
541 discard_transparency
= false;
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
,
554 printer_
->PrintImageBlock(png
);
556 printer_
->PrintImageFooter();
559 void WebKitTestController::OnAudioDump(const std::vector
<unsigned char>& dump
) {
560 printer_
->PrintAudioHeader();
561 printer_
->PrintAudioBlock(dump
);
562 printer_
->PrintAudioFooter();
565 void WebKitTestController::OnTextDump(const std::string
& dump
) {
566 printer_
->PrintTextHeader();
567 printer_
->PrintTextBlock(dump
);
568 printer_
->PrintTextFooter();
571 void WebKitTestController::OnPrintMessage(const std::string
& message
) {
572 printer_
->AddMessageRaw(message
);
575 void WebKitTestController::OnOverridePreferences(const WebPreferences
& prefs
) {
576 should_override_prefs_
= true;
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::LayoutTestDevToolsFrontend::GetDevToolsPathAsURL("", "")
590 void WebKitTestController::OnShowDevTools(const std::string
& settings
,
591 const std::string
& frontend_url
) {
592 if (!devtools_frontend_
) {
593 devtools_frontend_
= LayoutTestDevToolsFrontend::Show(
594 main_window_
->web_contents(), settings
, frontend_url
);
596 devtools_frontend_
->ReuseFrontend(settings
, frontend_url
);
598 devtools_frontend_
->Activate();
599 devtools_frontend_
->Focus();
602 void WebKitTestController::OnCloseDevTools() {
603 if (devtools_frontend_
)
604 devtools_frontend_
->DisconnectFromTarget();
607 void WebKitTestController::OnGoToOffset(int offset
) {
608 main_window_
->GoBackOrForward(offset
);
611 void WebKitTestController::OnReload() {
612 main_window_
->Reload();
615 void WebKitTestController::OnLoadURLForFrame(const GURL
& url
,
616 const std::string
& frame_name
) {
617 main_window_
->LoadURLForFrame(url
, frame_name
);
620 void WebKitTestController::OnCaptureSessionHistory() {
621 std::vector
<int> routing_ids
;
622 std::vector
<std::vector
<PageState
> > session_histories
;
623 std::vector
<unsigned> current_entry_indexes
;
625 RenderViewHost
* render_view_host
=
626 main_window_
->web_contents()->GetRenderViewHost();
628 for (std::vector
<Shell
*>::iterator window
= Shell::windows().begin();
629 window
!= Shell::windows().end();
631 WebContents
* web_contents
= (*window
)->web_contents();
632 // Only capture the history from windows in the same process as the main
633 // window. During layout tests, we only use two processes when an
634 // devtools window is open. This should not happen during history navigation
636 if (render_view_host
->GetProcess() !=
637 web_contents
->GetRenderViewHost()->GetProcess()) {
641 routing_ids
.push_back(web_contents
->GetRenderViewHost()->GetRoutingID());
642 current_entry_indexes
.push_back(
643 web_contents
->GetController().GetCurrentEntryIndex());
644 std::vector
<PageState
> history
;
645 for (int entry
= 0; entry
< web_contents
->GetController().GetEntryCount();
647 PageState state
= web_contents
->GetController().GetEntryAtIndex(entry
)->
649 if (!state
.IsValid()) {
650 state
= PageState::CreateFromURL(
651 web_contents
->GetController().GetEntryAtIndex(entry
)->GetURL());
653 history
.push_back(state
);
655 session_histories
.push_back(history
);
658 Send(new ShellViewMsg_SessionHistory(render_view_host
->GetRoutingID(),
661 current_entry_indexes
));
664 void WebKitTestController::OnCloseRemainingWindows() {
665 DevToolsAgentHost::DetachAllClients();
666 std::vector
<Shell
*> open_windows(Shell::windows());
667 Shell
* devtools_shell
= devtools_frontend_
?
668 devtools_frontend_
->frontend_shell() : NULL
;
669 for (size_t i
= 0; i
< open_windows
.size(); ++i
) {
670 if (open_windows
[i
] != main_window_
&& open_windows
[i
] != devtools_shell
)
671 open_windows
[i
]->Close();
673 base::MessageLoop::current()->RunUntilIdle();
676 void WebKitTestController::OnResetDone() {
677 if (is_leak_detection_enabled_
) {
678 if (main_window_
&& main_window_
->web_contents()) {
679 RenderViewHost
* render_view_host
=
680 main_window_
->web_contents()->GetRenderViewHost();
681 render_view_host
->Send(
682 new ShellViewMsg_TryLeakDetection(render_view_host
->GetRoutingID()));
687 base::MessageLoop::current()->PostTask(FROM_HERE
,
688 base::MessageLoop::QuitClosure());
691 void WebKitTestController::OnLeakDetectionDone(
692 const LeakDetectionResult
& result
) {
693 if (!result
.leaked
) {
694 base::MessageLoop::current()->PostTask(FROM_HERE
,
695 base::MessageLoop::QuitClosure());
699 printer_
->AddErrorMessage(
700 base::StringPrintf("#LEAK - renderer pid %d (%s)", current_pid_
,
701 result
.detail
.c_str()));
702 CHECK(!crash_when_leak_found_
);
707 } // namespace content