• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params);
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(&copy_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(&copy_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(&copy_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(&copy_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