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 | ||
cd9ddaee | 205 | protected: |
7e586023 | 206 | |
cd9ddaee RP |
207 | void slotReceivedData() |
208 | { | |
209 | receiveData(m_input_buffer); | |
210 | m_input_buffer.clear(); | |
211 | } // eo slotReceivedData() | |
7e586023 | 212 | |
cd9ddaee RP |
213 | }; // eo class TestProcess |
214 | ||
215 | ||
216 | ||
217 | class TestUnixIOSocket | |
218 | : public UnixIOSocket | |
219 | , public ReceivedData | |
220 | { | |
221 | public: | |
7e586023 | 222 | |
cd9ddaee RP |
223 | TestUnixIOSocket() |
224 | : UnixIOSocket() | |
225 | { | |
226 | m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) ); | |
227 | } // eo TestUnixIOSocket() | |
7e586023 RP |
228 | |
229 | ||
cd9ddaee | 230 | TestUnixIOSocket( |
6ac1fb46 | 231 | int fd, const std::string& path |
cd9ddaee | 232 | ) |
6ac1fb46 | 233 | : UnixIOSocket(fd, path) |
cd9ddaee RP |
234 | { |
235 | m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) ); | |
236 | } // eo TestUnixIOSocket() | |
7e586023 RP |
237 | |
238 | ||
cd9ddaee RP |
239 | void sendData(const std::string& data) |
240 | { | |
241 | lowSend(data); | |
242 | } // eo sendData(const std::string&) | |
7e586023 | 243 | |
cd9ddaee | 244 | protected: |
7e586023 | 245 | |
cd9ddaee RP |
246 | void slotReceivedData() |
247 | { | |
248 | receiveData(m_input_buffer); | |
249 | m_input_buffer.clear(); | |
250 | } // eo slotReceivedData() | |
7e586023 | 251 | |
cd9ddaee RP |
252 | }; // eo class TestUnixIOSocket |
253 | ||
254 | typedef boost::shared_ptr< TestUnixIOSocket > TestUnixIOSocketPtr; | |
255 | ||
256 | ||
257 | class UnixIOSocketHolder | |
258 | : public std::vector< UnixIOSocketPtr > | |
259 | { | |
260 | public: | |
7e586023 | 261 | |
cd9ddaee RP |
262 | void operator()(UnixIOSocketPtr ptr) |
263 | { | |
264 | push_back(ptr); | |
265 | } | |
7e586023 | 266 | |
cd9ddaee RP |
267 | void storeBase (IOImplementationPtr ptr) |
268 | { | |
269 | push_back(boost::dynamic_pointer_cast< UnixIOSocket >(ptr) ); | |
270 | } | |
7e586023 | 271 | |
cd9ddaee RP |
272 | void store (UnixIOSocketPtr ptr) |
273 | { | |
274 | push_back(ptr); | |
275 | } | |
7e586023 | 276 | |
cd9ddaee RP |
277 | TestUnixIOSocketPtr get(int idx) |
278 | { | |
279 | return boost::dynamic_pointer_cast< | |
280 | TestUnixIOSocket | |
281 | >( (*this)[idx] ); | |
282 | } | |
283 | }; // eo class UnixIOSocketHolder | |
284 | ||
285 | ||
286 | /// global random generator (from boost lib). | |
287 | boost::mt19937 g_random_gen; | |
288 | ||
289 | ||
290 | /** | |
291 | * generates a string with random characters from a given ASCII subset. | |
292 | * @param len the desired length of the output string | |
293 | * @return a random string of length @a len | |
294 | */ | |
295 | std::string makeRandomAsciiString(std::string::size_type len) | |
296 | { | |
297 | static std::string chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz=+-*/%(){}<>.,:;\\"); | |
298 | std::string s; | |
7e586023 | 299 | |
cd9ddaee RP |
300 | boost::uniform_int<> discreter(0, chars.size()-1); |
301 | boost::variate_generator<boost::mt19937&, boost::uniform_int<> > idxgen(g_random_gen, discreter); | |
7e586023 | 302 | |
cd9ddaee | 303 | for(; len-->0;) s+= chars.at( idxgen() ); |
7e586023 | 304 | |
cd9ddaee RP |
305 | return s; |
306 | } // eo makeRandomAsciiString | |
307 | ||
308 | ||
309 | } // eo namespace <anonymous> | |
310 | ||
311 | ||
436fb144 | 312 | class SimpleioBasicsFixture |
cd9ddaee | 313 | { |
436fb144 TJ |
314 | protected: |
315 | Backend *backend; | |
316 | std::set<std::string> used_check_files; | |
7e586023 | 317 | |
436fb144 TJ |
318 | template<class Callable> |
319 | bool backendLoopUntil( Callable condition, int maxLoops=100 ) | |
320 | { | |
321 | for (int i=std::max(maxLoops,1); i-->0 && ! condition();) | |
cd9ddaee | 322 | { |
436fb144 TJ |
323 | backend->doOneStep(10); |
324 | } | |
325 | return condition(); | |
326 | } // eo backendLoopUntil | |
7e586023 RP |
327 | |
328 | ||
436fb144 TJ |
329 | bool backendStep(int msTimeout= 10, int count=1) |
330 | { | |
331 | bool res= true; | |
332 | for(;count-->0 && res;) | |
cd9ddaee | 333 | { |
436fb144 TJ |
334 | res= backend->doOneStep(msTimeout); |
335 | } | |
336 | return res; | |
337 | } // eo backendStep | |
7e586023 RP |
338 | |
339 | ||
436fb144 TJ |
340 | std::string getCheckFilepath(std::string tag) |
341 | { | |
342 | std::string result; | |
343 | result= "__unittest__" + tag + ".dat"; | |
344 | used_check_files.insert(result); | |
345 | return result; | |
346 | } // eo get_check_file_path | |
7e586023 RP |
347 | |
348 | ||
436fb144 TJ |
349 | void removeCheckFiles() |
350 | { | |
351 | for(std::set<std::string>::iterator it= used_check_files.begin(); | |
352 | it != used_check_files.end(); | |
353 | ++it) | |
cd9ddaee | 354 | { |
436fb144 TJ |
355 | std::string filepath(*it); |
356 | if (Utils::FileStat(filepath)) | |
cd9ddaee | 357 | { |
436fb144 | 358 | Utils::unlink(filepath); |
cd9ddaee | 359 | } |
436fb144 TJ |
360 | } |
361 | used_check_files.clear(); | |
362 | } // eo removeCheckFiles | |
7e586023 | 363 | |
436fb144 TJ |
364 | public: |
365 | SimpleioBasicsFixture() | |
366 | { | |
367 | backend = Backend::getBackend(); | |
368 | installChildHandler(); | |
369 | used_check_files.clear(); | |
370 | } | |
7e586023 | 371 | |
436fb144 TJ |
372 | ~SimpleioBasicsFixture() |
373 | { | |
374 | restoreChildHandler(); | |
375 | removeCheckFiles(); | |
376 | } | |
377 | }; | |
7e586023 | 378 | |
436fb144 | 379 | BOOST_FIXTURE_TEST_SUITE(TestSimpleioBasics, SimpleioBasicsFixture) |
7e586023 | 380 | |
436fb144 TJ |
381 | BOOST_AUTO_TEST_CASE(EmptyBackendStepCall) |
382 | { | |
383 | BOOST_REQUIRE( backend ); | |
7e586023 | 384 | |
436fb144 TJ |
385 | // a backend call without active objects should return false: |
386 | bool result = backend->doOneStep(0); | |
7e586023 | 387 | |
436fb144 TJ |
388 | BOOST_CHECK_EQUAL( false, result ); |
389 | } // eo EmptyBackendStepCall | |
7e586023 | 390 | |
7e586023 | 391 | |
7e586023 | 392 | |
436fb144 TJ |
393 | BOOST_AUTO_TEST_CASE(NonEmptyBackendStepCall) |
394 | { | |
395 | BOOST_REQUIRE(backend); | |
7e586023 | 396 | |
436fb144 TJ |
397 | { |
398 | TestTimer timer; | |
399 | timer.setDelta(10); | |
400 | // with an active object, a step should return true: | |
401 | bool result = backend->doOneStep(0); | |
402 | BOOST_CHECK_EQUAL( true, result ); | |
403 | // the timer should not be executed: | |
404 | BOOST_CHECK_EQUAL( 0u, timer.m_counter ); | |
405 | } | |
406 | // now it should return false: | |
407 | bool result = backend->doOneStep(0); | |
408 | BOOST_CHECK_EQUAL( false, result ); | |
409 | } // eo NonEmptyBackendStepCall | |
7e586023 | 410 | |
cd9ddaee | 411 | |
7e586023 | 412 | |
436fb144 TJ |
413 | /** |
414 | * check for timer to execute immediatly. | |
415 | */ | |
416 | BOOST_AUTO_TEST_CASE(SingleTimerShot) | |
417 | { | |
418 | BOOST_REQUIRE(backend); | |
7e586023 | 419 | |
436fb144 TJ |
420 | TestTimer timer; |
421 | timer.setDelta(0); // shot now! | |
7e586023 | 422 | |
436fb144 | 423 | bool result = backend->doOneStep(10); |
7e586023 | 424 | |
436fb144 TJ |
425 | BOOST_CHECK_EQUAL( true, result ); |
426 | // the timer should be executed once: | |
427 | BOOST_CHECK_EQUAL( 1u, timer.m_counter ); | |
7e586023 | 428 | |
436fb144 | 429 | result = backend->doOneStep(0); |
7e586023 | 430 | |
436fb144 TJ |
431 | BOOST_CHECK_EQUAL( false, result ); |
432 | // the timer should not be executed again: | |
433 | BOOST_CHECK_EQUAL( 1u, timer.m_counter ); | |
7e586023 | 434 | |
436fb144 | 435 | } // eo SingleTimerShot() |
7e586023 | 436 | |
7e586023 | 437 | |
7e586023 | 438 | |
436fb144 TJ |
439 | /** |
440 | * tests a simple timer class to be executed with a timeout. | |
441 | */ | |
442 | BOOST_AUTO_TEST_CASE(SimpleTimerShot) | |
443 | { | |
444 | bool res; | |
445 | BOOST_REQUIRE(backend); | |
7e586023 | 446 | |
436fb144 TJ |
447 | SimpleTimer timer1; |
448 | Counter counter1; | |
449 | timer1.addAction( boost::bind(&Counter::advance,&counter1) ); | |
450 | BOOST_CHECK_EQUAL(false, timer1.active()); | |
7e586023 | 451 | |
436fb144 TJ |
452 | timer1.startTimerMS( 100 ); |
453 | BOOST_CHECK_EQUAL(true, timer1.active()); | |
7e586023 | 454 | |
436fb144 TJ |
455 | res=backend->doOneStep( 1000 ); |
456 | BOOST_CHECK_EQUAL( true, res ); | |
7e586023 | 457 | |
436fb144 TJ |
458 | BOOST_CHECK_EQUAL( 1, counter1.value ); |
459 | } // eo SimpleTimerShot | |
7e586023 | 460 | |
7e586023 | 461 | |
7e586023 | 462 | |
436fb144 TJ |
463 | /** |
464 | * tests 3 timers; after the first was active, disable another and check if the remaining one fires. | |
465 | */ | |
466 | BOOST_AUTO_TEST_CASE(SimpleTimerShot2) | |
467 | { | |
468 | bool res; | |
469 | BOOST_REQUIRE(backend); | |
7e586023 | 470 | |
436fb144 TJ |
471 | SimpleTimer timer1, timer2, timer3; |
472 | Counter counter1, counter2, counter3; | |
473 | timer1.addAction( boost::bind(&Counter::advance,&counter1) ); | |
474 | timer2.addAction( boost::bind(&Counter::advance,&counter2) ); | |
475 | timer3.addAction( boost::bind(&Counter::advance,&counter3) ); | |
476 | BOOST_CHECK_EQUAL(false, timer1.active()); | |
477 | BOOST_CHECK_EQUAL(false, timer2.active()); | |
478 | BOOST_CHECK_EQUAL(false, timer3.active()); | |
7e586023 | 479 | |
436fb144 TJ |
480 | timer1.startTimerMS( 100 ); |
481 | timer2.startTimerMS( 500 ); | |
482 | timer3.startTimerMS( 400 ); | |
483 | BOOST_CHECK_EQUAL(true, timer1.active()); | |
484 | BOOST_CHECK_EQUAL(true, timer2.active()); | |
485 | BOOST_CHECK_EQUAL(true, timer3.active()); | |
7e586023 | 486 | |
436fb144 TJ |
487 | res=backend->doOneStep( 1000 ); |
488 | BOOST_CHECK_EQUAL( true, res ); | |
7e586023 | 489 | |
436fb144 TJ |
490 | BOOST_CHECK_EQUAL(false, timer1.active()); |
491 | BOOST_CHECK_EQUAL(true, timer2.active()); | |
492 | BOOST_CHECK_EQUAL(true, timer3.active()); | |
7e586023 | 493 | |
436fb144 TJ |
494 | BOOST_CHECK_EQUAL( 1, counter1.value ); |
495 | BOOST_CHECK_EQUAL( 0, counter2.value ); | |
496 | BOOST_CHECK_EQUAL( 0, counter3.value ); | |
7e586023 | 497 | |
436fb144 TJ |
498 | // now stop the next timer: |
499 | timer3.stopTimer(); | |
500 | BOOST_CHECK_EQUAL(false, timer3.active()); | |
7e586023 | 501 | |
436fb144 TJ |
502 | res=backend->doOneStep( 1000 ); |
503 | BOOST_CHECK_EQUAL( true, res ); | |
7e586023 | 504 | |
436fb144 TJ |
505 | BOOST_CHECK_EQUAL( 1, counter1.value ); |
506 | BOOST_CHECK_EQUAL( 1, counter2.value ); | |
507 | BOOST_CHECK_EQUAL( 0, counter3.value ); | |
508 | } // eo SimpleTimerShot2 | |
7e586023 | 509 | |
7e586023 | 510 | |
7e586023 RP |
511 | |
512 | ||
436fb144 TJ |
513 | /* |
514 | ** I/O tests: | |
515 | */ | |
7e586023 | 516 | |
436fb144 TJ |
517 | BOOST_AUTO_TEST_CASE(EmptyWantTest) |
518 | { | |
519 | IOImplementation io; | |
7e586023 | 520 | |
436fb144 TJ |
521 | BOOST_CHECK_EQUAL(false, io.wantRead() ); |
522 | BOOST_CHECK_EQUAL(false, io.wantWrite() ); | |
523 | } // eo EmptyWantTest | |
7e586023 | 524 | |
7e586023 | 525 | |
436fb144 TJ |
526 | /** |
527 | * a simple pipe (and io) test. | |
528 | * | |
529 | * This test basically tests the io framework. | |
530 | * It opens two connected pipes and sends a test string in each direction. | |
531 | * It tests the following functionalities of the base classes: | |
532 | * - set write marks in backend step (enabling direct send of data) | |
533 | * - low send data | |
534 | * - construct and interpret poll() data structures | |
535 | * - receive data | |
536 | * - signal chains for received data | |
537 | * - eof detection | |
538 | * . | |
539 | * | |
540 | */ | |
541 | BOOST_AUTO_TEST_CASE(SimplePipeTest) | |
542 | { | |
543 | static const std::string test_string("a test string"); | |
544 | static const std::string test_string2("only another short test string"); | |
7e586023 | 545 | |
436fb144 | 546 | BOOST_REQUIRE(backend); |
7e586023 | 547 | |
436fb144 | 548 | TestPipe pipe1, pipe2; |
7e586023 | 549 | |
436fb144 | 550 | bool res= pipe1.makePipe(pipe2); |
7e586023 | 551 | |
436fb144 TJ |
552 | BOOST_CHECK_EQUAL(true, res); |
553 | BOOST_CHECK_EQUAL(true, pipe1.opened()); | |
554 | BOOST_CHECK_EQUAL(true, pipe2.opened()); | |
7e586023 | 555 | |
436fb144 TJ |
556 | res= backend->doOneStep(0); |
557 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 558 | |
436fb144 | 559 | pipe1.sendString(test_string); |
7e586023 | 560 | |
436fb144 TJ |
561 | res= backend->doOneStep(0); |
562 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 563 | |
436fb144 | 564 | BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string ); |
7e586023 | 565 | |
436fb144 | 566 | pipe2.sendString(test_string2); |
7e586023 | 567 | |
436fb144 TJ |
568 | res= backend->doOneStep(0); |
569 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 570 | |
436fb144 | 571 | BOOST_CHECK_EQUAL( test_string2, pipe1.m_received_string ); |
7e586023 | 572 | |
436fb144 TJ |
573 | pipe1.close(); |
574 | BOOST_CHECK_EQUAL(false, pipe1.opened()); | |
7e586023 | 575 | |
436fb144 TJ |
576 | res= backend->doOneStep(0); |
577 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 578 | |
436fb144 TJ |
579 | BOOST_CHECK_EQUAL(true, pipe2.eof()); |
580 | } // eo SimplePipeTest | |
7e586023 RP |
581 | |
582 | ||
7e586023 | 583 | |
436fb144 TJ |
584 | /** |
585 | * sends a larger data chunk through a pipe. | |
586 | * This tests if sending and receiving data in (smaller internal) chunks works. | |
587 | */ | |
588 | BOOST_AUTO_TEST_CASE(SimplePipePump) | |
589 | { | |
590 | BOOST_REQUIRE(backend); | |
7e586023 | 591 | |
436fb144 | 592 | TestPipe pipe1, pipe2; |
7e586023 | 593 | |
436fb144 | 594 | bool res= pipe1.makePipe(pipe2); |
7e586023 | 595 | |
436fb144 TJ |
596 | BOOST_CHECK_EQUAL(true, res); |
597 | BOOST_CHECK_EQUAL(true, pipe1.opened()); | |
598 | BOOST_CHECK_EQUAL(true, pipe2.opened()); | |
7e586023 | 599 | |
436fb144 TJ |
600 | res= backend->doOneStep(0); |
601 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 602 | |
436fb144 | 603 | std::string test_string= makeRandomAsciiString(256*1024); |
7e586023 | 604 | |
436fb144 | 605 | pipe1.sendString(test_string); |
7e586023 | 606 | |
436fb144 TJ |
607 | res= backend->doOneStep(0); |
608 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 609 | |
436fb144 TJ |
610 | // do some backend cycles to empty the pipe: |
611 | for (int i=64; i-->0 && res && !pipe1.empty(); ) | |
612 | { | |
613 | res= backend->doOneStep(100); | |
614 | }; | |
7e586023 | 615 | |
436fb144 TJ |
616 | pipe1.close(); |
617 | BOOST_CHECK_EQUAL(false, pipe1.opened()); | |
7e586023 | 618 | |
436fb144 TJ |
619 | // now read the remaining data until we recognize EOF: |
620 | for (int i=64; i-->0 && res && !pipe2.eof();) | |
621 | { | |
622 | res= backend->doOneStep(100); | |
623 | } | |
7e586023 | 624 | |
436fb144 TJ |
625 | BOOST_CHECK_EQUAL( test_string.size(), pipe2.m_received_string.size() ); |
626 | BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string ); | |
7e586023 | 627 | |
436fb144 TJ |
628 | BOOST_CHECK_EQUAL(true, pipe2.eof()); |
629 | } // eo SimplePipePump | |
7e586023 RP |
630 | |
631 | ||
7e586023 | 632 | |
436fb144 TJ |
633 | /** |
634 | * fork a subprocess (/bin/true) and test exit code. | |
635 | */ | |
636 | BOOST_AUTO_TEST_CASE(SimpleProcessTestBinTrue) | |
637 | { | |
638 | bool res; | |
639 | BOOST_REQUIRE(backend); | |
7e586023 | 640 | |
436fb144 | 641 | TestProcess proc("/bin/true"); |
7e586023 | 642 | |
436fb144 TJ |
643 | res= proc.startProcess(); |
644 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 645 | |
436fb144 TJ |
646 | res= backend->doOneStep(200); |
647 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 648 | |
436fb144 TJ |
649 | for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;) |
650 | { | |
651 | backend->doOneStep(15); | |
652 | } | |
7e586023 | 653 | |
436fb144 TJ |
654 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
655 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
656 | BOOST_CHECK_EQUAL( 0, proc.exitCode() ); | |
657 | } // eo SimpleProcessTestBinTrue | |
7e586023 | 658 | |
7e586023 | 659 | |
436fb144 TJ |
660 | /** |
661 | * fork a subprocess (/bin/false) and test exit code. | |
662 | */ | |
663 | BOOST_AUTO_TEST_CASE(SimpleProcessTestBinFalse) | |
664 | { | |
665 | bool res; | |
666 | BOOST_REQUIRE(backend); | |
7e586023 | 667 | |
436fb144 | 668 | TestProcess proc("/bin/false"); |
7e586023 | 669 | |
436fb144 TJ |
670 | res= proc.startProcess(); |
671 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 672 | |
436fb144 TJ |
673 | res= backend->doOneStep(200); |
674 | BOOST_CHECK_EQUAL(true, res); | |
675 | for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;) | |
676 | { | |
677 | backend->doOneStep(15); | |
678 | } | |
7e586023 | 679 | |
436fb144 TJ |
680 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
681 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
682 | BOOST_CHECK_EQUAL( 1, proc.exitCode() ); | |
683 | DOUT("leave SimpleProcessTestBinFalse"); | |
684 | } // eo SimpleProcessTestBinFalse | |
7e586023 | 685 | |
7e586023 | 686 | |
436fb144 TJ |
687 | /** |
688 | * fork an echo subprocess and read back the output. | |
689 | */ | |
690 | BOOST_AUTO_TEST_CASE(SimpleProcessTestEcho) | |
691 | { | |
692 | DOUT("enter SimpleProcessTestEcho"); | |
693 | bool res; | |
694 | BOOST_REQUIRE(backend); | |
7e586023 | 695 | |
436fb144 TJ |
696 | TestProcess proc( |
697 | "/bin/echo", | |
698 | TransientPushBackFiller<std::string, std::vector >()("Eine")("Zeichenkette") | |
699 | ); | |
7e586023 | 700 | |
436fb144 TJ |
701 | res= proc.startProcess(); |
702 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 703 | |
436fb144 TJ |
704 | res= backend->doOneStep(200); |
705 | BOOST_CHECK_EQUAL(true, res); | |
706 | for(int i=20; i-->0 && (proc.processState()!= ProcessState::stopped || !proc.eof());) | |
707 | { | |
708 | backend->doOneStep(10); | |
709 | } | |
7e586023 | 710 | |
436fb144 TJ |
711 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
712 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
713 | BOOST_CHECK_EQUAL( 0, proc.exitCode() ); | |
714 | BOOST_CHECK_EQUAL( std::string("Eine Zeichenkette\n"), proc.m_received_string); | |
715 | } // eo SimpleProcessTestEcho | |
7e586023 RP |
716 | |
717 | ||
cd9ddaee | 718 | |
436fb144 TJ |
719 | /** |
720 | * fork a bash subprocess, echo something on stderr and read back the output. | |
721 | */ | |
722 | BOOST_AUTO_TEST_CASE(SimpleProcessTestStderr) | |
723 | { | |
724 | bool res; | |
725 | BOOST_REQUIRE(backend); | |
726 | ||
727 | TestIO my_stderr; | |
728 | ||
729 | TestProcess proc( | |
730 | "/bin/bash", | |
731 | TransientPushBackFiller<std::string, std::vector >() | |
732 | ("-c") | |
733 | ("echo Eine Zeichenkette >&2") | |
734 | ); | |
735 | ||
736 | // start with a seperate io object for stderr. | |
737 | DOUT("## start process"); | |
738 | res= proc.startProcess( &my_stderr ); | |
739 | BOOST_CHECK_EQUAL(true, res); | |
740 | BOOST_CHECK_EQUAL(true, my_stderr.opened()); | |
741 | ||
742 | DOUT("## do a backend step"); | |
743 | res= backend->doOneStep(200); | |
744 | BOOST_CHECK_EQUAL(true, res); | |
745 | // wait until process stopped and both io's signal EOF (or until the loop ends ;-) ) | |
746 | DOUT("## enter loop"); | |
747 | for(int i=17; i-->0 && (proc.processState()!= ProcessState::stopped || !proc.eof() || !my_stderr.eof());) | |
748 | { | |
749 | DOUT("## round i=" << i); | |
750 | backend->doOneStep(10); | |
751 | } | |
752 | DOUT("## loop left"); | |
7e586023 | 753 | |
436fb144 TJ |
754 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
755 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
756 | BOOST_CHECK_EQUAL( true, my_stderr.eof() ); | |
757 | BOOST_CHECK_EQUAL( 0, proc.exitCode() ); | |
758 | BOOST_CHECK_EQUAL( std::string("Eine Zeichenkette\n"), my_stderr.m_received_string); | |
759 | DOUT("leave Test SimpleProcessTestStderr"); | |
760 | } // eo SimpleProcessTestStderr | |
7e586023 RP |
761 | |
762 | ||
7e586023 | 763 | |
436fb144 TJ |
764 | /** |
765 | * checks termination of process by signal and if the signal is returned. | |
766 | */ | |
767 | BOOST_AUTO_TEST_CASE(SignaledProcessTermination) | |
768 | { | |
769 | bool res; | |
770 | BOOST_REQUIRE(backend); | |
7e586023 | 771 | |
436fb144 TJ |
772 | TestProcess proc("/bin/sleep","2"); |
773 | res= proc.startProcess(); | |
774 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 775 | |
436fb144 TJ |
776 | res= backend->doOneStep(10); |
777 | BOOST_CHECK_EQUAL(true, res); | |
778 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::running), proc.processState() ); | |
7e586023 | 779 | |
436fb144 | 780 | res= backend->doOneStep(50); |
7e586023 | 781 | |
436fb144 TJ |
782 | // now send the process an USR1 (which terminates the process) |
783 | res=proc.kill( Signal::USR1 ); | |
784 | BOOST_CHECK_EQUAL(true, res); | |
7e586023 | 785 | |
436fb144 TJ |
786 | // give the backend a chance to process the termination event: |
787 | for(int i=30; i-->0 && proc.processState()!=ProcessState::stopped;) backend->doOneStep(10); | |
7e586023 | 788 | |
436fb144 TJ |
789 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); |
790 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
791 | BOOST_CHECK_EQUAL( Signal::USR1 , proc.exitCode()>>8 ); | |
792 | } // eo SignaledProcessTermination | |
7e586023 | 793 | |
b9c8a8e5 GE |
794 | /** |
795 | * fork an echo subprocess and read back the output. Directly use ProcessImplementation without helper class. | |
796 | */ | |
797 | BOOST_AUTO_TEST_CASE(DirectProcessImplementationTestEcho) | |
798 | { | |
799 | DOUT("enter SimpleProcessTestEcho"); | |
800 | bool res; | |
801 | BOOST_REQUIRE(backend); | |
802 | ||
803 | ProcessImplementation proc( | |
804 | "/bin/echo", | |
805 | TransientPushBackFiller<std::string, std::vector >()("Eine")("Zeichenkette") | |
806 | ); | |
807 | ||
808 | res= proc.startProcess(); | |
809 | BOOST_CHECK_EQUAL(true, res); | |
810 | ||
811 | res= backend->doOneStep(200); | |
812 | BOOST_CHECK_EQUAL(true, res); | |
813 | for(int i=20; i-->0 && (proc.processState()!= ProcessState::stopped || !proc.eof());) | |
814 | { | |
815 | backend->doOneStep(10); | |
816 | } | |
817 | ||
818 | BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() ); | |
819 | BOOST_CHECK_EQUAL( true, proc.eof() ); | |
820 | BOOST_CHECK_EQUAL( 0, proc.exitCode() ); | |
821 | BOOST_CHECK_EQUAL( std::string("Eine Zeichenkette\n"), proc.getInput()); | |
822 | BOOST_CHECK_EQUAL( 5, proc.shortenInput(5)); | |
823 | BOOST_CHECK_EQUAL( std::string("Zeichenkette\n"), proc.getInput()); | |
824 | BOOST_CHECK_EQUAL( true, proc.inputAvailable()); | |
825 | BOOST_CHECK_EQUAL( std::string("Zeichenkette\n"), proc.getInputClear()); | |
826 | BOOST_CHECK_EQUAL( false, proc.inputAvailable()); | |
827 | } // eo SimpleProcessTestEcho | |
7e586023 | 828 | |
7e586023 | 829 | |
436fb144 TJ |
830 | BOOST_AUTO_TEST_CASE(CallOut1) |
831 | { | |
832 | Counter count; | |
7e586023 | 833 | |
436fb144 TJ |
834 | callOut( boost::bind(&Counter::advance, &count), 1 ); |
835 | backend->doOneStep( 10 ); | |
7e586023 | 836 | |
436fb144 TJ |
837 | BOOST_CHECK_EQUAL( 0, count.value ); |
838 | backend->doOneStep( 1100 ); | |
7e586023 | 839 | |
436fb144 TJ |
840 | BOOST_CHECK_EQUAL( 1, count.value ); |
841 | } // eo CallOut1() | |
7e586023 RP |
842 | |
843 | ||
7e586023 | 844 | |
436fb144 TJ |
845 | BOOST_AUTO_TEST_CASE(CallOut2) |
846 | { | |
847 | Counter count; | |
7e586023 | 848 | |
436fb144 TJ |
849 | callOut( boost::bind(&Counter::advance, &count), 0.5 ); |
850 | backend->doOneStep( 10 ); | |
7e586023 | 851 | |
436fb144 TJ |
852 | BOOST_CHECK_EQUAL( 0, count.value ); |
853 | backend->doOneStep( 800 ); | |
7e586023 | 854 | |
436fb144 TJ |
855 | BOOST_CHECK_EQUAL( 1, count.value ); |
856 | } // eo CallOut2() | |
7e586023 RP |
857 | |
858 | ||
7e586023 | 859 | |
436fb144 TJ |
860 | BOOST_AUTO_TEST_CASE(RemoveCallOut1) |
861 | { | |
862 | Counter count; | |
7e586023 | 863 | |
436fb144 TJ |
864 | CallOutId id= callOut( boost::bind(&Counter::advance, &count), 1 ); |
865 | backend->doOneStep( 10 ); | |
7e586023 | 866 | |
436fb144 TJ |
867 | BOOST_CHECK_EQUAL( 0, count.value ); |
868 | bool res1 = removeCallOut(id); | |
869 | bool res2 = removeCallOut(id); | |
7e586023 | 870 | |
436fb144 TJ |
871 | BOOST_CHECK_EQUAL( true, res1 ); |
872 | BOOST_CHECK_EQUAL( false, res2 ); | |
7e586023 | 873 | |
436fb144 | 874 | backend->doOneStep( 1100 ); |
7e586023 | 875 | |
436fb144 TJ |
876 | BOOST_CHECK_EQUAL( 0, count.value ); |
877 | } // eo RemoveCallOut1() | |
7e586023 RP |
878 | |
879 | ||
7e586023 | 880 | |
436fb144 TJ |
881 | BOOST_AUTO_TEST_CASE(FrozenCall_Thaw) |
882 | { | |
883 | Counter count; | |
7e586023 | 884 | |
436fb144 TJ |
885 | CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 ); |
886 | backend->doOneStep( 10 ); | |
7e586023 | 887 | |
436fb144 TJ |
888 | BOOST_CHECK_EQUAL( 0, count.value ); |
889 | id.thaw(); | |
7e586023 | 890 | |
436fb144 | 891 | backend->doOneStep( 1100 ); |
7e586023 | 892 | |
436fb144 TJ |
893 | BOOST_CHECK_EQUAL( 1, count.value ); |
894 | } // eo FrozenCall_Thaw() | |
7e586023 RP |
895 | |
896 | ||
7e586023 | 897 | |
436fb144 TJ |
898 | BOOST_AUTO_TEST_CASE(FrozenCall_Decay) |
899 | { | |
900 | Counter count; | |
7e586023 | 901 | |
436fb144 TJ |
902 | CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 ); |
903 | backend->doOneStep( 10 ); | |
7e586023 | 904 | |
436fb144 TJ |
905 | BOOST_CHECK_EQUAL( 0, count.value ); |
906 | BOOST_CHECK_EQUAL( true, id.active() ); | |
907 | backend->doOneStep( 1100 ); | |
7e586023 | 908 | |
436fb144 TJ |
909 | BOOST_CHECK_EQUAL( 0, count.value ); |
910 | BOOST_CHECK_EQUAL( false, id.active() ); | |
911 | } // eo FrozenCall_Decay() | |
7e586023 RP |
912 | |
913 | ||
7e586023 | 914 | |
436fb144 TJ |
915 | BOOST_AUTO_TEST_CASE(UnixSockets_ClientServer) |
916 | { | |
917 | std::string path= getCheckFilepath("UDS_CS"); | |
7e586023 | 918 | |
436fb144 TJ |
919 | UnixIOSocketHolder server_holder; |
920 | UnixServerSocket< TestUnixIOSocket > server_port; | |
921 | UnixIOSocketPtr server; | |
922 | TestUnixIOSocket client0; | |
923 | TestUnixIOSocket client1; | |
7e586023 | 924 | |
436fb144 TJ |
925 | bool res1 = server_port.open(path, 0600); |
926 | BOOST_CHECK_EQUAL( true, res1 ); | |
7e586023 | 927 | |
436fb144 TJ |
928 | { |
929 | AsyncIo::Utils::FileStat stat(path,false); | |
930 | BOOST_REQUIRE( stat.is_socket() ); | |
931 | BOOST_CHECK_EQUAL( 0600u, (stat.mode() & 0777)); | |
932 | } | |
7e586023 | 933 | |
436fb144 TJ |
934 | server_port.setNewConnectionCallback( |
935 | boost::bind( &UnixIOSocketHolder::store, &server_holder, _1) | |
936 | ); | |
937 | ||
938 | // open a first client | |
939 | bool res2= client0.open(path); | |
940 | BOOST_CHECK_EQUAL( true, res2 ); | |
941 | ||
942 | BOOST_CHECK_EQUAL(0u, server_holder.size() ); | |
943 | backendStep(5,1); | |
944 | BOOST_CHECK_EQUAL(1u, server_holder.size() ); | |
945 | BOOST_REQUIRE( server_holder.get(0).get() ); | |
946 | ||
947 | client0.sendData("a simple test string."); | |
948 | backendStep(3,2); | |
949 | ||
950 | BOOST_CHECK_EQUAL( | |
951 | std::string("a simple test string."), | |
952 | server_holder.get(0)->m_received_string | |
953 | ); | |
954 | server_holder.get(0)->sendData("reply 1"); | |
955 | backendStep(3,2); | |
956 | BOOST_CHECK_EQUAL( std::string("reply 1"), client0.m_received_string ); | |
957 | ||
958 | // open a second client | |
959 | res2= client1.open(path); | |
960 | BOOST_CHECK_EQUAL( true, res2 ); | |
961 | backendStep(5,1); | |
962 | BOOST_CHECK_EQUAL(2u, server_holder.size() ); | |
963 | BOOST_REQUIRE( server_holder.get(1).get() ); | |
964 | ||
965 | server_holder.get(1)->sendData("::reply 2"); | |
966 | backendStep(3,2); | |
967 | BOOST_CHECK_EQUAL( std::string("::reply 2"), client1.m_received_string ); | |
968 | ||
969 | client1.sendData("another simple test string. 124"); | |
970 | backendStep(3,2); | |
971 | ||
972 | BOOST_CHECK_EQUAL( | |
973 | std::string("another simple test string. 124"), | |
974 | server_holder.get(1)->m_received_string | |
975 | ); | |
976 | ||
977 | // close first client | |
978 | client0.close(); | |
979 | BOOST_CHECK_EQUAL( false, server_holder.get(0)->eof() ); | |
980 | backendStep(3,2); | |
981 | BOOST_CHECK_EQUAL( true, server_holder.get(0)->eof() ); | |
982 | server_holder.get(0)->close(); | |
983 | ||
984 | // close second connection from server side | |
985 | BOOST_CHECK_EQUAL( false, client1.eof() ); | |
986 | server_holder.get(1)->close(); | |
987 | backendStep(3,2); | |
988 | BOOST_CHECK_EQUAL( true, client1.eof() ); | |
989 | client1.close(); | |
990 | } // eo UnixSockets_ClientServer() | |
7e586023 | 991 | |
cd9ddaee | 992 | |
436fb144 TJ |
993 | /* |
994 | BOOST_AUTO_TEST_CASE(Dummy) | |
995 | { | |
996 | using namespace std; | |
997 | cout << endl << "Random strings:" << endl; | |
998 | for (int i=10; i-->0;) | |
999 | { | |
1000 | cout << " " << makeRandomAsciiString(70)<< endl; | |
1001 | } | |
1002 | } // eo Dummy | |
1003 | */ | |
cd9ddaee | 1004 | |
436fb144 | 1005 | BOOST_AUTO_TEST_SUITE_END() |