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