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