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