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 // This file tests the chrome.alarms extension API.
6
7 #include "base/test/simple_test_clock.h"
8 #include "base/values.h"
9 #include "chrome/browser/extensions/api/alarms/alarm_manager.h"
10 #include "chrome/browser/extensions/api/alarms/alarms_api.h"
11 #include "chrome/browser/extensions/extension_api_unittest.h"
12 #include "chrome/browser/extensions/extension_function_test_utils.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/test/mock_render_process_host.h"
17 #include "extensions/common/extension_messages.h"
18 #include "ipc/ipc_test_sink.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 typedef extensions::api::alarms::Alarm JsAlarm;
23
24 namespace utils = extension_function_test_utils;
25
26 namespace extensions {
27
28 namespace {
29
30 // Test delegate which quits the message loop when an alarm fires.
31 class AlarmDelegate : public AlarmManager::Delegate {
32 public:
~AlarmDelegate()33 virtual ~AlarmDelegate() {}
OnAlarm(const std::string & extension_id,const Alarm & alarm)34 virtual void OnAlarm(const std::string& extension_id,
35 const Alarm& alarm) OVERRIDE {
36 alarms_seen.push_back(alarm.js_alarm->name);
37 if (base::MessageLoop::current()->is_running())
38 base::MessageLoop::current()->Quit();
39 }
40
41 std::vector<std::string> alarms_seen;
42 };
43
44 } // namespace
45
RunScheduleNextPoll(AlarmManager * alarm_manager)46 void RunScheduleNextPoll(AlarmManager* alarm_manager) {
47 alarm_manager->ScheduleNextPoll();
48 }
49
50 class ExtensionAlarmsTest : public ExtensionApiUnittest {
51 public:
52 using ExtensionApiUnittest::RunFunction;
53
SetUp()54 virtual void SetUp() {
55 ExtensionApiUnittest::SetUp();
56
57 test_clock_ = new base::SimpleTestClock();
58 alarm_manager_ = AlarmManager::Get(browser()->profile());
59 alarm_manager_->SetClockForTesting(test_clock_);
60
61 alarm_delegate_ = new AlarmDelegate();
62 alarm_manager_->set_delegate(alarm_delegate_);
63
64 // Make sure there's a RenderViewHost for alarms to warn into.
65 CreateBackgroundPage();
66
67 test_clock_->SetNow(base::Time::FromDoubleT(10));
68 }
69
CreateAlarm(const std::string & args)70 void CreateAlarm(const std::string& args) {
71 RunFunction(new AlarmsCreateFunction(test_clock_), args);
72 }
73
74 // Takes a JSON result from a function and converts it to a vector of
75 // JsAlarms.
ToAlarmList(base::ListValue * value)76 std::vector<linked_ptr<JsAlarm> > ToAlarmList(base::ListValue* value) {
77 std::vector<linked_ptr<JsAlarm> > list;
78 for (size_t i = 0; i < value->GetSize(); ++i) {
79 linked_ptr<JsAlarm> alarm(new JsAlarm);
80 base::DictionaryValue* alarm_value;
81 if (!value->GetDictionary(i, &alarm_value)) {
82 ADD_FAILURE() << "Expected a list of Alarm objects.";
83 return list;
84 }
85 EXPECT_TRUE(JsAlarm::Populate(*alarm_value, alarm.get()));
86 list.push_back(alarm);
87 }
88 return list;
89 }
90
91 // Creates up to 3 alarms using the extension API.
CreateAlarms(size_t num_alarms)92 void CreateAlarms(size_t num_alarms) {
93 CHECK(num_alarms <= 3);
94
95 const char* kCreateArgs[] = {
96 "[null, {\"periodInMinutes\": 0.001}]",
97 "[\"7\", {\"periodInMinutes\": 7}]",
98 "[\"0\", {\"delayInMinutes\": 0}]",
99 };
100 for (size_t i = 0; i < num_alarms; ++i) {
101 scoped_ptr<base::DictionaryValue> result(RunFunctionAndReturnDictionary(
102 new AlarmsCreateFunction(test_clock_), kCreateArgs[i]));
103 EXPECT_FALSE(result.get());
104 }
105 }
106
107 base::SimpleTestClock* test_clock_;
108 AlarmManager* alarm_manager_;
109 AlarmDelegate* alarm_delegate_;
110 };
111
ExtensionAlarmsTestGetAllAlarmsCallback(const AlarmManager::AlarmList * alarms)112 void ExtensionAlarmsTestGetAllAlarmsCallback(
113 const AlarmManager::AlarmList* alarms) {
114 // Ensure the alarm is gone.
115 ASSERT_FALSE(alarms);
116 }
117
ExtensionAlarmsTestGetAlarmCallback(ExtensionAlarmsTest * test,Alarm * alarm)118 void ExtensionAlarmsTestGetAlarmCallback(
119 ExtensionAlarmsTest* test, Alarm* alarm) {
120 ASSERT_TRUE(alarm);
121 EXPECT_EQ("", alarm->js_alarm->name);
122 EXPECT_DOUBLE_EQ(10000, alarm->js_alarm->scheduled_time);
123 EXPECT_FALSE(alarm->js_alarm->period_in_minutes.get());
124
125 // Now wait for the alarm to fire. Our test delegate will quit the
126 // MessageLoop when that happens.
127 base::MessageLoop::current()->Run();
128
129 ASSERT_EQ(1u, test->alarm_delegate_->alarms_seen.size());
130 EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
131
132 // Ensure the alarm is gone.
133 test->alarm_manager_->GetAllAlarms(test->extension()->id(), base::Bind(
134 ExtensionAlarmsTestGetAllAlarmsCallback));
135 }
136
TEST_F(ExtensionAlarmsTest,Create)137 TEST_F(ExtensionAlarmsTest, Create) {
138 test_clock_->SetNow(base::Time::FromDoubleT(10));
139 // Create 1 non-repeating alarm.
140 CreateAlarm("[null, {\"delayInMinutes\": 0}]");
141
142 alarm_manager_->GetAlarm(extension()->id(), std::string(), base::Bind(
143 ExtensionAlarmsTestGetAlarmCallback, this));
144 }
145
ExtensionAlarmsTestCreateRepeatingGetAlarmCallback(ExtensionAlarmsTest * test,Alarm * alarm)146 void ExtensionAlarmsTestCreateRepeatingGetAlarmCallback(
147 ExtensionAlarmsTest* test, Alarm* alarm) {
148 ASSERT_TRUE(alarm);
149 EXPECT_EQ("", alarm->js_alarm->name);
150 EXPECT_DOUBLE_EQ(10060, alarm->js_alarm->scheduled_time);
151 EXPECT_THAT(alarm->js_alarm->period_in_minutes,
152 testing::Pointee(testing::DoubleEq(0.001)));
153
154 test->test_clock_->Advance(base::TimeDelta::FromSeconds(1));
155 // Now wait for the alarm to fire. Our test delegate will quit the
156 // MessageLoop when that happens.
157 base::MessageLoop::current()->Run();
158
159 test->test_clock_->Advance(base::TimeDelta::FromSeconds(1));
160 // Wait again, and ensure the alarm fires again.
161 RunScheduleNextPoll(test->alarm_manager_);
162 base::MessageLoop::current()->Run();
163
164 ASSERT_EQ(2u, test->alarm_delegate_->alarms_seen.size());
165 EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
166 }
167
TEST_F(ExtensionAlarmsTest,CreateRepeating)168 TEST_F(ExtensionAlarmsTest, CreateRepeating) {
169 test_clock_->SetNow(base::Time::FromDoubleT(10));
170
171 // Create 1 repeating alarm.
172 CreateAlarm("[null, {\"periodInMinutes\": 0.001}]");
173
174 alarm_manager_->GetAlarm(extension()->id(), std::string(), base::Bind(
175 ExtensionAlarmsTestCreateRepeatingGetAlarmCallback, this));
176 }
177
ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback(ExtensionAlarmsTest * test,Alarm * alarm)178 void ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback(
179 ExtensionAlarmsTest* test, Alarm* alarm) {
180 ASSERT_FALSE(alarm);
181
182 ASSERT_EQ(1u, test->alarm_delegate_->alarms_seen.size());
183 EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
184 }
185
ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback(ExtensionAlarmsTest * test,Alarm * alarm)186 void ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback(
187 ExtensionAlarmsTest* test, Alarm* alarm) {
188 ASSERT_TRUE(alarm);
189 EXPECT_EQ("", alarm->js_alarm->name);
190 EXPECT_DOUBLE_EQ(10001, alarm->js_alarm->scheduled_time);
191 EXPECT_THAT(alarm->js_alarm->period_in_minutes,
192 testing::IsNull());
193
194 test->test_clock_->SetNow(base::Time::FromDoubleT(10.1));
195 // Now wait for the alarm to fire. Our test delegate will quit the
196 // MessageLoop when that happens.
197 base::MessageLoop::current()->Run();
198
199 test->alarm_manager_->GetAlarm(
200 test->extension()->id(), std::string(), base::Bind(
201 ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback, test));
202 }
203
TEST_F(ExtensionAlarmsTest,CreateAbsolute)204 TEST_F(ExtensionAlarmsTest, CreateAbsolute) {
205 test_clock_->SetNow(base::Time::FromDoubleT(9.99));
206 CreateAlarm("[null, {\"when\": 10001}]");
207
208 alarm_manager_->GetAlarm(extension()->id(), std::string(), base::Bind(
209 ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback, this));
210 }
211
ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm3Callback(ExtensionAlarmsTest * test,Alarm * alarm)212 void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm3Callback(
213 ExtensionAlarmsTest* test, Alarm* alarm) {
214 ASSERT_TRUE(alarm);
215 EXPECT_THAT(test->alarm_delegate_->alarms_seen, testing::ElementsAre("", ""));
216 }
217
ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm2Callback(ExtensionAlarmsTest * test,Alarm * alarm)218 void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm2Callback(
219 ExtensionAlarmsTest* test, Alarm* alarm) {
220 ASSERT_TRUE(alarm);
221 EXPECT_THAT(test->alarm_delegate_->alarms_seen, testing::ElementsAre(""));
222
223 test->test_clock_->SetNow(base::Time::FromDoubleT(10.7));
224 base::MessageLoop::current()->Run();
225
226 test->alarm_manager_->GetAlarm(
227 test->extension()->id(), std::string(), base::Bind(
228 ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm3Callback,
229 test));
230 }
231
ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm1Callback(ExtensionAlarmsTest * test,Alarm * alarm)232 void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm1Callback(
233 ExtensionAlarmsTest* test, Alarm* alarm) {
234 ASSERT_TRUE(alarm);
235 EXPECT_EQ("", alarm->js_alarm->name);
236 EXPECT_DOUBLE_EQ(10001, alarm->js_alarm->scheduled_time);
237 EXPECT_THAT(alarm->js_alarm->period_in_minutes,
238 testing::Pointee(testing::DoubleEq(0.001)));
239
240 test->test_clock_->SetNow(base::Time::FromDoubleT(10.1));
241 // Now wait for the alarm to fire. Our test delegate will quit the
242 // MessageLoop when that happens.
243 base::MessageLoop::current()->Run();
244
245 test->alarm_manager_->GetAlarm(
246 test->extension()->id(), std::string(), base::Bind(
247 ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm2Callback,
248 test));
249 }
250
TEST_F(ExtensionAlarmsTest,CreateRepeatingWithQuickFirstCall)251 TEST_F(ExtensionAlarmsTest, CreateRepeatingWithQuickFirstCall) {
252 test_clock_->SetNow(base::Time::FromDoubleT(9.99));
253 CreateAlarm("[null, {\"when\": 10001, \"periodInMinutes\": 0.001}]");
254
255 alarm_manager_->GetAlarm(extension()->id(), std::string(), base::Bind(
256 ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm1Callback,
257 this));
258 }
259
ExtensionAlarmsTestCreateDupeGetAllAlarmsCallback(const AlarmManager::AlarmList * alarms)260 void ExtensionAlarmsTestCreateDupeGetAllAlarmsCallback(
261 const AlarmManager::AlarmList* alarms) {
262 ASSERT_TRUE(alarms);
263 EXPECT_EQ(1u, alarms->size());
264 EXPECT_DOUBLE_EQ(430000, (*alarms)[0].js_alarm->scheduled_time);
265 }
266
TEST_F(ExtensionAlarmsTest,CreateDupe)267 TEST_F(ExtensionAlarmsTest, CreateDupe) {
268 test_clock_->SetNow(base::Time::FromDoubleT(10));
269
270 // Create 2 duplicate alarms. The first should be overridden.
271 CreateAlarm("[\"dup\", {\"delayInMinutes\": 1}]");
272 CreateAlarm("[\"dup\", {\"delayInMinutes\": 7}]");
273
274 alarm_manager_->GetAllAlarms(extension()->id(), base::Bind(
275 ExtensionAlarmsTestCreateDupeGetAllAlarmsCallback));
276 }
277
TEST_F(ExtensionAlarmsTest,CreateDelayBelowMinimum)278 TEST_F(ExtensionAlarmsTest, CreateDelayBelowMinimum) {
279 // Create an alarm with delay below the minimum accepted value.
280 CreateAlarm("[\"negative\", {\"delayInMinutes\": -0.2}]");
281 IPC::TestSink& sink = static_cast<content::MockRenderProcessHost*>(
282 contents()->GetRenderViewHost()->GetProcess())->sink();
283 const IPC::Message* warning = sink.GetUniqueMessageMatching(
284 ExtensionMsg_AddMessageToConsole::ID);
285 ASSERT_TRUE(warning);
286 ExtensionMsg_AddMessageToConsole::Param params;
287 ExtensionMsg_AddMessageToConsole::Read(warning, ¶ms);
288 content::ConsoleMessageLevel level = params.a;
289 std::string message = params.b;
290 EXPECT_EQ(content::CONSOLE_MESSAGE_LEVEL_WARNING, level);
291 EXPECT_THAT(message, testing::HasSubstr("delay is less than minimum of 1"));
292 }
293
TEST_F(ExtensionAlarmsTest,Get)294 TEST_F(ExtensionAlarmsTest, Get) {
295 test_clock_->SetNow(base::Time::FromDoubleT(4));
296
297 // Create 2 alarms, and make sure we can query them.
298 CreateAlarms(2);
299
300 // Get the default one.
301 {
302 JsAlarm alarm;
303 scoped_ptr<base::DictionaryValue> result(RunFunctionAndReturnDictionary(
304 new AlarmsGetFunction(), "[null]"));
305 ASSERT_TRUE(result.get());
306 EXPECT_TRUE(JsAlarm::Populate(*result, &alarm));
307 EXPECT_EQ("", alarm.name);
308 EXPECT_DOUBLE_EQ(4060, alarm.scheduled_time);
309 EXPECT_THAT(alarm.period_in_minutes,
310 testing::Pointee(testing::DoubleEq(0.001)));
311 }
312
313 // Get "7".
314 {
315 JsAlarm alarm;
316 scoped_ptr<base::DictionaryValue> result(RunFunctionAndReturnDictionary(
317 new AlarmsGetFunction(), "[\"7\"]"));
318 ASSERT_TRUE(result.get());
319 EXPECT_TRUE(JsAlarm::Populate(*result, &alarm));
320 EXPECT_EQ("7", alarm.name);
321 EXPECT_EQ(424000, alarm.scheduled_time);
322 EXPECT_THAT(alarm.period_in_minutes, testing::Pointee(7));
323 }
324
325 // Get a non-existent one.
326 {
327 scoped_ptr<base::DictionaryValue> result(RunFunctionAndReturnDictionary(
328 new AlarmsGetFunction(), "[\"nobody\"]"));
329 ASSERT_FALSE(result.get());
330 }
331 }
332
TEST_F(ExtensionAlarmsTest,GetAll)333 TEST_F(ExtensionAlarmsTest, GetAll) {
334 // Test getAll with 0 alarms.
335 {
336 scoped_ptr<base::ListValue> result(RunFunctionAndReturnList(
337 new AlarmsGetAllFunction(), "[]"));
338 std::vector<linked_ptr<JsAlarm> > alarms = ToAlarmList(result.get());
339 EXPECT_EQ(0u, alarms.size());
340 }
341
342 // Create 2 alarms, and make sure we can query them.
343 CreateAlarms(2);
344
345 {
346 scoped_ptr<base::ListValue> result(RunFunctionAndReturnList(
347 new AlarmsGetAllFunction(), "[null]"));
348 std::vector<linked_ptr<JsAlarm> > alarms = ToAlarmList(result.get());
349 EXPECT_EQ(2u, alarms.size());
350
351 // Test the "7" alarm.
352 JsAlarm* alarm = alarms[0].get();
353 if (alarm->name != "7")
354 alarm = alarms[1].get();
355 EXPECT_EQ("7", alarm->name);
356 EXPECT_THAT(alarm->period_in_minutes, testing::Pointee(7));
357 }
358 }
359
ExtensionAlarmsTestClearGetAllAlarms2Callback(const AlarmManager::AlarmList * alarms)360 void ExtensionAlarmsTestClearGetAllAlarms2Callback(
361 const AlarmManager::AlarmList* alarms) {
362 // Ensure the 0.001-minute alarm is still there, since it's repeating.
363 ASSERT_TRUE(alarms);
364 EXPECT_EQ(1u, alarms->size());
365 EXPECT_THAT((*alarms)[0].js_alarm->period_in_minutes,
366 testing::Pointee(0.001));
367 }
368
ExtensionAlarmsTestClearGetAllAlarms1Callback(ExtensionAlarmsTest * test,const AlarmManager::AlarmList * alarms)369 void ExtensionAlarmsTestClearGetAllAlarms1Callback(
370 ExtensionAlarmsTest* test, const AlarmManager::AlarmList* alarms) {
371 ASSERT_TRUE(alarms);
372 EXPECT_EQ(1u, alarms->size());
373 EXPECT_THAT((*alarms)[0].js_alarm->period_in_minutes,
374 testing::Pointee(0.001));
375
376 // Now wait for the alarms to fire, and ensure the cancelled alarms don't
377 // fire.
378 test->test_clock_->Advance(base::TimeDelta::FromMilliseconds(60));
379 RunScheduleNextPoll(test->alarm_manager_);
380 base::MessageLoop::current()->Run();
381
382 ASSERT_EQ(1u, test->alarm_delegate_->alarms_seen.size());
383 EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
384
385 // Ensure the 0.001-minute alarm is still there, since it's repeating.
386 test->alarm_manager_->GetAllAlarms(test->extension()->id(), base::Bind(
387 ExtensionAlarmsTestClearGetAllAlarms2Callback));
388 }
389
TEST_F(ExtensionAlarmsTest,Clear)390 TEST_F(ExtensionAlarmsTest, Clear) {
391 // Clear a non-existent one.
392 {
393 scoped_ptr<base::Value> result(
394 RunFunctionAndReturnValue(new AlarmsClearFunction(), "[\"nobody\"]"));
395 bool copy_bool_result = false;
396 ASSERT_TRUE(result->GetAsBoolean(©_bool_result));
397 EXPECT_FALSE(copy_bool_result);
398 }
399
400 // Create 3 alarms.
401 CreateAlarms(3);
402
403 // Clear all but the 0.001-minute alarm.
404 {
405 scoped_ptr<base::Value> result(
406 RunFunctionAndReturnValue(new AlarmsClearFunction(), "[\"7\"]"));
407 bool copy_bool_result = false;
408 ASSERT_TRUE(result->GetAsBoolean(©_bool_result));
409 EXPECT_TRUE(copy_bool_result);
410 }
411 {
412 scoped_ptr<base::Value> result(
413 RunFunctionAndReturnValue(new AlarmsClearFunction(), "[\"0\"]"));
414 bool copy_bool_result = false;
415 ASSERT_TRUE(result->GetAsBoolean(©_bool_result));
416 EXPECT_TRUE(copy_bool_result);
417 }
418
419 alarm_manager_->GetAllAlarms(extension()->id(), base::Bind(
420 ExtensionAlarmsTestClearGetAllAlarms1Callback, this));
421 }
422
ExtensionAlarmsTestClearAllGetAllAlarms2Callback(const AlarmManager::AlarmList * alarms)423 void ExtensionAlarmsTestClearAllGetAllAlarms2Callback(
424 const AlarmManager::AlarmList* alarms) {
425 ASSERT_FALSE(alarms);
426 }
427
ExtensionAlarmsTestClearAllGetAllAlarms1Callback(ExtensionAlarmsTest * test,const AlarmManager::AlarmList * alarms)428 void ExtensionAlarmsTestClearAllGetAllAlarms1Callback(
429 ExtensionAlarmsTest* test, const AlarmManager::AlarmList* alarms) {
430 ASSERT_TRUE(alarms);
431 EXPECT_EQ(3u, alarms->size());
432
433 // Clear them.
434 test->RunFunction(new AlarmsClearAllFunction(), "[]");
435 test->alarm_manager_->GetAllAlarms(
436 test->extension()->id(), base::Bind(
437 ExtensionAlarmsTestClearAllGetAllAlarms2Callback));
438 }
439
TEST_F(ExtensionAlarmsTest,ClearAll)440 TEST_F(ExtensionAlarmsTest, ClearAll) {
441 // ClearAll with no alarms set.
442 {
443 scoped_ptr<base::Value> result(RunFunctionAndReturnValue(
444 new AlarmsClearAllFunction(), "[]"));
445 bool copy_bool_result = false;
446 ASSERT_TRUE(result->GetAsBoolean(©_bool_result));
447 EXPECT_TRUE(copy_bool_result);
448 }
449
450 // Create 3 alarms.
451 CreateAlarms(3);
452 alarm_manager_->GetAllAlarms(extension()->id(), base::Bind(
453 ExtensionAlarmsTestClearAllGetAllAlarms1Callback, this));
454 }
455
456 class ExtensionAlarmsSchedulingTest : public ExtensionAlarmsTest {
GetAlarmCallback(Alarm * alarm)457 void GetAlarmCallback(Alarm* alarm) {
458 CHECK(alarm);
459 const base::Time scheduled_time =
460 base::Time::FromJsTime(alarm->js_alarm->scheduled_time);
461 EXPECT_EQ(scheduled_time, alarm_manager_->next_poll_time_);
462 }
463
RemoveAlarmCallback(bool success)464 static void RemoveAlarmCallback (bool success) { EXPECT_TRUE(success); }
RemoveAllAlarmsCallback()465 static void RemoveAllAlarmsCallback () {}
466 public:
467 // Get the time that the alarm named is scheduled to run.
VerifyScheduledTime(const std::string & alarm_name)468 void VerifyScheduledTime(const std::string& alarm_name) {
469 alarm_manager_->GetAlarm(extension()->id(), alarm_name, base::Bind(
470 &ExtensionAlarmsSchedulingTest::GetAlarmCallback,
471 base::Unretained(this)));
472 }
473
RemoveAlarm(const std::string & name)474 void RemoveAlarm(const std::string& name) {
475 alarm_manager_->RemoveAlarm(
476 extension()->id(),
477 name,
478 base::Bind(&ExtensionAlarmsSchedulingTest::RemoveAlarmCallback));
479 }
480
RemoveAllAlarms()481 void RemoveAllAlarms () {
482 alarm_manager_->RemoveAllAlarms(extension()->id(), base::Bind(
483 &ExtensionAlarmsSchedulingTest::RemoveAllAlarmsCallback));
484 }
485 };
486
TEST_F(ExtensionAlarmsSchedulingTest,PollScheduling)487 TEST_F(ExtensionAlarmsSchedulingTest, PollScheduling) {
488 {
489 CreateAlarm("[\"a\", {\"periodInMinutes\": 6}]");
490 CreateAlarm("[\"bb\", {\"periodInMinutes\": 8}]");
491 VerifyScheduledTime("a");
492 RemoveAllAlarms();
493 }
494 {
495 CreateAlarm("[\"a\", {\"delayInMinutes\": 10}]");
496 CreateAlarm("[\"bb\", {\"delayInMinutes\": 21}]");
497 VerifyScheduledTime("a");
498 RemoveAllAlarms();
499 }
500 {
501 test_clock_->SetNow(base::Time::FromDoubleT(10));
502 CreateAlarm("[\"a\", {\"periodInMinutes\": 10}]");
503 Alarm alarm;
504 alarm.js_alarm->name = "bb";
505 alarm.js_alarm->scheduled_time = 30 * 60000;
506 alarm.js_alarm->period_in_minutes.reset(new double(30));
507 alarm_manager_->AddAlarmImpl(extension()->id(), alarm);
508 VerifyScheduledTime("a");
509 RemoveAllAlarms();
510 }
511 {
512 test_clock_->SetNow(base::Time::FromDoubleT(3 * 60 + 1));
513 Alarm alarm;
514 alarm.js_alarm->name = "bb";
515 alarm.js_alarm->scheduled_time = 3 * 60000;
516 alarm.js_alarm->period_in_minutes.reset(new double(3));
517 alarm_manager_->AddAlarmImpl(extension()->id(), alarm);
518 base::MessageLoop::current()->Run();
519 EXPECT_EQ(base::Time::FromJsTime(3 * 60000) +
520 base::TimeDelta::FromMinutes(3),
521 alarm_manager_->next_poll_time_);
522 RemoveAllAlarms();
523 }
524 {
525 test_clock_->SetNow(base::Time::FromDoubleT(4 * 60 + 1));
526 CreateAlarm("[\"a\", {\"periodInMinutes\": 2}]");
527 RemoveAlarm("a");
528 Alarm alarm2;
529 alarm2.js_alarm->name = "bb";
530 alarm2.js_alarm->scheduled_time = 4 * 60000;
531 alarm2.js_alarm->period_in_minutes.reset(new double(4));
532 alarm_manager_->AddAlarmImpl(extension()->id(), alarm2);
533 Alarm alarm3;
534 alarm3.js_alarm->name = "ccc";
535 alarm3.js_alarm->scheduled_time = 25 * 60000;
536 alarm3.js_alarm->period_in_minutes.reset(new double(25));
537 alarm_manager_->AddAlarmImpl(extension()->id(), alarm3);
538 base::MessageLoop::current()->Run();
539 EXPECT_EQ(base::Time::FromJsTime(4 * 60000) +
540 base::TimeDelta::FromMinutes(4),
541 alarm_manager_->next_poll_time_);
542 RemoveAllAlarms();
543 }
544 }
545
TEST_F(ExtensionAlarmsSchedulingTest,ReleasedExtensionPollsInfrequently)546 TEST_F(ExtensionAlarmsSchedulingTest, ReleasedExtensionPollsInfrequently) {
547 set_extension(utils::CreateEmptyExtensionWithLocation(
548 extensions::Manifest::INTERNAL));
549 test_clock_->SetNow(base::Time::FromJsTime(300000));
550 CreateAlarm("[\"a\", {\"when\": 300010}]");
551 CreateAlarm("[\"b\", {\"when\": 340000}]");
552
553 // On startup (when there's no "last poll"), we let alarms fire as
554 // soon as they're scheduled.
555 EXPECT_DOUBLE_EQ(300010, alarm_manager_->next_poll_time_.ToJsTime());
556
557 alarm_manager_->last_poll_time_ = base::Time::FromJsTime(290000);
558 // In released extensions, we set the granularity to at least 1
559 // minute, which makes AddAlarm schedule the next poll after the
560 // extension requested.
561 alarm_manager_->ScheduleNextPoll();
562 EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
563 base::TimeDelta::FromMinutes(1)).ToJsTime(),
564 alarm_manager_->next_poll_time_.ToJsTime());
565 }
566
TEST_F(ExtensionAlarmsSchedulingTest,TimerRunning)567 TEST_F(ExtensionAlarmsSchedulingTest, TimerRunning) {
568 EXPECT_FALSE(alarm_manager_->timer_.IsRunning());
569 CreateAlarm("[\"a\", {\"delayInMinutes\": 0.001}]");
570 EXPECT_TRUE(alarm_manager_->timer_.IsRunning());
571 test_clock_->Advance(base::TimeDelta::FromMilliseconds(60));
572 base::MessageLoop::current()->Run();
573 EXPECT_FALSE(alarm_manager_->timer_.IsRunning());
574 CreateAlarm("[\"bb\", {\"delayInMinutes\": 10}]");
575 EXPECT_TRUE(alarm_manager_->timer_.IsRunning());
576 RemoveAllAlarms();
577 EXPECT_FALSE(alarm_manager_->timer_.IsRunning());
578 }
579
TEST_F(ExtensionAlarmsSchedulingTest,MinimumGranularity)580 TEST_F(ExtensionAlarmsSchedulingTest, MinimumGranularity) {
581 set_extension(utils::CreateEmptyExtensionWithLocation(
582 extensions::Manifest::INTERNAL));
583 test_clock_->SetNow(base::Time::FromJsTime(0));
584 CreateAlarm("[\"a\", {\"periodInMinutes\": 2}]");
585 test_clock_->Advance(base::TimeDelta::FromSeconds(1));
586 CreateAlarm("[\"b\", {\"periodInMinutes\": 2}]");
587 test_clock_->Advance(base::TimeDelta::FromMinutes(2));
588
589 alarm_manager_->last_poll_time_ = base::Time::FromJsTime(2 * 60000);
590 // In released extensions, we set the granularity to at least 1
591 // minute, which makes scheduler set it to 1 minute, rather than
592 // 1 second later (when b is supposed to go off).
593 alarm_manager_->ScheduleNextPoll();
594 EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
595 base::TimeDelta::FromMinutes(1)).ToJsTime(),
596 alarm_manager_->next_poll_time_.ToJsTime());
597 }
598
TEST_F(ExtensionAlarmsSchedulingTest,DifferentMinimumGranularities)599 TEST_F(ExtensionAlarmsSchedulingTest, DifferentMinimumGranularities) {
600 test_clock_->SetNow(base::Time::FromJsTime(0));
601 // Create an alarm to go off in 12 seconds. This uses the default, unpacked
602 // extension - so there is no minimum granularity.
603 CreateAlarm("[\"a\", {\"periodInMinutes\": 0.2}]"); // 12 seconds.
604
605 // Create a new extension, which is packed, and has a granularity of 1 minute.
606 // CreateAlarm() uses extension_, so keep a ref of the old one around, and
607 // repopulate extension_.
608 scoped_refptr<Extension> extension2(extension_ref());
609 set_extension(
610 utils::CreateEmptyExtensionWithLocation(extensions::Manifest::INTERNAL));
611
612 CreateAlarm("[\"b\", {\"periodInMinutes\": 2}]");
613
614 alarm_manager_->last_poll_time_ = base::Time::FromJsTime(0);
615 alarm_manager_->ScheduleNextPoll();
616
617 // The next poll time should be 12 seconds from now - the time at which the
618 // first alarm should go off.
619 EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
620 base::TimeDelta::FromSeconds(12)).ToJsTime(),
621 alarm_manager_->next_poll_time_.ToJsTime());
622 }
623
624 // Test that scheduled alarms go off at set intervals, even if their actual
625 // trigger is off.
TEST_F(ExtensionAlarmsSchedulingTest,RepeatingAlarmsScheduledPredictably)626 TEST_F(ExtensionAlarmsSchedulingTest, RepeatingAlarmsScheduledPredictably) {
627 test_clock_->SetNow(base::Time::FromJsTime(0));
628 CreateAlarm("[\"a\", {\"periodInMinutes\": 2}]");
629
630 alarm_manager_->last_poll_time_ = base::Time::FromJsTime(0);
631 alarm_manager_->ScheduleNextPoll();
632
633 // We expect the first poll to happen two minutes from the start.
634 EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
635 base::TimeDelta::FromSeconds(120)).ToJsTime(),
636 alarm_manager_->next_poll_time_.ToJsTime());
637
638 // Poll more than two minutes later.
639 test_clock_->Advance(base::TimeDelta::FromSeconds(125));
640 alarm_manager_->PollAlarms();
641
642 // The alarm should have triggered once.
643 EXPECT_EQ(1u, alarm_delegate_->alarms_seen.size());
644
645 // The next poll should still be scheduled for four minutes from the start,
646 // even though this is less than two minutes since the last alarm.
647 // Last poll was at 125 seconds; next poll should be at 240 seconds.
648 EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
649 base::TimeDelta::FromSeconds(115)).ToJsTime(),
650 alarm_manager_->next_poll_time_.ToJsTime());
651
652 // Completely miss a scheduled trigger.
653 test_clock_->Advance(base::TimeDelta::FromSeconds(255)); // Total Time: 380s
654 alarm_manager_->PollAlarms();
655
656 // The alarm should have triggered again at this last poll.
657 EXPECT_EQ(2u, alarm_delegate_->alarms_seen.size());
658
659 // The next poll should be the first poll that hasn't happened and is in-line
660 // with the original scheduling.
661 // Last poll was at 380 seconds; next poll should be at 480 seconds.
662 EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
663 base::TimeDelta::FromSeconds(100)).ToJsTime(),
664 alarm_manager_->next_poll_time_.ToJsTime());
665 }
666
667 } // namespace extensions
668