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