source: tests/SystemQueue-tests.cc@ 12759

Last change on this file since 12759 was 12758, checked in by hock@…, 11 years ago

..

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