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