idle_api_unittest.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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(idle::OnStateChanged::kEventName,
111                                  extension_id_,
112                                  NULL);
113  idle_manager_->OnListenerAdded(details);
114}
115
116ScopedListen::~ScopedListen() {
117  const EventListenerInfo details(idle::OnStateChanged::kEventName,
118                                  extension_id_,
119                                  NULL);
120  idle_manager_->OnListenerRemoved(details);
121}
122
123KeyedService* IdleManagerTestFactory(content::BrowserContext* profile) {
124  return new IdleManager(static_cast<Profile*>(profile));
125}
126
127}  // namespace
128
129class 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
139void 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".
156TEST_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".
170TEST_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".
185TEST_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.
204TEST_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.
223TEST_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.
248TEST_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.
278TEST_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.
304TEST_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.
316TEST_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.
331TEST_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.
347TEST_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.
363TEST_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.
379TEST_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.
409TEST_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.
436TEST_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.
455TEST_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.
474TEST_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.
492TEST_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.
530TEST_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.
538TEST_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.
547TEST_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