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
RevLine 
[12747]1#include "gtest/gtest.h"
2#include "ariba/utility/system/SystemQueue.h"
3
[12750]4#include <unistd.h> // usleep
[12756]5#include <boost/date_time.hpp> // local_time()
[12750]6
[12749]7#include <ostream>
8
[12747]9using namespace ::testing;
10using namespace ariba::utility;
[12749]11using namespace std;
[12747]12
[12756]13using boost::posix_time::microsec_clock;
14
15
[12748]16/**
17 * Tests if the SystemQueue is initialized empty and not running.
18 */
19TEST(SystemQueue, Instantiation)
[12747]20{
21 SystemQueue& sysq = SystemQueue::instance();
[12748]22
[12749]23// cout << &sysq << endl;
24
[12748]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();
[12747]39 SystemQueue& sysq2 = SystemQueue::instance();
[12748]40
41// cout << &sysq << endl;
[12749]42
43 EXPECT_TRUE( &sysq == &sysq2 );
[12747]44}
[12748]45
46
[12749]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
[12761]64 // XXX weg, wenn das join klappt!!
65 usleep(100);
66
[12749]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
[12751]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
[12749]86 SystemQueueTest() :
[12751]87 checkmark(false),
88 last_ordered_call(0)
[12749]89 {
90 }
91
92 void Check()
93 {
[12761]94 cout << "### Check ### "<< endl;
95
[12749]96 checkmark = true;
97 }
[12763]98
[12771]99 void CheckThread()
100 {
101 EXPECT_TRUE( SystemQueue::instance().am_I_in_the_SysQ_thread() );
102
103 checkmark = true;
104 }
105
[12763]106 void Cancel()
107 {
[12764]108 ASSERT_THROW(SystemQueue::instance().cancel(), std::logic_error);
109
[12763]110 checkmark = true;
111 }
112
[12765]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
[12751]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
[12761]139 cout << "### sleeping for " << SLEEP_TIME << " microseconds ..." << endl;
[12751]140 usleep(SLEEP_TIME);
141 }
142 }
[12749]143
[12751]144 /// call that checks wheather it was performed in order
145 void OrderedCall(int num)
146 {
[12754]147 // XXX
148 cout << "### OrderedCall num: " << num << endl;
149
[12751]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
[12749]182 bool checkmark;
[12751]183 int last_ordered_call;
[12749]184};
185
[12751]186
187/**
[12763]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
[12764]212 *
213 * --> and expects that this throws an exception
214 *
215 * NOTE: due to the SystemQueue singleton design, explicit cleanup is necessary!
[12763]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
[12764]233 // CLEANUP
234 sysq.cancel();
235
236 EXPECT_FALSE( sysq.isRunning() );
237 EXPECT_TRUE( sysq.isEmpty() );
[12763]238}
239
240
241/**
[12765]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/**
[12751]283 * schedule a call and test whether it is actually performed by the SystemQueue
284 */
[12749]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 );
[12751]297
298 // wait for the event to happen
299 wait_for_checkmark(MAX_WAIT);
[12749]300
[12751]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 */
[12762]321TEST_F(SystemQueueTest, Threading)
[12751]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() )
[12750]336 {
[12751]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 );
[12750]342 }
[12751]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
[12771]354
355TEST_F(SystemQueueTest, ThreadDetection)
356{
357 SystemQueue& sysq = SystemQueue::instance();
358
[12772]359 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
360
[12771]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
[12772]371 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
372
[12771]373 wait_for_checkmark(MAX_WAIT);
374
375 sysq.cancel();
376
[12772]377 EXPECT_FALSE( sysq.am_I_in_the_SysQ_thread() );
[12771]378 EXPECT_TRUE( checkmark ) << "WARNING! One of the test functions was not called at all!";
379}
380
381
[12751]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();
[12750]393
[12751]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
[12749]414 // stop
415 sysq.cancel();
[12751]416}
417
418
419
420/**
421 * This subclass has some special member functions suitable for timing tests
[12756]422 *
423 * NOTE: Timing tests are not always reproducable.. sorry. :-/
[12751]424 */
425class SystemQueueTimingTest :
426 public SystemQueueTest
427{
428public:
[12753]429
[12752]430/**
431 * typical delay time
432 *
433 * should be long enough for meaningful tests,
434 * but should not lengthen the test excessivly
435 */
[12754]436#define DELAY_TIME 20 // ms
[12764]437#define DELAY_MARGIN 1000 // microseconds (1/1000 ms) // NOTE: maybe a meaningful value depends
438 // on the target hardwarde and system load...
[12753]439
440
441 /// constructor
442 SystemQueueTimingTest() :
443 SystemQueueTest() /* super constructor */,
[12757]444 sysq( SystemQueue::instance() ),
445 calls(0)
[12753]446 {
447 }
[12752]448
[12753]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 }
[12756]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
[12757]477 cout << "### Timing difference: " << diff << " microseconds" << endl;
[12756]478
479 EXPECT_LT( abs(diff), margin );
480
[12757]481 calls++;
[12756]482 checkmark = true;
483 }
[12753]484
485 SystemQueue& sysq;
[12757]486 int calls;
[12751]487};
488
489
[12752]490/**
491 * schedules a delayed call and tests whether it is called (more or less timely..)
492 */
493TEST_F(SystemQueueTimingTest, DelayedCall)
[12751]494{
[12752]495 // scheduleCall
496 sysq.scheduleCall(
[12754]497 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
[12752]498 );
499
500 // noting to do until the delay is up..
[12764]501 usleep(DELAY_TIME*1000 + DELAY_MARGIN*10);
[12752]502
503 // wait for the event to happen
504 wait_for_checkmark(MAX_WAIT);
505
[12754]506 EXPECT_TRUE( checkmark ) << "Delayed function was not called within delaytime ("
[12752]507 << DELAY_TIME << " ms) + " << (MAX_WAIT + DELAY_MARGIN) << " microseconds.";
[12749]508}
509
[12754]510
511/**
[12755]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/**
[12754]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(
[12756]565 boost::bind(&SystemQueueTimingTest::Check, this),
[12754]566 DELAY_TIME*4
567 );
568
569 // noting to do until the delay is up..
[12764]570 usleep(DELAY_TIME * 4000 + DELAY_MARGIN*10);
[12754]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}
[12756]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
[12757]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}
[12758]634
635
636/*
637 * TODO
638 *
[12764]639 * maybe one more complicated testcase with timing and directly scheduled events
[12758]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.