extension_service_unittest.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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_unittest.h" 6 7#include <algorithm> 8#include <set> 9#include <vector> 10 11#include "base/basictypes.h" 12#include "base/command_line.h" 13#include "base/file_util.h" 14#include "base/json/json_reader.h" 15#include "base/message_loop.h" 16#include "base/path_service.h" 17#include "base/scoped_ptr.h" 18#include "base/stl_util-inl.h" 19#include "base/string16.h" 20#include "base/string_number_conversions.h" 21#include "base/string_util.h" 22#include "base/task.h" 23#include "base/utf_string_conversions.h" 24#include "base/version.h" 25#include "chrome/browser/appcache/chrome_appcache_service.h" 26#include "chrome/browser/browser_thread.h" 27#include "chrome/browser/extensions/crx_installer.h" 28#include "chrome/browser/extensions/extension_creator.h" 29#include "chrome/browser/extensions/extension_error_reporter.h" 30#include "chrome/browser/extensions/extension_service.h" 31#include "chrome/browser/extensions/external_extension_provider.h" 32#include "chrome/browser/extensions/external_pref_extension_provider.h" 33#include "chrome/browser/extensions/pack_extension_job.cc" 34#include "chrome/browser/file_system/browser_file_system_helper.h" 35#include "chrome/browser/in_process_webkit/dom_storage_context.h" 36#include "chrome/browser/in_process_webkit/webkit_context.h" 37#include "chrome/browser/prefs/browser_prefs.h" 38#include "chrome/browser/prefs/pref_service_mock_builder.h" 39#include "chrome/browser/prefs/scoped_pref_update.h" 40#include "chrome/common/chrome_paths.h" 41#include "chrome/common/chrome_switches.h" 42#include "chrome/common/extensions/extension.h" 43#include "chrome/common/extensions/extension_constants.h" 44#include "chrome/common/extensions/extension_resource.h" 45#include "chrome/common/extensions/url_pattern.h" 46#include "chrome/common/json_value_serializer.h" 47#include "chrome/common/net/url_request_context_getter.h" 48#include "chrome/common/notification_registrar.h" 49#include "chrome/common/notification_service.h" 50#include "chrome/common/notification_type.h" 51#include "chrome/common/pref_names.h" 52#include "chrome/common/url_constants.h" 53#include "chrome/test/testing_profile.h" 54#include "googleurl/src/gurl.h" 55#include "net/base/cookie_monster.h" 56#include "net/base/cookie_options.h" 57#include "net/url_request/url_request_context.h" 58#include "testing/gtest/include/gtest/gtest.h" 59#include "testing/platform_test.h" 60#include "webkit/database/database_tracker.h" 61#include "webkit/database/database_util.h" 62 63namespace keys = extension_manifest_keys; 64 65namespace { 66 67// Extension ids used during testing. 68const char* const all_zero = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 69const char* const zero_n_one = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"; 70const char* const good0 = "behllobkkfkfnphdnhnkndlbkcpglgmj"; 71const char* const good1 = "hpiknbiabeeppbpihjehijgoemciehgk"; 72const char* const good2 = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; 73const char* const good_crx = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; 74const char* const page_action = "obcimlgaoabeegjmmpldobjndiealpln"; 75const char* const theme_crx = "iamefpfkojoapidjnbafmgkgncegbkad"; 76const char* const theme2_crx = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf"; 77const char* const permissions_crx = "eagpmdpfmaekmmcejjbmjoecnejeiiin"; 78 79struct ExtensionsOrder { 80 bool operator()(const Extension* a, const Extension* b) { 81 return a->name() < b->name(); 82 } 83}; 84 85static std::vector<std::string> GetErrors() { 86 const std::vector<std::string>* errors = 87 ExtensionErrorReporter::GetInstance()->GetErrors(); 88 std::vector<std::string> ret_val; 89 90 for (std::vector<std::string>::const_iterator iter = errors->begin(); 91 iter != errors->end(); ++iter) { 92 if (iter->find(".svn") == std::string::npos) { 93 ret_val.push_back(*iter); 94 } 95 } 96 97 // The tests rely on the errors being in a certain order, which can vary 98 // depending on how filesystem iteration works. 99 std::stable_sort(ret_val.begin(), ret_val.end()); 100 101 return ret_val; 102} 103 104static void AddPattern(ExtensionExtent* extent, const std::string& pattern) { 105 int schemes = URLPattern::SCHEME_ALL; 106 extent->AddPattern(URLPattern(schemes, pattern)); 107} 108 109static void AssertEqualExtents(ExtensionExtent* extent1, 110 ExtensionExtent* extent2) { 111 std::vector<URLPattern> patterns1 = extent1->patterns(); 112 std::vector<URLPattern> patterns2 = extent2->patterns(); 113 std::set<std::string> strings1; 114 EXPECT_EQ(patterns1.size(), patterns2.size()); 115 116 for (size_t i = 0; i < patterns1.size(); ++i) 117 strings1.insert(patterns1.at(i).GetAsString()); 118 119 std::set<std::string> strings2; 120 for (size_t i = 0; i < patterns2.size(); ++i) 121 strings2.insert(patterns2.at(i).GetAsString()); 122 123 EXPECT_EQ(strings1, strings2); 124} 125 126} // namespace 127 128class MockExtensionProvider : public ExternalExtensionProvider { 129 public: 130 explicit MockExtensionProvider(Extension::Location location) 131 : location_(location), visit_count_(0) {} 132 virtual ~MockExtensionProvider() {} 133 134 void UpdateOrAddExtension(const std::string& id, 135 const std::string& version, 136 const FilePath& path) { 137 extension_map_[id] = std::make_pair(version, path); 138 } 139 140 void RemoveExtension(const std::string& id) { 141 extension_map_.erase(id); 142 } 143 144 // ExternalExtensionProvider implementation: 145 virtual void VisitRegisteredExtension(Visitor* visitor) const { 146 visit_count_++; 147 for (DataMap::const_iterator i = extension_map_.begin(); 148 i != extension_map_.end(); ++i) { 149 scoped_ptr<Version> version; 150 version.reset(Version::GetVersionFromString(i->second.first)); 151 152 visitor->OnExternalExtensionFileFound( 153 i->first, version.get(), i->second.second, location_); 154 } 155 } 156 157 virtual bool HasExtension(const std::string& id) const { 158 return extension_map_.find(id) != extension_map_.end(); 159 } 160 161 virtual bool GetExtensionDetails(const std::string& id, 162 Extension::Location* location, 163 scoped_ptr<Version>* version) const { 164 DataMap::const_iterator it = extension_map_.find(id); 165 if (it == extension_map_.end()) 166 return false; 167 168 if (version) 169 version->reset(Version::GetVersionFromString(it->second.first)); 170 171 if (location) 172 *location = location_; 173 174 return true; 175 } 176 int visit_count() const { return visit_count_; } 177 void set_visit_count(int visit_count) { 178 visit_count_ = visit_count; 179 } 180 181 private: 182 typedef std::map< std::string, std::pair<std::string, FilePath> > DataMap; 183 DataMap extension_map_; 184 Extension::Location location_; 185 186 // visit_count_ tracks the number of calls to VisitRegisteredExtension(). 187 // Mutable because it must be incremented on each call to 188 // VisitRegisteredExtension(), which must be a const method to inherit 189 // from the class being mocked. 190 mutable int visit_count_; 191 192 DISALLOW_COPY_AND_ASSIGN(MockExtensionProvider); 193}; 194 195class MockProviderVisitor : public ExternalExtensionProvider::Visitor { 196 public: 197 MockProviderVisitor() : ids_found_(0) { 198 } 199 200 int Visit(const std::string& json_data) { 201 // Give the test json file to the provider for parsing. 202 provider_.reset(new ExternalPrefExtensionProvider()); 203 provider_->SetPreferencesForTesting(json_data); 204 205 // We also parse the file into a dictionary to compare what we get back 206 // from the provider. 207 JSONStringValueSerializer serializer(json_data); 208 Value* json_value = serializer.Deserialize(NULL, NULL); 209 210 if (!json_value || !json_value->IsType(Value::TYPE_DICTIONARY)) { 211 NOTREACHED() << "Unable to deserialize json data"; 212 return -1; 213 } else { 214 DictionaryValue* external_extensions = 215 static_cast<DictionaryValue*>(json_value); 216 prefs_.reset(external_extensions); 217 } 218 219 // Reset our counter. 220 ids_found_ = 0; 221 // Ask the provider to look up all extensions and return them. 222 provider_->VisitRegisteredExtension(this); 223 224 return ids_found_; 225 } 226 227 virtual void OnExternalExtensionFileFound(const std::string& id, 228 const Version* version, 229 const FilePath& path, 230 Extension::Location unused) { 231 ++ids_found_; 232 DictionaryValue* pref; 233 // This tests is to make sure that the provider only notifies us of the 234 // values we gave it. So if the id we doesn't exist in our internal 235 // dictionary then something is wrong. 236 EXPECT_TRUE(prefs_->GetDictionary(id, &pref)) 237 << "Got back ID (" << id.c_str() << ") we weren't expecting"; 238 239 if (pref) { 240 EXPECT_TRUE(provider_->HasExtension(id)); 241 242 // Ask provider if the extension we got back is registered. 243 Extension::Location location = Extension::INVALID; 244 scoped_ptr<Version> v1; 245 FilePath crx_path; 246 247 EXPECT_TRUE(provider_->GetExtensionDetails(id, NULL, &v1)); 248 EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str()); 249 250 scoped_ptr<Version> v2; 251 EXPECT_TRUE(provider_->GetExtensionDetails(id, &location, &v2)); 252 EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str()); 253 EXPECT_STREQ(version->GetString().c_str(), v2->GetString().c_str()); 254 EXPECT_EQ(Extension::EXTERNAL_PREF, location); 255 256 // Remove it so we won't count it ever again. 257 prefs_->Remove(id, NULL); 258 } 259 } 260 261 virtual void OnExternalExtensionUpdateUrlFound( 262 const std::string& id, const GURL& update_url, 263 Extension::Location location) { 264 ++ids_found_; 265 DictionaryValue* pref; 266 // This tests is to make sure that the provider only notifies us of the 267 // values we gave it. So if the id we doesn't exist in our internal 268 // dictionary then something is wrong. 269 EXPECT_TRUE(prefs_->GetDictionary(id, &pref)) 270 << L"Got back ID (" << id.c_str() << ") we weren't expecting"; 271 EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location); 272 273 if (pref) { 274 EXPECT_TRUE(provider_->HasExtension(id)); 275 276 // External extensions with update URLs do not have versions. 277 scoped_ptr<Version> v1; 278 Extension::Location location1 = Extension::INVALID; 279 EXPECT_TRUE(provider_->GetExtensionDetails(id, &location1, &v1)); 280 EXPECT_FALSE(v1.get()); 281 EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location1); 282 283 // Remove it so we won't count it again. 284 prefs_->Remove(id, NULL); 285 } 286 } 287 288 private: 289 int ids_found_; 290 291 scoped_ptr<ExternalPrefExtensionProvider> provider_; 292 scoped_ptr<DictionaryValue> prefs_; 293 294 DISALLOW_COPY_AND_ASSIGN(MockProviderVisitor); 295}; 296 297class ExtensionTestingProfile : public TestingProfile { 298 public: 299 ExtensionTestingProfile() : service_(NULL) { 300 } 301 302 void set_extensions_service(ExtensionService* service) { 303 service_ = service; 304 } 305 virtual ExtensionService* GetExtensionService() { return service_; } 306 307 virtual ChromeAppCacheService* GetAppCacheService() { 308 if (!appcache_service_) { 309 appcache_service_ = new ChromeAppCacheService; 310 BrowserThread::PostTask( 311 BrowserThread::IO, FROM_HERE, 312 NewRunnableMethod(appcache_service_.get(), 313 &ChromeAppCacheService::InitializeOnIOThread, 314 GetPath(), IsOffTheRecord(), 315 make_scoped_refptr(GetHostContentSettingsMap()))); 316 } 317 return appcache_service_; 318 } 319 320 virtual fileapi::SandboxedFileSystemContext* GetFileSystemContext() { 321 if (!file_system_context_) 322 file_system_context_ = CreateFileSystemContext( 323 GetPath(), IsOffTheRecord()); 324 return file_system_context_; 325 } 326 327 private: 328 ExtensionService* service_; 329 scoped_refptr<ChromeAppCacheService> appcache_service_; 330 scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_; 331}; 332 333// Our message loop may be used in tests which require it to be an IO loop. 334ExtensionServiceTestBase::ExtensionServiceTestBase() 335 : total_successes_(0), 336 loop_(MessageLoop::TYPE_IO), 337 ui_thread_(BrowserThread::UI, &loop_), 338 db_thread_(BrowserThread::DB, &loop_), 339 webkit_thread_(BrowserThread::WEBKIT, &loop_), 340 file_thread_(BrowserThread::FILE, &loop_), 341 io_thread_(BrowserThread::IO, &loop_) { 342} 343 344ExtensionServiceTestBase::~ExtensionServiceTestBase() { 345 // Drop our reference to ExtensionService and TestingProfile, so that they 346 // can be destroyed while BrowserThreads and MessageLoop are still around 347 // (they are used in the destruction process). 348 service_ = NULL; 349 profile_.reset(NULL); 350 MessageLoop::current()->RunAllPending(); 351} 352 353void ExtensionServiceTestBase::InitializeExtensionService( 354 const FilePath& pref_file, const FilePath& extensions_install_dir) { 355 ExtensionTestingProfile* profile = new ExtensionTestingProfile(); 356 // Create a PrefService that only contains user defined preference values. 357 PrefService* prefs = 358 PrefServiceMockBuilder().WithUserFilePrefs(pref_file).Create(); 359 Profile::RegisterUserPrefs(prefs); 360 browser::RegisterUserPrefs(prefs); 361 profile->SetPrefService(prefs); 362 363 profile_.reset(profile); 364 365 service_ = profile->CreateExtensionService( 366 CommandLine::ForCurrentProcess(), 367 extensions_install_dir); 368 service_->set_extensions_enabled(true); 369 service_->set_show_extensions_prompts(false); 370 profile->set_extensions_service(service_.get()); 371 372 // When we start up, we want to make sure there is no external provider, 373 // since the ExtensionService on Windows will use the Registry as a default 374 // provider and if there is something already registered there then it will 375 // interfere with the tests. Those tests that need an external provider 376 // will register one specifically. 377 service_->ClearProvidersForTesting(); 378 379 total_successes_ = 0; 380} 381 382void ExtensionServiceTestBase::InitializeInstalledExtensionService( 383 const FilePath& prefs_file, const FilePath& source_install_dir) { 384 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 385 FilePath path_ = temp_dir_.path(); 386 path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath")); 387 file_util::Delete(path_, true); 388 file_util::CreateDirectory(path_); 389 FilePath temp_prefs = path_.Append(FILE_PATH_LITERAL("Preferences")); 390 file_util::CopyFile(prefs_file, temp_prefs); 391 392 extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions")); 393 file_util::Delete(extensions_install_dir_, true); 394 file_util::CopyDirectory(source_install_dir, extensions_install_dir_, true); 395 396 InitializeExtensionService(temp_prefs, extensions_install_dir_); 397} 398 399void ExtensionServiceTestBase::InitializeEmptyExtensionService() { 400 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 401 FilePath path_ = temp_dir_.path(); 402 path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath")); 403 file_util::Delete(path_, true); 404 file_util::CreateDirectory(path_); 405 FilePath prefs_filename = path_ 406 .Append(FILE_PATH_LITERAL("TestPreferences")); 407 extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions")); 408 file_util::Delete(extensions_install_dir_, true); 409 file_util::CreateDirectory(extensions_install_dir_); 410 411 InitializeExtensionService(prefs_filename, extensions_install_dir_); 412} 413 414// static 415void ExtensionServiceTestBase::SetUpTestCase() { 416 ExtensionErrorReporter::Init(false); // no noisy errors 417} 418 419void ExtensionServiceTestBase::SetUp() { 420 ExtensionErrorReporter::GetInstance()->ClearErrors(); 421} 422 423class ExtensionServiceTest 424 : public ExtensionServiceTestBase, public NotificationObserver { 425 public: 426 ExtensionServiceTest() : installed_(NULL) { 427 registrar_.Add(this, NotificationType::EXTENSION_LOADED, 428 NotificationService::AllSources()); 429 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 430 NotificationService::AllSources()); 431 registrar_.Add(this, NotificationType::EXTENSION_INSTALLED, 432 NotificationService::AllSources()); 433 registrar_.Add(this, NotificationType::THEME_INSTALLED, 434 NotificationService::AllSources()); 435 } 436 437 virtual void Observe(NotificationType type, 438 const NotificationSource& source, 439 const NotificationDetails& details) { 440 switch (type.value) { 441 case NotificationType::EXTENSION_LOADED: { 442 const Extension* extension = Details<const Extension>(details).ptr(); 443 loaded_.push_back(make_scoped_refptr(extension)); 444 // The tests rely on the errors being in a certain order, which can vary 445 // depending on how filesystem iteration works. 446 std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder()); 447 break; 448 } 449 450 case NotificationType::EXTENSION_UNLOADED: { 451 const Extension* e = 452 Details<UnloadedExtensionInfo>(details)->extension; 453 unloaded_id_ = e->id(); 454 ExtensionList::iterator i = 455 std::find(loaded_.begin(), loaded_.end(), e); 456 // TODO(erikkay) fix so this can be an assert. Right now the tests 457 // are manually calling clear() on loaded_, so this isn't doable. 458 if (i == loaded_.end()) 459 return; 460 loaded_.erase(i); 461 break; 462 } 463 case NotificationType::EXTENSION_INSTALLED: 464 case NotificationType::THEME_INSTALLED: 465 installed_ = Details<const Extension>(details).ptr(); 466 break; 467 468 default: 469 DCHECK(false); 470 } 471 } 472 473 void AddMockExternalProvider(ExternalExtensionProvider* provider) { 474 service_->AddProviderForTesting(provider); 475 } 476 477 protected: 478 void TestExternalProvider(MockExtensionProvider* provider, 479 Extension::Location location); 480 481 void PackAndInstallExtension(const FilePath& dir_path, 482 const FilePath& pem_path, 483 bool should_succeed) { 484 FilePath crx_path; 485 ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &crx_path)); 486 crx_path = crx_path.AppendASCII("temp.crx"); 487 488 // Use the existing pem key, if provided. 489 FilePath pem_output_path; 490 if (pem_path.value().empty()) { 491 pem_output_path = crx_path.DirName().AppendASCII("temp.pem"); 492 ASSERT_TRUE(file_util::Delete(pem_output_path, false)); 493 } else { 494 ASSERT_TRUE(file_util::PathExists(pem_path)); 495 } 496 497 ASSERT_TRUE(file_util::Delete(crx_path, false)); 498 499 scoped_ptr<ExtensionCreator> creator(new ExtensionCreator()); 500 ASSERT_TRUE(creator->Run(dir_path, 501 crx_path, 502 pem_path, 503 pem_output_path)); 504 505 ASSERT_TRUE(file_util::PathExists(crx_path)); 506 507 InstallExtension(crx_path, should_succeed); 508 } 509 510 void PackAndInstallExtension(const FilePath& dir_path, 511 bool should_succeed) { 512 PackAndInstallExtension(dir_path, FilePath(), should_succeed); 513 } 514 515 void InstallExtension(const FilePath& path, 516 bool should_succeed) { 517 ASSERT_TRUE(file_util::PathExists(path)); 518 service_->InstallExtension(path); 519 loop_.RunAllPending(); 520 std::vector<std::string> errors = GetErrors(); 521 if (should_succeed) { 522 ++total_successes_; 523 524 EXPECT_TRUE(installed_) << path.value(); 525 526 ASSERT_EQ(1u, loaded_.size()) << path.value(); 527 EXPECT_EQ(0u, errors.size()) << path.value(); 528 EXPECT_EQ(total_successes_, service_->extensions()->size()) << 529 path.value(); 530 EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) << 531 path.value(); 532 for (std::vector<std::string>::iterator err = errors.begin(); 533 err != errors.end(); ++err) { 534 LOG(ERROR) << *err; 535 } 536 } else { 537 EXPECT_FALSE(installed_) << path.value(); 538 EXPECT_EQ(0u, loaded_.size()) << path.value(); 539 EXPECT_EQ(1u, errors.size()) << path.value(); 540 } 541 542 installed_ = NULL; 543 loaded_.clear(); 544 ExtensionErrorReporter::GetInstance()->ClearErrors(); 545 } 546 547 enum UpdateState { 548 FAILED_SILENTLY, 549 FAILED, 550 UPDATED, 551 INSTALLED, 552 ENABLED 553 }; 554 555 void UpdateExtension(const std::string& id, const FilePath& in_path, 556 UpdateState expected_state) { 557 ASSERT_TRUE(file_util::PathExists(in_path)); 558 559 // We need to copy this to a temporary location because Update() will delete 560 // it. 561 FilePath path = temp_dir_.path(); 562 path = path.Append(in_path.BaseName()); 563 ASSERT_TRUE(file_util::CopyFile(in_path, path)); 564 565 int previous_enabled_extension_count = 566 service_->extensions()->size(); 567 int previous_installed_extension_count = 568 previous_enabled_extension_count + 569 service_->disabled_extensions()->size(); 570 571 service_->UpdateExtension(id, path, GURL()); 572 loop_.RunAllPending(); 573 574 std::vector<std::string> errors = GetErrors(); 575 int error_count = errors.size(); 576 int enabled_extension_count = 577 service_->extensions()->size(); 578 int installed_extension_count = 579 enabled_extension_count + service_->disabled_extensions()->size(); 580 581 int expected_error_count = (expected_state == FAILED) ? 1 : 0; 582 EXPECT_EQ(expected_error_count, error_count) << path.value(); 583 584 if (expected_state <= FAILED) { 585 EXPECT_EQ(previous_enabled_extension_count, 586 enabled_extension_count); 587 EXPECT_EQ(previous_installed_extension_count, 588 installed_extension_count); 589 } else { 590 int expected_installed_extension_count = 591 (expected_state >= INSTALLED) ? 1 : 0; 592 int expected_enabled_extension_count = 593 (expected_state >= ENABLED) ? 1 : 0; 594 EXPECT_EQ(expected_installed_extension_count, 595 installed_extension_count); 596 EXPECT_EQ(expected_enabled_extension_count, 597 enabled_extension_count); 598 } 599 600 // Update() should delete the temporary input file. 601 EXPECT_FALSE(file_util::PathExists(path)); 602 } 603 604 void ValidatePrefKeyCount(size_t count) { 605 DictionaryValue* dict = 606 profile_->GetPrefs()->GetMutableDictionary("extensions.settings"); 607 ASSERT_TRUE(dict != NULL); 608 EXPECT_EQ(count, dict->size()); 609 } 610 611 void ValidateBooleanPref(const std::string& extension_id, 612 const std::string& pref_path, 613 bool expected_val) { 614 std::string msg = " while checking: "; 615 msg += extension_id; 616 msg += " "; 617 msg += pref_path; 618 msg += " == "; 619 msg += expected_val ? "true" : "false"; 620 621 PrefService* prefs = profile_->GetPrefs(); 622 const DictionaryValue* dict = 623 prefs->GetDictionary("extensions.settings"); 624 ASSERT_TRUE(dict != NULL) << msg; 625 DictionaryValue* pref = NULL; 626 ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg; 627 EXPECT_TRUE(pref != NULL) << msg; 628 bool val; 629 ASSERT_TRUE(pref->GetBoolean(pref_path, &val)) << msg; 630 EXPECT_EQ(expected_val, val) << msg; 631 } 632 633 bool IsPrefExist(const std::string& extension_id, 634 const std::string& pref_path) { 635 const DictionaryValue* dict = 636 profile_->GetPrefs()->GetDictionary("extensions.settings"); 637 if (dict == NULL) return false; 638 DictionaryValue* pref = NULL; 639 if (!dict->GetDictionary(extension_id, &pref)) { 640 return false; 641 } 642 if (pref == NULL) { 643 return false; 644 } 645 bool val; 646 if (!pref->GetBoolean(pref_path, &val)) { 647 return false; 648 } 649 return true; 650 } 651 652 void ValidateIntegerPref(const std::string& extension_id, 653 const std::string& pref_path, 654 int expected_val) { 655 std::string msg = " while checking: "; 656 msg += extension_id; 657 msg += " "; 658 msg += pref_path; 659 msg += " == "; 660 msg += base::IntToString(expected_val); 661 662 PrefService* prefs = profile_->GetPrefs(); 663 const DictionaryValue* dict = 664 prefs->GetDictionary("extensions.settings"); 665 ASSERT_TRUE(dict != NULL) << msg; 666 DictionaryValue* pref = NULL; 667 ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg; 668 EXPECT_TRUE(pref != NULL) << msg; 669 int val; 670 ASSERT_TRUE(pref->GetInteger(pref_path, &val)) << msg; 671 EXPECT_EQ(expected_val, val) << msg; 672 } 673 674 void ValidateStringPref(const std::string& extension_id, 675 const std::string& pref_path, 676 const std::string& expected_val) { 677 std::string msg = " while checking: "; 678 msg += extension_id; 679 msg += ".manifest."; 680 msg += pref_path; 681 msg += " == "; 682 msg += expected_val; 683 684 const DictionaryValue* dict = 685 profile_->GetPrefs()->GetDictionary("extensions.settings"); 686 ASSERT_TRUE(dict != NULL) << msg; 687 DictionaryValue* pref = NULL; 688 std::string manifest_path = extension_id + ".manifest"; 689 ASSERT_TRUE(dict->GetDictionary(manifest_path, &pref)) << msg; 690 EXPECT_TRUE(pref != NULL) << msg; 691 std::string val; 692 ASSERT_TRUE(pref->GetString(pref_path, &val)) << msg; 693 EXPECT_EQ(expected_val, val) << msg; 694 } 695 696 void SetPref(const std::string& extension_id, 697 const std::string& pref_path, 698 Value* value, 699 const std::string& msg) { 700 const DictionaryValue* dict = 701 profile_->GetPrefs()->GetMutableDictionary("extensions.settings"); 702 ASSERT_TRUE(dict != NULL) << msg; 703 DictionaryValue* pref = NULL; 704 ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg; 705 EXPECT_TRUE(pref != NULL) << msg; 706 pref->Set(pref_path, value); 707 } 708 709 void SetPrefInteg(const std::string& extension_id, 710 const std::string& pref_path, 711 int value) { 712 std::string msg = " while setting: "; 713 msg += extension_id; 714 msg += " "; 715 msg += pref_path; 716 msg += " = "; 717 msg += base::IntToString(value); 718 719 SetPref(extension_id, pref_path, Value::CreateIntegerValue(value), msg); 720 } 721 722 void SetPrefBool(const std::string& extension_id, 723 const std::string& pref_path, 724 bool value) { 725 std::string msg = " while setting: "; 726 msg += extension_id + " " + pref_path; 727 msg += " = "; 728 msg += (value ? "true" : "false"); 729 730 SetPref(extension_id, pref_path, Value::CreateBooleanValue(value), msg); 731 } 732 733 void ClearPref(const std::string& extension_id, 734 const std::string& pref_path) { 735 std::string msg = " while clearing: "; 736 msg += extension_id + " " + pref_path; 737 738 const DictionaryValue* dict = 739 profile_->GetPrefs()->GetMutableDictionary("extensions.settings"); 740 ASSERT_TRUE(dict != NULL) << msg; 741 DictionaryValue* pref = NULL; 742 ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg; 743 EXPECT_TRUE(pref != NULL) << msg; 744 pref->Remove(pref_path, NULL); 745 } 746 747 void SetPrefStringSet(const std::string& extension_id, 748 const std::string& pref_path, 749 const std::set<std::string>& value) { 750 std::string msg = " while setting: "; 751 msg += extension_id + " " + pref_path; 752 753 ListValue* list_value = new ListValue(); 754 for (std::set<std::string>::const_iterator iter = value.begin(); 755 iter != value.end(); ++iter) 756 list_value->Append(Value::CreateStringValue(*iter)); 757 758 SetPref(extension_id, pref_path, list_value, msg); 759 } 760 761 protected: 762 ExtensionList loaded_; 763 std::string unloaded_id_; 764 const Extension* installed_; 765 766 private: 767 NotificationRegistrar registrar_; 768}; 769 770FilePath NormalizeSeparators(const FilePath& path) { 771#if defined(FILE_PATH_USES_WIN_SEPARATORS) 772 return path.NormalizeWindowsPathSeparators(); 773#else 774 return path; 775#endif // FILE_PATH_USES_WIN_SEPARATORS 776} 777 778// Receives notifications from a PackExtensionJob, indicating either that 779// packing succeeded or that there was some error. 780class PackExtensionTestClient : public PackExtensionJob::Client { 781 public: 782 PackExtensionTestClient(const FilePath& expected_crx_path, 783 const FilePath& expected_private_key_path); 784 virtual void OnPackSuccess(const FilePath& crx_path, 785 const FilePath& private_key_path); 786 virtual void OnPackFailure(const std::string& error_message); 787 788 private: 789 const FilePath expected_crx_path_; 790 const FilePath expected_private_key_path_; 791 DISALLOW_COPY_AND_ASSIGN(PackExtensionTestClient); 792}; 793 794PackExtensionTestClient::PackExtensionTestClient( 795 const FilePath& expected_crx_path, 796 const FilePath& expected_private_key_path) 797 : expected_crx_path_(expected_crx_path), 798 expected_private_key_path_(expected_private_key_path) {} 799 800// If packing succeeded, we make sure that the package names match our 801// expectations. 802void PackExtensionTestClient::OnPackSuccess(const FilePath& crx_path, 803 const FilePath& private_key_path) { 804 // We got the notification and processed it; we don't expect any further tasks 805 // to be posted to the current thread, so we should stop blocking and continue 806 // on with the rest of the test. 807 // This call to |Quit()| matches the call to |Run()| in the 808 // |PackPunctuatedExtension| test. 809 MessageLoop::current()->Quit(); 810 EXPECT_EQ(expected_crx_path_.value(), crx_path.value()); 811 EXPECT_EQ(expected_private_key_path_.value(), private_key_path.value()); 812 ASSERT_TRUE(file_util::PathExists(private_key_path)); 813} 814 815// The tests are designed so that we never expect to see a packing error. 816void PackExtensionTestClient::OnPackFailure(const std::string& error_message) { 817 FAIL() << "Packing should not fail."; 818} 819 820// Test loading good extensions from the profile directory. 821TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectorySuccess) { 822 // Initialize the test dir with a good Preferences/extensions. 823 FilePath source_install_dir; 824 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); 825 source_install_dir = source_install_dir 826 .AppendASCII("extensions") 827 .AppendASCII("good") 828 .AppendASCII("Extensions"); 829 FilePath pref_path = source_install_dir 830 .DirName() 831 .AppendASCII("Preferences"); 832 InitializeInstalledExtensionService(pref_path, source_install_dir); 833 834 service_->Init(); 835 836 // On Chrome OS, we disallow extensions with plugins. "good1" has plugins, 837 // so we need to edit it out here. 838 uint32 expected_num_extensions = 3u; 839#if defined(OS_CHROMEOS) 840 --expected_num_extensions; 841#endif 842 ASSERT_EQ(expected_num_extensions, loaded_.size()); 843 844 EXPECT_EQ(std::string(good0), loaded_[0]->id()); 845 EXPECT_EQ(std::string("My extension 1"), 846 loaded_[0]->name()); 847 EXPECT_EQ(std::string("The first extension that I made."), 848 loaded_[0]->description()); 849 EXPECT_EQ(Extension::INTERNAL, loaded_[0]->location()); 850 EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)); 851 EXPECT_EQ(expected_num_extensions, service_->extensions()->size()); 852 853 ValidatePrefKeyCount(3); 854 ValidateIntegerPref(good0, "state", Extension::ENABLED); 855 ValidateIntegerPref(good0, "location", Extension::INTERNAL); 856 ValidateIntegerPref(good1, "state", Extension::ENABLED); 857 ValidateIntegerPref(good1, "location", Extension::INTERNAL); 858 ValidateIntegerPref(good2, "state", Extension::ENABLED); 859 ValidateIntegerPref(good2, "location", Extension::INTERNAL); 860 861 const Extension* extension = loaded_[0]; 862 const UserScriptList& scripts = extension->content_scripts(); 863 ASSERT_EQ(2u, scripts.size()); 864 EXPECT_EQ(3u, scripts[0].url_patterns().size()); 865 EXPECT_EQ("file://*", 866 scripts[0].url_patterns()[0].GetAsString()); 867 EXPECT_EQ("http://*.google.com/*", 868 scripts[0].url_patterns()[1].GetAsString()); 869 EXPECT_EQ("https://*.google.com/*", 870 scripts[0].url_patterns()[2].GetAsString()); 871 EXPECT_EQ(2u, scripts[0].js_scripts().size()); 872 ExtensionResource resource00(extension->id(), 873 scripts[0].js_scripts()[0].extension_root(), 874 scripts[0].js_scripts()[0].relative_path()); 875 FilePath expected_path(extension->path().AppendASCII("script1.js")); 876 ASSERT_TRUE(file_util::AbsolutePath(&expected_path)); 877 EXPECT_TRUE(resource00.ComparePathWithDefault(expected_path)); 878 ExtensionResource resource01(extension->id(), 879 scripts[0].js_scripts()[1].extension_root(), 880 scripts[0].js_scripts()[1].relative_path()); 881 expected_path = extension->path().AppendASCII("script2.js"); 882 ASSERT_TRUE(file_util::AbsolutePath(&expected_path)); 883 EXPECT_TRUE(resource01.ComparePathWithDefault(expected_path)); 884 EXPECT_TRUE(extension->plugins().empty()); 885 EXPECT_EQ(1u, scripts[1].url_patterns().size()); 886 EXPECT_EQ("http://*.news.com/*", scripts[1].url_patterns()[0].GetAsString()); 887 ExtensionResource resource10(extension->id(), 888 scripts[1].js_scripts()[0].extension_root(), 889 scripts[1].js_scripts()[0].relative_path()); 890 expected_path = 891 extension->path().AppendASCII("js_files").AppendASCII("script3.js"); 892 ASSERT_TRUE(file_util::AbsolutePath(&expected_path)); 893 EXPECT_TRUE(resource10.ComparePathWithDefault(expected_path)); 894 const std::vector<URLPattern> permissions = extension->host_permissions(); 895 ASSERT_EQ(2u, permissions.size()); 896 EXPECT_EQ("http://*.google.com/*", permissions[0].GetAsString()); 897 EXPECT_EQ("https://*.google.com/*", permissions[1].GetAsString()); 898 899#if !defined(OS_CHROMEOS) 900 EXPECT_EQ(std::string(good1), loaded_[1]->id()); 901 EXPECT_EQ(std::string("My extension 2"), loaded_[1]->name()); 902 EXPECT_EQ(std::string(""), loaded_[1]->description()); 903 EXPECT_EQ(loaded_[1]->GetResourceURL("background.html"), 904 loaded_[1]->background_url()); 905 EXPECT_EQ(0u, loaded_[1]->content_scripts().size()); 906 EXPECT_EQ(2u, loaded_[1]->plugins().size()); 907 EXPECT_EQ(loaded_[1]->path().AppendASCII("content_plugin.dll").value(), 908 loaded_[1]->plugins()[0].path.value()); 909 EXPECT_TRUE(loaded_[1]->plugins()[0].is_public); 910 EXPECT_EQ(loaded_[1]->path().AppendASCII("extension_plugin.dll").value(), 911 loaded_[1]->plugins()[1].path.value()); 912 EXPECT_FALSE(loaded_[1]->plugins()[1].is_public); 913 EXPECT_EQ(Extension::INTERNAL, loaded_[1]->location()); 914#endif 915 916 int index = expected_num_extensions - 1; 917 EXPECT_EQ(std::string(good2), loaded_[index]->id()); 918 EXPECT_EQ(std::string("My extension 3"), loaded_[index]->name()); 919 EXPECT_EQ(std::string(""), loaded_[index]->description()); 920 EXPECT_EQ(0u, loaded_[index]->content_scripts().size()); 921 EXPECT_EQ(Extension::INTERNAL, loaded_[index]->location()); 922}; 923 924// Test loading bad extensions from the profile directory. 925TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectoryFail) { 926 // Initialize the test dir with a bad Preferences/extensions. 927 FilePath source_install_dir; 928 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); 929 source_install_dir = source_install_dir 930 .AppendASCII("extensions") 931 .AppendASCII("bad") 932 .AppendASCII("Extensions"); 933 FilePath pref_path = source_install_dir 934 .DirName() 935 .AppendASCII("Preferences"); 936 937 InitializeInstalledExtensionService(pref_path, source_install_dir); 938 939 service_->Init(); 940 loop_.RunAllPending(); 941 942 ASSERT_EQ(4u, GetErrors().size()); 943 ASSERT_EQ(0u, loaded_.size()); 944 945 EXPECT_TRUE(MatchPattern(GetErrors()[0], 946 std::string("Could not load extension from '*'. ") + 947 extension_manifest_errors::kManifestUnreadable)) << GetErrors()[0]; 948 949 EXPECT_TRUE(MatchPattern(GetErrors()[1], 950 std::string("Could not load extension from '*'. ") + 951 extension_manifest_errors::kManifestUnreadable)) << GetErrors()[1]; 952 953 EXPECT_TRUE(MatchPattern(GetErrors()[2], 954 std::string("Could not load extension from '*'. ") + 955 extension_manifest_errors::kMissingFile)) << GetErrors()[2]; 956 957 EXPECT_TRUE(MatchPattern(GetErrors()[3], 958 std::string("Could not load extension from '*'. ") + 959 extension_manifest_errors::kManifestUnreadable)) << GetErrors()[3]; 960}; 961 962// Test that partially deleted extensions are cleaned up during startup 963// Test loading bad extensions from the profile directory. 964TEST_F(ExtensionServiceTest, CleanupOnStartup) { 965 FilePath source_install_dir; 966 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); 967 source_install_dir = source_install_dir 968 .AppendASCII("extensions") 969 .AppendASCII("good") 970 .AppendASCII("Extensions"); 971 FilePath pref_path = source_install_dir 972 .DirName() 973 .AppendASCII("Preferences"); 974 975 InitializeInstalledExtensionService(pref_path, source_install_dir); 976 977 // Simulate that one of them got partially deleted by clearing its pref. 978 DictionaryValue* dict = 979 profile_->GetPrefs()->GetMutableDictionary("extensions.settings"); 980 ASSERT_TRUE(dict != NULL); 981 dict->Remove("behllobkkfkfnphdnhnkndlbkcpglgmj", NULL); 982 983 service_->Init(); 984 loop_.RunAllPending(); 985 986 file_util::FileEnumerator dirs(extensions_install_dir_, false, 987 file_util::FileEnumerator::DIRECTORIES); 988 size_t count = 0; 989 while (!dirs.Next().empty()) 990 count++; 991 992 // We should have only gotten two extensions now. 993 EXPECT_EQ(2u, count); 994 995 // And extension1 dir should now be toast. 996 FilePath extension_dir = extensions_install_dir_ 997 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj"); 998 ASSERT_FALSE(file_util::PathExists(extension_dir)); 999} 1000 1001// Test installing extensions. This test tries to install few extensions using 1002// crx files. If you need to change those crx files, feel free to repackage 1003// them, throw away the key used and change the id's above. 1004TEST_F(ExtensionServiceTest, InstallExtension) { 1005 InitializeEmptyExtensionService(); 1006 1007 FilePath extensions_path; 1008 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1009 extensions_path = extensions_path.AppendASCII("extensions"); 1010 1011 // Extensions not enabled. 1012 set_extensions_enabled(false); 1013 FilePath path = extensions_path.AppendASCII("good.crx"); 1014 InstallExtension(path, false); 1015 set_extensions_enabled(true); 1016 1017 ValidatePrefKeyCount(0); 1018 1019 // A simple extension that should install without error. 1020 path = extensions_path.AppendASCII("good.crx"); 1021 InstallExtension(path, true); 1022 // TODO(erikkay): verify the contents of the installed extension. 1023 1024 int pref_count = 0; 1025 ValidatePrefKeyCount(++pref_count); 1026 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 1027 ValidateIntegerPref(good_crx, "location", Extension::INTERNAL); 1028 1029 // An extension with page actions. 1030 path = extensions_path.AppendASCII("page_action.crx"); 1031 InstallExtension(path, true); 1032 ValidatePrefKeyCount(++pref_count); 1033 ValidateIntegerPref(page_action, "state", Extension::ENABLED); 1034 ValidateIntegerPref(page_action, "location", Extension::INTERNAL); 1035 1036 // Bad signature. 1037 path = extensions_path.AppendASCII("bad_signature.crx"); 1038 InstallExtension(path, false); 1039 ValidatePrefKeyCount(pref_count); 1040 1041 // 0-length extension file. 1042 path = extensions_path.AppendASCII("not_an_extension.crx"); 1043 InstallExtension(path, false); 1044 ValidatePrefKeyCount(pref_count); 1045 1046 // Bad magic number. 1047 path = extensions_path.AppendASCII("bad_magic.crx"); 1048 InstallExtension(path, false); 1049 ValidatePrefKeyCount(pref_count); 1050 1051 // Extensions cannot have folders or files that have underscores except in 1052 // certain whitelisted cases (eg _locales). This is an example of a broader 1053 // class of validation that we do to the directory structure of the extension. 1054 // We did not used to handle this correctly for installation. 1055 path = extensions_path.AppendASCII("bad_underscore.crx"); 1056 InstallExtension(path, false); 1057 ValidatePrefKeyCount(pref_count); 1058 1059 // TODO(erikkay): add more tests for many of the failure cases. 1060 // TODO(erikkay): add tests for upgrade cases. 1061} 1062 1063// Test the handling of killed extensions. 1064TEST_F(ExtensionServiceTest, KilledExtensions) { 1065 InitializeEmptyExtensionService(); 1066 1067 FilePath extensions_path; 1068 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1069 extensions_path = extensions_path.AppendASCII("extensions"); 1070 FilePath path = extensions_path.AppendASCII("good.crx"); 1071 set_extensions_enabled(true); 1072 1073 // Install an external extension. 1074 service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0", 1075 path, Extension::EXTERNAL_PREF); 1076 loop_.RunAllPending(); 1077 ASSERT_TRUE(NULL != service_->GetExtensionById(good_crx, false)); 1078 1079 // Uninstall it and check that its killbit gets set. 1080 service_->UninstallExtension(good_crx, false); 1081 loop_.RunAllPending(); 1082 ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); 1083 1084 // Try to re-install it externally. This should fail because of the killbit. 1085 service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0", 1086 path, Extension::EXTERNAL_PREF); 1087 loop_.RunAllPending(); 1088 ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false)); 1089 ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); 1090 1091 // Repeat the same thing with a newer version of the extension. 1092 path = extensions_path.AppendASCII("good2.crx"); 1093 service_->OnExternalExtensionFileFound(good_crx, "1.0.0.1", 1094 path, Extension::EXTERNAL_PREF); 1095 loop_.RunAllPending(); 1096 ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false)); 1097 ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); 1098 1099 // Try adding the same extension from an external update URL. 1100 service_->AddPendingExtensionFromExternalUpdateUrl( 1101 good_crx, 1102 GURL("http:://fake.update/url"), 1103 Extension::EXTERNAL_PREF_DOWNLOAD); 1104 const PendingExtensionMap& pending_extensions = 1105 service_->pending_extensions(); 1106 ASSERT_TRUE(pending_extensions.find(good_crx) == pending_extensions.end()); 1107} 1108 1109// Install a user script (they get converted automatically to an extension) 1110TEST_F(ExtensionServiceTest, InstallUserScript) { 1111 // The details of script conversion are tested elsewhere, this just tests 1112 // integration with ExtensionService. 1113 InitializeEmptyExtensionService(); 1114 1115 FilePath path; 1116 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 1117 path = path.AppendASCII("extensions") 1118 .AppendASCII("user_script_basic.user.js"); 1119 1120 ASSERT_TRUE(file_util::PathExists(path)); 1121 scoped_refptr<CrxInstaller> installer( 1122 new CrxInstaller(service_, NULL)); // silent install 1123 installer->InstallUserScript( 1124 path, 1125 GURL("http://www.aaronboodman.com/scripts/user_script_basic.user.js")); 1126 1127 loop_.RunAllPending(); 1128 std::vector<std::string> errors = GetErrors(); 1129 EXPECT_TRUE(installed_) << "Nothing was installed."; 1130 ASSERT_EQ(1u, loaded_.size()) << "Nothing was loaded."; 1131 EXPECT_EQ(0u, errors.size()) << "There were errors: " 1132 << JoinString(errors, ','); 1133 EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) << 1134 path.value(); 1135 1136 installed_ = NULL; 1137 loaded_.clear(); 1138 ExtensionErrorReporter::GetInstance()->ClearErrors(); 1139} 1140 1141// This tests that the granted permissions preferences are correctly set when 1142// installing an extension. 1143TEST_F(ExtensionServiceTest, GrantedPermissions) { 1144 InitializeEmptyExtensionService(); 1145 FilePath path; 1146 FilePath pem_path; 1147 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 1148 path = path.AppendASCII("extensions") 1149 .AppendASCII("permissions"); 1150 1151 pem_path = path.AppendASCII("unknown.pem"); 1152 path = path.AppendASCII("unknown"); 1153 1154 ASSERT_TRUE(file_util::PathExists(pem_path)); 1155 ASSERT_TRUE(file_util::PathExists(path)); 1156 1157 ExtensionPrefs* prefs = service_->extension_prefs(); 1158 1159 std::set<std::string> expected_api_perms; 1160 std::set<std::string> known_api_perms; 1161 bool full_access; 1162 ExtensionExtent expected_host_perms; 1163 ExtensionExtent known_host_perms; 1164 1165 // Make sure there aren't any granted permissions before the 1166 // extension is installed. 1167 EXPECT_FALSE(prefs->GetGrantedPermissions( 1168 permissions_crx, &full_access, &known_api_perms, &known_host_perms)); 1169 EXPECT_TRUE(known_api_perms.empty()); 1170 EXPECT_TRUE(known_host_perms.is_empty()); 1171 1172 PackAndInstallExtension(path, pem_path, true); 1173 1174 EXPECT_EQ(0u, GetErrors().size()); 1175 ASSERT_EQ(1u, service_->extensions()->size()); 1176 std::string extension_id = service_->extensions()->at(0)->id(); 1177 EXPECT_EQ(permissions_crx, extension_id); 1178 1179 1180 // Verify that the valid API permissions have been recognized. 1181 expected_api_perms.insert("tabs"); 1182 1183 AddPattern(&expected_host_perms, "http://*.google.com/*"); 1184 AddPattern(&expected_host_perms, "https://*.google.com/*"); 1185 AddPattern(&expected_host_perms, "http://*.google.com.hk/*"); 1186 AddPattern(&expected_host_perms, "http://www.example.com/*"); 1187 1188 EXPECT_TRUE(prefs->GetGrantedPermissions(extension_id, 1189 &full_access, 1190 &known_api_perms, 1191 &known_host_perms)); 1192 1193 EXPECT_EQ(expected_api_perms, known_api_perms); 1194 EXPECT_FALSE(full_access); 1195 AssertEqualExtents(&expected_host_perms, &known_host_perms); 1196} 1197 1198#if !defined(OS_CHROMEOS) 1199// Tests that the granted permissions full_access bit gets set correctly when 1200// an extension contains an NPAPI plugin. Don't run this test on Chrome OS 1201// since they don't support plugins. 1202TEST_F(ExtensionServiceTest, GrantedFullAccessPermissions) { 1203 InitializeEmptyExtensionService(); 1204 1205 FilePath path; 1206 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 1207 path = path.AppendASCII("extensions") 1208 .AppendASCII("good") 1209 .AppendASCII("Extensions") 1210 .AppendASCII(good1) 1211 .AppendASCII("2"); 1212 1213 ASSERT_TRUE(file_util::PathExists(path)); 1214 1215 PackAndInstallExtension(path, true); 1216 1217 EXPECT_EQ(0u, GetErrors().size()); 1218 EXPECT_EQ(1u, service_->extensions()->size()); 1219 const Extension* extension = service_->extensions()->at(0); 1220 std::string extension_id = extension->id(); 1221 ExtensionPrefs* prefs = service_->extension_prefs(); 1222 1223 bool full_access; 1224 std::set<std::string> api_permissions; 1225 ExtensionExtent host_permissions; 1226 EXPECT_TRUE(prefs->GetGrantedPermissions( 1227 extension_id, &full_access, &api_permissions, &host_permissions)); 1228 1229 EXPECT_TRUE(full_access); 1230 EXPECT_TRUE(api_permissions.empty()); 1231 EXPECT_TRUE(host_permissions.is_empty()); 1232} 1233#endif 1234 1235// Tests that the extension is disabled when permissions are missing from 1236// the extension's granted permissions preferences. (This simulates updating 1237// the browser to a version which recognizes more permissions). 1238TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) { 1239 InitializeEmptyExtensionService(); 1240 1241 FilePath path; 1242 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 1243 path = path.AppendASCII("extensions") 1244 .AppendASCII("permissions") 1245 .AppendASCII("unknown"); 1246 1247 ASSERT_TRUE(file_util::PathExists(path)); 1248 1249 PackAndInstallExtension(path, true); 1250 1251 EXPECT_EQ(0u, GetErrors().size()); 1252 EXPECT_EQ(1u, service_->extensions()->size()); 1253 const Extension* extension = service_->extensions()->at(0); 1254 std::string extension_id = extension->id(); 1255 1256 ExtensionPrefs* prefs = service_->extension_prefs(); 1257 1258 std::set<std::string> expected_api_permissions; 1259 ExtensionExtent expected_host_permissions; 1260 1261 expected_api_permissions.insert("tabs"); 1262 AddPattern(&expected_host_permissions, "http://*.google.com/*"); 1263 AddPattern(&expected_host_permissions, "https://*.google.com/*"); 1264 AddPattern(&expected_host_permissions, "http://*.google.com.hk/*"); 1265 AddPattern(&expected_host_permissions, "http://www.example.com/*"); 1266 1267 std::set<std::string> api_permissions; 1268 std::set<std::string> host_permissions; 1269 1270 // Test that the extension is disabled when an API permission is missing from 1271 // the extension's granted api permissions preference. (This simulates 1272 // updating the browser to a version which recognizes a new API permission). 1273 SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions); 1274 1275 service_->ReloadExtensions(); 1276 1277 EXPECT_EQ(1u, service_->disabled_extensions()->size()); 1278 extension = service_->disabled_extensions()->at(0); 1279 1280 ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED); 1281 ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id)); 1282 1283 // Now grant and re-enable the extension, making sure the prefs are updated. 1284 service_->GrantPermissionsAndEnableExtension(extension); 1285 1286 ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED); 1287 ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id)); 1288 1289 std::set<std::string> current_api_permissions; 1290 ExtensionExtent current_host_permissions; 1291 bool current_full_access; 1292 1293 ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id, 1294 ¤t_full_access, 1295 ¤t_api_permissions, 1296 ¤t_host_permissions)); 1297 1298 ASSERT_FALSE(current_full_access); 1299 ASSERT_EQ(expected_api_permissions, current_api_permissions); 1300 AssertEqualExtents(&expected_host_permissions, ¤t_host_permissions); 1301 1302 // Tests that the extension is disabled when a host permission is missing from 1303 // the extension's granted host permissions preference. (This simulates 1304 // updating the browser to a version which recognizes additional host 1305 // permissions). 1306 api_permissions.clear(); 1307 host_permissions.clear(); 1308 current_api_permissions.clear(); 1309 current_host_permissions.ClearPaths(); 1310 1311 api_permissions.insert("tabs"); 1312 host_permissions.insert("http://*.google.com/*"); 1313 host_permissions.insert("https://*.google.com/*"); 1314 host_permissions.insert("http://*.google.com.hk/*"); 1315 1316 SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions); 1317 SetPrefStringSet(extension_id, "granted_permissions.host", host_permissions); 1318 1319 service_->ReloadExtensions(); 1320 1321 EXPECT_EQ(1u, service_->disabled_extensions()->size()); 1322 extension = service_->disabled_extensions()->at(0); 1323 1324 ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED); 1325 ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id)); 1326 1327 // Now grant and re-enable the extension, making sure the prefs are updated. 1328 service_->GrantPermissionsAndEnableExtension(extension); 1329 1330 ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED); 1331 ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id)); 1332 1333 ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id, 1334 ¤t_full_access, 1335 ¤t_api_permissions, 1336 ¤t_host_permissions)); 1337 1338 ASSERT_FALSE(current_full_access); 1339 ASSERT_EQ(expected_api_permissions, current_api_permissions); 1340 AssertEqualExtents(&expected_host_permissions, ¤t_host_permissions); 1341 1342 // Tests that the granted permissions preferences are initialized when 1343 // migrating from the old pref schema. 1344 current_api_permissions.clear(); 1345 current_host_permissions.ClearPaths(); 1346 1347 ClearPref(extension_id, "granted_permissions"); 1348 1349 service_->ReloadExtensions(); 1350 1351 EXPECT_EQ(1u, service_->extensions()->size()); 1352 extension = service_->extensions()->at(0); 1353 1354 ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED); 1355 ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id)); 1356 1357 ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id, 1358 ¤t_full_access, 1359 ¤t_api_permissions, 1360 ¤t_host_permissions)); 1361 1362 ASSERT_FALSE(current_full_access); 1363 ASSERT_EQ(expected_api_permissions, current_api_permissions); 1364 AssertEqualExtents(&expected_host_permissions, ¤t_host_permissions); 1365} 1366 1367// Test Packaging and installing an extension. 1368TEST_F(ExtensionServiceTest, PackExtension) { 1369 InitializeEmptyExtensionService(); 1370 FilePath extensions_path; 1371 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1372 extensions_path = extensions_path.AppendASCII("extensions"); 1373 FilePath input_directory = extensions_path 1374 .AppendASCII("good") 1375 .AppendASCII("Extensions") 1376 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 1377 .AppendASCII("1.0.0.0"); 1378 1379 ScopedTempDir temp_dir; 1380 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 1381 FilePath output_directory = temp_dir.path(); 1382 1383 FilePath crx_path(output_directory.AppendASCII("ex1.crx")); 1384 FilePath privkey_path(output_directory.AppendASCII("privkey.pem")); 1385 1386 scoped_ptr<ExtensionCreator> creator(new ExtensionCreator()); 1387 ASSERT_TRUE(creator->Run(input_directory, crx_path, FilePath(), 1388 privkey_path)); 1389 1390 ASSERT_TRUE(file_util::PathExists(privkey_path)); 1391 InstallExtension(crx_path, true); 1392 1393 // Try packing with invalid paths. 1394 creator.reset(new ExtensionCreator()); 1395 ASSERT_FALSE(creator->Run(FilePath(), FilePath(), FilePath(), FilePath())); 1396 1397 // Try packing an empty directory. Should fail because an empty directory is 1398 // not a valid extension. 1399 ScopedTempDir temp_dir2; 1400 ASSERT_TRUE(temp_dir2.CreateUniqueTempDir()); 1401 creator.reset(new ExtensionCreator()); 1402 ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path, 1403 FilePath())); 1404 1405 // Try packing with an invalid manifest. 1406 std::string invalid_manifest_content = "I am not a manifest."; 1407 ASSERT_TRUE(file_util::WriteFile( 1408 temp_dir2.path().Append(Extension::kManifestFilename), 1409 invalid_manifest_content.c_str(), invalid_manifest_content.size())); 1410 creator.reset(new ExtensionCreator()); 1411 ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path, 1412 FilePath())); 1413} 1414 1415// Test Packaging and installing an extension whose name contains punctuation. 1416TEST_F(ExtensionServiceTest, PackPunctuatedExtension) { 1417 InitializeEmptyExtensionService(); 1418 FilePath extensions_path; 1419 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1420 extensions_path = extensions_path.AppendASCII("extensions"); 1421 FilePath input_directory = extensions_path 1422 .AppendASCII("good") 1423 .AppendASCII("Extensions") 1424 .AppendASCII(good0) 1425 .AppendASCII("1.0.0.0"); 1426 1427 ScopedTempDir temp_dir; 1428 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 1429 1430 // Extension names containing punctuation, and the expected names for the 1431 // packed extensions. 1432 const FilePath punctuated_names[] = { 1433 FilePath(FilePath::StringType( 1434 FILE_PATH_LITERAL("this.extensions.name.has.periods"))), 1435 FilePath(FilePath::StringType( 1436 FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod"))), 1437 NormalizeSeparators(FilePath(FilePath::StringType( 1438 FILE_PATH_LITERAL("thisextensionhasaslashinitsname/")))), 1439 }; 1440 const FilePath expected_crx_names[] = { 1441 FilePath(FilePath::StringType( 1442 FILE_PATH_LITERAL("this.extensions.name.has.periods.crx"))), 1443 FilePath(FilePath::StringType( 1444 FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.crx"))), 1445 FilePath(FilePath::StringType( 1446 FILE_PATH_LITERAL("thisextensionhasaslashinitsname.crx"))), 1447 }; 1448 const FilePath expected_private_key_names[] = { 1449 FilePath(FilePath::StringType( 1450 FILE_PATH_LITERAL("this.extensions.name.has.periods.pem"))), 1451 FilePath(FilePath::StringType( 1452 FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.pem"))), 1453 FilePath(FilePath::StringType( 1454 FILE_PATH_LITERAL("thisextensionhasaslashinitsname.pem"))), 1455 }; 1456 1457 for (size_t i = 0; i < arraysize(punctuated_names); ++i) { 1458 SCOPED_TRACE(punctuated_names[i].value().c_str()); 1459 FilePath output_dir = temp_dir.path().Append(punctuated_names[i]); 1460 1461 // Copy the extension into the output directory, as PackExtensionJob doesn't 1462 // let us choose where to output the packed extension. 1463 ASSERT_TRUE(file_util::CopyDirectory(input_directory, output_dir, true)); 1464 1465 FilePath expected_crx_path = temp_dir.path().Append(expected_crx_names[i]); 1466 FilePath expected_private_key_path = 1467 temp_dir.path().Append(expected_private_key_names[i]); 1468 PackExtensionTestClient pack_client(expected_crx_path, 1469 expected_private_key_path); 1470 scoped_refptr<PackExtensionJob> packer(new PackExtensionJob(&pack_client, 1471 output_dir, 1472 FilePath())); 1473 packer->Start(); 1474 1475 // The packer will post a notification task to the current thread's message 1476 // loop when it is finished. We manually run the loop here so that we 1477 // block and catch the notification; otherwise, the process would exit. 1478 // This call to |Run()| is matched by a call to |Quit()| in the 1479 // |PackExtensionTestClient|'s notification handling code. 1480 MessageLoop::current()->Run(); 1481 1482 if (HasFatalFailure()) 1483 return; 1484 1485 InstallExtension(expected_crx_path, true); 1486 } 1487} 1488 1489// Test Packaging and installing an extension using an openssl generated key. 1490// The openssl is generated with the following: 1491// > openssl genrsa -out privkey.pem 1024 1492// > openssl pkcs8 -topk8 -nocrypt -in privkey.pem -out privkey_asn1.pem 1493// The privkey.pem is a PrivateKey, and the pcks8 -topk8 creates a 1494// PrivateKeyInfo ASN.1 structure, we our RSAPrivateKey expects. 1495TEST_F(ExtensionServiceTest, PackExtensionOpenSSLKey) { 1496 InitializeEmptyExtensionService(); 1497 FilePath extensions_path; 1498 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1499 extensions_path = extensions_path.AppendASCII("extensions"); 1500 FilePath input_directory = extensions_path 1501 .AppendASCII("good") 1502 .AppendASCII("Extensions") 1503 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 1504 .AppendASCII("1.0.0.0"); 1505 FilePath privkey_path(extensions_path.AppendASCII( 1506 "openssl_privkey_asn1.pem")); 1507 ASSERT_TRUE(file_util::PathExists(privkey_path)); 1508 1509 ScopedTempDir temp_dir; 1510 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 1511 FilePath output_directory = temp_dir.path(); 1512 1513 FilePath crx_path(output_directory.AppendASCII("ex1.crx")); 1514 1515 scoped_ptr<ExtensionCreator> creator(new ExtensionCreator()); 1516 ASSERT_TRUE(creator->Run(input_directory, crx_path, privkey_path, 1517 FilePath())); 1518 1519 InstallExtension(crx_path, true); 1520} 1521 1522TEST_F(ExtensionServiceTest, InstallTheme) { 1523 InitializeEmptyExtensionService(); 1524 FilePath extensions_path; 1525 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1526 extensions_path = extensions_path.AppendASCII("extensions"); 1527 1528 // A theme. 1529 FilePath path = extensions_path.AppendASCII("theme.crx"); 1530 InstallExtension(path, true); 1531 int pref_count = 0; 1532 ValidatePrefKeyCount(++pref_count); 1533 ValidateIntegerPref(theme_crx, "state", Extension::ENABLED); 1534 ValidateIntegerPref(theme_crx, "location", Extension::INTERNAL); 1535 1536 // A theme when extensions are disabled. Themes can be installed, even when 1537 // extensions are disabled. 1538 set_extensions_enabled(false); 1539 path = extensions_path.AppendASCII("theme2.crx"); 1540 InstallExtension(path, true); 1541 ValidatePrefKeyCount(++pref_count); 1542 ValidateIntegerPref(theme2_crx, "state", Extension::ENABLED); 1543 ValidateIntegerPref(theme2_crx, "location", Extension::INTERNAL); 1544 1545 // A theme with extension elements. Themes cannot have extension elements so 1546 // this test should fail. 1547 set_extensions_enabled(true); 1548 path = extensions_path.AppendASCII("theme_with_extension.crx"); 1549 InstallExtension(path, false); 1550 ValidatePrefKeyCount(pref_count); 1551 1552 // A theme with image resources missing (misspelt path). 1553 path = extensions_path.AppendASCII("theme_missing_image.crx"); 1554 InstallExtension(path, false); 1555 ValidatePrefKeyCount(pref_count); 1556} 1557 1558TEST_F(ExtensionServiceTest, LoadLocalizedTheme) { 1559 // Load. 1560 InitializeEmptyExtensionService(); 1561 FilePath extension_path; 1562 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extension_path)); 1563 extension_path = extension_path 1564 .AppendASCII("extensions") 1565 .AppendASCII("theme_i18n"); 1566 1567 service_->LoadExtension(extension_path); 1568 loop_.RunAllPending(); 1569 EXPECT_EQ(0u, GetErrors().size()); 1570 ASSERT_EQ(1u, loaded_.size()); 1571 EXPECT_EQ(1u, service_->extensions()->size()); 1572 EXPECT_EQ("name", service_->extensions()->at(0)->name()); 1573 EXPECT_EQ("description", service_->extensions()->at(0)->description()); 1574} 1575 1576TEST_F(ExtensionServiceTest, InstallLocalizedTheme) { 1577 InitializeEmptyExtensionService(); 1578 FilePath theme_path; 1579 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &theme_path)); 1580 theme_path = theme_path 1581 .AppendASCII("extensions") 1582 .AppendASCII("theme_i18n"); 1583 1584 PackAndInstallExtension(theme_path, true); 1585 1586 EXPECT_EQ(0u, GetErrors().size()); 1587 EXPECT_EQ(1u, service_->extensions()->size()); 1588 EXPECT_EQ("name", service_->extensions()->at(0)->name()); 1589 EXPECT_EQ("description", service_->extensions()->at(0)->description()); 1590} 1591 1592TEST_F(ExtensionServiceTest, InstallApps) { 1593 InitializeEmptyExtensionService(); 1594 FilePath extensions_path; 1595 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1596 extensions_path = extensions_path.AppendASCII("extensions"); 1597 1598 // An empty app. 1599 PackAndInstallExtension(extensions_path.AppendASCII("app1"), true); 1600 int pref_count = 0; 1601 ValidatePrefKeyCount(++pref_count); 1602 ASSERT_EQ(1u, service_->extensions()->size()); 1603 std::string id = service_->extensions()->at(0)->id(); 1604 ValidateIntegerPref(id, "state", Extension::ENABLED); 1605 ValidateIntegerPref(id, "location", Extension::INTERNAL); 1606 1607 // Another app with non-overlapping extent. Should succeed. 1608 PackAndInstallExtension(extensions_path.AppendASCII("app2"), true); 1609 ValidatePrefKeyCount(++pref_count); 1610 1611 // A third app whose extent overlaps the first. Should fail. 1612 PackAndInstallExtension(extensions_path.AppendASCII("app3"), false); 1613 ValidatePrefKeyCount(pref_count); 1614} 1615 1616TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) { 1617 InitializeEmptyExtensionService(); 1618 EXPECT_TRUE(service_->extensions()->empty()); 1619 EXPECT_TRUE(service_->unlimited_storage_map_.empty()); 1620 1621 FilePath extensions_path; 1622 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1623 extensions_path = extensions_path.AppendASCII("extensions"); 1624 int pref_count = 0; 1625 ChromeAppCacheService* appcache_service = profile_->GetAppCacheService(); 1626 1627 // Install app1 with unlimited storage. 1628 PackAndInstallExtension(extensions_path.AppendASCII("app1"), true); 1629 ValidatePrefKeyCount(++pref_count); 1630 ASSERT_EQ(1u, service_->extensions()->size()); 1631 const Extension* extension = service_->extensions()->at(0); 1632 const std::string id1 = extension->id(); 1633 EXPECT_TRUE(extension->HasApiPermission( 1634 Extension::kUnlimitedStoragePermission)); 1635 EXPECT_TRUE(extension->web_extent().ContainsURL( 1636 extension->GetFullLaunchURL())); 1637 const GURL origin1(extension->GetFullLaunchURL().GetOrigin()); 1638 EXPECT_EQ(kint64max, 1639 appcache_service->storage()->GetOriginQuotaInMemory(origin1)); 1640 EXPECT_FALSE(service_->unlimited_storage_map_.empty()); 1641 1642 // Install app2 from the same origin with unlimited storage. 1643 PackAndInstallExtension(extensions_path.AppendASCII("app2"), true); 1644 ValidatePrefKeyCount(++pref_count); 1645 ASSERT_EQ(2u, service_->extensions()->size()); 1646 extension = service_->extensions()->at(1); 1647 const std::string id2 = extension->id(); 1648 EXPECT_TRUE(extension->HasApiPermission( 1649 Extension::kUnlimitedStoragePermission)); 1650 EXPECT_TRUE(extension->web_extent().ContainsURL( 1651 extension->GetFullLaunchURL())); 1652 const GURL origin2(extension->GetFullLaunchURL().GetOrigin()); 1653 EXPECT_EQ(origin1, origin2); 1654 EXPECT_EQ(kint64max, 1655 appcache_service->storage()->GetOriginQuotaInMemory(origin2)); 1656 EXPECT_FALSE(service_->unlimited_storage_map_.empty()); 1657 1658 // Uninstall one of them, unlimited storage should still be granted 1659 // to the origin. 1660 service_->UninstallExtension(id1, false); 1661 loop_.RunAllPending(); 1662 EXPECT_EQ(1u, service_->extensions()->size()); 1663 EXPECT_EQ(kint64max, 1664 appcache_service->storage()->GetOriginQuotaInMemory(origin1)); 1665 EXPECT_FALSE(service_->unlimited_storage_map_.empty()); 1666 1667 // Uninstall the other, unlimited storage should be revoked. 1668 service_->UninstallExtension(id2, false); 1669 loop_.RunAllPending(); 1670 EXPECT_EQ(0u, service_->extensions()->size()); 1671 EXPECT_EQ(-1L, 1672 appcache_service->storage()->GetOriginQuotaInMemory(origin2)); 1673 EXPECT_TRUE(service_->unlimited_storage_map_.empty()); 1674} 1675 1676TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) { 1677 InitializeEmptyExtensionService(); 1678 EXPECT_TRUE(service_->extensions()->empty()); 1679 EXPECT_TRUE(service_->protected_storage_map_.empty()); 1680 1681 FilePath extensions_path; 1682 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1683 extensions_path = extensions_path.AppendASCII("extensions"); 1684 int pref_count = 0; 1685 1686 PackAndInstallExtension(extensions_path.AppendASCII("app1"), true); 1687 ValidatePrefKeyCount(++pref_count); 1688 ASSERT_EQ(1u, service_->extensions()->size()); 1689 const Extension* extension = service_->extensions()->at(0); 1690 EXPECT_TRUE(extension->is_app()); 1691 const std::string id1 = extension->id(); 1692 EXPECT_FALSE(service_->protected_storage_map_.empty()); 1693 const GURL origin1(extension->GetFullLaunchURL().GetOrigin()); 1694 ASSERT_EQ(1, service_->protected_storage_map_[origin1]); 1695 1696 // App 4 has a different origin (maps.google.com). 1697 PackAndInstallExtension(extensions_path.AppendASCII("app4"), true); 1698 ValidatePrefKeyCount(++pref_count); 1699 ASSERT_EQ(2u, service_->extensions()->size()); 1700 extension = service_->extensions()->at(1); 1701 const std::string id2 = extension->id(); 1702 EXPECT_FALSE(service_->protected_storage_map_.empty()); 1703 const GURL origin2(extension->GetFullLaunchURL().GetOrigin()); 1704 ASSERT_NE(origin1, origin2); 1705 ASSERT_EQ(1, service_->protected_storage_map_[origin2]); 1706 1707 service_->UninstallExtension(id1, false); 1708 loop_.RunAllPending(); 1709 EXPECT_EQ(1u, service_->extensions()->size()); 1710 EXPECT_FALSE(service_->protected_storage_map_.empty()); 1711 1712 service_->UninstallExtension(id2, false); 1713 loop_.RunAllPending(); 1714 1715 EXPECT_TRUE(service_->extensions()->empty()); 1716 EXPECT_TRUE(service_->protected_storage_map_.empty()); 1717} 1718 1719// Test that when an extension version is reinstalled, nothing happens. 1720TEST_F(ExtensionServiceTest, Reinstall) { 1721 InitializeEmptyExtensionService(); 1722 FilePath extensions_path; 1723 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1724 extensions_path = extensions_path.AppendASCII("extensions"); 1725 1726 // A simple extension that should install without error. 1727 FilePath path = extensions_path.AppendASCII("good.crx"); 1728 service_->InstallExtension(path); 1729 loop_.RunAllPending(); 1730 1731 ASSERT_TRUE(installed_); 1732 ASSERT_EQ(1u, loaded_.size()); 1733 ASSERT_EQ(0u, GetErrors().size()); 1734 ValidatePrefKeyCount(1); 1735 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 1736 ValidateIntegerPref(good_crx, "location", Extension::INTERNAL); 1737 1738 installed_ = NULL; 1739 loaded_.clear(); 1740 ExtensionErrorReporter::GetInstance()->ClearErrors(); 1741 1742 // Reinstall the same version, it should overwrite the previous one. 1743 service_->InstallExtension(path); 1744 loop_.RunAllPending(); 1745 1746 ASSERT_TRUE(installed_); 1747 ASSERT_EQ(1u, loaded_.size()); 1748 ASSERT_EQ(0u, GetErrors().size()); 1749 ValidatePrefKeyCount(1); 1750 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 1751 ValidateIntegerPref(good_crx, "location", Extension::INTERNAL); 1752} 1753 1754// Test upgrading a signed extension. 1755TEST_F(ExtensionServiceTest, UpgradeSignedGood) { 1756 InitializeEmptyExtensionService(); 1757 FilePath extensions_path; 1758 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1759 extensions_path = extensions_path.AppendASCII("extensions"); 1760 1761 FilePath path = extensions_path.AppendASCII("good.crx"); 1762 service_->InstallExtension(path); 1763 loop_.RunAllPending(); 1764 1765 ASSERT_TRUE(installed_); 1766 ASSERT_EQ(1u, loaded_.size()); 1767 ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString()); 1768 ASSERT_EQ(0u, GetErrors().size()); 1769 1770 // Upgrade to version 2.0 1771 path = extensions_path.AppendASCII("good2.crx"); 1772 service_->InstallExtension(path); 1773 loop_.RunAllPending(); 1774 1775 ASSERT_TRUE(installed_); 1776 ASSERT_EQ(1u, loaded_.size()); 1777 ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString()); 1778 ASSERT_EQ(0u, GetErrors().size()); 1779} 1780 1781// Test upgrading a signed extension with a bad signature. 1782TEST_F(ExtensionServiceTest, UpgradeSignedBad) { 1783 InitializeEmptyExtensionService(); 1784 FilePath extensions_path; 1785 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1786 extensions_path = extensions_path.AppendASCII("extensions"); 1787 1788 FilePath path = extensions_path.AppendASCII("good.crx"); 1789 service_->InstallExtension(path); 1790 loop_.RunAllPending(); 1791 1792 ASSERT_TRUE(installed_); 1793 ASSERT_EQ(1u, loaded_.size()); 1794 ASSERT_EQ(0u, GetErrors().size()); 1795 installed_ = NULL; 1796 1797 // Try upgrading with a bad signature. This should fail during the unpack, 1798 // because the key will not match the signature. 1799 path = extensions_path.AppendASCII("good2_bad_signature.crx"); 1800 service_->InstallExtension(path); 1801 loop_.RunAllPending(); 1802 1803 ASSERT_FALSE(installed_); 1804 ASSERT_EQ(1u, loaded_.size()); 1805 ASSERT_EQ(1u, GetErrors().size()); 1806} 1807 1808// Test a normal update via the UpdateExtension API 1809TEST_F(ExtensionServiceTest, UpdateExtension) { 1810 InitializeEmptyExtensionService(); 1811 FilePath extensions_path; 1812 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1813 extensions_path = extensions_path.AppendASCII("extensions"); 1814 1815 FilePath path = extensions_path.AppendASCII("good.crx"); 1816 1817 InstallExtension(path, true); 1818 const Extension* good = service_->extensions()->at(0); 1819 ASSERT_EQ("1.0.0.0", good->VersionString()); 1820 ASSERT_EQ(good_crx, good->id()); 1821 1822 path = extensions_path.AppendASCII("good2.crx"); 1823 UpdateExtension(good_crx, path, ENABLED); 1824 ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString()); 1825} 1826 1827// Test updating a not-already-installed extension - this should fail 1828TEST_F(ExtensionServiceTest, UpdateNotInstalledExtension) { 1829 InitializeEmptyExtensionService(); 1830 FilePath extensions_path; 1831 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1832 extensions_path = extensions_path.AppendASCII("extensions"); 1833 1834 FilePath path = extensions_path.AppendASCII("good.crx"); 1835 UpdateExtension(good_crx, path, UPDATED); 1836 loop_.RunAllPending(); 1837 1838 ASSERT_EQ(0u, service_->extensions()->size()); 1839 ASSERT_FALSE(installed_); 1840 ASSERT_EQ(0u, loaded_.size()); 1841} 1842 1843// Makes sure you can't downgrade an extension via UpdateExtension 1844TEST_F(ExtensionServiceTest, UpdateWillNotDowngrade) { 1845 InitializeEmptyExtensionService(); 1846 FilePath extensions_path; 1847 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1848 extensions_path = extensions_path.AppendASCII("extensions"); 1849 1850 FilePath path = extensions_path.AppendASCII("good2.crx"); 1851 1852 InstallExtension(path, true); 1853 const Extension* good = service_->extensions()->at(0); 1854 ASSERT_EQ("1.0.0.1", good->VersionString()); 1855 ASSERT_EQ(good_crx, good->id()); 1856 1857 // Change path from good2.crx -> good.crx 1858 path = extensions_path.AppendASCII("good.crx"); 1859 UpdateExtension(good_crx, path, FAILED); 1860 ASSERT_EQ("1.0.0.1", service_->extensions()->at(0)->VersionString()); 1861} 1862 1863// Make sure calling update with an identical version does nothing 1864TEST_F(ExtensionServiceTest, UpdateToSameVersionIsNoop) { 1865 InitializeEmptyExtensionService(); 1866 FilePath extensions_path; 1867 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1868 extensions_path = extensions_path.AppendASCII("extensions"); 1869 1870 FilePath path = extensions_path.AppendASCII("good.crx"); 1871 1872 InstallExtension(path, true); 1873 const Extension* good = service_->extensions()->at(0); 1874 ASSERT_EQ(good_crx, good->id()); 1875 UpdateExtension(good_crx, path, FAILED_SILENTLY); 1876} 1877 1878// Tests that updating an extension does not clobber old state. 1879TEST_F(ExtensionServiceTest, UpdateExtensionPreservesState) { 1880 InitializeEmptyExtensionService(); 1881 FilePath extensions_path; 1882 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1883 extensions_path = extensions_path.AppendASCII("extensions"); 1884 1885 FilePath path = extensions_path.AppendASCII("good.crx"); 1886 1887 InstallExtension(path, true); 1888 const Extension* good = service_->extensions()->at(0); 1889 ASSERT_EQ("1.0.0.0", good->VersionString()); 1890 ASSERT_EQ(good_crx, good->id()); 1891 1892 // Disable it and allow it to run in incognito. These settings should carry 1893 // over to the updated version. 1894 service_->DisableExtension(good->id()); 1895 service_->SetIsIncognitoEnabled(good, true); 1896 1897 path = extensions_path.AppendASCII("good2.crx"); 1898 UpdateExtension(good_crx, path, INSTALLED); 1899 ASSERT_EQ(1u, service_->disabled_extensions()->size()); 1900 const Extension* good2 = service_->disabled_extensions()->at(0); 1901 ASSERT_EQ("1.0.0.1", good2->version()->GetString()); 1902 EXPECT_TRUE(service_->IsIncognitoEnabled(good2)); 1903} 1904 1905// Tests that updating preserves extension location. 1906TEST_F(ExtensionServiceTest, UpdateExtensionPreservesLocation) { 1907 InitializeEmptyExtensionService(); 1908 FilePath extensions_path; 1909 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 1910 extensions_path = extensions_path.AppendASCII("extensions"); 1911 1912 FilePath path = extensions_path.AppendASCII("good.crx"); 1913 1914 InstallExtension(path, true); 1915 const Extension* good = service_->extensions()->at(0); 1916 1917 ASSERT_EQ("1.0.0.0", good->VersionString()); 1918 ASSERT_EQ(good_crx, good->id()); 1919 1920 // Simulate non-internal location. 1921 const_cast<Extension*>(good)->location_ = Extension::EXTERNAL_PREF; 1922 1923 path = extensions_path.AppendASCII("good2.crx"); 1924 UpdateExtension(good_crx, path, ENABLED); 1925 const Extension* good2 = service_->extensions()->at(0); 1926 ASSERT_EQ("1.0.0.1", good2->version()->GetString()); 1927 EXPECT_EQ(good2->location(), Extension::EXTERNAL_PREF); 1928} 1929 1930// Makes sure that LOAD extension types can downgrade. 1931TEST_F(ExtensionServiceTest, LoadExtensionsCanDowngrade) { 1932 InitializeEmptyExtensionService(); 1933 1934 ScopedTempDir temp; 1935 ASSERT_TRUE(temp.CreateUniqueTempDir()); 1936 1937 // We'll write the extension manifest dynamically to a temporary path 1938 // to make it easier to change the version number. 1939 FilePath extension_path = temp.path(); 1940 FilePath manifest_path = extension_path.Append(Extension::kManifestFilename); 1941 ASSERT_FALSE(file_util::PathExists(manifest_path)); 1942 1943 // Start with version 2.0. 1944 DictionaryValue manifest; 1945 manifest.SetString("version", "2.0"); 1946 manifest.SetString("name", "LOAD Downgrade Test"); 1947 1948 JSONFileValueSerializer serializer(manifest_path); 1949 ASSERT_TRUE(serializer.Serialize(manifest)); 1950 1951 service_->LoadExtension(extension_path); 1952 loop_.RunAllPending(); 1953 1954 EXPECT_EQ(0u, GetErrors().size()); 1955 ASSERT_EQ(1u, loaded_.size()); 1956 EXPECT_EQ(Extension::LOAD, loaded_[0]->location()); 1957 EXPECT_EQ(1u, service_->extensions()->size()); 1958 EXPECT_EQ("2.0", loaded_[0]->VersionString()); 1959 1960 // Now set the version number to 1.0, reload the extensions and verify that 1961 // the downgrade was accepted. 1962 manifest.SetString("version", "1.0"); 1963 ASSERT_TRUE(serializer.Serialize(manifest)); 1964 1965 service_->LoadExtension(extension_path); 1966 loop_.RunAllPending(); 1967 1968 EXPECT_EQ(0u, GetErrors().size()); 1969 ASSERT_EQ(1u, loaded_.size()); 1970 EXPECT_EQ(Extension::LOAD, loaded_[0]->location()); 1971 EXPECT_EQ(1u, service_->extensions()->size()); 1972 EXPECT_EQ("1.0", loaded_[0]->VersionString()); 1973} 1974 1975namespace { 1976 1977bool IsExtension(const Extension& extension) { 1978 return extension.GetType() == Extension::TYPE_EXTENSION; 1979} 1980 1981} // namespace 1982 1983// Test adding a pending extension. 1984TEST_F(ExtensionServiceTest, AddPendingExtensionFromSync) { 1985 InitializeEmptyExtensionService(); 1986 1987 const std::string kFakeId("fake-id"); 1988 const GURL kFakeUpdateURL("http:://fake.update/url"); 1989 const bool kFakeInstallSilently(true); 1990 const Extension::State kFakeInitialState(Extension::ENABLED); 1991 const bool kFakeInitialIncognitoEnabled(false); 1992 1993 service_->AddPendingExtensionFromSync( 1994 kFakeId, kFakeUpdateURL, &IsExtension, 1995 kFakeInstallSilently, kFakeInitialState, kFakeInitialIncognitoEnabled); 1996 PendingExtensionMap::const_iterator it = 1997 service_->pending_extensions().find(kFakeId); 1998 ASSERT_TRUE(it != service_->pending_extensions().end()); 1999 EXPECT_EQ(kFakeUpdateURL, it->second.update_url); 2000 EXPECT_EQ(&IsExtension, it->second.should_install_extension); 2001 EXPECT_EQ(kFakeInstallSilently, it->second.install_silently); 2002} 2003 2004namespace { 2005const char kGoodId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; 2006const char kGoodUpdateURL[] = "http://good.update/url"; 2007const bool kGoodIsFromSync = true; 2008const bool kGoodInstallSilently = true; 2009const Extension::State kGoodInitialState = Extension::DISABLED; 2010const bool kGoodInitialIncognitoEnabled = true; 2011} // namespace 2012 2013// Test updating a pending extension. 2014TEST_F(ExtensionServiceTest, UpdatePendingExtension) { 2015 InitializeEmptyExtensionService(); 2016 service_->AddPendingExtensionFromSync( 2017 kGoodId, GURL(kGoodUpdateURL), &IsExtension, 2018 kGoodInstallSilently, kGoodInitialState, 2019 kGoodInitialIncognitoEnabled); 2020 EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId)); 2021 2022 FilePath extensions_path; 2023 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2024 extensions_path = extensions_path.AppendASCII("extensions"); 2025 FilePath path = extensions_path.AppendASCII("good.crx"); 2026 UpdateExtension(kGoodId, path, INSTALLED); 2027 2028 EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId)); 2029 2030 const Extension* extension = service_->GetExtensionById(kGoodId, true); 2031 ASSERT_TRUE(extension); 2032 2033 bool enabled = service_->GetExtensionById(kGoodId, false); 2034 EXPECT_EQ(kGoodInitialState == Extension::ENABLED, enabled); 2035 EXPECT_EQ(kGoodInitialState, 2036 service_->extension_prefs()->GetExtensionState(extension->id())); 2037 EXPECT_EQ(kGoodInitialIncognitoEnabled, 2038 service_->IsIncognitoEnabled(extension)); 2039} 2040 2041namespace { 2042 2043bool IsTheme(const Extension& extension) { 2044 return extension.is_theme(); 2045} 2046 2047} // namespace 2048 2049// Test updating a pending theme. 2050TEST_F(ExtensionServiceTest, UpdatePendingTheme) { 2051 InitializeEmptyExtensionService(); 2052 service_->AddPendingExtensionFromSync( 2053 theme_crx, GURL(), &IsTheme, 2054 false, Extension::ENABLED, false); 2055 EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx)); 2056 2057 FilePath extensions_path; 2058 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2059 extensions_path = extensions_path.AppendASCII("extensions"); 2060 FilePath path = extensions_path.AppendASCII("theme.crx"); 2061 UpdateExtension(theme_crx, path, ENABLED); 2062 2063 EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx)); 2064 2065 const Extension* extension = service_->GetExtensionById(theme_crx, true); 2066 ASSERT_TRUE(extension); 2067 2068 EXPECT_EQ(Extension::ENABLED, 2069 service_->extension_prefs()->GetExtensionState(extension->id())); 2070 EXPECT_FALSE(service_->IsIncognitoEnabled(extension)); 2071} 2072 2073// Test updating a pending CRX as if the source is an external extension 2074// with an update URL. In this case we don't know if the CRX is a theme 2075// or not. 2076TEST_F(ExtensionServiceTest, UpdatePendingExternalCrx) { 2077 InitializeEmptyExtensionService(); 2078 service_->AddPendingExtensionFromExternalUpdateUrl( 2079 theme_crx, GURL(), Extension::EXTERNAL_PREF_DOWNLOAD); 2080 2081 EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx)); 2082 2083 FilePath extensions_path; 2084 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2085 extensions_path = extensions_path.AppendASCII("extensions"); 2086 FilePath path = extensions_path.AppendASCII("theme.crx"); 2087 UpdateExtension(theme_crx, path, ENABLED); 2088 2089 EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx)); 2090 2091 const Extension* extension = service_->GetExtensionById(theme_crx, true); 2092 ASSERT_TRUE(extension); 2093 2094 EXPECT_EQ(Extension::ENABLED, 2095 service_->extension_prefs()->GetExtensionState(extension->id())); 2096 EXPECT_FALSE(service_->IsIncognitoEnabled(extension)); 2097} 2098 2099// Test updating a pending CRX as if the source is an external extension 2100// with an update URL. The external update should overwrite a sync update, 2101// but a sync update should not overwrite a non-sync update. 2102TEST_F(ExtensionServiceTest, UpdatePendingExternalCrxWinsOverSync) { 2103 InitializeEmptyExtensionService(); 2104 2105 // Add a crx to be installed from the update mechanism. 2106 service_->AddPendingExtensionFromSync( 2107 kGoodId, GURL(kGoodUpdateURL), &IsExtension, 2108 kGoodInstallSilently, kGoodInitialState, 2109 kGoodInitialIncognitoEnabled); 2110 2111 // Check that there is a pending crx, with is_from_sync set to true. 2112 PendingExtensionMap::const_iterator it; 2113 it = service_->pending_extensions().find(kGoodId); 2114 ASSERT_TRUE(it != service_->pending_extensions().end()); 2115 EXPECT_TRUE(it->second.is_from_sync); 2116 2117 // Add a crx to be updated, with the same ID, from a non-sync source. 2118 service_->AddPendingExtensionFromExternalUpdateUrl( 2119 kGoodId, GURL(kGoodUpdateURL), Extension::EXTERNAL_PREF_DOWNLOAD); 2120 2121 // Check that there is a pending crx, with is_from_sync set to false. 2122 it = service_->pending_extensions().find(kGoodId); 2123 ASSERT_TRUE(it != service_->pending_extensions().end()); 2124 EXPECT_FALSE(it->second.is_from_sync); 2125 2126 // Add a crx to be installed from the update mechanism. 2127 service_->AddPendingExtensionFromSync( 2128 kGoodId, GURL(kGoodUpdateURL), &IsExtension, 2129 kGoodInstallSilently, kGoodInitialState, 2130 kGoodInitialIncognitoEnabled); 2131 2132 // Check that the external, non-sync update was not overridden. 2133 it = service_->pending_extensions().find(kGoodId); 2134 ASSERT_TRUE(it != service_->pending_extensions().end()); 2135 EXPECT_FALSE(it->second.is_from_sync); 2136} 2137 2138// Updating a theme should fail if the updater is explicitly told that 2139// the CRX is not a theme. 2140TEST_F(ExtensionServiceTest, UpdatePendingCrxThemeMismatch) { 2141 InitializeEmptyExtensionService(); 2142 service_->AddPendingExtensionFromSync( 2143 theme_crx, GURL(), &IsExtension, 2144 true, Extension::ENABLED, false); 2145 2146 EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx)); 2147 2148 FilePath extensions_path; 2149 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2150 extensions_path = extensions_path.AppendASCII("extensions"); 2151 FilePath path = extensions_path.AppendASCII("theme.crx"); 2152 UpdateExtension(theme_crx, path, FAILED_SILENTLY); 2153 2154 EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx)); 2155 2156 const Extension* extension = service_->GetExtensionById(theme_crx, true); 2157 ASSERT_FALSE(extension); 2158} 2159 2160// TODO(akalin): Test updating a pending extension non-silently once 2161// we can mock out ExtensionInstallUI and inject our version into 2162// UpdateExtension(). 2163 2164// Test updating a pending extension which fails the should-install test. 2165TEST_F(ExtensionServiceTest, UpdatePendingExtensionFailedShouldInstallTest) { 2166 InitializeEmptyExtensionService(); 2167 // Add pending extension with a flipped is_theme. 2168 service_->AddPendingExtensionFromSync( 2169 kGoodId, GURL(kGoodUpdateURL), &IsTheme, 2170 kGoodInstallSilently, kGoodInitialState, 2171 kGoodInitialIncognitoEnabled); 2172 EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId)); 2173 2174 FilePath extensions_path; 2175 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2176 extensions_path = extensions_path.AppendASCII("extensions"); 2177 FilePath path = extensions_path.AppendASCII("good.crx"); 2178 UpdateExtension(kGoodId, path, UPDATED); 2179 2180 // TODO(akalin): Figure out how to check that the extensions 2181 // directory is cleaned up properly in OnExtensionInstalled(). 2182 2183 EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId)); 2184} 2185 2186// TODO(akalin): Figure out how to test that installs of pending 2187// unsyncable extensions are blocked. 2188 2189// Test updating a pending extension for one that is not pending. 2190TEST_F(ExtensionServiceTest, UpdatePendingExtensionNotPending) { 2191 InitializeEmptyExtensionService(); 2192 2193 FilePath extensions_path; 2194 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2195 extensions_path = extensions_path.AppendASCII("extensions"); 2196 FilePath path = extensions_path.AppendASCII("good.crx"); 2197 UpdateExtension(kGoodId, path, UPDATED); 2198 2199 EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId)); 2200} 2201 2202// Test updating a pending extension for one that is already 2203// installed. 2204TEST_F(ExtensionServiceTest, UpdatePendingExtensionAlreadyInstalled) { 2205 InitializeEmptyExtensionService(); 2206 2207 FilePath extensions_path; 2208 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2209 extensions_path = extensions_path.AppendASCII("extensions"); 2210 FilePath path = extensions_path.AppendASCII("good.crx"); 2211 InstallExtension(path, true); 2212 ASSERT_EQ(1u, service_->extensions()->size()); 2213 const Extension* good = service_->extensions()->at(0); 2214 2215 EXPECT_FALSE(good->is_theme()); 2216 2217 // Use AddPendingExtensionInternal() as AddPendingExtension() would 2218 // balk. 2219 service_->AddPendingExtensionInternal( 2220 good->id(), good->update_url(), &IsExtension, 2221 kGoodIsFromSync, kGoodInstallSilently, kGoodInitialState, 2222 kGoodInitialIncognitoEnabled, Extension::INTERNAL); 2223 UpdateExtension(good->id(), path, INSTALLED); 2224 2225 EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId)); 2226} 2227 2228// Test pref settings for blacklist and unblacklist extensions. 2229TEST_F(ExtensionServiceTest, SetUnsetBlacklistInPrefs) { 2230 InitializeEmptyExtensionService(); 2231 std::vector<std::string> blacklist; 2232 blacklist.push_back(good0); 2233 blacklist.push_back("invalid_id"); // an invalid id 2234 blacklist.push_back(good1); 2235 service_->UpdateExtensionBlacklist(blacklist); 2236 // Make sure pref is updated 2237 loop_.RunAllPending(); 2238 2239 // blacklist is set for good0,1,2 2240 ValidateBooleanPref(good0, "blacklist", true); 2241 ValidateBooleanPref(good1, "blacklist", true); 2242 // invalid_id should not be inserted to pref. 2243 EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist")); 2244 2245 // remove good1, add good2 2246 blacklist.pop_back(); 2247 blacklist.push_back(good2); 2248 2249 service_->UpdateExtensionBlacklist(blacklist); 2250 // only good0 and good1 should be set 2251 ValidateBooleanPref(good0, "blacklist", true); 2252 EXPECT_FALSE(IsPrefExist(good1, "blacklist")); 2253 ValidateBooleanPref(good2, "blacklist", true); 2254 EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist")); 2255} 2256 2257// Unload installed extension from blacklist. 2258TEST_F(ExtensionServiceTest, UnloadBlacklistedExtension) { 2259 InitializeEmptyExtensionService(); 2260 FilePath extensions_path; 2261 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2262 extensions_path = extensions_path.AppendASCII("extensions"); 2263 2264 FilePath path = extensions_path.AppendASCII("good.crx"); 2265 2266 InstallExtension(path, true); 2267 const Extension* good = service_->extensions()->at(0); 2268 EXPECT_EQ(good_crx, good->id()); 2269 UpdateExtension(good_crx, path, FAILED_SILENTLY); 2270 2271 std::vector<std::string> blacklist; 2272 blacklist.push_back(good_crx); 2273 service_->UpdateExtensionBlacklist(blacklist); 2274 // Make sure pref is updated 2275 loop_.RunAllPending(); 2276 2277 // Now, the good_crx is blacklisted. 2278 ValidateBooleanPref(good_crx, "blacklist", true); 2279 EXPECT_EQ(0u, service_->extensions()->size()); 2280 2281 // Remove good_crx from blacklist 2282 blacklist.pop_back(); 2283 service_->UpdateExtensionBlacklist(blacklist); 2284 // Make sure pref is updated 2285 loop_.RunAllPending(); 2286 // blacklist value should not be set for good_crx 2287 EXPECT_FALSE(IsPrefExist(good_crx, "blacklist")); 2288} 2289 2290// Unload installed extension from blacklist. 2291TEST_F(ExtensionServiceTest, BlacklistedExtensionWillNotInstall) { 2292 InitializeEmptyExtensionService(); 2293 std::vector<std::string> blacklist; 2294 blacklist.push_back(good_crx); 2295 service_->UpdateExtensionBlacklist(blacklist); 2296 // Make sure pref is updated 2297 loop_.RunAllPending(); 2298 2299 // Now, the good_crx is blacklisted. 2300 ValidateBooleanPref(good_crx, "blacklist", true); 2301 2302 // We can not install good_crx. 2303 FilePath extensions_path; 2304 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2305 extensions_path = extensions_path.AppendASCII("extensions"); 2306 FilePath path = extensions_path.AppendASCII("good.crx"); 2307 service_->InstallExtension(path); 2308 loop_.RunAllPending(); 2309 EXPECT_EQ(0u, service_->extensions()->size()); 2310 ValidateBooleanPref(good_crx, "blacklist", true); 2311} 2312 2313// Test loading extensions from the profile directory, except 2314// blacklisted ones. 2315TEST_F(ExtensionServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) { 2316 // Initialize the test dir with a good Preferences/extensions. 2317 FilePath source_install_dir; 2318 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); 2319 source_install_dir = source_install_dir 2320 .AppendASCII("extensions") 2321 .AppendASCII("good") 2322 .AppendASCII("Extensions"); 2323 FilePath pref_path = source_install_dir 2324 .DirName() 2325 .AppendASCII("Preferences"); 2326 InitializeInstalledExtensionService(pref_path, source_install_dir); 2327 2328 // Blacklist good1. 2329 std::vector<std::string> blacklist; 2330 blacklist.push_back(good1); 2331 service_->UpdateExtensionBlacklist(blacklist); 2332 // Make sure pref is updated 2333 loop_.RunAllPending(); 2334 2335 ValidateBooleanPref(good1, "blacklist", true); 2336 2337 // Load extensions. 2338 service_->Init(); 2339 loop_.RunAllPending(); 2340 2341 std::vector<std::string> errors = GetErrors(); 2342 for (std::vector<std::string>::iterator err = errors.begin(); 2343 err != errors.end(); ++err) { 2344 LOG(ERROR) << *err; 2345 } 2346 ASSERT_EQ(2u, loaded_.size()); 2347 2348 EXPECT_NE(std::string(good1), loaded_[0]->id()); 2349 EXPECT_NE(std::string(good1), loaded_[1]->id()); 2350} 2351 2352#if defined(OS_CHROMEOS) 2353// Test loading extensions from the profile directory, except 2354// ones with a plugin. 2355TEST_F(ExtensionServiceTest, WillNotLoadPluginExtensionsFromDirectory) { 2356 // Initialize the test dir with a good Preferences/extensions. 2357 FilePath source_install_dir; 2358 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); 2359 source_install_dir = source_install_dir 2360 .AppendASCII("extensions") 2361 .AppendASCII("good") 2362 .AppendASCII("Extensions"); 2363 FilePath pref_path = source_install_dir 2364 .DirName() 2365 .AppendASCII("Preferences"); 2366 InitializeInstalledExtensionService(pref_path, source_install_dir); 2367 2368 // good1 contains a plugin. 2369 // Load extensions. 2370 service_->Init(); 2371 loop_.RunAllPending(); 2372 2373 std::vector<std::string> errors = GetErrors(); 2374 for (std::vector<std::string>::iterator err = errors.begin(); 2375 err != errors.end(); ++err) { 2376 LOG(ERROR) << *err; 2377 } 2378 ASSERT_EQ(2u, loaded_.size()); 2379 2380 EXPECT_NE(std::string(good1), loaded_[0]->id()); 2381 EXPECT_NE(std::string(good1), loaded_[1]->id()); 2382} 2383#endif 2384 2385// Will not install extension blacklisted by policy. 2386TEST_F(ExtensionServiceTest, BlacklistedByPolicyWillNotInstall) { 2387 InitializeEmptyExtensionService(); 2388 2389 ListValue* whitelist = 2390 profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallAllowList); 2391 ListValue* blacklist = 2392 profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallDenyList); 2393 ASSERT_TRUE(whitelist != NULL && blacklist != NULL); 2394 2395 // Blacklist everything. 2396 blacklist->Append(Value::CreateStringValue("*")); 2397 2398 // Blacklist prevents us from installing good_crx. 2399 FilePath extensions_path; 2400 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2401 extensions_path = extensions_path.AppendASCII("extensions"); 2402 FilePath path = extensions_path.AppendASCII("good.crx"); 2403 service_->InstallExtension(path); 2404 loop_.RunAllPending(); 2405 EXPECT_EQ(0u, service_->extensions()->size()); 2406 2407 // Now whitelist this particular extension. 2408 whitelist->Append(Value::CreateStringValue(good_crx)); 2409 2410 // Ensure we can now install good_crx. 2411 service_->InstallExtension(path); 2412 loop_.RunAllPending(); 2413 EXPECT_EQ(1u, service_->extensions()->size()); 2414} 2415 2416// Extension blacklisted by policy get unloaded after installing. 2417TEST_F(ExtensionServiceTest, BlacklistedByPolicyRemovedIfRunning) { 2418 InitializeEmptyExtensionService(); 2419 2420 // Install good_crx. 2421 FilePath extensions_path; 2422 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2423 extensions_path = extensions_path.AppendASCII("extensions"); 2424 FilePath path = extensions_path.AppendASCII("good.crx"); 2425 service_->InstallExtension(path); 2426 loop_.RunAllPending(); 2427 EXPECT_EQ(1u, service_->extensions()->size()); 2428 2429 { // Scope for pref update notification. 2430 PrefService* prefs = profile_->GetPrefs(); 2431 ScopedPrefUpdate pref_update(prefs, prefs::kExtensionInstallDenyList); 2432 ListValue* blacklist = 2433 prefs->GetMutableList(prefs::kExtensionInstallDenyList); 2434 ASSERT_TRUE(blacklist != NULL); 2435 2436 // Blacklist this extension. 2437 blacklist->Append(Value::CreateStringValue(good_crx)); 2438 prefs->ScheduleSavePersistentPrefs(); 2439 } 2440 2441 // Extension should not be running now. 2442 loop_.RunAllPending(); 2443 EXPECT_EQ(0u, service_->extensions()->size()); 2444} 2445 2446// Tests disabling extensions 2447TEST_F(ExtensionServiceTest, DisableExtension) { 2448 InitializeEmptyExtensionService(); 2449 FilePath extensions_path; 2450 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2451 extensions_path = extensions_path.AppendASCII("extensions"); 2452 2453 // A simple extension that should install without error. 2454 FilePath path = extensions_path.AppendASCII("good.crx"); 2455 InstallExtension(path, true); 2456 2457 const char* extension_id = good_crx; 2458 EXPECT_FALSE(service_->extensions()->empty()); 2459 EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL); 2460 EXPECT_TRUE(service_->GetExtensionById(extension_id, false) != NULL); 2461 EXPECT_TRUE(service_->disabled_extensions()->empty()); 2462 2463 // Disable it. 2464 service_->DisableExtension(extension_id); 2465 2466 EXPECT_TRUE(service_->extensions()->empty()); 2467 EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL); 2468 EXPECT_FALSE(service_->GetExtensionById(extension_id, false) != NULL); 2469 EXPECT_FALSE(service_->disabled_extensions()->empty()); 2470} 2471 2472// Tests disabling all extensions (simulating --disable-extensions flag). 2473TEST_F(ExtensionServiceTest, DisableAllExtensions) { 2474 InitializeEmptyExtensionService(); 2475 2476 FilePath extensions_path; 2477 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2478 extensions_path = extensions_path.AppendASCII("extensions"); 2479 2480 FilePath path = extensions_path.AppendASCII("good.crx"); 2481 InstallExtension(path, true); 2482 2483 EXPECT_EQ(1u, service_->extensions()->size()); 2484 EXPECT_EQ(0u, service_->disabled_extensions()->size()); 2485 2486 // Disable extensions. 2487 service_->set_extensions_enabled(false); 2488 service_->ReloadExtensions(); 2489 2490 // There shouldn't be extensions in either list. 2491 EXPECT_EQ(0u, service_->extensions()->size()); 2492 EXPECT_EQ(0u, service_->disabled_extensions()->size()); 2493 2494 // This shouldn't do anything when all extensions are disabled. 2495 service_->EnableExtension(good_crx); 2496 service_->ReloadExtensions(); 2497 2498 // There still shouldn't be extensions in either list. 2499 EXPECT_EQ(0u, service_->extensions()->size()); 2500 EXPECT_EQ(0u, service_->disabled_extensions()->size()); 2501 2502 // And then re-enable the extensions. 2503 service_->set_extensions_enabled(true); 2504 service_->ReloadExtensions(); 2505 2506 EXPECT_EQ(1u, service_->extensions()->size()); 2507 EXPECT_EQ(0u, service_->disabled_extensions()->size()); 2508} 2509 2510// Tests reloading extensions 2511TEST_F(ExtensionServiceTest, ReloadExtensions) { 2512 InitializeEmptyExtensionService(); 2513 FilePath extensions_path; 2514 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2515 extensions_path = extensions_path.AppendASCII("extensions"); 2516 2517 // Simple extension that should install without error. 2518 FilePath path = extensions_path.AppendASCII("good.crx"); 2519 InstallExtension(path, true); 2520 const char* extension_id = good_crx; 2521 service_->DisableExtension(extension_id); 2522 2523 EXPECT_EQ(0u, service_->extensions()->size()); 2524 EXPECT_EQ(1u, service_->disabled_extensions()->size()); 2525 2526 service_->ReloadExtensions(); 2527 2528 // Extension counts shouldn't change. 2529 EXPECT_EQ(0u, service_->extensions()->size()); 2530 EXPECT_EQ(1u, service_->disabled_extensions()->size()); 2531 2532 service_->EnableExtension(extension_id); 2533 2534 EXPECT_EQ(1u, service_->extensions()->size()); 2535 EXPECT_EQ(0u, service_->disabled_extensions()->size()); 2536 2537 // Need to clear |loaded_| manually before reloading as the 2538 // EnableExtension() call above inserted into it and 2539 // UnloadAllExtensions() doesn't send out notifications. 2540 loaded_.clear(); 2541 service_->ReloadExtensions(); 2542 2543 // Extension counts shouldn't change. 2544 EXPECT_EQ(1u, service_->extensions()->size()); 2545 EXPECT_EQ(0u, service_->disabled_extensions()->size()); 2546} 2547 2548// Tests uninstalling normal extensions 2549TEST_F(ExtensionServiceTest, UninstallExtension) { 2550 InitializeEmptyExtensionService(); 2551 FilePath extensions_path; 2552 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2553 extensions_path = extensions_path.AppendASCII("extensions"); 2554 2555 // A simple extension that should install without error. 2556 FilePath path = extensions_path.AppendASCII("good.crx"); 2557 InstallExtension(path, true); 2558 2559 // The directory should be there now. 2560 const char* extension_id = good_crx; 2561 FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id); 2562 EXPECT_TRUE(file_util::PathExists(extension_path)); 2563 2564 ValidatePrefKeyCount(1); 2565 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 2566 ValidateIntegerPref(good_crx, "location", Extension::INTERNAL); 2567 2568 // Uninstall it. 2569 service_->UninstallExtension(extension_id, false); 2570 total_successes_ = 0; 2571 2572 // We should get an unload notification. 2573 ASSERT_TRUE(unloaded_id_.length()); 2574 EXPECT_EQ(extension_id, unloaded_id_); 2575 2576 ValidatePrefKeyCount(0); 2577 2578 // The extension should not be in the service anymore. 2579 ASSERT_FALSE(service_->GetExtensionById(extension_id, false)); 2580 loop_.RunAllPending(); 2581 2582 // The directory should be gone. 2583 EXPECT_FALSE(file_util::PathExists(extension_path)); 2584} 2585 2586// Tests the uninstaller helper. 2587TEST_F(ExtensionServiceTest, UninstallExtensionHelper) { 2588 InitializeEmptyExtensionService(); 2589 FilePath extensions_path; 2590 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2591 extensions_path = extensions_path.AppendASCII("extensions"); 2592 2593 // A simple extension that should install without error. 2594 FilePath path = extensions_path.AppendASCII("good.crx"); 2595 InstallExtension(path, true); 2596 2597 // The directory should be there now. 2598 const char* extension_id = good_crx; 2599 FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id); 2600 EXPECT_TRUE(file_util::PathExists(extension_path)); 2601 2602 bool result = ExtensionService::UninstallExtensionHelper(service_, 2603 extension_id); 2604 total_successes_ = 0; 2605 2606 EXPECT_TRUE(result); 2607 2608 // We should get an unload notification. 2609 ASSERT_TRUE(unloaded_id_.length()); 2610 EXPECT_EQ(extension_id, unloaded_id_); 2611 2612 ValidatePrefKeyCount(0); 2613 2614 // The extension should not be in the service anymore. 2615 ASSERT_FALSE(service_->GetExtensionById(extension_id, false)); 2616 loop_.RunAllPending(); 2617 2618 // The directory should be gone. 2619 EXPECT_FALSE(file_util::PathExists(extension_path)); 2620 2621 // Attempt to uninstall again. This should fail as we just removed the 2622 // extension. 2623 result = ExtensionService::UninstallExtensionHelper(service_, extension_id); 2624 EXPECT_FALSE(result); 2625} 2626 2627// Verifies extension state is removed upon uninstall 2628TEST_F(ExtensionServiceTest, ClearExtensionData) { 2629 InitializeEmptyExtensionService(); 2630 2631 // Load a test extension. 2632 FilePath path; 2633 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 2634 path = path.AppendASCII("extensions"); 2635 path = path.AppendASCII("good.crx"); 2636 InstallExtension(path, true); 2637 const Extension* extension = service_->GetExtensionById(good_crx, false); 2638 ASSERT_TRUE(extension); 2639 GURL ext_url(extension->url()); 2640 string16 origin_id = 2641 webkit_database::DatabaseUtil::GetOriginIdentifier(ext_url); 2642 2643 // Set a cookie for the extension. 2644 net::CookieMonster* cookie_monster = profile_ 2645 ->GetRequestContextForExtensions()->GetCookieStore()->GetCookieMonster(); 2646 ASSERT_TRUE(cookie_monster); 2647 net::CookieOptions options; 2648 cookie_monster->SetCookieWithOptions(ext_url, "dummy=value", options); 2649 net::CookieList list = cookie_monster->GetAllCookiesForURL(ext_url); 2650 EXPECT_EQ(1U, list.size()); 2651 2652 // Open a database. 2653 webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker(); 2654 string16 db_name = UTF8ToUTF16("db"); 2655 string16 description = UTF8ToUTF16("db_description"); 2656 int64 size; 2657 int64 available; 2658 db_tracker->DatabaseOpened(origin_id, db_name, description, 1, &size, 2659 &available); 2660 db_tracker->DatabaseClosed(origin_id, db_name); 2661 std::vector<webkit_database::OriginInfo> origins; 2662 db_tracker->GetAllOriginsInfo(&origins); 2663 EXPECT_EQ(1U, origins.size()); 2664 EXPECT_EQ(origin_id, origins[0].GetOrigin()); 2665 2666 // Create local storage. We only simulate this by creating the backing file 2667 // since webkit is not initialized. 2668 DOMStorageContext* context = 2669 profile_->GetWebKitContext()->dom_storage_context(); 2670 FilePath lso_path = context->GetLocalStorageFilePath(origin_id); 2671 EXPECT_TRUE(file_util::CreateDirectory(lso_path.DirName())); 2672 EXPECT_EQ(0, file_util::WriteFile(lso_path, NULL, 0)); 2673 EXPECT_TRUE(file_util::PathExists(lso_path)); 2674 2675 // Create indexed db. Again, it is enough to only simulate this by creating 2676 // the file on the disk. 2677 IndexedDBContext* idb_context = 2678 profile_->GetWebKitContext()->indexed_db_context(); 2679 FilePath idb_path = idb_context->GetIndexedDBFilePath(origin_id); 2680 EXPECT_TRUE(file_util::CreateDirectory(idb_path.DirName())); 2681 EXPECT_EQ(0, file_util::WriteFile(idb_path, NULL, 0)); 2682 EXPECT_TRUE(file_util::PathExists(idb_path)); 2683 2684 // Uninstall the extension. 2685 service_->UninstallExtension(good_crx, false); 2686 loop_.RunAllPending(); 2687 2688 // Check that the cookie is gone. 2689 list = cookie_monster->GetAllCookiesForURL(ext_url); 2690 EXPECT_EQ(0U, list.size()); 2691 2692 // The database should have vanished as well. 2693 origins.clear(); 2694 db_tracker->GetAllOriginsInfo(&origins); 2695 EXPECT_EQ(0U, origins.size()); 2696 2697 // Check that the LSO file has been removed. 2698 EXPECT_FALSE(file_util::PathExists(lso_path)); 2699 2700 // Check if the indexed db has disappeared too. 2701 EXPECT_FALSE(file_util::PathExists(idb_path)); 2702} 2703 2704// Tests loading single extensions (like --load-extension) 2705TEST_F(ExtensionServiceTest, LoadExtension) { 2706 InitializeEmptyExtensionService(); 2707 FilePath extensions_path; 2708 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2709 extensions_path = extensions_path.AppendASCII("extensions"); 2710 2711 FilePath ext1 = extensions_path 2712 .AppendASCII("good") 2713 .AppendASCII("Extensions") 2714 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 2715 .AppendASCII("1.0.0.0"); 2716 service_->LoadExtension(ext1); 2717 loop_.RunAllPending(); 2718 EXPECT_EQ(0u, GetErrors().size()); 2719 ASSERT_EQ(1u, loaded_.size()); 2720 EXPECT_EQ(Extension::LOAD, loaded_[0]->location()); 2721 EXPECT_EQ(1u, service_->extensions()->size()); 2722 2723 ValidatePrefKeyCount(1); 2724 2725 FilePath no_manifest = extensions_path 2726 .AppendASCII("bad") 2727 // .AppendASCII("Extensions") 2728 .AppendASCII("cccccccccccccccccccccccccccccccc") 2729 .AppendASCII("1"); 2730 service_->LoadExtension(no_manifest); 2731 loop_.RunAllPending(); 2732 EXPECT_EQ(1u, GetErrors().size()); 2733 ASSERT_EQ(1u, loaded_.size()); 2734 EXPECT_EQ(1u, service_->extensions()->size()); 2735 2736 // Test uninstall. 2737 std::string id = loaded_[0]->id(); 2738 EXPECT_FALSE(unloaded_id_.length()); 2739 service_->UninstallExtension(id, false); 2740 loop_.RunAllPending(); 2741 EXPECT_EQ(id, unloaded_id_); 2742 ASSERT_EQ(0u, loaded_.size()); 2743 EXPECT_EQ(0u, service_->extensions()->size()); 2744} 2745 2746// Tests that we generate IDs when they are not specified in the manifest for 2747// --load-extension. 2748TEST_F(ExtensionServiceTest, GenerateID) { 2749 InitializeEmptyExtensionService(); 2750 2751 FilePath extensions_path; 2752 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 2753 extensions_path = extensions_path.AppendASCII("extensions"); 2754 2755 FilePath no_id_ext = extensions_path.AppendASCII("no_id"); 2756 service_->LoadExtension(no_id_ext); 2757 loop_.RunAllPending(); 2758 EXPECT_EQ(0u, GetErrors().size()); 2759 ASSERT_EQ(1u, loaded_.size()); 2760 ASSERT_TRUE(Extension::IdIsValid(loaded_[0]->id())); 2761 EXPECT_EQ(loaded_[0]->location(), Extension::LOAD); 2762 2763 ValidatePrefKeyCount(1); 2764 2765 std::string previous_id = loaded_[0]->id(); 2766 2767 // If we reload the same path, we should get the same extension ID. 2768 service_->LoadExtension(no_id_ext); 2769 loop_.RunAllPending(); 2770 ASSERT_EQ(1u, loaded_.size()); 2771 ASSERT_EQ(previous_id, loaded_[0]->id()); 2772} 2773 2774void ExtensionServiceTest::TestExternalProvider( 2775 MockExtensionProvider* provider, Extension::Location location) { 2776 // Verify that starting with no providers loads no extensions. 2777 service_->Init(); 2778 loop_.RunAllPending(); 2779 ASSERT_EQ(0u, loaded_.size()); 2780 2781 provider->set_visit_count(0); 2782 2783 // Register a test extension externally using the mock registry provider. 2784 FilePath source_path; 2785 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path)); 2786 source_path = source_path.AppendASCII("extensions").AppendASCII("good.crx"); 2787 2788 // Add the extension. 2789 provider->UpdateOrAddExtension(good_crx, "1.0.0.0", source_path); 2790 2791 // Reloading extensions should find our externally registered extension 2792 // and install it. 2793 service_->CheckForExternalUpdates(); 2794 loop_.RunAllPending(); 2795 2796 ASSERT_EQ(0u, GetErrors().size()); 2797 ASSERT_EQ(1u, loaded_.size()); 2798 ASSERT_EQ(location, loaded_[0]->location()); 2799 ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString()); 2800 ValidatePrefKeyCount(1); 2801 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 2802 ValidateIntegerPref(good_crx, "location", location); 2803 2804 // Reload extensions without changing anything. The extension should be 2805 // loaded again. 2806 loaded_.clear(); 2807 service_->ReloadExtensions(); 2808 loop_.RunAllPending(); 2809 ASSERT_EQ(0u, GetErrors().size()); 2810 ASSERT_EQ(1u, loaded_.size()); 2811 ValidatePrefKeyCount(1); 2812 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 2813 ValidateIntegerPref(good_crx, "location", location); 2814 2815 // Now update the extension with a new version. We should get upgraded. 2816 source_path = source_path.DirName().AppendASCII("good2.crx"); 2817 provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path); 2818 2819 loaded_.clear(); 2820 service_->CheckForExternalUpdates(); 2821 loop_.RunAllPending(); 2822 ASSERT_EQ(0u, GetErrors().size()); 2823 ASSERT_EQ(1u, loaded_.size()); 2824 ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString()); 2825 ValidatePrefKeyCount(1); 2826 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 2827 ValidateIntegerPref(good_crx, "location", location); 2828 2829 // Uninstall the extension and reload. Nothing should happen because the 2830 // preference should prevent us from reinstalling. 2831 std::string id = loaded_[0]->id(); 2832 service_->UninstallExtension(id, false); 2833 loop_.RunAllPending(); 2834 2835 // The extension should also be gone from the install directory. 2836 FilePath install_path = extensions_install_dir_.AppendASCII(id); 2837 ASSERT_FALSE(file_util::PathExists(install_path)); 2838 2839 loaded_.clear(); 2840 service_->CheckForExternalUpdates(); 2841 loop_.RunAllPending(); 2842 ASSERT_EQ(0u, loaded_.size()); 2843 ValidatePrefKeyCount(1); 2844 ValidateIntegerPref(good_crx, "state", Extension::KILLBIT); 2845 ValidateIntegerPref(good_crx, "location", location); 2846 2847 // Now clear the preference and reinstall. 2848 SetPrefInteg(good_crx, "state", Extension::ENABLED); 2849 profile_->GetPrefs()->ScheduleSavePersistentPrefs(); 2850 2851 loaded_.clear(); 2852 service_->CheckForExternalUpdates(); 2853 loop_.RunAllPending(); 2854 ASSERT_EQ(1u, loaded_.size()); 2855 ValidatePrefKeyCount(1); 2856 ValidateIntegerPref(good_crx, "state", Extension::ENABLED); 2857 ValidateIntegerPref(good_crx, "location", location); 2858 2859 // Now test an externally triggered uninstall (deleting the registry key or 2860 // the pref entry). 2861 provider->RemoveExtension(good_crx); 2862 2863 loaded_.clear(); 2864 service_->UnloadAllExtensions(); 2865 service_->LoadAllExtensions(); 2866 loop_.RunAllPending(); 2867 ASSERT_EQ(0u, loaded_.size()); 2868 ValidatePrefKeyCount(0); 2869 2870 // The extension should also be gone from the install directory. 2871 ASSERT_FALSE(file_util::PathExists(install_path)); 2872 2873 // Now test the case where user uninstalls and then the extension is removed 2874 // from the external provider. 2875 2876 provider->UpdateOrAddExtension(good_crx, "1.0", source_path); 2877 service_->CheckForExternalUpdates(); 2878 loop_.RunAllPending(); 2879 2880 ASSERT_EQ(1u, loaded_.size()); 2881 ASSERT_EQ(0u, GetErrors().size()); 2882 2883 // User uninstalls. 2884 loaded_.clear(); 2885 service_->UninstallExtension(id, false); 2886 loop_.RunAllPending(); 2887 ASSERT_EQ(0u, loaded_.size()); 2888 2889 // Then remove the extension from the extension provider. 2890 provider->RemoveExtension(good_crx); 2891 2892 // Should still be at 0. 2893 loaded_.clear(); 2894 service_->LoadAllExtensions(); 2895 loop_.RunAllPending(); 2896 ASSERT_EQ(0u, loaded_.size()); 2897 ValidatePrefKeyCount(1); 2898 2899 EXPECT_EQ(5, provider->visit_count()); 2900} 2901 2902// Tests the external installation feature 2903#if defined(OS_WIN) 2904TEST_F(ExtensionServiceTest, ExternalInstallRegistry) { 2905 // This should all work, even when normal extension installation is disabled. 2906 InitializeEmptyExtensionService(); 2907 set_extensions_enabled(false); 2908 2909 // Now add providers. Extension system takes ownership of the objects. 2910 MockExtensionProvider* reg_provider = 2911 new MockExtensionProvider(Extension::EXTERNAL_REGISTRY); 2912 AddMockExternalProvider(reg_provider); 2913 TestExternalProvider(reg_provider, Extension::EXTERNAL_REGISTRY); 2914} 2915#endif 2916 2917TEST_F(ExtensionServiceTest, ExternalInstallPref) { 2918 InitializeEmptyExtensionService(); 2919 2920 // Now add providers. Extension system takes ownership of the objects. 2921 MockExtensionProvider* pref_provider = 2922 new MockExtensionProvider(Extension::EXTERNAL_PREF); 2923 2924 AddMockExternalProvider(pref_provider); 2925 TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF); 2926} 2927 2928TEST_F(ExtensionServiceTest, ExternalInstallPrefUpdateUrl) { 2929 // This should all work, even when normal extension installation is disabled. 2930 InitializeEmptyExtensionService(); 2931 set_extensions_enabled(false); 2932 2933 // TODO(skerner): The mock provider is not a good model of a provider 2934 // that works with update URLs, because it adds file and version info. 2935 // Extend the mock to work with update URLs. This test checks the 2936 // behavior that is common to all external extension visitors. The 2937 // browser test ExtensionManagementTest.ExternalUrlUpdate tests that 2938 // what the visitor does results in an extension being downloaded and 2939 // installed. 2940 MockExtensionProvider* pref_provider = 2941 new MockExtensionProvider(Extension::EXTERNAL_PREF_DOWNLOAD); 2942 AddMockExternalProvider(pref_provider); 2943 TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF_DOWNLOAD); 2944} 2945 2946// Tests that external extensions get uninstalled when the external extension 2947// providers can't account for them. 2948TEST_F(ExtensionServiceTest, ExternalUninstall) { 2949 // Start the extensions service with one external extension already installed. 2950 FilePath source_install_dir; 2951 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); 2952 source_install_dir = source_install_dir 2953 .AppendASCII("extensions") 2954 .AppendASCII("good") 2955 .AppendASCII("Extensions"); 2956 FilePath pref_path = source_install_dir 2957 .DirName() 2958 .AppendASCII("PreferencesExternal"); 2959 2960 // This initializes the extensions service with no ExternalExtensionProviders. 2961 InitializeInstalledExtensionService(pref_path, source_install_dir); 2962 set_extensions_enabled(false); 2963 2964 service_->Init(); 2965 loop_.RunAllPending(); 2966 2967 ASSERT_EQ(0u, GetErrors().size()); 2968 ASSERT_EQ(0u, loaded_.size()); 2969 2970 // Verify that it's not the disabled extensions flag causing it not to load. 2971 set_extensions_enabled(true); 2972 service_->ReloadExtensions(); 2973 loop_.RunAllPending(); 2974 2975 ASSERT_EQ(0u, GetErrors().size()); 2976 ASSERT_EQ(0u, loaded_.size()); 2977} 2978 2979TEST_F(ExtensionServiceTest, ExternalPrefProvider) { 2980 InitializeEmptyExtensionService(); 2981 std::string json_data = 2982 "{" 2983 " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {" 2984 " \"external_crx\": \"RandomExtension.crx\"," 2985 " \"external_version\": \"1.0\"" 2986 " }," 2987 " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {" 2988 " \"external_crx\": \"RandomExtension2.crx\"," 2989 " \"external_version\": \"2.0\"" 2990 " }," 2991 " \"cccccccccccccccccccccccccccccccc\": {" 2992 " \"external_update_url\": \"http:\\\\foo.com/update\"" 2993 " }" 2994 "}"; 2995 2996 MockProviderVisitor visitor; 2997 2998 // Simulate an external_extensions.json file that contains seven invalid 2999 // extensions: 3000 // - One that is missing the 'external_crx' key. 3001 // - One that is missing the 'external_version' key. 3002 // - One that is specifying .. in the path. 3003 // - One that specifies both a file and update URL. 3004 // - One that specifies no file or update URL. 3005 // - One that has an update URL that is not well formed. 3006 // - One that contains a malformed version. 3007 // The final extension is valid, and we check that it is read to make sure 3008 // failures don't stop valid records from being read. 3009 json_data = 3010 "{" 3011 " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {" 3012 " \"external_version\": \"1.0\"" 3013 " }," 3014 " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {" 3015 " \"external_crx\": \"RandomExtension.crx\"" 3016 " }," 3017 " \"cccccccccccccccccccccccccccccccc\": {" 3018 " \"external_crx\": \"..\\\\foo\\\\RandomExtension2.crx\"," 3019 " \"external_version\": \"2.0\"" 3020 " }," 3021 " \"dddddddddddddddddddddddddddddddd\": {" 3022 " \"external_crx\": \"RandomExtension2.crx\"," 3023 " \"external_version\": \"2.0\"," 3024 " \"external_update_url\": \"http:\\\\foo.com/update\"" 3025 " }," 3026 " \"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\": {" 3027 " }," 3028 " \"ffffffffffffffffffffffffffffffff\": {" 3029 " \"external_update_url\": \"This string is not a valid URL\"" 3030 " }," 3031 " \"gggggggggggggggggggggggggggggggg\": {" 3032 " \"external_crx\": \"RandomExtension3.crx\"," 3033 " \"external_version\": \"This is not a valid version!\"" 3034 " }," 3035 " \"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\": {" 3036 " \"external_crx\": \"RandomValidExtension.crx\"," 3037 " \"external_version\": \"1.0\"" 3038 " }" 3039 "}"; 3040 EXPECT_EQ(1, visitor.Visit(json_data)); 3041} 3042 3043// Test loading good extensions from the profile directory. 3044TEST_F(ExtensionServiceTest, LoadAndRelocalizeExtensions) { 3045 // Initialize the test dir with a good Preferences/extensions. 3046 FilePath source_install_dir; 3047 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir)); 3048 source_install_dir = source_install_dir 3049 .AppendASCII("extensions") 3050 .AppendASCII("l10n"); 3051 FilePath pref_path = source_install_dir.AppendASCII("Preferences"); 3052 InitializeInstalledExtensionService(pref_path, source_install_dir); 3053 3054 service_->Init(); 3055 loop_.RunAllPending(); 3056 3057 ASSERT_EQ(3u, loaded_.size()); 3058 3059 // This was equal to "sr" on load. 3060 ValidateStringPref(loaded_[0]->id(), keys::kCurrentLocale, "en"); 3061 3062 // These are untouched by re-localization. 3063 ValidateStringPref(loaded_[1]->id(), keys::kCurrentLocale, "en"); 3064 EXPECT_FALSE(IsPrefExist(loaded_[1]->id(), keys::kCurrentLocale)); 3065 3066 // This one starts with Serbian name, and gets re-localized into English. 3067 EXPECT_EQ("My name is simple.", loaded_[0]->name()); 3068 3069 // These are untouched by re-localization. 3070 EXPECT_EQ("My name is simple.", loaded_[1]->name()); 3071 EXPECT_EQ("no l10n", loaded_[2]->name()); 3072} 3073 3074class ExtensionsReadyRecorder : public NotificationObserver { 3075 public: 3076 ExtensionsReadyRecorder() : ready_(false) { 3077 registrar_.Add(this, NotificationType::EXTENSIONS_READY, 3078 NotificationService::AllSources()); 3079 } 3080 3081 void set_ready(bool value) { ready_ = value; } 3082 bool ready() { return ready_; } 3083 3084 private: 3085 virtual void Observe(NotificationType type, 3086 const NotificationSource& source, 3087 const NotificationDetails& details) { 3088 switch (type.value) { 3089 case NotificationType::EXTENSIONS_READY: 3090 ready_ = true; 3091 break; 3092 default: 3093 NOTREACHED(); 3094 } 3095 } 3096 3097 NotificationRegistrar registrar_; 3098 bool ready_; 3099}; 3100 3101// Test that we get enabled/disabled correctly for all the pref/command-line 3102// combinations. We don't want to derive from the ExtensionServiceTest class 3103// for this test, so we use ExtensionServiceTestSimple. 3104// 3105// Also tests that we always fire EXTENSIONS_READY, no matter whether we are 3106// enabled or not. 3107TEST(ExtensionServiceTestSimple, Enabledness) { 3108 ExtensionsReadyRecorder recorder; 3109 scoped_ptr<TestingProfile> profile(new TestingProfile()); 3110 MessageLoop loop; 3111 BrowserThread ui_thread(BrowserThread::UI, &loop); 3112 BrowserThread file_thread(BrowserThread::FILE, &loop); 3113 scoped_ptr<CommandLine> command_line; 3114 scoped_refptr<ExtensionService> service; 3115 FilePath install_dir = profile->GetPath() 3116 .AppendASCII(ExtensionService::kInstallDirectoryName); 3117 3118 // By default, we are enabled. 3119 command_line.reset(new CommandLine(CommandLine::NO_PROGRAM)); 3120 service = profile->CreateExtensionService(command_line.get(), 3121 install_dir); 3122 EXPECT_TRUE(service->extensions_enabled()); 3123 service->Init(); 3124 loop.RunAllPending(); 3125 EXPECT_TRUE(recorder.ready()); 3126 3127 // If either the command line or pref is set, we are disabled. 3128 recorder.set_ready(false); 3129 profile.reset(new TestingProfile()); 3130 command_line->AppendSwitch(switches::kDisableExtensions); 3131 service = profile->CreateExtensionService(command_line.get(), 3132 install_dir); 3133 EXPECT_FALSE(service->extensions_enabled()); 3134 service->Init(); 3135 loop.RunAllPending(); 3136 EXPECT_TRUE(recorder.ready()); 3137 3138 recorder.set_ready(false); 3139 profile.reset(new TestingProfile()); 3140 profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true); 3141 service = profile->CreateExtensionService(command_line.get(), 3142 install_dir); 3143 EXPECT_FALSE(service->extensions_enabled()); 3144 service->Init(); 3145 loop.RunAllPending(); 3146 EXPECT_TRUE(recorder.ready()); 3147 3148 recorder.set_ready(false); 3149 profile.reset(new TestingProfile()); 3150 profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true); 3151 command_line.reset(new CommandLine(CommandLine::NO_PROGRAM)); 3152 service = profile->CreateExtensionService(command_line.get(), 3153 install_dir); 3154 EXPECT_FALSE(service->extensions_enabled()); 3155 service->Init(); 3156 loop.RunAllPending(); 3157 EXPECT_TRUE(recorder.ready()); 3158 3159 // Explicitly delete all the resources used in this test. 3160 profile.reset(); 3161 service = NULL; 3162} 3163 3164// Test loading extensions that require limited and unlimited storage quotas. 3165TEST_F(ExtensionServiceTest, StorageQuota) { 3166 InitializeEmptyExtensionService(); 3167 3168 FilePath extensions_path; 3169 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 3170 extensions_path = extensions_path.AppendASCII("extensions") 3171 .AppendASCII("storage_quota"); 3172 3173 FilePath limited_quota_ext = extensions_path.AppendASCII("limited_quota") 3174 .AppendASCII("1.0"); 3175 3176 // The old permission name for unlimited quota was "unlimited_storage", but 3177 // we changed it to "unlimitedStorage". This tests both versions. 3178 FilePath unlimited_quota_ext = extensions_path.AppendASCII("unlimited_quota") 3179 .AppendASCII("1.0"); 3180 FilePath unlimited_quota_ext2 = extensions_path.AppendASCII("unlimited_quota") 3181 .AppendASCII("2.0"); 3182 service_->LoadExtension(limited_quota_ext); 3183 service_->LoadExtension(unlimited_quota_ext); 3184 service_->LoadExtension(unlimited_quota_ext2); 3185 loop_.RunAllPending(); 3186 3187 ASSERT_EQ(3u, loaded_.size()); 3188 EXPECT_TRUE(profile_.get()); 3189 EXPECT_FALSE(profile_->IsOffTheRecord()); 3190 3191 // Open the database from each origin to make the tracker aware 3192 // of the existence of these origins and to get their quotas. 3193 int64 limited_quota = -1; 3194 int64 unlimited_quota = -1; 3195 string16 limited_quota_identifier = 3196 webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[0]->url()); 3197 string16 unlimited_quota_identifier = 3198 webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[1]->url()); 3199 string16 unlimited_quota_identifier2 = 3200 webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[2]->url()); 3201 string16 db_name = UTF8ToUTF16("db"); 3202 string16 description = UTF8ToUTF16("db_description"); 3203 int64 database_size; 3204 webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker(); 3205 3206 // First check the normal limited quota extension. 3207 db_tracker->DatabaseOpened(limited_quota_identifier, db_name, description, 3208 1, &database_size, &limited_quota); 3209 db_tracker->DatabaseClosed(limited_quota_identifier, db_name); 3210 EXPECT_EQ(profile_->GetDatabaseTracker()->GetDefaultQuota(), limited_quota); 3211 3212 // Now check the two unlimited quota ones. 3213 db_tracker->DatabaseOpened(unlimited_quota_identifier, db_name, description, 3214 1, &database_size, &unlimited_quota); 3215 db_tracker->DatabaseClosed(unlimited_quota_identifier, db_name); 3216 EXPECT_EQ(kint64max, unlimited_quota); 3217 db_tracker->DatabaseOpened(unlimited_quota_identifier2, db_name, description, 3218 1, &database_size, &unlimited_quota); 3219 db_tracker->DatabaseClosed(unlimited_quota_identifier2, db_name); 3220 3221 EXPECT_EQ(kint64max, unlimited_quota); 3222} 3223 3224// Tests ExtensionService::register_component_extension(). 3225TEST_F(ExtensionServiceTest, ComponentExtensions) { 3226 InitializeEmptyExtensionService(); 3227 3228 // Component extensions should work even when extensions are disabled. 3229 set_extensions_enabled(false); 3230 3231 FilePath path; 3232 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 3233 path = path.AppendASCII("extensions") 3234 .AppendASCII("good") 3235 .AppendASCII("Extensions") 3236 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 3237 .AppendASCII("1.0.0.0"); 3238 3239 std::string manifest; 3240 ASSERT_TRUE(file_util::ReadFileToString( 3241 path.Append(Extension::kManifestFilename), &manifest)); 3242 3243 service_->register_component_extension( 3244 ExtensionService::ComponentExtensionInfo(manifest, path)); 3245 service_->Init(); 3246 3247 // Note that we do not pump messages -- the extension should be loaded 3248 // immediately. 3249 3250 EXPECT_EQ(0u, GetErrors().size()); 3251 ASSERT_EQ(1u, loaded_.size()); 3252 EXPECT_EQ(Extension::COMPONENT, loaded_[0]->location()); 3253 EXPECT_EQ(1u, service_->extensions()->size()); 3254 3255 // Component extensions shouldn't get recourded in the prefs. 3256 ValidatePrefKeyCount(0); 3257 3258 // Reload all extensions, and make sure it comes back. 3259 std::string extension_id = service_->extensions()->at(0)->id(); 3260 loaded_.clear(); 3261 service_->ReloadExtensions(); 3262 ASSERT_EQ(1u, service_->extensions()->size()); 3263 EXPECT_EQ(extension_id, service_->extensions()->at(0)->id()); 3264} 3265