idle_api_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 2012 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/idle/idle_api.h" 6 7#include <limits.h> 8#include <string> 9 10#include "base/strings/string_number_conversions.h" 11#include "chrome/browser/extensions/api/idle/idle_api_constants.h" 12#include "chrome/browser/extensions/api/idle/idle_manager.h" 13#include "chrome/browser/extensions/api/idle/idle_manager_factory.h" 14#include "chrome/browser/extensions/event_router.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/common/extensions/extension_constants.h" 19#include "chrome/test/base/browser_with_test_window_test.h" 20#include "content/public/browser/notification_details.h" 21#include "content/public/browser/notification_source.h" 22#include "testing/gmock/include/gmock/gmock.h" 23#include "testing/gtest/include/gtest/gtest.h" 24 25using ::testing::_; 26 27namespace utils = extension_function_test_utils; 28 29namespace extensions { 30 31namespace { 32 33class MockEventDelegate : public IdleManager::EventDelegate { 34 public: 35 MockEventDelegate() {} 36 virtual ~MockEventDelegate() {} 37 MOCK_METHOD2(OnStateChanged, void(const std::string&, IdleState)); 38 virtual void RegisterObserver(EventRouter::Observer* observer) {} 39 virtual void UnregisterObserver(EventRouter::Observer* observer) {} 40}; 41 42class TestIdleProvider : public IdleManager::IdleTimeProvider { 43 public: 44 TestIdleProvider(); 45 virtual ~TestIdleProvider(); 46 virtual void CalculateIdleState(int idle_threshold, 47 IdleCallback notify) OVERRIDE; 48 virtual void CalculateIdleTime(IdleTimeCallback notify) OVERRIDE; 49 virtual bool CheckIdleStateIsLocked() OVERRIDE; 50 51 void set_idle_time(int idle_time); 52 void set_locked(bool locked); 53 54 private: 55 int idle_time_; 56 bool locked_; 57}; 58 59TestIdleProvider::TestIdleProvider() 60 : idle_time_(0), 61 locked_(false) { 62} 63 64TestIdleProvider::~TestIdleProvider() { 65} 66 67void TestIdleProvider::CalculateIdleState(int idle_threshold, 68 IdleCallback notify) { 69 if (locked_) { 70 notify.Run(IDLE_STATE_LOCKED); 71 } else { 72 if (idle_time_ >= idle_threshold) { 73 notify.Run(IDLE_STATE_IDLE); 74 } else { 75 notify.Run(IDLE_STATE_ACTIVE); 76 } 77 } 78} 79 80void TestIdleProvider::CalculateIdleTime(IdleTimeCallback notify) { 81 notify.Run(idle_time_); 82} 83 84bool TestIdleProvider::CheckIdleStateIsLocked() { 85 return locked_; 86} 87 88void TestIdleProvider::set_idle_time(int idle_time) { 89 idle_time_ = idle_time; 90} 91 92void TestIdleProvider::set_locked(bool locked) { 93 locked_ = locked; 94} 95 96class ScopedListen { 97 public: 98 ScopedListen(IdleManager* idle_manager, const std::string& extension_id); 99 ~ScopedListen(); 100 101 private: 102 IdleManager* idle_manager_; 103 const std::string extension_id_; 104}; 105 106ScopedListen::ScopedListen(IdleManager* idle_manager, 107 const std::string& extension_id) 108 : idle_manager_(idle_manager), 109 extension_id_(extension_id) { 110 const EventListenerInfo details(idle_api_constants::kOnStateChanged, 111 extension_id_); 112 idle_manager_->OnListenerAdded(details); 113} 114 115ScopedListen::~ScopedListen() { 116 const EventListenerInfo details(idle_api_constants::kOnStateChanged, 117 extension_id_); 118 idle_manager_->OnListenerRemoved(details); 119} 120 121BrowserContextKeyedService* IdleManagerTestFactory( 122 content::BrowserContext* profile) { 123 return new IdleManager(static_cast<Profile*>(profile)); 124} 125 126} // namespace 127 128class IdleTest : public BrowserWithTestWindowTest { 129 public: 130 virtual void SetUp() OVERRIDE; 131 132 protected: 133 base::Value* RunFunctionWithExtension( 134 UIThreadExtensionFunction* function, const std::string& args); 135 136 IdleManager* idle_manager_; 137 TestIdleProvider* idle_provider_; 138 testing::StrictMock<MockEventDelegate>* event_delegate_; 139 scoped_refptr<extensions::Extension> extension_; 140}; 141 142void IdleTest::SetUp() { 143 BrowserWithTestWindowTest::SetUp(); 144 145 IdleManagerFactory::GetInstance()->SetTestingFactory(browser()->profile(), 146 &IdleManagerTestFactory); 147 idle_manager_ = IdleManagerFactory::GetForProfile(browser()->profile()); 148 149 extension_ = utils::CreateEmptyExtensionWithLocation( 150 extensions::Manifest::UNPACKED); 151 152 idle_provider_ = new TestIdleProvider(); 153 idle_manager_->SetIdleTimeProviderForTest( 154 scoped_ptr<IdleManager::IdleTimeProvider>(idle_provider_).Pass()); 155 event_delegate_ = new testing::StrictMock<MockEventDelegate>(); 156 idle_manager_->SetEventDelegateForTest( 157 scoped_ptr<IdleManager::EventDelegate>(event_delegate_).Pass()); 158 idle_manager_->Init(); 159} 160 161base::Value* IdleTest::RunFunctionWithExtension( 162 UIThreadExtensionFunction* function, const std::string& args) { 163 function->set_extension(extension_.get()); 164 return utils::RunFunctionAndReturnSingleResult(function, args, browser()); 165} 166 167// Verifies that "locked" takes priority over "active". 168TEST_F(IdleTest, QueryLockedActive) { 169 idle_provider_->set_locked(true); 170 idle_provider_->set_idle_time(0); 171 172 scoped_ptr<base::Value> result(RunFunctionWithExtension( 173 new IdleQueryStateFunction(), 174 "[60]")); 175 176 std::string idle_state; 177 ASSERT_TRUE(result->GetAsString(&idle_state)); 178 EXPECT_EQ("locked", idle_state); 179} 180 181// Verifies that "locked" takes priority over "idle". 182TEST_F(IdleTest, QueryLockedIdle) { 183 idle_provider_->set_locked(true); 184 idle_provider_->set_idle_time(INT_MAX); 185 186 scoped_ptr<base::Value> result(RunFunctionWithExtension( 187 new IdleQueryStateFunction(), 188 "[60]")); 189 190 std::string idle_state; 191 ASSERT_TRUE(result->GetAsString(&idle_state)); 192 EXPECT_EQ("locked", idle_state); 193} 194 195// Verifies that any amount of idle time less than the detection interval 196// translates to a state of "active". 197TEST_F(IdleTest, QueryActive) { 198 idle_provider_->set_locked(false); 199 200 for (int time = 0; time < 60; ++time) { 201 SCOPED_TRACE(time); 202 idle_provider_->set_idle_time(time); 203 204 scoped_ptr<base::Value> result(RunFunctionWithExtension( 205 new IdleQueryStateFunction(), 206 "[60]")); 207 208 std::string idle_state; 209 ASSERT_TRUE(result->GetAsString(&idle_state)); 210 EXPECT_EQ("active", idle_state); 211 } 212} 213 214// Verifies that an idle time >= the detection interval returns the "idle" 215// state. 216TEST_F(IdleTest, QueryIdle) { 217 idle_provider_->set_locked(false); 218 219 for (int time = 80; time >= 60; --time) { 220 SCOPED_TRACE(time); 221 idle_provider_->set_idle_time(time); 222 223 scoped_ptr<base::Value> result(RunFunctionWithExtension( 224 new IdleQueryStateFunction(), 225 "[60]")); 226 227 std::string idle_state; 228 ASSERT_TRUE(result->GetAsString(&idle_state)); 229 EXPECT_EQ("idle", idle_state); 230 } 231} 232 233// Verifies that requesting a detection interval < 15 has the same effect as 234// passing in 15. 235TEST_F(IdleTest, QueryMinThreshold) { 236 idle_provider_->set_locked(false); 237 238 for (int threshold = 0; threshold < 20; ++threshold) { 239 for (int time = 10; time < 60; ++time) { 240 SCOPED_TRACE(threshold); 241 SCOPED_TRACE(time); 242 idle_provider_->set_idle_time(time); 243 244 std::string args = "[" + base::IntToString(threshold) + "]"; 245 scoped_ptr<base::Value> result(RunFunctionWithExtension( 246 new IdleQueryStateFunction(), args)); 247 248 std::string idle_state; 249 ASSERT_TRUE(result->GetAsString(&idle_state)); 250 251 int real_threshold = (threshold < 15) ? 15 : threshold; 252 const char* expected = (time < real_threshold) ? "active" : "idle"; 253 EXPECT_EQ(expected, idle_state); 254 } 255 } 256} 257 258// Verifies that passing in a detection interval > 4 hours has the same effect 259// as passing in 4 hours. 260TEST_F(IdleTest, QueryMaxThreshold) { 261 idle_provider_->set_locked(false); 262 263 const int kFourHoursInSeconds = 4*60*60; 264 265 for (int threshold = kFourHoursInSeconds - 20; 266 threshold < (kFourHoursInSeconds + 20); ++threshold) { 267 for (int time = kFourHoursInSeconds - 30; time < kFourHoursInSeconds + 30; 268 ++time) { 269 SCOPED_TRACE(threshold); 270 SCOPED_TRACE(time); 271 idle_provider_->set_idle_time(time); 272 273 std::string args = "[" + base::IntToString(threshold) + "]"; 274 scoped_ptr<base::Value> result(RunFunctionWithExtension( 275 new IdleQueryStateFunction(), args)); 276 277 std::string idle_state; 278 ASSERT_TRUE(result->GetAsString(&idle_state)); 279 280 int real_threshold = (threshold > kFourHoursInSeconds) ? 281 kFourHoursInSeconds : threshold; 282 const char* expected = (time < real_threshold) ? "active" : "idle"; 283 EXPECT_EQ(expected, idle_state); 284 } 285 } 286} 287 288// Verifies that transitioning from an active to idle state fires an "idle" 289// OnStateChanged event. 290TEST_F(IdleTest, ActiveToIdle) { 291 ScopedListen listen_test(idle_manager_, "test"); 292 293 idle_provider_->set_locked(false); 294 295 for (int time = 0; time < 60; ++time) { 296 SCOPED_TRACE(time); 297 idle_provider_->set_idle_time(time); 298 299 idle_manager_->UpdateIdleState(); 300 } 301 302 idle_provider_->set_idle_time(60); 303 304 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_IDLE)); 305 idle_manager_->UpdateIdleState(); 306 testing::Mock::VerifyAndClearExpectations(event_delegate_); 307 308 for (int time = 61; time < 75; ++time) { 309 SCOPED_TRACE(time); 310 idle_provider_->set_idle_time(time); 311 idle_manager_->UpdateIdleState(); 312 } 313} 314 315// Verifies that locking an active system generates a "locked" event. 316TEST_F(IdleTest, ActiveToLocked) { 317 ScopedListen listen_test(idle_manager_, "test"); 318 319 idle_provider_->set_locked(true); 320 idle_provider_->set_idle_time(5); 321 322 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_LOCKED)); 323 idle_manager_->UpdateIdleState(); 324} 325 326// Verifies that transitioning from an idle to active state generates an 327// "active" event. 328TEST_F(IdleTest, IdleToActive) { 329 ScopedListen listen_test(idle_manager_, "test"); 330 331 idle_provider_->set_locked(false); 332 idle_provider_->set_idle_time(75); 333 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_IDLE)); 334 idle_manager_->UpdateIdleState(); 335 testing::Mock::VerifyAndClearExpectations(event_delegate_); 336 337 idle_provider_->set_idle_time(0); 338 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_ACTIVE)); 339 idle_manager_->UpdateIdleState(); 340} 341 342// Verifies that locking an idle system generates a "locked" event. 343TEST_F(IdleTest, IdleToLocked) { 344 ScopedListen listen_test(idle_manager_, "test"); 345 346 idle_provider_->set_locked(false); 347 idle_provider_->set_idle_time(75); 348 349 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_IDLE)); 350 idle_manager_->UpdateIdleState(); 351 testing::Mock::VerifyAndClearExpectations(event_delegate_); 352 353 idle_provider_->set_locked(true); 354 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_LOCKED)); 355 idle_manager_->UpdateIdleState(); 356} 357 358// Verifies that unlocking an active system generates an "active" event. 359TEST_F(IdleTest, LockedToActive) { 360 ScopedListen listen_test(idle_manager_, "test"); 361 362 idle_provider_->set_locked(true); 363 idle_provider_->set_idle_time(0); 364 365 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_LOCKED)); 366 idle_manager_->UpdateIdleState(); 367 368 idle_provider_->set_locked(false); 369 idle_provider_->set_idle_time(5); 370 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_ACTIVE)); 371 idle_manager_->UpdateIdleState(); 372} 373 374// Verifies that unlocking an inactive system generates an "idle" event. 375TEST_F(IdleTest, LockedToIdle) { 376 ScopedListen listen_test(idle_manager_, "test"); 377 378 idle_provider_->set_locked(true); 379 idle_provider_->set_idle_time(75); 380 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_LOCKED)); 381 idle_manager_->UpdateIdleState(); 382 testing::Mock::VerifyAndClearExpectations(event_delegate_); 383 384 idle_provider_->set_locked(false); 385 EXPECT_CALL(*event_delegate_, OnStateChanged("test", IDLE_STATE_IDLE)); 386 idle_manager_->UpdateIdleState(); 387} 388 389// Verifies that events are routed to extensions that have one or more listeners 390// in scope. 391TEST_F(IdleTest, MultipleExtensions) { 392 ScopedListen listen_1(idle_manager_, "1"); 393 ScopedListen listen_2(idle_manager_, "2"); 394 395 idle_provider_->set_locked(true); 396 EXPECT_CALL(*event_delegate_, OnStateChanged("1", IDLE_STATE_LOCKED)); 397 EXPECT_CALL(*event_delegate_, OnStateChanged("2", IDLE_STATE_LOCKED)); 398 idle_manager_->UpdateIdleState(); 399 testing::Mock::VerifyAndClearExpectations(event_delegate_); 400 401 { 402 ScopedListen listen_2prime(idle_manager_, "2"); 403 ScopedListen listen_3(idle_manager_, "3"); 404 idle_provider_->set_locked(false); 405 EXPECT_CALL(*event_delegate_, OnStateChanged("1", IDLE_STATE_ACTIVE)); 406 EXPECT_CALL(*event_delegate_, OnStateChanged("2", IDLE_STATE_ACTIVE)); 407 EXPECT_CALL(*event_delegate_, OnStateChanged("3", IDLE_STATE_ACTIVE)); 408 idle_manager_->UpdateIdleState(); 409 testing::Mock::VerifyAndClearExpectations(event_delegate_); 410 } 411 412 idle_provider_->set_locked(true); 413 EXPECT_CALL(*event_delegate_, OnStateChanged("1", IDLE_STATE_LOCKED)); 414 EXPECT_CALL(*event_delegate_, OnStateChanged("2", IDLE_STATE_LOCKED)); 415 idle_manager_->UpdateIdleState(); 416} 417 418// Verifies that setDetectionInterval changes the detection interval from the 419// default of 60 seconds, and that the call only affects a single extension's 420// IdleMonitor. 421TEST_F(IdleTest, SetDetectionInterval) { 422 ScopedListen listen_default(idle_manager_, "default"); 423 ScopedListen listen_extension(idle_manager_, extension_->id()); 424 425 scoped_ptr<base::Value> result45(RunFunctionWithExtension( 426 new IdleSetDetectionIntervalFunction(), 427 "[45]")); 428 429 idle_provider_->set_locked(false); 430 idle_provider_->set_idle_time(44); 431 idle_manager_->UpdateIdleState(); 432 433 idle_provider_->set_idle_time(45); 434 EXPECT_CALL(*event_delegate_, 435 OnStateChanged(extension_->id(), IDLE_STATE_IDLE)); 436 idle_manager_->UpdateIdleState(); 437 // Verify that the expectation has been fulfilled before incrementing the 438 // time again. 439 testing::Mock::VerifyAndClearExpectations(event_delegate_); 440 441 idle_provider_->set_idle_time(60); 442 EXPECT_CALL(*event_delegate_, OnStateChanged("default", IDLE_STATE_IDLE)); 443 idle_manager_->UpdateIdleState(); 444} 445 446// Verifies that setting the detection interval before creating the listener 447// works correctly. 448TEST_F(IdleTest, SetDetectionIntervalBeforeListener) { 449 scoped_ptr<base::Value> result45(RunFunctionWithExtension( 450 new IdleSetDetectionIntervalFunction(), 451 "[45]")); 452 453 ScopedListen listen_extension(idle_manager_, extension_->id()); 454 455 idle_provider_->set_locked(false); 456 idle_provider_->set_idle_time(44); 457 idle_manager_->UpdateIdleState(); 458 459 idle_provider_->set_idle_time(45); 460 EXPECT_CALL(*event_delegate_, 461 OnStateChanged(extension_->id(), IDLE_STATE_IDLE)); 462 idle_manager_->UpdateIdleState(); 463} 464 465// Verifies that setting a detection interval above the maximum value results 466// in an interval of 4 hours. 467TEST_F(IdleTest, SetDetectionIntervalMaximum) { 468 ScopedListen listen_extension(idle_manager_, extension_->id()); 469 470 scoped_ptr<base::Value> result(RunFunctionWithExtension( 471 new IdleSetDetectionIntervalFunction(), 472 "[18000]")); // five hours in seconds 473 474 idle_provider_->set_locked(false); 475 idle_provider_->set_idle_time(4*60*60 - 1); 476 idle_manager_->UpdateIdleState(); 477 478 idle_provider_->set_idle_time(4*60*60); 479 EXPECT_CALL(*event_delegate_, 480 OnStateChanged(extension_->id(), IDLE_STATE_IDLE)); 481 idle_manager_->UpdateIdleState(); 482} 483 484// Verifies that setting a detection interval below the minimum value results 485// in an interval of 15 seconds. 486TEST_F(IdleTest, SetDetectionIntervalMinimum) { 487 ScopedListen listen_extension(idle_manager_, extension_->id()); 488 489 scoped_ptr<base::Value> result(RunFunctionWithExtension( 490 new IdleSetDetectionIntervalFunction(), 491 "[10]")); 492 493 idle_provider_->set_locked(false); 494 idle_provider_->set_idle_time(14); 495 idle_manager_->UpdateIdleState(); 496 497 idle_provider_->set_idle_time(15); 498 EXPECT_CALL(*event_delegate_, 499 OnStateChanged(extension_->id(), IDLE_STATE_IDLE)); 500 idle_manager_->UpdateIdleState(); 501} 502 503// Verifies that an extension's detection interval is discarded when it unloads. 504TEST_F(IdleTest, UnloadCleanup) { 505 { 506 ScopedListen listen(idle_manager_, extension_->id()); 507 508 scoped_ptr<base::Value> result45(RunFunctionWithExtension( 509 new IdleSetDetectionIntervalFunction(), 510 "[15]")); 511 } 512 513 // Listener count dropping to zero does not reset threshold. 514 515 { 516 ScopedListen listen(idle_manager_, extension_->id()); 517 idle_provider_->set_idle_time(16); 518 EXPECT_CALL(*event_delegate_, 519 OnStateChanged(extension_->id(), IDLE_STATE_IDLE)); 520 idle_manager_->UpdateIdleState(); 521 testing::Mock::VerifyAndClearExpectations(event_delegate_); 522 } 523 524 // Threshold will reset after unload (and listen count == 0) 525 UnloadedExtensionInfo details(extension_.get(), 526 extension_misc::UNLOAD_REASON_UNINSTALL); 527 idle_manager_->Observe( 528 chrome::NOTIFICATION_EXTENSION_UNLOADED, 529 content::Source<Profile>(browser()->profile()), 530 content::Details<UnloadedExtensionInfo>(&details)); 531 532 { 533 ScopedListen listen(idle_manager_, extension_->id()); 534 idle_manager_->UpdateIdleState(); 535 testing::Mock::VerifyAndClearExpectations(event_delegate_); 536 537 idle_provider_->set_idle_time(61); 538 EXPECT_CALL(*event_delegate_, 539 OnStateChanged(extension_->id(), IDLE_STATE_IDLE)); 540 idle_manager_->UpdateIdleState(); 541 } 542} 543 544// Verifies that unloading an extension with no listeners or threshold works. 545TEST_F(IdleTest, UnloadOnly) { 546 UnloadedExtensionInfo details(extension_.get(), 547 extension_misc::UNLOAD_REASON_UNINSTALL); 548 idle_manager_->Observe( 549 chrome::NOTIFICATION_EXTENSION_UNLOADED, 550 content::Source<Profile>(browser()->profile()), 551 content::Details<UnloadedExtensionInfo>(&details)); 552} 553 554// Verifies that its ok for the unload notification to happen before all the 555// listener removals. 556TEST_F(IdleTest, UnloadWhileListening) { 557 ScopedListen listen(idle_manager_, extension_->id()); 558 UnloadedExtensionInfo details(extension_.get(), 559 extension_misc::UNLOAD_REASON_UNINSTALL); 560 idle_manager_->Observe( 561 chrome::NOTIFICATION_EXTENSION_UNLOADED, 562 content::Source<Profile>(browser()->profile()), 563 content::Details<UnloadedExtensionInfo>(&details)); 564} 565 566} // namespace extensions 567