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