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.
6 #include "base/command_line.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/test/test_simple_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "chrome/browser/background/background_mode_manager.h"
13 #include "chrome/browser/background/background_trigger.h"
14 #include "chrome/browser/browser_shutdown.h"
15 #include "chrome/browser/extensions/extension_function_test_utils.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/test_extension_system.h"
18 #include "chrome/browser/lifetime/application_lifetime.h"
19 #include "chrome/browser/profiles/profile_info_cache.h"
20 #include "chrome/browser/status_icons/status_icon_menu_model.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/test/base/testing_browser_process.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "chrome/test/base/testing_profile_manager.h"
26 #include "content/public/test/test_browser_thread_bundle.h"
27 #include "extensions/browser/api_test_utils.h"
28 #include "extensions/browser/extension_prefs.h"
29 #include "extensions/browser/extension_system.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "ui/gfx/image/image.h"
33 #include "ui/gfx/image/image_unittest_util.h"
34 #include "ui/message_center/message_center.h"
36 #if defined(OS_CHROMEOS)
37 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
38 #include "chrome/browser/chromeos/settings/cros_settings.h"
39 #include "chrome/browser/chromeos/settings/device_settings_service.h"
43 using testing::AtMost
;
44 using testing::Exactly
;
45 using testing::InSequence
;
47 using testing::StrictMock
;
51 scoped_ptr
<TestingProfileManager
> CreateTestingProfileManager() {
52 scoped_ptr
<TestingProfileManager
> profile_manager(
53 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
54 EXPECT_TRUE(profile_manager
->SetUp());
55 return profile_manager
.Pass();
58 class FakeBackgroundTrigger
: public BackgroundTrigger
{
60 ~FakeBackgroundTrigger() override
;
61 base::string16
GetName() override
;
62 gfx::ImageSkia
* GetIcon() override
;
63 void OnMenuClick() override
;
64 int get_name_call_count_
= 0;
65 int get_icon_call_count_
= 0;
66 int on_menu_click_call_count_
= 0;
69 FakeBackgroundTrigger::~FakeBackgroundTrigger() {
72 base::string16
FakeBackgroundTrigger::GetName() {
73 get_name_call_count_
++;
74 return base::UTF8ToUTF16("FakeBackgroundTrigger");
77 gfx::ImageSkia
* FakeBackgroundTrigger::GetIcon() {
78 get_icon_call_count_
++;
82 void FakeBackgroundTrigger::OnMenuClick() {
83 on_menu_click_call_count_
++;
86 // Helper class that tracks state transitions in BackgroundModeManager and
87 // exposes them via getters (or gmock for EnableLaunchOnStartup).
88 class TestBackgroundModeManager
: public StrictMock
<BackgroundModeManager
> {
90 TestBackgroundModeManager(const base::CommandLine
& command_line
,
91 ProfileInfoCache
* cache
)
92 : StrictMock
<BackgroundModeManager
>(command_line
, cache
),
93 have_status_tray_(false),
94 has_shown_balloon_(false) {
95 ResumeBackgroundMode();
98 MOCK_METHOD1(EnableLaunchOnStartup
, void(bool should_launch
));
100 // TODO: Use strict-mocking rather than keeping state through overrides below.
101 void DisplayClientInstalledNotification(const base::string16
& name
) override
{
102 has_shown_balloon_
= true;
104 void CreateStatusTrayIcon() override
{ have_status_tray_
= true; }
105 void RemoveStatusTrayIcon() override
{ have_status_tray_
= false; }
107 bool HaveStatusTray() const { return have_status_tray_
; }
108 bool HasShownBalloon() const { return has_shown_balloon_
; }
109 void SetHasShownBalloon(bool value
) { has_shown_balloon_
= value
; }
112 // Flags to track whether we have a status tray/have shown the balloon.
113 bool have_status_tray_
;
114 bool has_shown_balloon_
;
116 DISALLOW_COPY_AND_ASSIGN(TestBackgroundModeManager
);
119 class TestStatusIcon
: public StatusIcon
{
122 void SetImage(const gfx::ImageSkia
& image
) override
{}
123 void SetToolTip(const base::string16
& tool_tip
) override
{}
124 void DisplayBalloon(const gfx::ImageSkia
& icon
,
125 const base::string16
& title
,
126 const base::string16
& contents
) override
{}
127 void UpdatePlatformContextMenu(StatusIconMenuModel
* menu
) override
{}
130 DISALLOW_COPY_AND_ASSIGN(TestStatusIcon
);
133 void AssertBackgroundModeActive(const TestBackgroundModeManager
& manager
) {
134 EXPECT_TRUE(chrome::WillKeepAlive());
135 EXPECT_TRUE(manager
.HaveStatusTray());
138 void AssertBackgroundModeInactive(const TestBackgroundModeManager
& manager
) {
139 EXPECT_FALSE(chrome::WillKeepAlive());
140 EXPECT_FALSE(manager
.HaveStatusTray());
145 // More complex test helper that exposes APIs for fine grained control of
146 // things like the number of background applications. This allows writing
147 // smaller tests that don't have to install/uninstall extensions.
148 class AdvancedTestBackgroundModeManager
: public TestBackgroundModeManager
{
150 AdvancedTestBackgroundModeManager(const base::CommandLine
& command_line
,
151 ProfileInfoCache
* cache
,
153 : TestBackgroundModeManager(command_line
, cache
), enabled_(enabled
) {}
155 int GetBackgroundClientCount() const override
{
157 for (const auto& profile_count_pair
: profile_app_counts_
)
158 app_count
+= profile_count_pair
.second
;
161 int GetBackgroundClientCountForProfile(
162 Profile
* const profile
) const override
{
163 auto it
= profile_app_counts_
.find(profile
);
164 if (it
== profile_app_counts_
.end()) {
170 void SetBackgroundClientCountForProfile(Profile
* profile
, int count
) {
171 profile_app_counts_
[profile
] = count
;
173 void SetEnabled(bool enabled
) {
175 OnBackgroundModeEnabledPrefChanged();
177 bool IsBackgroundModePrefEnabled() const override
{ return enabled_
; }
181 std::map
<Profile
*, int> profile_app_counts_
;
183 DISALLOW_COPY_AND_ASSIGN(AdvancedTestBackgroundModeManager
);
186 class BackgroundModeManagerTest
: public testing::Test
{
188 BackgroundModeManagerTest() {}
189 ~BackgroundModeManagerTest() override
{}
191 void SetUp() override
{
192 command_line_
.reset(new base::CommandLine(base::CommandLine::NO_PROGRAM
));
193 profile_manager_
= CreateTestingProfileManager();
194 profile_
= profile_manager_
->CreateTestingProfile("p1");
195 chrome::DisableShutdownForTesting(true);
198 void TearDown() override
{
199 // Don't allow the browser to be closed because the shutdown procedure will
200 // attempt to access objects that we haven't created (e.g., MessageCenter).
201 browser_shutdown::SetTryingToQuit(true);
202 chrome::DisableShutdownForTesting(false);
203 browser_shutdown::SetTryingToQuit(false);
207 content::TestBrowserThreadBundle thread_bundle_
;
208 scoped_ptr
<base::CommandLine
> command_line_
;
210 scoped_ptr
<TestingProfileManager
> profile_manager_
;
211 // Test profile used by all tests - this is owned by profile_manager_.
212 TestingProfile
* profile_
;
215 DISALLOW_COPY_AND_ASSIGN(BackgroundModeManagerTest
);
218 class BackgroundModeManagerWithExtensionsTest
: public testing::Test
{
220 BackgroundModeManagerWithExtensionsTest() {}
221 ~BackgroundModeManagerWithExtensionsTest() override
{}
223 void SetUp() override
{
224 command_line_
.reset(new base::CommandLine(base::CommandLine::NO_PROGRAM
));
225 profile_manager_
= CreateTestingProfileManager();
226 profile_
= profile_manager_
->CreateTestingProfile("p1");
228 // Aura clears notifications from the message center at shutdown.
229 message_center::MessageCenter::Initialize();
231 // BackgroundModeManager actually affects Chrome start/stop state,
232 // tearing down our thread bundle before we've had chance to clean
233 // everything up. Keeping Chrome alive prevents this.
234 // We aren't interested in if the keep alive works correctly in this test.
235 chrome::IncrementKeepAliveCount();
237 #if defined(OS_CHROMEOS)
238 // On ChromeOS shutdown, HandleAppExitingForPlatform will call
239 // chrome::DecrementKeepAliveCount because it assumes the aura shell
240 // called chrome::IncrementKeepAliveCount. Simulate the call here.
241 chrome::IncrementKeepAliveCount();
244 // Create our test BackgroundModeManager.
245 manager_
.reset(new TestBackgroundModeManager(
246 *command_line_
, profile_manager_
->profile_info_cache()));
247 manager_
->RegisterProfile(profile_
);
250 void TearDown() override
{
251 // Clean up the status icon. If this is not done before profile deletes,
252 // the context menu updates will DCHECK with the now deleted profiles.
253 StatusIcon
* status_icon
= manager_
->status_icon_
;
254 manager_
->status_icon_
= NULL
;
257 // We have to destroy the profiles now because we created them with real
258 // thread state. This causes a lot of machinery to spin up that stops
259 // working when we tear down our thread state at the end of the test.
260 // Deleting our testing profile may have the side-effect of disabling
261 // background mode if it was enabled for that profile (explicitly note that
262 // here to satisfy StrictMock requirements.
263 EXPECT_CALL(*manager_
, EnableLaunchOnStartup(false)).Times(AtMost(1));
264 profile_manager_
->DeleteAllTestingProfiles();
265 Mock::VerifyAndClearExpectations(manager_
.get());
267 // We're getting ready to shutdown the message loop. Clear everything out!
268 base::MessageLoop::current()->RunUntilIdle();
269 // Matching the call to IncrementKeepAliveCount in SetUp().
270 chrome::DecrementKeepAliveCount();
272 // TestBackgroundModeManager has dependencies on the infrastructure.
273 // It should get cleared first.
276 // The Profile Manager references the Browser Process.
277 // The Browser Process references the Notification UI Manager.
278 // The Notification UI Manager references the Message Center.
279 // As a result, we have to clear the browser process state here
280 // before tearing down the Message Center.
281 profile_manager_
.reset();
283 // Message Center shutdown must occur after the DecrementKeepAliveCount
284 // because DecrementKeepAliveCount will end up referencing the message
285 // center during cleanup.
286 message_center::MessageCenter::Shutdown();
288 // Clear the shutdown flag to isolate the remaining effect of this test.
289 browser_shutdown::SetTryingToQuit(false);
293 scoped_refptr
<extensions::Extension
> CreateExtension(
294 extensions::Manifest::Location location
,
295 const std::string
& data
,
296 const std::string
& id
) {
297 scoped_ptr
<base::DictionaryValue
> parsed_manifest(
298 extensions::api_test_utils::ParseDictionary(data
));
299 return extensions::api_test_utils::CreateExtension(
300 location
, parsed_manifest
.get(), id
);
303 // From views::MenuModelAdapter::IsCommandEnabled with modification.
304 bool IsCommandEnabled(ui::MenuModel
* model
, int id
) const {
306 if (ui::MenuModel::GetModelAndIndexForCommandId(id
, &model
, &index
))
307 return model
->IsEnabledAt(index
);
312 void AddEphemeralApp(const extensions::Extension
* extension
,
313 ExtensionService
* service
) {
314 extensions::ExtensionPrefs
* prefs
=
315 extensions::ExtensionPrefs::Get(service
->profile());
317 prefs
->OnExtensionInstalled(extension
,
318 extensions::Extension::ENABLED
,
319 syncer::StringOrdinal(),
320 extensions::kInstallFlagIsEphemeral
,
323 service
->AddExtension(extension
);
326 scoped_ptr
<TestBackgroundModeManager
> manager_
;
328 scoped_ptr
<base::CommandLine
> command_line_
;
330 scoped_ptr
<TestingProfileManager
> profile_manager_
;
331 // Test profile used by all tests - this is owned by profile_manager_.
332 TestingProfile
* profile_
;
335 // Required for extension service.
336 content::TestBrowserThreadBundle thread_bundle_
;
338 #if defined(OS_CHROMEOS)
339 // ChromeOS needs extra services to run in the following order.
340 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_
;
341 chromeos::ScopedTestCrosSettings test_cros_settings_
;
342 chromeos::ScopedTestUserManager test_user_manager_
;
345 DISALLOW_COPY_AND_ASSIGN(BackgroundModeManagerWithExtensionsTest
);
349 TEST_F(BackgroundModeManagerTest
, BackgroundAppLoadUnload
) {
350 AdvancedTestBackgroundModeManager
manager(
351 *command_line_
, profile_manager_
->profile_info_cache(), true);
352 manager
.RegisterProfile(profile_
);
353 EXPECT_FALSE(chrome::WillKeepAlive());
356 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
357 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
358 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
359 manager
.OnApplicationListChanged(profile_
);
360 Mock::VerifyAndClearExpectations(&manager
);
361 AssertBackgroundModeActive(manager
);
363 manager
.SuspendBackgroundMode();
364 AssertBackgroundModeInactive(manager
);
365 manager
.ResumeBackgroundMode();
368 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
369 manager
.SetBackgroundClientCountForProfile(profile_
, 0);
370 manager
.OnApplicationListChanged(profile_
);
371 Mock::VerifyAndClearExpectations(&manager
);
372 AssertBackgroundModeInactive(manager
);
374 manager
.SuspendBackgroundMode();
375 AssertBackgroundModeInactive(manager
);
377 // Mimic app load while suspended, e.g. from sync. This should enable and
378 // resume background mode.
379 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
380 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
381 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
382 manager
.OnApplicationListChanged(profile_
);
383 Mock::VerifyAndClearExpectations(&manager
);
384 AssertBackgroundModeActive(manager
);
387 // Apps installed while background mode is disabled should cause activation
388 // after it is enabled - crbug.com/527023.
389 TEST_F(BackgroundModeManagerTest
, DISABLED_BackgroundAppInstallWhileDisabled
) {
390 AdvancedTestBackgroundModeManager
manager(
391 *command_line_
, profile_manager_
->profile_info_cache(), true);
392 manager
.RegisterProfile(profile_
);
394 // Turn off background mode (shouldn't explicitly disable launch-on-startup as
395 // the app-count is zero and launch-on-startup shouldn't be considered on).
396 manager
.SetEnabled(false);
397 AssertBackgroundModeInactive(manager
);
399 // When a new client is installed, status tray icons will not be created,
400 // launch on startup status will not be modified.
401 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
402 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
403 manager
.OnApplicationListChanged(profile_
);
404 AssertBackgroundModeInactive(manager
);
406 // Turn back on background mode, should show status tray icon as there is now
408 manager
.SetEnabled(true);
409 AssertBackgroundModeActive(manager
);
412 // Apps installed and uninstalled while background mode is disabled should do
414 TEST_F(BackgroundModeManagerTest
, BackgroundAppInstallUninstallWhileDisabled
) {
415 AdvancedTestBackgroundModeManager
manager(
416 *command_line_
, profile_manager_
->profile_info_cache(), true);
417 manager
.RegisterProfile(profile_
);
419 // Turn off background mode (shouldn't explicitly disable launch-on-startup as
420 // the app-count is zero and launch-on-startup shouldn't be considered on).
421 manager
.SetEnabled(false);
422 manager
.DisableBackgroundMode();
423 AssertBackgroundModeInactive(manager
);
425 // When a new client is installed, status tray icons will not be created,
426 // launch on startup status will not be modified.
427 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
428 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
429 manager
.OnApplicationListChanged(profile_
);
430 AssertBackgroundModeInactive(manager
);
432 manager
.SetBackgroundClientCountForProfile(profile_
, 0);
433 manager
.OnApplicationListChanged(profile_
);
434 AssertBackgroundModeInactive(manager
);
436 // Re-enable background mode (shouldn't actually enable launch-on-startup as
437 // the app-count is zero).
438 manager
.SetEnabled(true);
439 manager
.EnableBackgroundMode();
440 AssertBackgroundModeInactive(manager
);
443 // Apps installed before background mode is disabled cause the icon to show up
444 // again when it is enabled.
445 TEST_F(BackgroundModeManagerTest
, EnableAfterBackgroundAppInstall
) {
446 AdvancedTestBackgroundModeManager
manager(
447 *command_line_
, profile_manager_
->profile_info_cache(), true);
448 manager
.RegisterProfile(profile_
);
450 // Install app, should show status tray icon.
451 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
452 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
453 // OnBackgroundClientInstalled does not actually add an app to the
454 // BackgroundApplicationListModel which would result in another
455 // call to CreateStatusTray.
456 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
457 manager
.OnApplicationListChanged(profile_
);
458 AssertBackgroundModeActive(manager
);
459 Mock::VerifyAndClearExpectations(&manager
);
461 // Turn off background mode - should hide status tray icon.
462 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
463 manager
.SetEnabled(false);
464 manager
.DisableBackgroundMode();
465 Mock::VerifyAndClearExpectations(&manager
);
466 AssertBackgroundModeInactive(manager
);
468 // Turn back on background mode, should show status tray icon again as there
469 // was already an app installed before background mode was disabled.
470 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
471 manager
.SetEnabled(true);
472 manager
.EnableBackgroundMode();
473 Mock::VerifyAndClearExpectations(&manager
);
474 AssertBackgroundModeActive(manager
);
476 // Uninstall app, should hide status tray icon again.
477 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
478 manager
.SetBackgroundClientCountForProfile(profile_
, 0);
479 manager
.OnApplicationListChanged(profile_
);
480 Mock::VerifyAndClearExpectations(&manager
);
481 AssertBackgroundModeInactive(manager
);
484 TEST_F(BackgroundModeManagerTest
, MultiProfile
) {
485 TestingProfile
* profile2
= profile_manager_
->CreateTestingProfile("p2");
486 AdvancedTestBackgroundModeManager
manager(
487 *command_line_
, profile_manager_
->profile_info_cache(), true);
488 manager
.RegisterProfile(profile_
);
489 manager
.RegisterProfile(profile2
);
490 EXPECT_FALSE(chrome::WillKeepAlive());
492 // Install app, should show status tray icon.
493 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
494 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
495 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
496 manager
.OnApplicationListChanged(profile_
);
497 Mock::VerifyAndClearExpectations(&manager
);
498 AssertBackgroundModeActive(manager
);
500 // Install app for other profile, should show other status tray icon.
501 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
502 manager
.SetBackgroundClientCountForProfile(profile2
, 2);
503 manager
.OnApplicationListChanged(profile2
);
504 AssertBackgroundModeActive(manager
);
506 // Should hide both status tray icons.
507 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
508 manager
.SetEnabled(false);
509 manager
.DisableBackgroundMode();
510 Mock::VerifyAndClearExpectations(&manager
);
511 AssertBackgroundModeInactive(manager
);
513 // Turn back on background mode - should show both status tray icons.
514 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
515 manager
.SetEnabled(true);
516 manager
.EnableBackgroundMode();
517 Mock::VerifyAndClearExpectations(&manager
);
518 AssertBackgroundModeActive(manager
);
520 manager
.SetBackgroundClientCountForProfile(profile_
, 0);
521 manager
.OnApplicationListChanged(profile_
);
522 manager
.SetBackgroundClientCountForProfile(profile2
, 1);
523 manager
.OnApplicationListChanged(profile2
);
524 // There is still one background app alive
525 AssertBackgroundModeActive(manager
);
526 // Verify the implicit expectations of no calls on this StrictMock.
527 Mock::VerifyAndClearExpectations(&manager
);
529 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
530 manager
.SetBackgroundClientCountForProfile(profile2
, 0);
531 manager
.OnApplicationListChanged(profile_
);
532 Mock::VerifyAndClearExpectations(&manager
);
533 AssertBackgroundModeInactive(manager
);
536 TEST_F(BackgroundModeManagerTest
, ProfileInfoCacheStorage
) {
537 TestingProfile
* profile2
= profile_manager_
->CreateTestingProfile("p2");
538 AdvancedTestBackgroundModeManager
manager(
539 *command_line_
, profile_manager_
->profile_info_cache(), true);
540 manager
.RegisterProfile(profile_
);
541 manager
.RegisterProfile(profile2
);
542 EXPECT_FALSE(chrome::WillKeepAlive());
544 ProfileInfoCache
* cache
= profile_manager_
->profile_info_cache();
545 EXPECT_EQ(2u, cache
->GetNumberOfProfiles());
547 EXPECT_FALSE(cache
->GetBackgroundStatusOfProfileAtIndex(0));
548 EXPECT_FALSE(cache
->GetBackgroundStatusOfProfileAtIndex(1));
550 // Install app, should show status tray icon.
551 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
552 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
553 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
554 manager
.OnApplicationListChanged(profile_
);
555 Mock::VerifyAndClearExpectations(&manager
);
557 // Install app for other profile.
558 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
559 manager
.SetBackgroundClientCountForProfile(profile2
, 1);
560 manager
.OnApplicationListChanged(profile2
);
562 EXPECT_TRUE(cache
->GetBackgroundStatusOfProfileAtIndex(0));
563 EXPECT_TRUE(cache
->GetBackgroundStatusOfProfileAtIndex(1));
565 manager
.SetBackgroundClientCountForProfile(profile_
, 0);
566 manager
.OnApplicationListChanged(profile_
);
568 size_t p1_index
= cache
->GetIndexOfProfileWithPath(profile_
->GetPath());
569 EXPECT_FALSE(cache
->GetBackgroundStatusOfProfileAtIndex(p1_index
));
571 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
572 manager
.SetBackgroundClientCountForProfile(profile2
, 0);
573 manager
.OnApplicationListChanged(profile2
);
574 Mock::VerifyAndClearExpectations(&manager
);
576 size_t p2_index
= cache
->GetIndexOfProfileWithPath(profile_
->GetPath());
577 EXPECT_FALSE(cache
->GetBackgroundStatusOfProfileAtIndex(p2_index
));
579 // Even though neither has background status on, there should still be two
580 // profiles in the cache.
581 EXPECT_EQ(2u, cache
->GetNumberOfProfiles());
584 TEST_F(BackgroundModeManagerTest
, ProfileInfoCacheObserver
) {
585 AdvancedTestBackgroundModeManager
manager(
586 *command_line_
, profile_manager_
->profile_info_cache(), true);
587 manager
.RegisterProfile(profile_
);
588 EXPECT_FALSE(chrome::WillKeepAlive());
590 // Install app, should show status tray icon.
591 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
592 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
593 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
594 manager
.OnApplicationListChanged(profile_
);
595 Mock::VerifyAndClearExpectations(&manager
);
597 // Background mode should remain active for the remainder of this test.
599 manager
.OnProfileNameChanged(
601 manager
.GetBackgroundModeData(profile_
)->name());
603 EXPECT_EQ(base::UTF8ToUTF16("p1"),
604 manager
.GetBackgroundModeData(profile_
)->name());
606 EXPECT_TRUE(chrome::WillKeepAlive());
607 TestingProfile
* profile2
= profile_manager_
->CreateTestingProfile("p2");
608 manager
.RegisterProfile(profile2
);
609 EXPECT_EQ(2, manager
.NumberOfBackgroundModeData());
611 manager
.OnProfileAdded(profile2
->GetPath());
612 EXPECT_EQ(base::UTF8ToUTF16("p2"),
613 manager
.GetBackgroundModeData(profile2
)->name());
615 manager
.OnProfileWillBeRemoved(profile2
->GetPath());
616 // Should still be in background mode after deleting profile.
617 EXPECT_TRUE(chrome::WillKeepAlive());
618 EXPECT_EQ(1, manager
.NumberOfBackgroundModeData());
620 // Check that the background mode data we think is in the map actually is.
621 EXPECT_EQ(base::UTF8ToUTF16("p1"),
622 manager
.GetBackgroundModeData(profile_
)->name());
625 TEST_F(BackgroundModeManagerTest
, DeleteBackgroundProfile
) {
626 // Tests whether deleting the only profile when it is a BG profile works
627 // or not (http://crbug.com/346214).
628 AdvancedTestBackgroundModeManager
manager(
629 *command_line_
, profile_manager_
->profile_info_cache(), true);
630 manager
.RegisterProfile(profile_
);
631 EXPECT_FALSE(chrome::WillKeepAlive());
633 // Install app, should show status tray icon.
634 EXPECT_CALL(manager
, EnableLaunchOnStartup(true)).Times(Exactly(1));
635 manager
.OnBackgroundClientInstalled(base::UTF8ToUTF16("name"));
636 manager
.SetBackgroundClientCountForProfile(profile_
, 1);
637 manager
.OnApplicationListChanged(profile_
);
638 Mock::VerifyAndClearExpectations(&manager
);
640 manager
.OnProfileNameChanged(
642 manager
.GetBackgroundModeData(profile_
)->name());
644 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
645 EXPECT_TRUE(chrome::WillKeepAlive());
646 manager
.SetBackgroundClientCountForProfile(profile_
, 0);
647 manager
.OnProfileWillBeRemoved(profile_
->GetPath());
648 Mock::VerifyAndClearExpectations(&manager
);
649 EXPECT_FALSE(chrome::WillKeepAlive());
652 TEST_F(BackgroundModeManagerTest
, DisableBackgroundModeUnderTestFlag
) {
653 command_line_
->AppendSwitch(switches::kKeepAliveForTest
);
654 AdvancedTestBackgroundModeManager
manager(
655 *command_line_
, profile_manager_
->profile_info_cache(), true);
656 manager
.RegisterProfile(profile_
);
657 EXPECT_TRUE(manager
.ShouldBeInBackgroundMode());
659 // No enable-launch-on-startup calls expected yet.
660 Mock::VerifyAndClearExpectations(&manager
);
661 EXPECT_CALL(manager
, EnableLaunchOnStartup(false)).Times(Exactly(1));
662 manager
.SetEnabled(false);
663 EXPECT_FALSE(manager
.ShouldBeInBackgroundMode());
666 TEST_F(BackgroundModeManagerTest
,
667 BackgroundModeDisabledPreventsKeepAliveOnStartup
) {
668 command_line_
->AppendSwitch(switches::kKeepAliveForTest
);
669 AdvancedTestBackgroundModeManager
manager(
670 *command_line_
, profile_manager_
->profile_info_cache(), false);
671 manager
.RegisterProfile(profile_
);
672 EXPECT_FALSE(manager
.ShouldBeInBackgroundMode());
675 TEST_F(BackgroundModeManagerWithExtensionsTest
, BackgroundMenuGeneration
) {
676 scoped_refptr
<extensions::Extension
> component_extension(
678 extensions::Manifest::COMPONENT
,
679 "{\"name\": \"Component Extension\","
680 "\"version\": \"1.0\","
681 "\"manifest_version\": 2,"
682 "\"permissions\": [\"background\"]}",
685 scoped_refptr
<extensions::Extension
> component_extension_with_options(
687 extensions::Manifest::COMPONENT
,
688 "{\"name\": \"Component Extension with Options\","
689 "\"version\": \"1.0\","
690 "\"manifest_version\": 2,"
691 "\"permissions\": [\"background\"],"
692 "\"options_page\": \"test.html\"}",
695 scoped_refptr
<extensions::Extension
> regular_extension(
697 extensions::Manifest::COMMAND_LINE
,
698 "{\"name\": \"Regular Extension\", "
699 "\"version\": \"1.0\","
700 "\"manifest_version\": 2,"
701 "\"permissions\": [\"background\"]}",
704 scoped_refptr
<extensions::Extension
> regular_extension_with_options(
706 extensions::Manifest::COMMAND_LINE
,
707 "{\"name\": \"Regular Extension with Options\","
708 "\"version\": \"1.0\","
709 "\"manifest_version\": 2,"
710 "\"permissions\": [\"background\"],"
711 "\"options_page\": \"test.html\"}",
714 static_cast<extensions::TestExtensionSystem
*>(
715 extensions::ExtensionSystem::Get(profile_
))
716 ->CreateExtensionService(base::CommandLine::ForCurrentProcess(),
717 base::FilePath(), false);
718 ExtensionService
* service
=
719 extensions::ExtensionSystem::Get(profile_
)->extension_service();
722 EXPECT_CALL(*manager_
, EnableLaunchOnStartup(true)).Times(Exactly(1));
723 service
->AddComponentExtension(component_extension
.get());
724 service
->AddComponentExtension(component_extension_with_options
.get());
725 service
->AddExtension(regular_extension
.get());
726 service
->AddExtension(regular_extension_with_options
.get());
727 Mock::VerifyAndClearExpectations(manager_
.get());
729 scoped_ptr
<StatusIconMenuModel
> menu(new StatusIconMenuModel(NULL
));
730 scoped_ptr
<StatusIconMenuModel
> submenu(new StatusIconMenuModel(NULL
));
731 BackgroundModeManager::BackgroundModeData
* bmd
=
732 manager_
->GetBackgroundModeData(profile_
);
733 bmd
->BuildProfileMenu(submenu
.get(), menu
.get());
735 submenu
->GetLabelAt(0) ==
736 base::UTF8ToUTF16("Component Extension"));
737 EXPECT_FALSE(submenu
->IsCommandIdEnabled(submenu
->GetCommandIdAt(0)));
739 submenu
->GetLabelAt(1) ==
740 base::UTF8ToUTF16("Component Extension with Options"));
741 EXPECT_TRUE(submenu
->IsCommandIdEnabled(submenu
->GetCommandIdAt(1)));
743 submenu
->GetLabelAt(2) ==
744 base::UTF8ToUTF16("Regular Extension"));
745 EXPECT_TRUE(submenu
->IsCommandIdEnabled(submenu
->GetCommandIdAt(2)));
747 submenu
->GetLabelAt(3) ==
748 base::UTF8ToUTF16("Regular Extension with Options"));
749 EXPECT_TRUE(submenu
->IsCommandIdEnabled(submenu
->GetCommandIdAt(3)));
752 TEST_F(BackgroundModeManagerWithExtensionsTest
,
753 BackgroundMenuGenerationMultipleProfile
) {
754 TestingProfile
* profile2
= profile_manager_
->CreateTestingProfile("p2");
755 scoped_refptr
<extensions::Extension
> component_extension(
757 extensions::Manifest::COMPONENT
,
758 "{\"name\": \"Component Extension\","
759 "\"version\": \"1.0\","
760 "\"manifest_version\": 2,"
761 "\"permissions\": [\"background\"]}",
764 scoped_refptr
<extensions::Extension
> component_extension_with_options(
766 extensions::Manifest::COMPONENT
,
767 "{\"name\": \"Component Extension with Options\","
768 "\"version\": \"1.0\","
769 "\"manifest_version\": 2,"
770 "\"permissions\": [\"background\"],"
771 "\"options_page\": \"test.html\"}",
774 scoped_refptr
<extensions::Extension
> regular_extension(
776 extensions::Manifest::COMMAND_LINE
,
777 "{\"name\": \"Regular Extension\", "
778 "\"version\": \"1.0\","
779 "\"manifest_version\": 2,"
780 "\"permissions\": [\"background\"]}",
783 scoped_refptr
<extensions::Extension
> regular_extension_with_options(
785 extensions::Manifest::COMMAND_LINE
,
786 "{\"name\": \"Regular Extension with Options\","
787 "\"version\": \"1.0\","
788 "\"manifest_version\": 2,"
789 "\"permissions\": [\"background\"],"
790 "\"options_page\": \"test.html\"}",
793 static_cast<extensions::TestExtensionSystem
*>(
794 extensions::ExtensionSystem::Get(profile_
))
795 ->CreateExtensionService(base::CommandLine::ForCurrentProcess(),
796 base::FilePath(), false);
797 ExtensionService
* service1
=
798 extensions::ExtensionSystem::Get(profile_
)->extension_service();
801 EXPECT_CALL(*manager_
, EnableLaunchOnStartup(true)).Times(Exactly(1));
802 service1
->AddComponentExtension(component_extension
.get());
803 service1
->AddComponentExtension(component_extension_with_options
.get());
804 service1
->AddExtension(regular_extension
.get());
805 service1
->AddExtension(regular_extension_with_options
.get());
806 Mock::VerifyAndClearExpectations(manager_
.get());
808 static_cast<extensions::TestExtensionSystem
*>(
809 extensions::ExtensionSystem::Get(profile2
))
810 ->CreateExtensionService(base::CommandLine::ForCurrentProcess(),
811 base::FilePath(), false);
812 ExtensionService
* service2
=
813 extensions::ExtensionSystem::Get(profile2
)->extension_service();
816 service2
->AddComponentExtension(component_extension
.get());
817 service2
->AddExtension(regular_extension
.get());
818 service2
->AddExtension(regular_extension_with_options
.get());
820 manager_
->RegisterProfile(profile2
);
822 manager_
->status_icon_
= new TestStatusIcon();
823 manager_
->UpdateStatusTrayIconContextMenu();
824 StatusIconMenuModel
* context_menu
= manager_
->context_menu_
;
825 EXPECT_TRUE(context_menu
!= NULL
);
827 // Background Profile Enable Checks
828 EXPECT_TRUE(context_menu
->GetLabelAt(3) == base::UTF8ToUTF16("p1"));
830 context_menu
->IsCommandIdEnabled(context_menu
->GetCommandIdAt(3)));
831 EXPECT_TRUE(context_menu
->GetCommandIdAt(3) == 4);
833 EXPECT_TRUE(context_menu
->GetLabelAt(4) == base::UTF8ToUTF16("p2"));
835 context_menu
->IsCommandIdEnabled(context_menu
->GetCommandIdAt(4)));
836 EXPECT_TRUE(context_menu
->GetCommandIdAt(4) == 8);
838 // Profile 1 Submenu Checks
839 StatusIconMenuModel
* profile1_submenu
=
840 static_cast<StatusIconMenuModel
*>(context_menu
->GetSubmenuModelAt(3));
842 profile1_submenu
->GetLabelAt(0) ==
843 base::UTF8ToUTF16("Component Extension"));
845 profile1_submenu
->IsCommandIdEnabled(
846 profile1_submenu
->GetCommandIdAt(0)));
847 EXPECT_TRUE(profile1_submenu
->GetCommandIdAt(0) == 0);
849 profile1_submenu
->GetLabelAt(1) ==
850 base::UTF8ToUTF16("Component Extension with Options"));
852 profile1_submenu
->IsCommandIdEnabled(
853 profile1_submenu
->GetCommandIdAt(1)));
854 EXPECT_TRUE(profile1_submenu
->GetCommandIdAt(1) == 1);
856 profile1_submenu
->GetLabelAt(2) ==
857 base::UTF8ToUTF16("Regular Extension"));
859 profile1_submenu
->IsCommandIdEnabled(
860 profile1_submenu
->GetCommandIdAt(2)));
861 EXPECT_TRUE(profile1_submenu
->GetCommandIdAt(2) == 2);
863 profile1_submenu
->GetLabelAt(3) ==
864 base::UTF8ToUTF16("Regular Extension with Options"));
866 profile1_submenu
->IsCommandIdEnabled(
867 profile1_submenu
->GetCommandIdAt(3)));
868 EXPECT_TRUE(profile1_submenu
->GetCommandIdAt(3) == 3);
870 // Profile 2 Submenu Checks
871 StatusIconMenuModel
* profile2_submenu
=
872 static_cast<StatusIconMenuModel
*>(context_menu
->GetSubmenuModelAt(4));
874 profile2_submenu
->GetLabelAt(0) ==
875 base::UTF8ToUTF16("Component Extension"));
877 profile2_submenu
->IsCommandIdEnabled(
878 profile2_submenu
->GetCommandIdAt(0)));
879 EXPECT_TRUE(profile2_submenu
->GetCommandIdAt(0) == 5);
881 profile2_submenu
->GetLabelAt(1) ==
882 base::UTF8ToUTF16("Regular Extension"));
884 profile2_submenu
->IsCommandIdEnabled(
885 profile2_submenu
->GetCommandIdAt(1)));
886 EXPECT_TRUE(profile2_submenu
->GetCommandIdAt(1) == 6);
888 profile2_submenu
->GetLabelAt(2) ==
889 base::UTF8ToUTF16("Regular Extension with Options"));
891 profile2_submenu
->IsCommandIdEnabled(
892 profile2_submenu
->GetCommandIdAt(2)));
893 EXPECT_TRUE(profile2_submenu
->GetCommandIdAt(2) == 7);
895 // Model Adapter Checks for crbug.com/315164
896 // P1: Profile 1 Menu Item
897 // P2: Profile 2 Menu Item
898 // CE: Component Extension Menu Item
899 // CEO: Component Extenison with Options Menu Item
900 // RE: Regular Extension Menu Item
901 // REO: Regular Extension with Options Menu Item
902 EXPECT_FALSE(IsCommandEnabled(context_menu
, 0)); // P1 - CE
903 EXPECT_TRUE(IsCommandEnabled(context_menu
, 1)); // P1 - CEO
904 EXPECT_TRUE(IsCommandEnabled(context_menu
, 2)); // P1 - RE
905 EXPECT_TRUE(IsCommandEnabled(context_menu
, 3)); // P1 - REO
906 EXPECT_TRUE(IsCommandEnabled(context_menu
, 4)); // P1
907 EXPECT_FALSE(IsCommandEnabled(context_menu
, 5)); // P2 - CE
908 EXPECT_TRUE(IsCommandEnabled(context_menu
, 6)); // P2 - RE
909 EXPECT_TRUE(IsCommandEnabled(context_menu
, 7)); // P2 - REO
910 EXPECT_TRUE(IsCommandEnabled(context_menu
, 8)); // P2
913 TEST_F(BackgroundModeManagerWithExtensionsTest
, BalloonDisplay
) {
914 scoped_refptr
<extensions::Extension
> bg_ext(
916 extensions::Manifest::COMMAND_LINE
,
917 "{\"name\": \"Background Extension\", "
918 "\"version\": \"1.0\","
919 "\"manifest_version\": 2,"
920 "\"permissions\": [\"background\"]}",
923 scoped_refptr
<extensions::Extension
> upgraded_bg_ext(
925 extensions::Manifest::COMMAND_LINE
,
926 "{\"name\": \"Background Extension\", "
927 "\"version\": \"2.0\","
928 "\"manifest_version\": 2,"
929 "\"permissions\": [\"background\"]}",
932 scoped_refptr
<extensions::Extension
> no_bg_ext(
934 extensions::Manifest::COMMAND_LINE
,
935 "{\"name\": \"Regular Extension\", "
936 "\"version\": \"1.0\","
937 "\"manifest_version\": 2,"
938 "\"permissions\": []}",
941 scoped_refptr
<extensions::Extension
> upgraded_no_bg_ext_has_bg(
943 extensions::Manifest::COMMAND_LINE
,
944 "{\"name\": \"Regular Extension\", "
945 "\"version\": \"2.0\","
946 "\"manifest_version\": 2,"
947 "\"permissions\": [\"background\"]}",
950 static_cast<extensions::TestExtensionSystem
*>(
951 extensions::ExtensionSystem::Get(profile_
))
952 ->CreateExtensionService(base::CommandLine::ForCurrentProcess(),
953 base::FilePath(), false);
955 ExtensionService
* service
=
956 extensions::ExtensionSystem::Get(profile_
)->extension_service();
957 ASSERT_FALSE(service
->is_ready());
960 ASSERT_TRUE(service
->is_ready());
961 manager_
->status_icon_
= new TestStatusIcon();
962 manager_
->UpdateStatusTrayIconContextMenu();
964 // Adding a background extension should show the balloon.
965 EXPECT_FALSE(manager_
->HasShownBalloon());
966 EXPECT_CALL(*manager_
, EnableLaunchOnStartup(true)).Times(Exactly(1));
967 service
->AddExtension(bg_ext
.get());
968 Mock::VerifyAndClearExpectations(manager_
.get());
969 EXPECT_TRUE(manager_
->HasShownBalloon());
971 // Adding an extension without background should not show the balloon.
972 manager_
->SetHasShownBalloon(false);
973 service
->AddExtension(no_bg_ext
.get());
974 EXPECT_FALSE(manager_
->HasShownBalloon());
976 // Upgrading an extension that has background should not reshow the balloon.
978 // TODO: Fix crbug.com/438376 and remove these checks.
979 InSequence expected_call_sequence
;
980 EXPECT_CALL(*manager_
, EnableLaunchOnStartup(false)).Times(Exactly(1));
981 EXPECT_CALL(*manager_
, EnableLaunchOnStartup(true)).Times(Exactly(1));
983 service
->AddExtension(upgraded_bg_ext
.get());
984 Mock::VerifyAndClearExpectations(manager_
.get());
985 EXPECT_FALSE(manager_
->HasShownBalloon());
987 // Upgrading an extension that didn't have background to one that does should
989 service
->AddExtension(upgraded_no_bg_ext_has_bg
.get());
990 EXPECT_TRUE(manager_
->HasShownBalloon());
993 TEST_F(BackgroundModeManagerTest
, TriggerRegisterUnregister
) {
994 FakeBackgroundTrigger trigger
;
995 TestBackgroundModeManager
manager(*command_line_
,
996 profile_manager_
->profile_info_cache());
997 manager
.RegisterProfile(profile_
);
998 AssertBackgroundModeInactive(manager
);
1000 // Registering a trigger turns on background mode and shows a notification to
1002 EXPECT_CALL(manager
, EnableLaunchOnStartup(true));
1003 manager
.RegisterTrigger(profile_
, &trigger
, true /* should_notify_user */);
1004 Mock::VerifyAndClearExpectations(&manager
);
1005 ASSERT_EQ(1, manager
.GetBackgroundClientCountForProfile(profile_
));
1006 AssertBackgroundModeActive(manager
);
1007 ASSERT_TRUE(manager
.HasShownBalloon());
1009 // Unregistering the trigger turns off background mode.
1010 EXPECT_CALL(manager
, EnableLaunchOnStartup(false));
1011 manager
.UnregisterTrigger(profile_
, &trigger
);
1012 Mock::VerifyAndClearExpectations(&manager
);
1013 ASSERT_EQ(0, manager
.GetBackgroundClientCountForProfile(profile_
));
1014 AssertBackgroundModeInactive(manager
);
1017 // TODO(mvanouwerkerk): Make background mode behavior consistent when
1018 // registering a client while the pref is disabled - crbug.com/527032.
1019 TEST_F(BackgroundModeManagerTest
, TriggerRegisterWhileDisabled
) {
1020 g_browser_process
->local_state()->SetBoolean(prefs::kBackgroundModeEnabled
,
1022 FakeBackgroundTrigger trigger
;
1023 TestBackgroundModeManager
manager(*command_line_
,
1024 profile_manager_
->profile_info_cache());
1025 manager
.RegisterProfile(profile_
);
1026 AssertBackgroundModeInactive(manager
);
1027 ASSERT_FALSE(manager
.IsBackgroundModePrefEnabled());
1029 // Registering a trigger while disabled has no immediate effect but it is
1030 // stored as pending in case background mode is later enabled.
1031 manager
.RegisterTrigger(profile_
, &trigger
, true /* should_notify_user */);
1032 ASSERT_EQ(0, manager
.GetBackgroundClientCountForProfile(profile_
));
1033 AssertBackgroundModeInactive(manager
);
1034 ASSERT_FALSE(manager
.HasShownBalloon());
1036 // When the background mode pref is enabled and there are pending triggers
1037 // they will be registered and the user will be notified.
1038 EXPECT_CALL(manager
, EnableLaunchOnStartup(true));
1039 g_browser_process
->local_state()->SetBoolean(prefs::kBackgroundModeEnabled
,
1041 Mock::VerifyAndClearExpectations(&manager
);
1042 ASSERT_EQ(1, manager
.GetBackgroundClientCountForProfile(profile_
));
1043 AssertBackgroundModeActive(manager
);
1044 ASSERT_TRUE(manager
.HasShownBalloon());