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) {
212 if (is_leak_detection_enabled_
) {
213 std::string switchValue
=
214 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
215 switches::kEnableLeakDetection
);
216 crash_when_leak_found_
= switchValue
== switches::kCrashOnFailure
;
219 printer_
.reset(new WebKitTestResultPrinter(&std::cout
, &std::cerr
));
220 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
221 switches::kEncodeBinary
))
222 printer_
->set_encode_binary_data(true);
224 NOTIFICATION_RENDERER_PROCESS_CREATED
,
225 NotificationService::AllSources());
226 GpuDataManager::GetInstance()->AddObserver(this);
227 ResetAfterLayoutTest();
230 WebKitTestController::~WebKitTestController() {
231 DCHECK(CalledOnValidThread());
232 CHECK(instance_
== this);
233 CHECK(test_phase_
== BETWEEN_TESTS
);
234 GpuDataManager::GetInstance()->RemoveObserver(this);
239 bool WebKitTestController::PrepareForLayoutTest(
240 const GURL
& test_url
,
241 const base::FilePath
& current_working_directory
,
242 bool enable_pixel_dumping
,
243 const std::string
& expected_pixel_hash
) {
244 DCHECK(CalledOnValidThread());
245 test_phase_
= DURING_TEST
;
246 current_working_directory_
= current_working_directory
;
247 enable_pixel_dumping_
= enable_pixel_dumping
;
248 expected_pixel_hash_
= expected_pixel_hash
;
249 test_url_
= test_url
;
251 ShellBrowserContext
* browser_context
=
252 ShellContentBrowserClient::Get()->browser_context();
253 if (test_url
.spec().find("compositing/") != std::string::npos
)
254 is_compositing_test_
= true;
255 initial_size_
= gfx::Size(
256 Shell::kDefaultTestWindowWidthDip
, Shell::kDefaultTestWindowHeightDip
);
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");
439 void WebKitTestController::WebContentsDestroyed() {
440 DCHECK(CalledOnValidThread());
441 printer_
->AddErrorMessage("FAIL: main window was destroyed");
445 void WebKitTestController::Observe(int type
,
446 const NotificationSource
& source
,
447 const NotificationDetails
& details
) {
448 DCHECK(CalledOnValidThread());
450 case NOTIFICATION_RENDERER_PROCESS_CREATED
: {
453 RenderViewHost
* render_view_host
=
454 main_window_
->web_contents()->GetRenderViewHost();
455 if (!render_view_host
)
457 RenderProcessHost
* render_process_host
=
458 Source
<RenderProcessHost
>(source
).ptr();
459 if (render_process_host
!= render_view_host
->GetProcess())
461 current_pid_
= base::GetProcId(render_process_host
->GetHandle());
469 void WebKitTestController::OnGpuProcessCrashed(
470 base::TerminationStatus exit_code
) {
471 DCHECK(CalledOnValidThread());
472 printer_
->AddErrorMessage("#CRASHED - gpu");
476 void WebKitTestController::DiscardMainWindow() {
477 // If we're running a test, we need to close all windows and exit the message
478 // loop. Otherwise, we're already outside of the message loop, and we just
479 // discard the main window.
480 WebContentsObserver::Observe(NULL
);
481 if (test_phase_
!= BETWEEN_TESTS
) {
482 Shell::CloseAllWindows();
483 base::MessageLoop::current()->PostTask(FROM_HERE
,
484 base::MessageLoop::QuitClosure());
485 test_phase_
= CLEAN_UP
;
486 } else if (main_window_
) {
487 main_window_
->Close();
490 current_pid_
= base::kNullProcessId
;
493 void WebKitTestController::SendTestConfiguration() {
494 RenderViewHost
* render_view_host
=
495 main_window_
->web_contents()->GetRenderViewHost();
496 ShellTestConfiguration params
;
497 params
.current_working_directory
= current_working_directory_
;
498 params
.temp_path
= temp_path_
;
499 params
.test_url
= test_url_
;
500 params
.enable_pixel_dumping
= enable_pixel_dumping_
;
501 params
.allow_external_pages
=
502 base::CommandLine::ForCurrentProcess()->HasSwitch(
503 switches::kAllowExternalPages
);
504 params
.expected_pixel_hash
= expected_pixel_hash_
;
505 params
.initial_size
= initial_size_
;
506 render_view_host
->Send(new ShellViewMsg_SetTestConfiguration(
507 render_view_host
->GetRoutingID(), params
));
510 void WebKitTestController::OnTestFinished() {
511 test_phase_
= CLEAN_UP
;
512 if (!printer_
->output_finished())
513 printer_
->PrintImageFooter();
514 RenderViewHost
* render_view_host
=
515 main_window_
->web_contents()->GetRenderViewHost();
516 base::MessageLoop::current()->PostTask(
518 base::Bind(base::IgnoreResult(&WebKitTestController::Send
),
519 base::Unretained(this),
520 new ShellViewMsg_Reset(render_view_host
->GetRoutingID())));
523 void WebKitTestController::OnImageDump(
524 const std::string
& actual_pixel_hash
,
525 const SkBitmap
& image
) {
526 SkAutoLockPixels
image_lock(image
);
528 printer_
->PrintImageHeader(actual_pixel_hash
, expected_pixel_hash_
);
530 // Only encode and dump the png if the hashes don't match. Encoding the
531 // image is really expensive.
532 if (actual_pixel_hash
!= expected_pixel_hash_
) {
533 std::vector
<unsigned char> png
;
535 bool discard_transparency
= true;
536 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
537 switches::kEnableOverlayFullscreenVideo
))
538 discard_transparency
= false;
540 std::vector
<gfx::PNGCodec::Comment
> comments
;
541 comments
.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash
));
542 bool success
= gfx::PNGCodec::Encode(
543 static_cast<const unsigned char*>(image
.getPixels()),
544 gfx::PNGCodec::FORMAT_BGRA
,
545 gfx::Size(image
.width(), image
.height()),
546 static_cast<int>(image
.rowBytes()),
547 discard_transparency
,
551 printer_
->PrintImageBlock(png
);
553 printer_
->PrintImageFooter();
556 void WebKitTestController::OnAudioDump(const std::vector
<unsigned char>& dump
) {
557 printer_
->PrintAudioHeader();
558 printer_
->PrintAudioBlock(dump
);
559 printer_
->PrintAudioFooter();
562 void WebKitTestController::OnTextDump(const std::string
& dump
) {
563 printer_
->PrintTextHeader();
564 printer_
->PrintTextBlock(dump
);
565 printer_
->PrintTextFooter();
568 void WebKitTestController::OnPrintMessage(const std::string
& message
) {
569 printer_
->AddMessageRaw(message
);
572 void WebKitTestController::OnOverridePreferences(const WebPreferences
& prefs
) {
573 should_override_prefs_
= true;
577 void WebKitTestController::OnClearDevToolsLocalStorage() {
578 ShellBrowserContext
* browser_context
=
579 ShellContentBrowserClient::Get()->browser_context();
580 StoragePartition
* storage_partition
=
581 BrowserContext::GetStoragePartition(browser_context
, NULL
);
582 storage_partition
->GetDOMStorageContext()->DeleteLocalStorage(
583 content::LayoutTestDevToolsFrontend::GetDevToolsPathAsURL("", "")
587 void WebKitTestController::OnShowDevTools(const std::string
& settings
,
588 const std::string
& frontend_url
) {
589 main_window_
->ShowDevToolsForTest(settings
, frontend_url
);
592 void WebKitTestController::OnCloseDevTools() {
593 main_window_
->CloseDevTools();
596 void WebKitTestController::OnGoToOffset(int offset
) {
597 main_window_
->GoBackOrForward(offset
);
600 void WebKitTestController::OnReload() {
601 main_window_
->Reload();
604 void WebKitTestController::OnLoadURLForFrame(const GURL
& url
,
605 const std::string
& frame_name
) {
606 main_window_
->LoadURLForFrame(url
, frame_name
);
609 void WebKitTestController::OnCaptureSessionHistory() {
610 std::vector
<int> routing_ids
;
611 std::vector
<std::vector
<PageState
> > session_histories
;
612 std::vector
<unsigned> current_entry_indexes
;
614 RenderViewHost
* render_view_host
=
615 main_window_
->web_contents()->GetRenderViewHost();
617 for (std::vector
<Shell
*>::iterator window
= Shell::windows().begin();
618 window
!= Shell::windows().end();
620 WebContents
* web_contents
= (*window
)->web_contents();
621 // Only capture the history from windows in the same process as the main
622 // window. During layout tests, we only use two processes when an
623 // devtools window is open. This should not happen during history navigation
625 if (render_view_host
->GetProcess() !=
626 web_contents
->GetRenderViewHost()->GetProcess()) {
630 routing_ids
.push_back(web_contents
->GetRenderViewHost()->GetRoutingID());
631 current_entry_indexes
.push_back(
632 web_contents
->GetController().GetCurrentEntryIndex());
633 std::vector
<PageState
> history
;
634 for (int entry
= 0; entry
< web_contents
->GetController().GetEntryCount();
636 PageState state
= web_contents
->GetController().GetEntryAtIndex(entry
)->
638 if (!state
.IsValid()) {
639 state
= PageState::CreateFromURL(
640 web_contents
->GetController().GetEntryAtIndex(entry
)->GetURL());
642 history
.push_back(state
);
644 session_histories
.push_back(history
);
647 Send(new ShellViewMsg_SessionHistory(render_view_host
->GetRoutingID(),
650 current_entry_indexes
));
653 void WebKitTestController::OnCloseRemainingWindows() {
654 DevToolsAgentHost::DetachAllClients();
655 std::vector
<Shell
*> open_windows(Shell::windows());
656 for (size_t i
= 0; i
< open_windows
.size(); ++i
) {
657 if (open_windows
[i
] != main_window_
)
658 open_windows
[i
]->Close();
660 base::MessageLoop::current()->RunUntilIdle();
663 void WebKitTestController::OnResetDone() {
664 if (is_leak_detection_enabled_
) {
665 if (main_window_
&& main_window_
->web_contents()) {
666 RenderViewHost
* render_view_host
=
667 main_window_
->web_contents()->GetRenderViewHost();
668 render_view_host
->Send(
669 new ShellViewMsg_TryLeakDetection(render_view_host
->GetRoutingID()));
674 base::MessageLoop::current()->PostTask(FROM_HERE
,
675 base::MessageLoop::QuitClosure());
678 void WebKitTestController::OnLeakDetectionDone(
679 const LeakDetectionResult
& result
) {
680 if (!result
.leaked
) {
681 base::MessageLoop::current()->PostTask(FROM_HERE
,
682 base::MessageLoop::QuitClosure());
686 printer_
->AddErrorMessage(
687 base::StringPrintf("#LEAK - renderer pid %d (%s)", current_pid_
,
688 result
.detail
.c_str()));
689 CHECK(!crash_when_leak_found_
);
694 } // namespace content