Commit | Line | Data |
---|---|---|
8c15b8c7 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on this file might be covered by the GNU General Public License. | |
19 | */ | |
cd9ddaee RP |
20 | /** @file |
21 | * | |
436fb144 | 22 | * (c) Copyright 2007-2010 by Intra2net AG |
cd9ddaee RP |
23 | */ |
24 | ||
cbcb9570 | 25 | //#define NOISEDEBUG |
cd9ddaee RP |
26 | |
27 | #include <string> | |
28 | #include <iostream> | |
29 | #include <iomanip> | |
30 | #include <vector> | |
31 | ||
4f6228c3 RP |
32 | #include <async_io.hpp> |
33 | #include <async_pipe.hpp> | |
34 | #include <async_process.hpp> | |
35 | #include <async_timer.hpp> | |
36 | #include <async_callout.hpp> | |
37 | #include <async_socket.hpp> | |
7e586023 RP |
38 | #include <asyncio_system_tools.hpp> |
39 | #include <asyncio_containerfunc.hpp> | |
436fb144 | 40 | |
cd9ddaee RP |
41 | #include <boost/signal.hpp> |
42 | #include <boost/bind.hpp> | |
43 | #include <boost/random.hpp> | |
44 | ||
436fb144 TJ |
45 | #define BOOST_TEST_MAIN |
46 | #define BOOST_TEST_DYN_LINK | |
47 | #include <boost/test/unit_test.hpp> | |
cd9ddaee RP |
48 | |
49 | #ifdef NOISEDEBUG | |
50 | #define DOUT(msg) std::cout << msg << std::endl | |
51 | #else | |
52 | #define DOUT(msg) do {} while (0) | |
53 | #endif | |
54 | ||
55 | ||
56 | using namespace I2n; | |
aba4c34d | 57 | using namespace AsyncIo; |
cd9ddaee | 58 | |
cd9ddaee RP |
59 | namespace { |
60 | ||
61 | ||
62 | struct Counter | |
63 | { | |
64 | int value; | |
7e586023 RP |
65 | |
66 | ||
cd9ddaee | 67 | Counter() : value(0) { DOUT("Counter construct");} |
7e586023 | 68 | |
cd9ddaee | 69 | void reset() { value=0;} |
7e586023 | 70 | |
cd9ddaee RP |
71 | void advance() |
72 | { | |
73 | DOUT(" advance called"); | |
74 | ++value; | |
75 | } | |
7e586023 | 76 | |
cd9ddaee RP |
77 | int operator()() |
78 | { | |
79 | DOUT(" () called"); | |
80 | return ++value; | |
81 | } | |
82 | }; // eo struct Counter | |
83 | ||
84 | ||
85 | class TestTimer : public TimerBase | |
86 | { | |
87 | public: | |
7e586023 | 88 | |
cd9ddaee RP |
89 | TestTimer() |
90 | : m_counter(0u) | |
91 | { | |
92 | } // eo TestTimer() | |
7e586023 RP |
93 | |
94 | ||
cd9ddaee RP |
95 | void setDelta(long msec) |
96 | { | |
97 | setDeltaWhenTime(0,msec); | |
98 | activate(); | |
99 | } // eo setDelta(long) | |
7e586023 RP |
100 | |
101 | ||
cd9ddaee | 102 | unsigned m_counter; |
7e586023 | 103 | |
cd9ddaee | 104 | protected: |
7e586023 | 105 | |
cd9ddaee RP |
106 | virtual void execute() |
107 | { | |
108 | ++m_counter; | |
109 | } // eo execute() | |
7e586023 | 110 | |
cd9ddaee RP |
111 | }; // eo class TestTimer |
112 | ||
113 | ||
114 | ||
115 | struct ReceivedData | |
116 | { | |
117 | std::vector<std::string> m_received_vector; | |
118 | std::string m_received_string; | |
7e586023 | 119 | |
cd9ddaee RP |
120 | unsigned long m_count_lines; |
121 | unsigned long m_data_size; | |
7e586023 RP |
122 | |
123 | ||
cd9ddaee RP |
124 | void resetReceivedData() |
125 | { | |
126 | m_received_vector.clear(); | |
127 | m_received_string.clear(); | |
128 | m_count_lines= 0uL; | |
129 | m_data_size= 0uL; | |
130 | } // eo reset | |
131 | ||
132 | ||
133 | void receiveData(const std::string& data) | |
134 | { | |
135 | m_received_vector.push_back(data); | |
136 | m_received_string.append(data); | |
137 | ++m_count_lines; | |
138 | m_data_size += data.size(); | |
139 | } // eo receiveData(const std::string&) | |
7e586023 | 140 | |
cd9ddaee RP |
141 | }; // eo struct ReceivedData |
142 | ||
143 | ||
144 | ||
145 | class TestPipe : public SimplePipe, public ReceivedData | |
146 | { | |
147 | public: | |
148 | TestPipe() | |
149 | : SimplePipe() | |
150 | { | |
151 | signal_received_string.connect( boost::bind(&TestPipe::receiveData, this, _1) ); | |
152 | } // eo TestPipe() | |
153 | ||
154 | ||
7e586023 | 155 | |
cd9ddaee | 156 | protected: |
7e586023 | 157 | |
cd9ddaee RP |
158 | }; // eo class TestPipe |
159 | ||
160 | ||
161 | class TestIO : public SimpleIO2, public ReceivedData | |
162 | { | |
163 | public: | |
164 | TestIO() | |
165 | { | |
166 | signal_received_string.connect( boost::bind(&TestIO::receiveData, this, _1) ); | |
167 | } | |
168 | ||
169 | }; // eo TestIO | |
170 | ||
171 | ||
172 | class TestProcess : public ProcessImplementation, public ReceivedData | |
173 | { | |
174 | public: | |
175 | TestProcess( | |
176 | const std::string& path, | |
177 | const std::vector<std::string>& args= std::vector<std::string>() ) | |
178 | : ProcessImplementation(path,args) | |
179 | { | |
180 | m_signal_read.connect( boost::bind(&TestProcess::slotReceivedData, this) ); | |
181 | } // eo Testprocess(const std::string&, const std::vector<std::string>&) | |
7e586023 | 182 | |
cd9ddaee RP |
183 | TestProcess( |
184 | const std::string& path, | |
185 | const std::string& arg1 ) | |
186 | : ProcessImplementation( | |
187 | path, | |
188 | TransientPushBackFiller< std::string,std::vector >()(arg1) | |
189 | ) | |
190 | { | |
191 | m_signal_read.connect( boost::bind(&TestProcess::slotReceivedData, this) ); | |
192 | } // eo Testprocess(const std::string&, const std::vector<std::string>&) | |
7e586023 | 193 | |
cd9ddaee RP |
194 | TestProcess( |
195 | const std::string& path, | |
196 | const std::string& arg1, const std::string& arg2 ) | |
197 | : ProcessImplementation( | |
198 | path, | |
199 | TransientPushBackFiller< std::string, std::vector >()(arg1)(arg2) | |
200 | ) | |
201 | { | |
202 | m_signal_read.connect( boost::bind(&TestProcess::slotReceivedData, this) ); | |
203 | } // eo Testprocess(const std::string&, const std::vector<std::string>&) | |
204 | ||
205 | ||
206 | ||
207 | pid_t pid() { return m_pid; } | |
208 | ||
209 | bool kill( Signal signal) { return ProcessImplementation::kill(signal); } | |
210 | ||
211 | protected: | |
7e586023 | 212 | |
cd9ddaee RP |
213 | void slotReceivedData() |
214 | { | |
215 | receiveData(m_input_buffer); | |
216 | m_input_buffer.clear(); | |
217 | } // eo slotReceivedData() | |
7e586023 | 218 | |
cd9ddaee RP |
219 | }; // eo class TestProcess |
220 | ||
221 | ||
222 | ||
223 | class TestUnixIOSocket | |
224 | : public UnixIOSocket | |
225 | , public ReceivedData | |
226 | { | |
227 | public: | |
7e586023 | 228 | |
cd9ddaee RP |
229 | TestUnixIOSocket() |
230 | : UnixIOSocket() | |
231 | { | |
232 | m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) ); | |
233 | } // eo TestUnixIOSocket() | |
7e586023 RP |
234 | |
235 | ||
cd9ddaee | 236 | TestUnixIOSocket( |
6ac1fb46 | 237 | int fd, const std::string& path |
cd9ddaee | 238 | ) |
6ac1fb46 | 239 | : UnixIOSocket(fd, path) |
cd9ddaee RP |
240 | { |
241 | m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) ); | |
242 | } // eo TestUnixIOSocket() | |
7e586023 RP |
243 | |
244 | ||
cd9ddaee RP |
245 | void sendData(const std::string& data) |
246 | { | |
247 | lowSend(data); | |
248 | } // eo sendData(const std::string&) | |
7e586023 | 249 | |
cd9ddaee | 250 | protected: |
7e586023 | 251 | |
cd9ddaee RP |
252 | void slotReceivedData() |
253 | { | |
254 | receiveData(m_input_buffer); | |
255 | m_input_buffer.clear(); | |
256 | } // eo slotReceivedData() | |
7e586023 | 257 | |
cd9ddaee RP |
258 | }; // eo class TestUnixIOSocket |
259 | ||
260 | typedef boost::shared_ptr< TestUnixIOSocket > TestUnixIOSocketPtr; | |
261 | ||
262 | ||
263 | class UnixIOSocketHolder | |
264 | : public std::vector< UnixIOSocketPtr > | |
265 | { | |
266 | public: | |
7e586023 | 267 | |
cd9ddaee RP |
268 | void operator()(UnixIOSocketPtr ptr) |
269 | { | |
270 | push_back(ptr); | |
271 | } | |
7e586023 | 272 | |
cd9ddaee RP |
273 | void storeBase (IOImplementationPtr ptr) |
274 | { | |
275 | push_back(boost::dynamic_pointer_cast< UnixIOSocket >(ptr) ); | |
276 | } | |
7e586023 | 277 | |
cd9ddaee RP |
278 | void store (UnixIOSocketPtr ptr) |
279 | { | |
280 | push_back(ptr); | |
281 | } | |
7e586023 | 282 | |
cd9ddaee RP |
283 | TestUnixIOSocketPtr get(int idx) |
284 | { | |
285 | return boost::dynamic_pointer_cast< | |
286 | TestUnixIOSocket | |
287 | >( (*this)[idx] ); | |
288 | } | |
289 | }; // eo class UnixIOSocketHolder | |
290 | ||
291 | ||
292 | /// global random generator (from boost lib). | |
293 | boost::mt19937 g_random_gen; | |
294 | ||
295 | ||
296 | /** | |
297 | * generates a string with random characters from a given ASCII subset. | |
298 | * @param len the desired length of the output string | |
299 | * @return a random string of length @a len | |
300 | */ | |
301 | std::string makeRandomAsciiString(std::string::size_type len) | |
302 | { | |
303 | static std::string chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz=+-*/%(){}<>.,:;\\"); | |
304 | std::string s; | |
7e586023 | 305 | |
cd9ddaee RP |
306 | boost::uniform_int<> discreter(0, chars.size()-1); |
307 | boost::variate_generator<boost::mt19937&, boost::uniform_int<> > idxgen(g_random_gen, discreter); | |
7e586023 | 308 | |
cd9ddaee | 309 | for(; len-->0;) s+= chars.at( idxgen() ); |
7e586023 | 310 | |
cd9ddaee RP |
311 | return s; |
312 | } // eo makeRandomAsciiString | |
313 | ||
314 | ||
315 | } // eo namespace <anonymous> | |
316 | ||
317 | ||
436fb144 | 318 | class SimpleioBasicsFixture |
cd9ddaee | 319 | { |
436fb144 TJ |
320 | protected: |
321 | Backend *backend; | |
322 | std::set<std::string> used_check_files; | |
7e586023 | 323 | |
436fb144 TJ |
324 | template<class Callable> |
325 | bool backendLoopUntil( Callable condition, int maxLoops=100 ) | |
326 | { | |
327 | for (int i=std::max(maxLoops,1); i-->0 && ! condition();) | |
cd9ddaee | 328 | { |
436fb144 TJ |
329 | backend->doOneStep(10); |
330 | } | |
331 | return condition(); | |
332 | } // eo backendLoopUntil | |
7e586023 RP |
333 | |
334 | ||
436fb144 TJ |
335 | bool backendStep(int msTimeout= 10, int count=1) |
336 | { | |
337 | bool res= true; | |
338 | for(;count-->0 && res;) | |
cd9ddaee | 339 | { |
436fb144 TJ |
340 | res= backend->doOneStep(msTimeout); |
341 | } | |
342 | return res; | |
343 | } // eo backendStep | |
7e586023 RP |
344 | |
345 | ||
436fb144 TJ |
346 | std::string getCheckFilepath(std::string tag) |
347 | { | |
348 | std::string result; | |
349 | result= "__unittest__" + tag + ".dat"; | |
350 | used_check_files.insert(result); | |
351 | return result; | |
352 | } // eo get_check_file_path | |
7e586023 RP |
353 | |
354 | ||
436fb144 TJ |
355 | void removeCheckFiles() |
356 | { | |
357 | for(std::set<std::string>::iterator it= used_check_files.begin(); | |
358 | it != used_check_files.end(); | |
359 | ++it) | |
cd9ddaee | 360 | { |
436fb144 TJ |
361 | std::string filepath(*it); |
362 | if (Utils::FileStat(filepath)) | |
cd9ddaee | 363 | { |
436fb144 | 364 | Utils::unlink(filepath); |
cd9ddaee | 365 | } |
436fb144 TJ |
366 | } |
367 | used_check_files.clear(); | |
368 | } // eo removeCheckFiles | |
7e586023 | 369 | |
436fb144 TJ |
370 | public: |
371 | SimpleioBasicsFixture() | |
372 | { | |
373 | backend = Backend::getBackend(); | |
374 | installChildHandler(); | |
375 | used_check_files.clear(); | |
376 | } | |
7e586023 | 377 | |
436fb144 TJ |
378 | ~SimpleioBasicsFixture() |
379 | { | |
380 | restoreChildHandler(); | |
381 | removeCheckFiles(); | |
382 | } | |
383 | }; | |
7e586023 | 384 | |
436fb144 | 385 | BOOST_FIXTURE_TEST_SUITE(TestSimpleioBasics, SimpleioBasicsFixture) |
7e586023 | 386 | |
436fb144 TJ |
387 | BOOST_AUTO_TEST_CASE(EmptyBackendStepCall) |
388 | { | |
389 | BOOST_REQUIRE( backend ); | |
7e586023 | 390 | |
436fb144 TJ |
391 | // a backend call without active objects should return false: |
392 | bool result = backend->doOneStep(0); | |
7e586023 | 393 | |
436fb144 TJ |
394 | BOOST_CHECK_EQUAL( false, result ); |
395 | } // eo EmptyBackendStepCall | |
7e586023 | 396 | |
7e586023 | 397 | |
7e586023 | 398 | |
436fb144 TJ |
399 | BOOST_AUTO_TEST_CASE(NonEmptyBackendStepCall) |
400 | { | |
401 | BOOST_REQUIRE(backend); | |
7e586023 | 402 | |
436fb144 TJ |
403 | { |
404 | TestTimer timer; | |
405 | timer.setDelta(10); | |
406 | // with an active object, a step should return true: | |
407 | bool result = backend->doOneStep(0); | |
408 | BOOST_CHECK_EQUAL( true, result ); | |
409 | // the timer should not be executed: | |
410 | BOOST_CHECK_EQUAL( 0u, timer.m_counter ); | |
411 | } | |
412 | // now it should return false: | |
413 | bool result = backend->doOneStep(0); | |
414 | BOOST_CHECK_EQUAL( false, result ); | |
415 | } // eo NonEmptyBackendStepCall | |
7e586023 | 416 | |
cd9ddaee | 417 | |
7e586023 | 418 | |
436fb144 TJ |
419 | /** |
420 | * check for timer to execute immediatly. | |
421 | */ | |
422 | BOOST_AUTO_TEST_CASE(SingleTimerShot) | |
423 | { | |
424 | BOOST_REQUIRE(backend); | |
7e586023 | 425 | |
436fb144 TJ |
426 | TestTimer timer; |
427 | timer.setDelta(0); // shot now! | |
7e586023 | 428 | |
436fb144 | 429 | bool result = backend->doOneStep(10); |
7e586023 | 430 | |
436fb144 TJ |
431 | BOOST_CHECK_EQUAL( true, result ); |
432 | // the timer should be executed once: | |
433 | BOOST_CHECK_EQUAL( 1u, timer.m_counter ); | |
7e586023 | 434 | |
436fb144 | 435 | result = backend->doOneStep(0); |
7e586023 | 436 | |
436fb144 TJ |
437 | BOOST_CHECK_EQUAL( false, result ); |
438 | // the timer should not be executed again: | |
439 | BOOST_CHECK_EQUAL( 1u, timer.m_counter ); | |
7e586023 | 440 | |
436fb144 | 441 | } // eo SingleTimerShot() |
7e586023 | 442 | |
7e586023 | 443 | |
7e586023 | 444 | |
436fb144 TJ |
445 | /** |
446 | * tests a simple timer class to be executed with a timeout. | |
447 | */ | |
448 | BOOST_AUTO_TEST_CASE(SimpleTimerShot) | |
449 | { | |
450 | bool res; | |
451 | BOOST_REQUIRE(backend); | |
7e586023 | 452 | |
436fb144 TJ |
453 | SimpleTimer timer1; |
454 | Counter counter1; | |
455 | timer1.addAction( boost::bind(&Counter::advance,&counter1) ); | |
456 | BOOST_CHECK_EQUAL(false, timer1.active()); | |
7e586023 | 457 | |
436fb144 TJ |
458 | timer1.startTimerMS( 100 ); |
459 | BOOST_CHECK_EQUAL(true, timer1.active()); | |
7e586023 | 460 | |
436fb144 TJ |
461 | res=backend->doOneStep( 1000 ); |
462 | BOOST_CHECK_EQUAL( true, res ); | |
7e586023 | 463 | |
436fb144 TJ |
464 | BOOST_CHECK_EQUAL( 1, counter1.value ); |
465 | } // eo SimpleTimerShot | |
7e586023 | 466 | |
7e586023 | 467 | |
7e586023 | 468 | |
436fb144 TJ |
469 | /** |
470 | * tests 3 timers; after the first was active, disable another and check if the remaining one fires. | |
471 | */ | |
472 | BOOST_AUTO_TEST_CASE(SimpleTimerShot2) | |
473 | { | |
474 | bool res; | |
475 | BOOST_REQUIRE(backend); | |
7e586023 | 476 | |
436fb144 TJ |
477 | SimpleTimer timer1, timer2, timer3; |
478 | Counter counter1, counter2, counter3; | |
479 | timer1.addAction( boost::bind(&Counter::advance,&counter1) ); | |
480 | timer2.addAction( boost::bind(&Counter::advance,&counter2) ); | |
481 | timer3.addAction( boost::bind(&Counter::advance,&counter3) ); | |
482 | BOOST_CHECK_EQUAL(false, timer1.active()); | |
483 | BOOST_CHECK_EQUAL(false, timer2.active()); | |
484 | BOOST_CHECK_EQUAL(false, timer3.active()); | |
7e586023 | 485 | |
436fb144 TJ |
486 | timer1.startTimerMS( 100 ); |
487 | timer2.startTimerMS( 500 ); | |
488 | timer3.startTimerMS( 400 ); | |
489 | BOOST_CHECK_EQUAL(true, timer1.active()); | |
490 | BOOST_CHECK_EQUAL(true, timer2.active()); | |
491 | BOOST_CHECK_EQUAL(true, timer3.active()); | |
7e586023 | 492 | |
436fb144 TJ |
493 | res=backend->doOneStep( 1000 ); |
494 | BOOST_CHECK_EQUAL( true, res ); | |
7e586023 | 495 | |
436fb144 TJ |
496 | BOOST_CHECK_EQUAL(false, timer1.active()); |
497 | BOOST_CHECK_EQUAL(true, timer2.active()); | |
498 | BOOST_CHECK_EQUAL(true, timer3.active()); | |
7e586023 | 499 | |
436fb144 TJ |
500 | BOOST_CHECK_EQUAL( 1, counter1.value ); |
501 | BOOST_CHECK_EQUAL( 0, counter2.value ); | |
502 | BOOST_CHECK_EQUAL( 0, counter3.value ); | |
7e586023 | 503 | |
436fb144 TJ |
504 | // now stop the next timer: |
505 | timer3.stopTimer(); | |
506 | BOOST_CHECK_EQUAL(false, timer3.active()); | |
7e586023 | 507 | |
436fb144 TJ |
508 | res=backend->doOneStep( 1000 ); |
509 | BOOST_CHECK_EQUAL( true, res ); | |
7e586023 | 510 | |
436fb144 TJ |
511 | BOOST_CHECK_EQUAL( 1, counter1.value ); |
512 | BOOST_CHECK_EQUAL( 1, counter2.value ); | |
513 | BOOST_CHECK_EQUAL( 0, counter3.value ); | |
514 | } // eo SimpleTimerShot2 | |
7e586023 | 515 | |
7e586023 | 516 | |
7e586023 RP |
517 | |
518 | ||
436fb144 TJ |
519 | /* |
520 | ** I/O tests: | |
521 | */ | |
7e586023 | 522 | |
436fb144 TJ |
523 | BOOST_AUTO_TEST_CASE(EmptyWantTest) |
524 | { | |
525 | IOImplementation io; | |
7e586023 | 526 | |
436fb144 TJ |
527 | BOOST_CHECK_EQUAL(false, io.wantRead() ); |
528 | BOOST_CHECK_EQUAL(false, io.wantWrite() ); | |
529 | } // eo EmptyWantTest | |
7e586023 | 530 | |
7e586023 | 531 | |
436fb144 TJ |
532 | /** |
533 | * a simple pipe (and io) test. | |
534 | * | |
535 | * This test basically tests the io framework. | |
536 | * It opens two connected pipes and sends a test string in each direction. | |
537 | * It tests the following functionalities of the base classes: | |
538 | * - set write marks in backend step (enabling direct send of data) | |
539 | * - low send data | |
540 | * - construct and interpret poll() data structures | |
541 | * - receive data | |
542 | * - signal chains for received data | |
543 | * - eof detection | |
544 | * . | |
545 | * | |
546 | */ | |
547 | BOOST_AUTO_TEST_CASE(SimplePipeTest) | |
548 | { | |
549 | static const std::string test_string("a test string"); | |
550 | static const std::string test_string2("only another short test string"); | |
7e586023 | 551 | |
436fb144 | 552 | BOOST_REQUIRE(backend); |
7e586023 | 553 | |
436fb144 | 554 | TestPipe pipe1, pipe2; |
7e586023 | 555 | |
436fb144 | 556 | bool res= pipe1.makePipe(pipe2); |
7e586023 | 557 | |
436fb144 TJ |
558 | BOOST_CHECK_EQUAL(true, res); |
559 | BOOST_CHECK_EQUAL(true, pipe1.opened()); | |
560 | BOOST_CHECK_EQUAL(true, pipe2.opened()); | |
7e586023 | 561 | |
436fb144 TJ |
562 | res= backend->doOneStep(0); |
563 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 564 | |
436fb144 | 565 | pipe1.sendString(test_string); |
7e586023 | 566 | |
436fb144 TJ |
567 | res= backend->doOneStep(0); |
568 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 569 | |
436fb144 | 570 | BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string ); |
7e586023 | 571 | |
436fb144 | 572 | pipe2.sendString(test_string2); |
7e586023 | 573 | |
436fb144 TJ |
574 | res= backend->doOneStep(0); |
575 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 576 | |
436fb144 | 577 | BOOST_CHECK_EQUAL( test_string2, pipe1.m_received_string ); |
7e586023 | 578 | |
436fb144 TJ |
579 | pipe1.close(); |
580 | BOOST_CHECK_EQUAL(false, pipe1.opened()); | |
7e586023 | 581 | |
436fb144 TJ |
582 | res= backend->doOneStep(0); |
583 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 584 | |
436fb144 TJ |
585 | BOOST_CHECK_EQUAL(true, pipe2.eof()); |
586 | } // eo SimplePipeTest | |
7e586023 RP |
587 | |
588 | ||
7e586023 | 589 | |
436fb144 TJ |
590 | /** |
591 | * sends a larger data chunk through a pipe. | |
592 | * This tests if sending and receiving data in (smaller internal) chunks works. | |
593 | */ | |
594 | BOOST_AUTO_TEST_CASE(SimplePipePump) | |
595 | { | |
596 | BOOST_REQUIRE(backend); | |
7e586023 | 597 | |
436fb144 | 598 | TestPipe pipe1, pipe2; |
7e586023 | 599 | |
436fb144 | 600 | bool res= pipe1.makePipe(pipe2); |
7e586023 | 601 | |
436fb144 TJ |
602 | BOOST_CHECK_EQUAL(true, res); |
603 | BOOST_CHECK_EQUAL(true, pipe1.opened()); | |
604 | BOOST_CHECK_EQUAL(true, pipe2.opened()); | |
7e586023 | 605 | |
436fb144 TJ |
606 | res= backend->doOneStep(0); |
607 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 608 | |
436fb144 | 609 | std::string test_string= makeRandomAsciiString(256*1024); |
7e586023 | 610 | |
436fb144 | 611 | pipe1.sendString(test_string); |
7e586023 | 612 | |
436fb144 TJ |
613 | res= backend->doOneStep(0); |
614 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 615 | |
436fb144 TJ |
616 | // do some backend cycles to empty the pipe: |
617 | for (int i=64; i-->0 && res && !pipe1.empty(); ) | |
618 | { | |
619 | res= backend->doOneStep(100); | |
620 | }; | |
7e586023 | 621 | |
436fb144 TJ |
622 | pipe1.close(); |
623 | BOOST_CHECK_EQUAL(false, pipe1.opened()); | |
7e586023 | 624 | |
436fb144 TJ |
625 | // now read the remaining data until we recognize EOF: |
626 | for (int i=64; i-->0 && res && !pipe2.eof();) | |
627 | { | |
628 | res= backend->doOneStep(100); | |
629 | } | |
7e586023 | 630 | |
436fb144 TJ |
631 | BOOST_CHECK_EQUAL( test_string.size(), pipe2.m_received_string.size() ); |
632 | BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string ); | |
7e586023 | 633 | |
436fb144 TJ |
634 | BOOST_CHECK_EQUAL(true, pipe2.eof()); |
635 | } // eo SimplePipePump | |
7e586023 RP |
636 | |
637 | ||
7e586023 | 638 | |
436fb144 TJ |
639 | /** |
640 | * fork a subprocess (/bin/true) and test exit code. | |
641 | */ | |
642 | BOOST_AUTO_TEST_CASE(SimpleProcessTestBinTrue) | |
643 | { | |
644 | bool res; | |
645 | BOOST_REQUIRE(backend); | |
7e586023 | 646 | |
436fb144 | 647 | TestProcess proc("/bin/true"); |
7e586023 | 648 | |
436fb144 TJ |
649 | res= proc.startProcess(); |
650 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 651 | |
436fb144 TJ |
652 | res= backend->doOneStep(200); |
653 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 654 | |
436fb144 TJ |
655 | for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;) |
656 | { | |
657 | backend->doOneStep(15); | |
658 | } | |
7e586023 | 659 | |
436fb144 TJ |
660 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
661 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
662 | BOOST_CHECK_EQUAL( 0, proc.exitCode() ); | |
663 | } // eo SimpleProcessTestBinTrue | |
7e586023 | 664 | |
7e586023 | 665 | |
436fb144 TJ |
666 | /** |
667 | * fork a subprocess (/bin/false) and test exit code. | |
668 | */ | |
669 | BOOST_AUTO_TEST_CASE(SimpleProcessTestBinFalse) | |
670 | { | |
671 | bool res; | |
672 | BOOST_REQUIRE(backend); | |
7e586023 | 673 | |
436fb144 | 674 | TestProcess proc("/bin/false"); |
7e586023 | 675 | |
436fb144 TJ |
676 | res= proc.startProcess(); |
677 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 678 | |
436fb144 TJ |
679 | res= backend->doOneStep(200); |
680 | BOOST_CHECK_EQUAL(true, res); | |
681 | for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;) | |
682 | { | |
683 | backend->doOneStep(15); | |
684 | } | |
7e586023 | 685 | |
436fb144 TJ |
686 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
687 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
688 | BOOST_CHECK_EQUAL( 1, proc.exitCode() ); | |
689 | DOUT("leave SimpleProcessTestBinFalse"); | |
690 | } // eo SimpleProcessTestBinFalse | |
7e586023 | 691 | |
7e586023 | 692 | |
436fb144 TJ |
693 | /** |
694 | * fork an echo subprocess and read back the output. | |
695 | */ | |
696 | BOOST_AUTO_TEST_CASE(SimpleProcessTestEcho) | |
697 | { | |
698 | DOUT("enter SimpleProcessTestEcho"); | |
699 | bool res; | |
700 | BOOST_REQUIRE(backend); | |
7e586023 | 701 | |
436fb144 TJ |
702 | TestProcess proc( |
703 | "/bin/echo", | |
704 | TransientPushBackFiller<std::string, std::vector >()("Eine")("Zeichenkette") | |
705 | ); | |
7e586023 | 706 | |
436fb144 TJ |
707 | res= proc.startProcess(); |
708 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 709 | |
436fb144 TJ |
710 | res= backend->doOneStep(200); |
711 | BOOST_CHECK_EQUAL(true, res); | |
712 | for(int i=20; i-->0 && (proc.processState()!= ProcessState::stopped || !proc.eof());) | |
713 | { | |
714 | backend->doOneStep(10); | |
715 | } | |
7e586023 | 716 | |
436fb144 TJ |
717 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
718 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
719 | BOOST_CHECK_EQUAL( 0, proc.exitCode() ); | |
720 | BOOST_CHECK_EQUAL( std::string("Eine Zeichenkette\n"), proc.m_received_string); | |
721 | } // eo SimpleProcessTestEcho | |
7e586023 RP |
722 | |
723 | ||
cd9ddaee | 724 | |
436fb144 TJ |
725 | /** |
726 | * fork a bash subprocess, echo something on stderr and read back the output. | |
727 | */ | |
728 | BOOST_AUTO_TEST_CASE(SimpleProcessTestStderr) | |
729 | { | |
730 | bool res; | |
731 | BOOST_REQUIRE(backend); | |
732 | ||
733 | TestIO my_stderr; | |
734 | ||
735 | TestProcess proc( | |
736 | "/bin/bash", | |
737 | TransientPushBackFiller<std::string, std::vector >() | |
738 | ("-c") | |
739 | ("echo Eine Zeichenkette >&2") | |
740 | ); | |
741 | ||
742 | // start with a seperate io object for stderr. | |
743 | DOUT("## start process"); | |
744 | res= proc.startProcess( &my_stderr ); | |
745 | BOOST_CHECK_EQUAL(true, res); | |
746 | BOOST_CHECK_EQUAL(true, my_stderr.opened()); | |
747 | ||
748 | DOUT("## do a backend step"); | |
749 | res= backend->doOneStep(200); | |
750 | BOOST_CHECK_EQUAL(true, res); | |
751 | // wait until process stopped and both io's signal EOF (or until the loop ends ;-) ) | |
752 | DOUT("## enter loop"); | |
753 | for(int i=17; i-->0 && (proc.processState()!= ProcessState::stopped || !proc.eof() || !my_stderr.eof());) | |
754 | { | |
755 | DOUT("## round i=" << i); | |
756 | backend->doOneStep(10); | |
757 | } | |
758 | DOUT("## loop left"); | |
7e586023 | 759 | |
436fb144 TJ |
760 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
761 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
762 | BOOST_CHECK_EQUAL( true, my_stderr.eof() ); | |
763 | BOOST_CHECK_EQUAL( 0, proc.exitCode() ); | |
764 | BOOST_CHECK_EQUAL( std::string("Eine Zeichenkette\n"), my_stderr.m_received_string); | |
765 | DOUT("leave Test SimpleProcessTestStderr"); | |
766 | } // eo SimpleProcessTestStderr | |
7e586023 RP |
767 | |
768 | ||
7e586023 | 769 | |
436fb144 TJ |
770 | /** |
771 | * checks termination of process by signal and if the signal is returned. | |
772 | */ | |
773 | BOOST_AUTO_TEST_CASE(SignaledProcessTermination) | |
774 | { | |
775 | bool res; | |
776 | BOOST_REQUIRE(backend); | |
7e586023 | 777 | |
436fb144 TJ |
778 | TestProcess proc("/bin/sleep","2"); |
779 | res= proc.startProcess(); | |
780 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 781 | |
436fb144 TJ |
782 | res= backend->doOneStep(10); |
783 | BOOST_CHECK_EQUAL(true, res); | |
784 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::running), proc.processState() ); | |
7e586023 | 785 | |
436fb144 | 786 | res= backend->doOneStep(50); |
7e586023 | 787 | |
436fb144 TJ |
788 | // now send the process an USR1 (which terminates the process) |
789 | res=proc.kill( Signal::USR1 ); | |
790 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 791 | |
436fb144 TJ |
792 | // give the backend a chance to process the termination event: |
793 | for(int i=30; i-->0 && proc.processState()!=ProcessState::stopped;) backend->doOneStep(10); | |
7e586023 | 794 | |
436fb144 TJ |
795 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
796 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
797 | BOOST_CHECK_EQUAL( Signal::USR1 , proc.exitCode()>>8 ); | |
798 | } // eo SignaledProcessTermination | |
7e586023 RP |
799 | |
800 | ||
7e586023 | 801 | |
436fb144 TJ |
802 | BOOST_AUTO_TEST_CASE(CallOut1) |
803 | { | |
804 | Counter count; | |
7e586023 | 805 | |
436fb144 TJ |
806 | callOut( boost::bind(&Counter::advance, &count), 1 ); |
807 | backend->doOneStep( 10 ); | |
7e586023 | 808 | |
436fb144 TJ |
809 | BOOST_CHECK_EQUAL( 0, count.value ); |
810 | backend->doOneStep( 1100 ); | |
7e586023 | 811 | |
436fb144 TJ |
812 | BOOST_CHECK_EQUAL( 1, count.value ); |
813 | } // eo CallOut1() | |
7e586023 RP |
814 | |
815 | ||
7e586023 | 816 | |
436fb144 TJ |
817 | BOOST_AUTO_TEST_CASE(CallOut2) |
818 | { | |
819 | Counter count; | |
7e586023 | 820 | |
436fb144 TJ |
821 | callOut( boost::bind(&Counter::advance, &count), 0.5 ); |
822 | backend->doOneStep( 10 ); | |
7e586023 | 823 | |
436fb144 TJ |
824 | BOOST_CHECK_EQUAL( 0, count.value ); |
825 | backend->doOneStep( 800 ); | |
7e586023 | 826 | |
436fb144 TJ |
827 | BOOST_CHECK_EQUAL( 1, count.value ); |
828 | } // eo CallOut2() | |
7e586023 RP |
829 | |
830 | ||
7e586023 | 831 | |
436fb144 TJ |
832 | BOOST_AUTO_TEST_CASE(RemoveCallOut1) |
833 | { | |
834 | Counter count; | |
7e586023 | 835 | |
436fb144 TJ |
836 | CallOutId id= callOut( boost::bind(&Counter::advance, &count), 1 ); |
837 | backend->doOneStep( 10 ); | |
7e586023 | 838 | |
436fb144 TJ |
839 | BOOST_CHECK_EQUAL( 0, count.value ); |
840 | bool res1 = removeCallOut(id); | |
841 | bool res2 = removeCallOut(id); | |
7e586023 | 842 | |
436fb144 TJ |
843 | BOOST_CHECK_EQUAL( true, res1 ); |
844 | BOOST_CHECK_EQUAL( false, res2 ); | |
7e586023 | 845 | |
436fb144 | 846 | backend->doOneStep( 1100 ); |
7e586023 | 847 | |
436fb144 TJ |
848 | BOOST_CHECK_EQUAL( 0, count.value ); |
849 | } // eo RemoveCallOut1() | |
7e586023 RP |
850 | |
851 | ||
7e586023 | 852 | |
436fb144 TJ |
853 | BOOST_AUTO_TEST_CASE(FrozenCall_Thaw) |
854 | { | |
855 | Counter count; | |
7e586023 | 856 | |
436fb144 TJ |
857 | CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 ); |
858 | backend->doOneStep( 10 ); | |
7e586023 | 859 | |
436fb144 TJ |
860 | BOOST_CHECK_EQUAL( 0, count.value ); |
861 | id.thaw(); | |
7e586023 | 862 | |
436fb144 | 863 | backend->doOneStep( 1100 ); |
7e586023 | 864 | |
436fb144 TJ |
865 | BOOST_CHECK_EQUAL( 1, count.value ); |
866 | } // eo FrozenCall_Thaw() | |
7e586023 RP |
867 | |
868 | ||
7e586023 | 869 | |
436fb144 TJ |
870 | BOOST_AUTO_TEST_CASE(FrozenCall_Decay) |
871 | { | |
872 | Counter count; | |
7e586023 | 873 | |
436fb144 TJ |
874 | CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 ); |
875 | backend->doOneStep( 10 ); | |
7e586023 | 876 | |
436fb144 TJ |
877 | BOOST_CHECK_EQUAL( 0, count.value ); |
878 | BOOST_CHECK_EQUAL( true, id.active() ); | |
879 | backend->doOneStep( 1100 ); | |
7e586023 | 880 | |
436fb144 TJ |
881 | BOOST_CHECK_EQUAL( 0, count.value ); |
882 | BOOST_CHECK_EQUAL( false, id.active() ); | |
883 | } // eo FrozenCall_Decay() | |
7e586023 RP |
884 | |
885 | ||
7e586023 | 886 | |
436fb144 TJ |
887 | BOOST_AUTO_TEST_CASE(UnixSockets_ClientServer) |
888 | { | |
889 | std::string path= getCheckFilepath("UDS_CS"); | |
7e586023 | 890 | |
436fb144 TJ |
891 | UnixIOSocketHolder server_holder; |
892 | UnixServerSocket< TestUnixIOSocket > server_port; | |
893 | UnixIOSocketPtr server; | |
894 | TestUnixIOSocket client0; | |
895 | TestUnixIOSocket client1; | |
7e586023 | 896 | |
436fb144 TJ |
897 | bool res1 = server_port.open(path, 0600); |
898 | BOOST_CHECK_EQUAL( true, res1 ); | |
7e586023 | 899 | |
436fb144 TJ |
900 | { |
901 | AsyncIo::Utils::FileStat stat(path,false); | |
902 | BOOST_REQUIRE( stat.is_socket() ); | |
903 | BOOST_CHECK_EQUAL( 0600u, (stat.mode() & 0777)); | |
904 | } | |
7e586023 | 905 | |
436fb144 TJ |
906 | server_port.setNewConnectionCallback( |
907 | boost::bind( &UnixIOSocketHolder::store, &server_holder, _1) | |
908 | ); | |
909 | ||
910 | // open a first client | |
911 | bool res2= client0.open(path); | |
912 | BOOST_CHECK_EQUAL( true, res2 ); | |
913 | ||
914 | BOOST_CHECK_EQUAL(0u, server_holder.size() ); | |
915 | backendStep(5,1); | |
916 | BOOST_CHECK_EQUAL(1u, server_holder.size() ); | |
917 | BOOST_REQUIRE( server_holder.get(0).get() ); | |
918 | ||
919 | client0.sendData("a simple test string."); | |
920 | backendStep(3,2); | |
921 | ||
922 | BOOST_CHECK_EQUAL( | |
923 | std::string("a simple test string."), | |
924 | server_holder.get(0)->m_received_string | |
925 | ); | |
926 | server_holder.get(0)->sendData("reply 1"); | |
927 | backendStep(3,2); | |
928 | BOOST_CHECK_EQUAL( std::string("reply 1"), client0.m_received_string ); | |
929 | ||
930 | // open a second client | |
931 | res2= client1.open(path); | |
932 | BOOST_CHECK_EQUAL( true, res2 ); | |
933 | backendStep(5,1); | |
934 | BOOST_CHECK_EQUAL(2u, server_holder.size() ); | |
935 | BOOST_REQUIRE( server_holder.get(1).get() ); | |
936 | ||
937 | server_holder.get(1)->sendData("::reply 2"); | |
938 | backendStep(3,2); | |
939 | BOOST_CHECK_EQUAL( std::string("::reply 2"), client1.m_received_string ); | |
940 | ||
941 | client1.sendData("another simple test string. 124"); | |
942 | backendStep(3,2); | |
943 | ||
944 | BOOST_CHECK_EQUAL( | |
945 | std::string("another simple test string. 124"), | |
946 | server_holder.get(1)->m_received_string | |
947 | ); | |
948 | ||
949 | // close first client | |
950 | client0.close(); | |
951 | BOOST_CHECK_EQUAL( false, server_holder.get(0)->eof() ); | |
952 | backendStep(3,2); | |
953 | BOOST_CHECK_EQUAL( true, server_holder.get(0)->eof() ); | |
954 | server_holder.get(0)->close(); | |
955 | ||
956 | // close second connection from server side | |
957 | BOOST_CHECK_EQUAL( false, client1.eof() ); | |
958 | server_holder.get(1)->close(); | |
959 | backendStep(3,2); | |
960 | BOOST_CHECK_EQUAL( true, client1.eof() ); | |
961 | client1.close(); | |
962 | } // eo UnixSockets_ClientServer() | |
7e586023 | 963 | |
cd9ddaee | 964 | |
436fb144 TJ |
965 | /* |
966 | BOOST_AUTO_TEST_CASE(Dummy) | |
967 | { | |
968 | using namespace std; | |
969 | cout << endl << "Random strings:" << endl; | |
970 | for (int i=10; i-->0;) | |
971 | { | |
972 | cout << " " << makeRandomAsciiString(70)<< endl; | |
973 | } | |
974 | } // eo Dummy | |
975 | */ | |
cd9ddaee | 976 | |
436fb144 | 977 | BOOST_AUTO_TEST_SUITE_END() |