webstore_startup_installer_browsertest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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/scoped_observer.h"
7#include "chrome/browser/chrome_notification_types.h"
8#include "chrome/browser/extensions/extension_install_prompt.h"
9#include "chrome/browser/extensions/extension_install_ui.h"
10#include "chrome/browser/extensions/extension_service.h"
11#include "chrome/browser/extensions/startup_helper.h"
12#include "chrome/browser/extensions/webstore_installer_test.h"
13#include "chrome/browser/infobars/infobar_service.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/tabs/tab_strip_model.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/test/base/in_process_browser_test.h"
20#include "chrome/test/base/test_switches.h"
21#include "chrome/test/base/ui_test_utils.h"
22#include "content/public/browser/notification_registrar.h"
23#include "content/public/browser/notification_service.h"
24#include "content/public/browser/notification_types.h"
25#include "content/public/browser/web_contents.h"
26#include "content/public/test/browser_test_utils.h"
27#include "extensions/browser/extension_host.h"
28#include "extensions/browser/extension_registry.h"
29#include "extensions/browser/extension_registry_observer.h"
30#include "extensions/browser/extension_system.h"
31#include "extensions/common/extension_builder.h"
32#include "extensions/common/value_builder.h"
33#include "net/dns/mock_host_resolver.h"
34#include "url/gurl.h"
35
36using content::WebContents;
37using extensions::DictionaryBuilder;
38using extensions::Extension;
39using extensions::ExtensionBuilder;
40using extensions::ListBuilder;
41
42const char kWebstoreDomain[] = "cws.com";
43const char kAppDomain[] = "app.com";
44const char kNonAppDomain[] = "nonapp.com";
45const char kTestExtensionId[] = "ecglahbcnmdpdciemllbhojghbkagdje";
46const char kTestDataPath[] = "extensions/api_test/webstore_inline_install";
47const char kCrxFilename[] = "extension.crx";
48
49class WebstoreStartupInstallerTest : public WebstoreInstallerTest {
50 public:
51  WebstoreStartupInstallerTest()
52      : WebstoreInstallerTest(
53            kWebstoreDomain,
54            kTestDataPath,
55            kCrxFilename,
56            kAppDomain,
57            kNonAppDomain) {}
58};
59
60IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, Install) {
61  ExtensionInstallPrompt::g_auto_confirm_for_tests =
62      ExtensionInstallPrompt::ACCEPT;
63
64  ui_test_utils::NavigateToURL(
65      browser(), GenerateTestServerUrl(kAppDomain, "install.html"));
66
67  RunTest("runTest");
68
69  const extensions::Extension* extension =
70      extensions::ExtensionRegistry::Get(
71          browser()->profile())->enabled_extensions().GetByID(kTestExtensionId);
72  EXPECT_TRUE(extension);
73}
74
75IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
76    InstallNotAllowedFromNonVerifiedDomains) {
77  ExtensionInstallPrompt::g_auto_confirm_for_tests =
78      ExtensionInstallPrompt::CANCEL;
79  ui_test_utils::NavigateToURL(
80      browser(),
81      GenerateTestServerUrl(kNonAppDomain, "install_non_verified_domain.html"));
82
83  RunTest("runTest1");
84  RunTest("runTest2");
85}
86
87IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, FindLink) {
88  ui_test_utils::NavigateToURL(
89      browser(), GenerateTestServerUrl(kAppDomain, "find_link.html"));
90
91  RunTest("runTest");
92}
93
94// Flakes on all platforms: http://crbug.com/95713, http://crbug.com/229947
95IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
96                       DISABLED_ArgumentValidation) {
97  ExtensionInstallPrompt::g_auto_confirm_for_tests =
98      ExtensionInstallPrompt::CANCEL;
99
100  // Each of these tests has to run separately, since one page/tab can
101  // only have one in-progress install request. These tests don't all pass
102  // callbacks to install, so they have no way to wait for the installation
103  // to complete before starting the next test.
104  bool is_finished = false;
105  for (int i = 0; !is_finished; ++i) {
106    ui_test_utils::NavigateToURL(
107        browser(),
108        GenerateTestServerUrl(kAppDomain, "argument_validation.html"));
109    is_finished = !RunIndexedTest("runTest", i);
110  }
111}
112
113IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, MultipleInstallCalls) {
114  ExtensionInstallPrompt::g_auto_confirm_for_tests =
115      ExtensionInstallPrompt::CANCEL;
116
117  ui_test_utils::NavigateToURL(
118      browser(),
119      GenerateTestServerUrl(kAppDomain, "multiple_install_calls.html"));
120  RunTest("runTest");
121}
122
123IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallNotSupported) {
124  ExtensionInstallPrompt::g_auto_confirm_for_tests =
125      ExtensionInstallPrompt::CANCEL;
126  ui_test_utils::NavigateToURL(
127      browser(),
128      GenerateTestServerUrl(kAppDomain, "install_not_supported.html"));
129
130  ui_test_utils::WindowedTabAddedNotificationObserver observer(
131      content::NotificationService::AllSources());
132  RunTest("runTest");
133  observer.Wait();
134
135  // The inline install should fail, and a store-provided URL should be opened
136  // in a new tab.
137  WebContents* web_contents =
138      browser()->tab_strip_model()->GetActiveWebContents();
139  EXPECT_EQ(GURL("http://cws.com/show-me-the-money"), web_contents->GetURL());
140}
141
142// Regression test for http://crbug.com/144991.
143IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallFromHostedApp) {
144  ExtensionInstallPrompt::g_auto_confirm_for_tests =
145      ExtensionInstallPrompt::ACCEPT;
146
147  const GURL kInstallUrl = GenerateTestServerUrl(kAppDomain, "install.html");
148
149  // We're forced to construct a hosted app dynamically because we need the
150  // app to run on a declared URL, but we don't know the port ahead of time.
151  scoped_refptr<const Extension> hosted_app = ExtensionBuilder()
152      .SetManifest(DictionaryBuilder()
153          .Set("name", "hosted app")
154          .Set("version", "1")
155          .Set("app", DictionaryBuilder()
156              .Set("urls", ListBuilder().Append(kInstallUrl.spec()))
157              .Set("launch", DictionaryBuilder()
158                  .Set("web_url", kInstallUrl.spec())))
159          .Set("manifest_version", 2))
160      .Build();
161  ASSERT_TRUE(hosted_app.get());
162
163  ExtensionService* extension_service =
164      extensions::ExtensionSystem::Get(browser()->profile())->
165          extension_service();
166
167  extension_service->AddExtension(hosted_app.get());
168  EXPECT_TRUE(extension_service->extensions()->Contains(hosted_app->id()));
169
170  ui_test_utils::NavigateToURL(browser(), kInstallUrl);
171
172  EXPECT_FALSE(extension_service->extensions()->Contains(kTestExtensionId));
173  RunTest("runTest");
174  EXPECT_TRUE(extension_service->extensions()->Contains(kTestExtensionId));
175}
176
177class WebstoreStartupInstallerSupervisedUsersTest
178    : public WebstoreStartupInstallerTest {
179 public:
180  // InProcessBrowserTest overrides:
181  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
182    WebstoreStartupInstallerTest::SetUpCommandLine(command_line);
183    command_line->AppendSwitchASCII(switches::kSupervisedUserId, "asdf");
184  }
185};
186
187IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerSupervisedUsersTest,
188                       InstallProhibited) {
189#if defined(OS_WIN) && defined(USE_ASH)
190  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
191  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
192          switches::kAshBrowserTests))
193    return;
194#endif
195
196  ExtensionInstallPrompt::g_auto_confirm_for_tests =
197      ExtensionInstallPrompt::ACCEPT;
198
199  ui_test_utils::NavigateToURL(
200      browser(), GenerateTestServerUrl(kAppDomain, "install_prohibited.html"));
201
202  RunTest("runTest");
203
204  // No error infobar should show up.
205  WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
206  InfoBarService* infobar_service = InfoBarService::FromWebContents(contents);
207  EXPECT_EQ(0u, infobar_service->infobar_count());
208}
209
210// The unpack failure test needs to use a different install .crx, which is
211// specified via a command-line flag, so it needs its own test subclass.
212class WebstoreStartupInstallUnpackFailureTest
213    : public WebstoreStartupInstallerTest {
214 public:
215  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
216    WebstoreStartupInstallerTest::SetUpCommandLine(command_line);
217
218    GURL crx_url = GenerateTestServerUrl(
219        kWebstoreDomain, "malformed_extension.crx");
220    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
221        switches::kAppsGalleryUpdateURL, crx_url.spec());
222  }
223
224  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
225    WebstoreStartupInstallerTest::SetUpInProcessBrowserTestFixture();
226    ExtensionInstallUI::set_disable_failure_ui_for_tests();
227  }
228};
229
230IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallUnpackFailureTest,
231    WebstoreStartupInstallUnpackFailureTest) {
232  ExtensionInstallPrompt::g_auto_confirm_for_tests =
233      ExtensionInstallPrompt::ACCEPT;
234
235  ui_test_utils::NavigateToURL(browser(),
236      GenerateTestServerUrl(kAppDomain, "install_unpack_failure.html"));
237
238  RunTest("runTest");
239}
240
241class CommandLineWebstoreInstall
242    : public WebstoreStartupInstallerTest,
243      public content::NotificationObserver,
244      public extensions::ExtensionRegistryObserver {
245 public:
246  CommandLineWebstoreInstall() : saw_install_(false), browser_open_count_(0) {}
247  virtual ~CommandLineWebstoreInstall() {}
248
249  virtual void SetUpOnMainThread() OVERRIDE {
250    WebstoreStartupInstallerTest::SetUpOnMainThread();
251    extensions::ExtensionRegistry::Get(browser()->profile())->AddObserver(this);
252    registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
253                   content::NotificationService::AllSources());
254  }
255
256  virtual void TearDownOnMainThread() OVERRIDE {
257    extensions::ExtensionRegistry::Get(browser()->profile())
258        ->RemoveObserver(this);
259    WebstoreStartupInstallerTest::TearDownOnMainThread();
260  }
261
262  bool saw_install() { return saw_install_; }
263
264  int browser_open_count() { return browser_open_count_; }
265
266  // NotificationObserver interface.
267  virtual void Observe(int type,
268                       const content::NotificationSource& source,
269                       const content::NotificationDetails& details) OVERRIDE {
270    DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_OPENED);
271    ++browser_open_count_;
272  }
273
274  virtual void OnExtensionWillBeInstalled(
275      content::BrowserContext* browser_context,
276      const extensions::Extension* extension,
277      bool is_update,
278      bool from_ephemeral,
279      const std::string& old_name) OVERRIDE {
280    EXPECT_EQ(extension->id(), kTestExtensionId);
281    saw_install_ = true;
282  }
283
284  content::NotificationRegistrar registrar_;
285
286  // Have we seen an installation notification for kTestExtensionId ?
287  bool saw_install_;
288
289  // How many NOTIFICATION_BROWSER_OPENED notifications have we seen?
290  int browser_open_count_;
291};
292
293IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, Accept) {
294  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
295  command_line->AppendSwitchASCII(
296      switches::kInstallFromWebstore, kTestExtensionId);
297  ExtensionInstallPrompt::g_auto_confirm_for_tests =
298      ExtensionInstallPrompt::ACCEPT;
299  extensions::StartupHelper helper;
300  EXPECT_TRUE(helper.InstallFromWebstore(*command_line, browser()->profile()));
301  EXPECT_TRUE(saw_install());
302  EXPECT_EQ(0, browser_open_count());
303}
304
305IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, Cancel) {
306  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
307  command_line->AppendSwitchASCII(
308      switches::kInstallFromWebstore, kTestExtensionId);
309  ExtensionInstallPrompt::g_auto_confirm_for_tests =
310      ExtensionInstallPrompt::CANCEL;
311  extensions::StartupHelper helper;
312  EXPECT_FALSE(helper.InstallFromWebstore(*command_line, browser()->profile()));
313  EXPECT_FALSE(saw_install());
314  EXPECT_EQ(0, browser_open_count());
315}
316
317IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, LimitedAccept) {
318  extensions::StartupHelper helper;
319
320  // Small test of "WebStoreIdFromLimitedInstallCmdLine" which made more
321  // sense together with the rest of the test for "LimitedInstallFromWebstore".
322  base::CommandLine command_line_test1(base::CommandLine::NO_PROGRAM);
323  command_line_test1.AppendSwitchASCII(switches::kLimitedInstallFromWebstore,
324      "1");
325  EXPECT_EQ("nckgahadagoaajjgafhacjanaoiihapd",
326      helper.WebStoreIdFromLimitedInstallCmdLine(command_line_test1));
327
328  base::CommandLine command_line_test2(base::CommandLine::NO_PROGRAM);
329  command_line_test1.AppendSwitchASCII(switches::kLimitedInstallFromWebstore,
330      "2");
331  EXPECT_EQ(kTestExtensionId,
332      helper.WebStoreIdFromLimitedInstallCmdLine(command_line_test1));
333
334  // Now, on to the real test for LimitedInstallFromWebstore.
335  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
336  command_line->AppendSwitchASCII(
337      switches::kLimitedInstallFromWebstore, "2");
338  helper.LimitedInstallFromWebstore(*command_line, browser()->profile(),
339      base::MessageLoop::QuitWhenIdleClosure());
340  base::MessageLoop::current()->Run();
341
342  EXPECT_TRUE(saw_install());
343  EXPECT_EQ(0, browser_open_count());
344}
345