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