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