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

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

Powered by Google App Engine
This is Rietveld 408576698