1// Copyright 2013 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 "chrome/browser/extensions/extension_install_prompt.h"
6#include "chrome/browser/extensions/extension_service.h"
7#include "chrome/browser/extensions/tab_helper.h"
8#include "chrome/browser/extensions/webstore_inline_installer.h"
9#include "chrome/browser/extensions/webstore_inline_installer_factory.h"
10#include "chrome/browser/extensions/webstore_installer_test.h"
11#include "chrome/browser/extensions/webstore_standalone_installer.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/browser/ui/tabs/tab_strip_model.h"
15#include "chrome/test/base/ui_test_utils.h"
16#include "content/public/browser/web_contents.h"
17#include "extensions/browser/extension_system.h"
18#include "url/gurl.h"
19
20using content::WebContents;
21
22namespace extensions {
23
24namespace {
25
26const char kWebstoreDomain[] = "cws.com";
27const char kAppDomain[] = "app.com";
28const char kNonAppDomain[] = "nonapp.com";
29const char kTestExtensionId[] = "ecglahbcnmdpdciemllbhojghbkagdje";
30const char kTestDataPath[] = "extensions/api_test/webstore_inline_install";
31const char kCrxFilename[] = "extension.crx";
32
33}  // namespace
34
35class WebstoreInlineInstallerTest : public WebstoreInstallerTest {
36 public:
37  WebstoreInlineInstallerTest()
38      : WebstoreInstallerTest(
39            kWebstoreDomain,
40            kTestDataPath,
41            kCrxFilename,
42            kAppDomain,
43            kNonAppDomain) {}
44};
45
46class ProgrammableInstallPrompt : public ExtensionInstallPrompt {
47 public:
48  explicit ProgrammableInstallPrompt(WebContents* contents)
49      : ExtensionInstallPrompt(contents)
50  {}
51
52  virtual ~ProgrammableInstallPrompt() {}
53
54  virtual void ConfirmStandaloneInstall(
55      Delegate* delegate,
56      const Extension* extension,
57      SkBitmap* icon,
58      scoped_refptr<ExtensionInstallPrompt::Prompt> prompt) OVERRIDE {
59    delegate_ = delegate;
60  }
61
62  static bool Ready() {
63    return delegate_ != NULL;
64  }
65
66  static void Accept() {
67    delegate_->InstallUIProceed();
68  }
69
70  static void Reject() {
71    delegate_->InstallUIAbort(true);
72  }
73
74 private:
75  static Delegate* delegate_;
76};
77
78ExtensionInstallPrompt::Delegate* ProgrammableInstallPrompt::delegate_;
79
80// Fake inline installer which creates a programmable prompt in place of
81// the normal dialog UI.
82class WebstoreInlineInstallerForTest : public WebstoreInlineInstaller {
83 public:
84  WebstoreInlineInstallerForTest(WebContents* contents,
85                                 const std::string& extension_id,
86                                 const GURL& requestor_url,
87                                 const Callback& callback)
88      : WebstoreInlineInstaller(
89            contents,
90            kTestExtensionId,
91            requestor_url,
92            base::Bind(DummyCallback)),
93        programmable_prompt_(NULL) {
94  }
95
96  virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() OVERRIDE {
97    programmable_prompt_ = new ProgrammableInstallPrompt(web_contents());
98    return make_scoped_ptr(programmable_prompt_).
99        PassAs<ExtensionInstallPrompt>();
100  }
101
102 private:
103  virtual ~WebstoreInlineInstallerForTest() {}
104
105  friend class base::RefCountedThreadSafe<WebstoreStandaloneInstaller>;
106
107  static void DummyCallback(bool success,
108                            const std::string& error,
109                            webstore_install::Result result) {
110  }
111
112  ProgrammableInstallPrompt* programmable_prompt_;
113};
114
115class WebstoreInlineInstallerForTestFactory :
116    public WebstoreInlineInstallerFactory {
117  virtual ~WebstoreInlineInstallerForTestFactory() {}
118  virtual WebstoreInlineInstaller* CreateInstaller(
119      WebContents* contents,
120      const std::string& webstore_item_id,
121      const GURL& requestor_url,
122      const WebstoreStandaloneInstaller::Callback& callback) OVERRIDE {
123    return new WebstoreInlineInstallerForTest(
124        contents, webstore_item_id, requestor_url, callback);
125  }
126};
127
128IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallerTest,
129    CloseTabBeforeInstallConfirmation) {
130  GURL install_url = GenerateTestServerUrl(kAppDomain, "install.html");
131  ui_test_utils::NavigateToURL(browser(), install_url);
132  WebContents* web_contents =
133      browser()->tab_strip_model()->GetActiveWebContents();
134  TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
135  tab_helper->SetWebstoreInlineInstallerFactoryForTests(
136      new WebstoreInlineInstallerForTestFactory());
137  RunTestAsync("runTest");
138  while (!ProgrammableInstallPrompt::Ready())
139    base::RunLoop().RunUntilIdle();
140  web_contents->Close();
141  ProgrammableInstallPrompt::Accept();
142}
143
144// Ensure that inline-installing a disabled extension simply re-enables it.
145IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallerTest,
146                       ReinstallDisabledExtension) {
147  // Install an extension via inline install, and confirm it is successful.
148  ExtensionInstallPrompt::g_auto_confirm_for_tests =
149      ExtensionInstallPrompt::ACCEPT;
150  ui_test_utils::NavigateToURL(
151      browser(), GenerateTestServerUrl(kAppDomain, "install.html"));
152  RunTest("runTest");
153  ExtensionService* extension_service =
154      ExtensionSystem::Get(browser()->profile())->extension_service();
155  ASSERT_TRUE(extension_service->GetExtensionById(kTestExtensionId, false));
156
157  // Disable the extension.
158  extension_service->DisableExtension(kTestExtensionId,
159                                      Extension::DISABLE_USER_ACTION);
160  ASSERT_FALSE(extension_service->IsExtensionEnabled(kTestExtensionId));
161
162  // Revisit the inline install site and reinstall the extension. It should
163  // simply be re-enabled, rather than try to install again.
164  ui_test_utils::NavigateToURL(
165      browser(), GenerateTestServerUrl(kAppDomain, "install.html"));
166  RunTest("runTest");
167  ASSERT_TRUE(extension_service->IsExtensionEnabled(kTestExtensionId));
168}
169
170class WebstoreInlineInstallerListenerTest : public WebstoreInlineInstallerTest {
171 public:
172  WebstoreInlineInstallerListenerTest() {}
173  virtual ~WebstoreInlineInstallerListenerTest() {}
174
175 protected:
176  void RunTest(const std::string& file_name) {
177    ExtensionInstallPrompt::g_auto_confirm_for_tests =
178        ExtensionInstallPrompt::ACCEPT;
179    ui_test_utils::NavigateToURL(browser(),
180                                 GenerateTestServerUrl(kAppDomain, file_name));
181    WebstoreInstallerTest::RunTest("runTest");
182  }
183};
184
185IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallerListenerTest,
186                       InstallStageListenerTest) {
187  RunTest("install_stage_listener.html");
188}
189
190IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallerListenerTest,
191                       DownloadProgressListenerTest) {
192  RunTest("download_progress_listener.html");
193}
194
195IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallerListenerTest, BothListenersTest) {
196  RunTest("both_listeners.html");
197}
198
199}  // namespace extensions
200