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