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