source: tests/SystemQueue-tests.cc@ 12761

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

New System Queue:

The new System Queue already passes most tests that do not contain delayed calls.

[ But it's (abviously) not ready for productive use, yet. ]

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