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