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"
36 class ExtensionEventObserverTest
: public ::testing::Test
{
38 ExtensionEventObserverTest()
39 : power_manager_client_(new FakePowerManagerClient()),
40 fake_user_manager_(new FakeChromeUserManager()),
41 scoped_user_manager_enabler_(fake_user_manager_
) {
42 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
43 make_scoped_ptr(power_manager_client_
));
45 profile_manager_
.reset(
46 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
48 extension_event_observer_
.reset(new ExtensionEventObserver());
49 test_api_
= extension_event_observer_
->CreateTestApi();
52 ~ExtensionEventObserverTest() override
{
53 extension_event_observer_
.reset();
54 profile_manager_
.reset();
55 DBusThreadManager::Shutdown();
58 // ::testing::Test overrides.
59 void SetUp() override
{
60 ::testing::Test::SetUp();
62 // Must be called from ::testing::Test::SetUp.
63 ASSERT_TRUE(profile_manager_
->SetUp());
65 const char kUserProfile
[] = "profile1@example.com";
66 fake_user_manager_
->AddUser(kUserProfile
);
67 fake_user_manager_
->LoginUser(kUserProfile
);
68 profile_
= profile_manager_
->CreateTestingProfile(kUserProfile
);
70 profile_manager_
->SetLoggedIn(true);
72 void TearDown() override
{
74 profile_manager_
->DeleteAllTestingProfiles();
76 ::testing::Test::TearDown();
80 scoped_refptr
<extensions::Extension
> CreateApp(const std::string
& name
,
82 scoped_refptr
<extensions::Extension
> app
=
83 extensions::ExtensionBuilder()
85 extensions::DictionaryBuilder()
87 .Set("version", "1.0.0")
88 .Set("manifest_version", 2)
90 extensions::DictionaryBuilder().Set(
92 extensions::DictionaryBuilder().Set(
93 "scripts", extensions::ListBuilder().Append(
95 .Set("permissions", extensions::ListBuilder().Append(
96 uses_gcm
? "gcm" : "")))
99 created_apps_
.push_back(app
);
104 extensions::ExtensionHost
* CreateHostForApp(Profile
* profile
,
105 extensions::Extension
* app
) {
106 extensions::ProcessManager::Get(profile
)->CreateBackgroundHost(
107 app
, extensions::BackgroundInfo::GetBackgroundURL(app
));
108 base::RunLoop().RunUntilIdle();
110 return extensions::ProcessManager::Get(profile
)
111 ->GetBackgroundHostForExtension(app
->id());
114 // Owned by DBusThreadManager.
115 FakePowerManagerClient
* power_manager_client_
;
117 scoped_ptr
<ExtensionEventObserver
> extension_event_observer_
;
118 scoped_ptr
<ExtensionEventObserver::TestApi
> test_api_
;
120 // Owned by |profile_manager_|.
121 TestingProfile
* profile_
;
122 scoped_ptr
<TestingProfileManager
> profile_manager_
;
125 content::TestBrowserThreadBundle browser_thread_bundle_
;
127 // Needed to ensure we don't end up creating actual RenderViewHosts
128 // and RenderProcessHosts.
129 content::RenderViewHostTestEnabler render_view_host_test_enabler_
;
131 // Chrome OS needs extra services to run in the following order.
132 ScopedTestDeviceSettingsService test_device_settings_service_
;
133 ScopedTestCrosSettings test_cros_settings_
;
135 // Owned by |scoped_user_manager_enabler_|.
136 FakeChromeUserManager
* fake_user_manager_
;
137 ScopedUserManagerEnabler scoped_user_manager_enabler_
;
139 std::vector
<scoped_refptr
<extensions::Extension
>> created_apps_
;
141 DISALLOW_COPY_AND_ASSIGN(ExtensionEventObserverTest
);
144 // Tests that the ExtensionEventObserver reports readiness for suspend when
145 // there is nothing interesting going on.
146 TEST_F(ExtensionEventObserverTest
, BasicSuspendAndDarkSuspend
) {
147 power_manager_client_
->SendSuspendImminent();
148 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
150 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
151 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
153 power_manager_client_
->SendDarkSuspendImminent();
154 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
156 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
157 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
160 // Tests that the ExtensionEventObserver properly handles a canceled suspend
162 TEST_F(ExtensionEventObserverTest
, CanceledSuspend
) {
163 power_manager_client_
->SendSuspendImminent();
164 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
166 power_manager_client_
->SendSuspendDone();
167 EXPECT_FALSE(test_api_
->MaybeRunSuspendReadinessCallback());
170 // Tests that the ExtensionEventObserver delays suspends and dark suspends while
171 // there is a push message pending for an app that uses GCM.
172 TEST_F(ExtensionEventObserverTest
, PushMessagesDelaySuspend
) {
173 scoped_refptr
<extensions::Extension
> gcm_app
=
174 CreateApp("DelaysSuspendForPushMessages", true /* uses_gcm */);
175 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, gcm_app
.get());
177 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
179 // Test that a push message received before a suspend attempt delays the
181 const int kSuspendPushId
= 23874;
182 extension_event_observer_
->OnBackgroundEventDispatched(
183 host
, extensions::api::gcm::OnMessage::kEventName
, kSuspendPushId
);
184 power_manager_client_
->SendSuspendImminent();
186 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
187 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
189 extension_event_observer_
->OnBackgroundEventAcked(host
, kSuspendPushId
);
190 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
192 // Now test receiving the suspend attempt before the push message.
193 const int kDarkSuspendPushId
= 56674;
194 power_manager_client_
->SendDarkSuspendImminent();
195 extension_event_observer_
->OnBackgroundEventDispatched(
196 host
, extensions::api::gcm::OnMessage::kEventName
, kDarkSuspendPushId
);
198 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
199 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
201 extension_event_observer_
->OnBackgroundEventAcked(host
, kDarkSuspendPushId
);
202 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
204 // Test that non-push messages do not delay the suspend.
205 const int kNonPushId
= 5687;
206 power_manager_client_
->SendDarkSuspendImminent();
207 extension_event_observer_
->OnBackgroundEventDispatched(host
, "FakeMessage",
210 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
211 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
214 // Tests that messages sent for apps that don't use GCM are ignored.
215 TEST_F(ExtensionEventObserverTest
, IgnoresNonGCMApps
) {
216 scoped_refptr
<extensions::Extension
> app
= CreateApp("Non-GCM", false);
217 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, app
.get());
220 EXPECT_FALSE(test_api_
->WillDelaySuspendForExtensionHost(host
));
222 power_manager_client_
->SendSuspendImminent();
223 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
224 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
227 // Tests that network requests started by an app while it is processing a push
228 // message delay any suspend attempt.
229 TEST_F(ExtensionEventObserverTest
, NetworkRequestsMayDelaySuspend
) {
230 scoped_refptr
<extensions::Extension
> app
= CreateApp("NetworkRequests", true);
231 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, app
.get());
233 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
235 // Test that network requests started while there is no pending push message
237 const uint64 kNonPushRequestId
= 5170725;
238 extension_event_observer_
->OnNetworkRequestStarted(host
, kNonPushRequestId
);
239 power_manager_client_
->SendSuspendImminent();
241 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
242 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
244 // Test that network requests started while a push message is pending delay
245 // the suspend even after the push message has been acked.
246 const int kPushMessageId
= 178674;
247 const uint64 kNetworkRequestId
= 78917089;
248 power_manager_client_
->SendDarkSuspendImminent();
249 extension_event_observer_
->OnBackgroundEventDispatched(
250 host
, extensions::api::gcm::OnMessage::kEventName
, kPushMessageId
);
252 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
253 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
255 extension_event_observer_
->OnNetworkRequestStarted(host
, kNetworkRequestId
);
256 extension_event_observer_
->OnBackgroundEventAcked(host
, kPushMessageId
);
257 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
259 extension_event_observer_
->OnNetworkRequestDone(host
, kNetworkRequestId
);
260 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
263 // Tests that any outstanding push messages or network requests for an
264 // ExtensionHost that is destroyed do not end up blocking system suspend.
265 TEST_F(ExtensionEventObserverTest
, DeletedExtensionHostDoesNotBlockSuspend
) {
266 scoped_refptr
<extensions::Extension
> app
=
267 CreateApp("DeletedExtensionHost", true);
269 // The easiest way to delete an extension host is to delete the Profile it is
270 // associated with so we create a new Profile here.
271 const char kProfileName
[] = "DeletedExtensionHostProfile";
272 Profile
* new_profile
= profile_manager_
->CreateTestingProfile(kProfileName
);
274 extensions::ExtensionHost
* host
= CreateHostForApp(new_profile
, app
.get());
276 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
278 const int kPushId
= 156178;
279 const uint64 kNetworkId
= 791605;
280 extension_event_observer_
->OnBackgroundEventDispatched(
281 host
, extensions::api::gcm::OnMessage::kEventName
, kPushId
);
282 extension_event_observer_
->OnNetworkRequestStarted(host
, kNetworkId
);
284 // Now delete the Profile. This has the side-effect of also deleting all the
286 profile_manager_
->DeleteTestingProfile(kProfileName
);
288 power_manager_client_
->SendSuspendImminent();
289 EXPECT_TRUE(test_api_
->MaybeRunSuspendReadinessCallback());
290 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
293 // Tests that the ExtensionEventObserver does not delay suspend attempts when it
295 TEST_F(ExtensionEventObserverTest
, DoesNotDelaySuspendWhenDisabled
) {
296 scoped_refptr
<extensions::Extension
> app
=
297 CreateApp("NoDelayWhenDisabled", true);
298 extensions::ExtensionHost
* host
= CreateHostForApp(profile_
, app
.get());
300 EXPECT_TRUE(test_api_
->WillDelaySuspendForExtensionHost(host
));
302 // Test that disabling the suspend delay while a suspend is pending will cause
303 // the ExtensionEventObserver to immediately report readiness.
304 const int kPushId
= 416753;
305 extension_event_observer_
->OnBackgroundEventDispatched(
306 host
, extensions::api::gcm::OnMessage::kEventName
, kPushId
);
307 power_manager_client_
->SendSuspendImminent();
308 EXPECT_EQ(1, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
310 extension_event_observer_
->SetShouldDelaySuspend(false);
311 EXPECT_FALSE(test_api_
->MaybeRunSuspendReadinessCallback());
312 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
314 // Test that the ExtensionEventObserver does not delay suspend attempts when
316 power_manager_client_
->SendDarkSuspendImminent();
317 EXPECT_EQ(0, power_manager_client_
->GetNumPendingSuspendReadinessCallbacks());
320 } // namespace chromeos