1 // Copyright 2015 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.
5 #include "chrome/browser/chromeos/power/extension_event_observer.h"
9 #include "base/macros.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
14 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
15 #include "chrome/browser/chromeos/settings/cros_settings.h"
16 #include "chrome/browser/chromeos/settings/device_settings_service.h"
17 #include "chrome/common/extensions/api/gcm.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 "chromeos/dbus/dbus_thread_manager.h"
22 #include "chromeos/dbus/fake_power_manager_client.h"
23 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "content/public/test/test_renderer_host.h"
25 #include "extensions/browser/extension_host.h"
26 #include "extensions/browser/extension_host_observer.h"
27 #include "extensions/browser/process_manager.h"
28 #include "extensions/common/extension.h"
29 #include "extensions/common/extension_builder.h"
30 #include "extensions/common/manifest_handlers/background_info.h"
31 #include "extensions/common/value_builder.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "ui/aura/test/test_screen.h"
34 #include "ui/gfx/screen.h"
38 class ExtensionEventObserverTest
: public ::testing::Test
{
40 ExtensionEventObserverTest()
41 : power_manager_client_(new FakePowerManagerClient()),
42 test_screen_(aura::TestScreen::Create(gfx::Size())),
43 fake_user_manager_(new FakeChromeUserManager()),
44 scoped_user_manager_enabler_(fake_user_manager_
) {
45 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
46 make_scoped_ptr(power_manager_client_
));
48 profile_manager_
.reset(
49 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
51 extension_event_observer_
.reset(new ExtensionEventObserver());
52 test_api_
= extension_event_observer_
->CreateTestApi();
55 ~ExtensionEventObserverTest() override
{
56 extension_event_observer_
.reset();
57 profile_manager_
.reset();
58 DBusThreadManager::Shutdown();
61 // ::testing::Test overrides.
62 void SetUp() override
{
63 ::testing::Test::SetUp();
65 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, test_screen_
.get());
67 // Must be called from ::testing::Test::SetUp.
68 ASSERT_TRUE(profile_manager_
->SetUp());
70 const char kUserProfile
[] = "profile1@example.com";
71 fake_user_manager_
->AddUser(kUserProfile
);
72 fake_user_manager_
->LoginUser(kUserProfile
);
73 profile_
= profile_manager_
->CreateTestingProfile(kUserProfile
);
75 profile_manager_
->SetLoggedIn(true);
77 void TearDown() override
{
79 profile_manager_
->DeleteAllTestingProfiles();
80 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, nullptr);
81 ::testing::Test::TearDown();
85 scoped_refptr
<extensions::Extension
> CreateApp(const std::string
& name
,
87 scoped_refptr
<extensions::Extension
> app
=
88 extensions::ExtensionBuilder()
90 extensions::DictionaryBuilder()
92 .Set("version", "1.0.0")
93 .Set("manifest_version", 2)
95 extensions::DictionaryBuilder().Set(
97 extensions::DictionaryBuilder().Set(
98 "scripts", extensions::ListBuilder().Append(
100 .Set("permissions", extensions::ListBuilder().Append(
101 uses_gcm
? "gcm" : "")))
104 created_apps_
.push_back(app
);
109 extensions::ExtensionHost
* CreateHostForApp(Profile
* profile
,
110 extensions::Extension
* app
) {
111 extensions::ProcessManager::Get(profile
)->CreateBackgroundHost(
112 app
, extensions::BackgroundInfo::GetBackgroundURL(app
));
113 base::RunLoop().RunUntilIdle();
115 return extensions::ProcessManager::Get(profile
)
116 ->GetBackgroundHostForExtension(app
->id());
119 // Owned by DBusThreadManager.
120 FakePowerManagerClient
* power_manager_client_
;
122 scoped_ptr
<ExtensionEventObserver
> extension_event_observer_
;
123 scoped_ptr
<ExtensionEventObserver::TestApi
> test_api_
;
125 // Owned by |profile_manager_|.
126 TestingProfile
* profile_
;
127 scoped_ptr
<TestingProfileManager
> profile_manager_
;
130 scoped_ptr
<aura::TestScreen
> test_screen_
;
131 content::TestBrowserThreadBundle browser_thread_bundle_
;
133 // Needed to ensure we don't end up creating actual RenderViewHosts
134 // and RenderProcessHosts.
135 content::RenderViewHostTestEnabler render_view_host_test_enabler_
;
137 // Chrome OS needs extra services to run in the following order.
138 ScopedTestDeviceSettingsService test_device_settings_service_
;
139 ScopedTestCrosSettings test_cros_settings_
;
141 // Owned by |scoped_user_manager_enabler_|.
142 FakeChromeUserManager
* fake_user_manager_
;
143 ScopedUserManagerEnabler scoped_user_manager_enabler_
;
145 std::vector
<scoped_refptr
<extensions::Extension
>> created_apps_
;
147 DISALLOW_COPY_AND_ASSIGN(ExtensionEventObserverTest
);
150 // Tests that the ExtensionEventObserver reports readiness for suspend when
151 // there is nothing interesting going on.
152 TEST_F(ExtensionEventObserverTest
, BasicSuspendAndDarkSuspend
) {
153 power_manager_client_
->SendSuspendImminent();
154 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
156 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
157 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
159 power_manager_client_
->SendDarkSuspendImminent();
160 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
162 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
163 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
166 // Tests that the ExtensionEventObserver properly handles a canceled suspend
168 TEST_F(ExtensionEventObserverTest
, CanceledSuspend
) {
169 power_manager_client_
->SendSuspendImminent();
170 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
172 power_manager_client_
->SendSuspendDone();
173 EXPECT_FALSE(test_api_
->MaybeRunSuspendReadinessCallback());
176 // Tests that the ExtensionEventObserver delays suspends and dark suspends while
177 // there is a push message pending for an app that uses GCM.
178 TEST_F(ExtensionEventObserverTest
, PushMessagesDelaySuspend
) {
179 scoped_refptr
<extensions::Extension
> gcm_app
=
180 CreateApp("DelaysSuspendForPushMessages", true /* uses_gcm */);
181 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, gcm_app
.get());
183 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
185 // Test that a push message received before a suspend attempt delays the
187 const int kSuspendPushId
= 23874;
188 extension_event_observer_
->OnBackgroundEventDispatched(
189 host
, extensions::api::gcm::OnMessage::kEventName
, kSuspendPushId
);
190 power_manager_client_
->SendSuspendImminent();
192 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
193 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
195 extension_event_observer_
->OnBackgroundEventAcked(host
, kSuspendPushId
);
196 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
198 // Now test receiving the suspend attempt before the push message.
199 const int kDarkSuspendPushId
= 56674;
200 power_manager_client_
->SendDarkSuspendImminent();
201 extension_event_observer_
->OnBackgroundEventDispatched(
202 host
, extensions::api::gcm::OnMessage::kEventName
, kDarkSuspendPushId
);
204 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
205 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
207 extension_event_observer_
->OnBackgroundEventAcked(host
, kDarkSuspendPushId
);
208 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
210 // Test that non-push messages do not delay the suspend.
211 const int kNonPushId
= 5687;
212 power_manager_client_
->SendDarkSuspendImminent();
213 extension_event_observer_
->OnBackgroundEventDispatched(host
, "FakeMessage",
216 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
217 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
220 // Tests that messages sent for apps that don't use GCM are ignored.
221 TEST_F(ExtensionEventObserverTest
, IgnoresNonGCMApps
) {
222 scoped_refptr
<extensions::Extension
> app
= CreateApp("Non-GCM", false);
223 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, app
.get());
226 EXPECT_FALSE(test_api_
->WillDelaySuspendForExtensionHost(host
));
228 power_manager_client_
->SendSuspendImminent();
229 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
230 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
233 // Tests that network requests started by an app while it is processing a push
234 // message delay any suspend attempt.
235 TEST_F(ExtensionEventObserverTest
, NetworkRequestsMayDelaySuspend
) {
236 scoped_refptr
<extensions::Extension
> app
= CreateApp("NetworkRequests", true);
237 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, app
.get());
239 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
241 // Test that network requests started while there is no pending push message
243 const uint64 kNonPushRequestId
= 5170725;
244 extension_event_observer_
->OnNetworkRequestStarted(host
, kNonPushRequestId
);
245 power_manager_client_
->SendSuspendImminent();
247 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
248 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
250 // Test that network requests started while a push message is pending delay
251 // the suspend even after the push message has been acked.
252 const int kPushMessageId
= 178674;
253 const uint64 kNetworkRequestId
= 78917089;
254 power_manager_client_
->SendDarkSuspendImminent();
255 extension_event_observer_
->OnBackgroundEventDispatched(
256 host
, extensions::api::gcm::OnMessage::kEventName
, kPushMessageId
);
258 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
259 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
261 extension_event_observer_
->OnNetworkRequestStarted(host
, kNetworkRequestId
);
262 extension_event_observer_
->OnBackgroundEventAcked(host
, kPushMessageId
);
263 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
265 extension_event_observer_
->OnNetworkRequestDone(host
, kNetworkRequestId
);
266 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
269 // Tests that any outstanding push messages or network requests for an
270 // ExtensionHost that is destroyed do not end up blocking system suspend.
271 TEST_F(ExtensionEventObserverTest
, DeletedExtensionHostDoesNotBlockSuspend
) {
272 scoped_refptr
<extensions::Extension
> app
=
273 CreateApp("DeletedExtensionHost", true);
275 // The easiest way to delete an extension host is to delete the Profile it is
276 // associated with so we create a new Profile here.
277 const char kProfileName
[] = "DeletedExtensionHostProfile";
278 Profile
* new_profile
= profile_manager_
->CreateTestingProfile(kProfileName
);
280 extensions::ExtensionHost
* host
= CreateHostForApp(new_profile
, app
.get());
282 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
284 const int kPushId
= 156178;
285 const uint64 kNetworkId
= 791605;
286 extension_event_observer_
->OnBackgroundEventDispatched(
287 host
, extensions::api::gcm::OnMessage::kEventName
, kPushId
);
288 extension_event_observer_
->OnNetworkRequestStarted(host
, kNetworkId
);
290 // Now delete the Profile. This has the side-effect of also deleting all the
292 profile_manager_
->DeleteTestingProfile(kProfileName
);
294 power_manager_client_
->SendSuspendImminent();
295 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
296 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
299 // Tests that the ExtensionEventObserver does not delay suspend attempts when it
301 TEST_F(ExtensionEventObserverTest
, DoesNotDelaySuspendWhenDisabled
) {
302 scoped_refptr
<extensions::Extension
> app
=
303 CreateApp("NoDelayWhenDisabled", true);
304 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, app
.get());
306 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
308 // Test that disabling the suspend delay while a suspend is pending will cause
309 // the ExtensionEventObserver to immediately report readiness.
310 const int kPushId
= 416753;
311 extension_event_observer_
->OnBackgroundEventDispatched(
312 host
, extensions::api::gcm::OnMessage::kEventName
, kPushId
);
313 power_manager_client_
->SendSuspendImminent();
314 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
316 extension_event_observer_
->SetShouldDelaySuspend(false);
317 EXPECT_FALSE(test_api_
->MaybeRunSuspendReadinessCallback());
318 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
320 // Test that the ExtensionEventObserver does not delay suspend attempts when
322 power_manager_client_
->SendDarkSuspendImminent();
323 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
326 } // namespace chromeos