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