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