Home | History | Annotate | Download | only in idle
      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/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 
     25 using ::testing::_;
     26 
     27 namespace utils = extension_function_test_utils;
     28 
     29 namespace extensions {
     30 
     31 namespace {
     32 
     33 class 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 
     42 class 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 
     59 TestIdleProvider::TestIdleProvider()
     60     : idle_time_(0),
     61       locked_(false) {
     62 }
     63 
     64 TestIdleProvider::~TestIdleProvider() {
     65 }
     66 
     67 void 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 
     80 void TestIdleProvider::CalculateIdleTime(IdleTimeCallback notify) {
     81   notify.Run(idle_time_);
     82 }
     83 
     84 bool TestIdleProvider::CheckIdleStateIsLocked() {
     85   return locked_;
     86 }
     87 
     88 void TestIdleProvider::set_idle_time(int idle_time) {
     89   idle_time_ = idle_time;
     90 }
     91 
     92 void TestIdleProvider::set_locked(bool locked) {
     93   locked_ = locked;
     94 }
     95 
     96 class 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 
    106 ScopedListen::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 
    115 ScopedListen::~ScopedListen() {
    116   const EventListenerInfo details(idle_api_constants::kOnStateChanged,
    117                                   extension_id_);
    118   idle_manager_->OnListenerRemoved(details);
    119 }
    120 
    121 BrowserContextKeyedService* IdleManagerTestFactory(
    122     content::BrowserContext* profile) {
    123   return new IdleManager(static_cast<Profile*>(profile));
    124 }
    125 
    126 }  // namespace
    127 
    128 class 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 
    142 void 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 
    161 base::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".
    168 TEST_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".
    182 TEST_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".
    197 TEST_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.
    216 TEST_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.
    235 TEST_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.
    260 TEST_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.
    290 TEST_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.
    316 TEST_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.
    328 TEST_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.
    343 TEST_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.
    359 TEST_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.
    375 TEST_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.
    391 TEST_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.
    421 TEST_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.
    448 TEST_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.
    467 TEST_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.
    486 TEST_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.
    504 TEST_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.
    545 TEST_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.
    556 TEST_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