source: tests/SystemQueue-tests.cc@ 12771

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

added new interface: SystemQueue::am_I_in_the_SysQ_thread

for debugging and asserts..

File size: 15.6 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 CheckThread()
100 {
101 EXPECT_TRUE( SystemQueue::instance().am_I_in_the_SysQ_thread() );
102
103 checkmark = true;
104 }
105
106 void Cancel()
107 {
108 ASSERT_THROW(SystemQueue::instance().cancel(), std::logic_error);
109
110 checkmark = true;
111 }
112
113 void Leave()
114 {
115 // let's do something before leaving..
116 this->LongRunner();
117 checkmark = false;
118
119 cout << "### Leaving SysQ ### "<< endl;
120 SystemQueue::instance().leave();
121 }
122
123 void LongRunner()
124 {
125 usleep( MAX_WAIT / 2 );
126
127 checkmark = true;
128 }
129
130
131 /// wait for the checkmark to be set by a SystemQueue call, (but not too long!)
132 void wait_for_checkmark(int max_wait = MAX_WAIT)
133 {
134 for ( int i = 0; i < max_wait / SLEEP_TIME; i++)
135 {
136 if ( checkmark )
137 break;
138
139 cout << "### sleeping for " << SLEEP_TIME << " microseconds ..." << endl;
140 usleep(SLEEP_TIME);
141 }
142 }
143
144 /// call that checks wheather it was performed in order
145 void OrderedCall(int num)
146 {
147 // XXX
148 cout << "### OrderedCall num: " << num << endl;
149
150 // check ordering
151 EXPECT_EQ( num, last_ordered_call + 1);
152
153 last_ordered_call = num;
154 }
155
156 /// like OrderedCall, but calls itself to test nested calls
157 void NestedOrderedCall(int from, int to)
158 {
159 // check ordering
160 OrderedCall(from);
161
162 // nested call
163 if ( from < to )
164 {
165 SystemQueue::instance().scheduleCall(
166 boost::bind(&SystemQueueTest::NestedOrderedCall,
167 this,
168 from+1,
169 to)
170 );
171 }
172 else
173 {
174 /// XXX because the current/old SystemQueue does not pass the Threading test,
175 /// we have to signal, that when all nested calls are finished,
176 /// so we need to set the checkmark here..
177
178 checkmark = true;
179 }
180 }
181
182 bool checkmark;
183 int last_ordered_call;
184};
185
186
187/**
188 * Enqueues an event but then cancels the SystemQueue without running
189 */
190TEST_F(SystemQueueTest, EmptyAfterCancel)
191{
192 SystemQueue& sysq = SystemQueue::instance();
193
194 EXPECT_TRUE( sysq.isEmpty() );
195
196 // enqueue event
197 sysq.scheduleCall(
198 boost::bind(&SystemQueueTest::Check, this)
199 );
200
201 EXPECT_FALSE( sysq.isEmpty() );
202
203 // cancel
204 sysq.cancel();
205
206 EXPECT_TRUE( sysq.isEmpty() );
207}
208
209
210/**
211 * cancels the SystemQueue from inside a scheduled event
212 *
213 * --> and expects that this throws an exception
214 *
215 * NOTE: due to the SystemQueue singleton design, explicit cleanup is necessary!
216 */
217TEST_F(SystemQueueTest, CancelFromInsideEvent)
218{
219 SystemQueue& sysq = SystemQueue::instance();
220 checkmark = false; // just to be sure..
221
222 // start
223 sysq.run();
224
225 // scheduleCall
226 sysq.scheduleCall(
227 boost::bind(&SystemQueueTest::Cancel, this)
228 );
229
230 // wait for the event to happen
231 wait_for_checkmark(MAX_WAIT);
232
233 // CLEANUP
234 sysq.cancel();
235
236 EXPECT_FALSE( sysq.isRunning() );
237 EXPECT_TRUE( sysq.isEmpty() );
238}
239
240
241/**
242 * leaves the SystemQueue from inside a scheduled event (in contrast to cancel)
243 *
244 * NOTE: due to the SystemQueue singleton design, explicit cleanup is necessary!
245 *
246 * [ NOTE: the old System Queue does not support this. ]
247 */
248TEST_F(SystemQueueTest, LeaveFromInsideEvent)
249{
250 SystemQueue& sysq = SystemQueue::instance();
251
252 // start
253 sysq.run();
254
255 // scheduleCall
256 sysq.scheduleCall(
257 boost::bind(&SystemQueueTest::Leave, this)
258 );
259
260 // schedule another which must NOT be performed
261 sysq.scheduleCall(
262 boost::bind(&SystemQueueTest::Check, this)
263 );
264
265 // sleep until the SystemQueue thread has finished
266 sysq.join();
267
268 EXPECT_FALSE( sysq.isRunning() );
269
270 // ensure Check() was not perfomed
271 EXPECT_FALSE( sysq.isEmpty() );
272 EXPECT_FALSE( checkmark );
273
274 // CLEANUP
275 sysq.cancel();
276
277 EXPECT_FALSE( sysq.isRunning() );
278 EXPECT_TRUE( sysq.isEmpty() );
279}
280
281
282/**
283 * schedule a call and test whether it is actually performed by the SystemQueue
284 */
285TEST_F(SystemQueueTest, ScheduleCall)
286{
287 SystemQueue& sysq = SystemQueue::instance();
288 checkmark = false; // just to be sure..
289
290 // start
291 sysq.run();
292
293 // scheduleCall
294 sysq.scheduleCall(
295 boost::bind(&SystemQueueTest::Check, this)
296 );
297
298 // wait for the event to happen
299 wait_for_checkmark(MAX_WAIT);
300
301 // stop
302 sysq.cancel();
303
304 EXPECT_TRUE( checkmark ) << "Function was not called within " << MAX_WAIT << " microseconds.";
305}
306
307
308/**
309 * This test actually tests two things [sorry, but it's hard to test them separately!]
310 *
311 * - first: the SystemQueue should not consider itself empty, while an event is processed
312 * - second: SystemQueue events should be processed in parallel to the main thread
313 *
314 * NOTE: The timings here are not obvious, maybe they have to be adjusted on very slow machines
315 *
316 * NOTE: !! The current/old SystemQueue does NOT pass this test!!
317 *
318 * That's also why we need the unhandy wait_for_checkmark function,
319 * instead a wait_until_empty function.
320 */
321TEST_F(SystemQueueTest, Threading)
322{
323 SystemQueue& sysq = SystemQueue::instance();
324 checkmark = false; // just to be sure..
325
326 // start
327 sysq.run();
328
329 // scheduleCall
330 sysq.scheduleCall(
331 boost::bind(&SystemQueueTest::LongRunner, this)
332 );
333
334 // SystemQueue must not be empty as long as the event is not finished
335 if ( sysq.isEmpty() )
336 {
337 // assert that this test is actually meaningful
338 ASSERT_FALSE( checkmark )
339 << "NOTE: This is not necessarily a bug, maybe the timing just have to adjusted. Try to increase MAX_WAIT.";
340
341 EXPECT_TRUE( ! sysq.isEmpty() || checkmark );
342 }
343
344 // wait for the event to finish
345 wait_for_checkmark(MAX_WAIT);
346
347 // stop
348 sysq.cancel();
349
350 // even the long-runner should finally finish
351 EXPECT_TRUE( checkmark ) << "Function has not finished within " << MAX_WAIT << " microseconds.";
352}
353
354
355TEST_F(SystemQueueTest, ThreadDetection)
356{
357 SystemQueue& sysq = SystemQueue::instance();
358
359 // start
360 sysq.run();
361
362 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
363
364 // scheduleCall
365 sysq.scheduleCall(
366 boost::bind(&SystemQueueTest::CheckThread, this)
367 );
368
369 wait_for_checkmark(MAX_WAIT);
370
371 sysq.cancel();
372
373 EXPECT_TRUE( checkmark ) << "WARNING! One of the test functions was not called at all!";
374}
375
376
377/**
378 * schedule multiple calls
379 *
380 * each call must be performed, in the correct order
381 *
382 * NOTE: The nested calls are not necessarily in order with calls scheduled from the main thread,
383 * that's fine, therefore we make sure the nested calls are done, before scheduling new ones.
384 */
385TEST_F(SystemQueueTest, MultipleCalls)
386{
387 SystemQueue& sysq = SystemQueue::instance();
388
389 // start
390 sysq.run();
391
392 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 1) );
393 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 2) );
394 sysq.scheduleCall( boost::bind(&SystemQueueTest::NestedOrderedCall, this, 3, 5) );
395
396 // make sure all nested calls are done
397 wait_for_checkmark(MAX_WAIT); // XXX should be "wait_until_empty() ...."
398
399 checkmark = false;
400 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 6) );
401
402 // XXX same here... [ wait_until_empty() ]
403 sysq.scheduleCall( boost::bind(&SystemQueueTest::Check, this) );
404 wait_for_checkmark(MAX_WAIT);
405
406 // evaluation
407 EXPECT_EQ( 6, last_ordered_call);
408
409 // stop
410 sysq.cancel();
411}
412
413
414
415/**
416 * This subclass has some special member functions suitable for timing tests
417 *
418 * NOTE: Timing tests are not always reproducable.. sorry. :-/
419 */
420class SystemQueueTimingTest :
421 public SystemQueueTest
422{
423public:
424
425/**
426 * typical delay time
427 *
428 * should be long enough for meaningful tests,
429 * but should not lengthen the test excessivly
430 */
431#define DELAY_TIME 20 // ms
432#define DELAY_MARGIN 1000 // microseconds (1/1000 ms) // NOTE: maybe a meaningful value depends
433 // on the target hardwarde and system load...
434
435
436 /// constructor
437 SystemQueueTimingTest() :
438 SystemQueueTest() /* super constructor */,
439 sysq( SystemQueue::instance() ),
440 calls(0)
441 {
442 }
443
444 virtual void SetUp()
445 {
446 // start SystemQueue
447 sysq.run();
448 }
449
450
451 virtual void TearDown()
452 {
453 // stop SystemQueue
454 sysq.cancel();
455 }
456
457
458 /**
459 * @param placed_in_queue The time (as ptime) when this event is put into the delay queue
460 * @param intended_sleep_time The time (in microseconds) the event is supposed to sleep in the queue
461 * @param margin The acceptable margin (in microseconds)
462 */
463 void TimeCheckingCall(ptime placed_in_queue, uint64_t intended_sleep_time, uint64_t margin)
464 {
465 ptime called_at = microsec_clock::local_time();
466
467 // calculate actual sleep time and difference to intended sleep time
468 boost::posix_time::time_duration actual_sleep_time = called_at - placed_in_queue;
469 uint64_t diff = actual_sleep_time.total_microseconds() - intended_sleep_time;
470
471 // info
472 cout << "### Timing difference: " << diff << " microseconds" << endl;
473
474 EXPECT_LT( abs(diff), margin );
475
476 calls++;
477 checkmark = true;
478 }
479
480 SystemQueue& sysq;
481 int calls;
482};
483
484
485/**
486 * schedules a delayed call and tests whether it is called (more or less timely..)
487 */
488TEST_F(SystemQueueTimingTest, DelayedCall)
489{
490 // scheduleCall
491 sysq.scheduleCall(
492 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
493 );
494
495 // noting to do until the delay is up..
496 usleep(DELAY_TIME*1000 + DELAY_MARGIN*10);
497
498 // wait for the event to happen
499 wait_for_checkmark(MAX_WAIT);
500
501 EXPECT_TRUE( checkmark ) << "Delayed function was not called within delaytime ("
502 << DELAY_TIME << " ms) + " << (MAX_WAIT + DELAY_MARGIN) << " microseconds.";
503}
504
505
506/**
507 * tests whether the SystemQueue is considered non-empty, while an event is delayed-waiting
508 */
509TEST_F(SystemQueueTimingTest, NotEmptyWhileWaiting)
510{
511 // scheduleCall
512 sysq.scheduleCall(
513 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
514 );
515
516 // SystemQueue must not be empty as long as the event is not finished (and especially while stille queued)
517 if ( sysq.isEmpty() )
518 {
519 // assert that this test is actually meaningful
520 ASSERT_FALSE( checkmark )
521 << "NOTE: This is not necessarily a bug, maybe the timing just have to adjusted. Try to increase MAX_WAIT.";
522
523 EXPECT_TRUE( ! sysq.isEmpty() || checkmark );
524 }
525}
526
527
528
529/**
530 * schedules a delayed call and tests whether it is called (more or less timely..)
531 */
532TEST_F(SystemQueueTimingTest, MultipleCalls)
533{
534 // schedule 4th call
535 sysq.scheduleCall(
536 boost::bind(&SystemQueueTest::OrderedCall, this, 4),
537 DELAY_TIME*3
538 );
539
540 // schedule 2nd call
541 sysq.scheduleCall(
542 boost::bind(&SystemQueueTest::OrderedCall, this, 2),
543 DELAY_TIME*1
544 );
545
546 // schedule 3rd call
547 sysq.scheduleCall(
548 boost::bind(&SystemQueueTest::OrderedCall, this, 3),
549 DELAY_TIME*2
550 );
551
552 // schedule 1st call (without delay)
553 sysq.scheduleCall(
554 boost::bind(&SystemQueueTest::OrderedCall, this, 1)
555 );
556
557
558 // XXX the usual bug..
559 sysq.scheduleCall(
560 boost::bind(&SystemQueueTimingTest::Check, this),
561 DELAY_TIME*4
562 );
563
564 // noting to do until the delay is up..
565 usleep(DELAY_TIME * 4000 + DELAY_MARGIN*10);
566
567 // wait for the event to happen
568 wait_for_checkmark(MAX_WAIT);
569
570 // evaluation
571 EXPECT_EQ( 4, last_ordered_call);
572}
573
574
575/**
576 * Schedules a delayed call and test whether the sleep time is acurate
577 */
578TEST_F(SystemQueueTimingTest, TimingSingleCall)
579{
580 ptime now = microsec_clock::local_time();
581
582 sysq.scheduleCall(
583 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
584 now, DELAY_TIME*1000, DELAY_MARGIN),
585 DELAY_TIME
586 );
587
588 // main thread is going to sleep..
589 usleep(DELAY_TIME * 1000 + DELAY_MARGIN * 2);
590 wait_for_checkmark(MAX_WAIT);
591
592 // make sure the measurement function was called at all
593 EXPECT_TRUE(checkmark) << "Measurement function was NOT RUN AT ALL!";
594}
595
596
597/**
598 * Like TimingSingleCall but tests whether the timings change when multiple events are scheduled.
599 */
600TEST_F(SystemQueueTimingTest, TimingMultipleCalls)
601{
602 ptime now = microsec_clock::local_time();
603
604 sysq.scheduleCall(
605 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
606 now, DELAY_TIME*1000 * 2, DELAY_MARGIN),
607 DELAY_TIME * 2
608 );
609
610 sysq.scheduleCall(
611 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
612 now, DELAY_TIME*1000 * 3, DELAY_MARGIN),
613 DELAY_TIME * 3
614 );
615
616 sysq.scheduleCall(
617 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
618 now, DELAY_TIME*1000, DELAY_MARGIN),
619 DELAY_TIME
620 );
621
622 // main thread is going to sleep..
623 usleep(DELAY_TIME * 3000 + DELAY_MARGIN * 2);
624 wait_for_checkmark(MAX_WAIT); // XXX wait_until_empty
625
626 // make sure the measurement function was called at all
627 EXPECT_EQ(3, calls) << "Not every event was performed..";
628}
629
630
631/*
632 * TODO
633 *
634 * maybe one more complicated testcase with timing and directly scheduled events
635 *
636 * but this probably only makes sense after a working SysQ implementation exists..
637 */
Note: See TracBrowser for help on using the repository browser.