Home | History | Annotate | Download | only in devtools
      1 // Copyright (c) 2012 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 "base/bind.h"
      6 #include "base/cancelable_callback.h"
      7 #include "base/command_line.h"
      8 #include "base/compiler_specific.h"
      9 #include "base/memory/ref_counted.h"
     10 #include "base/path_service.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/test/test_timeouts.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/devtools/browser_list_tabcontents_provider.h"
     17 #include "chrome/browser/devtools/devtools_window.h"
     18 #include "chrome/browser/extensions/extension_apitest.h"
     19 #include "chrome/browser/extensions/extension_browsertest.h"
     20 #include "chrome/browser/extensions/extension_service.h"
     21 #include "chrome/browser/extensions/extension_system.h"
     22 #include "chrome/browser/extensions/unpacked_installer.h"
     23 #include "chrome/browser/lifetime/application_lifetime.h"
     24 #include "chrome/browser/profiles/profile.h"
     25 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
     26 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
     27 #include "chrome/browser/ui/browser.h"
     28 #include "chrome/browser/ui/browser_commands.h"
     29 #include "chrome/browser/ui/browser_iterator.h"
     30 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     31 #include "chrome/common/chrome_paths.h"
     32 #include "chrome/common/chrome_switches.h"
     33 #include "chrome/common/pref_names.h"
     34 #include "chrome/common/url_constants.h"
     35 #include "chrome/test/base/in_process_browser_test.h"
     36 #include "chrome/test/base/test_switches.h"
     37 #include "chrome/test/base/ui_test_utils.h"
     38 #include "content/public/browser/child_process_data.h"
     39 #include "content/public/browser/content_browser_client.h"
     40 #include "content/public/browser/devtools_agent_host.h"
     41 #include "content/public/browser/devtools_client_host.h"
     42 #include "content/public/browser/devtools_http_handler.h"
     43 #include "content/public/browser/devtools_manager.h"
     44 #include "content/public/browser/notification_registrar.h"
     45 #include "content/public/browser/notification_service.h"
     46 #include "content/public/browser/render_view_host.h"
     47 #include "content/public/browser/web_contents.h"
     48 #include "content/public/browser/worker_service.h"
     49 #include "content/public/browser/worker_service_observer.h"
     50 #include "content/public/common/content_switches.h"
     51 #include "content/public/test/browser_test_utils.h"
     52 #include "extensions/common/switches.h"
     53 #include "net/socket/tcp_listen_socket.h"
     54 #include "net/test/spawned_test_server/spawned_test_server.h"
     55 
     56 using content::BrowserThread;
     57 using content::DevToolsManager;
     58 using content::DevToolsAgentHost;
     59 using content::NavigationController;
     60 using content::RenderViewHost;
     61 using content::WebContents;
     62 using content::WorkerService;
     63 using content::WorkerServiceObserver;
     64 
     65 namespace {
     66 
     67 const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html";
     68 const char kPauseWhenLoadingDevTools[] =
     69     "files/devtools/pause_when_loading_devtools.html";
     70 const char kPauseWhenScriptIsRunning[] =
     71     "files/devtools/pause_when_script_is_running.html";
     72 const char kPageWithContentScript[] =
     73     "files/devtools/page_with_content_script.html";
     74 const char kNavigateBackTestPage[] =
     75     "files/devtools/navigate_back.html";
     76 const char kChunkedTestPage[] = "chunked";
     77 const char kSlowTestPage[] =
     78     "chunked?waitBeforeHeaders=100&waitBetweenChunks=100&chunksNumber=2";
     79 const char kSharedWorkerTestPage[] =
     80     "files/workers/workers_ui_shared_worker.html";
     81 const char kReloadSharedWorkerTestPage[] =
     82     "files/workers/debug_shared_worker_initialization.html";
     83 
     84 void RunTestFunction(DevToolsWindow* window, const char* test_name) {
     85   std::string result;
     86 
     87   // At first check that JavaScript part of the front-end is loaded by
     88   // checking that global variable uiTests exists(it's created after all js
     89   // files have been loaded) and has runTest method.
     90   ASSERT_TRUE(
     91       content::ExecuteScriptAndExtractString(
     92           window->GetRenderViewHost(),
     93           "window.domAutomationController.send("
     94           "    '' + (window.uiTests && (typeof uiTests.runTest)));",
     95           &result));
     96 
     97   if (result == "function") {
     98     ASSERT_TRUE(
     99         content::ExecuteScriptAndExtractString(
    100             window->GetRenderViewHost(),
    101             base::StringPrintf("uiTests.runTest('%s')", test_name),
    102             &result));
    103     EXPECT_EQ("[OK]", result);
    104   } else {
    105     FAIL() << "DevTools front-end is broken.";
    106   }
    107 }
    108 
    109 class DevToolsSanityTest : public InProcessBrowserTest {
    110  public:
    111   DevToolsSanityTest()
    112       : window_(NULL),
    113         inspected_rvh_(NULL) {}
    114 
    115  protected:
    116   void RunTest(const std::string& test_name, const std::string& test_page) {
    117     OpenDevToolsWindow(test_page);
    118     RunTestFunction(window_, test_name.c_str());
    119     CloseDevToolsWindow();
    120   }
    121 
    122   void LoadTestPage(const std::string& test_page) {
    123     content::WindowedNotificationObserver load_observer(
    124         content::NOTIFICATION_LOAD_STOP,
    125         content::NotificationService::AllSources());
    126     GURL url = test_server()->GetURL(test_page);
    127     ui_test_utils::NavigateToURL(browser(), url);
    128     load_observer.Wait();
    129   }
    130 
    131   void OpenDevToolsWindow(const std::string& test_page) {
    132     ASSERT_TRUE(test_server()->Start());
    133     LoadTestPage(test_page);
    134 
    135     content::WindowedNotificationObserver observer(
    136         content::NOTIFICATION_LOAD_STOP,
    137         content::NotificationService::AllSources());
    138     inspected_rvh_ = GetInspectedTab()->GetRenderViewHost();
    139     window_ = DevToolsWindow::OpenDevToolsWindow(inspected_rvh_);
    140     observer.Wait();
    141   }
    142 
    143   WebContents* GetInspectedTab() {
    144     return browser()->tab_strip_model()->GetWebContentsAt(0);
    145   }
    146 
    147   void ToggleDevToolsWindow() {
    148     content::WindowedNotificationObserver close_observer(
    149         content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    150         content::Source<content::WebContents>(window_->web_contents()));
    151     DevToolsWindow::ToggleDevToolsWindow(inspected_rvh_, false,
    152         DevToolsToggleAction::Toggle());
    153     close_observer.Wait();
    154   }
    155 
    156   void CloseDevToolsWindow() {
    157     DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    158     content::WindowedNotificationObserver close_observer(
    159         content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    160         content::Source<content::WebContents>(window_->web_contents()));
    161     devtools_manager->CloseAllClientHosts();
    162     close_observer.Wait();
    163   }
    164 
    165   DevToolsWindow* window_;
    166   RenderViewHost* inspected_rvh_;
    167 };
    168 
    169 // Used to block until a dev tools window gets beforeunload event.
    170 class DevToolsWindowBeforeUnloadObserver
    171     : public content::WebContentsObserver {
    172  public:
    173   explicit DevToolsWindowBeforeUnloadObserver(DevToolsWindow*);
    174   void Wait();
    175  private:
    176   // Invoked when the beforeunload handler fires.
    177   virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE;
    178 
    179   bool m_fired;
    180   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
    181   DISALLOW_COPY_AND_ASSIGN(DevToolsWindowBeforeUnloadObserver);
    182 };
    183 
    184 DevToolsWindowBeforeUnloadObserver::DevToolsWindowBeforeUnloadObserver(
    185     DevToolsWindow* devtools_window)
    186     : WebContentsObserver(devtools_window->web_contents()),
    187       m_fired(false) {
    188 }
    189 
    190 void DevToolsWindowBeforeUnloadObserver::Wait() {
    191   if (m_fired)
    192     return;
    193   message_loop_runner_ = new content::MessageLoopRunner;
    194   message_loop_runner_->Run();
    195 }
    196 
    197 void DevToolsWindowBeforeUnloadObserver::BeforeUnloadFired(
    198     const base::TimeTicks& proceed_time) {
    199   m_fired = true;
    200   if (message_loop_runner_.get())
    201     message_loop_runner_->Quit();
    202 }
    203 
    204 class DevToolsBeforeUnloadTest: public DevToolsSanityTest {
    205  public:
    206   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    207     command_line->AppendSwitch(
    208         switches::kDisableHangMonitor);
    209   }
    210 
    211   void CloseInspectedTab() {
    212     browser()->tab_strip_model()->CloseWebContentsAt(0,
    213         TabStripModel::CLOSE_NONE);
    214   }
    215 
    216   void CloseDockedDevTools() {
    217     DevToolsWindow::ToggleDevToolsWindow(inspected_rvh_, false,
    218         DevToolsToggleAction::Toggle());
    219   }
    220 
    221   void CloseUndockedDevTools() {
    222     chrome::CloseWindow(window_->browser());
    223   }
    224 
    225   void CloseInspectedBrowser() {
    226     chrome::CloseWindow(browser());
    227   }
    228  protected:
    229   void InjectBeforeUnloadListener(content::WebContents* web_contents) {
    230     ASSERT_TRUE(content::ExecuteScript(web_contents->GetRenderViewHost(),
    231         "window.addEventListener('beforeunload',"
    232         "function(event) { event.returnValue = 'Foo'; });"));
    233   }
    234 
    235   void RunBeforeUnloadSanityTest(DevToolsDockSide dock_side,
    236                              base::Callback<void(void)> close_method,
    237                              bool wait_for_browser_close = true) {
    238     OpenDevToolsWindow(kDebuggerTestPage);
    239     window_->SetDockSideForTest(dock_side);
    240     content::WindowedNotificationObserver devtools_close_observer(
    241         content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    242         content::Source<content::WebContents>(window_->web_contents()));
    243     InjectBeforeUnloadListener(window_->web_contents());
    244     {
    245       DevToolsWindowBeforeUnloadObserver before_unload_observer(window_);
    246       close_method.Run();
    247       CancelModalDialog();
    248       before_unload_observer.Wait();
    249     }
    250     {
    251       content::WindowedNotificationObserver close_observer(
    252           chrome::NOTIFICATION_BROWSER_CLOSED,
    253           content::Source<Browser>(browser()));
    254       close_method.Run();
    255       AcceptModalDialog();
    256       if (wait_for_browser_close)
    257         close_observer.Wait();
    258     }
    259     devtools_close_observer.Wait();
    260   }
    261 
    262   DevToolsWindow* OpenDevToolWindowOnWebContents(
    263       content::WebContents* contents) {
    264     content::WindowedNotificationObserver observer(
    265         content::NOTIFICATION_LOAD_STOP,
    266         content::NotificationService::AllSources());
    267     DevToolsWindow* window = DevToolsWindow::OpenDevToolsWindow(
    268         contents->GetRenderViewHost());
    269     observer.Wait();
    270     return window;
    271   }
    272 
    273   void OpenDevToolsPopupWindow(DevToolsWindow* devtools_window) {
    274     content::WindowedNotificationObserver observer(
    275         content::NOTIFICATION_LOAD_STOP,
    276         content::NotificationService::AllSources());
    277     ASSERT_TRUE(content::ExecuteScript(
    278         devtools_window->web_contents()->GetRenderViewHost(),
    279         "window.open(\"\", \"\", \"location=0\");"));
    280     observer.Wait();
    281   }
    282 
    283   void CloseDevToolsPopupWindow(DevToolsWindow* devtools_window) {
    284     Browser* popup_browser = NULL;
    285     for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    286       if (it->is_devtools()) {
    287         content::WebContents* contents =
    288             it->tab_strip_model()->GetWebContentsAt(0);
    289         if (devtools_window->web_contents() != contents) {
    290           popup_browser = *it;
    291           break;
    292         }
    293       }
    294     }
    295     ASSERT_FALSE(popup_browser == NULL);
    296     content::WindowedNotificationObserver close_observer(
    297         chrome::NOTIFICATION_BROWSER_CLOSED,
    298         content::Source<Browser>(popup_browser));
    299     chrome::CloseWindow(popup_browser);
    300     close_observer.Wait();
    301   }
    302 
    303   void AcceptModalDialog() {
    304     NativeAppModalDialog* native_dialog = GetDialog();
    305     native_dialog->AcceptAppModalDialog();
    306   }
    307 
    308   void CancelModalDialog() {
    309     NativeAppModalDialog* native_dialog = GetDialog();
    310     native_dialog->CancelAppModalDialog();
    311   }
    312 
    313   NativeAppModalDialog* GetDialog() {
    314     AppModalDialog* dialog = ui_test_utils::WaitForAppModalDialog();
    315     EXPECT_TRUE(dialog->IsJavaScriptModalDialog());
    316     JavaScriptAppModalDialog* js_dialog =
    317         static_cast<JavaScriptAppModalDialog*>(dialog);
    318     NativeAppModalDialog* native_dialog = js_dialog->native_dialog();
    319     EXPECT_TRUE(native_dialog);
    320     return native_dialog;
    321   }
    322 };
    323 
    324 class DevToolsUnresponsiveBeforeUnloadTest: public DevToolsBeforeUnloadTest {
    325  public:
    326   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {}
    327 };
    328 
    329 void TimeoutCallback(const std::string& timeout_message) {
    330   FAIL() << timeout_message;
    331   base::MessageLoop::current()->Quit();
    332 }
    333 
    334 // Base class for DevTools tests that test devtools functionality for
    335 // extensions and content scripts.
    336 class DevToolsExtensionTest : public DevToolsSanityTest,
    337                               public content::NotificationObserver {
    338  public:
    339   DevToolsExtensionTest() : DevToolsSanityTest() {
    340     PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_);
    341     test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools");
    342     test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions");
    343   }
    344 
    345  protected:
    346   // Load an extension from test\data\devtools\extensions\<extension_name>
    347   void LoadExtension(const char* extension_name) {
    348     base::FilePath path = test_extensions_dir_.AppendASCII(extension_name);
    349     ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension.";
    350   }
    351 
    352  private:
    353   bool LoadExtensionFromPath(const base::FilePath& path) {
    354     ExtensionService* service = extensions::ExtensionSystem::Get(
    355         browser()->profile())->extension_service();
    356     size_t num_before = service->extensions()->size();
    357     {
    358       content::NotificationRegistrar registrar;
    359       registrar.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
    360                     content::NotificationService::AllSources());
    361       base::CancelableClosure timeout(
    362           base::Bind(&TimeoutCallback, "Extension load timed out."));
    363       base::MessageLoop::current()->PostDelayedTask(
    364           FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
    365       extensions::UnpackedInstaller::Create(service)->Load(path);
    366       content::RunMessageLoop();
    367       timeout.Cancel();
    368     }
    369     size_t num_after = service->extensions()->size();
    370     if (num_after != (num_before + 1))
    371       return false;
    372 
    373     return WaitForExtensionViewsToLoad();
    374   }
    375 
    376   bool WaitForExtensionViewsToLoad() {
    377     // Wait for all the extension render views that exist to finish loading.
    378     // NOTE: This assumes that the extension views list is not changing while
    379     // this method is running.
    380 
    381     content::NotificationRegistrar registrar;
    382     registrar.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
    383                   content::NotificationService::AllSources());
    384     base::CancelableClosure timeout(
    385         base::Bind(&TimeoutCallback, "Extension host load timed out."));
    386     base::MessageLoop::current()->PostDelayedTask(
    387         FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
    388 
    389     extensions::ProcessManager* manager =
    390         extensions::ExtensionSystem::Get(browser()->profile())->
    391             process_manager();
    392     extensions::ProcessManager::ViewSet all_views = manager->GetAllViews();
    393     for (extensions::ProcessManager::ViewSet::const_iterator iter =
    394              all_views.begin();
    395          iter != all_views.end();) {
    396       if (!(*iter)->IsLoading())
    397         ++iter;
    398       else
    399         content::RunMessageLoop();
    400     }
    401 
    402     timeout.Cancel();
    403     return true;
    404   }
    405 
    406   virtual void Observe(int type,
    407                        const content::NotificationSource& source,
    408                        const content::NotificationDetails& details) OVERRIDE {
    409     switch (type) {
    410       case chrome::NOTIFICATION_EXTENSION_LOADED:
    411       case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING:
    412         base::MessageLoopForUI::current()->Quit();
    413         break;
    414       default:
    415         NOTREACHED();
    416         break;
    417     }
    418   }
    419 
    420   base::FilePath test_extensions_dir_;
    421 };
    422 
    423 class DevToolsExperimentalExtensionTest : public DevToolsExtensionTest {
    424  public:
    425   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    426     command_line->AppendSwitch(
    427         extensions::switches::kEnableExperimentalExtensionApis);
    428   }
    429 };
    430 
    431 class WorkerDevToolsSanityTest : public InProcessBrowserTest {
    432  public:
    433   WorkerDevToolsSanityTest() : window_(NULL) {}
    434 
    435  protected:
    436   class WorkerData : public base::RefCountedThreadSafe<WorkerData> {
    437    public:
    438     WorkerData() : worker_process_id(0), worker_route_id(0) {}
    439     int worker_process_id;
    440     int worker_route_id;
    441 
    442    private:
    443     friend class base::RefCountedThreadSafe<WorkerData>;
    444     ~WorkerData() {}
    445   };
    446 
    447   class WorkerCreationObserver : public WorkerServiceObserver {
    448    public:
    449     explicit WorkerCreationObserver(WorkerData* worker_data)
    450         : worker_data_(worker_data) {
    451     }
    452 
    453    private:
    454     virtual ~WorkerCreationObserver() {}
    455 
    456     virtual void WorkerCreated (
    457         const GURL& url,
    458         const base::string16& name,
    459         int process_id,
    460         int route_id) OVERRIDE {
    461       worker_data_->worker_process_id = process_id;
    462       worker_data_->worker_route_id = route_id;
    463       WorkerService::GetInstance()->RemoveObserver(this);
    464       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    465           base::MessageLoop::QuitClosure());
    466       delete this;
    467     }
    468     scoped_refptr<WorkerData> worker_data_;
    469   };
    470 
    471   class WorkerTerminationObserver : public WorkerServiceObserver {
    472    public:
    473     explicit WorkerTerminationObserver(WorkerData* worker_data)
    474         : worker_data_(worker_data) {
    475     }
    476 
    477    private:
    478     virtual ~WorkerTerminationObserver() {}
    479 
    480     virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE {
    481       ASSERT_EQ(worker_data_->worker_process_id, process_id);
    482       ASSERT_EQ(worker_data_->worker_route_id, route_id);
    483       WorkerService::GetInstance()->RemoveObserver(this);
    484       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    485           base::MessageLoop::QuitClosure());
    486       delete this;
    487     }
    488     scoped_refptr<WorkerData> worker_data_;
    489   };
    490 
    491   void RunTest(const char* test_name, const char* test_page) {
    492     ASSERT_TRUE(test_server()->Start());
    493     GURL url = test_server()->GetURL(test_page);
    494     ui_test_utils::NavigateToURL(browser(), url);
    495 
    496     scoped_refptr<WorkerData> worker_data = WaitForFirstSharedWorker();
    497     OpenDevToolsWindowForSharedWorker(worker_data.get());
    498     RunTestFunction(window_, test_name);
    499     CloseDevToolsWindow();
    500   }
    501 
    502   static void TerminateWorkerOnIOThread(scoped_refptr<WorkerData> worker_data) {
    503     if (WorkerService::GetInstance()->TerminateWorker(
    504             worker_data->worker_process_id, worker_data->worker_route_id)) {
    505       WorkerService::GetInstance()->AddObserver(
    506           new WorkerTerminationObserver(worker_data.get()));
    507       return;
    508     }
    509     FAIL() << "Failed to terminate worker.\n";
    510   }
    511 
    512   static void TerminateWorker(scoped_refptr<WorkerData> worker_data) {
    513     BrowserThread::PostTask(
    514         BrowserThread::IO, FROM_HERE,
    515         base::Bind(&TerminateWorkerOnIOThread, worker_data));
    516     content::RunMessageLoop();
    517   }
    518 
    519   static void WaitForFirstSharedWorkerOnIOThread(
    520       scoped_refptr<WorkerData> worker_data) {
    521     std::vector<WorkerService::WorkerInfo> worker_info =
    522         WorkerService::GetInstance()->GetWorkers();
    523     if (!worker_info.empty()) {
    524       worker_data->worker_process_id = worker_info[0].process_id;
    525       worker_data->worker_route_id = worker_info[0].route_id;
    526       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    527           base::MessageLoop::QuitClosure());
    528       return;
    529     }
    530 
    531     WorkerService::GetInstance()->AddObserver(
    532         new WorkerCreationObserver(worker_data.get()));
    533   }
    534 
    535   static scoped_refptr<WorkerData> WaitForFirstSharedWorker() {
    536     scoped_refptr<WorkerData> worker_data(new WorkerData());
    537     BrowserThread::PostTask(
    538         BrowserThread::IO, FROM_HERE,
    539         base::Bind(&WaitForFirstSharedWorkerOnIOThread, worker_data));
    540     content::RunMessageLoop();
    541     return worker_data;
    542   }
    543 
    544   void OpenDevToolsWindowForSharedWorker(WorkerData* worker_data) {
    545     Profile* profile = browser()->profile();
    546     window_ = DevToolsWindow::CreateDevToolsWindowForWorker(profile);
    547     window_->Show(DevToolsToggleAction::Show());
    548     scoped_refptr<DevToolsAgentHost> agent_host(
    549         DevToolsAgentHost::GetForWorker(
    550             worker_data->worker_process_id,
    551             worker_data->worker_route_id));
    552     DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
    553         agent_host.get(), window_->GetDevToolsClientHostForTest());
    554     RenderViewHost* client_rvh = window_->GetRenderViewHost();
    555     WebContents* client_contents = WebContents::FromRenderViewHost(client_rvh);
    556     if (client_contents->IsLoading()) {
    557       content::WindowedNotificationObserver observer(
    558           content::NOTIFICATION_LOAD_STOP,
    559           content::Source<NavigationController>(
    560               &client_contents->GetController()));
    561       observer.Wait();
    562     }
    563   }
    564 
    565   void CloseDevToolsWindow() {
    566     Browser* browser = window_->browser();
    567     content::WindowedNotificationObserver close_observer(
    568         content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    569         content::Source<content::WebContents>(window_->web_contents()));
    570     browser->tab_strip_model()->CloseAllTabs();
    571     close_observer.Wait();
    572   }
    573 
    574   DevToolsWindow* window_;
    575 };
    576 
    577 // Tests that BeforeUnload event gets called on docked devtools if
    578 // we try to close them.
    579 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest, TestDockedDevToolsClose) {
    580   RunBeforeUnloadSanityTest(DEVTOOLS_DOCK_SIDE_BOTTOM, base::Bind(
    581       &DevToolsBeforeUnloadTest::CloseDockedDevTools, this), false);
    582 }
    583 
    584 // Tests that BeforeUnload event gets called on docked devtools if
    585 // we try to close the inspected page.
    586 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
    587                        TestDockedDevToolsInspectedTabClose) {
    588   RunBeforeUnloadSanityTest(DEVTOOLS_DOCK_SIDE_BOTTOM, base::Bind(
    589       &DevToolsBeforeUnloadTest::CloseInspectedTab, this));
    590 }
    591 
    592 // Tests that BeforeUnload event gets called on docked devtools if
    593 // we try to close the inspected browser.
    594 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
    595                        TestDockedDevToolsInspectedBrowserClose) {
    596   RunBeforeUnloadSanityTest(DEVTOOLS_DOCK_SIDE_BOTTOM, base::Bind(
    597       &DevToolsBeforeUnloadTest::CloseInspectedBrowser, this));
    598 }
    599 
    600 // Tests that BeforeUnload event gets called on undocked devtools if
    601 // we try to close them.
    602 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest, TestUndockedDevToolsClose) {
    603   RunBeforeUnloadSanityTest(DEVTOOLS_DOCK_SIDE_UNDOCKED, base::Bind(
    604       &DevToolsBeforeUnloadTest::CloseUndockedDevTools, this), false);
    605 }
    606 
    607 // Tests that BeforeUnload event gets called on undocked devtools if
    608 // we try to close the inspected page.
    609 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
    610                        TestUndockedDevToolsInspectedTabClose) {
    611   RunBeforeUnloadSanityTest(DEVTOOLS_DOCK_SIDE_UNDOCKED, base::Bind(
    612       &DevToolsBeforeUnloadTest::CloseInspectedTab, this));
    613 }
    614 
    615 // Tests that BeforeUnload event gets called on undocked devtools if
    616 // we try to close the inspected browser.
    617 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
    618                        TestUndockedDevToolsInspectedBrowserClose) {
    619   RunBeforeUnloadSanityTest(DEVTOOLS_DOCK_SIDE_UNDOCKED, base::Bind(
    620       &DevToolsBeforeUnloadTest::CloseInspectedBrowser, this));
    621 }
    622 
    623 // Tests that BeforeUnload event gets called on undocked devtools if
    624 // we try to exit application.
    625 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
    626                        TestUndockedDevToolsApplicationClose) {
    627   RunBeforeUnloadSanityTest(DEVTOOLS_DOCK_SIDE_UNDOCKED, base::Bind(
    628       &chrome::CloseAllBrowsers));
    629 }
    630 
    631 // Tests that inspected tab gets closed if devtools renderer
    632 // becomes unresponsive during beforeunload event interception.
    633 // @see http://crbug.com/322380
    634 IN_PROC_BROWSER_TEST_F(DevToolsUnresponsiveBeforeUnloadTest,
    635                        TestUndockedDevToolsUnresponsive) {
    636   ASSERT_TRUE(test_server()->Start());
    637   LoadTestPage(kDebuggerTestPage);
    638   DevToolsWindow* devtools_window = OpenDevToolWindowOnWebContents(
    639       GetInspectedTab());
    640   devtools_window->SetDockSideForTest(DEVTOOLS_DOCK_SIDE_UNDOCKED);
    641   content::WindowedNotificationObserver devtools_close_observer(
    642       content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    643       content::Source<content::WebContents>(
    644           devtools_window->web_contents()));
    645 
    646   ASSERT_TRUE(content::ExecuteScript(
    647       devtools_window->web_contents()->GetRenderViewHost(),
    648       "window.addEventListener('beforeunload',"
    649       "function(event) { while (true); });"));
    650   CloseInspectedTab();
    651   devtools_close_observer.Wait();
    652 }
    653 
    654 // Tests that closing worker inspector window does not cause browser crash
    655 // @see http://crbug.com/323031
    656 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
    657                        TestWorkerWindowClosing) {
    658   ASSERT_TRUE(test_server()->Start());
    659   LoadTestPage(kDebuggerTestPage);
    660   DevToolsWindow* devtools_window = OpenDevToolWindowOnWebContents(
    661       GetInspectedTab());
    662   devtools_window->SetDockSideForTest(DEVTOOLS_DOCK_SIDE_UNDOCKED);
    663   content::WindowedNotificationObserver devtools_close_observer(
    664       content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    665       content::Source<content::WebContents>(
    666           devtools_window->web_contents()));
    667 
    668   OpenDevToolsPopupWindow(devtools_window);
    669   CloseDevToolsPopupWindow(devtools_window);
    670 }
    671 
    672 // Tests that BeforeUnload event gets called on devtools that are opened
    673 // on another devtools.
    674 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
    675                        TestDevToolsOnDevTools) {
    676   ASSERT_TRUE(test_server()->Start());
    677   LoadTestPage(kDebuggerTestPage);
    678 
    679   std::vector<DevToolsWindow*> windows;
    680   std::vector<content::WindowedNotificationObserver*> close_observers;
    681   content::WebContents* inspected_web_contents = GetInspectedTab();
    682   for (int i = 0; i < 3; ++i) {
    683     DevToolsWindow* devtools_window = OpenDevToolWindowOnWebContents(
    684       inspected_web_contents);
    685     windows.push_back(devtools_window);
    686     content::WindowedNotificationObserver* close_observer =
    687         new content::WindowedNotificationObserver(
    688                 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    689                 content::Source<content::WebContents>(
    690                     devtools_window->web_contents()));
    691     close_observers.push_back(close_observer);
    692     inspected_web_contents = devtools_window->web_contents();
    693   }
    694 
    695   InjectBeforeUnloadListener(windows[0]->web_contents());
    696   InjectBeforeUnloadListener(windows[2]->web_contents());
    697   // Try to close second devtools.
    698   {
    699     content::WindowedNotificationObserver cancel_browser(
    700         chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
    701         content::NotificationService::AllSources());
    702     chrome::CloseWindow(windows[1]->browser());
    703     CancelModalDialog();
    704     cancel_browser.Wait();
    705   }
    706   // Try to close browser window.
    707   {
    708     content::WindowedNotificationObserver cancel_browser(
    709         chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
    710         content::NotificationService::AllSources());
    711     chrome::CloseWindow(browser());
    712     AcceptModalDialog();
    713     CancelModalDialog();
    714     cancel_browser.Wait();
    715   }
    716   // Try to exit application.
    717   {
    718     content::WindowedNotificationObserver close_observer(
    719         chrome::NOTIFICATION_BROWSER_CLOSED,
    720         content::Source<Browser>(browser()));
    721     chrome::CloseAllBrowsers();
    722     AcceptModalDialog();
    723     AcceptModalDialog();
    724     close_observer.Wait();
    725   }
    726   for (size_t i = 0; i < close_observers.size(); ++i) {
    727     close_observers[i]->Wait();
    728     delete close_observers[i];
    729   }
    730 }
    731 
    732 // Tests scripts panel showing.
    733 // TODO(pfeldman): figure out flake.
    734 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestShowScriptsTab) {
    735   RunTest("testShowScriptsTab", kDebuggerTestPage);
    736 }
    737 
    738 // Tests that scripts tab is populated with inspected scripts even if it
    739 // hadn't been shown by the moment inspected paged refreshed.
    740 // @see http://crbug.com/26312
    741 IN_PROC_BROWSER_TEST_F(
    742     DevToolsSanityTest,
    743     TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
    744   // Clear inspector settings to ensure that Elements will be
    745   // current panel when DevTools window is open.
    746   content::BrowserContext* browser_context =
    747       GetInspectedTab()->GetBrowserContext();
    748   Profile::FromBrowserContext(browser_context)->GetPrefs()->
    749       ClearPref(prefs::kWebKitInspectorSettings);
    750 
    751   RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh",
    752           kDebuggerTestPage);
    753 }
    754 
    755 // Tests that chrome.devtools extension is correctly exposed.
    756 IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
    757                        TestDevToolsExtensionAPI) {
    758   LoadExtension("devtools_extension");
    759   RunTest("waitForTestResultsInConsole", std::string());
    760 }
    761 
    762 // Disabled on Windows due to flakiness. http://crbug.com/183649
    763 #if defined(OS_WIN)
    764 #define MAYBE_TestDevToolsExtensionMessaging DISABLED_TestDevToolsExtensionMessaging
    765 #else
    766 #define MAYBE_TestDevToolsExtensionMessaging TestDevToolsExtensionMessaging
    767 #endif
    768 
    769 // Tests that chrome.devtools extension can communicate with background page
    770 // using extension messaging.
    771 IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
    772                        MAYBE_TestDevToolsExtensionMessaging) {
    773   LoadExtension("devtools_messaging");
    774   RunTest("waitForTestResultsInConsole", std::string());
    775 }
    776 
    777 // Tests that chrome.experimental.devtools extension is correctly exposed
    778 // when the extension has experimental permission.
    779 IN_PROC_BROWSER_TEST_F(DevToolsExperimentalExtensionTest,
    780                        TestDevToolsExperimentalExtensionAPI) {
    781   LoadExtension("devtools_experimental");
    782   RunTest("waitForTestResultsInConsole", std::string());
    783 }
    784 
    785 // Tests that a content script is in the scripts list.
    786 // History of flakiness: http://crbug.com/114104, http://crbug.com/315288.
    787 IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
    788                        DISABLED_TestContentScriptIsPresent) {
    789   LoadExtension("simple_content_script");
    790   RunTest("testContentScriptIsPresent", kPageWithContentScript);
    791 }
    792 
    793 // Fails quite consistently on Win XP: crbug.com/317725.
    794 #if defined(OS_WIN)
    795 #define MAYBE_TestNoScriptDuplicatesOnPanelSwitch \
    796   DISABLED_TestNoScriptDuplicatesOnPanelSwitch
    797 #else
    798 #define MAYBE_TestNoScriptDuplicatesOnPanelSwitch \
    799   TestNoScriptDuplicatesOnPanelSwitch
    800 #endif
    801 
    802 // Tests that scripts are not duplicated after Scripts Panel switch.
    803 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
    804                        MAYBE_TestNoScriptDuplicatesOnPanelSwitch) {
    805   RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
    806 }
    807 
    808 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
    809 #define MAYBE_TestPauseWhenLoadingDevTools DISABLED_TestPauseWhenLoadingDevTools
    810 #else
    811 #define MAYBE_TestPauseWhenLoadingDevTools TestPauseWhenLoadingDevTools
    812 #endif
    813 // Tests that debugger works correctly if pause event occurs when DevTools
    814 // frontend is being loaded.
    815 // Disabled because of flakiness on multiple platforms: crbug.com/329036
    816 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
    817                        MAYBE_TestPauseWhenLoadingDevTools) {
    818   RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
    819 }
    820 
    821 // Tests that pressing 'Pause' will pause script execution if the script
    822 // is already running.
    823 #if defined(OS_WIN)
    824 // Timing out on windows tryservers: http://crbug.com/219515
    825 #define MAYBE_TestPauseWhenScriptIsRunning DISABLED_TestPauseWhenScriptIsRunning
    826 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
    827 // Timing out on linux ARM bot: https://crbug/238453
    828 #define MAYBE_TestPauseWhenScriptIsRunning DISABLED_TestPauseWhenScriptIsRunning
    829 #else
    830 #define MAYBE_TestPauseWhenScriptIsRunning TestPauseWhenScriptIsRunning
    831 #endif
    832 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
    833                        MAYBE_TestPauseWhenScriptIsRunning) {
    834   RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
    835 }
    836 
    837 // Tests network timing.
    838 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkTiming) {
    839   RunTest("testNetworkTiming", kSlowTestPage);
    840 }
    841 
    842 // Tests network size.
    843 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkSize) {
    844   RunTest("testNetworkSize", kChunkedTestPage);
    845 }
    846 
    847 // Tests raw headers text.
    848 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkSyncSize) {
    849   RunTest("testNetworkSyncSize", kChunkedTestPage);
    850 }
    851 
    852 // Tests raw headers text.
    853 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkRawHeadersText) {
    854   RunTest("testNetworkRawHeadersText", kChunkedTestPage);
    855 }
    856 
    857 // Tests that console messages are not duplicated on navigation back.
    858 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleOnNavigateBack) {
    859   RunTest("testConsoleOnNavigateBack", kNavigateBackTestPage);
    860 }
    861 
    862 
    863 // Tests that external navigation from inspector page is always handled by
    864 // DevToolsWindow and results in inspected page navigation.
    865 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDevToolsExternalNavigation) {
    866   OpenDevToolsWindow(kDebuggerTestPage);
    867   GURL url = test_server()->GetURL(kNavigateBackTestPage);
    868   content::WindowedNotificationObserver observer(
    869       content::NOTIFICATION_LOAD_STOP,
    870       content::NotificationService::AllSources());
    871   ASSERT_TRUE(content::ExecuteScript(
    872       window_->web_contents(),
    873       std::string("window.location = \"") + url.spec() + "\""));
    874   observer.Wait();
    875 
    876   ASSERT_TRUE(window_->web_contents()->GetURL().
    877                   SchemeIs(chrome::kChromeDevToolsScheme));
    878   ASSERT_EQ(GetInspectedTab()->GetURL(), url);
    879   CloseDevToolsWindow();
    880 }
    881 
    882 #if defined(OS_WIN)
    883 // Flakily times out: http://crbug.com/163411
    884 #define MAYBE_TestReattachAfterCrash DISABLED_TestReattachAfterCrash
    885 #else
    886 #define MAYBE_TestReattachAfterCrash TestReattachAfterCrash
    887 #endif
    888 // Tests that inspector will reattach to inspected page when it is reloaded
    889 // after a crash. See http://crbug.com/101952
    890 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestReattachAfterCrash) {
    891   OpenDevToolsWindow(kDebuggerTestPage);
    892 
    893   content::CrashTab(GetInspectedTab());
    894   content::WindowedNotificationObserver observer(
    895       content::NOTIFICATION_LOAD_STOP,
    896       content::Source<NavigationController>(
    897           &browser()->tab_strip_model()->GetActiveWebContents()->
    898               GetController()));
    899   chrome::Reload(browser(), CURRENT_TAB);
    900   observer.Wait();
    901 
    902   RunTestFunction(window_, "testReattachAfterCrash");
    903   CloseDevToolsWindow();
    904 }
    905 
    906 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPageWithNoJavaScript) {
    907   OpenDevToolsWindow("about:blank");
    908   std::string result;
    909   ASSERT_TRUE(
    910       content::ExecuteScriptAndExtractString(
    911           window_->GetRenderViewHost(),
    912           "window.domAutomationController.send("
    913           "    '' + (window.uiTests && (typeof uiTests.runTest)));",
    914           &result));
    915   ASSERT_EQ("function", result) << "DevTools front-end is broken.";
    916   CloseDevToolsWindow();
    917 }
    918 
    919 #if defined(OS_MACOSX)
    920 #define MAYBE_InspectSharedWorker DISABLED_InspectSharedWorker
    921 #else
    922 #define MAYBE_InspectSharedWorker InspectSharedWorker
    923 #endif
    924 // Flakily fails with 25s timeout: http://crbug.com/89845
    925 IN_PROC_BROWSER_TEST_F(WorkerDevToolsSanityTest, MAYBE_InspectSharedWorker) {
    926 #if defined(OS_WIN) && defined(USE_ASH)
    927   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    928   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    929     return;
    930 #endif
    931 
    932   RunTest("testSharedWorker", kSharedWorkerTestPage);
    933 }
    934 
    935 // http://crbug.com/100538
    936 #if defined(OS_MACOSX) || defined(OS_WIN)
    937 #define MAYBE_PauseInSharedWorkerInitialization DISABLED_PauseInSharedWorkerInitialization
    938 #else
    939 #define MAYBE_PauseInSharedWorkerInitialization PauseInSharedWorkerInitialization
    940 #endif
    941 
    942 // http://crbug.com/106114 is masking
    943 // MAYBE_PauseInSharedWorkerInitialization into
    944 // DISABLED_PauseInSharedWorkerInitialization
    945 IN_PROC_BROWSER_TEST_F(WorkerDevToolsSanityTest,
    946                        MAYBE_PauseInSharedWorkerInitialization) {
    947   ASSERT_TRUE(test_server()->Start());
    948   GURL url = test_server()->GetURL(kReloadSharedWorkerTestPage);
    949   ui_test_utils::NavigateToURL(browser(), url);
    950 
    951   scoped_refptr<WorkerData> worker_data = WaitForFirstSharedWorker();
    952   OpenDevToolsWindowForSharedWorker(worker_data.get());
    953 
    954   TerminateWorker(worker_data);
    955 
    956   // Reload page to restart the worker.
    957   ui_test_utils::NavigateToURL(browser(), url);
    958 
    959   // Wait until worker script is paused on the debugger statement.
    960   RunTestFunction(window_, "testPauseInSharedWorkerInitialization");
    961   CloseDevToolsWindow();
    962 }
    963 
    964 class DevToolsAgentHostTest : public InProcessBrowserTest {};
    965 
    966 // Tests DevToolsAgentHost retention by its target.
    967 IN_PROC_BROWSER_TEST_F(DevToolsAgentHostTest, TestAgentHostReleased) {
    968   ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
    969   RenderViewHost* rvh = browser()->tab_strip_model()->GetWebContentsAt(0)->
    970       GetRenderViewHost();
    971   DevToolsAgentHost* agent_raw = DevToolsAgentHost::GetOrCreateFor(rvh).get();
    972   const std::string agent_id = agent_raw->GetId();
    973   ASSERT_EQ(agent_raw, DevToolsAgentHost::GetForId(agent_id)) <<
    974       "DevToolsAgentHost cannot be found by id";
    975   browser()->tab_strip_model()->
    976       CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
    977   ASSERT_FALSE(DevToolsAgentHost::GetForId(agent_id).get())
    978       << "DevToolsAgentHost is not released when the tab is closed";
    979 }
    980 
    981 class RemoteDebuggingTest: public ExtensionApiTest {
    982   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    983     ExtensionApiTest::SetUpCommandLine(command_line);
    984     command_line->AppendSwitchASCII(switches::kRemoteDebuggingPort, "9222");
    985 
    986     // Override the extension root path.
    987     PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
    988     test_data_dir_ = test_data_dir_.AppendASCII("devtools");
    989   }
    990 };
    991 
    992 IN_PROC_BROWSER_TEST_F(RemoteDebuggingTest, RemoteDebugger) {
    993 #if defined(OS_WIN) && defined(USE_ASH)
    994   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    995   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    996     return;
    997 #endif
    998 
    999   ASSERT_TRUE(RunExtensionTest("target_list")) << message_;
   1000 }
   1001 
   1002 }  // namespace
   1003