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. 4 5#include "chrome/browser/chromeos/power/renderer_freezer.h" 6 7#include <string> 8 9#include "base/message_loop/message_loop.h" 10#include "base/run_loop.h" 11#include "chromeos/dbus/dbus_thread_manager.h" 12#include "chromeos/dbus/fake_power_manager_client.h" 13#include "testing/gtest/include/gtest/gtest-death-test.h" 14#include "testing/gtest/include/gtest/gtest.h" 15 16namespace chromeos { 17 18namespace { 19// Class that delegates used in testing can inherit from to record calls that 20// are made by the code being tested. 21class ActionRecorder { 22 public: 23 ActionRecorder() {} 24 virtual ~ActionRecorder() {} 25 26 // Returns a comma-separated string describing the actions that were 27 // requested since the previous call to GetActions() (i.e. results are 28 // non-repeatable). 29 std::string GetActions() { 30 std::string actions = actions_; 31 actions_.clear(); 32 return actions; 33 } 34 35 protected: 36 // Appends |new_action| to |actions_|, using a comma as a separator if 37 // other actions are already listed. 38 void AppendAction(const std::string& new_action) { 39 if (!actions_.empty()) 40 actions_ += ","; 41 actions_ += new_action; 42 } 43 44 private: 45 // Comma-separated list of actions that have been performed. 46 std::string actions_; 47 48 DISALLOW_COPY_AND_ASSIGN(ActionRecorder); 49}; 50 51// Actions that can be returned by TestDelegate::GetActions(). 52const char kFreezeRenderers[] = "freeze_renderers"; 53const char kThawRenderers[] = "thaw_renderers"; 54const char kNoActions[] = ""; 55 56// Test implementation of RendererFreezer::Delegate that records the actions it 57// was asked to perform. 58class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder { 59 public: 60 TestDelegate() 61 : can_freeze_renderers_(true), 62 freeze_renderers_result_(true), 63 thaw_renderers_result_(true) {} 64 65 virtual ~TestDelegate() {} 66 67 // RendererFreezer::Delegate overrides. 68 virtual bool FreezeRenderers() OVERRIDE { 69 AppendAction(kFreezeRenderers); 70 71 return freeze_renderers_result_; 72 } 73 virtual bool ThawRenderers() OVERRIDE { 74 AppendAction(kThawRenderers); 75 76 return thaw_renderers_result_; 77 } 78 virtual bool CanFreezeRenderers() OVERRIDE { return can_freeze_renderers_; } 79 80 void set_freeze_renderers_result(bool result) { 81 freeze_renderers_result_ = result; 82 } 83 84 void set_thaw_renderers_result(bool result) { 85 thaw_renderers_result_ = result; 86 } 87 88 // Sets whether the delegate is capable of freezing renderers. This also 89 // changes |freeze_renderers_result_| and |thaw_renderers_result_|. 90 void set_can_freeze_renderers(bool can_freeze) { 91 can_freeze_renderers_ = can_freeze; 92 93 // If the delegate cannot freeze renderers, then the result of trying to do 94 // so will be false. 95 freeze_renderers_result_ = can_freeze; 96 thaw_renderers_result_ = can_freeze; 97 } 98 99 private: 100 bool can_freeze_renderers_; 101 bool freeze_renderers_result_; 102 bool thaw_renderers_result_; 103 104 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 105}; 106 107} // namespace 108 109class RendererFreezerTest : public testing::Test { 110 public: 111 RendererFreezerTest() 112 : power_manager_client_(new FakePowerManagerClient()), 113 test_delegate_(new TestDelegate()) { 114 DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient( 115 scoped_ptr<PowerManagerClient>(power_manager_client_)); 116 } 117 118 virtual ~RendererFreezerTest() { 119 renderer_freezer_.reset(); 120 121 DBusThreadManager::Shutdown(); 122 } 123 124 void Init() { 125 renderer_freezer_.reset(new RendererFreezer( 126 scoped_ptr<RendererFreezer::Delegate>(test_delegate_))); 127 } 128 129 protected: 130 FakePowerManagerClient* power_manager_client_; 131 TestDelegate* test_delegate_; 132 133 scoped_ptr<RendererFreezer> renderer_freezer_; 134 135 private: 136 base::MessageLoop message_loop_; 137 DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest); 138}; 139 140// Tests that the RendererFreezer freezes renderers on suspend and thaws them on 141// resume. 142TEST_F(RendererFreezerTest, SuspendResume) { 143 Init(); 144 145 power_manager_client_->SendSuspendImminent(); 146 147 // The RendererFreezer should have grabbed an asynchronous callback and done 148 // nothing else. 149 EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); 150 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); 151 152 // The RendererFreezer should eventually freeze the renderers and run the 153 // callback. 154 base::RunLoop().RunUntilIdle(); 155 EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); 156 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); 157 158 // The renderers should be thawed when we resume. 159 power_manager_client_->SendSuspendDone(); 160 EXPECT_EQ(kThawRenderers, test_delegate_->GetActions()); 161} 162 163// Tests that the RendereFreezer doesn't freeze renderers if the suspend attempt 164// was canceled before it had a chance to complete. 165TEST_F(RendererFreezerTest, SuspendCanceled) { 166 Init(); 167 168 // We shouldn't do anything yet. 169 power_manager_client_->SendSuspendImminent(); 170 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); 171 172 // If a suspend gets canceled for any reason, we should see a SuspendDone(). 173 power_manager_client_->SendSuspendDone(); 174 175 // We shouldn't try to freeze the renderers now. 176 base::RunLoop().RunUntilIdle(); 177 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); 178} 179 180// Tests that the renderer freezer does nothing if the delegate cannot freeze 181// renderers. 182TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) { 183 test_delegate_->set_can_freeze_renderers(false); 184 Init(); 185 186 power_manager_client_->SendSuspendImminent(); 187 188 // The RendererFreezer should not have grabbed a callback or done anything 189 // else. 190 EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); 191 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); 192 193 // There should be nothing in the message loop. 194 base::RunLoop().RunUntilIdle(); 195 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); 196 197 // Nothing happens on resume. 198 power_manager_client_->SendSuspendDone(); 199 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); 200} 201 202// Tests that the RendererFreezer does nothing on resume if the freezing 203// operation was unsuccessful. 204TEST_F(RendererFreezerTest, ErrorFreezingRenderers) { 205 Init(); 206 test_delegate_->set_freeze_renderers_result(false); 207 208 power_manager_client_->SendSuspendImminent(); 209 EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); 210 211 // The freezing operation should fail, but we should still report readiness. 212 base::RunLoop().RunUntilIdle(); 213 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); 214 EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); 215 216 // Since the delegate reported that the freezing was unsuccessful, don't do 217 // anything on resume. 218 power_manager_client_->SendSuspendDone(); 219 EXPECT_EQ(kNoActions, test_delegate_->GetActions()); 220} 221 222#if defined(GTEST_HAS_DEATH_TEST) 223// Tests that the RendererFreezer crashes the browser if the freezing operation 224// was successful but the thawing operation failed. 225TEST_F(RendererFreezerTest, ErrorThawingRenderers) { 226 Init(); 227 test_delegate_->set_thaw_renderers_result(false); 228 229 power_manager_client_->SendSuspendImminent(); 230 base::RunLoop().RunUntilIdle(); 231 EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); 232 233 EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw"); 234} 235#endif // GTEST_HAS_DEATH_TEST 236 237} // namespace chromeos 238