Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Side by Side Diff: chrome/browser/extensions/api/power/power_api_unittest.cc

Issue 12576018: Add chrome.power extension API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: apply review feedback Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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/extensions/api/power/power_api.h"
6
7 #include <deque>
8 #include <string>
9
10 #include "base/basictypes.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "chrome/browser/extensions/api/power/power_api_manager.h"
14 #include "chrome/browser/extensions/extension_function_test_utils.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "chrome/common/extensions/extension.h"
17 #include "chrome/test/base/browser_with_test_window_test.h"
18 #include "content/public/browser/power_save_blocker.h"
19
20 namespace utils = extension_function_test_utils;
21
22 namespace extensions {
23
24 namespace {
25
26 // Args commonly passed to PowerSaveBlockerStubManager::CallFunction().
27 const char kDisplayArgs[] = "[\"display\"]";
28 const char kSystemArgs[] = "[\"system\"]";
29 const char kEmptyArgs[] = "[]";
30
31 // Different actions that can be performed as a result of a
32 // PowerSaveBlocker being created or destroyed.
33 enum Request {
34 BLOCK_APP_SUSPENSION,
35 UNBLOCK_APP_SUSPENSION,
36 BLOCK_DISPLAY_SLEEP,
37 UNBLOCK_DISPLAY_SLEEP,
38 // Returned by PowerSaveBlockerStubManager::PopFirstRequest() when no
39 // requests are present.
40 NONE,
41 };
42
43 // Stub implementation of content::PowerSaveBlocker that just runs a
44 // callback on destruction.
45 class PowerSaveBlockerStub : public content::PowerSaveBlocker {
46 public:
47 explicit PowerSaveBlockerStub(base::Closure unblock_callback)
48 : unblock_callback_(unblock_callback) {
49 }
50
51 virtual ~PowerSaveBlockerStub() {
52 unblock_callback_.Run();
53 }
54
55 private:
56 base::Closure unblock_callback_;
57
58 DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStub);
59 };
60
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 {
66 public:
67 PowerSaveBlockerStubManager() : weak_ptr_factory_(this) {
68 // Use base::Unretained since callbacks with return values can't use
69 // weak pointers.
70 PowerApiManager::GetInstance()->SetCreateBlockerFunctionForTesting(
71 base::Bind(&PowerSaveBlockerStubManager::CreateStub,
72 base::Unretained(this)));
73 }
74
75 ~PowerSaveBlockerStubManager() {
76 PowerApiManager::GetInstance()->SetCreateBlockerFunctionForTesting(
77 PowerApiManager::CreateBlockerFunction());
78 }
79
80 // Removes and returns the first item from |requests_|. Returns NONE if
81 // |requests_| is empty.
82 Request PopFirstRequest() {
83 if (requests_.empty())
84 return NONE;
85
86 Request request = requests_.front();
87 requests_.pop_front();
88 return request;
89 }
90
91 private:
92 // Creates a new PowerSaveBlockerStub of type |type|.
93 scoped_ptr<content::PowerSaveBlocker> CreateStub(
94 content::PowerSaveBlocker::PowerSaveBlockerType type,
95 const std::string& reason) {
96 Request unblock_request = NONE;
97 switch (type) {
98 case content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension:
99 requests_.push_back(BLOCK_APP_SUSPENSION);
100 unblock_request = UNBLOCK_APP_SUSPENSION;
101 break;
102 case content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
103 requests_.push_back(BLOCK_DISPLAY_SLEEP);
104 unblock_request = UNBLOCK_DISPLAY_SLEEP;
105 break;
106 }
107 return scoped_ptr<content::PowerSaveBlocker>(
108 new PowerSaveBlockerStub(
109 base::Bind(&PowerSaveBlockerStubManager::AppendRequest,
110 weak_ptr_factory_.GetWeakPtr(),
111 unblock_request)));
112 }
113
114 void AppendRequest(Request request) {
115 requests_.push_back(request);
116 }
117
118 // Requests in chronological order.
119 std::deque<Request> requests_;
120
121 base::WeakPtrFactory<PowerSaveBlockerStubManager> weak_ptr_factory_;
122
123 DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStubManager);
124 };
125
126 } // namespace
127
128 class PowerApiTest : public BrowserWithTestWindowTest {
129 public:
130 virtual void SetUp() OVERRIDE {
131 BrowserWithTestWindowTest::SetUp();
132 manager_.reset(new PowerSaveBlockerStubManager);
133 extension_ = utils::CreateEmptyExtensionWithLocation(
134 extensions::Manifest::UNPACKED);
135 }
136
137 protected:
138 // Shorthand for PowerRequestKeepAwakeFunction and
139 // PowerReleaseKeepAwakeFunction.
140 enum FunctionType {
141 REQUEST,
142 RELEASE,
143 };
144
145 // Calls the function described by |type| with |args|, a JSON list of
146 // arguments, on behalf of |extension|.
147 bool CallFunction(FunctionType type,
148 const std::string& args,
149 extensions::Extension* extension) {
150 UIThreadExtensionFunction* function =
151 type == REQUEST ?
152 static_cast<UIThreadExtensionFunction*>(
153 new PowerRequestKeepAwakeFunction) :
154 static_cast<UIThreadExtensionFunction*>(
155 new PowerReleaseKeepAwakeFunction);
156 function->set_extension(extension);
157 return utils::RunFunction(function, args, browser(), utils::NONE);
158 }
159
160 // Send a notification to PowerApiManager saying that |extension| has
161 // been unloaded.
162 void UnloadExtension(extensions::Extension* extension) {
163 UnloadedExtensionInfo details(
164 extension, extension_misc::UNLOAD_REASON_UNINSTALL);
165 PowerApiManager::GetInstance()->Observe(
166 chrome::NOTIFICATION_EXTENSION_UNLOADED,
167 content::Source<Profile>(browser()->profile()),
168 content::Details<UnloadedExtensionInfo>(&details));
169 }
170
171 scoped_ptr<PowerSaveBlockerStubManager> manager_;
172 scoped_refptr<extensions::Extension> extension_;
173 };
174
175 TEST_F(PowerApiTest, RequestAndRelease) {
176 // Simulate an extension making and releasing a "display" request, a
177 // "system" request, and a request without any arguments (which should be
178 // treated as "display").
179 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
180 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
181 EXPECT_EQ(NONE, manager_->PopFirstRequest());
182 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
183 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
184 EXPECT_EQ(NONE, manager_->PopFirstRequest());
185
186 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension_.get()));
187 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
188 EXPECT_EQ(NONE, manager_->PopFirstRequest());
189 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
190 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
191 EXPECT_EQ(NONE, manager_->PopFirstRequest());
192
193 ASSERT_TRUE(CallFunction(REQUEST, kEmptyArgs, extension_.get()));
194 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
195 EXPECT_EQ(NONE, manager_->PopFirstRequest());
196 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
197 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
198 EXPECT_EQ(NONE, manager_->PopFirstRequest());
199 }
200
201 TEST_F(PowerApiTest, RequestWithoutRelease) {
202 // Simulate an extension calling requestKeepAwake() without calling
203 // releaseKeepAwake(). The override should be automatically removed when
204 // the extension is unloaded.
205 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
206 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
207 EXPECT_EQ(NONE, manager_->PopFirstRequest());
208
209 UnloadExtension(extension_.get());
210 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
211 EXPECT_EQ(NONE, manager_->PopFirstRequest());
212 }
213
214 TEST_F(PowerApiTest, ReleaseWithoutRequest) {
215 // Simulate an extension calling releaseKeepAwake() without having
216 // calling requestKeepAwake() earlier. The call should be ignored.
217 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
218 EXPECT_EQ(NONE, manager_->PopFirstRequest());
219 }
220
221 TEST_F(PowerApiTest, UpgradeRequest) {
222 // Simulate an extension calling requestKeepAwake("system") and then
223 // requestKeepAwake("display"). When the second call is made, a
224 // display-sleep-blocking request should be made before the initial
225 // app-suspension-blocking request is released.
226 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension_.get()));
227 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
228 EXPECT_EQ(NONE, manager_->PopFirstRequest());
229
230 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
231 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
232 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
233 EXPECT_EQ(NONE, manager_->PopFirstRequest());
234
235 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
236 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
237 EXPECT_EQ(NONE, manager_->PopFirstRequest());
238 }
239
240 TEST_F(PowerApiTest, DowngradeRequest) {
241 // Simulate an extension calling requestKeepAwake("display") and then
242 // requestKeepAwake("system"). When the second call is made, an
243 // app-suspension-blocking request should be made before the initial
244 // display-sleep-blocking request is released.
245 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
246 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
247 EXPECT_EQ(NONE, manager_->PopFirstRequest());
248
249 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension_.get()));
250 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
251 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
252 EXPECT_EQ(NONE, manager_->PopFirstRequest());
253
254 ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
255 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
256 EXPECT_EQ(NONE, manager_->PopFirstRequest());
257 }
258
259 TEST_F(PowerApiTest, MultipleExtensions) {
260 // Simulate an extension blocking the display from sleeping.
261 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
262 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
263 EXPECT_EQ(NONE, manager_->PopFirstRequest());
264
265 // Create a second extension that blocks system suspend. No additional
266 // PowerSaveBlocker is needed; the blocker from the first extension
267 // already covers the behavior requested by the second extension.
268 scoped_ptr<base::DictionaryValue> extension_value(
269 utils::ParseDictionary("{\"name\": \"Test\", \"version\": \"1.0\"}"));
270 scoped_refptr<extensions::Extension> extension2(
271 utils::CreateExtension(extensions::Manifest::UNPACKED,
272 extension_value.get(), "second_extension"));
273 ASSERT_TRUE(CallFunction(REQUEST, kSystemArgs, extension2.get()));
274 EXPECT_EQ(NONE, manager_->PopFirstRequest());
275
276 // When the first extension is unloaded, a new app-suspension blocker
277 // should be created before the display-sleep blocker is destroyed.
278 UnloadExtension(extension_.get());
279 EXPECT_EQ(BLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
280 EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
281 EXPECT_EQ(NONE, manager_->PopFirstRequest());
282
283 // Make the first extension block display-sleep again.
284 ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension_.get()));
285 EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
286 EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
287 EXPECT_EQ(NONE, manager_->PopFirstRequest());
288 }
289
290 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698