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