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