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