source: tests/SystemQueue-tests.cc@ 12756

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

TEST_F(SystemQueueTimingTest, TimingSingleCall)

File size: 11.3 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 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
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
83 SystemQueueTest() :
84 checkmark(false),
85 last_ordered_call(0)
86 {
87 }
88
89 void Check()
90 {
91 checkmark = true;
92 }
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 }
114
115 /// call that checks wheather it was performed in order
116 void OrderedCall(int num)
117 {
118 // XXX
119 cout << "### OrderedCall num: " << num << endl;
120
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
153 bool checkmark;
154 int last_ordered_call;
155};
156
157
158/**
159 * schedule a call and test whether it is actually performed by the SystemQueue
160 */
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 );
173
174 // wait for the event to happen
175 wait_for_checkmark(MAX_WAIT);
176
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() )
212 {
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 );
218 }
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();
241
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
262 // stop
263 sysq.cancel();
264}
265
266
267
268/**
269 * This subclass has some special member functions suitable for timing tests
270 *
271 * NOTE: Timing tests are not always reproducable.. sorry. :-/
272 */
273class SystemQueueTimingTest :
274 public SystemQueueTest
275{
276public:
277
278/**
279 * typical delay time
280 *
281 * should be long enough for meaningful tests,
282 * but should not lengthen the test excessivly
283 */
284#define DELAY_TIME 20 // ms
285#define DELAY_MARGIN 2000 // microseconds (1/1000 ms) // TODO maybe this is too much..
286
287
288 /// constructor
289 SystemQueueTimingTest() :
290 SystemQueueTest() /* super constructor */,
291 sysq( SystemQueue::instance() )
292 {
293 }
294
295 virtual void SetUp()
296 {
297 // start SystemQueue
298 sysq.run();
299 }
300
301
302 virtual void TearDown()
303 {
304 // stop SystemQueue
305 sysq.cancel();
306 }
307
308
309 /**
310 * @param placed_in_queue The time (as ptime) when this event is put into the delay queue
311 * @param intended_sleep_time The time (in microseconds) the event is supposed to sleep in the queue
312 * @param margin The acceptable margin (in microseconds)
313 */
314 void TimeCheckingCall(ptime placed_in_queue, uint64_t intended_sleep_time, uint64_t margin)
315 {
316 ptime called_at = microsec_clock::local_time();
317
318 // calculate actual sleep time and difference to intended sleep time
319 boost::posix_time::time_duration actual_sleep_time = called_at - placed_in_queue;
320 uint64_t diff = actual_sleep_time.total_microseconds() - intended_sleep_time;
321
322 // info
323 cout << "/// Timing difference: " << diff << " microseconds" << endl;
324
325 EXPECT_LT( abs(diff), margin );
326
327 checkmark = true;
328 }
329
330 SystemQueue& sysq;
331};
332
333
334/**
335 * schedules a delayed call and tests whether it is called (more or less timely..)
336 */
337TEST_F(SystemQueueTimingTest, DelayedCall)
338{
339 // scheduleCall
340 sysq.scheduleCall(
341 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
342 );
343
344 // noting to do until the delay is up..
345 usleep(DELAY_TIME*1000 + DELAY_MARGIN*10); // XXX margin too high (TODO lower when SysQ is reimplemented)
346
347 // wait for the event to happen
348 wait_for_checkmark(MAX_WAIT);
349
350 EXPECT_TRUE( checkmark ) << "Delayed function was not called within delaytime ("
351 << DELAY_TIME << " ms) + " << (MAX_WAIT + DELAY_MARGIN) << " microseconds.";
352}
353
354
355/**
356 * tests whether the SystemQueue is considered non-empty, while an event is delayed-waiting
357 */
358TEST_F(SystemQueueTimingTest, NotEmptyWhileWaiting)
359{
360 // scheduleCall
361 sysq.scheduleCall(
362 boost::bind(&SystemQueueTimingTest::Check, this), DELAY_TIME
363 );
364
365 // SystemQueue must not be empty as long as the event is not finished (and especially while stille queued)
366 if ( sysq.isEmpty() )
367 {
368 // assert that this test is actually meaningful
369 ASSERT_FALSE( checkmark )
370 << "NOTE: This is not necessarily a bug, maybe the timing just have to adjusted. Try to increase MAX_WAIT.";
371
372 EXPECT_TRUE( ! sysq.isEmpty() || checkmark );
373 }
374}
375
376
377
378/**
379 * schedules a delayed call and tests whether it is called (more or less timely..)
380 */
381TEST_F(SystemQueueTimingTest, MultipleCalls)
382{
383 // schedule 4th call
384 sysq.scheduleCall(
385 boost::bind(&SystemQueueTest::OrderedCall, this, 4),
386 DELAY_TIME*3
387 );
388
389 // schedule 2nd call
390 sysq.scheduleCall(
391 boost::bind(&SystemQueueTest::OrderedCall, this, 2),
392 DELAY_TIME*1
393 );
394
395 // schedule 3rd call
396 sysq.scheduleCall(
397 boost::bind(&SystemQueueTest::OrderedCall, this, 3),
398 DELAY_TIME*2
399 );
400
401 // schedule 1st call (without delay)
402 sysq.scheduleCall(
403 boost::bind(&SystemQueueTest::OrderedCall, this, 1)
404 );
405
406
407 // XXX the usual bug..
408 sysq.scheduleCall(
409 boost::bind(&SystemQueueTimingTest::Check, this),
410 DELAY_TIME*4
411 );
412
413 // noting to do until the delay is up..
414 usleep(DELAY_TIME * 4000 + DELAY_MARGIN*100); // XXX margin too high
415
416 // wait for the event to happen
417 wait_for_checkmark(MAX_WAIT);
418
419 // evaluation
420 EXPECT_EQ( 4, last_ordered_call);
421}
422
423
424/**
425 * Schedules a delayed call and test whether the sleep time is acurate
426 */
427TEST_F(SystemQueueTimingTest, TimingSingleCall)
428{
429 ptime now = microsec_clock::local_time();
430
431 sysq.scheduleCall(
432 boost::bind(&SystemQueueTimingTest::TimeCheckingCall, this,
433 now, DELAY_TIME*1000, DELAY_MARGIN),
434 DELAY_TIME
435 );
436
437 // main thread is going to sleep..
438 usleep(DELAY_TIME * 1000 + DELAY_MARGIN * 2);
439 wait_for_checkmark(MAX_WAIT);
440
441 // make sure the measurement function was called at all
442 EXPECT_TRUE(checkmark) << "Measurement function was NOT RUN AT ALL!";
443}
444
Note: See TracBrowser for help on using the repository browser.