Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / api / power / power_api_unittest.cc
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 "extensions/browser/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/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"
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   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
71     // weak pointers.
72     PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting(
73         base::Bind(&PowerSaveBlockerStubManager::CreateStub,
74                    base::Unretained(this)));
75   }
76
77   ~PowerSaveBlockerStubManager() {
78     PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting(
79         PowerApiManager::CreateBlockerFunction());
80   }
81
82   // Removes and returns the first item from |requests_|.  Returns NONE if
83   // |requests_| is empty.
84   Request PopFirstRequest() {
85     if (requests_.empty())
86       return NONE;
87
88     Request request = requests_.front();
89     requests_.pop_front();
90     return request;
91   }
92
93  private:
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;
99     switch (type) {
100       case content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension:
101         requests_.push_back(BLOCK_APP_SUSPENSION);
102         unblock_request = UNBLOCK_APP_SUSPENSION;
103         break;
104       case content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
105         requests_.push_back(BLOCK_DISPLAY_SLEEP);
106         unblock_request = UNBLOCK_DISPLAY_SLEEP;
107         break;
108     }
109     return scoped_ptr<content::PowerSaveBlocker>(
110         new PowerSaveBlockerStub(
111             base::Bind(&PowerSaveBlockerStubManager::AppendRequest,
112                        weak_ptr_factory_.GetWeakPtr(),
113                        unblock_request)));
114   }
115
116   void AppendRequest(Request request) {
117     requests_.push_back(request);
118   }
119
120   content::BrowserContext* browser_context_;
121
122   // Requests in chronological order.
123   std::deque<Request> requests_;
124
125   base::WeakPtrFactory<PowerSaveBlockerStubManager> weak_ptr_factory_;
126
127   DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStubManager);
128 };
129
130 }  // namespace
131
132 class PowerApiTest : public BrowserWithTestWindowTest {
133  public:
134   virtual void SetUp() OVERRIDE {
135     BrowserWithTestWindowTest::SetUp();
136     manager_.reset(new PowerSaveBlockerStubManager(profile()));
137     extension_ = utils::CreateEmptyExtensionWithLocation(
138         extensions::Manifest::UNPACKED);
139   }
140
141   virtual void TearDown() OVERRIDE {
142     extension_ = NULL;
143     manager_.reset();
144     BrowserWithTestWindowTest::TearDown();
145   }
146
147  protected:
148   // Shorthand for PowerRequestKeepAwakeFunction and
149   // PowerReleaseKeepAwakeFunction.
150   enum FunctionType {
151     REQUEST,
152     RELEASE,
153   };
154
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(
161         type == REQUEST ?
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);
168   }
169
170   // Send a notification to PowerApiManager saying that |extension| has
171   // been unloaded.
172   void UnloadExtension(extensions::Extension* extension) {
173     PowerApiManager::Get(profile())->OnExtensionUnloaded(
174         profile(), extension, UnloadedExtensionInfo::REASON_UNINSTALL);
175   }
176
177   scoped_ptr<PowerSaveBlockerStubManager> manager_;
178   scoped_refptr<extensions::Extension> extension_;
179 };
180
181 TEST_F(PowerApiTest, RequestAndRelease) {
182   // Simulate an extension making and releasing a "display" request and a
183   // "system" request.
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());
190
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());
197 }
198
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());
206
207   UnloadExtension(extension_.get());
208   EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
209   EXPECT_EQ(NONE, manager_->PopFirstRequest());
210 }
211
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());
217 }
218
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());
227
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());
232
233   ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
234   EXPECT_EQ(UNBLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
235   EXPECT_EQ(NONE, manager_->PopFirstRequest());
236 }
237
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());
246
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());
251
252   ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension_.get()));
253   EXPECT_EQ(UNBLOCK_APP_SUSPENSION, manager_->PopFirstRequest());
254   EXPECT_EQ(NONE, manager_->PopFirstRequest());
255 }
256
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());
262
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());
273
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());
280
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());
286 }
287
288 }  // namespace extensions