1 // Copyright (c) 2011 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/command_line.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "base/message_loop/message_loop.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/background/background_mode_manager.h" 10 #include "chrome/browser/browser_shutdown.h" 11 #include "chrome/browser/extensions/extension_function_test_utils.h" 12 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/test_extension_system.h" 14 #include "chrome/browser/lifetime/application_lifetime.h" 15 #include "chrome/browser/profiles/profile_info_cache.h" 16 #include "chrome/browser/status_icons/status_icon_menu_model.h" 17 #include "chrome/common/chrome_switches.h" 18 #include "chrome/test/base/testing_browser_process.h" 19 #include "chrome/test/base/testing_profile.h" 20 #include "chrome/test/base/testing_profile_manager.h" 21 #include "content/public/test/test_browser_thread_bundle.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 #include "ui/gfx/image/image.h" 24 #include "ui/gfx/image/image_unittest_util.h" 25 #include "ui/message_center/message_center.h" 26 27 #if defined(OS_CHROMEOS) 28 #include "chrome/browser/chromeos/login/users/user_manager.h" 29 #include "chrome/browser/chromeos/settings/cros_settings.h" 30 #include "chrome/browser/chromeos/settings/device_settings_service.h" 31 #endif 32 33 class BackgroundModeManagerTest : public testing::Test { 34 public: 35 BackgroundModeManagerTest() {} 36 virtual ~BackgroundModeManagerTest() {} 37 virtual void SetUp() { 38 command_line_.reset(new CommandLine(CommandLine::NO_PROGRAM)); 39 } 40 scoped_ptr<CommandLine> command_line_; 41 42 protected: 43 scoped_refptr<extensions::Extension> CreateExtension( 44 extensions::Manifest::Location location, 45 const std::string& data, 46 const std::string& id) { 47 scoped_ptr<base::DictionaryValue> parsed_manifest( 48 extension_function_test_utils::ParseDictionary(data)); 49 return extension_function_test_utils::CreateExtension( 50 location, 51 parsed_manifest.get(), 52 id); 53 } 54 55 scoped_ptr<TestingProfileManager> CreateTestingProfileManager() { 56 scoped_ptr<TestingProfileManager> profile_manager 57 (new TestingProfileManager(TestingBrowserProcess::GetGlobal())); 58 EXPECT_TRUE(profile_manager->SetUp()); 59 return profile_manager.Pass(); 60 } 61 62 // From views::MenuModelAdapter::IsCommandEnabled with modification. 63 bool IsCommandEnabled(ui::MenuModel* model, int id) const { 64 int index = 0; 65 if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 66 return model->IsEnabledAt(index); 67 68 return false; 69 } 70 71 private: 72 DISALLOW_COPY_AND_ASSIGN(BackgroundModeManagerTest); 73 }; 74 75 class TestBackgroundModeManager : public BackgroundModeManager { 76 public: 77 TestBackgroundModeManager( 78 CommandLine* command_line, ProfileInfoCache* cache, bool enabled) 79 : BackgroundModeManager(command_line, cache), 80 enabled_(enabled), 81 app_count_(0), 82 profile_app_count_(0), 83 have_status_tray_(false), 84 launch_on_startup_(false) { 85 ResumeBackgroundMode(); 86 } 87 virtual void EnableLaunchOnStartup(bool launch) OVERRIDE { 88 launch_on_startup_ = launch; 89 } 90 virtual void DisplayAppInstalledNotification( 91 const extensions::Extension* extension) OVERRIDE {} 92 virtual void CreateStatusTrayIcon() OVERRIDE { have_status_tray_ = true; } 93 virtual void RemoveStatusTrayIcon() OVERRIDE { have_status_tray_ = false; } 94 virtual int GetBackgroundAppCount() const OVERRIDE { return app_count_; } 95 virtual int GetBackgroundAppCountForProfile( 96 Profile* const profile) const OVERRIDE { 97 return profile_app_count_; 98 } 99 virtual bool IsBackgroundModePrefEnabled() const OVERRIDE { return enabled_; } 100 void SetBackgroundAppCount(int count) { app_count_ = count; } 101 void SetBackgroundAppCountForProfile(int count) { 102 profile_app_count_ = count; 103 } 104 void SetEnabled(bool enabled) { 105 enabled_ = enabled; 106 OnBackgroundModeEnabledPrefChanged(); 107 } 108 bool HaveStatusTray() const { return have_status_tray_; } 109 bool IsLaunchOnStartup() const { return launch_on_startup_; } 110 private: 111 bool enabled_; 112 int app_count_; 113 int profile_app_count_; 114 115 // Flags to track whether we are launching on startup/have a status tray. 116 bool have_status_tray_; 117 bool launch_on_startup_; 118 }; 119 120 class TestStatusIcon : public StatusIcon { 121 virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE {} 122 virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE {} 123 virtual void SetToolTip(const base::string16& tool_tip) OVERRIDE {} 124 virtual void DisplayBalloon(const gfx::ImageSkia& icon, 125 const base::string16& title, 126 const base::string16& contents) OVERRIDE {} 127 virtual void UpdatePlatformContextMenu( 128 StatusIconMenuModel* menu) OVERRIDE {} 129 }; 130 131 static void AssertBackgroundModeActive( 132 const TestBackgroundModeManager& manager) { 133 EXPECT_TRUE(chrome::WillKeepAlive()); 134 EXPECT_TRUE(manager.HaveStatusTray()); 135 EXPECT_TRUE(manager.IsLaunchOnStartup()); 136 } 137 138 static void AssertBackgroundModeInactive( 139 const TestBackgroundModeManager& manager) { 140 EXPECT_FALSE(chrome::WillKeepAlive()); 141 EXPECT_FALSE(manager.HaveStatusTray()); 142 EXPECT_FALSE(manager.IsLaunchOnStartup()); 143 } 144 145 static void AssertBackgroundModeSuspended( 146 const TestBackgroundModeManager& manager) { 147 EXPECT_FALSE(chrome::WillKeepAlive()); 148 EXPECT_FALSE(manager.HaveStatusTray()); 149 EXPECT_TRUE(manager.IsLaunchOnStartup()); 150 } 151 152 TEST_F(BackgroundModeManagerTest, BackgroundAppLoadUnload) { 153 scoped_ptr<TestingProfileManager> profile_manager = 154 CreateTestingProfileManager(); 155 TestingProfile* profile = profile_manager->CreateTestingProfile("p1"); 156 TestBackgroundModeManager manager( 157 command_line_.get(), profile_manager->profile_info_cache(), true); 158 manager.RegisterProfile(profile); 159 EXPECT_FALSE(chrome::WillKeepAlive()); 160 161 // Mimic app load. 162 manager.OnBackgroundAppInstalled(NULL); 163 manager.SetBackgroundAppCount(1); 164 manager.OnApplicationListChanged(profile); 165 AssertBackgroundModeActive(manager); 166 167 manager.SuspendBackgroundMode(); 168 AssertBackgroundModeSuspended(manager); 169 manager.ResumeBackgroundMode(); 170 171 // Mimic app unload. 172 manager.SetBackgroundAppCount(0); 173 manager.OnApplicationListChanged(profile); 174 AssertBackgroundModeInactive(manager); 175 176 manager.SuspendBackgroundMode(); 177 AssertBackgroundModeInactive(manager); 178 179 // Mimic app load while suspended, e.g. from sync. This should enable and 180 // resume background mode. 181 manager.OnBackgroundAppInstalled(NULL); 182 manager.SetBackgroundAppCount(1); 183 manager.OnApplicationListChanged(profile); 184 AssertBackgroundModeActive(manager); 185 } 186 187 // App installs while background mode is disabled should do nothing. 188 TEST_F(BackgroundModeManagerTest, BackgroundAppInstallUninstallWhileDisabled) { 189 scoped_ptr<TestingProfileManager> profile_manager = 190 CreateTestingProfileManager(); 191 TestingProfile* profile = profile_manager->CreateTestingProfile("p1"); 192 TestBackgroundModeManager manager( 193 command_line_.get(), profile_manager->profile_info_cache(), true); 194 manager.RegisterProfile(profile); 195 // Turn off background mode. 196 manager.SetEnabled(false); 197 manager.DisableBackgroundMode(); 198 AssertBackgroundModeInactive(manager); 199 200 // Status tray icons will not be created, launch on startup status will not 201 // be modified. 202 manager.OnBackgroundAppInstalled(NULL); 203 manager.SetBackgroundAppCount(1); 204 manager.OnApplicationListChanged(profile); 205 AssertBackgroundModeInactive(manager); 206 207 manager.SetBackgroundAppCount(0); 208 manager.OnApplicationListChanged(profile); 209 AssertBackgroundModeInactive(manager); 210 211 // Re-enable background mode. 212 manager.SetEnabled(true); 213 manager.EnableBackgroundMode(); 214 AssertBackgroundModeInactive(manager); 215 } 216 217 218 // App installs while disabled should do nothing until background mode is 219 // enabled.. 220 TEST_F(BackgroundModeManagerTest, EnableAfterBackgroundAppInstall) { 221 scoped_ptr<TestingProfileManager> profile_manager = 222 CreateTestingProfileManager(); 223 TestingProfile* profile = profile_manager->CreateTestingProfile("p1"); 224 TestBackgroundModeManager manager( 225 command_line_.get(), profile_manager->profile_info_cache(), true); 226 manager.RegisterProfile(profile); 227 228 // Install app, should show status tray icon. 229 manager.OnBackgroundAppInstalled(NULL); 230 // OnBackgroundAppInstalled does not actually add an app to the 231 // BackgroundApplicationListModel which would result in another 232 // call to CreateStatusTray. 233 manager.SetBackgroundAppCount(1); 234 manager.OnApplicationListChanged(profile); 235 AssertBackgroundModeActive(manager); 236 237 // Turn off background mode - should hide status tray icon. 238 manager.SetEnabled(false); 239 manager.DisableBackgroundMode(); 240 AssertBackgroundModeInactive(manager); 241 242 // Turn back on background mode - again, no status tray icon 243 // will show up since we didn't actually add anything to the list. 244 manager.SetEnabled(true); 245 manager.EnableBackgroundMode(); 246 AssertBackgroundModeActive(manager); 247 248 // Uninstall app, should hide status tray icon again. 249 manager.SetBackgroundAppCount(0); 250 manager.OnApplicationListChanged(profile); 251 AssertBackgroundModeInactive(manager); 252 } 253 254 TEST_F(BackgroundModeManagerTest, MultiProfile) { 255 scoped_ptr<TestingProfileManager> profile_manager = 256 CreateTestingProfileManager(); 257 TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1"); 258 TestingProfile* profile2 = profile_manager->CreateTestingProfile("p2"); 259 TestBackgroundModeManager manager( 260 command_line_.get(), profile_manager->profile_info_cache(), true); 261 manager.RegisterProfile(profile1); 262 manager.RegisterProfile(profile2); 263 EXPECT_FALSE(chrome::WillKeepAlive()); 264 265 // Install app, should show status tray icon. 266 manager.OnBackgroundAppInstalled(NULL); 267 manager.SetBackgroundAppCount(1); 268 manager.OnApplicationListChanged(profile1); 269 AssertBackgroundModeActive(manager); 270 271 // Install app for other profile, hsould show other status tray icon. 272 manager.OnBackgroundAppInstalled(NULL); 273 manager.SetBackgroundAppCount(2); 274 manager.OnApplicationListChanged(profile2); 275 AssertBackgroundModeActive(manager); 276 277 // Should hide both status tray icons. 278 manager.SetEnabled(false); 279 manager.DisableBackgroundMode(); 280 AssertBackgroundModeInactive(manager); 281 282 // Turn back on background mode - should show both status tray icons. 283 manager.SetEnabled(true); 284 manager.EnableBackgroundMode(); 285 AssertBackgroundModeActive(manager); 286 287 manager.SetBackgroundAppCount(1); 288 manager.OnApplicationListChanged(profile2); 289 // There is still one background app alive 290 AssertBackgroundModeActive(manager); 291 292 manager.SetBackgroundAppCount(0); 293 manager.OnApplicationListChanged(profile1); 294 AssertBackgroundModeInactive(manager); 295 } 296 297 TEST_F(BackgroundModeManagerTest, ProfileInfoCacheStorage) { 298 scoped_ptr<TestingProfileManager> profile_manager = 299 CreateTestingProfileManager(); 300 TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1"); 301 TestingProfile* profile2 = profile_manager->CreateTestingProfile("p2"); 302 TestBackgroundModeManager manager( 303 command_line_.get(), profile_manager->profile_info_cache(), true); 304 manager.RegisterProfile(profile1); 305 manager.RegisterProfile(profile2); 306 EXPECT_FALSE(chrome::WillKeepAlive()); 307 308 ProfileInfoCache* cache = profile_manager->profile_info_cache(); 309 EXPECT_EQ(2u, cache->GetNumberOfProfiles()); 310 311 EXPECT_FALSE(cache->GetBackgroundStatusOfProfileAtIndex(0)); 312 EXPECT_FALSE(cache->GetBackgroundStatusOfProfileAtIndex(1)); 313 314 // Install app, should show status tray icon. 315 manager.OnBackgroundAppInstalled(NULL); 316 manager.SetBackgroundAppCount(1); 317 manager.SetBackgroundAppCountForProfile(1); 318 manager.OnApplicationListChanged(profile1); 319 320 // Install app for other profile. 321 manager.OnBackgroundAppInstalled(NULL); 322 manager.SetBackgroundAppCount(1); 323 manager.SetBackgroundAppCountForProfile(1); 324 manager.OnApplicationListChanged(profile2); 325 326 EXPECT_TRUE(cache->GetBackgroundStatusOfProfileAtIndex(0)); 327 EXPECT_TRUE(cache->GetBackgroundStatusOfProfileAtIndex(1)); 328 329 manager.SetBackgroundAppCountForProfile(0); 330 manager.OnApplicationListChanged(profile1); 331 332 size_t p1_index = cache->GetIndexOfProfileWithPath(profile1->GetPath()); 333 EXPECT_FALSE(cache->GetBackgroundStatusOfProfileAtIndex(p1_index)); 334 335 manager.SetBackgroundAppCountForProfile(0); 336 manager.OnApplicationListChanged(profile2); 337 338 size_t p2_index = cache->GetIndexOfProfileWithPath(profile1->GetPath()); 339 EXPECT_FALSE(cache->GetBackgroundStatusOfProfileAtIndex(p2_index)); 340 341 // Even though neither has background status on, there should still be two 342 // profiles in the cache. 343 EXPECT_EQ(2u, cache->GetNumberOfProfiles()); 344 } 345 346 TEST_F(BackgroundModeManagerTest, ProfileInfoCacheObserver) { 347 scoped_ptr<TestingProfileManager> profile_manager = 348 CreateTestingProfileManager(); 349 TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1"); 350 TestBackgroundModeManager manager( 351 command_line_.get(), profile_manager->profile_info_cache(), true); 352 manager.RegisterProfile(profile1); 353 EXPECT_FALSE(chrome::WillKeepAlive()); 354 355 // Install app, should show status tray icon. 356 manager.OnBackgroundAppInstalled(NULL); 357 manager.SetBackgroundAppCount(1); 358 manager.SetBackgroundAppCountForProfile(1); 359 manager.OnApplicationListChanged(profile1); 360 361 manager.OnProfileNameChanged( 362 profile1->GetPath(), 363 manager.GetBackgroundModeData(profile1)->name()); 364 365 EXPECT_EQ(base::UTF8ToUTF16("p1"), 366 manager.GetBackgroundModeData(profile1)->name()); 367 368 EXPECT_TRUE(chrome::WillKeepAlive()); 369 TestingProfile* profile2 = profile_manager->CreateTestingProfile("p2"); 370 manager.RegisterProfile(profile2); 371 EXPECT_EQ(2, manager.NumberOfBackgroundModeData()); 372 373 manager.OnProfileAdded(profile2->GetPath()); 374 EXPECT_EQ(base::UTF8ToUTF16("p2"), 375 manager.GetBackgroundModeData(profile2)->name()); 376 377 manager.OnProfileWillBeRemoved(profile2->GetPath()); 378 // Should still be in background mode after deleting profile. 379 EXPECT_TRUE(chrome::WillKeepAlive()); 380 EXPECT_EQ(1, manager.NumberOfBackgroundModeData()); 381 382 // Check that the background mode data we think is in the map actually is. 383 EXPECT_EQ(base::UTF8ToUTF16("p1"), 384 manager.GetBackgroundModeData(profile1)->name()); 385 } 386 387 TEST_F(BackgroundModeManagerTest, DeleteBackgroundProfile) { 388 // Tests whether deleting the only profile when it is a BG profile works 389 // or not (http://crbug.com/346214). 390 scoped_ptr<TestingProfileManager> profile_manager = 391 CreateTestingProfileManager(); 392 TestingProfile* profile = profile_manager->CreateTestingProfile("p1"); 393 TestBackgroundModeManager manager( 394 command_line_.get(), profile_manager->profile_info_cache(), true); 395 manager.RegisterProfile(profile); 396 EXPECT_FALSE(chrome::WillKeepAlive()); 397 398 // Install app, should show status tray icon. 399 manager.OnBackgroundAppInstalled(NULL); 400 manager.SetBackgroundAppCount(1); 401 manager.SetBackgroundAppCountForProfile(1); 402 manager.OnApplicationListChanged(profile); 403 404 manager.OnProfileNameChanged( 405 profile->GetPath(), 406 manager.GetBackgroundModeData(profile)->name()); 407 408 EXPECT_TRUE(chrome::WillKeepAlive()); 409 manager.SetBackgroundAppCount(0); 410 manager.SetBackgroundAppCountForProfile(0); 411 manager.OnProfileWillBeRemoved(profile->GetPath()); 412 EXPECT_FALSE(chrome::WillKeepAlive()); 413 } 414 415 TEST_F(BackgroundModeManagerTest, DisableBackgroundModeUnderTestFlag) { 416 scoped_ptr<TestingProfileManager> profile_manager = 417 CreateTestingProfileManager(); 418 TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1"); 419 command_line_->AppendSwitch(switches::kKeepAliveForTest); 420 TestBackgroundModeManager manager( 421 command_line_.get(), profile_manager->profile_info_cache(), true); 422 manager.RegisterProfile(profile1); 423 EXPECT_TRUE(manager.ShouldBeInBackgroundMode()); 424 manager.SetEnabled(false); 425 EXPECT_FALSE(manager.ShouldBeInBackgroundMode()); 426 } 427 428 TEST_F(BackgroundModeManagerTest, 429 BackgroundModeDisabledPreventsKeepAliveOnStartup) { 430 scoped_ptr<TestingProfileManager> profile_manager = 431 CreateTestingProfileManager(); 432 TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1"); 433 command_line_->AppendSwitch(switches::kKeepAliveForTest); 434 TestBackgroundModeManager manager( 435 command_line_.get(), profile_manager->profile_info_cache(), false); 436 manager.RegisterProfile(profile1); 437 EXPECT_FALSE(manager.ShouldBeInBackgroundMode()); 438 } 439 440 TEST_F(BackgroundModeManagerTest, BackgroundMenuGeneration) { 441 // Aura clears notifications from the message center at shutdown. 442 message_center::MessageCenter::Initialize(); 443 444 // Required for extension service. 445 content::TestBrowserThreadBundle thread_bundle; 446 447 scoped_ptr<TestingProfileManager> profile_manager = 448 CreateTestingProfileManager(); 449 450 // BackgroundModeManager actually affects Chrome start/stop state, 451 // tearing down our thread bundle before we've had chance to clean 452 // everything up. Keeping Chrome alive prevents this. 453 // We aren't interested in if the keep alive works correctly in this test. 454 chrome::IncrementKeepAliveCount(); 455 TestingProfile* profile = profile_manager->CreateTestingProfile("p"); 456 457 #if defined(OS_CHROMEOS) 458 // ChromeOS needs extra services to run in the following order. 459 chromeos::ScopedTestDeviceSettingsService test_device_settings_service; 460 chromeos::ScopedTestCrosSettings test_cros_settings; 461 chromeos::ScopedTestUserManager test_user_manager; 462 463 // On ChromeOS shutdown, HandleAppExitingForPlatform will call 464 // chrome::DecrementKeepAliveCount because it assumes the aura shell 465 // called chrome::IncrementKeepAliveCount. Simulate the call here. 466 chrome::IncrementKeepAliveCount(); 467 #endif 468 469 scoped_refptr<extensions::Extension> component_extension( 470 CreateExtension( 471 extensions::Manifest::COMPONENT, 472 "{\"name\": \"Component Extension\"," 473 "\"version\": \"1.0\"," 474 "\"manifest_version\": 2," 475 "\"permissions\": [\"background\"]}", 476 "ID-1")); 477 478 scoped_refptr<extensions::Extension> component_extension_with_options( 479 CreateExtension( 480 extensions::Manifest::COMPONENT, 481 "{\"name\": \"Component Extension with Options\"," 482 "\"version\": \"1.0\"," 483 "\"manifest_version\": 2," 484 "\"permissions\": [\"background\"]," 485 "\"options_page\": \"test.html\"}", 486 "ID-2")); 487 488 scoped_refptr<extensions::Extension> regular_extension( 489 CreateExtension( 490 extensions::Manifest::COMMAND_LINE, 491 "{\"name\": \"Regular Extension\", " 492 "\"version\": \"1.0\"," 493 "\"manifest_version\": 2," 494 "\"permissions\": [\"background\"]}", 495 "ID-3")); 496 497 scoped_refptr<extensions::Extension> regular_extension_with_options( 498 CreateExtension( 499 extensions::Manifest::COMMAND_LINE, 500 "{\"name\": \"Regular Extension with Options\"," 501 "\"version\": \"1.0\"," 502 "\"manifest_version\": 2," 503 "\"permissions\": [\"background\"]," 504 "\"options_page\": \"test.html\"}", 505 "ID-4")); 506 507 static_cast<extensions::TestExtensionSystem*>( 508 extensions::ExtensionSystem::Get(profile))->CreateExtensionService( 509 CommandLine::ForCurrentProcess(), 510 base::FilePath(), 511 false); 512 ExtensionService* service = profile->GetExtensionService(); 513 service->Init(); 514 515 service->AddComponentExtension(component_extension); 516 service->AddComponentExtension(component_extension_with_options); 517 service->AddExtension(regular_extension); 518 service->AddExtension(regular_extension_with_options); 519 520 scoped_ptr<TestBackgroundModeManager> manager(new TestBackgroundModeManager( 521 command_line_.get(), profile_manager->profile_info_cache(), true)); 522 manager->RegisterProfile(profile); 523 524 scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(NULL)); 525 scoped_ptr<StatusIconMenuModel> submenu(new StatusIconMenuModel(NULL)); 526 BackgroundModeManager::BackgroundModeData* bmd = 527 manager->GetBackgroundModeData(profile); 528 bmd->BuildProfileMenu(submenu.get(), menu.get()); 529 EXPECT_TRUE( 530 submenu->GetLabelAt(0) == 531 base::UTF8ToUTF16("Component Extension")); 532 EXPECT_FALSE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(0))); 533 EXPECT_TRUE( 534 submenu->GetLabelAt(1) == 535 base::UTF8ToUTF16("Component Extension with Options")); 536 EXPECT_TRUE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(1))); 537 EXPECT_TRUE( 538 submenu->GetLabelAt(2) == 539 base::UTF8ToUTF16("Regular Extension")); 540 EXPECT_TRUE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(2))); 541 EXPECT_TRUE( 542 submenu->GetLabelAt(3) == 543 base::UTF8ToUTF16("Regular Extension with Options")); 544 EXPECT_TRUE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(3))); 545 546 // We have to destroy the profile now because we created it with real thread 547 // state. This causes a lot of machinery to spin up that stops working 548 // when we tear down our thread state at the end of the test. 549 profile_manager->DeleteTestingProfile("p"); 550 551 // We're getting ready to shutdown the message loop. Clear everything out! 552 base::MessageLoop::current()->RunUntilIdle(); 553 chrome::DecrementKeepAliveCount(); // Matching the above 554 // chrome::IncrementKeepAliveCount(). 555 556 // TestBackgroundModeManager has dependencies on the infrastructure. 557 // It should get cleared first. 558 manager.reset(); 559 560 // The Profile Manager references the Browser Process. 561 // The Browser Process references the Notification UI Manager. 562 // The Notification UI Manager references the Message Center. 563 // As a result, we have to clear the browser process state here 564 // before tearing down the Message Center. 565 profile_manager.reset(); 566 567 // Message Center shutdown must occur after the DecrementKeepAliveCount 568 // because DecrementKeepAliveCount will end up referencing the message 569 // center during cleanup. 570 message_center::MessageCenter::Shutdown(); 571 572 // Clear the shutdown flag to isolate the remaining effect of this test. 573 browser_shutdown::SetTryingToQuit(false); 574 } 575 576 TEST_F(BackgroundModeManagerTest, BackgroundMenuGenerationMultipleProfile) { 577 // Aura clears notifications from the message center at shutdown. 578 message_center::MessageCenter::Initialize(); 579 580 // Required for extension service. 581 content::TestBrowserThreadBundle thread_bundle; 582 583 scoped_ptr<TestingProfileManager> profile_manager = 584 CreateTestingProfileManager(); 585 586 // BackgroundModeManager actually affects Chrome start/stop state, 587 // tearing down our thread bundle before we've had chance to clean 588 // everything up. Keeping Chrome alive prevents this. 589 // We aren't interested in if the keep alive works correctly in this test. 590 chrome::IncrementKeepAliveCount(); 591 TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1"); 592 TestingProfile* profile2 = profile_manager->CreateTestingProfile("p2"); 593 594 #if defined(OS_CHROMEOS) 595 // ChromeOS needs extensionsra services to run in the following order. 596 chromeos::ScopedTestDeviceSettingsService test_device_settings_service; 597 chromeos::ScopedTestCrosSettings test_cros_settings; 598 chromeos::ScopedTestUserManager test_user_manager; 599 600 // On ChromeOS shutdown, HandleAppExitingForPlatform will call 601 // chrome::DecrementKeepAliveCount because it assumes the aura shell 602 // called chrome::IncrementKeepAliveCount. Simulate the call here. 603 chrome::IncrementKeepAliveCount(); 604 #endif 605 606 scoped_refptr<extensions::Extension> component_extension( 607 CreateExtension( 608 extensions::Manifest::COMPONENT, 609 "{\"name\": \"Component Extension\"," 610 "\"version\": \"1.0\"," 611 "\"manifest_version\": 2," 612 "\"permissions\": [\"background\"]}", 613 "ID-1")); 614 615 scoped_refptr<extensions::Extension> component_extension_with_options( 616 CreateExtension( 617 extensions::Manifest::COMPONENT, 618 "{\"name\": \"Component Extension with Options\"," 619 "\"version\": \"1.0\"," 620 "\"manifest_version\": 2," 621 "\"permissions\": [\"background\"]," 622 "\"options_page\": \"test.html\"}", 623 "ID-2")); 624 625 scoped_refptr<extensions::Extension> regular_extension( 626 CreateExtension( 627 extensions::Manifest::COMMAND_LINE, 628 "{\"name\": \"Regular Extension\", " 629 "\"version\": \"1.0\"," 630 "\"manifest_version\": 2," 631 "\"permissions\": [\"background\"]}", 632 "ID-3")); 633 634 scoped_refptr<extensions::Extension> regular_extension_with_options( 635 CreateExtension( 636 extensions::Manifest::COMMAND_LINE, 637 "{\"name\": \"Regular Extension with Options\"," 638 "\"version\": \"1.0\"," 639 "\"manifest_version\": 2," 640 "\"permissions\": [\"background\"]," 641 "\"options_page\": \"test.html\"}", 642 "ID-4")); 643 644 static_cast<extensions::TestExtensionSystem*>( 645 extensions::ExtensionSystem::Get(profile1))->CreateExtensionService( 646 CommandLine::ForCurrentProcess(), 647 base::FilePath(), 648 false); 649 ExtensionService* service1 = profile1->GetExtensionService(); 650 service1->Init(); 651 652 service1->AddComponentExtension(component_extension); 653 service1->AddComponentExtension(component_extension_with_options); 654 service1->AddExtension(regular_extension); 655 service1->AddExtension(regular_extension_with_options); 656 657 static_cast<extensions::TestExtensionSystem*>( 658 extensions::ExtensionSystem::Get(profile2))->CreateExtensionService( 659 CommandLine::ForCurrentProcess(), 660 base::FilePath(), 661 false); 662 ExtensionService* service2 = profile2->GetExtensionService(); 663 service2->Init(); 664 665 service2->AddComponentExtension(component_extension); 666 service2->AddExtension(regular_extension); 667 service2->AddExtension(regular_extension_with_options); 668 669 scoped_ptr<TestBackgroundModeManager> manager(new TestBackgroundModeManager( 670 command_line_.get(), profile_manager->profile_info_cache(), true)); 671 manager->RegisterProfile(profile1); 672 manager->RegisterProfile(profile2); 673 674 manager->status_icon_ = new TestStatusIcon(); 675 manager->UpdateStatusTrayIconContextMenu(); 676 StatusIconMenuModel* context_menu = manager->context_menu_; 677 EXPECT_TRUE(context_menu != NULL); 678 679 // Background Profile Enable Checks 680 EXPECT_TRUE(context_menu->GetLabelAt(3) == base::UTF8ToUTF16("p1")); 681 EXPECT_TRUE( 682 context_menu->IsCommandIdEnabled(context_menu->GetCommandIdAt(3))); 683 EXPECT_TRUE(context_menu->GetCommandIdAt(3) == 4); 684 685 EXPECT_TRUE(context_menu->GetLabelAt(4) == base::UTF8ToUTF16("p2")); 686 EXPECT_TRUE( 687 context_menu->IsCommandIdEnabled(context_menu->GetCommandIdAt(4))); 688 EXPECT_TRUE(context_menu->GetCommandIdAt(4) == 8); 689 690 // Profile 1 Submenu Checks 691 StatusIconMenuModel* profile1_submenu = 692 static_cast<StatusIconMenuModel*>(context_menu->GetSubmenuModelAt(3)); 693 EXPECT_TRUE( 694 profile1_submenu->GetLabelAt(0) == 695 base::UTF8ToUTF16("Component Extension")); 696 EXPECT_FALSE( 697 profile1_submenu->IsCommandIdEnabled( 698 profile1_submenu->GetCommandIdAt(0))); 699 EXPECT_TRUE(profile1_submenu->GetCommandIdAt(0) == 0); 700 EXPECT_TRUE( 701 profile1_submenu->GetLabelAt(1) == 702 base::UTF8ToUTF16("Component Extension with Options")); 703 EXPECT_TRUE( 704 profile1_submenu->IsCommandIdEnabled( 705 profile1_submenu->GetCommandIdAt(1))); 706 EXPECT_TRUE(profile1_submenu->GetCommandIdAt(1) == 1); 707 EXPECT_TRUE( 708 profile1_submenu->GetLabelAt(2) == 709 base::UTF8ToUTF16("Regular Extension")); 710 EXPECT_TRUE( 711 profile1_submenu->IsCommandIdEnabled( 712 profile1_submenu->GetCommandIdAt(2))); 713 EXPECT_TRUE(profile1_submenu->GetCommandIdAt(2) == 2); 714 EXPECT_TRUE( 715 profile1_submenu->GetLabelAt(3) == 716 base::UTF8ToUTF16("Regular Extension with Options")); 717 EXPECT_TRUE( 718 profile1_submenu->IsCommandIdEnabled( 719 profile1_submenu->GetCommandIdAt(3))); 720 EXPECT_TRUE(profile1_submenu->GetCommandIdAt(3) == 3); 721 722 // Profile 2 Submenu Checks 723 StatusIconMenuModel* profile2_submenu = 724 static_cast<StatusIconMenuModel*>(context_menu->GetSubmenuModelAt(4)); 725 EXPECT_TRUE( 726 profile2_submenu->GetLabelAt(0) == 727 base::UTF8ToUTF16("Component Extension")); 728 EXPECT_FALSE( 729 profile2_submenu->IsCommandIdEnabled( 730 profile2_submenu->GetCommandIdAt(0))); 731 EXPECT_TRUE(profile2_submenu->GetCommandIdAt(0) == 5); 732 EXPECT_TRUE( 733 profile2_submenu->GetLabelAt(1) == 734 base::UTF8ToUTF16("Regular Extension")); 735 EXPECT_TRUE( 736 profile2_submenu->IsCommandIdEnabled( 737 profile2_submenu->GetCommandIdAt(1))); 738 EXPECT_TRUE(profile2_submenu->GetCommandIdAt(1) == 6); 739 EXPECT_TRUE( 740 profile2_submenu->GetLabelAt(2) == 741 base::UTF8ToUTF16("Regular Extension with Options")); 742 EXPECT_TRUE( 743 profile2_submenu->IsCommandIdEnabled( 744 profile2_submenu->GetCommandIdAt(2))); 745 EXPECT_TRUE(profile2_submenu->GetCommandIdAt(2) == 7); 746 747 // Model Adapter Checks for crbug.com/315164 748 // P1: Profile 1 Menu Item 749 // P2: Profile 2 Menu Item 750 // CE: Component Extension Menu Item 751 // CEO: Component Extenison with Options Menu Item 752 // RE: Regular Extension Menu Item 753 // REO: Regular Extension with Options Menu Item 754 EXPECT_FALSE(IsCommandEnabled(context_menu, 0)); // P1 - CE 755 EXPECT_TRUE(IsCommandEnabled(context_menu, 1)); // P1 - CEO 756 EXPECT_TRUE(IsCommandEnabled(context_menu, 2)); // P1 - RE 757 EXPECT_TRUE(IsCommandEnabled(context_menu, 3)); // P1 - REO 758 EXPECT_TRUE(IsCommandEnabled(context_menu, 4)); // P1 759 EXPECT_FALSE(IsCommandEnabled(context_menu, 5)); // P2 - CE 760 EXPECT_TRUE(IsCommandEnabled(context_menu, 6)); // P2 - RE 761 EXPECT_TRUE(IsCommandEnabled(context_menu, 7)); // P2 - REO 762 EXPECT_TRUE(IsCommandEnabled(context_menu, 8)); // P2 763 764 // Clean up the status icon. If this is not done before profile deletes, 765 // the context menu updates will DCHECK with the now deleted profiles. 766 StatusIcon* status_icon = manager->status_icon_; 767 manager->status_icon_ = NULL; 768 delete status_icon; 769 770 // We have to destroy the profiles now because we created them with real 771 // thread state. This causes a lot of machinery to spin up that stops working 772 // when we tear down our thread state at the end of the test. 773 profile_manager->DeleteTestingProfile("p2"); 774 profile_manager->DeleteTestingProfile("p1"); 775 776 // We're getting ready to shutdown the message loop. Clear everything out! 777 base::MessageLoop::current()->RunUntilIdle(); 778 chrome::DecrementKeepAliveCount(); // Matching the above 779 // chrome::IncrementKeepAliveCount(). 780 781 // TestBackgroundModeManager has dependencies on the infrastructure. 782 // It should get cleared first. 783 manager.reset(); 784 785 // The Profile Manager references the Browser Process. 786 // The Browser Process references the Notification UI Manager. 787 // The Notification UI Manager references the Message Center. 788 // As a result, we have to clear the browser process state here 789 // before tearing down the Message Center. 790 profile_manager.reset(); 791 792 // Message Center shutdown must occur after the DecrementKeepAliveCount 793 // because DecrementKeepAliveCount will end up referencing the message 794 // center during cleanup. 795 message_center::MessageCenter::Shutdown(); 796 797 // Clear the shutdown flag to isolate the remaining effect of this test. 798 browser_shutdown::SetTryingToQuit(false); 799 } 800