blob: dfc2826e33d5a8c41b9af8f7e528c0319e6c816c [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
Yingdi Yuf2a82092014-02-03 16:49:15 -080081BOOST_AUTO_TEST_CASE(CancelEmptyEvent)
82{
Yingdi Yuf2a82092014-02-03 16:49:15 -080083 EventId i;
84 scheduler.cancelEvent(i);
85}
86
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080087BOOST_AUTO_TEST_CASE(SelfCancel)
Yingdi Yuf2a82092014-02-03 16:49:15 -080088{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080089 EventId selfEventId;
90 selfEventId = scheduler.scheduleEvent(time::milliseconds(100), [&] {
91 scheduler.cancelEvent(selfEventId);
92 });
Yingdi Yuf2a82092014-02-03 16:49:15 -080093
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080094 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(100), 10));
Yingdi Yuf2a82092014-02-03 16:49:15 -080095}
96
Junxiao Shid50f2b42016-08-10 02:59:59 +000097class SelfRescheduleFixture : public SchedulerFixture
Yingdi Yuf2a82092014-02-03 16:49:15 -080098{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -080099public:
Yingdi Yuf2a82092014-02-03 16:49:15 -0800100 SelfRescheduleFixture()
Junxiao Shid50f2b42016-08-10 02:59:59 +0000101 : count(0)
Yingdi Yuf2a82092014-02-03 16:49:15 -0800102 {
103 }
104
105 void
106 reschedule()
107 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800108 EventId eventId = scheduler.scheduleEvent(time::milliseconds(100),
109 bind(&SelfRescheduleFixture::reschedule, this));
110 scheduler.cancelEvent(selfEventId);
111 selfEventId = eventId;
Yingdi Yuf2a82092014-02-03 16:49:15 -0800112
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800113 if (count < 5)
114 count++;
Yingdi Yuf2a82092014-02-03 16:49:15 -0800115 else
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800116 scheduler.cancelEvent(selfEventId);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800117 }
118
119 void
120 reschedule2()
121 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800122 scheduler.cancelEvent(selfEventId);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700123
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800124 if (count < 5) {
125 selfEventId = scheduler.scheduleEvent(time::milliseconds(100),
126 bind(&SelfRescheduleFixture::reschedule2, this));
127 count++;
128 }
Yingdi Yuf2a82092014-02-03 16:49:15 -0800129 }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700130
Yingdi Yuf2a82092014-02-03 16:49:15 -0800131 void
132 reschedule3()
133 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800134 scheduler.cancelEvent(selfEventId);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700135
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800136 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
137 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
138 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
139 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
140 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
141 scheduler.scheduleEvent(time::milliseconds(100), [&] { ++count; });
Yingdi Yuf2a82092014-02-03 16:49:15 -0800142 }
143
Junxiao Shid50f2b42016-08-10 02:59:59 +0000144public:
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800145 EventId selfEventId;
146 size_t count;
Yingdi Yuf2a82092014-02-03 16:49:15 -0800147};
148
149BOOST_FIXTURE_TEST_CASE(Reschedule, SelfRescheduleFixture)
150{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800151 selfEventId = scheduler.scheduleEvent(time::seconds(0),
152 bind(&SelfRescheduleFixture::reschedule, this));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800153
Junxiao Shid50f2b42016-08-10 02:59:59 +0000154 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000)));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800155
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800156 BOOST_CHECK_EQUAL(count, 5);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800157}
158
159BOOST_FIXTURE_TEST_CASE(Reschedule2, SelfRescheduleFixture)
160{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800161 selfEventId = scheduler.scheduleEvent(time::seconds(0),
162 bind(&SelfRescheduleFixture::reschedule2, this));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800163
Junxiao Shid50f2b42016-08-10 02:59:59 +0000164 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000)));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800165
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800166 BOOST_CHECK_EQUAL(count, 5);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800167}
168
169BOOST_FIXTURE_TEST_CASE(Reschedule3, SelfRescheduleFixture)
170{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800171 selfEventId = scheduler.scheduleEvent(time::seconds(0),
172 bind(&SelfRescheduleFixture::reschedule3, this));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800173
Junxiao Shid50f2b42016-08-10 02:59:59 +0000174 BOOST_REQUIRE_NO_THROW(advanceClocks(time::milliseconds(50), time::milliseconds(1000)));
Yingdi Yuf2a82092014-02-03 16:49:15 -0800175
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800176 BOOST_CHECK_EQUAL(count, 6);
Yingdi Yuf2a82092014-02-03 16:49:15 -0800177}
178
Junxiao Shid50f2b42016-08-10 02:59:59 +0000179class CancelAllFixture : public SchedulerFixture
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700180{
Junxiao Shid50f2b42016-08-10 02:59:59 +0000181public:
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700182 CancelAllFixture()
Junxiao Shid50f2b42016-08-10 02:59:59 +0000183 : count(0)
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700184 {
185 }
186
187 void
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700188 event()
189 {
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800190 ++count;
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700191
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800192 scheduler.scheduleEvent(time::seconds(1), [&] { event(); });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700193 }
194
Junxiao Shid50f2b42016-08-10 02:59:59 +0000195public:
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800196 uint32_t count;
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700197};
198
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700199BOOST_FIXTURE_TEST_CASE(CancelAll, CancelAllFixture)
200{
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800201 scheduler.scheduleEvent(time::milliseconds(500), [&] { scheduler.cancelAllEvents(); });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700202
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800203 scheduler.scheduleEvent(time::seconds(1), [&] { event(); });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700204
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800205 scheduler.scheduleEvent(time::seconds(3), [] {
206 BOOST_ERROR("This event should have been cancelled" );
207 });
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700208
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800209 advanceClocks(time::milliseconds(100), 100);
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700210
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800211 BOOST_CHECK_EQUAL(count, 0);
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700212}
213
Junxiao Shid50f2b42016-08-10 02:59:59 +0000214BOOST_AUTO_TEST_CASE(CancelAllWithScopedEventId) // Bug 3691
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800215{
Junxiao Shid50f2b42016-08-10 02:59:59 +0000216 Scheduler sched(io);
217 ScopedEventId eid(sched);
218 eid = sched.scheduleEvent(time::milliseconds(10), []{});
219 sched.cancelAllEvents();
220 eid.cancel(); // should not crash
221}
Alexander Afanasyev7ae4bf52014-07-11 17:12:41 -0700222
Junxiao Shid50f2b42016-08-10 02:59:59 +0000223BOOST_AUTO_TEST_SUITE(EventId)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800224
Junxiao Shid50f2b42016-08-10 02:59:59 +0000225using scheduler::EventId;
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800226
Junxiao Shid50f2b42016-08-10 02:59:59 +0000227BOOST_AUTO_TEST_CASE(ConstructEmpty)
228{
229 EventId eid;
230 eid = nullptr;
231}
232
233BOOST_AUTO_TEST_CASE(Compare)
234{
235 EventId eid, eid2;
236 BOOST_CHECK_EQUAL(eid == eid2, true);
237 BOOST_CHECK_EQUAL(eid != eid2, false);
238 BOOST_CHECK_EQUAL(eid == nullptr, true);
239 BOOST_CHECK_EQUAL(eid != nullptr, false);
240
241 eid = scheduler.scheduleEvent(time::milliseconds(10), []{});
242 BOOST_CHECK_EQUAL(eid == eid2, false);
243 BOOST_CHECK_EQUAL(eid != eid2, true);
244 BOOST_CHECK_EQUAL(eid == nullptr, false);
245 BOOST_CHECK_EQUAL(eid != nullptr, true);
246
247 eid2 = eid;
248 BOOST_CHECK_EQUAL(eid == eid2, true);
249 BOOST_CHECK_EQUAL(eid != eid2, false);
250
251 eid2 = scheduler.scheduleEvent(time::milliseconds(10), []{});
252 BOOST_CHECK_EQUAL(eid == eid2, false);
253 BOOST_CHECK_EQUAL(eid != eid2, true);
254}
255
256BOOST_AUTO_TEST_CASE(Valid)
257{
258 EventId eid;
259 BOOST_CHECK_EQUAL(static_cast<bool>(eid), false);
260 BOOST_CHECK_EQUAL(!eid, true);
261
262 eid = scheduler.scheduleEvent(time::milliseconds(10), []{});
263 BOOST_CHECK_EQUAL(static_cast<bool>(eid), true);
264 BOOST_CHECK_EQUAL(!eid, false);
265
266 EventId eid2 = eid;
267 scheduler.cancelEvent(eid2);
268 BOOST_CHECK_EQUAL(static_cast<bool>(eid), false);
269 BOOST_CHECK_EQUAL(!eid, true);
270 BOOST_CHECK_EQUAL(static_cast<bool>(eid2), false);
271 BOOST_CHECK_EQUAL(!eid2, true);
272}
273
274BOOST_AUTO_TEST_CASE(DuringCallback)
275{
276 EventId eid;
277 EventId eid2 = scheduler.scheduleEvent(time::milliseconds(20), []{});
278
279 bool isCallbackInvoked = false;
280 eid = scheduler.scheduleEvent(time::milliseconds(10), [this, &eid, &eid2, &isCallbackInvoked] {
281 isCallbackInvoked = true;
282
283 // eid is "expired" during callback execution
284 BOOST_CHECK_EQUAL(static_cast<bool>(eid), false);
285 BOOST_CHECK_EQUAL(!eid, true);
286 BOOST_CHECK_EQUAL(eid == eid2, false);
287 BOOST_CHECK_EQUAL(eid != eid2, true);
288 BOOST_CHECK_EQUAL(eid == nullptr, true);
289 BOOST_CHECK_EQUAL(eid != nullptr, false);
290
291 scheduler.cancelEvent(eid2);
292 BOOST_CHECK_EQUAL(eid == eid2, true);
293 BOOST_CHECK_EQUAL(eid != eid2, false);
294 });
295 this->advanceClocks(time::milliseconds(6), 2);
296 BOOST_CHECK(isCallbackInvoked);
297}
298
299BOOST_AUTO_TEST_CASE(Reset)
300{
301 bool isCallbackInvoked = false;
302 EventId eid = scheduler.scheduleEvent(time::milliseconds(10),
303 [&isCallbackInvoked]{ isCallbackInvoked = true; });
304 eid.reset();
305 BOOST_CHECK_EQUAL(!eid, true);
306 BOOST_CHECK_EQUAL(eid == nullptr, true);
307
308 this->advanceClocks(time::milliseconds(6), 2);
309 BOOST_CHECK(isCallbackInvoked);
310}
311
312BOOST_AUTO_TEST_CASE(ToString)
313{
314 std::string nullString = boost::lexical_cast<std::string>(shared_ptr<int>());
315
316 EventId eid;
317 BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(eid), nullString);
318
319 eid = scheduler.scheduleEvent(time::milliseconds(10), []{});
320 BOOST_TEST_MESSAGE("eid=" << eid);
321 BOOST_CHECK_NE(boost::lexical_cast<std::string>(eid), nullString);
322}
323
324BOOST_AUTO_TEST_SUITE_END() // EventId
325
326BOOST_AUTO_TEST_SUITE(ScopedEventId)
327
328using scheduler::ScopedEventId;
329
330BOOST_AUTO_TEST_CASE(Destruct)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800331{
332 int hit = 0;
333 {
334 ScopedEventId se(scheduler);
335 se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; });
336 } // se goes out of scope
337 this->advanceClocks(time::milliseconds(1), 15);
338 BOOST_CHECK_EQUAL(hit, 0);
339}
340
Junxiao Shid50f2b42016-08-10 02:59:59 +0000341BOOST_AUTO_TEST_CASE(Assign)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800342{
343 int hit1 = 0, hit2 = 0;
344 ScopedEventId se1(scheduler);
345 se1 = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit1; });
346 se1 = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit2; });
347 this->advanceClocks(time::milliseconds(1), 15);
348 BOOST_CHECK_EQUAL(hit1, 0);
349 BOOST_CHECK_EQUAL(hit2, 1);
350}
351
Junxiao Shid50f2b42016-08-10 02:59:59 +0000352BOOST_AUTO_TEST_CASE(Release)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800353{
354 int hit = 0;
355 {
356 ScopedEventId se(scheduler);
357 se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; });
358 se.release();
359 } // se goes out of scope
360 this->advanceClocks(time::milliseconds(1), 15);
361 BOOST_CHECK_EQUAL(hit, 1);
362}
363
Junxiao Shid50f2b42016-08-10 02:59:59 +0000364BOOST_AUTO_TEST_CASE(Move)
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800365{
366 int hit = 0;
367 unique_ptr<scheduler::ScopedEventId> se2;
368 {
369 ScopedEventId se(scheduler);
370 se = scheduler.scheduleEvent(time::milliseconds(10), [&] { ++hit; });
371 se2.reset(new ScopedEventId(std::move(se)));
372 } // se goes out of scope
373 this->advanceClocks(time::milliseconds(1), 15);
374 BOOST_CHECK_EQUAL(hit, 1);
375}
376
377BOOST_AUTO_TEST_SUITE_END() // ScopedEventId
378
Junxiao Shid50f2b42016-08-10 02:59:59 +0000379BOOST_AUTO_TEST_SUITE_END() // TestScheduler
380BOOST_AUTO_TEST_SUITE_END() // Util
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800381
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800382} // namespace tests
Alexander Afanasyev9a9952f2015-01-28 19:06:48 -0800383} // namespace scheduler
384} // namespace util
Alexander Afanasyevf6468892014-01-29 01:04:14 -0800385} // namespace ndn