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 55using content::BrowserThread; 56using content::DevToolsAgentHost; 57using content::NavigationController; 58using content::RenderViewHost; 59using content::WebContents; 60using content::WorkerService; 61using content::WorkerServiceObserver; 62 63namespace { 64 65const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html"; 66const char kPauseWhenLoadingDevTools[] = 67 "files/devtools/pause_when_loading_devtools.html"; 68const char kPauseWhenScriptIsRunning[] = 69 "files/devtools/pause_when_script_is_running.html"; 70const char kPageWithContentScript[] = 71 "files/devtools/page_with_content_script.html"; 72const char kNavigateBackTestPage[] = 73 "files/devtools/navigate_back.html"; 74const char kChunkedTestPage[] = "chunked"; 75const char kSlowTestPage[] = 76 "chunked?waitBeforeHeaders=100&waitBetweenChunks=100&chunksNumber=2"; 77const char kSharedWorkerTestPage[] = 78 "files/workers/workers_ui_shared_worker.html"; 79const char kReloadSharedWorkerTestPage[] = 80 "files/workers/debug_shared_worker_initialization.html"; 81 82void 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 107class 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. 151class 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 165DevToolsWindowBeforeUnloadObserver::DevToolsWindowBeforeUnloadObserver( 166 DevToolsWindow* devtools_window) 167 : WebContentsObserver( 168 DevToolsWindowTesting::Get(devtools_window)->main_web_contents()), 169 m_fired(false) { 170} 171 172void DevToolsWindowBeforeUnloadObserver::Wait() { 173 if (m_fired) 174 return; 175 message_loop_runner_ = new content::MessageLoopRunner; 176 message_loop_runner_->Run(); 177} 178 179void 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 186class 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 283class DevToolsUnresponsiveBeforeUnloadTest: public DevToolsBeforeUnloadTest { 284 public: 285 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {} 286}; 287 288void 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. 295class 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 384class DevToolsExperimentalExtensionTest : public DevToolsExtensionTest { 385 public: 386 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 387 command_line->AppendSwitch( 388 extensions::switches::kEnableExperimentalExtensionApis); 389 } 390}; 391 392class 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. 522IN_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. 529IN_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. 537IN_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. 545IN_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. 552IN_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. 560IN_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. 568IN_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 585IN_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 608IN_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. 621IN_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. 685IN_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 692IN_PROC_BROWSER_TEST_F( 693 DevToolsSanityTest, 694 TestScriptsTabIsPopulatedOnInspectedPageRefresh) { 695 RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh", 696 kDebuggerTestPage); 697} 698 699// Tests that chrome.devtools extension is correctly exposed. 700IN_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. 715IN_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. 723IN_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. 730IN_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. 737IN_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. 744IN_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 757IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, 758 MAYBE_TestPauseWhenScriptIsRunning) { 759 RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning); 760} 761 762// Tests network timing. 763IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkTiming) { 764 RunTest("testNetworkTiming", kSlowTestPage); 765} 766 767// Tests network size. 768IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkSize) { 769 RunTest("testNetworkSize", kChunkedTestPage); 770} 771 772// Tests raw headers text. 773IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkSyncSize) { 774 RunTest("testNetworkSyncSize", kChunkedTestPage); 775} 776 777// Tests raw headers text. 778IN_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 789IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestConsoleOnNavigateBack) { 790 RunTest("testConsoleOnNavigateBack", kNavigateBackTestPage); 791} 792 793// https://crbug.com/397889 794IN_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. 801IN_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. 818IN_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. 829IN_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 841IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestReattachAfterCrash) { 842 RunTest("testReattachAfterCrash", std::string()); 843} 844 845IN_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 859IN_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 870IN_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 889class DevToolsAgentHostTest : public InProcessBrowserTest {}; 890 891// Tests DevToolsAgentHost retention by its target. 892IN_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 906class 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 917IN_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