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