Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / shell / browser / webkit_test_controller.cc
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_manager.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
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
54 WebKitTestResultPrinter::~WebKitTestResultPrinter() {
55 }
56
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
65 void WebKitTestResultPrinter::PrintTextBlock(const std::string& block) {
66   if (state_ != IN_TEXT_BLOCK)
67     return;
68   *output_ << block;
69 }
70
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
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
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
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
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
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
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
147 void WebKitTestResultPrinter::AddMessage(const std::string& message) {
148   AddMessageRaw(message + "\n");
149 }
150
151 void WebKitTestResultPrinter::AddMessageRaw(const std::string& message) {
152   if (state_ != DURING_TEST)
153     return;
154   *output_ << message;
155 }
156
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
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
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
196 WebKitTestController* WebKitTestController::Get() {
197   DCHECK(instance_);
198   return instance_;
199 }
200
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
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
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 = PageTransitionFromInt(
285         PAGE_TRANSITION_TYPED | 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
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
317 void WebKitTestController::SetTempPath(const base::FilePath& temp_path) {
318   temp_path_ = temp_path;
319 }
320
321 void WebKitTestController::RendererUnresponsive() {
322   DCHECK(CalledOnValidThread());
323   LOG(WARNING) << "renderer unresponsive";
324 }
325
326 void WebKitTestController::WorkerCrashed() {
327   DCHECK(CalledOnValidThread());
328   printer_->AddErrorMessage("#CRASHED - worker");
329   DiscardMainWindow();
330 }
331
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
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
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
364 bool WebKitTestController::IsMainWindow(WebContents* web_contents) const {
365   return main_window_ && web_contents == main_window_->web_contents();
366 }
367
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
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
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
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
432 void WebKitTestController::DevToolsProcessCrashed() {
433   DCHECK(CalledOnValidThread());
434   printer_->AddErrorMessage("#CRASHED - devtools");
435   DiscardMainWindow();
436 }
437
438 void WebKitTestController::WebContentsDestroyed() {
439   DCHECK(CalledOnValidThread());
440   printer_->AddErrorMessage("FAIL: main window was destroyed");
441   DiscardMainWindow();
442 }
443
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
468 void WebKitTestController::OnGpuProcessCrashed(
469     base::TerminationStatus exit_code) {
470   DCHECK(CalledOnValidThread());
471   printer_->AddErrorMessage("#CRASHED - gpu");
472   DiscardMainWindow();
473 }
474
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
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
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
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
559 void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) {
560   printer_->PrintAudioHeader();
561   printer_->PrintAudioBlock(dump);
562   printer_->PrintAudioFooter();
563 }
564
565 void WebKitTestController::OnTextDump(const std::string& dump) {
566   printer_->PrintTextHeader();
567   printer_->PrintTextBlock(dump);
568   printer_->PrintTextFooter();
569 }
570
571 void WebKitTestController::OnPrintMessage(const std::string& message) {
572   printer_->AddMessageRaw(message);
573 }
574
575 void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) {
576   should_override_prefs_ = true;
577   prefs_ = prefs;
578 }
579
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
589 void WebKitTestController::OnShowDevTools(const std::string& settings,
590                                           const std::string& frontend_url) {
591   main_window_->ShowDevToolsForTest(settings, frontend_url);
592 }
593
594 void WebKitTestController::OnCloseDevTools() {
595   main_window_->CloseDevTools();
596 }
597
598 void WebKitTestController::OnGoToOffset(int offset) {
599   main_window_->GoBackOrForward(offset);
600 }
601
602 void WebKitTestController::OnReload() {
603   main_window_->Reload();
604 }
605
606 void WebKitTestController::OnLoadURLForFrame(const GURL& url,
607                                              const std::string& frame_name) {
608   main_window_->LoadURLForFrame(url, frame_name);
609 }
610
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
655 void WebKitTestController::OnCloseRemainingWindows() {
656   DevToolsManager::GetInstance()->CloseAllClientHosts();
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
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
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