• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/command_line.h"
6 #include "base/path_service.h"
7 #include "base/string_util.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/debugger/devtools_client_host.h"
10 #include "chrome/browser/debugger/devtools_manager.h"
11 #include "chrome/browser/debugger/devtools_window.h"
12 #include "chrome/browser/extensions/extension_host.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/common/chrome_paths.h"
17 #include "chrome/test/in_process_browser_test.h"
18 #include "chrome/test/ui_test_utils.h"
19 #include "content/browser/renderer_host/render_view_host.h"
20 #include "content/browser/tab_contents/tab_contents.h"
21 #include "content/common/notification_registrar.h"
22 #include "content/common/notification_service.h"
23 #include "net/test/test_server.h"
24 
25 namespace {
26 
27 // Used to block until a dev tools client window's browser is closed.
28 class BrowserClosedObserver : public NotificationObserver {
29  public:
BrowserClosedObserver(Browser * browser)30   explicit BrowserClosedObserver(Browser* browser) {
31     registrar_.Add(this, NotificationType::BROWSER_CLOSED,
32                    Source<Browser>(browser));
33     ui_test_utils::RunMessageLoop();
34   }
35 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)36   virtual void Observe(NotificationType type,
37                        const NotificationSource& source,
38                        const NotificationDetails& details) {
39     MessageLoopForUI::current()->Quit();
40   }
41 
42  private:
43   NotificationRegistrar registrar_;
44   DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
45 };
46 
47 // The delay waited in some cases where we don't have a notifications for an
48 // action we take.
49 const int kActionDelayMs = 500;
50 
51 const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html";
52 const char kHeapProfilerPage[] = "files/devtools/heap_profiler.html";
53 const char kPauseWhenLoadingDevTools[] =
54     "files/devtools/pause_when_loading_devtools.html";
55 const char kPauseWhenScriptIsRunning[] =
56     "files/devtools/pause_when_script_is_running.html";
57 const char kPageWithContentScript[] =
58     "files/devtools/page_with_content_script.html";
59 
60 
61 class DevToolsSanityTest : public InProcessBrowserTest {
62  public:
DevToolsSanityTest()63   DevToolsSanityTest() {
64     set_show_window(true);
65     EnableDOMAutomation();
66   }
67 
68  protected:
RunTest(const std::string & test_name,const std::string & test_page)69   void RunTest(const std::string& test_name, const std::string& test_page) {
70     OpenDevToolsWindow(test_page);
71     std::string result;
72 
73     // At first check that JavaScript part of the front-end is loaded by
74     // checking that global variable uiTests exists(it's created after all js
75     // files have been loaded) and has runTest method.
76     ASSERT_TRUE(
77         ui_test_utils::ExecuteJavaScriptAndExtractString(
78             client_contents_->render_view_host(),
79             L"",
80             L"window.domAutomationController.send("
81             L"'' + (window.uiTests && (typeof uiTests.runTest)));",
82             &result));
83 
84     if (result == "function") {
85       ASSERT_TRUE(
86           ui_test_utils::ExecuteJavaScriptAndExtractString(
87               client_contents_->render_view_host(),
88               L"",
89               UTF8ToWide(StringPrintf("uiTests.runTest('%s')",
90                                       test_name.c_str())),
91               &result));
92       EXPECT_EQ("[OK]", result);
93     } else {
94       FAIL() << "DevTools front-end is broken.";
95     }
96     CloseDevToolsWindow();
97   }
98 
OpenDevToolsWindow(const std::string & test_page)99   void OpenDevToolsWindow(const std::string& test_page) {
100     ASSERT_TRUE(test_server()->Start());
101     GURL url = test_server()->GetURL(test_page);
102     ui_test_utils::NavigateToURL(browser(), url);
103 
104     inspected_rvh_ = GetInspectedTab()->render_view_host();
105     DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
106     devtools_manager->OpenDevToolsWindow(inspected_rvh_);
107 
108     DevToolsClientHost* client_host =
109         devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
110     window_ = client_host->AsDevToolsWindow();
111     RenderViewHost* client_rvh = window_->GetRenderViewHost();
112     client_contents_ = client_rvh->delegate()->GetAsTabContents();
113     ui_test_utils::WaitForNavigation(&client_contents_->controller());
114   }
115 
GetInspectedTab()116   TabContents* GetInspectedTab() {
117     return browser()->GetTabContentsAt(0);
118   }
119 
CloseDevToolsWindow()120   void CloseDevToolsWindow() {
121     DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
122     // UnregisterDevToolsClientHostFor may destroy window_ so store the browser
123     // first.
124     Browser* browser = window_->browser();
125     devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);
126 
127     // Wait only when DevToolsWindow has a browser. For docked DevTools, this
128     // is NULL and we skip the wait.
129     if (browser)
130       BrowserClosedObserver close_observer(browser);
131   }
132 
133   TabContents* client_contents_;
134   DevToolsWindow* window_;
135   RenderViewHost* inspected_rvh_;
136 };
137 
138 
139 class CancelableQuitTask : public Task {
140  public:
CancelableQuitTask(const std::string & timeout_message)141   explicit CancelableQuitTask(const std::string& timeout_message)
142       : timeout_message_(timeout_message),
143         cancelled_(false) {
144   }
145 
cancel()146   void cancel() {
147     cancelled_ = true;
148   }
149 
Run()150   virtual void Run() {
151     if (cancelled_) {
152       return;
153     }
154     FAIL() << timeout_message_;
155     MessageLoop::current()->Quit();
156   }
157 
158  private:
159   std::string timeout_message_;
160   bool cancelled_;
161 };
162 
163 
164 // Base class for DevTools tests that test devtools functionality for
165 // extensions and content scripts.
166 class DevToolsExtensionDebugTest : public DevToolsSanityTest,
167                                    public NotificationObserver {
168  public:
DevToolsExtensionDebugTest()169   DevToolsExtensionDebugTest() : DevToolsSanityTest() {
170     PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_);
171     test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools");
172     test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions");
173   }
174 
175  protected:
176   // Load an extention from test\data\devtools\extensions\<extension_name>
LoadExtension(const char * extension_name)177   void LoadExtension(const char* extension_name) {
178     FilePath path = test_extensions_dir_.AppendASCII(extension_name);
179     ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension.";
180   }
181 
182  private:
LoadExtensionFromPath(const FilePath & path)183   bool LoadExtensionFromPath(const FilePath& path) {
184     ExtensionService* service = browser()->profile()->GetExtensionService();
185     size_t num_before = service->extensions()->size();
186     {
187       NotificationRegistrar registrar;
188       registrar.Add(this, NotificationType::EXTENSION_LOADED,
189                     NotificationService::AllSources());
190       CancelableQuitTask* delayed_quit =
191           new CancelableQuitTask("Extension load timed out.");
192       MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
193           4*1000);
194       service->LoadExtension(path);
195       ui_test_utils::RunMessageLoop();
196       delayed_quit->cancel();
197     }
198     size_t num_after = service->extensions()->size();
199     if (num_after != (num_before + 1))
200       return false;
201 
202     return WaitForExtensionHostsToLoad();
203   }
204 
WaitForExtensionHostsToLoad()205   bool WaitForExtensionHostsToLoad() {
206     // Wait for all the extension hosts that exist to finish loading.
207     // NOTE: This assumes that the extension host list is not changing while
208     // this method is running.
209 
210     NotificationRegistrar registrar;
211     registrar.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
212                   NotificationService::AllSources());
213     CancelableQuitTask* delayed_quit =
214         new CancelableQuitTask("Extension host load timed out.");
215     MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
216         4*1000);
217 
218     ExtensionProcessManager* manager =
219           browser()->profile()->GetExtensionProcessManager();
220     for (ExtensionProcessManager::const_iterator iter = manager->begin();
221          iter != manager->end();) {
222       if ((*iter)->did_stop_loading())
223         ++iter;
224       else
225         ui_test_utils::RunMessageLoop();
226     }
227 
228     delayed_quit->cancel();
229     return true;
230   }
231 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)232   void Observe(NotificationType type,
233                const NotificationSource& source,
234                const NotificationDetails& details) {
235     switch (type.value) {
236       case NotificationType::EXTENSION_LOADED:
237       case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
238         MessageLoopForUI::current()->Quit();
239         break;
240       default:
241         NOTREACHED();
242         break;
243     }
244   }
245 
246   FilePath test_extensions_dir_;
247 };
248 
249 // Tests heap profiler.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,FAILS_TestHeapProfiler)250 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, FAILS_TestHeapProfiler) {
251   RunTest("testHeapProfiler", kHeapProfilerPage);
252 }
253 
254 // Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,TestShowScriptsTab)255 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
256   RunTest("testShowScriptsTab", kDebuggerTestPage);
257 }
258 
259 // Tests that scripts tab is populated with inspected scripts even if it
260 // hadn't been shown by the moment inspected paged refreshed.
261 // @see http://crbug.com/26312
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,TestScriptsTabIsPopulatedOnInspectedPageRefresh)262 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
263                        TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
264   // Clear inspector settings to ensure that Elements will be
265   // current panel when DevTools window is open.
266   GetInspectedTab()->render_view_host()->delegate()->ClearInspectorSettings();
267   RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh",
268           kDebuggerTestPage);
269 }
270 
271 // Tests that a content script is in the scripts list.
272 // This test is disabled, see bug 28961.
IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest,TestContentScriptIsPresent)273 IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest,
274                        TestContentScriptIsPresent) {
275   LoadExtension("simple_content_script");
276   RunTest("testContentScriptIsPresent", kPageWithContentScript);
277 }
278 
279 // Tests that scripts are not duplicated after Scripts Panel switch.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,TestNoScriptDuplicatesOnPanelSwitch)280 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
281                        TestNoScriptDuplicatesOnPanelSwitch) {
282   RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
283 }
284 
285 // Tests that debugger works correctly if pause event occurs when DevTools
286 // frontend is being loaded.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,TestPauseWhenLoadingDevTools)287 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) {
288   RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
289 }
290 
291 // Tests that pressing 'Pause' will pause script execution if the script
292 // is already running.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,TestPauseWhenScriptIsRunning)293 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) {
294   RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
295 }
296 
297 }  // namespace
298