Home | History | Annotate | Download | only in background
      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/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(UTF8ToUTF16("p1"),
    366             manager.GetBackgroundModeData(profile1)->name());
    367 
    368   TestingProfile* profile2 = profile_manager->CreateTestingProfile("p2");
    369   manager.RegisterProfile(profile2);
    370   EXPECT_EQ(2, manager.NumberOfBackgroundModeData());
    371 
    372   manager.OnProfileAdded(profile2->GetPath());
    373   EXPECT_EQ(UTF8ToUTF16("p2"),
    374             manager.GetBackgroundModeData(profile2)->name());
    375 
    376   manager.OnProfileWillBeRemoved(profile2->GetPath());
    377   EXPECT_EQ(1, manager.NumberOfBackgroundModeData());
    378 
    379   // Check that the background mode data we think is in the map actually is.
    380   EXPECT_EQ(UTF8ToUTF16("p1"),
    381             manager.GetBackgroundModeData(profile1)->name());
    382 }
    383 
    384 TEST_F(BackgroundModeManagerTest, DisableBackgroundModeUnderTestFlag) {
    385   scoped_ptr<TestingProfileManager> profile_manager =
    386       CreateTestingProfileManager();
    387   TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1");
    388   command_line_->AppendSwitch(switches::kKeepAliveForTest);
    389   TestBackgroundModeManager manager(
    390       command_line_.get(), profile_manager->profile_info_cache(), true);
    391   manager.RegisterProfile(profile1);
    392   EXPECT_TRUE(manager.ShouldBeInBackgroundMode());
    393   manager.SetEnabled(false);
    394   EXPECT_FALSE(manager.ShouldBeInBackgroundMode());
    395 }
    396 
    397 TEST_F(BackgroundModeManagerTest,
    398        BackgroundModeDisabledPreventsKeepAliveOnStartup) {
    399   scoped_ptr<TestingProfileManager> profile_manager =
    400       CreateTestingProfileManager();
    401   TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1");
    402   command_line_->AppendSwitch(switches::kKeepAliveForTest);
    403   TestBackgroundModeManager manager(
    404       command_line_.get(), profile_manager->profile_info_cache(), false);
    405   manager.RegisterProfile(profile1);
    406   EXPECT_FALSE(manager.ShouldBeInBackgroundMode());
    407 }
    408 
    409 TEST_F(BackgroundModeManagerTest, BackgroundMenuGeneration) {
    410   // Aura clears notifications from the message center at shutdown.
    411   message_center::MessageCenter::Initialize();
    412 
    413   // Required for extension service.
    414   content::TestBrowserThreadBundle thread_bundle;
    415 
    416   scoped_ptr<TestingProfileManager> profile_manager =
    417       CreateTestingProfileManager();
    418 
    419   // BackgroundModeManager actually affects Chrome start/stop state,
    420   // tearing down our thread bundle before we've had chance to clean
    421   // everything up. Keeping Chrome alive prevents this.
    422   // We aren't interested in if the keep alive works correctly in this test.
    423   chrome::StartKeepAlive();
    424   TestingProfile* profile = profile_manager->CreateTestingProfile("p");
    425 
    426 #if defined(OS_CHROMEOS)
    427   // ChromeOS needs extra services to run in the following order.
    428   chromeos::ScopedTestDeviceSettingsService test_device_settings_service;
    429   chromeos::ScopedTestCrosSettings test_cros_settings;
    430   chromeos::ScopedTestUserManager test_user_manager;
    431 
    432   // On ChromeOS shutdown, HandleAppExitingForPlatform will call
    433   // chrome::EndKeepAlive because it assumes the aura shell
    434   // called chrome::StartKeepAlive. Simulate the call here.
    435   chrome::StartKeepAlive();
    436 #endif
    437 
    438   scoped_refptr<extensions::Extension> component_extension(
    439     CreateExtension(
    440         extensions::Manifest::COMPONENT,
    441         "{\"name\": \"Component Extension\","
    442         "\"version\": \"1.0\","
    443         "\"manifest_version\": 2,"
    444         "\"permissions\": [\"background\"]}",
    445         "ID-1"));
    446 
    447   scoped_refptr<extensions::Extension> component_extension_with_options(
    448     CreateExtension(
    449         extensions::Manifest::COMPONENT,
    450         "{\"name\": \"Component Extension with Options\","
    451         "\"version\": \"1.0\","
    452         "\"manifest_version\": 2,"
    453         "\"permissions\": [\"background\"],"
    454         "\"options_page\": \"test.html\"}",
    455         "ID-2"));
    456 
    457   scoped_refptr<extensions::Extension> regular_extension(
    458     CreateExtension(
    459         extensions::Manifest::COMMAND_LINE,
    460         "{\"name\": \"Regular Extension\", "
    461         "\"version\": \"1.0\","
    462         "\"manifest_version\": 2,"
    463         "\"permissions\": [\"background\"]}",
    464         "ID-3"));
    465 
    466   scoped_refptr<extensions::Extension> regular_extension_with_options(
    467     CreateExtension(
    468         extensions::Manifest::COMMAND_LINE,
    469         "{\"name\": \"Regular Extension with Options\","
    470         "\"version\": \"1.0\","
    471         "\"manifest_version\": 2,"
    472         "\"permissions\": [\"background\"],"
    473         "\"options_page\": \"test.html\"}",
    474         "ID-4"));
    475 
    476   static_cast<extensions::TestExtensionSystem*>(
    477       extensions::ExtensionSystem::Get(profile))->CreateExtensionService(
    478           CommandLine::ForCurrentProcess(),
    479           base::FilePath(),
    480           false);
    481   ExtensionService* service = profile->GetExtensionService();
    482   service->Init();
    483 
    484   service->AddComponentExtension(component_extension);
    485   service->AddComponentExtension(component_extension_with_options);
    486   service->AddExtension(regular_extension);
    487   service->AddExtension(regular_extension_with_options);
    488 
    489   scoped_ptr<TestBackgroundModeManager> manager(new TestBackgroundModeManager(
    490       command_line_.get(), profile_manager->profile_info_cache(), true));
    491   manager->RegisterProfile(profile);
    492 
    493   scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(NULL));
    494   scoped_ptr<StatusIconMenuModel> submenu(new StatusIconMenuModel(NULL));
    495   BackgroundModeManager::BackgroundModeData* bmd =
    496       manager->GetBackgroundModeData(profile);
    497   bmd->BuildProfileMenu(submenu.get(), menu.get());
    498   EXPECT_TRUE(
    499       submenu->GetLabelAt(0) ==
    500           UTF8ToUTF16("Component Extension"));
    501   EXPECT_FALSE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(0)));
    502   EXPECT_TRUE(
    503       submenu->GetLabelAt(1) ==
    504           UTF8ToUTF16("Component Extension with Options"));
    505   EXPECT_TRUE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(1)));
    506   EXPECT_TRUE(
    507       submenu->GetLabelAt(2) ==
    508           UTF8ToUTF16("Regular Extension"));
    509   EXPECT_TRUE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(2)));
    510   EXPECT_TRUE(
    511       submenu->GetLabelAt(3) ==
    512           UTF8ToUTF16("Regular Extension with Options"));
    513   EXPECT_TRUE(submenu->IsCommandIdEnabled(submenu->GetCommandIdAt(3)));
    514 
    515   // We have to destroy the profile now because we created it with real thread
    516   // state. This causes a lot of machinery to spin up that stops working
    517   // when we tear down our thread state at the end of the test.
    518   profile_manager->DeleteTestingProfile("p");
    519 
    520   // We're getting ready to shutdown the message loop. Clear everything out!
    521   base::MessageLoop::current()->RunUntilIdle();
    522   chrome::EndKeepAlive(); // Matching the above chrome::StartKeepAlive().
    523 
    524   // TestBackgroundModeManager has dependencies on the infrastructure.
    525   // It should get cleared first.
    526   manager.reset();
    527 
    528   // The Profile Manager references the Browser Process.
    529   // The Browser Process references the Notification UI Manager.
    530   // The Notification UI Manager references the Message Center.
    531   // As a result, we have to clear the browser process state here
    532   // before tearing down the Message Center.
    533   profile_manager.reset();
    534 
    535   // Message Center shutdown must occur after the EndKeepAlive because
    536   // EndKeepAlive will end up referencing the message center during cleanup.
    537   message_center::MessageCenter::Shutdown();
    538 
    539   // Clear the shutdown flag to isolate the remaining effect of this test.
    540   browser_shutdown::SetTryingToQuit(false);
    541 }
    542 
    543 TEST_F(BackgroundModeManagerTest, BackgroundMenuGenerationMultipleProfile) {
    544   // Aura clears notifications from the message center at shutdown.
    545   message_center::MessageCenter::Initialize();
    546 
    547   // Required for extension service.
    548   content::TestBrowserThreadBundle thread_bundle;
    549 
    550   scoped_ptr<TestingProfileManager> profile_manager =
    551       CreateTestingProfileManager();
    552 
    553   // BackgroundModeManager actually affects Chrome start/stop state,
    554   // tearing down our thread bundle before we've had chance to clean
    555   // everything up. Keeping Chrome alive prevents this.
    556   // We aren't interested in if the keep alive works correctly in this test.
    557   chrome::StartKeepAlive();
    558   TestingProfile* profile1 = profile_manager->CreateTestingProfile("p1");
    559   TestingProfile* profile2 = profile_manager->CreateTestingProfile("p2");
    560 
    561 #if defined(OS_CHROMEOS)
    562   // ChromeOS needs extensionsra services to run in the following order.
    563   chromeos::ScopedTestDeviceSettingsService test_device_settings_service;
    564   chromeos::ScopedTestCrosSettings test_cros_settings;
    565   chromeos::ScopedTestUserManager test_user_manager;
    566 
    567   // On ChromeOS shutdown, HandleAppExitingForPlatform will call
    568   // chrome::EndKeepAlive because it assumes the aura shell
    569   // called chrome::StartKeepAlive. Simulate the call here.
    570   chrome::StartKeepAlive();
    571 #endif
    572 
    573   scoped_refptr<extensions::Extension> component_extension(
    574     CreateExtension(
    575         extensions::Manifest::COMPONENT,
    576         "{\"name\": \"Component Extension\","
    577         "\"version\": \"1.0\","
    578         "\"manifest_version\": 2,"
    579         "\"permissions\": [\"background\"]}",
    580         "ID-1"));
    581 
    582   scoped_refptr<extensions::Extension> component_extension_with_options(
    583     CreateExtension(
    584         extensions::Manifest::COMPONENT,
    585         "{\"name\": \"Component Extension with Options\","
    586         "\"version\": \"1.0\","
    587         "\"manifest_version\": 2,"
    588         "\"permissions\": [\"background\"],"
    589         "\"options_page\": \"test.html\"}",
    590         "ID-2"));
    591 
    592   scoped_refptr<extensions::Extension> regular_extension(
    593     CreateExtension(
    594         extensions::Manifest::COMMAND_LINE,
    595         "{\"name\": \"Regular Extension\", "
    596         "\"version\": \"1.0\","
    597         "\"manifest_version\": 2,"
    598         "\"permissions\": [\"background\"]}",
    599         "ID-3"));
    600 
    601   scoped_refptr<extensions::Extension> regular_extension_with_options(
    602     CreateExtension(
    603         extensions::Manifest::COMMAND_LINE,
    604         "{\"name\": \"Regular Extension with Options\","
    605         "\"version\": \"1.0\","
    606         "\"manifest_version\": 2,"
    607         "\"permissions\": [\"background\"],"
    608         "\"options_page\": \"test.html\"}",
    609         "ID-4"));
    610 
    611   static_cast<extensions::TestExtensionSystem*>(
    612       extensions::ExtensionSystem::Get(profile1))->CreateExtensionService(
    613           CommandLine::ForCurrentProcess(),
    614           base::FilePath(),
    615           false);
    616   ExtensionService* service1 = profile1->GetExtensionService();
    617   service1->Init();
    618 
    619   service1->AddComponentExtension(component_extension);
    620   service1->AddComponentExtension(component_extension_with_options);
    621   service1->AddExtension(regular_extension);
    622   service1->AddExtension(regular_extension_with_options);
    623 
    624   static_cast<extensions::TestExtensionSystem*>(
    625       extensions::ExtensionSystem::Get(profile2))->CreateExtensionService(
    626           CommandLine::ForCurrentProcess(),
    627           base::FilePath(),
    628           false);
    629   ExtensionService* service2 = profile2->GetExtensionService();
    630   service2->Init();
    631 
    632   service2->AddComponentExtension(component_extension);
    633   service2->AddExtension(regular_extension);
    634   service2->AddExtension(regular_extension_with_options);
    635 
    636   scoped_ptr<TestBackgroundModeManager> manager(new TestBackgroundModeManager(
    637       command_line_.get(), profile_manager->profile_info_cache(), true));
    638   manager->RegisterProfile(profile1);
    639   manager->RegisterProfile(profile2);
    640 
    641   manager->status_icon_ = new TestStatusIcon();
    642   manager->UpdateStatusTrayIconContextMenu();
    643   StatusIconMenuModel* context_menu = manager->context_menu_;
    644   EXPECT_TRUE(context_menu != NULL);
    645 
    646   // Background Profile Enable Checks
    647   EXPECT_TRUE(context_menu->GetLabelAt(3) == UTF8ToUTF16("p1"));
    648   EXPECT_TRUE(
    649       context_menu->IsCommandIdEnabled(context_menu->GetCommandIdAt(3)));
    650   EXPECT_TRUE(context_menu->GetCommandIdAt(3) == 4);
    651 
    652   EXPECT_TRUE(context_menu->GetLabelAt(4) == UTF8ToUTF16("p2"));
    653   EXPECT_TRUE(
    654       context_menu->IsCommandIdEnabled(context_menu->GetCommandIdAt(4)));
    655   EXPECT_TRUE(context_menu->GetCommandIdAt(4) == 8);
    656 
    657   // Profile 1 Submenu Checks
    658   StatusIconMenuModel* profile1_submenu =
    659       static_cast<StatusIconMenuModel*>(context_menu->GetSubmenuModelAt(3));
    660   EXPECT_TRUE(
    661       profile1_submenu->GetLabelAt(0) ==
    662           UTF8ToUTF16("Component Extension"));
    663   EXPECT_FALSE(
    664       profile1_submenu->IsCommandIdEnabled(
    665           profile1_submenu->GetCommandIdAt(0)));
    666   EXPECT_TRUE(profile1_submenu->GetCommandIdAt(0) == 0);
    667   EXPECT_TRUE(
    668       profile1_submenu->GetLabelAt(1) ==
    669           UTF8ToUTF16("Component Extension with Options"));
    670   EXPECT_TRUE(
    671       profile1_submenu->IsCommandIdEnabled(
    672           profile1_submenu->GetCommandIdAt(1)));
    673   EXPECT_TRUE(profile1_submenu->GetCommandIdAt(1) == 1);
    674   EXPECT_TRUE(
    675       profile1_submenu->GetLabelAt(2) ==
    676           UTF8ToUTF16("Regular Extension"));
    677   EXPECT_TRUE(
    678       profile1_submenu->IsCommandIdEnabled(
    679           profile1_submenu->GetCommandIdAt(2)));
    680   EXPECT_TRUE(profile1_submenu->GetCommandIdAt(2) == 2);
    681   EXPECT_TRUE(
    682       profile1_submenu->GetLabelAt(3) ==
    683           UTF8ToUTF16("Regular Extension with Options"));
    684   EXPECT_TRUE(
    685       profile1_submenu->IsCommandIdEnabled(
    686           profile1_submenu->GetCommandIdAt(3)));
    687   EXPECT_TRUE(profile1_submenu->GetCommandIdAt(3) == 3);
    688 
    689   // Profile 2 Submenu Checks
    690   StatusIconMenuModel* profile2_submenu =
    691       static_cast<StatusIconMenuModel*>(context_menu->GetSubmenuModelAt(4));
    692   EXPECT_TRUE(
    693       profile2_submenu->GetLabelAt(0) ==
    694           UTF8ToUTF16("Component Extension"));
    695   EXPECT_FALSE(
    696       profile2_submenu->IsCommandIdEnabled(
    697           profile2_submenu->GetCommandIdAt(0)));
    698   EXPECT_TRUE(profile2_submenu->GetCommandIdAt(0) == 5);
    699   EXPECT_TRUE(
    700       profile2_submenu->GetLabelAt(1) ==
    701           UTF8ToUTF16("Regular Extension"));
    702   EXPECT_TRUE(
    703       profile2_submenu->IsCommandIdEnabled(
    704           profile2_submenu->GetCommandIdAt(1)));
    705   EXPECT_TRUE(profile2_submenu->GetCommandIdAt(1) == 6);
    706   EXPECT_TRUE(
    707       profile2_submenu->GetLabelAt(2) ==
    708           UTF8ToUTF16("Regular Extension with Options"));
    709   EXPECT_TRUE(
    710       profile2_submenu->IsCommandIdEnabled(
    711           profile2_submenu->GetCommandIdAt(2)));
    712   EXPECT_TRUE(profile2_submenu->GetCommandIdAt(2) == 7);
    713 
    714   // Model Adapter Checks for crbug.com/315164
    715   // P1: Profile 1 Menu Item
    716   // P2: Profile 2 Menu Item
    717   // CE: Component Extension Menu Item
    718   // CEO: Component Extenison with Options Menu Item
    719   // RE: Regular Extension Menu Item
    720   // REO: Regular Extension with Options Menu Item
    721   EXPECT_FALSE(IsCommandEnabled(context_menu, 0)); // P1 - CE
    722   EXPECT_TRUE(IsCommandEnabled(context_menu, 1));  // P1 - CEO
    723   EXPECT_TRUE(IsCommandEnabled(context_menu, 2));  // P1 - RE
    724   EXPECT_TRUE(IsCommandEnabled(context_menu, 3));  // P1 - REO
    725   EXPECT_TRUE(IsCommandEnabled(context_menu, 4));  // P1
    726   EXPECT_FALSE(IsCommandEnabled(context_menu, 5)); // P2 - CE
    727   EXPECT_TRUE(IsCommandEnabled(context_menu, 6));  // P2 - RE
    728   EXPECT_TRUE(IsCommandEnabled(context_menu, 7));  // P2 - REO
    729   EXPECT_TRUE(IsCommandEnabled(context_menu, 8));  // P2
    730 
    731   // Clean up the status icon. If this is not done before profile deletes,
    732   // the context menu updates will DCHECK with the now deleted profiles.
    733   StatusIcon* status_icon = manager->status_icon_;
    734   manager->status_icon_ = NULL;
    735   delete status_icon;
    736 
    737   // We have to destroy the profiles now because we created them with real
    738   // thread state. This causes a lot of machinery to spin up that stops working
    739   // when we tear down our thread state at the end of the test.
    740   profile_manager->DeleteTestingProfile("p2");
    741   profile_manager->DeleteTestingProfile("p1");
    742 
    743   // We're getting ready to shutdown the message loop. Clear everything out!
    744   base::MessageLoop::current()->RunUntilIdle();
    745   chrome::EndKeepAlive(); // Matching the above chrome::StartKeepAlive().
    746 
    747   // TestBackgroundModeManager has dependencies on the infrastructure.
    748   // It should get cleared first.
    749   manager.reset();
    750 
    751   // The Profile Manager references the Browser Process.
    752   // The Browser Process references the Notification UI Manager.
    753   // The Notification UI Manager references the Message Center.
    754   // As a result, we have to clear the browser process state here
    755   // before tearing down the Message Center.
    756   profile_manager.reset();
    757 
    758   // Message Center shutdown must occur after the EndKeepAlive because
    759   // EndKeepAlive will end up referencing the message center during cleanup.
    760   message_center::MessageCenter::Shutdown();
    761 
    762   // Clear the shutdown flag to isolate the remaining effect of this test.
    763   browser_shutdown::SetTryingToQuit(false);
    764 }
    765