Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/shell/browser/webkit_test_controller.h"
      6 
      7 #include <iostream>
      8 
      9 #include "base/base64.h"
     10 #include "base/command_line.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/run_loop.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "content/public/browser/devtools_agent_host.h"
     16 #include "content/public/browser/dom_storage_context.h"
     17 #include "content/public/browser/gpu_data_manager.h"
     18 #include "content/public/browser/navigation_controller.h"
     19 #include "content/public/browser/navigation_entry.h"
     20 #include "content/public/browser/notification_service.h"
     21 #include "content/public/browser/notification_types.h"
     22 #include "content/public/browser/render_process_host.h"
     23 #include "content/public/browser/render_view_host.h"
     24 #include "content/public/browser/render_widget_host_view.h"
     25 #include "content/public/browser/storage_partition.h"
     26 #include "content/public/browser/web_contents.h"
     27 #include "content/public/common/content_switches.h"
     28 #include "content/public/common/url_constants.h"
     29 #include "content/shell/browser/shell.h"
     30 #include "content/shell/browser/shell_browser_context.h"
     31 #include "content/shell/browser/shell_content_browser_client.h"
     32 #include "content/shell/browser/shell_devtools_frontend.h"
     33 #include "content/shell/common/shell_messages.h"
     34 #include "content/shell/common/shell_switches.h"
     35 #include "content/shell/common/webkit_test_helpers.h"
     36 #include "ui/gfx/codec/png_codec.h"
     37 
     38 namespace content {
     39 
     40 const int kTestSVGWindowWidthDip = 480;
     41 const int kTestSVGWindowHeightDip = 360;
     42 
     43 // WebKitTestResultPrinter ----------------------------------------------------
     44 
     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 = ui::PageTransitionFromInt(
    285         ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
    286     params.should_clear_history_list = true;
    287     main_window_->web_contents()->GetController().LoadURLWithParams(params);
    288     main_window_->web_contents()->Focus();
    289   }
    290   main_window_->web_contents()->GetRenderViewHost()->SetActive(true);
    291   main_window_->web_contents()->GetRenderViewHost()->Focus();
    292   return true;
    293 }
    294 
    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   DevToolsAgentHost::DetachAllClients();
    657   std::vector<Shell*> open_windows(Shell::windows());
    658   for (size_t i = 0; i < open_windows.size(); ++i) {
    659     if (open_windows[i] != main_window_)
    660       open_windows[i]->Close();
    661   }
    662   base::MessageLoop::current()->RunUntilIdle();
    663 }
    664 
    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
    697