blob: 72db28499ada9008a2f1b6974ce1812743f327e4 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevf6468892014-01-29 01:04:14 -08002/**
Junxiao Shid50f2b42016-08-10 02:59:59 +00003 * Copyright (c) 2013-2016 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevf6468892014-01-29 01:04:14 -080020 */
21
22#include "util/scheduler.hpp"
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -080023#include "util/scheduler-scoped-event-id.hpp"
Alexander Afanasyevf6468892014-01-29 01:04:14 -080024
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070025#include "boost-test.hpp"
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080026#include "../unit-test-time-fixture.hpp"
Junxiao Shid50f2b42016-08-10 02:59:59 +000027#include <boost/lexical_cast.hpp>
Alexander Afanasyevf6468892014-01-29 01:04:14 -080028
29namespace ndn {
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -080030namespace util {
31namespace scheduler {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080032namespace tests {
Alexander Afanasyevf6468892014-01-29 01:04:14 -080033
Spyridon Mastorakis429634f2015-02-19 17:35:33 -080034using namespace ndn::tests;
35
Junxiao Shid50f2b42016-08-10 02:59:59 +000036class SchedulerFixture : public UnitTestTimeFixture
37{
38public:
39 SchedulerFixture()
40 : scheduler(io)
41 {
42 }
43
44public:
45 Scheduler scheduler;
46};
47
48BOOST_AUTO_TEST_SUITE(Util)
49BOOST_FIXTURE_TEST_SUITE(TestScheduler, SchedulerFixture)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080050
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080051BOOST_AUTO_TEST_CASE(Events)
Alexander Afanasyevf6468892014-01-29 01:04:14 -080052{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080053 size_t count1 = 0;
54 size_t count2 = 0;
Alexander Afanasyevf6468892014-01-29 01:04:14 -080055
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080056 scheduler.scheduleEvent(time::milliseconds(500), [&] {
57 ++count1;
58 BOOST_CHECK_EQUAL(count2, 1);
59 });
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070060
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080061 EventId i = scheduler.scheduleEvent(time::seconds(1), [&] {
62 BOOST_ERROR("This event should not have been fired");
63 });
Alexander Afanasyevf6468892014-01-29 01:04:14 -080064 scheduler.cancelEvent(i);
65
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080066 scheduler.scheduleEvent(time::milliseconds(250), [&] {
67 BOOST_CHECK_EQUAL(count1, 0);
68 ++count2;
69 });
Alexander Afanasyevf6468892014-01-29 01:04:14 -080070
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080071 i = scheduler.scheduleEvent(time::milliseconds(50), [&] {
72 BOOST_ERROR("This event should not have been fired");
73 });
Alexander Afanasyevf6468892014-01-29 01:04:14 -080074 scheduler.cancelEvent(i);
75
Junxiao Shid50f2b42016-08-10 02:59:59 +000076 advanceClocks(time::milliseconds(25), time::milliseconds(1000));
Alexander Afanasyevf6468892014-01-29 01:04:14 -080077 BOOST_CHECK_EQUAL(count1, 1);
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080078 BOOST_CHECK_EQUAL(count2, 1);
Alexander Afanasyevf6468892014-01-29 01:04:14 -080079}
80
Junxiao Shi86dfa532016-08-10 03:00:11 +000081BOOST_AUTO_TEST_CASE(CallbackException)
82{
83 class MyException : public std::exception
84 {
85 };
86 scheduler.scheduleEvent(time::milliseconds(10), [] { BOOST_THROW_EXCEPTION(MyException()); });
87
88 bool isCallbackInvoked = false;
89 scheduler.scheduleEvent(time::milliseconds(20), [&isCallbackInvoked] { isCallbackInvoked = true; });
90
91 BOOST_CHECK_THROW(this->advanceClocks(time::milliseconds(6), 2), MyException);
92 this->advanceClocks(time::milliseconds(6), 2);
93 BOOST_CHECK(isCallbackInvoked);
94}
95
Yingdi Yuf2a82092014-02-03 16:49:15 -080096BOOST_AUTO_TEST_CASE(CancelEmptyEvent)
97{
Yingdi Yuf2a82092014-02-03 16:49:15 -080098 EventId i;
99 scheduler.cancelEvent(i);
100}
101
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800102BOOST_AUTO_TEST_CASE(SelfCancel)
Yingdi Yuf2a82092014-02-03 16:49:15 -0800103{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800104 EventId selfEventId;
105 selfEventId = scheduler.scheduleEvent(time::milliseconds(100), [&] {
106 scheduler.cancelEvent(selfEventId);
107 });
Yingdi Yuf2a82092014-02-03 16:49:15 -0800108
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800109 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(100), 10));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800110}
111
Junxiao Shid50f2b42016-08-10 02:59:59 +0000112class SelfRescheduleFixture : public SchedulerFixture
Yingdi Yuf2a82092014-02-03 16:49:15 -0800113{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800114public:
Yingdi Yuf2a82092014-02-03 16:49:15 -0800115 SelfRescheduleFixture()
Junxiao Shid50f2b42016-08-10 02:59:59 +0000116 : count(0)
Yingdi Yuf2a82092014-02-03 16:49:15 -0800117 {
118 }
119
120 void
121 reschedule()
122 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800123 EventId eventId = scheduler.scheduleEvent(time::milliseconds(100),
124 bind(&SelfRescheduleFixture::reschedule, this));
125 scheduler.cancelEvent(selfEventId);
126 selfEventId = eventId;
Yingdi Yuf2a82092014-02-03 16:49:15 -0800127
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800128 if (count < 5)
129 count++;
Yingdi Yuf2a82092014-02-03 16:49:15 -0800130 else
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800131 scheduler.cancelEvent(selfEventId);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800132 }
133
134 void
135 reschedule2()
136 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800137 scheduler.cancelEvent(selfEventId);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700138
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800139 if (count < 5) {
140 selfEventId = scheduler.scheduleEvent(time::milliseconds(100),
141 bind(&SelfRescheduleFixture::reschedule2, this));
142 count++;
143 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800144 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700145
Yingdi Yuf2a82092014-02-03 16:49:15 -0800146 void
147 reschedule3()
148 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800149 scheduler.cancelEvent(selfEventId);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700150
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800151 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
152 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
153 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
154 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
155 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
156 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
Yingdi Yuf2a82092014-02-03 16:49:15 -0800157 }
158
Junxiao Shid50f2b42016-08-10 02:59:59 +0000159public:
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800160 EventId selfEventId;
161 size_t count;
Yingdi Yuf2a82092014-02-03 16:49:15 -0800162};
163
164BOOST_FIXTURE_TEST_CASE(Reschedule, SelfRescheduleFixture)
165{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800166 selfEventId = scheduler.scheduleEvent(time::seconds(0),
167 bind(&SelfRescheduleFixture::reschedule, this));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800168
Junxiao Shid50f2b42016-08-10 02:59:59 +0000169 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000)));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800170
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800171 BOOST_CHECK_EQUAL(count, 5);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800172}
173
174BOOST_FIXTURE_TEST_CASE(Reschedule2, SelfRescheduleFixture)
175{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800176 selfEventId = scheduler.scheduleEvent(time::seconds(0),
177 bind(&SelfRescheduleFixture::reschedule2, this));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800178
Junxiao Shid50f2b42016-08-10 02:59:59 +0000179 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000)));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800180
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800181 BOOST_CHECK_EQUAL(count, 5);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800182}
183
184BOOST_FIXTURE_TEST_CASE(Reschedule3, SelfRescheduleFixture)
185{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800186 selfEventId = scheduler.scheduleEvent(time::seconds(0),
187 bind(&SelfRescheduleFixture::reschedule3, this));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800188
Junxiao Shid50f2b42016-08-10 02:59:59 +0000189 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000)));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800190
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800191 BOOST_CHECK_EQUAL(count, 6);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800192}
193
Junxiao Shid50f2b42016-08-10 02:59:59 +0000194class CancelAllFixture : public SchedulerFixture
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700195{
Junxiao Shid50f2b42016-08-10 02:59:59 +0000196public:
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700197 CancelAllFixture()
Junxiao Shid50f2b42016-08-10 02:59:59 +0000198 : count(0)
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700199 {
200 }
201
202 void
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700203 event()
204 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800205 ++count;
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700206
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800207 scheduler.scheduleEvent(time::seconds(1), [&] { event(); });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700208 }
209
Junxiao Shid50f2b42016-08-10 02:59:59 +0000210public:
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800211 uint32_t count;
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700212};
213
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700214BOOST_FIXTURE_TEST_CASE(CancelAll, CancelAllFixture)
215{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800216 scheduler.scheduleEvent(time::milliseconds(500), [&] { scheduler.cancelAllEvents(); });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700217
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800218 scheduler.scheduleEvent(time::seconds(1), [&] { event(); });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700219
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800220 scheduler.scheduleEvent(time::seconds(3), [] {
221 BOOST_ERROR("This event should have been cancelled" );
222 });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700223
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800224 advanceClocks(time::milliseconds(100), 100);
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700225
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800226 BOOST_CHECK_EQUAL(count, 0);
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700227}
228
Junxiao Shid50f2b42016-08-10 02:59:59 +0000229BOOST_AUTO_TEST_CASE(CancelAllWithScopedEventId) // Bug 3691
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800230{
Junxiao Shid50f2b42016-08-10 02:59:59 +0000231 Scheduler sched(io);
232 ScopedEventId eid(sched);
233 eid = sched.scheduleEvent(time::milliseconds(10), []{});
234 sched.cancelAllEvents();
235 eid.cancel(); // should not crash
236}
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700237
Junxiao Shid50f2b42016-08-10 02:59:59 +0000238BOOST_AUTO_TEST_SUITE(EventId)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800239
Junxiao Shid50f2b42016-08-10 02:59:59 +0000240using scheduler::EventId;
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800241
Junxiao Shid50f2b42016-08-10 02:59:59 +0000242BOOST_AUTO_TEST_CASE(ConstructEmpty)
243{
244 EventId eid;
245 eid = nullptr;
246}
247
248BOOST_AUTO_TEST_CASE(Compare)
249{
250 EventId eid, eid2;
251 BOOST_CHECK_EQUAL(eid == eid2, true);
252 BOOST_CHECK_EQUAL(eid != eid2, false);
253 BOOST_CHECK_EQUAL(eid == nullptr, true);
254 BOOST_CHECK_EQUAL(eid != nullptr, false);
255
256 eid = scheduler.scheduleEvent(time::milliseconds(10), []{});
257 BOOST_CHECK_EQUAL(eid == eid2, false);
258 BOOST_CHECK_EQUAL(eid != eid2, true);
259 BOOST_CHECK_EQUAL(eid == nullptr, false);
260 BOOST_CHECK_EQUAL(eid != nullptr, true);
261
262 eid2 = eid;
263 BOOST_CHECK_EQUAL(eid == eid2, true);
264 BOOST_CHECK_EQUAL(eid != eid2, false);
265
266 eid2 = scheduler.scheduleEvent(time::milliseconds(10), []{});
267 BOOST_CHECK_EQUAL(eid == eid2, false);
268 BOOST_CHECK_EQUAL(eid != eid2, true);
269}
270
271BOOST_AUTO_TEST_CASE(Valid)
272{
273 EventId eid;
274 BOOST_CHECK_EQUAL(static_cast<bool>(eid), false);
275 BOOST_CHECK_EQUAL(!eid, true);
276
277 eid = scheduler.scheduleEvent(time::milliseconds(10), []{});
278 BOOST_CHECK_EQUAL(static_cast<bool>(eid), true);
279 BOOST_CHECK_EQUAL(!eid, false);
280
281 EventId eid2 = eid;
282 scheduler.cancelEvent(eid2);
283 BOOST_CHECK_EQUAL(static_cast<bool>(eid), false);
284 BOOST_CHECK_EQUAL(!eid, true);
285 BOOST_CHECK_EQUAL(static_cast<bool>(eid2), false);
286 BOOST_CHECK_EQUAL(!eid2, true);
287}
288
289BOOST_AUTO_TEST_CASE(DuringCallback)
290{
291 EventId eid;
292 EventId eid2 = scheduler.scheduleEvent(time::milliseconds(20), []{});
293
294 bool isCallbackInvoked = false;
295 eid = scheduler.scheduleEvent(time::milliseconds(10), [this, &eid, &eid2, &isCallbackInvoked] {
296 isCallbackInvoked = true;
297
298 // eid is "expired" during callback execution
299 BOOST_CHECK_EQUAL(static_cast<bool>(eid), false);
300 BOOST_CHECK_EQUAL(!eid, true);
301 BOOST_CHECK_EQUAL(eid == eid2, false);
302 BOOST_CHECK_EQUAL(eid != eid2, true);
303 BOOST_CHECK_EQUAL(eid == nullptr, true);
304 BOOST_CHECK_EQUAL(eid != nullptr, false);
305
306 scheduler.cancelEvent(eid2);
307 BOOST_CHECK_EQUAL(eid == eid2, true);
308 BOOST_CHECK_EQUAL(eid != eid2, false);
309 });
310 this->advanceClocks(time::milliseconds(6), 2);
311 BOOST_CHECK(isCallbackInvoked);
312}
313
314BOOST_AUTO_TEST_CASE(Reset)
315{
316 bool isCallbackInvoked = false;
317 EventId eid = scheduler.scheduleEvent(time::milliseconds(10),
318 [&isCallbackInvoked]{ isCallbackInvoked = true; });
319 eid.reset();
320 BOOST_CHECK_EQUAL(!eid, true);
321 BOOST_CHECK_EQUAL(eid == nullptr, true);
322
323 this->advanceClocks(time::milliseconds(6), 2);
324 BOOST_CHECK(isCallbackInvoked);
325}
326
327BOOST_AUTO_TEST_CASE(ToString)
328{
329 std::string nullString = boost::lexical_cast<std::string>(shared_ptr<int>());
330
331 EventId eid;
332 BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(eid), nullString);
333
334 eid = scheduler.scheduleEvent(time::milliseconds(10), []{});
335 BOOST_TEST_MESSAGE("eid=" << eid);
336 BOOST_CHECK_NE(boost::lexical_cast<std::string>(eid), nullString);
337}
338
339BOOST_AUTO_TEST_SUITE_END() // EventId
340
341BOOST_AUTO_TEST_SUITE(ScopedEventId)
342
343using scheduler::ScopedEventId;
344
345BOOST_AUTO_TEST_CASE(Destruct)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800346{
347 int hit = 0;
348 {
349 ScopedEventId se(scheduler);
350 se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; });
351 } // se goes out of scope
352 this->advanceClocks(time::milliseconds(1), 15);
353 BOOST_CHECK_EQUAL(hit, 0);
354}
355
Junxiao Shid50f2b42016-08-10 02:59:59 +0000356BOOST_AUTO_TEST_CASE(Assign)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800357{
358 int hit1 = 0, hit2 = 0;
359 ScopedEventId se1(scheduler);
360 se1 = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit1; });
361 se1 = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit2; });
362 this->advanceClocks(time::milliseconds(1), 15);
363 BOOST_CHECK_EQUAL(hit1, 0);
364 BOOST_CHECK_EQUAL(hit2, 1);
365}
366
Junxiao Shid50f2b42016-08-10 02:59:59 +0000367BOOST_AUTO_TEST_CASE(Release)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800368{
369 int hit = 0;
370 {
371 ScopedEventId se(scheduler);
372 se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; });
373 se.release();
374 } // se goes out of scope
375 this->advanceClocks(time::milliseconds(1), 15);
376 BOOST_CHECK_EQUAL(hit, 1);
377}
378
Junxiao Shid50f2b42016-08-10 02:59:59 +0000379BOOST_AUTO_TEST_CASE(Move)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800380{
381 int hit = 0;
382 unique_ptr<scheduler::ScopedEventId> se2;
383 {
384 ScopedEventId se(scheduler);
385 se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; });
386 se2.reset(new ScopedEventId(std::move(se)));
387 } // se goes out of scope
388 this->advanceClocks(time::milliseconds(1), 15);
389 BOOST_CHECK_EQUAL(hit, 1);
390}
391
392BOOST_AUTO_TEST_SUITE_END() // ScopedEventId
393
Junxiao Shid50f2b42016-08-10 02:59:59 +0000394BOOST_AUTO_TEST_SUITE_END() // TestScheduler
395BOOST_AUTO_TEST_SUITE_END() // Util
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800396
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800397} // namespace tests
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800398} // namespace scheduler
399} // namespace util
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800400} // namespace ndn