source: tests/SystemQueue-tests.cc@ 12763

Last change on this file since 12763 was 12763, checked in by hock@…, 10 years ago

priority queue (but not tested)

--> FIXME in SystemEvent.h (has to be fixed first!)

File size: 13.8 KB
Line 
1#include "gtest/gtest.h"
2#include "ariba/utility/system/SystemQueue.h"
3
4#include <unistd.h> // usleep
5#include <boost/date_time.hpp> // local_time()
6
7#include <ostream>
8
9using namespace ::testing;
10using namespace ariba::utility;
11using namespace std;
12
13using boost::posix_time::microsec_clock;
14
15
16/**
17 * Tests if the SystemQueue is initialized empty and not running.
18 */
19TEST(SystemQueue, Instantiation)
20{
21 SystemQueue& sysq = SystemQueue::instance();
22
23// cout << &sysq << endl;
24
25 EXPECT_FALSE( sysq.isRunning() );
26 EXPECT_TRUE( sysq.isEmpty() );
27}
28
29
30/**
31 * Tests whether calling the SystemQueue::instance() always returns the same object.
32 *
33 * NOTE: This is an easy case, since this is the same compile unit..
34 * But can't hurt to test it anyway.
35 */
36TEST(SystemQueue, Singleton)
37{
38 SystemQueue& sysq = SystemQueue::instance();
39 SystemQueue& sysq2 = SystemQueue::instance();
40
41// cout << &sysq << endl;
42
43 EXPECT_TRUE( &sysq == &sysq2 );
44}
45
46
47/**
48 * Start and stop the SystemQueue
49 */
50TEST(SystemQueue, StartStop)
51{
52 SystemQueue& sysq = SystemQueue::instance();
53
54 EXPECT_FALSE( sysq.isRunning() );
55
56 // start
57 sysq.run();
58
59 EXPECT_TRUE( sysq.isRunning() );
60
61 // stop
62 sysq.cancel();
63
64 // XXX weg, wenn das join klappt!!
65 usleep(100);
66
67 EXPECT_FALSE( sysq.isRunning() );
68}
69
70
71/**
72 * Test fixture
73 *
74 * class that can be called by the SystemQueue
75 */
76// To use a test fixture, derive a class from testing::Test.
77class SystemQueueTest :
78 public testing::Test
79{
80public:
81
82// sleep time when waiting for the system queue (max total / each step)
83#define MAX_WAIT 100 // microseconds
84#define SLEEP_TIME 10 // microseconds
85
86 SystemQueueTest() :
87 checkmark(false),
88 last_ordered_call(0)
89 {
90 }
91
92 void Check()
93 {
94 cout << "### Check ### "<< endl;
95
96 checkmark = true;
97 }
98
99 void Cancel()
100 {
101 cout << "### Cancel ### "<< endl;
102
103 SystemQueue::instance().cancel();
104 checkmark = true;
105 }
106
107 void LongRunner()
108 {
109 usleep( MAX_WAIT / 2 );
110
111 checkmark = true;
112 }
113
114
115 /// wait for the checkmark to be set by a SystemQueue call, (but not too long!)
116 void wait_for_checkmark(int max_wait = MAX_WAIT)
117 {
118 for ( int i = 0; i < max_wait / SLEEP_TIME; i++)
119 {
120 if ( checkmark )
121 break;
122
123 cout << "### sleeping for " << SLEEP_TIME << " microseconds ..." << endl;
124 usleep(SLEEP_TIME);
125 }
126 }
127
128 /// call that checks wheather it was performed in order
129 void OrderedCall(int num)
130 {
131 // XXX
132 cout << "### OrderedCall num: " << num << endl;
133
134 // check ordering
135 EXPECT_EQ( num, last_ordered_call + 1);
136
137 last_ordered_call = num;
138 }
139
140 /// like OrderedCall, but calls itself to test nested calls
141 void NestedOrderedCall(int from, int to)
142 {
143 // check ordering
144 OrderedCall(from);
145
146 // nested call
147 if ( from < to )
148 {
149 SystemQueue::instance().scheduleCall(
150 boost::bind(&SystemQueueTest::NestedOrderedCall,
151 this,
152 from+1,
153 to)
154 );
155 }
156 else
157 {
158 /// XXX because the current/old SystemQueue does not pass the Threading test,
159 /// we have to signal, that when all nested calls are finished,
160 /// so we need to set the checkmark here..
161
162 checkmark = true;
163 }
164 }
165
166 bool checkmark;
167 int last_ordered_call;
168};
169
170
171/**
172 * Enqueues an event but then cancels the SystemQueue without running
173 */
174TEST_F(SystemQueueTest, EmptyAfterCancel)
175{
176 SystemQueue& sysq = SystemQueue::instance();
177
178 EXPECT_TRUE( sysq.isEmpty() );
179
180 // enqueue event
181 sysq.scheduleCall(
182 boost::bind(&SystemQueueTest::Check, this)
183 );
184
185 EXPECT_FALSE( sysq.isEmpty() );
186
187 // cancel
188 sysq.cancel();
189
190 EXPECT_TRUE( sysq.isEmpty() );
191}
192
193
194/**
195 * cancels the SystemQueue from inside a scheduled event
196 */
197TEST_F(SystemQueueTest, CancelFromInsideEvent)
198{
199 SystemQueue& sysq = SystemQueue::instance();
200 checkmark = false; // just to be sure..
201
202 // start
203 sysq.run();
204
205 // scheduleCall
206 sysq.scheduleCall(
207 boost::bind(&SystemQueueTest::Cancel, this)
208 );
209
210 // wait for the event to happen
211 wait_for_checkmark(MAX_WAIT);
212
213 EXPECT_FALSE( sysq.isRunning() ) << "SystemQueue has not stopped properly.";
214 EXPECT_TRUE( sysq.isEmpty() ) << "SystemQueue has not stopped properly.";
215}
216
217
218/**
219 * schedule a call and test whether it is actually performed by the SystemQueue
220 */
221TEST_F(SystemQueueTest, ScheduleCall)
222{
223 SystemQueue& sysq = SystemQueue::instance();
224 checkmark = false; // just to be sure..
225
226 // start
227 sysq.run();
228
229 // scheduleCall
230 sysq.scheduleCall(
231 boost::bind(&SystemQueueTest::Check, this)
232 );
233
234 // wait for the event to happen
235 wait_for_checkmark(MAX_WAIT);
236
237 // stop
238 sysq.cancel();
239
240 EXPECT_TRUE( checkmark ) << "Function was not called within " << MAX_WAIT << " microseconds.";
241}
242
243
244/**
245 * This test actually tests two things [sorry, but it's hard to test them separately!]
246 *
247 * - first: the SystemQueue should not consider itself empty, while an event is processed
248 * - second: SystemQueue events should be processed in parallel to the main thread
249 *
250 * NOTE: The timings here are not obvious, maybe they have to be adjusted on very slow machines
251 *
252 * NOTE: !! The current/old SystemQueue does NOT pass this test!!
253 *
254 * That's also why we need the unhandy wait_for_checkmark function,
255 * instead a wait_until_empty function.
256 */
257TEST_F(SystemQueueTest, Threading)
258{
259 SystemQueue& sysq = SystemQueue::instance();
260 checkmark = false; // just to be sure..
261
262 // start
263 sysq.run();
264
265 // scheduleCall
266 sysq.scheduleCall(
267 boost::bind(&SystemQueueTest::LongRunner, this)
268 );
269
270 // SystemQueue must not be empty as long as the event is not finished
271 if ( sysq.isEmpty() )
272 {
273 // assert that this test is actually meaningful
274 ASSERT_FALSE( checkmark )
275 << "NOTE: This is not necessarily a bug, maybe the timing just have to adjusted. Try to increase MAX_WAIT.";
276
277 EXPECT_TRUE( ! sysq.isEmpty() || checkmark );
278 }
279
280 // wait for the event to finish
281 wait_for_checkmark(MAX_WAIT);
282
283 // stop
284 sysq.cancel();
285
286 // even the long-runner should finally finish
287 EXPECT_TRUE( checkmark ) << "Function has not finished within " << MAX_WAIT << " microseconds.";
288}
289
290/**
291 * schedule multiple calls
292 *
293 * each call must be performed, in the correct order
294 *
295 * NOTE: The nested calls are not necessarily in order with calls scheduled from the main thread,
296 * that's fine, therefore we make sure the nested calls are done, before scheduling new ones.
297 */
298TEST_F(SystemQueueTest, MultipleCalls)
299{
300 SystemQueue& sysq = SystemQueue::instance();
301
302 // start
303 sysq.run();
304
305 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 1) );
306 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 2) );
307 sysq.scheduleCall( boost::bind(&SystemQueueTest::NestedOrderedCall, this, 3, 5) );
308
309 // make sure all nested calls are done
310 wait_for_checkmark(MAX_WAIT); // XXX should be "wait_until_empty() ...."
311
312 checkmark = false;
313 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 6) );
314
315 // XXX same here... [ wait_until_empty() ]
316 sysq.scheduleCall( boost::bind(&SystemQueueTest::Check, this) );
317 wait_for_checkmark(MAX_WAIT);
318
319 // evaluation
320 EXPECT_EQ( 6, last_ordered_call);
321
322 // stop
323 sysq.cancel();
324}
325
326
327
328/**
329 * This subclass has some special member functions suitable for timing tests
330 *
331 * NOTE: Timing tests are not always reproducable.. sorry. :-/
332 */
333class SystemQueueTimingTest :
334 public SystemQueueTest
335{
336public:
337
338/**
339 * typical delay time
340 *
341 * should be long enough for meaningful tests,
342 * but should not lengthen the test excessivly
343 */
344#define DELAY_TIME 20 // ms
345#define DELAY_MARGIN 2000 // microseconds (1/1000 ms) // TODO maybe this is too much..
346
347
348 /// constructor
349 SystemQueueTimingTest() :
350 SystemQueueTest() /* super constructor */,
351 sysq( SystemQueue::instance() ),
352 calls(0)
353 {
354 }
355
356 virtual void SetUp()
357 {
358 // start SystemQueue
359 sysq.run();
360 }
361
362
363 virtual void TearDown()
364 {
365 // stop SystemQueue
366 sysq.cancel();
367 }
368
369
370 /**
371 * @param placed_in_queue The time (as ptime) when this event is put into the delay queue
372 * @param intended_sleep_time The time (in microseconds) the event is supposed to sleep in the queue
373 * @param margin The acceptable margin (in microseconds)
374 */
375 void TimeCheckingCall(ptime placed_in_queue, uint64_t intended_sleep_time, uint64_t margin)
376 {
377 ptime called_at = microsec_clock::local_time();
378
379 // calculate actual sleep time and difference to intended sleep time
380 boost::posix_time::time_duration actual_sleep_time = called_at - placed_in_queue;
381 uint64_t diff = actual_sleep_time.total_microseconds() - intended_sleep_time;
382
383 // info
384 cout << "### Timing difference: " << diff << " microseconds" << endl;
385
386 EXPECT_LT( abs(diff), margin );
387
388 calls++;
389 checkmark = true;
390 }
391
392 SystemQueue& sysq;
393 int calls;
394};
395
396
397/**
398 * schedules a delayed call and tests whether it is called (more or less timely..)
399 */
400TEST_F(SystemQueueTimingTest, DelayedCall)
401{
402 // scheduleCall
403 sysq.scheduleCall(
404 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
405 );
406
407 // noting to do until the delay is up..
408 usleep(DELAY_TIME*1000 + DELAY_MARGIN*10); // XXX margin too high (TODO lower when SysQ is reimplemented)
409
410 // wait for the event to happen
411 wait_for_checkmark(MAX_WAIT);
412
413 EXPECT_TRUE( checkmark ) << "Delayed function was not called within delaytime ("
414 << DELAY_TIME << " ms) + " << (MAX_WAIT + DELAY_MARGIN) << " microseconds.";
415}
416
417
418/**
419 * tests whether the SystemQueue is considered non-empty, while an event is delayed-waiting
420 */
421TEST_F(SystemQueueTimingTest, NotEmptyWhileWaiting)
422{
423 // scheduleCall
424 sysq.scheduleCall(
425 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
426 );
427
428 // SystemQueue must not be empty as long as the event is not finished (and especially while stille queued)
429 if ( sysq.isEmpty() )
430 {
431 // assert that this test is actually meaningful
432 ASSERT_FALSE( checkmark )
433 << "NOTE: This is not necessarily a bug, maybe the timing just have to adjusted. Try to increase MAX_WAIT.";
434
435 EXPECT_TRUE( ! sysq.isEmpty() || checkmark );
436 }
437}
438
439
440
441/**
442 * schedules a delayed call and tests whether it is called (more or less timely..)
443 */
444TEST_F(SystemQueueTimingTest, MultipleCalls)
445{
446 // schedule 4th call
447 sysq.scheduleCall(
448 boost::bind(&SystemQueueTest::OrderedCall, this, 4),
449 DELAY_TIME*3
450 );
451
452 // schedule 2nd call
453 sysq.scheduleCall(
454 boost::bind(&SystemQueueTest::OrderedCall, this, 2),
455 DELAY_TIME*1
456 );
457
458 // schedule 3rd call
459 sysq.scheduleCall(
460 boost::bind(&SystemQueueTest::OrderedCall, this, 3),
461 DELAY_TIME*2
462 );
463
464 // schedule 1st call (without delay)
465 sysq.scheduleCall(
466 boost::bind(&SystemQueueTest::OrderedCall, this, 1)
467 );
468
469
470 // XXX the usual bug..
471 sysq.scheduleCall(
472 boost::bind(&SystemQueueTimingTest::Check, this),
473 DELAY_TIME*4
474 );
475
476 // noting to do until the delay is up..
477 usleep(DELAY_TIME * 4000 + DELAY_MARGIN*100); // XXX margin too high
478
479 // wait for the event to happen
480 wait_for_checkmark(MAX_WAIT);
481
482 // evaluation
483 EXPECT_EQ( 4, last_ordered_call);
484}
485
486
487/**
488 * Schedules a delayed call and test whether the sleep time is acurate
489 */
490TEST_F(SystemQueueTimingTest, TimingSingleCall)
491{
492 ptime now = microsec_clock::local_time();
493
494 sysq.scheduleCall(
495 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
496 now, DELAY_TIME*1000, DELAY_MARGIN),
497 DELAY_TIME
498 );
499
500 // main thread is going to sleep..
501 usleep(DELAY_TIME * 1000 + DELAY_MARGIN * 2);
502 wait_for_checkmark(MAX_WAIT);
503
504 // make sure the measurement function was called at all
505 EXPECT_TRUE(checkmark) << "Measurement function was NOT RUN AT ALL!";
506}
507
508
509/**
510 * Like TimingSingleCall but tests whether the timings change when multiple events are scheduled.
511 */
512TEST_F(SystemQueueTimingTest, TimingMultipleCalls)
513{
514 ptime now = microsec_clock::local_time();
515
516 sysq.scheduleCall(
517 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
518 now, DELAY_TIME*1000 * 2, DELAY_MARGIN),
519 DELAY_TIME * 2
520 );
521
522 sysq.scheduleCall(
523 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
524 now, DELAY_TIME*1000 * 3, DELAY_MARGIN),
525 DELAY_TIME * 3
526 );
527
528 sysq.scheduleCall(
529 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
530 now, DELAY_TIME*1000, DELAY_MARGIN),
531 DELAY_TIME
532 );
533
534 // main thread is going to sleep..
535 usleep(DELAY_TIME * 3000 + DELAY_MARGIN * 2);
536 wait_for_checkmark(MAX_WAIT); // XXX wait_until_empty
537
538 // make sure the measurement function was called at all
539 EXPECT_EQ(3, calls) << "Not every event was performed..";
540}
541
542
543/*
544 * TODO
545 *
546 * maybe one more complicated testcall with timing and directly scheduled events
547 *
548 * but this probably only makes sense after a working SysQ implementation exists..
549 */
Note: See TracBrowser for help on using the repository browser.