Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: chrome/browser/extensions/extension_service_test_with_install.cc

Issue 1411773002: Move Sync-specific tests from ExtensionServiceTest into new file (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@su_ext_reenable
Patch Set: move ExternalInstallPrompt override Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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_service_test_with_install.h"
6
7 #include "base/files/file_util.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/crx_installer.h"
10 #include "chrome/browser/extensions/extension_creator.h"
11 #include "chrome/browser/extensions/extension_error_reporter.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "content/public/browser/notification_service.h"
14 #include "extensions/browser/extension_registry.h"
15 #include "extensions/browser/notification_types.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace extensions {
19
20 namespace {
21
22 struct ExtensionsOrder {
23 bool operator()(const scoped_refptr<const Extension>& a,
24 const scoped_refptr<const Extension>& b) {
25 return a->name() < b->name();
26 }
27 };
28
29 // Helper method to set up a WindowedNotificationObserver to wait for a
30 // specific CrxInstaller to finish if we don't know the value of the
31 // |installer| yet.
32 bool IsCrxInstallerDone(extensions::CrxInstaller** installer,
33 const content::NotificationSource& source,
34 const content::NotificationDetails& details) {
35 return content::Source<extensions::CrxInstaller>(source).ptr() == *installer;
36 }
37
38 } // namespace
39
40 ExtensionServiceTestWithInstall::ExtensionServiceTestWithInstall()
41 : installed_(nullptr),
42 was_update_(false),
43 unloaded_reason_(UnloadedExtensionInfo::REASON_UNDEFINED),
44 expected_extensions_count_(0),
45 override_external_install_prompt_(
46 FeatureSwitch::prompt_for_external_extensions(),
47 false) {
48 // TODO(treib,devlin): This should use ExtensionRegistryObserver instead.
49 registrar_.Add(this,
50 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
51 content::NotificationService::AllSources());
52 registrar_.Add(this,
53 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
54 content::NotificationService::AllSources());
55 registrar_.Add(
56 this,
57 extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED,
58 content::NotificationService::AllSources());
59 }
60
61 ExtensionServiceTestWithInstall::~ExtensionServiceTestWithInstall() {}
62
63 // static
64 std::vector<base::string16> ExtensionServiceTestWithInstall::GetErrors() {
65 const std::vector<base::string16>* errors =
66 ExtensionErrorReporter::GetInstance()->GetErrors();
67 std::vector<base::string16> ret_val;
68
69 for (const base::string16& error : *errors) {
70 std::string utf8_error = base::UTF16ToUTF8(error);
71 if (utf8_error.find(".svn") == std::string::npos) {
72 ret_val.push_back(error);
73 }
74 }
75
76 // The tests rely on the errors being in a certain order, which can vary
77 // depending on how filesystem iteration works.
78 std::stable_sort(ret_val.begin(), ret_val.end());
79
80 return ret_val;
81 }
82
83 void ExtensionServiceTestWithInstall::PackCRX(const base::FilePath& dir_path,
84 const base::FilePath& pem_path,
85 const base::FilePath& crx_path) {
86 // Use the existing pem key, if provided.
87 base::FilePath pem_output_path;
88 if (pem_path.value().empty()) {
89 pem_output_path = crx_path.DirName().AppendASCII("temp.pem");
90 } else {
91 ASSERT_TRUE(base::PathExists(pem_path));
92 }
93
94 ASSERT_TRUE(base::DeleteFile(crx_path, false));
95
96 scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
97 ASSERT_TRUE(creator->Run(dir_path,
98 crx_path,
99 pem_path,
100 pem_output_path,
101 ExtensionCreator::kOverwriteCRX));
102
103 ASSERT_TRUE(base::PathExists(crx_path));
104 }
105
106 const Extension* ExtensionServiceTestWithInstall::PackAndInstallCRX(
107 const base::FilePath& dir_path,
108 const base::FilePath& pem_path,
109 InstallState install_state,
110 int creation_flags) {
111 base::FilePath crx_path;
112 base::ScopedTempDir temp_dir;
113 EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
114 crx_path = temp_dir.path().AppendASCII("temp.crx");
115
116 PackCRX(dir_path, pem_path, crx_path);
117 return InstallCRX(crx_path, install_state, creation_flags);
118 }
119
120 const Extension* ExtensionServiceTestWithInstall::PackAndInstallCRX(
121 const base::FilePath& dir_path,
122 const base::FilePath& pem_path,
123 InstallState install_state) {
124 return PackAndInstallCRX(dir_path, pem_path, install_state,
125 Extension::NO_FLAGS);
126 }
127
128 const Extension* ExtensionServiceTestWithInstall::PackAndInstallCRX(
129 const base::FilePath& dir_path,
130 InstallState install_state) {
131 return PackAndInstallCRX(dir_path, base::FilePath(), install_state,
132 Extension::NO_FLAGS);
133 }
134
135 // Attempts to install an extension. Use INSTALL_FAILED if the installation
136 // is expected to fail.
137 // If |install_state| is INSTALL_UPDATED, and |expected_old_name| is
138 // non-empty, expects that the existing extension's title was
139 // |expected_old_name|.
140 const Extension* ExtensionServiceTestWithInstall::InstallCRX(
141 const base::FilePath& path,
142 InstallState install_state,
143 int creation_flags,
144 const std::string& expected_old_name) {
145 InstallCRXInternal(path, creation_flags);
146 return VerifyCrxInstall(path, install_state, expected_old_name);
147 }
148
149 // Attempts to install an extension. Use INSTALL_FAILED if the installation
150 // is expected to fail.
151 const Extension* ExtensionServiceTestWithInstall::InstallCRX(
152 const base::FilePath& path,
153 InstallState install_state,
154 int creation_flags) {
155 return InstallCRX(path, install_state, creation_flags, std::string());
156 }
157
158 // Attempts to install an extension. Use INSTALL_FAILED if the installation
159 // is expected to fail.
160 const Extension* ExtensionServiceTestWithInstall::InstallCRX(
161 const base::FilePath& path,
162 InstallState install_state) {
163 return InstallCRX(path, install_state, Extension::NO_FLAGS);
164 }
165
166 const Extension* ExtensionServiceTestWithInstall::InstallCRXFromWebStore(
167 const base::FilePath& path,
168 InstallState install_state) {
169 InstallCRXInternal(path, Extension::FROM_WEBSTORE);
170 return VerifyCrxInstall(path, install_state);
171 }
172
173 const Extension* ExtensionServiceTestWithInstall::InstallCRXWithLocation(
174 const base::FilePath& crx_path,
175 Manifest::Location install_location,
176 InstallState install_state) {
177 EXPECT_TRUE(base::PathExists(crx_path))
178 << "Path does not exist: "<< crx_path.value().c_str();
179 // no client (silent install)
180 scoped_refptr<CrxInstaller> installer(
181 CrxInstaller::CreateSilent(service()));
182 installer->set_install_source(install_location);
183
184 content::WindowedNotificationObserver observer(
185 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
186 content::NotificationService::AllSources());
187 installer->InstallCrx(crx_path);
188 observer.Wait();
189
190 return VerifyCrxInstall(crx_path, install_state);
191 }
192
193 const Extension* ExtensionServiceTestWithInstall::VerifyCrxInstall(
194 const base::FilePath& path,
195 InstallState install_state) {
196 return VerifyCrxInstall(path, install_state, std::string());
197 }
198
199 const Extension* ExtensionServiceTestWithInstall::VerifyCrxInstall(
200 const base::FilePath& path,
201 InstallState install_state,
202 const std::string& expected_old_name) {
203 std::vector<base::string16> errors = GetErrors();
204 const Extension* extension = NULL;
205 if (install_state != INSTALL_FAILED) {
206 if (install_state == INSTALL_NEW)
207 ++expected_extensions_count_;
208
209 EXPECT_TRUE(installed_) << path.value();
210 // If and only if INSTALL_UPDATED, it should have the is_update flag.
211 EXPECT_EQ(install_state == INSTALL_UPDATED, was_update_)
212 << path.value();
213 // If INSTALL_UPDATED, old_name_ should match the given string.
214 if (install_state == INSTALL_UPDATED && !expected_old_name.empty())
215 EXPECT_EQ(expected_old_name, old_name_);
216 EXPECT_EQ(0u, errors.size()) << path.value();
217
218 if (install_state == INSTALL_WITHOUT_LOAD) {
219 EXPECT_EQ(0u, loaded_.size()) << path.value();
220 } else {
221 EXPECT_EQ(1u, loaded_.size()) << path.value();
222 size_t actual_extension_count =
223 registry()->enabled_extensions().size() +
224 registry()->disabled_extensions().size();
225 EXPECT_EQ(expected_extensions_count_, actual_extension_count) <<
226 path.value();
227 extension = loaded_[0].get();
228 EXPECT_TRUE(service()->GetExtensionById(extension->id(), false))
229 << path.value();
230 }
231
232 for (std::vector<base::string16>::iterator err = errors.begin();
233 err != errors.end(); ++err) {
234 LOG(ERROR) << *err;
235 }
236 } else {
237 EXPECT_FALSE(installed_) << path.value();
238 EXPECT_EQ(0u, loaded_.size()) << path.value();
239 EXPECT_EQ(1u, errors.size()) << path.value();
240 }
241
242 installed_ = NULL;
243 was_update_ = false;
244 old_name_ = "";
245 loaded_.clear();
246 ExtensionErrorReporter::GetInstance()->ClearErrors();
247 return extension;
248 }
249
250 void ExtensionServiceTestWithInstall::PackCRXAndUpdateExtension(
251 const std::string& id,
252 const base::FilePath& dir_path,
253 const base::FilePath& pem_path,
254 UpdateState expected_state) {
255 base::ScopedTempDir temp_dir;
256 EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
257 base::FilePath crx_path = temp_dir.path().AppendASCII("temp.crx");
258
259 PackCRX(dir_path, pem_path, crx_path);
260 UpdateExtension(id, crx_path, expected_state);
261 }
262
263 void ExtensionServiceTestWithInstall::UpdateExtension(
264 const std::string& id,
265 const base::FilePath& in_path,
266 UpdateState expected_state) {
267 ASSERT_TRUE(base::PathExists(in_path));
268
269 // We need to copy this to a temporary location because Update() will delete
270 // it.
271 base::FilePath path = temp_dir().path();
272 path = path.Append(in_path.BaseName());
273 ASSERT_TRUE(base::CopyFile(in_path, path));
274
275 int previous_enabled_extension_count =
276 registry()->enabled_extensions().size();
277 int previous_installed_extension_count =
278 previous_enabled_extension_count +
279 registry()->disabled_extensions().size();
280
281 extensions::CrxInstaller* installer = NULL;
282 content::WindowedNotificationObserver observer(
283 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
284 base::Bind(&IsCrxInstallerDone, &installer));
285 service()->UpdateExtension(extensions::CRXFileInfo(id, path), true,
286 &installer);
287
288 if (installer)
289 observer.Wait();
290 else
291 base::RunLoop().RunUntilIdle();
292
293 std::vector<base::string16> errors = GetErrors();
294 int error_count = errors.size();
295 int enabled_extension_count = registry()->enabled_extensions().size();
296 int installed_extension_count =
297 enabled_extension_count + registry()->disabled_extensions().size();
298
299 int expected_error_count = (expected_state == FAILED) ? 1 : 0;
300 EXPECT_EQ(expected_error_count, error_count) << path.value();
301
302 if (expected_state <= FAILED) {
303 EXPECT_EQ(previous_enabled_extension_count,
304 enabled_extension_count);
305 EXPECT_EQ(previous_installed_extension_count,
306 installed_extension_count);
307 } else {
308 int expected_installed_extension_count =
309 (expected_state >= INSTALLED) ? 1 : 0;
310 int expected_enabled_extension_count =
311 (expected_state >= ENABLED) ? 1 : 0;
312 EXPECT_EQ(expected_installed_extension_count,
313 installed_extension_count);
314 EXPECT_EQ(expected_enabled_extension_count,
315 enabled_extension_count);
316 }
317
318 // Update() should the temporary input file.
319 EXPECT_FALSE(base::PathExists(path));
320 }
321
322 void ExtensionServiceTestWithInstall::UninstallExtension(const std::string& id,
323 bool use_helper) {
324 UninstallExtension(id, use_helper, Extension::ENABLED);
325 }
326
327 void ExtensionServiceTestWithInstall::UninstallExtension(
328 const std::string& id,
329 bool use_helper,
330 Extension::State expected_state) {
331 // Verify that the extension is installed.
332 base::FilePath extension_path = extensions_install_dir().AppendASCII(id);
333 EXPECT_TRUE(base::PathExists(extension_path));
334 size_t pref_key_count = GetPrefKeyCount();
335 EXPECT_GT(pref_key_count, 0u);
336 ValidateIntegerPref(id, "state", expected_state);
337
338 // Uninstall it.
339 if (use_helper) {
340 EXPECT_TRUE(ExtensionService::UninstallExtensionHelper(
341 service(), id, extensions::UNINSTALL_REASON_FOR_TESTING));
342 } else {
343 EXPECT_TRUE(service()->UninstallExtension(
344 id,
345 extensions::UNINSTALL_REASON_FOR_TESTING,
346 base::Bind(&base::DoNothing),
347 NULL));
348 }
349 --expected_extensions_count_;
350
351 // We should get an unload notification.
352 EXPECT_FALSE(unloaded_id_.empty());
353 EXPECT_EQ(id, unloaded_id_);
354
355 // Verify uninstalled state.
356 size_t new_pref_key_count = GetPrefKeyCount();
357 if (new_pref_key_count == pref_key_count) {
358 ValidateIntegerPref(id, "state",
359 Extension::EXTERNAL_EXTENSION_UNINSTALLED);
360 } else {
361 EXPECT_EQ(new_pref_key_count, pref_key_count - 1);
362 }
363
364 // The extension should not be in the service anymore.
365 EXPECT_FALSE(service()->GetInstalledExtension(id));
366 base::RunLoop().RunUntilIdle();
367
368 // The directory should be gone.
369 EXPECT_FALSE(base::PathExists(extension_path));
370 }
371
372 void ExtensionServiceTestWithInstall::TerminateExtension(
373 const std::string& id) {
374 const Extension* extension = service()->GetInstalledExtension(id);
375 if (!extension) {
376 ADD_FAILURE();
377 return;
378 }
379 service()->TrackTerminatedExtensionForTest(extension);
380 }
381
382 void ExtensionServiceTestWithInstall::Observe(
383 int type,
384 const content::NotificationSource& source,
385 const content::NotificationDetails& details) {
386 switch (type) {
387 case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
388 const Extension* extension =
389 content::Details<const Extension>(details).ptr();
390 loaded_.push_back(make_scoped_refptr(extension));
391 // The tests rely on the errors being in a certain order, which can vary
392 // depending on how filesystem iteration works.
393 std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder());
394 break;
395 }
396
397 case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
398 UnloadedExtensionInfo* unloaded_info =
399 content::Details<UnloadedExtensionInfo>(details).ptr();
400 const Extension* e = unloaded_info->extension;
401 unloaded_id_ = e->id();
402 unloaded_reason_ = unloaded_info->reason;
403 extensions::ExtensionList::iterator i =
404 std::find(loaded_.begin(), loaded_.end(), e);
405 // TODO(erikkay) fix so this can be an assert. Right now the tests
406 // are manually calling clear() on loaded_, so this isn't doable.
407 if (i == loaded_.end())
408 return;
409 loaded_.erase(i);
410 break;
411 }
412 case extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED: {
413 const extensions::InstalledExtensionInfo* installed_info =
414 content::Details<const extensions::InstalledExtensionInfo>(details)
415 .ptr();
416 installed_ = installed_info->extension;
417 was_update_ = installed_info->is_update;
418 old_name_ = installed_info->old_name;
419 break;
420 }
421
422 default:
423 DCHECK(false);
424 }
425 }
426
427 // Create a CrxInstaller and install the CRX file.
428 // Instead of calling this method yourself, use InstallCRX(), which does extra
429 // error checking.
430 void ExtensionServiceTestWithInstall::InstallCRXInternal(
431 const base::FilePath& crx_path,
432 int creation_flags) {
433 ASSERT_TRUE(base::PathExists(crx_path))
434 << "Path does not exist: "<< crx_path.value().c_str();
435 scoped_refptr<CrxInstaller> installer(
436 CrxInstaller::CreateSilent(service()));
437 installer->set_creation_flags(creation_flags);
438 if (!(creation_flags & Extension::WAS_INSTALLED_BY_DEFAULT))
439 installer->set_allow_silent_install(true);
440
441 content::WindowedNotificationObserver observer(
442 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
443 content::Source<extensions::CrxInstaller>(installer.get()));
444
445 installer->InstallCrx(crx_path);
446
447 observer.Wait();
448 }
449
450 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698