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