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