| 1 | #include "gtest/gtest.h" | 
|---|
| 2 | #include "ariba/utility/system/SystemQueue.h" | 
|---|
| 3 |  | 
|---|
| 4 | #include <unistd.h>  // usleep | 
|---|
| 5 |  | 
|---|
| 6 | #include <ostream> | 
|---|
| 7 |  | 
|---|
| 8 | using namespace ::testing; | 
|---|
| 9 | using namespace ariba::utility; | 
|---|
| 10 | using namespace std; | 
|---|
| 11 |  | 
|---|
| 12 | /** | 
|---|
| 13 | *  Tests if the SystemQueue is initialized empty and not running. | 
|---|
| 14 | */ | 
|---|
| 15 | TEST(SystemQueue, Instantiation) | 
|---|
| 16 | { | 
|---|
| 17 | SystemQueue& sysq = SystemQueue::instance(); | 
|---|
| 18 |  | 
|---|
| 19 | //     cout << &sysq << endl; | 
|---|
| 20 |  | 
|---|
| 21 | EXPECT_FALSE( sysq.isRunning() ); | 
|---|
| 22 | EXPECT_TRUE( sysq.isEmpty() ); | 
|---|
| 23 | } | 
|---|
| 24 |  | 
|---|
| 25 |  | 
|---|
| 26 | /** | 
|---|
| 27 | *  Tests whether calling the SystemQueue::instance() always returns the same object. | 
|---|
| 28 | * | 
|---|
| 29 | *  NOTE: This is an easy case, since this is the same compile unit.. | 
|---|
| 30 | *    But can't hurt to test it anyway. | 
|---|
| 31 | */ | 
|---|
| 32 | TEST(SystemQueue, Singleton) | 
|---|
| 33 | { | 
|---|
| 34 | SystemQueue& sysq = SystemQueue::instance(); | 
|---|
| 35 | SystemQueue& sysq2 = SystemQueue::instance(); | 
|---|
| 36 |  | 
|---|
| 37 | //     cout << &sysq << endl; | 
|---|
| 38 |  | 
|---|
| 39 | EXPECT_TRUE( &sysq == &sysq2 ); | 
|---|
| 40 | } | 
|---|
| 41 |  | 
|---|
| 42 |  | 
|---|
| 43 | /** | 
|---|
| 44 | *  Start and stop the SystemQueue | 
|---|
| 45 | */ | 
|---|
| 46 | TEST(SystemQueue, StartStop) | 
|---|
| 47 | { | 
|---|
| 48 | SystemQueue& sysq = SystemQueue::instance(); | 
|---|
| 49 |  | 
|---|
| 50 | EXPECT_FALSE( sysq.isRunning() ); | 
|---|
| 51 |  | 
|---|
| 52 | // start | 
|---|
| 53 | sysq.run(); | 
|---|
| 54 |  | 
|---|
| 55 | EXPECT_TRUE( sysq.isRunning() ); | 
|---|
| 56 |  | 
|---|
| 57 | // stop | 
|---|
| 58 | sysq.cancel(); | 
|---|
| 59 |  | 
|---|
| 60 | EXPECT_FALSE( sysq.isRunning() ); | 
|---|
| 61 | } | 
|---|
| 62 |  | 
|---|
| 63 |  | 
|---|
| 64 | /** | 
|---|
| 65 | *  Test fixture | 
|---|
| 66 | * | 
|---|
| 67 | *  class that can be called by the SystemQueue | 
|---|
| 68 | */ | 
|---|
| 69 | // To use a test fixture, derive a class from testing::Test. | 
|---|
| 70 | class SystemQueueTest : | 
|---|
| 71 | public testing::Test | 
|---|
| 72 | { | 
|---|
| 73 | public: | 
|---|
| 74 |  | 
|---|
| 75 | // sleep time when waiting for the system queue (max total / each step) | 
|---|
| 76 | #define MAX_WAIT 100  // microseconds | 
|---|
| 77 | #define SLEEP_TIME 10  // microseconds | 
|---|
| 78 |  | 
|---|
| 79 | SystemQueueTest() : | 
|---|
| 80 | checkmark(false), | 
|---|
| 81 | last_ordered_call(0) | 
|---|
| 82 | { | 
|---|
| 83 | } | 
|---|
| 84 |  | 
|---|
| 85 | void Check() | 
|---|
| 86 | { | 
|---|
| 87 | checkmark = true; | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | void LongRunner() | 
|---|
| 91 | { | 
|---|
| 92 | usleep( MAX_WAIT / 2 ); | 
|---|
| 93 |  | 
|---|
| 94 | checkmark = true; | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 |  | 
|---|
| 98 | /// wait for the checkmark to be set by a SystemQueue call, (but not too long!) | 
|---|
| 99 | void wait_for_checkmark(int max_wait = MAX_WAIT) | 
|---|
| 100 | { | 
|---|
| 101 | for ( int i = 0; i < max_wait / SLEEP_TIME; i++) | 
|---|
| 102 | { | 
|---|
| 103 | if ( checkmark ) | 
|---|
| 104 | break; | 
|---|
| 105 |  | 
|---|
| 106 | cout << "/// sleeping for " << SLEEP_TIME << " microseconds ..." << endl; | 
|---|
| 107 | usleep(SLEEP_TIME); | 
|---|
| 108 | } | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | /// call that checks wheather it was performed in order | 
|---|
| 112 | void OrderedCall(int num) | 
|---|
| 113 | { | 
|---|
| 114 | // check ordering | 
|---|
| 115 | EXPECT_EQ( num, last_ordered_call + 1); | 
|---|
| 116 |  | 
|---|
| 117 | last_ordered_call = num; | 
|---|
| 118 | } | 
|---|
| 119 |  | 
|---|
| 120 | /// like OrderedCall, but calls itself to test nested calls | 
|---|
| 121 | void NestedOrderedCall(int from, int to) | 
|---|
| 122 | { | 
|---|
| 123 | // check ordering | 
|---|
| 124 | OrderedCall(from); | 
|---|
| 125 |  | 
|---|
| 126 | // nested call | 
|---|
| 127 | if ( from < to ) | 
|---|
| 128 | { | 
|---|
| 129 | SystemQueue::instance().scheduleCall( | 
|---|
| 130 | boost::bind(&SystemQueueTest::NestedOrderedCall, | 
|---|
| 131 | this, | 
|---|
| 132 | from+1, | 
|---|
| 133 | to) | 
|---|
| 134 | ); | 
|---|
| 135 | } | 
|---|
| 136 | else | 
|---|
| 137 | { | 
|---|
| 138 | /// XXX because the current/old SystemQueue does not pass the Threading test, | 
|---|
| 139 | /// we have to signal, that when all nested calls are finished, | 
|---|
| 140 | /// so we need to set the checkmark here.. | 
|---|
| 141 |  | 
|---|
| 142 | checkmark = true; | 
|---|
| 143 | } | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | bool checkmark; | 
|---|
| 147 | int last_ordered_call; | 
|---|
| 148 | }; | 
|---|
| 149 |  | 
|---|
| 150 |  | 
|---|
| 151 | /** | 
|---|
| 152 | *  schedule a call and test whether it is actually performed by the SystemQueue | 
|---|
| 153 | */ | 
|---|
| 154 | TEST_F(SystemQueueTest, ScheduleCall) | 
|---|
| 155 | { | 
|---|
| 156 | SystemQueue& sysq = SystemQueue::instance(); | 
|---|
| 157 | checkmark = false;  // just to be sure.. | 
|---|
| 158 |  | 
|---|
| 159 | // start | 
|---|
| 160 | sysq.run(); | 
|---|
| 161 |  | 
|---|
| 162 | // scheduleCall | 
|---|
| 163 | sysq.scheduleCall( | 
|---|
| 164 | boost::bind(&SystemQueueTest::Check, this) | 
|---|
| 165 | ); | 
|---|
| 166 |  | 
|---|
| 167 | // wait for the event to happen | 
|---|
| 168 | wait_for_checkmark(MAX_WAIT); | 
|---|
| 169 |  | 
|---|
| 170 | // stop | 
|---|
| 171 | sysq.cancel(); | 
|---|
| 172 |  | 
|---|
| 173 | EXPECT_TRUE( checkmark ) << "Function was not called within " << MAX_WAIT << " microseconds."; | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 |  | 
|---|
| 177 | /** | 
|---|
| 178 | *  This test actually tests two things [sorry, but it's hard to test them separately!] | 
|---|
| 179 | * | 
|---|
| 180 | *  - first: the SystemQueue should not consider itself empty, while an event is processed | 
|---|
| 181 | *  - second: SystemQueue events should be processed in parallel to the main thread | 
|---|
| 182 | * | 
|---|
| 183 | *  NOTE: The timings here are not obvious, maybe they have to be adjusted on very slow machines | 
|---|
| 184 | * | 
|---|
| 185 | *  NOTE: !! The current/old SystemQueue does NOT pass this test!! | 
|---|
| 186 | * | 
|---|
| 187 | *    That's also why we need the unhandy wait_for_checkmark function, | 
|---|
| 188 | *    instead a wait_until_empty function. | 
|---|
| 189 | */ | 
|---|
| 190 | TEST_F(SystemQueueTest, DISABLED_Threading) | 
|---|
| 191 | { | 
|---|
| 192 | SystemQueue& sysq = SystemQueue::instance(); | 
|---|
| 193 | checkmark = false;  // just to be sure.. | 
|---|
| 194 |  | 
|---|
| 195 | // start | 
|---|
| 196 | sysq.run(); | 
|---|
| 197 |  | 
|---|
| 198 | // scheduleCall | 
|---|
| 199 | sysq.scheduleCall( | 
|---|
| 200 | boost::bind(&SystemQueueTest::LongRunner, this) | 
|---|
| 201 | ); | 
|---|
| 202 |  | 
|---|
| 203 | // SystemQueue must not be empty as long as the event is not finished | 
|---|
| 204 | if ( sysq.isEmpty() ) | 
|---|
| 205 | { | 
|---|
| 206 | // assert that this test is actually meaningful | 
|---|
| 207 | ASSERT_FALSE( checkmark ) | 
|---|
| 208 | << "NOTE: This is not necessarily a bug, maybe the timing just have to adjusted. Try to increase MAX_WAIT."; | 
|---|
| 209 |  | 
|---|
| 210 | EXPECT_TRUE( ! sysq.isEmpty() || checkmark ); | 
|---|
| 211 | } | 
|---|
| 212 |  | 
|---|
| 213 | // wait for the event to finish | 
|---|
| 214 | wait_for_checkmark(MAX_WAIT); | 
|---|
| 215 |  | 
|---|
| 216 | // stop | 
|---|
| 217 | sysq.cancel(); | 
|---|
| 218 |  | 
|---|
| 219 | // even the long-runner should finally finish | 
|---|
| 220 | EXPECT_TRUE( checkmark ) << "Function has not finished within " << MAX_WAIT << " microseconds."; | 
|---|
| 221 | } | 
|---|
| 222 |  | 
|---|
| 223 | /** | 
|---|
| 224 | *  schedule multiple calls | 
|---|
| 225 | * | 
|---|
| 226 | *  each call must be performed, in the correct order | 
|---|
| 227 | * | 
|---|
| 228 | *  NOTE: The nested calls are not necessarily in order with calls scheduled from the main thread, | 
|---|
| 229 | *  that's fine, therefore we make sure the nested calls are done, before scheduling new ones. | 
|---|
| 230 | */ | 
|---|
| 231 | TEST_F(SystemQueueTest, MultipleCalls) | 
|---|
| 232 | { | 
|---|
| 233 | SystemQueue& sysq = SystemQueue::instance(); | 
|---|
| 234 |  | 
|---|
| 235 | // start | 
|---|
| 236 | sysq.run(); | 
|---|
| 237 |  | 
|---|
| 238 | sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 1) ); | 
|---|
| 239 | sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 2) ); | 
|---|
| 240 | sysq.scheduleCall( boost::bind(&SystemQueueTest::NestedOrderedCall, this, 3, 5) ); | 
|---|
| 241 |  | 
|---|
| 242 | // make sure all nested calls are done | 
|---|
| 243 | wait_for_checkmark(MAX_WAIT);  // XXX should be "wait_until_empty() ...." | 
|---|
| 244 |  | 
|---|
| 245 | checkmark = false; | 
|---|
| 246 | sysq.scheduleCall( boost::bind(&SystemQueueTest::OrderedCall, this, 6) ); | 
|---|
| 247 |  | 
|---|
| 248 | // XXX same here...  [ wait_until_empty() ] | 
|---|
| 249 | sysq.scheduleCall( boost::bind(&SystemQueueTest::Check, this) ); | 
|---|
| 250 | wait_for_checkmark(MAX_WAIT); | 
|---|
| 251 |  | 
|---|
| 252 | // evaluation | 
|---|
| 253 | EXPECT_EQ( 6, last_ordered_call); | 
|---|
| 254 |  | 
|---|
| 255 | // stop | 
|---|
| 256 | sysq.cancel(); | 
|---|
| 257 | } | 
|---|
| 258 |  | 
|---|
| 259 |  | 
|---|
| 260 |  | 
|---|
| 261 | /** | 
|---|
| 262 | *  This subclass has some special member functions suitable for timing tests | 
|---|
| 263 | */ | 
|---|
| 264 | class SystemQueueTimingTest : | 
|---|
| 265 | public SystemQueueTest | 
|---|
| 266 | { | 
|---|
| 267 | public: | 
|---|
| 268 |  | 
|---|
| 269 | }; | 
|---|
| 270 |  | 
|---|
| 271 |  | 
|---|
| 272 | TEST_F(SystemQueueTimingTest, MultipleCalls)  /* TODO different name..? */ | 
|---|
| 273 | { | 
|---|
| 274 |  | 
|---|
| 275 | } | 
|---|
| 276 |  | 
|---|