• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 using ::testing::_;
26 
27 namespace idle = extensions::api::idle;
28 
29 namespace extensions {
30 
31 namespace {
32 
33 class MockEventDelegate : public IdleManager::EventDelegate {
34  public:
MockEventDelegate()35   MockEventDelegate() {}
~MockEventDelegate()36   virtual ~MockEventDelegate() {}
37   MOCK_METHOD2(OnStateChanged, void(const std::string&, IdleState));
RegisterObserver(EventRouter::Observer * observer)38   virtual void RegisterObserver(EventRouter::Observer* observer) {}
UnregisterObserver(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 
TestIdleProvider()59 TestIdleProvider::TestIdleProvider()
60     : idle_time_(0),
61       locked_(false) {
62 }
63 
~TestIdleProvider()64 TestIdleProvider::~TestIdleProvider() {
65 }
66 
CalculateIdleState(int idle_threshold,IdleCallback notify)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 
CalculateIdleTime(IdleTimeCallback notify)80 void TestIdleProvider::CalculateIdleTime(IdleTimeCallback notify) {
81   notify.Run(idle_time_);
82 }
83 
CheckIdleStateIsLocked()84 bool TestIdleProvider::CheckIdleStateIsLocked() {
85   return locked_;
86 }
87 
set_idle_time(int idle_time)88 void TestIdleProvider::set_idle_time(int idle_time) {
89   idle_time_ = idle_time;
90 }
91 
set_locked(bool locked)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 
ScopedListen(IdleManager * idle_manager,const std::string & extension_id)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::OnStateChanged::kEventName,
111                                   extension_id_,
112                                   NULL);
113   idle_manager_->OnListenerAdded(details);
114 }
115 
~ScopedListen()116 ScopedListen::~ScopedListen() {
117   const EventListenerInfo details(idle::OnStateChanged::kEventName,
118                                   extension_id_,
119                                   NULL);
120   idle_manager_->OnListenerRemoved(details);
121 }
122 
IdleManagerTestFactory(content::BrowserContext * profile)123 KeyedService* IdleManagerTestFactory(content::BrowserContext* profile) {
124   return new IdleManager(static_cast<Profile*>(profile));
125 }
126 
127 }  // namespace
128 
129 class 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 
SetUp()139 void 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".
TEST_F(IdleTest,QueryLockedActive)156 TEST_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".
TEST_F(IdleTest,QueryLockedIdle)170 TEST_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".
TEST_F(IdleTest,QueryActive)185 TEST_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.
TEST_F(IdleTest,QueryIdle)204 TEST_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.
TEST_F(IdleTest,QueryMinThreshold)223 TEST_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.
TEST_F(IdleTest,QueryMaxThreshold)248 TEST_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.
TEST_F(IdleTest,ActiveToIdle)278 TEST_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.
TEST_F(IdleTest,ActiveToLocked)304 TEST_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.
TEST_F(IdleTest,IdleToActive)316 TEST_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.
TEST_F(IdleTest,IdleToLocked)331 TEST_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.
TEST_F(IdleTest,LockedToActive)347 TEST_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.
TEST_F(IdleTest,LockedToIdle)363 TEST_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.
TEST_F(IdleTest,MultipleExtensions)379 TEST_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.
TEST_F(IdleTest,SetDetectionInterval)409 TEST_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.
TEST_F(IdleTest,SetDetectionIntervalBeforeListener)436 TEST_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.
TEST_F(IdleTest,SetDetectionIntervalMaximum)455 TEST_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.
TEST_F(IdleTest,SetDetectionIntervalMinimum)474 TEST_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.
TEST_F(IdleTest,UnloadCleanup)492 TEST_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.
TEST_F(IdleTest,UnloadOnly)530 TEST_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.
TEST_F(IdleTest,UnloadWhileListening)538 TEST_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.
TEST_F(IdleTest,ReAddListener)547 TEST_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