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