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