Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / power / renderer_freezer_unittest.cc
blob953f8af16e16b473633228a51d9c5600e51d1677
1 // Copyright 2014 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/renderer_freezer.h"
7 #include <string>
9 #include "base/command_line.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
15 #include "chrome/browser/chromeos/settings/cros_settings.h"
16 #include "chrome/browser/chromeos/settings/device_settings_service.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/test_extension_system.h"
19 #include "chrome/test/base/testing_browser_process.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "chrome/test/base/testing_profile_manager.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/fake_power_manager_client.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/notification_types.h"
27 #include "content/public/browser/site_instance.h"
28 #include "content/public/test/mock_render_process_host.h"
29 #include "content/public/test/test_browser_thread_bundle.h"
30 #include "extensions/browser/notification_types.h"
31 #include "extensions/browser/process_manager.h"
32 #include "extensions/browser/process_map.h"
33 #include "extensions/common/extension_builder.h"
34 #include "extensions/common/manifest_handlers/background_info.h"
35 #include "extensions/common/value_builder.h"
36 #include "testing/gtest/include/gtest/gtest-death-test.h"
37 #include "testing/gtest/include/gtest/gtest.h"
39 namespace chromeos {
41 namespace {
42 // Class that delegates used in testing can inherit from to record calls that
43 // are made by the code being tested.
44 class ActionRecorder {
45 public:
46 ActionRecorder() {}
47 virtual ~ActionRecorder() {}
49 // Returns a comma-separated string describing the actions that were
50 // requested since the previous call to GetActions() (i.e. results are
51 // non-repeatable).
52 std::string GetActions() {
53 std::string actions = actions_;
54 actions_.clear();
55 return actions;
58 protected:
59 // Appends |new_action| to |actions_|, using a comma as a separator if
60 // other actions are already listed.
61 void AppendAction(const std::string& new_action) {
62 if (!actions_.empty())
63 actions_ += ",";
64 actions_ += new_action;
67 private:
68 // Comma-separated list of actions that have been performed.
69 std::string actions_;
71 DISALLOW_COPY_AND_ASSIGN(ActionRecorder);
74 // Actions that can be returned by TestDelegate::GetActions().
75 const char kSetShouldFreezeRenderer[] = "set_should_freeze_renderer";
76 const char kSetShouldNotFreezeRenderer[] = "set_should_not_freeze_renderer";
77 const char kFreezeRenderers[] = "freeze_renderers";
78 const char kThawRenderers[] = "thaw_renderers";
79 const char kNoActions[] = "";
81 // Test implementation of RendererFreezer::Delegate that records the actions it
82 // was asked to perform.
83 class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder {
84 public:
85 TestDelegate()
86 : can_freeze_renderers_(true),
87 thaw_renderers_result_(true) {}
89 ~TestDelegate() override {}
91 // RendererFreezer::Delegate overrides.
92 void SetShouldFreezeRenderer(base::ProcessHandle handle,
93 bool frozen) override {
94 AppendAction(frozen ? kSetShouldFreezeRenderer
95 : kSetShouldNotFreezeRenderer);
97 void FreezeRenderers() override {
98 AppendAction(kFreezeRenderers);
100 void ThawRenderers(ResultCallback callback) override {
101 AppendAction(kThawRenderers);
103 callback.Run(thaw_renderers_result_);
105 void CheckCanFreezeRenderers(ResultCallback callback) override {
106 callback.Run(can_freeze_renderers_);
109 void set_thaw_renderers_result(bool result) {
110 thaw_renderers_result_ = result;
113 // Sets whether the delegate is capable of freezing renderers. This also
114 // changes |freeze_renderers_result_| and |thaw_renderers_result_|.
115 void set_can_freeze_renderers(bool can_freeze) {
116 can_freeze_renderers_ = can_freeze;
118 thaw_renderers_result_ = can_freeze;
121 private:
122 bool can_freeze_renderers_;
123 bool thaw_renderers_result_;
125 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
128 } // namespace
130 class RendererFreezerTest : public testing::Test {
131 public:
132 RendererFreezerTest()
133 : power_manager_client_(new FakePowerManagerClient()),
134 test_delegate_(new TestDelegate()) {
135 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
136 scoped_ptr<PowerManagerClient>(power_manager_client_));
139 ~RendererFreezerTest() override {
140 renderer_freezer_.reset();
142 DBusThreadManager::Shutdown();
145 protected:
146 void Init() {
147 renderer_freezer_.reset(new RendererFreezer(
148 scoped_ptr<RendererFreezer::Delegate>(test_delegate_)));
151 // Owned by DBusThreadManager.
152 FakePowerManagerClient* power_manager_client_;
154 // Owned by |renderer_freezer_|.
155 TestDelegate* test_delegate_;
156 scoped_ptr<RendererFreezer> renderer_freezer_;
158 private:
159 content::TestBrowserThreadBundle browser_thread_bundle_;
161 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest);
164 // Tests that the RendererFreezer freezes renderers on suspend and thaws them on
165 // resume.
166 TEST_F(RendererFreezerTest, SuspendResume) {
167 Init();
169 power_manager_client_->SendSuspendImminent();
170 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
172 // The renderers should be thawed when we resume.
173 power_manager_client_->SendSuspendDone();
174 EXPECT_EQ(kThawRenderers, test_delegate_->GetActions());
177 // Tests that the renderer freezer does nothing if the delegate cannot freeze
178 // renderers.
179 TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) {
180 test_delegate_->set_can_freeze_renderers(false);
181 Init();
183 // Nothing happens on suspend.
184 power_manager_client_->SendSuspendImminent();
185 EXPECT_EQ(kNoActions, test_delegate_->GetActions());
187 // Nothing happens on resume.
188 power_manager_client_->SendSuspendDone();
189 EXPECT_EQ(kNoActions, test_delegate_->GetActions());
192 #if defined(GTEST_HAS_DEATH_TEST)
193 // Tests that the RendererFreezer crashes the browser if the freezing operation
194 // was successful but the thawing operation failed.
195 TEST_F(RendererFreezerTest, ErrorThawingRenderers) {
196 // The "threadsafe" style of death test re-executes the unit test binary,
197 // which in turn re-initializes some global state leading to failed CHECKs.
198 // Instead, we use the "fast" style here to prevent re-initialization.
199 ::testing::FLAGS_gtest_death_test_style = "fast";
200 Init();
201 test_delegate_->set_thaw_renderers_result(false);
203 power_manager_client_->SendSuspendImminent();
204 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
206 EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw");
208 #endif // GTEST_HAS_DEATH_TEST
210 class RendererFreezerTestWithExtensions : public RendererFreezerTest {
211 public:
212 RendererFreezerTestWithExtensions() {}
213 ~RendererFreezerTestWithExtensions() override {}
215 // testing::Test overrides.
216 void SetUp() override {
217 RendererFreezerTest::SetUp();
219 profile_manager_.reset(
220 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
222 // Must be called from testing::Test::SetUp.
223 EXPECT_TRUE(profile_manager_->SetUp());
225 profile_ = profile_manager_->CreateTestingProfile("RendererFreezerTest");
227 extensions::TestExtensionSystem* extension_system =
228 static_cast<extensions::TestExtensionSystem*>(
229 extensions::ExtensionSystem::Get(profile_));
230 extension_system->CreateExtensionService(
231 base::CommandLine::ForCurrentProcess(),
232 base::FilePath() /* install_directory */,
233 false /* autoupdate_enabled*/);
235 void TearDown() override {
236 extensions::ExtensionSystem::Get(profile_)->Shutdown();
238 profile_ = NULL;
240 profile_manager_->DeleteAllTestingProfiles();
242 base::RunLoop().RunUntilIdle();
244 profile_manager_.reset();
246 RendererFreezerTest::TearDown();
249 protected:
250 void CreateRenderProcessForExtension(extensions::Extension* extension) {
251 scoped_ptr<content::MockRenderProcessHostFactory> rph_factory(
252 new content::MockRenderProcessHostFactory());
253 scoped_refptr<content::SiteInstance> site_instance(
254 extensions::ProcessManager::Get(profile_)->GetSiteInstanceForURL(
255 extensions::BackgroundInfo::GetBackgroundURL(extension)));
256 scoped_ptr<content::RenderProcessHost> rph(
257 rph_factory->CreateRenderProcessHost(profile_, site_instance.get()));
259 // Fake that the RenderProcessHost is hosting the gcm app.
260 extensions::ProcessMap::Get(profile_)
261 ->Insert(extension->id(), rph->GetID(), site_instance->GetId());
263 // Send the notification that the RenderProcessHost has been created.
264 content::NotificationService::current()->Notify(
265 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
266 content::Source<content::RenderProcessHost>(rph.get()),
267 content::NotificationService::NoDetails());
270 // Owned by |profile_manager_|.
271 TestingProfile* profile_;
272 scoped_ptr<TestingProfileManager> profile_manager_;
274 private:
275 // Chrome OS needs extra services to run in the following order.
276 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
277 chromeos::ScopedTestCrosSettings test_cros_settings_;
278 chromeos::ScopedTestUserManager test_user_manager_;
280 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTestWithExtensions);
283 // Tests that the RendererFreezer freezes renderers that are not hosting
284 // GCM extensions.
285 TEST_F(RendererFreezerTestWithExtensions, FreezesNonExtensionRenderers) {
286 Init();
288 // Create the mock RenderProcessHost.
289 scoped_ptr<content::MockRenderProcessHostFactory> rph_factory(
290 new content::MockRenderProcessHostFactory());
291 scoped_refptr<content::SiteInstance> site_instance(
292 content::SiteInstance::Create(profile_));
293 scoped_ptr<content::RenderProcessHost> rph(
294 rph_factory->CreateRenderProcessHost(profile_, site_instance.get()));
296 // Send the notification that the RenderProcessHost has been created.
297 content::NotificationService::current()->Notify(
298 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
299 content::Source<content::RenderProcessHost>(rph.get()),
300 content::NotificationService::NoDetails());
302 EXPECT_EQ(kSetShouldFreezeRenderer, test_delegate_->GetActions());
305 // Tests that the RendererFreezer does not freeze renderers that are hosting
306 // extensions that use GCM.
307 TEST_F(RendererFreezerTestWithExtensions, DoesNotFreezeGcmExtensionRenderers) {
308 Init();
310 // First build the GCM extension.
311 scoped_refptr<extensions::Extension> gcm_app =
312 extensions::ExtensionBuilder()
313 .SetManifest(extensions::DictionaryBuilder()
314 .Set("name", "GCM App")
315 .Set("version", "1.0.0")
316 .Set("manifest_version", 2)
317 .Set("app",
318 extensions::DictionaryBuilder()
319 .Set("background",
320 extensions::DictionaryBuilder()
321 .Set("scripts",
322 extensions::ListBuilder()
323 .Append("background.js"))))
324 .Set("permissions",
325 extensions::ListBuilder()
326 .Append("gcm")))
327 .Build();
329 // Now install it and give it a renderer.
330 extensions::ExtensionSystem::Get(profile_)
331 ->extension_service()
332 ->AddExtension(gcm_app.get());
333 CreateRenderProcessForExtension(gcm_app.get());
335 EXPECT_EQ(kSetShouldNotFreezeRenderer, test_delegate_->GetActions());
338 // Tests that the RendererFreezer freezes renderers that are hosting extensions
339 // that do not use GCM.
340 TEST_F(RendererFreezerTestWithExtensions, FreezesNonGcmExtensionRenderers) {
341 Init();
343 // First build the extension.
344 scoped_refptr<extensions::Extension> background_app =
345 extensions::ExtensionBuilder()
346 .SetManifest(extensions::DictionaryBuilder()
347 .Set("name", "Background App")
348 .Set("version", "1.0.0")
349 .Set("manifest_version", 2)
350 .Set("app",
351 extensions::DictionaryBuilder()
352 .Set("background",
353 extensions::DictionaryBuilder()
354 .Set("scripts",
355 extensions::ListBuilder()
356 .Append("background.js")))))
357 .Build();
359 // Now install it and give it a renderer.
360 extensions::ExtensionSystem::Get(profile_)
361 ->extension_service()
362 ->AddExtension(background_app.get());
363 CreateRenderProcessForExtension(background_app.get());
365 EXPECT_EQ(kSetShouldFreezeRenderer, test_delegate_->GetActions());
368 } // namespace chromeos