| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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/apps/ephemeral_app_browsertest.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "apps/app_restore_service.h" | |
| 10 #include "apps/saved_files_service.h" | |
| 11 #include "base/files/scoped_temp_dir.h" | |
| 12 #include "base/scoped_observer.h" | |
| 13 #include "base/stl_util.h" | |
| 14 #include "chrome/browser/apps/app_browsertest_util.h" | |
| 15 #include "chrome/browser/apps/ephemeral_app_service.h" | |
| 16 #include "chrome/browser/extensions/api/file_system/file_system_api.h" | |
| 17 #include "chrome/browser/extensions/extension_service.h" | |
| 18 #include "chrome/browser/extensions/extension_sync_data.h" | |
| 19 #include "chrome/browser/extensions/extension_sync_service.h" | |
| 20 #include "chrome/browser/extensions/extension_util.h" | |
| 21 #include "chrome/browser/notifications/notifier_state_tracker.h" | |
| 22 #include "chrome/browser/notifications/notifier_state_tracker_factory.h" | |
| 23 #include "content/public/browser/power_save_blocker.h" | |
| 24 #include "content/public/test/browser_test.h" | |
| 25 #include "content/public/test/test_utils.h" | |
| 26 #include "extensions/browser/api/power/power_api.h" | |
| 27 #include "extensions/browser/app_sorting.h" | |
| 28 #include "extensions/browser/event_router.h" | |
| 29 #include "extensions/browser/extension_prefs.h" | |
| 30 #include "extensions/browser/extension_registry.h" | |
| 31 #include "extensions/browser/extension_registry_observer.h" | |
| 32 #include "extensions/browser/extension_system.h" | |
| 33 #include "extensions/browser/extension_util.h" | |
| 34 #include "extensions/browser/process_manager.h" | |
| 35 #include "extensions/browser/test_extension_registry_observer.h" | |
| 36 #include "extensions/browser/uninstall_reason.h" | |
| 37 #include "extensions/common/api/alarms.h" | |
| 38 #include "extensions/common/extension.h" | |
| 39 #include "extensions/test/extension_test_message_listener.h" | |
| 40 #include "extensions/test/result_catcher.h" | |
| 41 #include "sync/api/fake_sync_change_processor.h" | |
| 42 #include "sync/api/sync_change_processor_wrapper_for_test.h" | |
| 43 #include "sync/api/sync_error_factory_mock.h" | |
| 44 #include "ui/app_list/app_list_switches.h" | |
| 45 #include "ui/message_center/message_center.h" | |
| 46 #include "ui/message_center/notifier_settings.h" | |
| 47 | |
| 48 using extensions::AppSorting; | |
| 49 using extensions::Event; | |
| 50 using extensions::EventRouter; | |
| 51 using extensions::Extension; | |
| 52 using extensions::ExtensionPrefs; | |
| 53 using extensions::ExtensionRegistry; | |
| 54 using extensions::ExtensionRegistryObserver; | |
| 55 using extensions::ExtensionSyncData; | |
| 56 using extensions::ExtensionSystem; | |
| 57 using extensions::Manifest; | |
| 58 using extensions::ResultCatcher; | |
| 59 | |
| 60 namespace { | |
| 61 | |
| 62 namespace alarms = extensions::api::alarms; | |
| 63 | |
| 64 const char kPowerTestApp[] = "ephemeral_apps/power"; | |
| 65 | |
| 66 // Enabling sync causes these tests to be flaky on Windows. Disable sync so that | |
| 67 // everything else can be tested. See crbug.com/401028 | |
| 68 #if defined(OS_WIN) | |
| 69 const bool kEnableSync = false; | |
| 70 #else | |
| 71 const bool kEnableSync = true; | |
| 72 #endif | |
| 73 | |
| 74 typedef std::vector<message_center::Notifier*> NotifierList; | |
| 75 | |
| 76 bool IsNotifierInList(const message_center::NotifierId& notifier_id, | |
| 77 const NotifierList& notifiers) { | |
| 78 for (NotifierList::const_iterator it = notifiers.begin(); | |
| 79 it != notifiers.end(); ++it) { | |
| 80 const message_center::Notifier* notifier = *it; | |
| 81 if (notifier->notifier_id == notifier_id) | |
| 82 return true; | |
| 83 } | |
| 84 | |
| 85 return false; | |
| 86 } | |
| 87 | |
| 88 // Saves some parameters from the extension installed notification in order | |
| 89 // to verify them in tests. | |
| 90 class InstallObserver : public ExtensionRegistryObserver { | |
| 91 public: | |
| 92 struct InstallParameters { | |
| 93 std::string id; | |
| 94 bool is_update; | |
| 95 bool from_ephemeral; | |
| 96 | |
| 97 InstallParameters( | |
| 98 const std::string& id, | |
| 99 bool is_update, | |
| 100 bool from_ephemeral) | |
| 101 : id(id), is_update(is_update), from_ephemeral(from_ephemeral) {} | |
| 102 }; | |
| 103 | |
| 104 explicit InstallObserver(Profile* profile) : registry_observer_(this) { | |
| 105 registry_observer_.Add(ExtensionRegistry::Get(profile)); | |
| 106 } | |
| 107 | |
| 108 ~InstallObserver() override {} | |
| 109 | |
| 110 const InstallParameters& Last() { | |
| 111 CHECK(!install_params_.empty()); | |
| 112 return install_params_.back(); | |
| 113 } | |
| 114 | |
| 115 private: | |
| 116 void OnExtensionWillBeInstalled(content::BrowserContext* browser_context, | |
| 117 const Extension* extension, | |
| 118 bool is_update, | |
| 119 bool from_ephemeral, | |
| 120 const std::string& old_name) override { | |
| 121 install_params_.push_back( | |
| 122 InstallParameters(extension->id(), is_update, from_ephemeral)); | |
| 123 } | |
| 124 | |
| 125 std::vector<InstallParameters> install_params_; | |
| 126 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> | |
| 127 registry_observer_; | |
| 128 }; | |
| 129 | |
| 130 // Instead of actually changing the system power settings, tests will just | |
| 131 // issue requests to this mock. | |
| 132 class PowerSettingsMock { | |
| 133 public: | |
| 134 PowerSettingsMock() : keep_awake_count_(0) {} | |
| 135 | |
| 136 void request_keep_awake() { ++keep_awake_count_; } | |
| 137 | |
| 138 void release_keep_awake() { | |
| 139 --keep_awake_count_; | |
| 140 ASSERT_GE(keep_awake_count_, 0); | |
| 141 } | |
| 142 | |
| 143 int keep_awake_count() const { return keep_awake_count_; } | |
| 144 | |
| 145 private: | |
| 146 int keep_awake_count_; | |
| 147 | |
| 148 DISALLOW_COPY_AND_ASSIGN(PowerSettingsMock); | |
| 149 }; | |
| 150 | |
| 151 // Stub implementation of content::PowerSaveBlocker that updates the | |
| 152 // PowerSettingsMock. | |
| 153 class PowerSaveBlockerStub : public content::PowerSaveBlocker { | |
| 154 public: | |
| 155 explicit PowerSaveBlockerStub(PowerSettingsMock* power_settings) | |
| 156 : power_settings_(power_settings) { | |
| 157 power_settings_->request_keep_awake(); | |
| 158 } | |
| 159 | |
| 160 ~PowerSaveBlockerStub() override { power_settings_->release_keep_awake(); } | |
| 161 | |
| 162 static scoped_ptr<PowerSaveBlocker> Create(PowerSettingsMock* power_settings, | |
| 163 PowerSaveBlockerType type, | |
| 164 Reason reason, | |
| 165 const std::string& description) { | |
| 166 return scoped_ptr<PowerSaveBlocker>( | |
| 167 new PowerSaveBlockerStub(power_settings)); | |
| 168 } | |
| 169 | |
| 170 private: | |
| 171 PowerSettingsMock* power_settings_; // Not owned. | |
| 172 | |
| 173 DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStub); | |
| 174 }; | |
| 175 | |
| 176 } // namespace | |
| 177 | |
| 178 | |
| 179 // EphemeralAppTestBase: | |
| 180 | |
| 181 const char EphemeralAppTestBase::kMessagingReceiverApp[] = | |
| 182 "ephemeral_apps/messaging_receiver"; | |
| 183 const char EphemeralAppTestBase::kMessagingReceiverAppV2[] = | |
| 184 "ephemeral_apps/messaging_receiver2"; | |
| 185 const char EphemeralAppTestBase::kDispatchEventTestApp[] = | |
| 186 "ephemeral_apps/dispatch_event"; | |
| 187 const char EphemeralAppTestBase::kNotificationsTestApp[] = | |
| 188 "ephemeral_apps/notification_settings"; | |
| 189 const char EphemeralAppTestBase::kFileSystemTestApp[] = | |
| 190 "ephemeral_apps/filesystem_retain_entries"; | |
| 191 | |
| 192 EphemeralAppTestBase::EphemeralAppTestBase() {} | |
| 193 | |
| 194 EphemeralAppTestBase::~EphemeralAppTestBase() {} | |
| 195 | |
| 196 void EphemeralAppTestBase::SetUpCommandLine(base::CommandLine* command_line) { | |
| 197 // Skip PlatformAppBrowserTest, which sets different values for the switches | |
| 198 // below. | |
| 199 ExtensionBrowserTest::SetUpCommandLine(command_line); | |
| 200 | |
| 201 // Make event pages get suspended immediately. | |
| 202 extensions::ProcessManager::SetEventPageIdleTimeForTesting(1); | |
| 203 extensions::ProcessManager::SetEventPageSuspendingTimeForTesting(1); | |
| 204 | |
| 205 // Enable ephemeral apps, which are gated by the experimental app launcher | |
| 206 // flag. | |
| 207 command_line->AppendSwitch(app_list::switches::kEnableExperimentalAppList); | |
| 208 } | |
| 209 | |
| 210 void EphemeralAppTestBase::SetUpOnMainThread() { | |
| 211 PlatformAppBrowserTest::SetUpOnMainThread(); | |
| 212 | |
| 213 // Disable ephemeral apps immediately after they stop running in tests. | |
| 214 EphemeralAppService::Get(profile())->set_disable_delay_for_test(0); | |
| 215 } | |
| 216 | |
| 217 base::FilePath EphemeralAppTestBase::GetTestPath(const char* test_path) { | |
| 218 return test_data_dir_.AppendASCII("platform_apps").AppendASCII(test_path); | |
| 219 } | |
| 220 | |
| 221 const Extension* EphemeralAppTestBase::InstallEphemeralApp( | |
| 222 const char* test_path, Manifest::Location manifest_location) { | |
| 223 const Extension* extension = InstallEphemeralAppWithSourceAndFlags( | |
| 224 GetTestPath(test_path), 1, manifest_location, Extension::NO_FLAGS); | |
| 225 EXPECT_TRUE(extension); | |
| 226 if (extension) | |
| 227 EXPECT_TRUE(extensions::util::IsEphemeralApp(extension->id(), profile())); | |
| 228 return extension; | |
| 229 } | |
| 230 | |
| 231 const Extension* EphemeralAppTestBase::InstallEphemeralApp( | |
| 232 const char* test_path) { | |
| 233 return InstallEphemeralApp(test_path, Manifest::INTERNAL); | |
| 234 } | |
| 235 | |
| 236 const Extension* EphemeralAppTestBase::InstallAndLaunchEphemeralApp( | |
| 237 const char* test_path) { | |
| 238 ExtensionTestMessageListener launched_listener("launched", false); | |
| 239 const Extension* extension = InstallEphemeralApp(test_path); | |
| 240 EXPECT_TRUE(extension); | |
| 241 if (!extension) | |
| 242 return NULL; | |
| 243 | |
| 244 LaunchPlatformApp(extension); | |
| 245 bool wait_result = launched_listener.WaitUntilSatisfied(); | |
| 246 EXPECT_TRUE(wait_result); | |
| 247 if (!wait_result) | |
| 248 return NULL; | |
| 249 | |
| 250 return extension; | |
| 251 } | |
| 252 | |
| 253 const Extension* EphemeralAppTestBase::UpdateEphemeralApp( | |
| 254 const std::string& app_id, | |
| 255 const base::FilePath& test_dir, | |
| 256 const base::FilePath& pem_path) { | |
| 257 // Pack a new version of the app. | |
| 258 base::ScopedTempDir temp_dir; | |
| 259 EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 260 | |
| 261 base::FilePath crx_path = temp_dir.path().AppendASCII("temp.crx"); | |
| 262 if (!base::DeleteFile(crx_path, false)) { | |
| 263 ADD_FAILURE() << "Failed to delete existing crx: " << crx_path.value(); | |
| 264 return NULL; | |
| 265 } | |
| 266 | |
| 267 base::FilePath app_v2_path = PackExtensionWithOptions( | |
| 268 test_dir, crx_path, pem_path, base::FilePath()); | |
| 269 EXPECT_FALSE(app_v2_path.empty()); | |
| 270 | |
| 271 // Update the ephemeral app and wait for the update to finish. | |
| 272 extensions::CrxInstaller* crx_installer = NULL; | |
| 273 content::WindowedNotificationObserver windowed_observer( | |
| 274 extensions::NOTIFICATION_CRX_INSTALLER_DONE, | |
| 275 content::Source<extensions::CrxInstaller>(crx_installer)); | |
| 276 ExtensionService* service = | |
| 277 ExtensionSystem::Get(profile())->extension_service(); | |
| 278 EXPECT_TRUE(service->UpdateExtension( | |
| 279 extensions::CRXFileInfo(app_id, app_v2_path), true, &crx_installer)); | |
| 280 windowed_observer.Wait(); | |
| 281 | |
| 282 return ExtensionRegistry::Get(profile()) | |
| 283 ->GetExtensionById(app_id, ExtensionRegistry::EVERYTHING); | |
| 284 } | |
| 285 | |
| 286 void EphemeralAppTestBase::PromoteEphemeralApp( | |
| 287 const extensions::Extension* app) { | |
| 288 ExtensionService* extension_service = | |
| 289 ExtensionSystem::Get(profile())->extension_service(); | |
| 290 ASSERT_TRUE(extension_service); | |
| 291 extension_service->PromoteEphemeralApp(app, false); | |
| 292 } | |
| 293 | |
| 294 void EphemeralAppTestBase::DisableEphemeralApp( | |
| 295 const Extension* app, | |
| 296 Extension::DisableReason disable_reason) { | |
| 297 ExtensionSystem::Get(profile())->extension_service()->DisableExtension( | |
| 298 app->id(), disable_reason); | |
| 299 | |
| 300 ASSERT_TRUE(ExtensionRegistry::Get(profile())->disabled_extensions().Contains( | |
| 301 app->id())); | |
| 302 } | |
| 303 | |
| 304 void EphemeralAppTestBase::CloseApp(const std::string& app_id) { | |
| 305 EXPECT_EQ(1U, GetAppWindowCountForApp(app_id)); | |
| 306 extensions::AppWindow* app_window = GetFirstAppWindowForApp(app_id); | |
| 307 ASSERT_TRUE(app_window); | |
| 308 CloseAppWindow(app_window); | |
| 309 } | |
| 310 | |
| 311 void EphemeralAppTestBase::CloseAppWaitForUnload(const std::string& app_id) { | |
| 312 // Ephemeral apps are unloaded from extension system after they stop running. | |
| 313 extensions::TestExtensionRegistryObserver observer( | |
| 314 ExtensionRegistry::Get(profile()), app_id); | |
| 315 CloseApp(app_id); | |
| 316 observer.WaitForExtensionUnloaded(); | |
| 317 } | |
| 318 | |
| 319 void EphemeralAppTestBase::EvictApp(const std::string& app_id) { | |
| 320 // Uninstall the app, which is what happens when ephemeral apps get evicted | |
| 321 // from the cache. | |
| 322 extensions::TestExtensionRegistryObserver observer( | |
| 323 ExtensionRegistry::Get(profile()), app_id); | |
| 324 | |
| 325 ExtensionService* service = | |
| 326 ExtensionSystem::Get(profile())->extension_service(); | |
| 327 ASSERT_TRUE(service); | |
| 328 service->UninstallExtension( | |
| 329 app_id, | |
| 330 extensions::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION, | |
| 331 base::Bind(&base::DoNothing), | |
| 332 NULL); | |
| 333 | |
| 334 observer.WaitForExtensionUninstalled(); | |
| 335 } | |
| 336 | |
| 337 // EphemeralAppBrowserTest: | |
| 338 | |
| 339 class EphemeralAppBrowserTest : public EphemeralAppTestBase { | |
| 340 protected: | |
| 341 bool LaunchAppAndRunTest(const Extension* app, const char* test_name) { | |
| 342 // Ephemeral apps are unloaded after they are closed. Ensure they are | |
| 343 // enabled before launch. | |
| 344 ExtensionService* service = | |
| 345 ExtensionSystem::Get(profile())->extension_service(); | |
| 346 service->EnableExtension(app->id()); | |
| 347 | |
| 348 ExtensionTestMessageListener launched_listener("launched", true); | |
| 349 LaunchPlatformApp(app); | |
| 350 if (!launched_listener.WaitUntilSatisfied()) { | |
| 351 message_ = "Failed to receive launched message from test"; | |
| 352 return false; | |
| 353 } | |
| 354 | |
| 355 ResultCatcher catcher; | |
| 356 launched_listener.Reply(test_name); | |
| 357 | |
| 358 bool result = catcher.GetNextResult(); | |
| 359 message_ = catcher.message(); | |
| 360 | |
| 361 CloseAppWaitForUnload(app->id()); | |
| 362 return result; | |
| 363 } | |
| 364 | |
| 365 // Verify that the event page of the app has not been loaded. | |
| 366 void VerifyAppNotLoaded(const std::string& app_id) { | |
| 367 EXPECT_FALSE(extensions::ProcessManager::Get(profile()) | |
| 368 ->GetBackgroundHostForExtension(app_id)); | |
| 369 } | |
| 370 | |
| 371 // Verify properties of ephemeral apps. | |
| 372 void VerifyEphemeralApp(const std::string& app_id) { | |
| 373 EXPECT_TRUE(extensions::util::IsEphemeralApp(app_id, profile())); | |
| 374 | |
| 375 // Ephemeral apps should not be synced. | |
| 376 scoped_ptr<ExtensionSyncData> sync_change = GetLastSyncChangeForApp(app_id); | |
| 377 EXPECT_FALSE(sync_change.get()); | |
| 378 | |
| 379 // Ephemeral apps should not be assigned ordinals. | |
| 380 AppSorting* app_sorting = ExtensionSystem::Get(profile())->app_sorting(); | |
| 381 EXPECT_FALSE(app_sorting->GetAppLaunchOrdinal(app_id).IsValid()); | |
| 382 EXPECT_FALSE(app_sorting->GetPageOrdinal(app_id).IsValid()); | |
| 383 } | |
| 384 | |
| 385 // Verify that after ephemeral apps stop running, they reside in extension | |
| 386 // system in a disabled and unloaded state. | |
| 387 void VerifyInactiveEphemeralApp(const std::string& app_id) { | |
| 388 EXPECT_TRUE( | |
| 389 ExtensionRegistry::Get(profile())->disabled_extensions().Contains( | |
| 390 app_id)); | |
| 391 | |
| 392 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); | |
| 393 EXPECT_TRUE(prefs->IsExtensionDisabled(app_id)); | |
| 394 EXPECT_NE(0, | |
| 395 prefs->GetDisableReasons(app_id) & | |
| 396 Extension::DISABLE_INACTIVE_EPHEMERAL_APP); | |
| 397 } | |
| 398 | |
| 399 // Verify the state of an app that has been promoted from an ephemeral to a | |
| 400 // fully installed app. | |
| 401 void VerifyPromotedApp(const std::string& app_id, | |
| 402 ExtensionRegistry::IncludeFlag expected_set) { | |
| 403 const Extension* app = ExtensionRegistry::Get(profile()) | |
| 404 ->GetExtensionById(app_id, expected_set); | |
| 405 ASSERT_TRUE(app) << "App not found in expected set: " << expected_set; | |
| 406 | |
| 407 // The app should not be ephemeral. | |
| 408 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); | |
| 409 ASSERT_TRUE(prefs); | |
| 410 EXPECT_FALSE(prefs->IsEphemeralApp(app_id)); | |
| 411 EXPECT_EQ(0, | |
| 412 prefs->GetDisableReasons(app_id) & | |
| 413 Extension::DISABLE_INACTIVE_EPHEMERAL_APP); | |
| 414 | |
| 415 // Check sort ordinals. | |
| 416 AppSorting* app_sorting = ExtensionSystem::Get(profile())->app_sorting(); | |
| 417 EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(app_id).IsValid()); | |
| 418 EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).IsValid()); | |
| 419 } | |
| 420 | |
| 421 // Dispatch a fake alarm event to the app. | |
| 422 void DispatchAlarmEvent(EventRouter* event_router, | |
| 423 const std::string& app_id) { | |
| 424 alarms::Alarm dummy_alarm; | |
| 425 dummy_alarm.name = "test_alarm"; | |
| 426 | |
| 427 scoped_ptr<base::ListValue> args(new base::ListValue()); | |
| 428 args->Append(dummy_alarm.ToValue().release()); | |
| 429 scoped_ptr<Event> event(new Event(extensions::events::ALARMS_ON_ALARM, | |
| 430 alarms::OnAlarm::kEventName, | |
| 431 args.Pass())); | |
| 432 | |
| 433 event_router->DispatchEventToExtension(app_id, event.Pass()); | |
| 434 } | |
| 435 | |
| 436 // Simulates the scenario where an app is installed, via the normal | |
| 437 // installation route, on top of an ephemeral app. This can occur due to race | |
| 438 // conditions. | |
| 439 const Extension* ReplaceEphemeralApp(const std::string& app_id, | |
| 440 const char* test_path, | |
| 441 int expected_enabled_change) { | |
| 442 return UpdateExtensionWaitForIdle( | |
| 443 app_id, GetTestPath(test_path), expected_enabled_change); | |
| 444 } | |
| 445 | |
| 446 void PromoteEphemeralAppAndVerify( | |
| 447 const Extension* app, | |
| 448 ExtensionRegistry::IncludeFlag expected_set, | |
| 449 bool expect_sync_enabled) { | |
| 450 ASSERT_TRUE(app); | |
| 451 | |
| 452 // Ephemeral apps should not be synced. | |
| 453 scoped_ptr<ExtensionSyncData> sync_change = | |
| 454 GetLastSyncChangeForApp(app->id()); | |
| 455 EXPECT_FALSE(sync_change.get()); | |
| 456 | |
| 457 // Promote the app to a regular installed app. | |
| 458 InstallObserver installed_observer(profile()); | |
| 459 PromoteEphemeralApp(app); | |
| 460 VerifyPromotedApp(app->id(), expected_set); | |
| 461 | |
| 462 // Check the notification parameters. | |
| 463 const InstallObserver::InstallParameters& params = | |
| 464 installed_observer.Last(); | |
| 465 EXPECT_EQ(app->id(), params.id); | |
| 466 EXPECT_TRUE(params.is_update); | |
| 467 EXPECT_TRUE(params.from_ephemeral); | |
| 468 | |
| 469 // The installation should now be synced. | |
| 470 sync_change = GetLastSyncChangeForApp(app->id()); | |
| 471 VerifySyncChange(sync_change.get(), expect_sync_enabled); | |
| 472 } | |
| 473 | |
| 474 void PromoteEphemeralAppAndVerify( | |
| 475 const Extension* app, | |
| 476 ExtensionRegistry::IncludeFlag expected_set) { | |
| 477 PromoteEphemeralAppAndVerify(app, expected_set, | |
| 478 expected_set == ExtensionRegistry::ENABLED); | |
| 479 } | |
| 480 | |
| 481 void PromoteEphemeralAppFromSyncAndVerify( | |
| 482 const Extension* app, | |
| 483 bool enable_from_sync, | |
| 484 ExtensionRegistry::IncludeFlag expected_set) { | |
| 485 ASSERT_TRUE(app); | |
| 486 | |
| 487 // Simulate an install from sync. | |
| 488 int disable_reasons = enable_from_sync ? 0 : Extension::DISABLE_USER_ACTION; | |
| 489 const syncer::StringOrdinal kAppLaunchOrdinal("x"); | |
| 490 const syncer::StringOrdinal kPageOrdinal("y"); | |
| 491 ExtensionSyncData app_sync_data( | |
| 492 *app, | |
| 493 enable_from_sync, | |
| 494 disable_reasons, | |
| 495 false /* incognito enabled */, | |
| 496 false /* remote install */, | |
| 497 extensions::ExtensionSyncData::BOOLEAN_UNSET, | |
| 498 kAppLaunchOrdinal, | |
| 499 kPageOrdinal, | |
| 500 extensions::LAUNCH_TYPE_REGULAR); | |
| 501 | |
| 502 std::string app_id = app->id(); | |
| 503 app = NULL; | |
| 504 | |
| 505 ExtensionSyncService::Get(profile())->ProcessSyncChanges( | |
| 506 FROM_HERE, | |
| 507 syncer::SyncChangeList( | |
| 508 1, app_sync_data.GetSyncChange(syncer::SyncChange::ACTION_ADD))); | |
| 509 | |
| 510 // Verify the installation. | |
| 511 VerifyPromotedApp(app_id, expected_set); | |
| 512 | |
| 513 // The sort ordinals from sync should not be overridden. | |
| 514 AppSorting* app_sorting = ExtensionSystem::Get(profile())->app_sorting(); | |
| 515 EXPECT_TRUE( | |
| 516 app_sorting->GetAppLaunchOrdinal(app_id).Equals(kAppLaunchOrdinal)); | |
| 517 EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).Equals(kPageOrdinal)); | |
| 518 } | |
| 519 | |
| 520 void InitSyncService() { | |
| 521 if (!kEnableSync) | |
| 522 return; | |
| 523 | |
| 524 ExtensionSyncService* sync_service = ExtensionSyncService::Get(profile()); | |
| 525 sync_service->MergeDataAndStartSyncing( | |
| 526 syncer::APPS, | |
| 527 syncer::SyncDataList(), | |
| 528 scoped_ptr<syncer::SyncChangeProcessor>( | |
| 529 new syncer::SyncChangeProcessorWrapperForTest( | |
| 530 &mock_sync_processor_)), | |
| 531 scoped_ptr<syncer::SyncErrorFactory>( | |
| 532 new syncer::SyncErrorFactoryMock())); | |
| 533 } | |
| 534 | |
| 535 scoped_ptr<ExtensionSyncData> GetLastSyncChangeForApp(const std::string& id) { | |
| 536 scoped_ptr<ExtensionSyncData> sync_data; | |
| 537 for (syncer::SyncChangeList::iterator it = | |
| 538 mock_sync_processor_.changes().begin(); | |
| 539 it != mock_sync_processor_.changes().end(); ++it) { | |
| 540 scoped_ptr<ExtensionSyncData> data( | |
| 541 ExtensionSyncData::CreateFromSyncChange(*it)); | |
| 542 if (data.get() && data->id() == id) | |
| 543 sync_data.reset(data.release()); | |
| 544 } | |
| 545 | |
| 546 return sync_data.Pass(); | |
| 547 } | |
| 548 | |
| 549 void VerifySyncChange(const ExtensionSyncData* sync_change, | |
| 550 bool expect_enabled) { | |
| 551 if (!kEnableSync) | |
| 552 return; | |
| 553 | |
| 554 ASSERT_TRUE(sync_change); | |
| 555 EXPECT_TRUE(sync_change->page_ordinal().IsValid()); | |
| 556 EXPECT_TRUE(sync_change->app_launch_ordinal().IsValid()); | |
| 557 EXPECT_FALSE(sync_change->uninstalled()); | |
| 558 EXPECT_EQ(expect_enabled, sync_change->enabled()); | |
| 559 } | |
| 560 | |
| 561 void TestInstallEvent(bool close_app) { | |
| 562 ExtensionTestMessageListener first_msg_listener(false); | |
| 563 const Extension* app = InstallAndLaunchEphemeralApp(kDispatchEventTestApp); | |
| 564 ASSERT_TRUE(app); | |
| 565 | |
| 566 // When an ephemeral app is first added, it should not receive the | |
| 567 // onInstalled event, hence the first message received from the test should | |
| 568 // be "launched" and not "installed". | |
| 569 ASSERT_TRUE(first_msg_listener.WaitUntilSatisfied()); | |
| 570 EXPECT_EQ(std::string("launched"), first_msg_listener.message()); | |
| 571 | |
| 572 if (close_app) | |
| 573 CloseAppWaitForUnload(app->id()); | |
| 574 | |
| 575 // When installed permanently, the app should receive the onInstalled event. | |
| 576 ExtensionTestMessageListener install_listener("installed", false); | |
| 577 PromoteEphemeralApp(app); | |
| 578 ASSERT_TRUE(install_listener.WaitUntilSatisfied()); | |
| 579 } | |
| 580 | |
| 581 private: | |
| 582 syncer::FakeSyncChangeProcessor mock_sync_processor_; | |
| 583 }; | |
| 584 | |
| 585 // Verify that ephemeral apps can be launched and receive system events when | |
| 586 // they are running. Once they are inactive they should not receive system | |
| 587 // events. | |
| 588 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, EventDispatchWhenLaunched) { | |
| 589 const Extension* extension = | |
| 590 InstallAndLaunchEphemeralApp(kDispatchEventTestApp); | |
| 591 ASSERT_TRUE(extension); | |
| 592 | |
| 593 // Send a fake alarm event to the app and verify that a response is | |
| 594 // received. | |
| 595 EventRouter* event_router = EventRouter::Get(profile()); | |
| 596 ASSERT_TRUE(event_router); | |
| 597 | |
| 598 ExtensionTestMessageListener alarm_received_listener("alarm_received", false); | |
| 599 DispatchAlarmEvent(event_router, extension->id()); | |
| 600 ASSERT_TRUE(alarm_received_listener.WaitUntilSatisfied()); | |
| 601 | |
| 602 CloseAppWaitForUnload(extension->id()); | |
| 603 | |
| 604 // Dispatch the alarm event again and verify that the event page did not get | |
| 605 // loaded for the app. | |
| 606 DispatchAlarmEvent(event_router, extension->id()); | |
| 607 VerifyAppNotLoaded(extension->id()); | |
| 608 } | |
| 609 | |
| 610 // Verify that ephemeral apps will receive messages while they are running. | |
| 611 // Flaky test: crbug.com/394426 | |
| 612 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 613 DISABLED_ReceiveMessagesWhenLaunched) { | |
| 614 const Extension* receiver = | |
| 615 InstallAndLaunchEphemeralApp(kMessagingReceiverApp); | |
| 616 ASSERT_TRUE(receiver); | |
| 617 | |
| 618 // Verify that messages are received while the app is running. | |
| 619 ResultCatcher result_catcher; | |
| 620 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_success", | |
| 621 "Launched"); | |
| 622 EXPECT_TRUE(result_catcher.GetNextResult()); | |
| 623 | |
| 624 CloseAppWaitForUnload(receiver->id()); | |
| 625 | |
| 626 // Verify that messages are not received while the app is inactive. | |
| 627 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_fail", "Launched"); | |
| 628 EXPECT_TRUE(result_catcher.GetNextResult()); | |
| 629 } | |
| 630 | |
| 631 // Verifies that the chrome.runtime.onInstalled() event is received by a running | |
| 632 // ephemeral app only when it is promoted. | |
| 633 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 634 InstallEventReceivedWhileRunning) { | |
| 635 TestInstallEvent(false /* close app */); | |
| 636 } | |
| 637 | |
| 638 // Verifies that when an idle ephemeral app is promoted, it will be loaded to | |
| 639 // receive the chrome.runtime.onInstalled() event. | |
| 640 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, InstallEventReceivedWhileIdle) { | |
| 641 TestInstallEvent(true /* close app */); | |
| 642 } | |
| 643 | |
| 644 // Verifies that the chrome.runtime.onRestarted() event is received by an | |
| 645 // ephemeral app. | |
| 646 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, RestartEventReceived) { | |
| 647 const Extension* app = InstallAndLaunchEphemeralApp(kDispatchEventTestApp); | |
| 648 ASSERT_TRUE(app); | |
| 649 CloseAppWaitForUnload(app->id()); | |
| 650 | |
| 651 // Fake ephemeral app running before restart. | |
| 652 ExtensionSystem::Get(profile())->extension_service()->EnableExtension( | |
| 653 app->id()); | |
| 654 ASSERT_TRUE(ExtensionRegistry::Get(profile())->enabled_extensions().Contains( | |
| 655 app->id())); | |
| 656 ExtensionPrefs::Get(profile())->SetExtensionRunning(app->id(), true); | |
| 657 | |
| 658 ExtensionTestMessageListener restart_listener("restarted", false); | |
| 659 apps::AppRestoreService::Get(profile())->HandleStartup(true); | |
| 660 EXPECT_TRUE(restart_listener.WaitUntilSatisfied()); | |
| 661 } | |
| 662 | |
| 663 // Verify that an updated ephemeral app will still have its ephemeral flag | |
| 664 // enabled. | |
| 665 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, UpdateEphemeralApp) { | |
| 666 InitSyncService(); | |
| 667 | |
| 668 const Extension* app_v1 = InstallAndLaunchEphemeralApp(kMessagingReceiverApp); | |
| 669 ASSERT_TRUE(app_v1); | |
| 670 VerifyEphemeralApp(app_v1->id()); | |
| 671 CloseAppWaitForUnload(app_v1->id()); | |
| 672 VerifyInactiveEphemeralApp(app_v1->id()); | |
| 673 | |
| 674 std::string app_id = app_v1->id(); | |
| 675 base::Version app_original_version = *app_v1->version(); | |
| 676 | |
| 677 // Update to version 2 of the app. | |
| 678 app_v1 = NULL; // The extension object will be destroyed during update. | |
| 679 InstallObserver installed_observer(profile()); | |
| 680 const Extension* app_v2 = | |
| 681 UpdateEphemeralApp(app_id, | |
| 682 GetTestPath(kMessagingReceiverAppV2), | |
| 683 GetTestPath(kMessagingReceiverApp) | |
| 684 .ReplaceExtension(FILE_PATH_LITERAL(".pem"))); | |
| 685 | |
| 686 // Check the notification parameters. | |
| 687 const InstallObserver::InstallParameters& params = installed_observer.Last(); | |
| 688 EXPECT_EQ(app_id, params.id); | |
| 689 EXPECT_TRUE(params.is_update); | |
| 690 EXPECT_FALSE(params.from_ephemeral); | |
| 691 | |
| 692 // The ephemeral flag should still be set. | |
| 693 ASSERT_TRUE(app_v2); | |
| 694 EXPECT_GT(app_v2->version()->CompareTo(app_original_version), 0); | |
| 695 VerifyEphemeralApp(app_id); | |
| 696 | |
| 697 // The app should still be disabled in extension system. | |
| 698 VerifyInactiveEphemeralApp(app_id); | |
| 699 } | |
| 700 | |
| 701 // Verify that if notifications have been disabled for an ephemeral app, it will | |
| 702 // remain disabled even after being evicted from the cache. | |
| 703 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, StickyNotificationSettings) { | |
| 704 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 705 ASSERT_TRUE(app); | |
| 706 | |
| 707 // Disable notifications for this app. | |
| 708 NotifierStateTracker* notifier_state_tracker = | |
| 709 NotifierStateTrackerFactory::GetForProfile(profile()); | |
| 710 ASSERT_TRUE(notifier_state_tracker); | |
| 711 | |
| 712 message_center::NotifierId notifier_id( | |
| 713 message_center::NotifierId::APPLICATION, app->id()); | |
| 714 EXPECT_TRUE(notifier_state_tracker->IsNotifierEnabled(notifier_id)); | |
| 715 notifier_state_tracker->SetNotifierEnabled(notifier_id, false); | |
| 716 EXPECT_FALSE(notifier_state_tracker->IsNotifierEnabled(notifier_id)); | |
| 717 | |
| 718 // Remove the app. | |
| 719 CloseAppWaitForUnload(app->id()); | |
| 720 EvictApp(app->id()); | |
| 721 | |
| 722 // Reinstall the ephemeral app and verify that notifications remain disabled. | |
| 723 app = InstallEphemeralApp(kNotificationsTestApp); | |
| 724 ASSERT_TRUE(app); | |
| 725 message_center::NotifierId reinstalled_notifier_id( | |
| 726 message_center::NotifierId::APPLICATION, app->id()); | |
| 727 EXPECT_FALSE(notifier_state_tracker->IsNotifierEnabled( | |
| 728 reinstalled_notifier_id)); | |
| 729 } | |
| 730 | |
| 731 // Verify that only running ephemeral apps will appear in the Notification | |
| 732 // Settings UI. Inactive, cached ephemeral apps should not appear. | |
| 733 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 734 IncludeRunningEphemeralAppsInNotifiers) { | |
| 735 message_center::NotifierSettingsProvider* settings_provider = | |
| 736 message_center::MessageCenter::Get()->GetNotifierSettingsProvider(); | |
| 737 DCHECK(settings_provider); | |
| 738 | |
| 739 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 740 ASSERT_TRUE(app); | |
| 741 message_center::NotifierId notifier_id( | |
| 742 message_center::NotifierId::APPLICATION, app->id()); | |
| 743 | |
| 744 // Since the ephemeral app is running, it should be included in the list | |
| 745 // of notifiers to show in the UI. | |
| 746 NotifierList notifiers; | |
| 747 STLElementDeleter<NotifierList> notifier_deleter(¬ifiers); | |
| 748 | |
| 749 settings_provider->GetNotifierList(¬ifiers); | |
| 750 EXPECT_TRUE(IsNotifierInList(notifier_id, notifiers)); | |
| 751 STLDeleteElements(¬ifiers); | |
| 752 | |
| 753 // Close the ephemeral app. | |
| 754 CloseAppWaitForUnload(app->id()); | |
| 755 | |
| 756 // Inactive ephemeral apps should not be included in the list of notifiers to | |
| 757 // show in the UI. | |
| 758 settings_provider->GetNotifierList(¬ifiers); | |
| 759 EXPECT_FALSE(IsNotifierInList(notifier_id, notifiers)); | |
| 760 } | |
| 761 | |
| 762 // Verify that ephemeral apps will have no ability to retain file entries after | |
| 763 // close. Normal retainEntry behavior for installed apps is tested in | |
| 764 // FileSystemApiTest. | |
| 765 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 766 DisableRetainFileSystemEntries) { | |
| 767 // Create a dummy file that we can just return to the test. | |
| 768 base::ScopedTempDir temp_dir; | |
| 769 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 770 base::FilePath temp_file; | |
| 771 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file)); | |
| 772 | |
| 773 using extensions::FileSystemChooseEntryFunction; | |
| 774 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( | |
| 775 &temp_file); | |
| 776 // The temporary file needs to be registered for the tests to pass on | |
| 777 // ChromeOS. | |
| 778 FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( | |
| 779 "temp", temp_dir.path()); | |
| 780 | |
| 781 // The first test opens the file and writes the file handle to local storage. | |
| 782 const Extension* app = InstallEphemeralApp(kFileSystemTestApp, | |
| 783 Manifest::UNPACKED); | |
| 784 ASSERT_TRUE(LaunchAppAndRunTest(app, "OpenAndRetainFile")) << message_; | |
| 785 | |
| 786 // Verify that after the app has been closed, all retained entries are | |
| 787 // flushed. | |
| 788 std::vector<apps::SavedFileEntry> file_entries = | |
| 789 apps::SavedFilesService::Get(profile()) | |
| 790 ->GetAllFileEntries(app->id()); | |
| 791 EXPECT_TRUE(file_entries.empty()); | |
| 792 | |
| 793 // The second test verifies that the file cannot be reopened. | |
| 794 ASSERT_TRUE(LaunchAppAndRunTest(app, "RestoreRetainedFile")) << message_; | |
| 795 } | |
| 796 | |
| 797 // Checks the process of launching an ephemeral app and then promoting the app | |
| 798 // while it is running. | |
| 799 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppWhileRunning) { | |
| 800 InitSyncService(); | |
| 801 | |
| 802 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 803 ASSERT_TRUE(app); | |
| 804 | |
| 805 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED); | |
| 806 | |
| 807 // Ensure that the app is not unloaded and disabled after it is closed. | |
| 808 CloseApp(app->id()); | |
| 809 VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED); | |
| 810 } | |
| 811 | |
| 812 // Checks the process of launching an ephemeral app and then promoting the app | |
| 813 // while it is idle. | |
| 814 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppWhileIdle) { | |
| 815 InitSyncService(); | |
| 816 | |
| 817 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 818 ASSERT_TRUE(app); | |
| 819 CloseAppWaitForUnload(app->id()); | |
| 820 VerifyInactiveEphemeralApp(app->id()); | |
| 821 | |
| 822 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED); | |
| 823 } | |
| 824 | |
| 825 // Verifies that promoting an ephemeral app that was disabled due to a | |
| 826 // permissions increase will enable it. | |
| 827 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppAndGrantPermissions) { | |
| 828 InitSyncService(); | |
| 829 | |
| 830 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 831 ASSERT_TRUE(app); | |
| 832 CloseAppWaitForUnload(app->id()); | |
| 833 DisableEphemeralApp(app, Extension::DISABLE_PERMISSIONS_INCREASE); | |
| 834 | |
| 835 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED); | |
| 836 EXPECT_FALSE(ExtensionPrefs::Get(profile()) | |
| 837 ->DidExtensionEscalatePermissions(app->id())); | |
| 838 } | |
| 839 | |
| 840 // Verifies that promoting an ephemeral app that has unsupported requirements | |
| 841 // will not enable it. | |
| 842 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 843 PromoteUnsupportedEphemeralApp) { | |
| 844 InitSyncService(); | |
| 845 | |
| 846 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 847 ASSERT_TRUE(app); | |
| 848 CloseAppWaitForUnload(app->id()); | |
| 849 DisableEphemeralApp(app, Extension::DISABLE_UNSUPPORTED_REQUIREMENT); | |
| 850 | |
| 851 // When promoted to a regular installed app, it should remain disabled. | |
| 852 // However, DISABLE_UNSUPPORTED_REQUIREMENT is not a syncable disable reason, | |
| 853 // so sync should still say "enabled". | |
| 854 bool expect_sync_enabled = true; | |
| 855 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::DISABLED, | |
| 856 expect_sync_enabled); | |
| 857 } | |
| 858 | |
| 859 // Verifies that promoting an ephemeral app that is blacklisted will not enable | |
| 860 // it. | |
| 861 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 862 PromoteBlacklistedEphemeralApp) { | |
| 863 InitSyncService(); | |
| 864 | |
| 865 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 866 ASSERT_TRUE(app); | |
| 867 CloseAppWaitForUnload(app->id()); | |
| 868 | |
| 869 ExtensionService* service = | |
| 870 ExtensionSystem::Get(profile())->extension_service(); | |
| 871 service->BlacklistExtensionForTest(app->id()); | |
| 872 ASSERT_TRUE( | |
| 873 ExtensionRegistry::Get(profile())->blacklisted_extensions().Contains( | |
| 874 app->id())); | |
| 875 | |
| 876 // When promoted to a regular installed app, it should remain blacklisted. | |
| 877 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::BLACKLISTED); | |
| 878 | |
| 879 // The app should be synced, but disabled. | |
| 880 scoped_ptr<ExtensionSyncData> sync_change = | |
| 881 GetLastSyncChangeForApp(app->id()); | |
| 882 VerifySyncChange(sync_change.get(), false); | |
| 883 } | |
| 884 | |
| 885 // Checks the process of promoting an ephemeral app from sync while the app is | |
| 886 // running. | |
| 887 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 888 PromoteAppFromSyncWhileRunning) { | |
| 889 InitSyncService(); | |
| 890 | |
| 891 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 892 ASSERT_TRUE(app); | |
| 893 | |
| 894 PromoteEphemeralAppFromSyncAndVerify(app, true, ExtensionRegistry::ENABLED); | |
| 895 | |
| 896 // Ensure that the app is not unloaded and disabled after it is closed. | |
| 897 CloseApp(app->id()); | |
| 898 VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED); | |
| 899 } | |
| 900 | |
| 901 // Checks the process of promoting an ephemeral app from sync while the app is | |
| 902 // idle. | |
| 903 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppFromSyncWhileIdle) { | |
| 904 InitSyncService(); | |
| 905 | |
| 906 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 907 ASSERT_TRUE(app); | |
| 908 CloseAppWaitForUnload(app->id()); | |
| 909 VerifyInactiveEphemeralApp(app->id()); | |
| 910 | |
| 911 PromoteEphemeralAppFromSyncAndVerify(app, true, ExtensionRegistry::ENABLED); | |
| 912 } | |
| 913 | |
| 914 // Checks the process of promoting an ephemeral app from sync, where the app | |
| 915 // from sync is disabled, and the ephemeral app is running. | |
| 916 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 917 PromoteDisabledAppFromSyncWhileRunning) { | |
| 918 InitSyncService(); | |
| 919 | |
| 920 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 921 ASSERT_TRUE(app); | |
| 922 | |
| 923 PromoteEphemeralAppFromSyncAndVerify(app, false, ExtensionRegistry::DISABLED); | |
| 924 } | |
| 925 | |
| 926 // Checks the process of promoting an ephemeral app from sync, where the app | |
| 927 // from sync is disabled, and the ephemeral app is idle. | |
| 928 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 929 PromoteDisabledAppFromSyncWhileIdle) { | |
| 930 InitSyncService(); | |
| 931 | |
| 932 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 933 ASSERT_TRUE(app); | |
| 934 CloseAppWaitForUnload(app->id()); | |
| 935 VerifyInactiveEphemeralApp(app->id()); | |
| 936 | |
| 937 PromoteEphemeralAppFromSyncAndVerify(app, false, ExtensionRegistry::DISABLED); | |
| 938 } | |
| 939 | |
| 940 // In most cases, ExtensionService::PromoteEphemeralApp() will be called to | |
| 941 // permanently install an ephemeral app. However, there may be cases where an | |
| 942 // install occurs through the usual route of installing from the Web Store (due | |
| 943 // to race conditions). Ensure that the app is still installed correctly. | |
| 944 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 945 ReplaceEphemeralAppWithInstalledApp) { | |
| 946 InitSyncService(); | |
| 947 | |
| 948 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 949 ASSERT_TRUE(app); | |
| 950 CloseAppWaitForUnload(app->id()); | |
| 951 std::string app_id = app->id(); | |
| 952 app = NULL; | |
| 953 | |
| 954 InstallObserver installed_observer(profile()); | |
| 955 ReplaceEphemeralApp(app_id, kNotificationsTestApp, 1); | |
| 956 VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED); | |
| 957 | |
| 958 // Check the notification parameters. | |
| 959 const InstallObserver::InstallParameters& params = installed_observer.Last(); | |
| 960 EXPECT_EQ(app_id, params.id); | |
| 961 EXPECT_TRUE(params.is_update); | |
| 962 EXPECT_TRUE(params.from_ephemeral); | |
| 963 } | |
| 964 | |
| 965 // This is similar to ReplaceEphemeralAppWithInstalledApp, but installs will | |
| 966 // be delayed until the app is idle. | |
| 967 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 968 ReplaceEphemeralAppWithDelayedInstalledApp) { | |
| 969 InitSyncService(); | |
| 970 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); | |
| 971 ASSERT_TRUE(app); | |
| 972 std::string app_id = app->id(); | |
| 973 app = NULL; | |
| 974 | |
| 975 // Initiate install. | |
| 976 ReplaceEphemeralApp(app_id, kNotificationsTestApp, 0); | |
| 977 | |
| 978 // The delayed installation will occur when the ephemeral app is closed. | |
| 979 extensions::TestExtensionRegistryObserver observer( | |
| 980 ExtensionRegistry::Get(profile()), app_id); | |
| 981 InstallObserver installed_observer(profile()); | |
| 982 CloseAppWaitForUnload(app_id); | |
| 983 observer.WaitForExtensionWillBeInstalled(); | |
| 984 VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED); | |
| 985 | |
| 986 // Check the notification parameters. | |
| 987 const InstallObserver::InstallParameters& params = installed_observer.Last(); | |
| 988 EXPECT_EQ(app_id, params.id); | |
| 989 EXPECT_TRUE(params.is_update); | |
| 990 EXPECT_TRUE(params.from_ephemeral); | |
| 991 } | |
| 992 | |
| 993 // Verifies that an installed app cannot turn into an ephemeral app as result of | |
| 994 // race conditions, i.e. an ephemeral app can be promoted to an installed app, | |
| 995 // but not vice versa. | |
| 996 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 997 ReplaceInstalledAppWithEphemeralApp) { | |
| 998 const Extension* app = InstallPlatformApp(kNotificationsTestApp); | |
| 999 ASSERT_TRUE(app); | |
| 1000 std::string app_id = app->id(); | |
| 1001 app = NULL; | |
| 1002 | |
| 1003 EXPECT_FALSE(extensions::util::IsEphemeralApp(app_id, profile())); | |
| 1004 app = | |
| 1005 InstallEphemeralAppWithSourceAndFlags(GetTestPath(kNotificationsTestApp), | |
| 1006 0, | |
| 1007 Manifest::INTERNAL, | |
| 1008 Extension::NO_FLAGS); | |
| 1009 EXPECT_FALSE(extensions::util::IsEphemeralApp(app_id, profile())); | |
| 1010 } | |
| 1011 | |
| 1012 // Ephemerality was previously encoded by the Extension::IS_EPHEMERAL creation | |
| 1013 // flag. This was changed to an "ephemeral_app" property. Check that the prefs | |
| 1014 // are handled correctly. | |
| 1015 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, | |
| 1016 ExtensionPrefBackcompatibility) { | |
| 1017 // Ensure that apps with the old prefs are recognized as ephemeral. | |
| 1018 const Extension* app = | |
| 1019 InstallExtensionWithSourceAndFlags(GetTestPath(kNotificationsTestApp), | |
| 1020 1, | |
| 1021 Manifest::INTERNAL, | |
| 1022 Extension::IS_EPHEMERAL); | |
| 1023 ASSERT_TRUE(app); | |
| 1024 EXPECT_TRUE(extensions::util::IsEphemeralApp(app->id(), profile())); | |
| 1025 | |
| 1026 // Ensure that when the app is promoted to an installed app, the bit in the | |
| 1027 // creation flags is cleared. | |
| 1028 PromoteEphemeralApp(app); | |
| 1029 EXPECT_FALSE(extensions::util::IsEphemeralApp(app->id(), profile())); | |
| 1030 | |
| 1031 int creation_flags = | |
| 1032 ExtensionPrefs::Get(profile())->GetCreationFlags(app->id()); | |
| 1033 EXPECT_EQ(0, creation_flags & Extension::IS_EPHEMERAL); | |
| 1034 } | |
| 1035 | |
| 1036 // Verifies that the power keep awake will be automatically released for | |
| 1037 // ephemeral apps that stop running. Well behaved apps should actually call | |
| 1038 // chrome.power.releaseKeepAwake() themselves. | |
| 1039 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, ReleasePowerKeepAwake) { | |
| 1040 PowerSettingsMock power_settings; | |
| 1041 extensions::PowerAPI::Get(profile())->SetCreateBlockerFunctionForTesting( | |
| 1042 base::Bind(&PowerSaveBlockerStub::Create, &power_settings)); | |
| 1043 | |
| 1044 const Extension* app = InstallAndLaunchEphemeralApp(kPowerTestApp); | |
| 1045 ASSERT_TRUE(app); | |
| 1046 EXPECT_EQ(1, power_settings.keep_awake_count()); | |
| 1047 | |
| 1048 CloseAppWaitForUnload(app->id()); | |
| 1049 | |
| 1050 EXPECT_EQ(0, power_settings.keep_awake_count()); | |
| 1051 } | |
| OLD | NEW |