Migrate from cppunit to boost::test
[libasyncio] / unittest / test_simpleio_basics.cpp
CommitLineData
8c15b8c7
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on 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
56using namespace I2n;
aba4c34d 57using namespace AsyncIo;
cd9ddaee 58
cd9ddaee
RP
59namespace {
60
61
62struct 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
85class 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
115struct 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
145class 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
161class 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
172class 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
223class 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
260typedef boost::shared_ptr< TestUnixIOSocket > TestUnixIOSocketPtr;
261
262
263class 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).
293boost::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 */
301std::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 318class SimpleioBasicsFixture
cd9ddaee 319{
436fb144
TJ
320protected:
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
370public:
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 385BOOST_FIXTURE_TEST_SUITE(TestSimpleioBasics, SimpleioBasicsFixture)
7e586023 386
436fb144
TJ
387BOOST_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
399BOOST_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 */
422BOOST_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 */
448BOOST_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 */
472BOOST_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
523BOOST_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 */
547BOOST_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 */
594BOOST_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 */
642BOOST_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 */
669BOOST_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 */
696BOOST_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 */
728BOOST_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 */
773BOOST_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
802BOOST_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
817BOOST_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
832BOOST_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
853BOOST_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
870BOOST_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
887BOOST_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/*
966BOOST_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 977BOOST_AUTO_TEST_SUITE_END()