• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
BackgroundModeManagerTest()35   BackgroundModeManagerTest() {}
~BackgroundModeManagerTest()36   virtual ~BackgroundModeManagerTest() {}
SetUp()37   virtual void SetUp() {
38     command_line_.reset(new CommandLine(CommandLine::NO_PROGRAM));
39   }
40   scoped_ptr<CommandLine> command_line_;
41 
42  protected:
CreateExtension(extensions::Manifest::Location location,const std::string & data,const std::string & id)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 
CreateTestingProfileManager()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.
IsCommandEnabled(ui::MenuModel * model,int id) const63   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:
TestBackgroundModeManager(CommandLine * command_line,ProfileInfoCache * cache,bool enabled)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   }
EnableLaunchOnStartup(bool launch)87   virtual void EnableLaunchOnStartup(bool launch) OVERRIDE {
88     launch_on_startup_ = launch;
89   }
DisplayAppInstalledNotification(const extensions::Extension * extension)90   virtual void DisplayAppInstalledNotification(
91       const extensions::Extension* extension) OVERRIDE {}
CreateStatusTrayIcon()92   virtual void CreateStatusTrayIcon() OVERRIDE { have_status_tray_ = true; }
RemoveStatusTrayIcon()93   virtual void RemoveStatusTrayIcon() OVERRIDE { have_status_tray_ = false; }
GetBackgroundAppCount() const94   virtual int GetBackgroundAppCount() const OVERRIDE { return app_count_; }
GetBackgroundAppCountForProfile(Profile * const profile) const95   virtual int GetBackgroundAppCountForProfile(
96       Profile* const profile) const OVERRIDE {
97     return profile_app_count_;
98   }
IsBackgroundModePrefEnabled() const99   virtual bool IsBackgroundModePrefEnabled() const OVERRIDE { return enabled_; }
SetBackgroundAppCount(int count)100   void SetBackgroundAppCount(int count) { app_count_ = count; }
SetBackgroundAppCountForProfile(int count)101   void SetBackgroundAppCountForProfile(int count) {
102     profile_app_count_ = count;
103   }
SetEnabled(bool enabled)104   void SetEnabled(bool enabled) {
105     enabled_ = enabled;
106     OnBackgroundModeEnabledPrefChanged();
107   }
HaveStatusTray() const108   bool HaveStatusTray() const { return have_status_tray_; }
IsLaunchOnStartup() const109   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 {
SetImage(const gfx::ImageSkia & image)121   virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE {}
SetPressedImage(const gfx::ImageSkia & image)122   virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE {}
SetToolTip(const base::string16 & tool_tip)123   virtual void SetToolTip(const base::string16& tool_tip) OVERRIDE {}
DisplayBalloon(const gfx::ImageSkia & icon,const base::string16 & title,const base::string16 & contents)124   virtual void DisplayBalloon(const gfx::ImageSkia& icon,
125                               const base::string16& title,
126                               const base::string16& contents) OVERRIDE {}
UpdatePlatformContextMenu(StatusIconMenuModel * menu)127   virtual void UpdatePlatformContextMenu(
128       StatusIconMenuModel* menu) OVERRIDE {}
129 };
130 
AssertBackgroundModeActive(const TestBackgroundModeManager & manager)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 
AssertBackgroundModeInactive(const TestBackgroundModeManager & manager)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 
AssertBackgroundModeSuspended(const TestBackgroundModeManager & manager)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 
TEST_F(BackgroundModeManagerTest,BackgroundAppLoadUnload)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.
TEST_F(BackgroundModeManagerTest,BackgroundAppInstallUninstallWhileDisabled)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..
TEST_F(BackgroundModeManagerTest,EnableAfterBackgroundAppInstall)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 
TEST_F(BackgroundModeManagerTest,MultiProfile)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 
TEST_F(BackgroundModeManagerTest,ProfileInfoCacheStorage)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 
TEST_F(BackgroundModeManagerTest,ProfileInfoCacheObserver)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 
TEST_F(BackgroundModeManagerTest,DisableBackgroundModeUnderTestFlag)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 
TEST_F(BackgroundModeManagerTest,BackgroundModeDisabledPreventsKeepAliveOnStartup)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 
TEST_F(BackgroundModeManagerTest,BackgroundMenuGeneration)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 
TEST_F(BackgroundModeManagerTest,BackgroundMenuGenerationMultipleProfile)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