957103db24ee6131b0c1bde88e4d3ab2bdb3decc
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / window_open_apitest.cc
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/command_line.h"
6 #include "base/memory/scoped_vector.h"
7 #include "base/path_service.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/extensions/extension_host.h"
11 #include "chrome/browser/extensions/extension_test_message_listener.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_finder.h"
15 #include "chrome/browser/ui/browser_iterator.h"
16 #include "chrome/browser/ui/panels/panel_manager.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/test/base/test_switches.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/result_codes.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "extensions/browser/extension_system.h"
27 #include "extensions/browser/process_manager.h"
28 #include "extensions/common/extension.h"
29 #include "extensions/common/switches.h"
30 #include "net/dns/mock_host_resolver.h"
31 #include "net/test/embedded_test_server/embedded_test_server.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33
34 #if defined(USE_ASH)
35 #include "apps/app_window_registry.h"
36 #endif
37
38 #if defined(USE_ASH) && !defined(OS_WIN)
39 // TODO(stevenjb): Figure out the correct behavior for Ash + Win
40 #define USE_ASH_PANELS
41 #endif
42
43 using content::OpenURLParams;
44 using content::Referrer;
45 using content::WebContents;
46
47 // Disabled, http://crbug.com/64899.
48 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpen) {
49   CommandLine::ForCurrentProcess()->AppendSwitch(
50       extensions::switches::kEnableExperimentalExtensionApis);
51
52   ResultCatcher catcher;
53   ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
54       .AppendASCII("window_open").AppendASCII("spanning")));
55   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
56 }
57
58 int GetPanelCount(Browser* browser) {
59 #if defined(USE_ASH_PANELS)
60   return static_cast<int>(
61       apps::AppWindowRegistry::Get(browser->profile())->app_windows().size());
62 #else
63   return PanelManager::GetInstance()->num_panels();
64 #endif
65 }
66
67 bool WaitForTabsAndPopups(Browser* browser,
68                           int num_tabs,
69                           int num_popups,
70                           int num_panels) {
71   SCOPED_TRACE(
72       base::StringPrintf("WaitForTabsAndPopups tabs:%d, popups:%d, panels:%d",
73                          num_tabs, num_popups, num_panels));
74   // We start with one tab and one browser already open.
75   ++num_tabs;
76   size_t num_browsers = static_cast<size_t>(num_popups) + 1;
77
78   const base::TimeDelta kWaitTime = base::TimeDelta::FromSeconds(10);
79   base::TimeTicks end_time = base::TimeTicks::Now() + kWaitTime;
80   while (base::TimeTicks::Now() < end_time) {
81     if (chrome::GetBrowserCount(browser->profile(),
82                                 browser->host_desktop_type()) == num_browsers &&
83         browser->tab_strip_model()->count() == num_tabs &&
84         GetPanelCount(browser) == num_panels)
85       break;
86
87     content::RunAllPendingInMessageLoop();
88   }
89
90   EXPECT_EQ(num_browsers,
91             chrome::GetBrowserCount(browser->profile(),
92                                     browser->host_desktop_type()));
93   EXPECT_EQ(num_tabs, browser->tab_strip_model()->count());
94   EXPECT_EQ(num_panels, GetPanelCount(browser));
95
96   int num_popups_seen = 0;
97   for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
98     if (*iter == browser)
99       continue;
100
101     EXPECT_TRUE((*iter)->is_type_popup());
102     ++num_popups_seen;
103   }
104   EXPECT_EQ(num_popups, num_popups_seen);
105
106   return ((num_browsers ==
107                chrome::GetBrowserCount(browser->profile(),
108                                        browser->host_desktop_type())) &&
109           (num_tabs == browser->tab_strip_model()->count()) &&
110           (num_panels == GetPanelCount(browser)) &&
111           (num_popups == num_popups_seen));
112 }
113
114 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BrowserIsApp) {
115   host_resolver()->AddRule("a.com", "127.0.0.1");
116   ASSERT_TRUE(StartEmbeddedTestServer());
117   ASSERT_TRUE(LoadExtension(
118       test_data_dir_.AppendASCII("window_open").AppendASCII("browser_is_app")));
119
120   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 0, 2, 0));
121
122   for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
123     if (*iter == browser())
124       ASSERT_FALSE(iter->is_app());
125     else
126       ASSERT_TRUE(iter->is_app());
127   }
128 }
129
130 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupDefault) {
131   ASSERT_TRUE(StartEmbeddedTestServer());
132   ASSERT_TRUE(LoadExtension(
133       test_data_dir_.AppendASCII("window_open").AppendASCII("popup")));
134
135   const int num_tabs = 1;
136   const int num_popups = 0;
137   EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0));
138 }
139
140 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupIframe) {
141   ASSERT_TRUE(StartEmbeddedTestServer());
142   base::FilePath test_data_dir;
143   PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
144   embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
145   ASSERT_TRUE(LoadExtension(
146       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_iframe")));
147
148   const int num_tabs = 0;
149   const int num_popups = 1;
150   EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0));
151 }
152
153 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupLarge) {
154   ASSERT_TRUE(StartEmbeddedTestServer());
155   ASSERT_TRUE(LoadExtension(
156       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_large")));
157
158   // On other systems this should open a new popup window.
159   const int num_tabs = 0;
160   const int num_popups = 1;
161   EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0));
162 }
163
164 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupSmall) {
165   ASSERT_TRUE(StartEmbeddedTestServer());
166   ASSERT_TRUE(LoadExtension(
167       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_small")));
168
169   // On ChromeOS this should open a new panel (acts like a new popup window).
170   // On other systems this should open a new popup window.
171   const int num_tabs = 0;
172   const int num_popups = 1;
173   EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0));
174 }
175
176 // Disabled on Windows. Often times out or fails: crbug.com/177530
177 #if defined(OS_WIN)
178 #define MAYBE_PopupBlockingExtension DISABLED_PopupBlockingExtension
179 #else
180 #define MAYBE_PopupBlockingExtension PopupBlockingExtension
181 #endif
182 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_PopupBlockingExtension) {
183   host_resolver()->AddRule("*", "127.0.0.1");
184   ASSERT_TRUE(StartEmbeddedTestServer());
185
186   ASSERT_TRUE(LoadExtension(
187       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_blocking")
188       .AppendASCII("extension")));
189
190   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 5, 3, 0));
191 }
192
193 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingHostedApp) {
194   host_resolver()->AddRule("*", "127.0.0.1");
195   ASSERT_TRUE(test_server()->Start());
196
197   ASSERT_TRUE(LoadExtension(
198       test_data_dir_.AppendASCII("window_open").AppendASCII("popup_blocking")
199       .AppendASCII("hosted_app")));
200
201   // The app being tested owns the domain a.com .  The test URLs we navigate
202   // to below must be within that domain, so that they fall within the app's
203   // web extent.
204   GURL::Replacements replace_host;
205   std::string a_dot_com = "a.com";
206   replace_host.SetHostStr(a_dot_com);
207
208   const std::string popup_app_contents_path(
209     "files/extensions/api_test/window_open/popup_blocking/hosted_app/");
210
211   GURL open_tab =
212       test_server()->GetURL(popup_app_contents_path + "open_tab.html")
213           .ReplaceComponents(replace_host);
214   GURL open_popup =
215       test_server()->GetURL(popup_app_contents_path + "open_popup.html")
216           .ReplaceComponents(replace_host);
217
218   browser()->OpenURL(OpenURLParams(
219       open_tab, Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_TYPED,
220       false));
221   browser()->OpenURL(OpenURLParams(
222       open_popup, Referrer(), NEW_FOREGROUND_TAB,
223       content::PAGE_TRANSITION_TYPED, false));
224
225   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 3, 1, 0));
226 }
227
228 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowArgumentsOverflow) {
229   ASSERT_TRUE(RunExtensionTest("window_open/argument_overflow")) << message_;
230 }
231
232 class WindowOpenPanelDisabledTest : public ExtensionApiTest {
233   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
234     ExtensionApiTest::SetUpCommandLine(command_line);
235     // TODO(jennb): Re-enable when panels are enabled by default.
236     // command_line->AppendSwitch(switches::kDisablePanels);
237   }
238 };
239
240 IN_PROC_BROWSER_TEST_F(WindowOpenPanelDisabledTest,
241                        DISABLED_WindowOpenPanelNotEnabled) {
242   ASSERT_TRUE(RunExtensionTest("window_open/panel_not_enabled")) << message_;
243 }
244
245 class WindowOpenPanelTest : public ExtensionApiTest {
246   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
247     ExtensionApiTest::SetUpCommandLine(command_line);
248     command_line->AppendSwitch(switches::kEnablePanels);
249   }
250 };
251
252 #if defined(USE_ASH_PANELS)
253 // On Ash, this currently fails because we're currently opening new panel
254 // windows as popup windows instead.
255 #define MAYBE_WindowOpenPanel DISABLED_WindowOpenPanel
256 #else
257 #define MAYBE_WindowOpenPanel WindowOpenPanel
258 #endif
259 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanel) {
260   ASSERT_TRUE(RunExtensionTest("window_open/panel")) << message_;
261 }
262
263 #if defined(USE_ASH_PANELS)
264 // On Ash, this currently fails because we're currently opening new panel
265 // windows as popup windows instead.
266 #define MAYBE_WindowOpenPanelDetached DISABLED_WindowOpenPanelDetached
267 #else
268 #define MAYBE_WindowOpenPanelDetached WindowOpenPanelDetached
269 #endif
270 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanelDetached) {
271   ASSERT_TRUE(RunExtensionTest("window_open/panel_detached")) << message_;
272 }
273
274 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest,
275                        CloseNonExtensionPanelsOnUninstall) {
276 #if defined(OS_WIN) && defined(USE_ASH)
277   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
278   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
279     return;
280 #endif
281
282 #if defined(USE_ASH_PANELS)
283   // On Ash, new panel windows open as popup windows instead.
284   int num_popups, num_panels;
285   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) {
286     num_popups = 2;
287     num_panels = 2;
288   } else {
289     num_popups = 4;
290     num_panels = 0;
291   }
292 #else
293   int num_popups = 2;
294   int num_panels = 2;
295 #endif
296   ASSERT_TRUE(StartEmbeddedTestServer());
297
298   // Setup listeners to wait on strings we expect the extension pages to send.
299   std::vector<std::string> test_strings;
300   test_strings.push_back("content_tab");
301   if (num_panels)
302     test_strings.push_back("content_panel");
303   test_strings.push_back("content_popup");
304
305   ScopedVector<ExtensionTestMessageListener> listeners;
306   for (size_t i = 0; i < test_strings.size(); ++i) {
307     listeners.push_back(
308         new ExtensionTestMessageListener(test_strings[i], false));
309   }
310
311   const extensions::Extension* extension = LoadExtension(
312       test_data_dir_.AppendASCII("window_open").AppendASCII(
313           "close_panels_on_uninstall"));
314   ASSERT_TRUE(extension);
315
316   // Two tabs. One in extension domain and one in non-extension domain.
317   // Two popups - one in extension domain and one in non-extension domain.
318   // Two panels - one in extension domain and one in non-extension domain.
319   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, num_panels));
320
321   // Wait on test messages to make sure the pages loaded.
322   for (size_t i = 0; i < listeners.size(); ++i)
323     ASSERT_TRUE(listeners[i]->WaitUntilSatisfied());
324
325   UninstallExtension(extension->id());
326
327   // Wait for the tabs and popups in non-extension domain to stay open.
328   // Expect everything else, including panels, to close.
329   num_popups -= 1;
330 #if defined(USE_ASH_PANELS)
331   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) {
332     // On Ash, new panel windows open as popup windows instead, so there are 2
333     // extension domain popups that will close (instead of 1 popup on non-Ash).
334     num_popups -= 1;
335   }
336 #endif
337 #if defined(USE_ASH)
338 #if !defined(OS_WIN)
339   // On linux ash we close all popup applications when closing its extension.
340   num_popups = 0;
341 #endif
342 #endif
343   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 1, num_popups, 0));
344 }
345
346 // This test isn't applicable on Chrome OS, which automatically reloads
347 // crashed pages.
348 #if !defined(OS_CHROMEOS)
349 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, ClosePanelsOnExtensionCrash) {
350 #if defined(USE_ASH_PANELS)
351   // On Ash, new panel windows open as popup windows instead.
352   int num_popups = 4;
353   int num_panels = 0;
354 #else
355   int num_popups = 2;
356   int num_panels = 2;
357 #endif
358   ASSERT_TRUE(StartEmbeddedTestServer());
359
360   // Setup listeners to wait on strings we expect the extension pages to send.
361   std::vector<std::string> test_strings;
362   test_strings.push_back("content_tab");
363   if (num_panels)
364     test_strings.push_back("content_panel");
365   test_strings.push_back("content_popup");
366
367   ScopedVector<ExtensionTestMessageListener> listeners;
368   for (size_t i = 0; i < test_strings.size(); ++i) {
369     listeners.push_back(
370         new ExtensionTestMessageListener(test_strings[i], false));
371   }
372
373   const extensions::Extension* extension = LoadExtension(
374       test_data_dir_.AppendASCII("window_open").AppendASCII(
375           "close_panels_on_uninstall"));
376   ASSERT_TRUE(extension);
377
378   // Two tabs. One in extension domain and one in non-extension domain.
379   // Two popups - one in extension domain and one in non-extension domain.
380   // Two panels - one in extension domain and one in non-extension domain.
381   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, num_panels));
382
383   // Wait on test messages to make sure the pages loaded.
384   for (size_t i = 0; i < listeners.size(); ++i)
385     ASSERT_TRUE(listeners[i]->WaitUntilSatisfied());
386
387   // Crash the extension.
388   extensions::ExtensionHost* extension_host =
389       extensions::ExtensionSystem::Get(browser()->profile())->
390           process_manager()->GetBackgroundHostForExtension(extension->id());
391   ASSERT_TRUE(extension_host);
392   base::KillProcess(extension_host->render_process_host()->GetHandle(),
393                     content::RESULT_CODE_KILLED, false);
394   WaitForExtensionCrash(extension->id());
395
396   // Only expect panels to close. The rest stay open to show a sad-tab.
397   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, 0));
398 }
399 #endif  // !defined(OS_CHROMEOS)
400
401 #if defined(USE_ASH_PANELS)
402 // This test is not applicable on Ash. The modified window.open behavior only
403 // applies to non-Ash panel windows.
404 #define MAYBE_WindowOpenFromPanel DISABLED_WindowOpenFromPanel
405 #else
406 #define MAYBE_WindowOpenFromPanel WindowOpenFromPanel
407 #endif
408 IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenFromPanel) {
409   ASSERT_TRUE(StartEmbeddedTestServer());
410
411   // Load the extension that will open a panel which then calls window.open.
412   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("window_open").
413                             AppendASCII("panel_window_open")));
414
415   // Expect one panel (opened by extension) and one tab (from the panel calling
416   // window.open). Panels modify the WindowOpenDisposition in window.open
417   // to always open in a tab.
418   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 1, 0, 1));
419 }
420
421 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpener) {
422   ASSERT_TRUE(RunExtensionTest("window_open/opener")) << message_;
423 }
424
425 #if defined(OS_MACOSX)
426 // Extension popup windows are incorrectly sized on OSX, crbug.com/225601
427 #define MAYBE_WindowOpenSized DISABLED_WindowOpenSized
428 #else
429 #define MAYBE_WindowOpenSized WindowOpenSized
430 #endif
431 // Ensure that the width and height properties of a window opened with
432 // chrome.windows.create match the creation parameters. See crbug.com/173831.
433 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_WindowOpenSized) {
434   ASSERT_TRUE(RunExtensionTest("window_open/window_size")) << message_;
435   EXPECT_TRUE(WaitForTabsAndPopups(browser(), 0, 1, 0));
436 }
437
438 // Tests that an extension page can call window.open to an extension URL and
439 // the new window has extension privileges.
440 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenExtension) {
441   ASSERT_TRUE(LoadExtension(
442       test_data_dir_.AppendASCII("uitest").AppendASCII("window_open")));
443
444   GURL start_url(std::string("chrome-extension://") +
445       last_loaded_extension_id() + "/test.html");
446   ui_test_utils::NavigateToURL(browser(), start_url);
447   WebContents* newtab = NULL;
448   ASSERT_NO_FATAL_FAILURE(
449       OpenWindow(browser()->tab_strip_model()->GetActiveWebContents(),
450       start_url.Resolve("newtab.html"), true, &newtab));
451
452   bool result = false;
453   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(newtab, "testExtensionApi()",
454                                                    &result));
455   EXPECT_TRUE(result);
456 }
457
458 // Tests that if an extension page calls window.open to an invalid extension
459 // URL, the browser doesn't crash.
460 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenInvalidExtension) {
461   ASSERT_TRUE(LoadExtension(
462       test_data_dir_.AppendASCII("uitest").AppendASCII("window_open")));
463
464   GURL start_url(std::string("chrome-extension://") +
465       last_loaded_extension_id() + "/test.html");
466   ui_test_utils::NavigateToURL(browser(), start_url);
467   ASSERT_NO_FATAL_FAILURE(
468       OpenWindow(browser()->tab_strip_model()->GetActiveWebContents(),
469       GURL("chrome-extension://thisissurelynotavalidextensionid/newtab.html"),
470       false, NULL));
471
472   // If we got to this point, we didn't crash, so we're good.
473 }
474
475 // Tests that calling window.open from the newtab page to an extension URL
476 // gives the new window extension privileges - even though the opening page
477 // does not have extension privileges, we break the script connection, so
478 // there is no privilege leak.
479 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WindowOpenNoPrivileges) {
480   ASSERT_TRUE(LoadExtension(
481       test_data_dir_.AppendASCII("uitest").AppendASCII("window_open")));
482
483   ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
484   WebContents* newtab = NULL;
485   ASSERT_NO_FATAL_FAILURE(
486       OpenWindow(browser()->tab_strip_model()->GetActiveWebContents(),
487       GURL(std::string("chrome-extension://") + last_loaded_extension_id() +
488           "/newtab.html"), false, &newtab));
489
490   // Extension API should succeed.
491   bool result = false;
492   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(newtab, "testExtensionApi()",
493                                                    &result));
494   EXPECT_TRUE(result);
495 }