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 "extensions/browser/api/power/power_api.h"
10 #include "base/basictypes.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/weak_ptr.h"
14 #include "chrome/browser/extensions/extension_function_test_utils.h"
15 #include "chrome/test/base/browser_with_test_window_test.h"
16 #include "content/public/browser/power_save_blocker.h"
17 #include "extensions/browser/api/power/power_api_manager.h"
18 #include "extensions/common/extension.h"
20 namespace utils = extension_function_test_utils;
22 namespace extensions {
26 // Args commonly passed to PowerSaveBlockerStubManager::CallFunction().
27 const char kDisplayArgs[] = "[\"display\"]";
28 const char kSystemArgs[] = "[\"system\"]";
29 const char kEmptyArgs[] = "[]";
31 // Different actions that can be performed as a result of a
32 // PowerSaveBlocker being created or destroyed.
35 UNBLOCK_APP_SUSPENSION,
37 UNBLOCK_DISPLAY_SLEEP,
38 // Returned by PowerSaveBlockerStubManager::PopFirstRequest() when no
39 // requests are present.
43 // Stub implementation of content::PowerSaveBlocker that just runs a
44 // callback on destruction.
45 class PowerSaveBlockerStub : public content::PowerSaveBlocker {
47 explicit PowerSaveBlockerStub(base::Closure unblock_callback)
48 : unblock_callback_(unblock_callback) {
51 virtual ~PowerSaveBlockerStub() {
52 unblock_callback_.Run();
56 base::Closure unblock_callback_;
58 DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStub);
61 // Manages PowerSaveBlockerStub objects. Tests can instantiate this class
62 // to make PowerApiManager's calls to create PowerSaveBlockers record the
63 // actions that would've been performed instead of actually blocking and
64 // unblocking power management.
65 class PowerSaveBlockerStubManager {
67 explicit PowerSaveBlockerStubManager(content::BrowserContext* context)
68 : browser_context_(context),
69 weak_ptr_factory_(this) {
70 // Use base::Unretained since callbacks with return values can't use
72 PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting(
73 base::Bind(&PowerSaveBlockerStubManager::CreateStub,
74 base::Unretained(this)));
77 ~PowerSaveBlockerStubManager() {
78 PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting(
79 PowerApiManager::CreateBlockerFunction());
82 // Removes and returns the first item from |requests_|. Returns NONE if
83 // |requests_| is empty.
84 Request PopFirstRequest() {
85 if (requests_.empty())
88 Request request = requests_.front();
89 requests_.pop_front();
94 // Creates a new PowerSaveBlockerStub of type |type|.
95 scoped_ptr<content::PowerSaveBlocker> CreateStub(
96 content::PowerSaveBlocker::PowerSaveBlockerType type,
97 const std::string& reason) {
98 Request unblock_request = NONE;
100 case content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension:
101 requests_.push_back(BLOCK_APP_SUSPENSION);
102 unblock_request = UNBLOCK_APP_SUSPENSION;
104 case content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
105 requests_.push_back(BLOCK_DISPLAY_SLEEP);
106 unblock_request = UNBLOCK_DISPLAY_SLEEP;
109 return scoped_ptr<content::PowerSaveBlocker>(
110 new PowerSaveBlockerStub(
111 base::Bind(&PowerSaveBlockerStubManager::AppendRequest,
112 weak_ptr_factory_.GetWeakPtr(),
116 void AppendRequest(Request request) {
117 requests_.push_back(request);
120 content::BrowserContext* browser_context_;
122 // Requests in chronological order.
123 std::deque<Request> requests_;
125 base::WeakPtrFactory<PowerSaveBlockerStubManager> weak_ptr_factory_;
127 DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStubManager);
132 class PowerApiTest : public BrowserWithTestWindowTest {
134 virtual void SetUp() OVERRIDE {
135 BrowserWithTestWindowTest::SetUp();
136 manager_.reset(new PowerSaveBlockerStubManager(profile()));
137 extension_ = utils::CreateEmptyExtensionWithLocation(
138 extensions::Manifest::UNPACKED);
141 virtual void TearDown() OVERRIDE {
144 BrowserWithTestWindowTest::TearDown();
148 // Shorthand for PowerRequestKeepAwakeFunction and
149 // PowerReleaseKeepAwakeFunction.
155 // Calls the function described by |type| with |args|, a JSON list of
156 // arguments, on behalf of |extension|.
157 bool CallFunction(FunctionType type,
158 const std::string& args,
159 extensions::Extension* extension) {
160 scoped_refptr<UIThreadExtensionFunction> function(
162 static_cast<UIThreadExtensionFunction*>(
163 new PowerRequestKeepAwakeFunction) :
164 static_cast<UIThreadExtensionFunction*>(
165 new PowerReleaseKeepAwakeFunction));
166 function->set_extension(extension);
167 return utils::RunFunction(function.get(), args, browser(), utils::NONE);
170 // Send a notification to PowerApiManager saying that |extension| has
172 void UnloadExtension(extensions::Extension* extension) {
173 PowerApiManager::Get(profile())->OnExtensionUnloaded(
174 profile(), extension, UnloadedExtensionInfo::REASON_UNINSTALL);
177 scoped_ptr<PowerSaveBlockerStubManager> manager_;
178 scoped_refptr<extensions::Extension> extension_;
181 TEST_F(PowerApiTest, RequestAndRelease) {
182 // Simulate an extension making and releasing a "display" request and a
184 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
185 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
186 EXPECT_EQ(NONE, manager_->PopFirstRequest());
187 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
188 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
189 EXPECT_EQ(NONE, manager_->PopFirstRequest());
191 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension_.get()));
192 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
193 EXPECT_EQ(NONE, manager_->PopFirstRequest());
194 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
195 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
196 EXPECT_EQ(NONE, manager_->PopFirstRequest());
199 TEST_F(PowerApiTest, RequestWithoutRelease) {
200 // Simulate an extension calling requestKeepAwake() without calling
201 // releaseKeepAwake(). The override should be automatically removed when
202 // the extension is unloaded.
203 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
204 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
205 EXPECT_EQ(NONE, manager_->PopFirstRequest());
207 UnloadExtension(extension_.get());
208 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
209 EXPECT_EQ(NONE, manager_->PopFirstRequest());
212 TEST_F(PowerApiTest, ReleaseWithoutRequest) {
213 // Simulate an extension calling releaseKeepAwake() without having
214 // calling requestKeepAwake() earlier. The call should be ignored.
215 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
216 EXPECT_EQ(NONE, manager_->PopFirstRequest());
219 TEST_F(PowerApiTest, UpgradeRequest) {
220 // Simulate an extension calling requestKeepAwake("system") and then
221 // requestKeepAwake("display"). When the second call is made, a
222 // display-sleep-blocking request should be made before the initial
223 // app-suspension-blocking request is released.
224 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension_.get()));
225 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
226 EXPECT_EQ(NONE, manager_->PopFirstRequest());
228 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
229 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
230 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
231 EXPECT_EQ(NONE, manager_->PopFirstRequest());
233 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
234 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
235 EXPECT_EQ(NONE, manager_->PopFirstRequest());
238 TEST_F(PowerApiTest, DowngradeRequest) {
239 // Simulate an extension calling requestKeepAwake("display") and then
240 // requestKeepAwake("system"). When the second call is made, an
241 // app-suspension-blocking request should be made before the initial
242 // display-sleep-blocking request is released.
243 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
244 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
245 EXPECT_EQ(NONE, manager_->PopFirstRequest());
247 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension_.get()));
248 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
249 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
250 EXPECT_EQ(NONE, manager_->PopFirstRequest());
252 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
253 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
254 EXPECT_EQ(NONE, manager_->PopFirstRequest());
257 TEST_F(PowerApiTest, MultipleExtensions) {
258 // Simulate an extension blocking the display from sleeping.
259 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
260 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
261 EXPECT_EQ(NONE, manager_->PopFirstRequest());
263 // Create a second extension that blocks system suspend. No additional
264 // PowerSaveBlocker is needed; the blocker from the first extension
265 // already covers the behavior requested by the second extension.
266 scoped_ptr<base::DictionaryValue> extension_value(
267 utils::ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
268 scoped_refptr<extensions::Extension> extension2(
269 utils::CreateExtension(extensions::Manifest::UNPACKED,
270 extension_value.get(), "second_extension"));
271 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension2.get()));
272 EXPECT_EQ(NONE, manager_->PopFirstRequest());
274 // When the first extension is unloaded, a new app-suspension blocker
275 // should be created before the display-sleep blocker is destroyed.
276 UnloadExtension(extension_.get());
277 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
278 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
279 EXPECT_EQ(NONE, manager_->PopFirstRequest());
281 // Make the first extension block display-sleep again.
282 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
283 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
284 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
285 EXPECT_EQ(NONE, manager_->PopFirstRequest());
288 } // namespace extensions