1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/at_exit.h" 6 #include "base/memory/ref_counted.h" 7 #include "chrome/browser/download/download_crx_util.h" 8 #include "chrome/browser/extensions/browser_action_test_util.h" 9 #include "chrome/browser/extensions/crx_installer.h" 10 #include "chrome/browser/extensions/extension_browsertest.h" 11 #include "chrome/browser/extensions/extension_install_prompt.h" 12 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_util.h" 14 #include "chrome/browser/extensions/fake_safe_browsing_database_manager.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/ui/browser.h" 17 #include "chrome/browser/ui/browser_window.h" 18 #include "chrome/browser/ui/tabs/tab_strip_model.h" 19 #include "chrome/test/base/ui_test_utils.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/download_manager.h" 22 #include "content/public/browser/render_view_host.h" 23 #include "content/public/test/browser_test_utils.h" 24 #include "content/public/test/download_test_observer.h" 25 #include "extensions/browser/extension_prefs.h" 26 #include "extensions/browser/extension_system.h" 27 #include "extensions/common/extension.h" 28 #include "extensions/common/feature_switch.h" 29 #include "extensions/common/file_util.h" 30 #include "extensions/common/permissions/permission_set.h" 31 #include "extensions/common/switches.h" 32 #include "grit/generated_resources.h" 33 #include "ui/base/l10n/l10n_util.h" 34 35 #if defined(OS_CHROMEOS) 36 #include "chrome/browser/chromeos/login/users/fake_user_manager.h" 37 #include "chrome/browser/chromeos/login/users/user_manager.h" 38 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h" 39 #include "chromeos/chromeos_switches.h" 40 #endif 41 42 class SkBitmap; 43 44 namespace extensions { 45 46 namespace { 47 48 class MockInstallPrompt; 49 50 // This class holds information about things that happen with a 51 // MockInstallPrompt. We create the MockInstallPrompt but need to pass 52 // ownership of it to CrxInstaller, so it isn't safe to hang this data on 53 // MockInstallPrompt itself becuase we can't guarantee it's lifetime. 54 class MockPromptProxy : public base::RefCountedThreadSafe<MockPromptProxy> { 55 public: 56 explicit MockPromptProxy(content::WebContents* web_contents); 57 58 bool did_succeed() const { return !extension_id_.empty(); } 59 const std::string& extension_id() { return extension_id_; } 60 bool confirmation_requested() const { return confirmation_requested_; } 61 const base::string16& error() const { return error_; } 62 63 // To have any effect, this should be called before CreatePrompt. 64 void set_record_oauth2_grant(bool record_oauth2_grant) { 65 record_oauth2_grant_.reset(new bool(record_oauth2_grant)); 66 } 67 68 void set_extension_id(const std::string& id) { extension_id_ = id; } 69 void set_confirmation_requested() { confirmation_requested_ = true; } 70 void set_error(const base::string16& error) { error_ = error; } 71 72 scoped_ptr<ExtensionInstallPrompt> CreatePrompt(); 73 74 private: 75 friend class base::RefCountedThreadSafe<MockPromptProxy>; 76 virtual ~MockPromptProxy(); 77 78 // Data used to create a prompt. 79 content::WebContents* web_contents_; 80 scoped_ptr<bool> record_oauth2_grant_; 81 82 // Data reported back to us by the prompt we created. 83 bool confirmation_requested_; 84 std::string extension_id_; 85 base::string16 error_; 86 }; 87 88 class MockInstallPrompt : public ExtensionInstallPrompt { 89 public: 90 MockInstallPrompt(content::WebContents* web_contents, 91 MockPromptProxy* proxy) : 92 ExtensionInstallPrompt(web_contents), 93 proxy_(proxy) {} 94 95 void set_record_oauth2_grant(bool record) { record_oauth2_grant_ = record; } 96 97 // Overriding some of the ExtensionInstallUI API. 98 virtual void ConfirmInstall( 99 Delegate* delegate, 100 const Extension* extension, 101 const ShowDialogCallback& show_dialog_callback) OVERRIDE { 102 proxy_->set_confirmation_requested(); 103 delegate->InstallUIProceed(); 104 } 105 virtual void OnInstallSuccess(const Extension* extension, 106 SkBitmap* icon) OVERRIDE { 107 proxy_->set_extension_id(extension->id()); 108 base::MessageLoopForUI::current()->Quit(); 109 } 110 virtual void OnInstallFailure(const CrxInstallerError& error) OVERRIDE { 111 proxy_->set_error(error.message()); 112 base::MessageLoopForUI::current()->Quit(); 113 } 114 115 private: 116 scoped_refptr<MockPromptProxy> proxy_; 117 }; 118 119 MockPromptProxy::MockPromptProxy(content::WebContents* web_contents) 120 : web_contents_(web_contents), confirmation_requested_(false) { 121 } 122 123 MockPromptProxy::~MockPromptProxy() {} 124 125 scoped_ptr<ExtensionInstallPrompt> MockPromptProxy::CreatePrompt() { 126 scoped_ptr<MockInstallPrompt> prompt( 127 new MockInstallPrompt(web_contents_, this)); 128 if (record_oauth2_grant_.get()) 129 prompt->set_record_oauth2_grant(*record_oauth2_grant_.get()); 130 return prompt.PassAs<ExtensionInstallPrompt>(); 131 } 132 133 134 scoped_refptr<MockPromptProxy> CreateMockPromptProxyForBrowser( 135 Browser* browser) { 136 return new MockPromptProxy( 137 browser->tab_strip_model()->GetActiveWebContents()); 138 } 139 140 } // namespace 141 142 class ExtensionCrxInstallerTest : public ExtensionBrowserTest { 143 public: 144 scoped_ptr<WebstoreInstaller::Approval> GetApproval( 145 const char* manifest_dir, 146 const std::string& id, 147 bool strict_manifest_checks) { 148 scoped_ptr<WebstoreInstaller::Approval> result; 149 150 base::FilePath ext_path = test_data_dir_.AppendASCII(manifest_dir); 151 std::string error; 152 scoped_ptr<base::DictionaryValue> parsed_manifest( 153 file_util::LoadManifest(ext_path, &error)); 154 if (!parsed_manifest.get() || !error.empty()) 155 return result.Pass(); 156 157 return WebstoreInstaller::Approval::CreateWithNoInstallPrompt( 158 browser()->profile(), 159 id, 160 parsed_manifest.Pass(), 161 strict_manifest_checks); 162 } 163 164 void RunCrxInstaller(const WebstoreInstaller::Approval* approval, 165 scoped_ptr<ExtensionInstallPrompt> prompt, 166 const base::FilePath& crx_path) { 167 ExtensionService* service = extensions::ExtensionSystem::Get( 168 browser()->profile())->extension_service(); 169 scoped_refptr<CrxInstaller> installer( 170 CrxInstaller::Create(service, prompt.Pass(), approval)); 171 installer->set_allow_silent_install(true); 172 installer->set_is_gallery_install(true); 173 installer->InstallCrx(crx_path); 174 content::RunMessageLoop(); 175 } 176 177 // Installs a crx from |crx_relpath| (a path relative to the extension test 178 // data dir) with expected id |id|. 179 void InstallWithPrompt(const char* ext_relpath, 180 const std::string& id, 181 scoped_refptr<MockPromptProxy> mock_install_prompt) { 182 base::FilePath ext_path = test_data_dir_.AppendASCII(ext_relpath); 183 184 scoped_ptr<WebstoreInstaller::Approval> approval; 185 if (!id.empty()) 186 approval = GetApproval(ext_relpath, id, true); 187 188 base::FilePath crx_path = PackExtension(ext_path); 189 EXPECT_FALSE(crx_path.empty()); 190 RunCrxInstaller(approval.get(), mock_install_prompt->CreatePrompt(), 191 crx_path); 192 193 EXPECT_TRUE(mock_install_prompt->did_succeed()); 194 } 195 196 // Installs an extension and checks that it has scopes granted IFF 197 // |record_oauth2_grant| is true. 198 void CheckHasEmptyScopesAfterInstall(const std::string& ext_relpath, 199 bool record_oauth2_grant) { 200 CommandLine::ForCurrentProcess()->AppendSwitch( 201 switches::kEnableExperimentalExtensionApis); 202 203 scoped_refptr<MockPromptProxy> mock_prompt = 204 CreateMockPromptProxyForBrowser(browser()); 205 206 mock_prompt->set_record_oauth2_grant(record_oauth2_grant); 207 InstallWithPrompt("browsertest/scopes", std::string(), mock_prompt); 208 209 scoped_refptr<PermissionSet> permissions = 210 ExtensionPrefs::Get(browser()->profile()) 211 ->GetGrantedPermissions(mock_prompt->extension_id()); 212 ASSERT_TRUE(permissions.get()); 213 } 214 }; 215 216 #if defined(OS_CHROMEOS) 217 #define MAYBE_Whitelisting DISABLED_Whitelisting 218 #else 219 #define MAYBE_Whitelisting Whitelisting 220 #endif 221 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, MAYBE_Whitelisting) { 222 std::string id = "hdgllgikmikobbofgnabhfimcfoopgnd"; 223 ExtensionService* service = extensions::ExtensionSystem::Get( 224 browser()->profile())->extension_service(); 225 226 // Even whitelisted extensions with NPAPI should not prompt. 227 scoped_refptr<MockPromptProxy> mock_prompt = 228 CreateMockPromptProxyForBrowser(browser()); 229 InstallWithPrompt("uitest/plugins", id, mock_prompt); 230 EXPECT_FALSE(mock_prompt->confirmation_requested()); 231 EXPECT_TRUE(service->GetExtensionById(id, false)); 232 } 233 234 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, 235 GalleryInstallGetsExperimental) { 236 // We must modify the command line temporarily in order to pack an extension 237 // that requests the experimental permission. 238 CommandLine* command_line = CommandLine::ForCurrentProcess(); 239 CommandLine old_command_line = *command_line; 240 command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis); 241 base::FilePath crx_path = PackExtension( 242 test_data_dir_.AppendASCII("experimental")); 243 ASSERT_FALSE(crx_path.empty()); 244 245 // Now reset the command line so that we are testing specifically whether 246 // installing from webstore enables experimental permissions. 247 *(CommandLine::ForCurrentProcess()) = old_command_line; 248 249 EXPECT_FALSE(InstallExtension(crx_path, 0)); 250 EXPECT_TRUE(InstallExtensionFromWebstore(crx_path, 1)); 251 } 252 253 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, PlatformAppCrx) { 254 CommandLine::ForCurrentProcess()->AppendSwitch( 255 switches::kEnableExperimentalExtensionApis); 256 EXPECT_TRUE(InstallExtension( 257 test_data_dir_.AppendASCII("minimal_platform_app.crx"), 1)); 258 } 259 260 // http://crbug.com/136397 261 #if defined(OS_CHROMEOS) 262 #define MAYBE_PackAndInstallExtension DISABLED_PackAndInstallExtension 263 #else 264 #define MAYBE_PackAndInstallExtension PackAndInstallExtension 265 #endif 266 IN_PROC_BROWSER_TEST_F( 267 ExtensionCrxInstallerTest, MAYBE_PackAndInstallExtension) { 268 if (!FeatureSwitch::easy_off_store_install()->IsEnabled()) 269 return; 270 271 const int kNumDownloadsExpected = 1; 272 273 LOG(ERROR) << "PackAndInstallExtension: Packing extension"; 274 base::FilePath crx_path = PackExtension( 275 test_data_dir_.AppendASCII("common/background_page")); 276 ASSERT_FALSE(crx_path.empty()); 277 std::string crx_path_string(crx_path.value().begin(), crx_path.value().end()); 278 GURL url = GURL(std::string("file:///").append(crx_path_string)); 279 280 scoped_refptr<MockPromptProxy> mock_prompt = 281 CreateMockPromptProxyForBrowser(browser()); 282 download_crx_util::SetMockInstallPromptForTesting( 283 mock_prompt->CreatePrompt()); 284 285 LOG(ERROR) << "PackAndInstallExtension: Getting download manager"; 286 content::DownloadManager* download_manager = 287 content::BrowserContext::GetDownloadManager(browser()->profile()); 288 289 LOG(ERROR) << "PackAndInstallExtension: Setting observer"; 290 scoped_ptr<content::DownloadTestObserver> observer( 291 new content::DownloadTestObserverTerminal( 292 download_manager, kNumDownloadsExpected, 293 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT)); 294 LOG(ERROR) << "PackAndInstallExtension: Navigating to URL"; 295 ui_test_utils::NavigateToURLWithDisposition(browser(), url, CURRENT_TAB, 296 ui_test_utils::BROWSER_TEST_NONE); 297 298 EXPECT_TRUE(WaitForCrxInstallerDone()); 299 LOG(ERROR) << "PackAndInstallExtension: Extension install"; 300 EXPECT_TRUE(mock_prompt->confirmation_requested()); 301 LOG(ERROR) << "PackAndInstallExtension: Extension install confirmed"; 302 } 303 304 // Tests that scopes are only granted if |record_oauth2_grant_| on the prompt is 305 // true. 306 #if defined(OS_WIN) 307 #define MAYBE_GrantScopes DISABLED_GrantScopes 308 #else 309 #define MAYBE_GrantScopes GrantScopes 310 #endif 311 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, MAYBE_GrantScopes) { 312 EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall("browsertest/scopes", 313 true)); 314 } 315 316 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DoNotGrantScopes) { 317 EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall("browsertest/scopes", 318 false)); 319 } 320 321 // Off-store install cannot yet be disabled on Aura. 322 #if defined(USE_AURA) 323 #define MAYBE_AllowOffStore DISABLED_AllowOffStore 324 #else 325 #define MAYBE_AllowOffStore AllowOffStore 326 #endif 327 // Crashy: http://crbug.com/140893 328 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DISABLED_AllowOffStore) { 329 ExtensionService* service = extensions::ExtensionSystem::Get( 330 browser()->profile())->extension_service(); 331 const bool kTestData[] = {false, true}; 332 333 for (size_t i = 0; i < arraysize(kTestData); ++i) { 334 scoped_refptr<MockPromptProxy> mock_prompt = 335 CreateMockPromptProxyForBrowser(browser()); 336 337 scoped_refptr<CrxInstaller> crx_installer( 338 CrxInstaller::Create(service, mock_prompt->CreatePrompt())); 339 crx_installer->set_install_cause( 340 extension_misc::INSTALL_CAUSE_USER_DOWNLOAD); 341 342 if (kTestData[i]) { 343 crx_installer->set_off_store_install_allow_reason( 344 CrxInstaller::OffStoreInstallAllowedInTest); 345 } 346 347 crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx")); 348 EXPECT_EQ(kTestData[i], 349 WaitForExtensionInstall()) << kTestData[i]; 350 EXPECT_EQ(kTestData[i], mock_prompt->did_succeed()); 351 EXPECT_EQ(kTestData[i], mock_prompt->confirmation_requested()) << 352 kTestData[i]; 353 if (kTestData[i]) { 354 EXPECT_EQ(base::string16(), mock_prompt->error()) << kTestData[i]; 355 } else { 356 EXPECT_EQ(l10n_util::GetStringUTF16( 357 IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE), 358 mock_prompt->error()) << kTestData[i]; 359 } 360 } 361 } 362 363 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, HiDpiThemeTest) { 364 base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx"); 365 crx_path = crx_path.AppendASCII("theme_hidpi.crx"); 366 367 ASSERT_TRUE(InstallExtension(crx_path, 1)); 368 369 const std::string extension_id("gllekhaobjnhgeagipipnkpmmmpchacm"); 370 ExtensionService* service = extensions::ExtensionSystem::Get( 371 browser()->profile())->extension_service(); 372 ASSERT_TRUE(service); 373 const extensions::Extension* extension = 374 service->GetExtensionById(extension_id, false); 375 ASSERT_TRUE(extension); 376 EXPECT_EQ(extension_id, extension->id()); 377 378 UninstallExtension(extension_id); 379 EXPECT_FALSE(service->GetExtensionById(extension_id, false)); 380 } 381 382 // See http://crbug.com/315299. 383 #if defined(OS_WIN) 384 #define MAYBE_InstallDelayedUntilNextUpdate \ 385 DISABLED_InstallDelayedUntilNextUpdate 386 #else 387 #define MAYBE_InstallDelayedUntilNextUpdate InstallDelayedUntilNextUpdate 388 #endif // defined(OS_WIN) 389 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, 390 MAYBE_InstallDelayedUntilNextUpdate) { 391 const std::string extension_id("ldnnhddmnhbkjipkidpdiheffobcpfmf"); 392 base::FilePath crx_path = test_data_dir_.AppendASCII("delayed_install"); 393 ExtensionSystem* extension_system = extensions::ExtensionSystem::Get( 394 browser()->profile()); 395 ExtensionService* service = extension_system->extension_service(); 396 ASSERT_TRUE(service); 397 398 // Install version 1 of the test extension. This extension does not have 399 // a background page but does have a browser action. 400 ASSERT_TRUE(InstallExtension(crx_path.AppendASCII("v1.crx"), 1)); 401 const extensions::Extension* extension = 402 service->GetExtensionById(extension_id, false); 403 ASSERT_TRUE(extension); 404 ASSERT_EQ(extension_id, extension->id()); 405 ASSERT_EQ("1.0", extension->version()->GetString()); 406 407 // Make test extension non-idle by opening the extension's browser action 408 // popup. This should cause the installation to be delayed. 409 content::WindowedNotificationObserver loading_observer( 410 chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, 411 content::Source<Profile>(profile())); 412 BrowserActionTestUtil util(browser()); 413 // There is only one extension, so just click the first browser action. 414 ASSERT_EQ(1, util.NumberOfBrowserActions()); 415 util.Press(0); 416 loading_observer.Wait(); 417 ExtensionHost* extension_host = 418 content::Details<ExtensionHost>(loading_observer.details()).ptr(); 419 420 // Install version 2 of the extension and check that it is indeed delayed. 421 ASSERT_TRUE(UpdateExtensionWaitForIdle( 422 extension_id, crx_path.AppendASCII("v2.crx"), 0)); 423 424 ASSERT_EQ(1u, service->delayed_installs()->size()); 425 extension = service->GetExtensionById(extension_id, false); 426 ASSERT_EQ("1.0", extension->version()->GetString()); 427 428 // Make the extension idle again by closing the popup. This should not trigger 429 // the delayed install. 430 content::RenderProcessHostWatcher terminated_observer( 431 extension_host->render_process_host(), 432 content::RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION); 433 extension_host->render_view_host()->ClosePage(); 434 terminated_observer.Wait(); 435 ASSERT_EQ(1u, service->delayed_installs()->size()); 436 437 // Install version 3 of the extension. Because the extension is idle, 438 // this install should succeed. 439 ASSERT_TRUE(UpdateExtensionWaitForIdle( 440 extension_id, crx_path.AppendASCII("v3.crx"), 0)); 441 extension = service->GetExtensionById(extension_id, false); 442 ASSERT_EQ("3.0", extension->version()->GetString()); 443 444 // The version 2 delayed install should be cleaned up, and finishing 445 // delayed extension installation shouldn't break anything. 446 ASSERT_EQ(0u, service->delayed_installs()->size()); 447 service->MaybeFinishDelayedInstallations(); 448 extension = service->GetExtensionById(extension_id, false); 449 ASSERT_EQ("3.0", extension->version()->GetString()); 450 } 451 452 #if defined(FULL_SAFE_BROWSING) 453 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, Blacklist) { 454 scoped_refptr<FakeSafeBrowsingDatabaseManager> blacklist_db( 455 new FakeSafeBrowsingDatabaseManager(true)); 456 Blacklist::ScopedDatabaseManagerForTest scoped_blacklist_db(blacklist_db); 457 458 blacklist_db->SetUnsafe("gllekhaobjnhgeagipipnkpmmmpchacm"); 459 460 base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx") 461 .AppendASCII("theme_hidpi.crx"); 462 EXPECT_FALSE(InstallExtension(crx_path, 0)); 463 } 464 #endif 465 466 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, NonStrictManifestCheck) { 467 scoped_refptr<MockPromptProxy> mock_prompt = 468 CreateMockPromptProxyForBrowser(browser()); 469 470 // We want to simulate the case where the webstore sends a more recent 471 // version of the manifest, but the downloaded .crx file is old since 472 // the newly published version hasn't fully propagated to all the download 473 // servers yet. So load the v2 manifest, but then install the v1 crx file. 474 std::string id = "lhnaeclnpobnlbjbgogdanmhadigfnjp"; 475 scoped_ptr<WebstoreInstaller::Approval> approval = 476 GetApproval("crx_installer/v2_no_permission_change/", id, false); 477 478 RunCrxInstaller(approval.get(), mock_prompt->CreatePrompt(), 479 test_data_dir_.AppendASCII("crx_installer/v1.crx")); 480 481 EXPECT_TRUE(mock_prompt->did_succeed()); 482 } 483 484 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, KioskOnlyTest) { 485 base::FilePath crx_path = 486 test_data_dir_.AppendASCII("kiosk/kiosk_only.crx"); 487 EXPECT_FALSE(InstallExtension(crx_path, 0)); 488 #if defined(OS_CHROMEOS) 489 // Simulate ChromeOS kiosk mode. |scoped_user_manager| will take over 490 // lifetime of |user_manager|. 491 chromeos::FakeUserManager* fake_user_manager = 492 new chromeos::FakeUserManager(); 493 fake_user_manager->AddKioskAppUser("example (at) example.com"); 494 fake_user_manager->LoginUser("example (at) example.com"); 495 chromeos::ScopedUserManagerEnabler scoped_user_manager(fake_user_manager); 496 EXPECT_TRUE(InstallExtension(crx_path, 1)); 497 #endif 498 } 499 500 #if defined(OS_CHROMEOS) 501 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, InstallToSharedLocation) { 502 base::ShadowingAtExitManager at_exit_manager; 503 CommandLine::ForCurrentProcess()->AppendSwitch( 504 chromeos::switches::kEnableExtensionAssetsSharing); 505 base::ScopedTempDir cache_dir; 506 ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); 507 ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting( 508 cache_dir.path()); 509 510 base::FilePath crx_path = test_data_dir_.AppendASCII("crx_installer/v1.crx"); 511 const extensions::Extension* extension = InstallExtension( 512 crx_path, 1, extensions::Manifest::EXTERNAL_PREF); 513 base::FilePath extension_path = extension->path(); 514 EXPECT_TRUE(cache_dir.path().IsParent(extension_path)); 515 EXPECT_TRUE(base::PathExists(extension_path)); 516 517 std::string extension_id = extension->id(); 518 UninstallExtension(extension_id); 519 ExtensionService* service = extensions::ExtensionSystem::Get( 520 browser()->profile())->extension_service(); 521 EXPECT_FALSE(service->GetExtensionById(extension_id, false)); 522 523 // In the worst case you need to repeat this up to 3 times to make sure that 524 // all pending tasks we sent from UI thread to task runner and back to UI. 525 for (int i = 0; i < 3; i++) { 526 // Wait for background task completion that sends replay to UI thread. 527 content::BrowserThread::GetBlockingPool()->FlushForTesting(); 528 // Wait for UI thread task completion. 529 base::RunLoop().RunUntilIdle(); 530 } 531 532 EXPECT_FALSE(base::PathExists(extension_path)); 533 } 534 #endif 535 536 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DoNotSync) { 537 ExtensionService* service = extensions::ExtensionSystem::Get( 538 browser()->profile())->extension_service(); 539 scoped_refptr<CrxInstaller> crx_installer( 540 CrxInstaller::CreateSilent(service)); 541 crx_installer->set_do_not_sync(true); 542 crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx")); 543 EXPECT_TRUE(WaitForCrxInstallerDone()); 544 ASSERT_TRUE(crx_installer->extension()); 545 546 const ExtensionPrefs* extension_prefs = 547 ExtensionPrefs::Get(browser()->profile()); 548 EXPECT_TRUE(extension_prefs->DoNotSync(crx_installer->extension()->id())); 549 EXPECT_FALSE(extensions::util::ShouldSyncApp(crx_installer->extension(), 550 browser()->profile())); 551 } 552 553 } // namespace extensions 554