extension_management_browsertest.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2009 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/ref_counted.h"
6#include "chrome/browser/browser.h"
7#include "chrome/browser/renderer_host/render_view_host.h"
8#include "chrome/browser/extensions/autoupdate_interceptor.h"
9#include "chrome/browser/extensions/extension_browsertest.h"
10#include "chrome/browser/extensions/extension_host.h"
11#include "chrome/browser/extensions/extensions_service.h"
12#include "chrome/browser/extensions/extension_test_message_listener.h"
13#include "chrome/browser/extensions/extension_updater.h"
14#include "chrome/browser/profile.h"
15#include "chrome/common/url_constants.h"
16#include "chrome/test/ui_test_utils.h"
17
18class ExtensionManagementTest : public ExtensionBrowserTest {
19 protected:
20  // Helper method that returns whether the extension is at the given version.
21  // This calls version(), which must be defined in the extension's bg page,
22  // as well as asking the extension itself.
23  //
24  // Note that 'version' here means something different than the version field
25  // in the extension's manifest. We use the version as reported by the
26  // background page to test how overinstalling crx files with the same
27  // manifest version works.
28  bool IsExtensionAtVersion(Extension* extension,
29                            const std::string& expected_version) {
30    // Test that the extension's version from the manifest and reported by the
31    // background page is correct.  This is to ensure that the processes are in
32    // sync with the Extension.
33    ExtensionProcessManager* manager = browser()->profile()->
34        GetExtensionProcessManager();
35    ExtensionHost* ext_host = manager->GetBackgroundHostForExtension(extension);
36    EXPECT_TRUE(ext_host);
37    if (!ext_host)
38      return false;
39
40    std::string version_from_bg;
41    bool exec = ui_test_utils::ExecuteJavaScriptAndExtractString(
42        ext_host->render_view_host(), L"", L"version()", &version_from_bg);
43    EXPECT_TRUE(exec);
44    if (!exec)
45      return false;
46
47    if (version_from_bg != expected_version ||
48        extension->VersionString() != expected_version)
49      return false;
50    return true;
51  }
52
53  // Helper method that installs a low permission extension then updates
54  // to the second version requiring increased permissions. Returns whether
55  // the operation was completed successfully.
56  bool InstallAndUpdateIncreasingPermissionsExtension() {
57    ExtensionsService* service = browser()->profile()->GetExtensionsService();
58    size_t size_before = service->extensions()->size();
59
60    // Install the initial version, which should happen just fine.
61    if (!InstallExtension(
62        test_data_dir_.AppendASCII("permissions-low-v1.crx"), 1))
63      return false;
64
65    // Upgrade to a version that wants more permissions. We should disable the
66    // extension and prompt the user to reenable.
67    if (service->extensions()->size() != size_before + 1)
68      return false;
69    if (!UpdateExtension(
70        service->extensions()->at(size_before)->id(),
71        test_data_dir_.AppendASCII("permissions-high-v2.crx"), -1))
72      return false;
73    EXPECT_EQ(size_before, service->extensions()->size());
74    if (service->disabled_extensions()->size() != 1u)
75      return false;
76    return true;
77  }
78};
79
80// Tests that installing the same version overwrites.
81IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) {
82  ExtensionsService* service = browser()->profile()->GetExtensionsService();
83  const size_t size_before = service->extensions()->size();
84  ASSERT_TRUE(InstallExtension(
85      test_data_dir_.AppendASCII("install/install.crx"), 1));
86  FilePath old_path = service->extensions()->back()->path();
87
88  // Install an extension with the same version. The previous install should be
89  // overwritten.
90  ASSERT_TRUE(InstallExtension(
91      test_data_dir_.AppendASCII("install/install_same_version.crx"), 0));
92  FilePath new_path = service->extensions()->back()->path();
93
94  EXPECT_FALSE(IsExtensionAtVersion(service->extensions()->at(size_before),
95                                    "1.0"));
96  EXPECT_NE(old_path.value(), new_path.value());
97}
98
99IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) {
100  ExtensionsService* service = browser()->profile()->GetExtensionsService();
101  const size_t size_before = service->extensions()->size();
102  ASSERT_TRUE(InstallExtension(
103      test_data_dir_.AppendASCII("install/install.crx"), 1));
104  ASSERT_TRUE(InstallExtension(
105      test_data_dir_.AppendASCII("install/install_older_version.crx"), 0));
106  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(size_before),
107                                   "1.0"));
108}
109
110IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) {
111  ExtensionsService* service = browser()->profile()->GetExtensionsService();
112  const size_t size_before = service->extensions()->size();
113  ASSERT_TRUE(InstallExtension(
114      test_data_dir_.AppendASCII("install/install.crx"), 1));
115
116  // Cancel this install.
117  StartInstallButCancel(test_data_dir_.AppendASCII("install/install_v2.crx"));
118  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(size_before),
119                                   "1.0"));
120}
121
122#if defined(OS_MACOSX)
123// See http://crbug.com/46097
124#define MAYBE_Incognito FLAKY_Incognito
125#else
126#define MAYBE_Incognito Incognito
127#endif
128// Tests that installing and uninstalling extensions don't crash with an
129// incognito window open.
130IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, MAYBE_Incognito) {
131  // Open an incognito window to the extensions management page.  We just
132  // want to make sure that we don't crash while playing with extensions when
133  // this guy is around.
134  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
135                                     GURL(chrome::kChromeUIExtensionsURL));
136
137  ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx"), 1));
138  UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf");
139}
140
141// Tests the process of updating an extension to one that requires higher
142// permissions.
143IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) {
144  ExtensionsService* service = browser()->profile()->GetExtensionsService();
145  ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());
146  const size_t size_before = service->extensions()->size();
147
148  // Now try reenabling it.
149  service->EnableExtension(service->disabled_extensions()->at(0)->id());
150  EXPECT_EQ(size_before + 1, service->extensions()->size());
151  EXPECT_EQ(0u, service->disabled_extensions()->size());
152}
153
154// Tests that we can uninstall a disabled extension.
155IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) {
156  ExtensionsService* service = browser()->profile()->GetExtensionsService();
157  ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());
158  const size_t size_before = service->extensions()->size();
159
160  // Now try uninstalling it.
161  UninstallExtension(service->disabled_extensions()->at(0)->id());
162  EXPECT_EQ(size_before, service->extensions()->size());
163  EXPECT_EQ(0u, service->disabled_extensions()->size());
164}
165
166// Tests that disabling and re-enabling an extension works.
167IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) {
168  ExtensionProcessManager* manager = browser()->profile()->
169      GetExtensionProcessManager();
170  ExtensionsService* service = browser()->profile()->GetExtensionsService();
171  const size_t size_before = service->extensions()->size();
172
173  // Load an extension, expect the background page to be available.
174  ASSERT_TRUE(LoadExtension(
175      test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
176                    .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
177                    .AppendASCII("1.0")));
178  ASSERT_EQ(size_before + 1, service->extensions()->size());
179  EXPECT_EQ(0u, service->disabled_extensions()->size());
180  Extension* extension = service->extensions()->at(size_before);
181  EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
182  ASSERT_TRUE(service->HasInstalledExtensions());
183
184  // After disabling, the background page should go away.
185  service->DisableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
186  EXPECT_EQ(size_before, service->extensions()->size());
187  EXPECT_EQ(1u, service->disabled_extensions()->size());
188  EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension));
189  ASSERT_TRUE(service->HasInstalledExtensions());
190
191  // And bring it back.
192  service->EnableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
193  EXPECT_EQ(size_before + 1, service->extensions()->size());
194  EXPECT_EQ(0u, service->disabled_extensions()->size());
195  EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
196  ASSERT_TRUE(service->HasInstalledExtensions());
197}
198
199// Tests extension autoupdate.
200IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
201  FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
202  // Note: This interceptor gets requests on the IO thread.
203  scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
204  URLFetcher::enable_interception_for_tests(true);
205
206  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
207                                     basedir.AppendASCII("manifest_v2.xml"));
208  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
209                                     basedir.AppendASCII("v2.crx"));
210
211  // Install version 1 of the extension.
212  ExtensionTestMessageListener listener1("v1 installed");
213  ExtensionsService* service = browser()->profile()->GetExtensionsService();
214  const size_t size_before = service->extensions()->size();
215  ASSERT_TRUE(service->disabled_extensions()->empty());
216  ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1));
217  listener1.WaitUntilSatisfied();
218  const ExtensionList* extensions = service->extensions();
219  ASSERT_EQ(size_before + 1, extensions->size());
220  ASSERT_TRUE(service->HasInstalledExtensions());
221  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf",
222            extensions->at(size_before)->id());
223  ASSERT_EQ("1.0", extensions->at(size_before)->VersionString());
224
225  // We don't want autoupdate blacklist checks.
226  service->updater()->set_blacklist_checks_enabled(false);
227
228  // Run autoupdate and make sure version 2 of the extension was installed.
229  ExtensionTestMessageListener listener2("v2 installed");
230  service->updater()->CheckNow();
231  ASSERT_TRUE(WaitForExtensionInstall());
232  listener2.WaitUntilSatisfied();
233  extensions = service->extensions();
234  ASSERT_EQ(size_before + 1, extensions->size());
235  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf",
236            extensions->at(size_before)->id());
237  ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
238
239  // Now try doing an update to version 3, which has been incorrectly
240  // signed. This should fail.
241  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
242                                     basedir.AppendASCII("manifest_v3.xml"));
243  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v3.crx",
244                                     basedir.AppendASCII("v3.crx"));
245
246  service->updater()->CheckNow();
247  ASSERT_TRUE(WaitForExtensionInstallError());
248
249  // Make sure the extension state is the same as before.
250  extensions = service->extensions();
251  ASSERT_EQ(size_before + 1, extensions->size());
252  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf",
253            extensions->at(size_before)->id());
254  ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
255}
256
257IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) {
258  ExtensionsService* service = browser()->profile()->GetExtensionsService();
259  const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf";
260  // We don't want autoupdate blacklist checks.
261  service->updater()->set_blacklist_checks_enabled(false);
262
263  FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
264
265  // Note: This interceptor gets requests on the IO thread.
266  scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
267  URLFetcher::enable_interception_for_tests(true);
268
269  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
270                                     basedir.AppendASCII("manifest_v2.xml"));
271  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
272                                     basedir.AppendASCII("v2.crx"));
273
274  const size_t size_before = service->extensions()->size();
275  ASSERT_TRUE(service->disabled_extensions()->empty());
276
277  // The code that reads external_extensions.json uses this method to inform
278  // the ExtensionsService of an extension to download.  Using the real code
279  // is race-prone, because instantating the ExtensionService starts a read
280  // of external_extensions.json before this test function starts.
281  service->AddPendingExtensionFromExternalUpdateUrl(
282      kExtensionId, GURL("http://localhost/autoupdate/manifest"));
283
284  // Run autoupdate and make sure version 2 of the extension was installed.
285  service->updater()->CheckNow();
286  ASSERT_TRUE(WaitForExtensionInstall());
287  const ExtensionList* extensions = service->extensions();
288  ASSERT_EQ(size_before + 1, extensions->size());
289  ASSERT_EQ(kExtensionId, extensions->at(size_before)->id());
290  ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
291
292  // Uninstalling the extension should set a pref that keeps the extension from
293  // being installed again the next time external_extensions.json is read.
294
295  UninstallExtension(kExtensionId);
296
297  std::set<std::string> killed_ids;
298  service->extension_prefs()->GetKilledExtensionIds(&killed_ids);
299  EXPECT_TRUE(killed_ids.end() != killed_ids.find(kExtensionId))
300      << "Uninstalling should set kill bit on externaly installed extension.";
301
302  // Installing from non-external source.
303  ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v2.crx"), 1));
304
305  killed_ids.clear();
306  service->extension_prefs()->GetKilledExtensionIds(&killed_ids);
307  EXPECT_TRUE(killed_ids.end() == killed_ids.find(kExtensionId))
308      << "Reinstalling should clear the kill bit.";
309
310  // Uninstalling from a non-external source should not set the kill bit.
311  UninstallExtension(kExtensionId);
312
313  killed_ids.clear();
314  service->extension_prefs()->GetKilledExtensionIds(&killed_ids);
315  EXPECT_TRUE(killed_ids.end() == killed_ids.find(kExtensionId))
316      << "Uninstalling non-external extension should not set kill bit.";
317}
318