source: tests/SystemQueue-tests.cc

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

modified unit test

File size: 15.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 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 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
360
361 // start
362 sysq.run();
363
364 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
365
366 // scheduleCall
367 sysq.scheduleCall(
368 boost::bind(&SystemQueueTest::CheckThread, this)
369 );
370
371 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
372
373 wait_for_checkmark(MAX_WAIT);
374
375 sysq.cancel();
376
377 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
378 EXPECT_TRUE( checkmark ) << "WARNING! One of the test functions was not called at all!";
379}
380
381
382/**
383 * schedule multiple calls
384 *
385 * each call must be performed, in the correct order
386 *
387 * NOTE: The nested calls are not necessarily in order with calls scheduled from the main thread,
388 * that's fine, therefore we make sure the nested calls are done, before scheduling new ones.
389 */
390TEST_F(SystemQueueTest, MultipleCalls)
391{
392 SystemQueue& sysq = SystemQueue::instance();
393
394 // start
395 sysq.run();
396
397 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 1) );
398 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 2) );
399 sysq.scheduleCall( boost::bind(&SystemQueueTest::NestedOrderedCall, this, 3, 5) );
400
401 // make sure all nested calls are done
402 wait_for_checkmark(MAX_WAIT); // XXX should be "wait_until_empty() ...."
403
404 checkmark = false;
405 sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 6) );
406
407 // XXX same here... [ wait_until_empty() ]
408 sysq.scheduleCall( boost::bind(&SystemQueueTest::Check, this) );
409 wait_for_checkmark(MAX_WAIT);
410
411 // evaluation
412 EXPECT_EQ( 6, last_ordered_call);
413
414 // stop
415 sysq.cancel();
416}
417
418
419
420/**
421 * This subclass has some special member functions suitable for timing tests
422 *
423 * NOTE: Timing tests are not always reproducable.. sorry. :-/
424 */
425class SystemQueueTimingTest :
426 public SystemQueueTest
427{
428public:
429
430/**
431 * typical delay time
432 *
433 * should be long enough for meaningful tests,
434 * but should not lengthen the test excessivly
435 */
436#define DELAY_TIME 20 // ms
437#define DELAY_MARGIN 1000 // microseconds (1/1000 ms) // NOTE: maybe a meaningful value depends
438 // on the target hardwarde and system load...
439
440
441 /// constructor
442 SystemQueueTimingTest() :
443 SystemQueueTest() /* super constructor */,
444 sysq( SystemQueue::instance() ),
445 calls(0)
446 {
447 }
448
449 virtual void SetUp()
450 {
451 // start SystemQueue
452 sysq.run();
453 }
454
455
456 virtual void TearDown()
457 {
458 // stop SystemQueue
459 sysq.cancel();
460 }
461
462
463 /**
464 * @param placed_in_queue The time (as ptime) when this event is put into the delay queue
465 * @param intended_sleep_time The time (in microseconds) the event is supposed to sleep in the queue
466 * @param margin The acceptable margin (in microseconds)
467 */
468 void TimeCheckingCall(ptime placed_in_queue, uint64_t intended_sleep_time, uint64_t margin)
469 {
470 ptime called_at = microsec_clock::local_time();
471
472 // calculate actual sleep time and difference to intended sleep time
473 boost::posix_time::time_duration actual_sleep_time = called_at - placed_in_queue;
474 uint64_t diff = actual_sleep_time.total_microseconds() - intended_sleep_time;
475
476 // info
477 cout << "### Timing difference: " << diff << " microseconds" << endl;
478
479 EXPECT_LT( abs(diff), margin );
480
481 calls++;
482 checkmark = true;
483 }
484
485 SystemQueue& sysq;
486 int calls;
487};
488
489
490/**
491 * schedules a delayed call and tests whether it is called (more or less timely..)
492 */
493TEST_F(SystemQueueTimingTest, DelayedCall)
494{
495 // scheduleCall
496 sysq.scheduleCall(
497 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
498 );
499
500 // noting to do until the delay is up..
501 usleep(DELAY_TIME*1000 + DELAY_MARGIN*10);
502
503 // wait for the event to happen
504 wait_for_checkmark(MAX_WAIT);
505
506 EXPECT_TRUE( checkmark ) << "Delayed function was not called within delaytime ("
507 << DELAY_TIME << " ms) + " << (MAX_WAIT + DELAY_MARGIN) << " microseconds.";
508}
509
510
511/**
512 * tests whether the SystemQueue is considered non-empty, while an event is delayed-waiting
513 */
514TEST_F(SystemQueueTimingTest, NotEmptyWhileWaiting)
515{
516 // scheduleCall
517 sysq.scheduleCall(
518 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
519 );
520
521 // SystemQueue must not be empty as long as the event is not finished (and especially while stille queued)
522 if ( sysq.isEmpty() )
523 {
524 // assert that this test is actually meaningful
525 ASSERT_FALSE( checkmark )
526 << "NOTE: This is not necessarily a bug, maybe the timing just have to adjusted. Try to increase MAX_WAIT.";
527
528 EXPECT_TRUE( ! sysq.isEmpty() || checkmark );
529 }
530}
531
532
533
534/**
535 * schedules a delayed call and tests whether it is called (more or less timely..)
536 */
537TEST_F(SystemQueueTimingTest, MultipleCalls)
538{
539 // schedule 4th call
540 sysq.scheduleCall(
541 boost::bind(&SystemQueueTest::OrderedCall, this, 4),
542 DELAY_TIME*3
543 );
544
545 // schedule 2nd call
546 sysq.scheduleCall(
547 boost::bind(&SystemQueueTest::OrderedCall, this, 2),
548 DELAY_TIME*1
549 );
550
551 // schedule 3rd call
552 sysq.scheduleCall(
553 boost::bind(&SystemQueueTest::OrderedCall, this, 3),
554 DELAY_TIME*2
555 );
556
557 // schedule 1st call (without delay)
558 sysq.scheduleCall(
559 boost::bind(&SystemQueueTest::OrderedCall, this, 1)
560 );
561
562
563 // XXX the usual bug..
564 sysq.scheduleCall(
565 boost::bind(&SystemQueueTimingTest::Check, this),
566 DELAY_TIME*4
567 );
568
569 // noting to do until the delay is up..
570 usleep(DELAY_TIME * 4000 + DELAY_MARGIN*10);
571
572 // wait for the event to happen
573 wait_for_checkmark(MAX_WAIT);
574
575 // evaluation
576 EXPECT_EQ( 4, last_ordered_call);
577}
578
579
580/**
581 * Schedules a delayed call and test whether the sleep time is acurate
582 */
583TEST_F(SystemQueueTimingTest, TimingSingleCall)
584{
585 ptime now = microsec_clock::local_time();
586
587 sysq.scheduleCall(
588 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
589 now, DELAY_TIME*1000, DELAY_MARGIN),
590 DELAY_TIME
591 );
592
593 // main thread is going to sleep..
594 usleep(DELAY_TIME * 1000 + DELAY_MARGIN * 2);
595 wait_for_checkmark(MAX_WAIT);
596
597 // make sure the measurement function was called at all
598 EXPECT_TRUE(checkmark) << "Measurement function was NOT RUN AT ALL!";
599}
600
601
602/**
603 * Like TimingSingleCall but tests whether the timings change when multiple events are scheduled.
604 */
605TEST_F(SystemQueueTimingTest, TimingMultipleCalls)
606{
607 ptime now = microsec_clock::local_time();
608
609 sysq.scheduleCall(
610 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
611 now, DELAY_TIME*1000 * 2, DELAY_MARGIN),
612 DELAY_TIME * 2
613 );
614
615 sysq.scheduleCall(
616 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
617 now, DELAY_TIME*1000 * 3, DELAY_MARGIN),
618 DELAY_TIME * 3
619 );
620
621 sysq.scheduleCall(
622 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
623 now, DELAY_TIME*1000, DELAY_MARGIN),
624 DELAY_TIME
625 );
626
627 // main thread is going to sleep..
628 usleep(DELAY_TIME * 3000 + DELAY_MARGIN * 2);
629 wait_for_checkmark(MAX_WAIT); // XXX wait_until_empty
630
631 // make sure the measurement function was called at all
632 EXPECT_EQ(3, calls) << "Not every event was performed..";
633}
634
635
636/*
637 * TODO
638 *
639 * maybe one more complicated testcase with timing and directly scheduled events
640 *
641 * but this probably only makes sense after a working SysQ implementation exists..
642 */
Note: See TracBrowser for help on using the repository browser.