Migrate libasyncio from boost.signal to signals2 (#8756)
[libasyncio] / unittest / test_simpleio_basics.cpp
... / ...
CommitLineData
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*/
20/** @file
21 *
22 * (c) Copyright 2007-2010 by Intra2net AG
23 */
24
25//#define NOISEDEBUG
26
27#include <string>
28#include <iostream>
29#include <iomanip>
30#include <vector>
31
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>
38#include <asyncio_system_tools.hpp>
39#include <asyncio_containerfunc.hpp>
40
41#include <boost/signals2.hpp>
42#include <boost/bind.hpp>
43#include <boost/random.hpp>
44
45#define BOOST_TEST_MAIN
46#define BOOST_TEST_DYN_LINK
47#include <boost/test/unit_test.hpp>
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;
57using namespace AsyncIo;
58
59namespace {
60
61
62struct Counter
63{
64 int value;
65
66
67 Counter() : value(0) { DOUT("Counter construct");}
68
69 void reset() { value=0;}
70
71 void advance()
72 {
73 DOUT(" advance called");
74 ++value;
75 }
76
77 int operator()()
78 {
79 DOUT(" () called");
80 return ++value;
81 }
82}; // eo struct Counter
83
84
85class TestTimer : public TimerBase
86{
87 public:
88
89 TestTimer()
90 : m_counter(0u)
91 {
92 } // eo TestTimer()
93
94
95 void setDelta(long msec)
96 {
97 setDeltaWhenTime(0,msec);
98 activate();
99 } // eo setDelta(long)
100
101
102 unsigned m_counter;
103
104 protected:
105
106 virtual void execute()
107 {
108 ++m_counter;
109 } // eo execute()
110
111}; // eo class TestTimer
112
113
114
115struct ReceivedData
116{
117 std::vector<std::string> m_received_vector;
118 std::string m_received_string;
119
120 unsigned long m_count_lines;
121 unsigned long m_data_size;
122
123
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&)
140
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
155
156 protected:
157
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>&)
182
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>&)
193
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 protected:
206
207 void slotReceivedData()
208 {
209 receiveData(m_input_buffer);
210 m_input_buffer.clear();
211 } // eo slotReceivedData()
212
213}; // eo class TestProcess
214
215
216
217class TestUnixIOSocket
218: public UnixIOSocket
219, public ReceivedData
220{
221 public:
222
223 TestUnixIOSocket()
224 : UnixIOSocket()
225 {
226 m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) );
227 } // eo TestUnixIOSocket()
228
229
230 TestUnixIOSocket(
231 int fd, const std::string& path
232 )
233 : UnixIOSocket(fd, path)
234 {
235 m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) );
236 } // eo TestUnixIOSocket()
237
238
239 void sendData(const std::string& data)
240 {
241 lowSend(data);
242 } // eo sendData(const std::string&)
243
244 protected:
245
246 void slotReceivedData()
247 {
248 receiveData(m_input_buffer);
249 m_input_buffer.clear();
250 } // eo slotReceivedData()
251
252}; // eo class TestUnixIOSocket
253
254typedef boost::shared_ptr< TestUnixIOSocket > TestUnixIOSocketPtr;
255
256
257class UnixIOSocketHolder
258: public std::vector< UnixIOSocketPtr >
259{
260 public:
261
262 void operator()(UnixIOSocketPtr ptr)
263 {
264 push_back(ptr);
265 }
266
267 void storeBase (IOImplementationPtr ptr)
268 {
269 push_back(boost::dynamic_pointer_cast< UnixIOSocket >(ptr) );
270 }
271
272 void store (UnixIOSocketPtr ptr)
273 {
274 push_back(ptr);
275 }
276
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).
287boost::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 */
295std::string makeRandomAsciiString(std::string::size_type len)
296{
297 static std::string chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz=+-*/%(){}<>.,:;\\");
298 std::string s;
299
300 boost::uniform_int<> discreter(0, chars.size()-1);
301 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > idxgen(g_random_gen, discreter);
302
303 for(; len-->0;) s+= chars.at( idxgen() );
304
305 return s;
306} // eo makeRandomAsciiString
307
308
309} // eo namespace <anonymous>
310
311
312class SimpleioBasicsFixture
313{
314protected:
315 Backend *backend;
316 std::set<std::string> used_check_files;
317
318 template<class Callable>
319 bool backendLoopUntil( Callable condition, int maxLoops=100 )
320 {
321 for (int i=std::max(maxLoops,1); i-->0 && ! condition();)
322 {
323 backend->doOneStep(10);
324 }
325 return condition();
326 } // eo backendLoopUntil
327
328
329 bool backendStep(int msTimeout= 10, int count=1)
330 {
331 bool res= true;
332 for(;count-->0 && res;)
333 {
334 res= backend->doOneStep(msTimeout);
335 }
336 return res;
337 } // eo backendStep
338
339
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
347
348
349 void removeCheckFiles()
350 {
351 for(std::set<std::string>::iterator it= used_check_files.begin();
352 it != used_check_files.end();
353 ++it)
354 {
355 std::string filepath(*it);
356 if (Utils::FileStat(filepath))
357 {
358 Utils::unlink(filepath);
359 }
360 }
361 used_check_files.clear();
362 } // eo removeCheckFiles
363
364public:
365 SimpleioBasicsFixture()
366 {
367 backend = Backend::getBackend();
368 installChildHandler();
369 used_check_files.clear();
370 }
371
372 ~SimpleioBasicsFixture()
373 {
374 restoreChildHandler();
375 removeCheckFiles();
376 }
377};
378
379BOOST_FIXTURE_TEST_SUITE(TestSimpleioBasics, SimpleioBasicsFixture)
380
381BOOST_AUTO_TEST_CASE(EmptyBackendStepCall)
382{
383 BOOST_REQUIRE( backend );
384
385 // a backend call without active objects should return false:
386 bool result = backend->doOneStep(0);
387
388 BOOST_CHECK_EQUAL( false, result );
389} // eo EmptyBackendStepCall
390
391
392
393BOOST_AUTO_TEST_CASE(NonEmptyBackendStepCall)
394{
395 BOOST_REQUIRE(backend);
396
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
410
411
412
413/**
414 * check for timer to execute immediatly.
415 */
416BOOST_AUTO_TEST_CASE(SingleTimerShot)
417{
418 BOOST_REQUIRE(backend);
419
420 TestTimer timer;
421 timer.setDelta(0); // shot now!
422
423 bool result = backend->doOneStep(10);
424
425 BOOST_CHECK_EQUAL( true, result );
426 // the timer should be executed once:
427 BOOST_CHECK_EQUAL( 1u, timer.m_counter );
428
429 result = backend->doOneStep(0);
430
431 BOOST_CHECK_EQUAL( false, result );
432 // the timer should not be executed again:
433 BOOST_CHECK_EQUAL( 1u, timer.m_counter );
434
435} // eo SingleTimerShot()
436
437
438
439/**
440 * tests a simple timer class to be executed with a timeout.
441 */
442BOOST_AUTO_TEST_CASE(SimpleTimerShot)
443{
444 bool res;
445 BOOST_REQUIRE(backend);
446
447 SimpleTimer timer1;
448 Counter counter1;
449 timer1.addAction( boost::bind(&Counter::advance,&counter1) );
450 BOOST_CHECK_EQUAL(false, timer1.active());
451
452 timer1.startTimerMS( 100 );
453 BOOST_CHECK_EQUAL(true, timer1.active());
454
455 res=backend->doOneStep( 1000 );
456 BOOST_CHECK_EQUAL( true, res );
457
458 BOOST_CHECK_EQUAL( 1, counter1.value );
459} // eo SimpleTimerShot
460
461
462
463/**
464 * tests 3 timers; after the first was active, disable another and check if the remaining one fires.
465 */
466BOOST_AUTO_TEST_CASE(SimpleTimerShot2)
467{
468 bool res;
469 BOOST_REQUIRE(backend);
470
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());
479
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());
486
487 res=backend->doOneStep( 1000 );
488 BOOST_CHECK_EQUAL( true, res );
489
490 BOOST_CHECK_EQUAL(false, timer1.active());
491 BOOST_CHECK_EQUAL(true, timer2.active());
492 BOOST_CHECK_EQUAL(true, timer3.active());
493
494 BOOST_CHECK_EQUAL( 1, counter1.value );
495 BOOST_CHECK_EQUAL( 0, counter2.value );
496 BOOST_CHECK_EQUAL( 0, counter3.value );
497
498 // now stop the next timer:
499 timer3.stopTimer();
500 BOOST_CHECK_EQUAL(false, timer3.active());
501
502 res=backend->doOneStep( 1000 );
503 BOOST_CHECK_EQUAL( true, res );
504
505 BOOST_CHECK_EQUAL( 1, counter1.value );
506 BOOST_CHECK_EQUAL( 1, counter2.value );
507 BOOST_CHECK_EQUAL( 0, counter3.value );
508} // eo SimpleTimerShot2
509
510
511
512
513/*
514** I/O tests:
515*/
516
517BOOST_AUTO_TEST_CASE(EmptyWantTest)
518{
519 IOImplementation io;
520
521 BOOST_CHECK_EQUAL(false, io.wantRead() );
522 BOOST_CHECK_EQUAL(false, io.wantWrite() );
523} // eo EmptyWantTest
524
525
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 */
541BOOST_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");
545
546 BOOST_REQUIRE(backend);
547
548 TestPipe pipe1, pipe2;
549
550 bool res= pipe1.makePipe(pipe2);
551
552 BOOST_CHECK_EQUAL(true, res);
553 BOOST_CHECK_EQUAL(true, pipe1.opened());
554 BOOST_CHECK_EQUAL(true, pipe2.opened());
555
556 res= backend->doOneStep(0);
557 BOOST_CHECK_EQUAL(true, res);
558
559 pipe1.sendString(test_string);
560
561 res= backend->doOneStep(0);
562 BOOST_CHECK_EQUAL(true, res);
563
564 BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string );
565
566 pipe2.sendString(test_string2);
567
568 res= backend->doOneStep(0);
569 BOOST_CHECK_EQUAL(true, res);
570
571 BOOST_CHECK_EQUAL( test_string2, pipe1.m_received_string );
572
573 pipe1.close();
574 BOOST_CHECK_EQUAL(false, pipe1.opened());
575
576 res= backend->doOneStep(0);
577 BOOST_CHECK_EQUAL(true, res);
578
579 BOOST_CHECK_EQUAL(true, pipe2.eof());
580} // eo SimplePipeTest
581
582
583
584/**
585 * sends a larger data chunk through a pipe.
586 * This tests if sending and receiving data in (smaller internal) chunks works.
587 */
588BOOST_AUTO_TEST_CASE(SimplePipePump)
589{
590 BOOST_REQUIRE(backend);
591
592 TestPipe pipe1, pipe2;
593
594 bool res= pipe1.makePipe(pipe2);
595
596 BOOST_CHECK_EQUAL(true, res);
597 BOOST_CHECK_EQUAL(true, pipe1.opened());
598 BOOST_CHECK_EQUAL(true, pipe2.opened());
599
600 res= backend->doOneStep(0);
601 BOOST_CHECK_EQUAL(true, res);
602
603 std::string test_string= makeRandomAsciiString(256*1024);
604
605 pipe1.sendString(test_string);
606
607 res= backend->doOneStep(0);
608 BOOST_CHECK_EQUAL(true, res);
609
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 };
615
616 pipe1.close();
617 BOOST_CHECK_EQUAL(false, pipe1.opened());
618
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 }
624
625 BOOST_CHECK_EQUAL( test_string.size(), pipe2.m_received_string.size() );
626 BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string );
627
628 BOOST_CHECK_EQUAL(true, pipe2.eof());
629} // eo SimplePipePump
630
631
632
633/**
634 * fork a subprocess (/bin/true) and test exit code.
635 */
636BOOST_AUTO_TEST_CASE(SimpleProcessTestBinTrue)
637{
638 bool res;
639 BOOST_REQUIRE(backend);
640
641 TestProcess proc("/bin/true");
642
643 res= proc.startProcess();
644 BOOST_CHECK_EQUAL(true, res);
645
646 res= backend->doOneStep(200);
647 BOOST_CHECK_EQUAL(true, res);
648
649 for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;)
650 {
651 backend->doOneStep(15);
652 }
653
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
658
659
660/**
661 * fork a subprocess (/bin/false) and test exit code.
662 */
663BOOST_AUTO_TEST_CASE(SimpleProcessTestBinFalse)
664{
665 bool res;
666 BOOST_REQUIRE(backend);
667
668 TestProcess proc("/bin/false");
669
670 res= proc.startProcess();
671 BOOST_CHECK_EQUAL(true, res);
672
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 }
679
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
685
686
687/**
688 * fork an echo subprocess and read back the output.
689 */
690BOOST_AUTO_TEST_CASE(SimpleProcessTestEcho)
691{
692 DOUT("enter SimpleProcessTestEcho");
693 bool res;
694 BOOST_REQUIRE(backend);
695
696 TestProcess proc(
697 "/bin/echo",
698 TransientPushBackFiller<std::string, std::vector >()("Eine")("Zeichenkette")
699 );
700
701 res= proc.startProcess();
702 BOOST_CHECK_EQUAL(true, res);
703
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 }
710
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
716
717
718
719/**
720 * fork a bash subprocess, echo something on stderr and read back the output.
721 */
722BOOST_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");
753
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
761
762
763
764/**
765 * checks termination of process by signal and if the signal is returned.
766 */
767BOOST_AUTO_TEST_CASE(SignaledProcessTermination)
768{
769 bool res;
770 BOOST_REQUIRE(backend);
771
772 TestProcess proc("/bin/sleep","2");
773 res= proc.startProcess();
774 BOOST_CHECK_EQUAL(true, res);
775
776 res= backend->doOneStep(10);
777 BOOST_CHECK_EQUAL(true, res);
778 BOOST_CHECK_EQUAL( ProcessState(ProcessState::running), proc.processState() );
779
780 res= backend->doOneStep(50);
781
782 // now send the process an USR1 (which terminates the process)
783 res=proc.kill( Signal::USR1 );
784 BOOST_CHECK_EQUAL(true, res);
785
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);
788
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
793
794/**
795 * fork an echo subprocess and read back the output. Directly use ProcessImplementation without helper class.
796 */
797BOOST_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
828
829BOOST_AUTO_TEST_CASE(DirectProcessImplementationGetline)
830{
831 DOUT("enter SimpleProcessTestEcho");
832 bool res;
833 BOOST_REQUIRE(backend);
834
835 ProcessImplementation proc(
836 "/bin/sh",
837 TransientPushBackFiller<std::string, std::vector >()("-c")("echo -n 1; sleep 1; echo 2; echo")
838 );
839
840 res= proc.startProcess();
841 BOOST_CHECK_EQUAL(true, res);
842
843 res= backend->doOneStep(800);
844 BOOST_CHECK_EQUAL(true, res);
845
846 // echo -n 1 should be out by now
847
848 BOOST_CHECK_EQUAL( std::string(""), proc.getline());
849
850 for(int i=20; i-->0 && (proc.processState()!= ProcessState::stopped || !proc.eof());)
851 {
852 backend->doOneStep(100);
853 }
854
855 BOOST_CHECK_EQUAL( ProcessState(ProcessState::stopped), proc.processState() );
856 BOOST_CHECK_EQUAL( true, proc.eof() );
857 BOOST_CHECK_EQUAL( 0, proc.exitCode() );
858 BOOST_CHECK_EQUAL( std::string("12\n"), proc.getline());
859 BOOST_CHECK_EQUAL( std::string("\n"), proc.getline());
860 BOOST_CHECK_EQUAL( false, proc.inputAvailable());
861} // eo SimpleProcessTestEcho
862
863BOOST_AUTO_TEST_CASE(CallOut1)
864{
865 Counter count;
866
867 callOut( boost::bind(&Counter::advance, &count), 1 );
868 backend->doOneStep( 10 );
869
870 BOOST_CHECK_EQUAL( 0, count.value );
871 backend->doOneStep( 1100 );
872
873 BOOST_CHECK_EQUAL( 1, count.value );
874} // eo CallOut1()
875
876
877
878BOOST_AUTO_TEST_CASE(CallOut2)
879{
880 Counter count;
881
882 callOut( boost::bind(&Counter::advance, &count), 0.5 );
883 backend->doOneStep( 10 );
884
885 BOOST_CHECK_EQUAL( 0, count.value );
886 backend->doOneStep( 800 );
887
888 BOOST_CHECK_EQUAL( 1, count.value );
889} // eo CallOut2()
890
891
892
893BOOST_AUTO_TEST_CASE(RemoveCallOut1)
894{
895 Counter count;
896
897 CallOutId id= callOut( boost::bind(&Counter::advance, &count), 1 );
898 backend->doOneStep( 10 );
899
900 BOOST_CHECK_EQUAL( 0, count.value );
901 bool res1 = removeCallOut(id);
902 bool res2 = removeCallOut(id);
903
904 BOOST_CHECK_EQUAL( true, res1 );
905 BOOST_CHECK_EQUAL( false, res2 );
906
907 backend->doOneStep( 1100 );
908
909 BOOST_CHECK_EQUAL( 0, count.value );
910} // eo RemoveCallOut1()
911
912
913
914BOOST_AUTO_TEST_CASE(FrozenCall_Thaw)
915{
916 Counter count;
917
918 CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
919 backend->doOneStep( 10 );
920
921 BOOST_CHECK_EQUAL( 0, count.value );
922 id.thaw();
923
924 backend->doOneStep( 1100 );
925
926 BOOST_CHECK_EQUAL( 1, count.value );
927} // eo FrozenCall_Thaw()
928
929
930
931BOOST_AUTO_TEST_CASE(FrozenCall_Decay)
932{
933 Counter count;
934
935 CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
936 backend->doOneStep( 10 );
937
938 BOOST_CHECK_EQUAL( 0, count.value );
939 BOOST_CHECK_EQUAL( true, id.active() );
940 backend->doOneStep( 1100 );
941
942 BOOST_CHECK_EQUAL( 0, count.value );
943 BOOST_CHECK_EQUAL( false, id.active() );
944} // eo FrozenCall_Decay()
945
946
947
948BOOST_AUTO_TEST_CASE(UnixSockets_ClientServer)
949{
950 std::string path= getCheckFilepath("UDS_CS");
951
952 UnixIOSocketHolder server_holder;
953 UnixServerSocket< TestUnixIOSocket > server_port;
954 UnixIOSocketPtr server;
955 TestUnixIOSocket client0;
956 TestUnixIOSocket client1;
957
958 bool res1 = server_port.open(path, 0600);
959 BOOST_CHECK_EQUAL( true, res1 );
960
961 {
962 AsyncIo::Utils::FileStat stat(path,false);
963 BOOST_REQUIRE( stat.is_socket() );
964 BOOST_CHECK_EQUAL( 0600u, (stat.mode() & 0777));
965 }
966
967 server_port.setNewConnectionCallback(
968 boost::bind( &UnixIOSocketHolder::store, &server_holder, _1)
969 );
970
971 // open a first client
972 bool res2= client0.open(path);
973 BOOST_CHECK_EQUAL( true, res2 );
974
975 BOOST_CHECK_EQUAL(0u, server_holder.size() );
976 backendStep(5,1);
977 BOOST_CHECK_EQUAL(1u, server_holder.size() );
978 BOOST_REQUIRE( server_holder.get(0).get() );
979
980 client0.sendData("a simple test string.");
981 backendStep(3,2);
982
983 BOOST_CHECK_EQUAL(
984 std::string("a simple test string."),
985 server_holder.get(0)->m_received_string
986 );
987 server_holder.get(0)->sendData("reply 1");
988 backendStep(3,2);
989 BOOST_CHECK_EQUAL( std::string("reply 1"), client0.m_received_string );
990
991 // open a second client
992 res2= client1.open(path);
993 BOOST_CHECK_EQUAL( true, res2 );
994 backendStep(5,1);
995 BOOST_CHECK_EQUAL(2u, server_holder.size() );
996 BOOST_REQUIRE( server_holder.get(1).get() );
997
998 server_holder.get(1)->sendData("::reply 2");
999 backendStep(3,2);
1000 BOOST_CHECK_EQUAL( std::string("::reply 2"), client1.m_received_string );
1001
1002 client1.sendData("another simple test string. 124");
1003 backendStep(3,2);
1004
1005 BOOST_CHECK_EQUAL(
1006 std::string("another simple test string. 124"),
1007 server_holder.get(1)->m_received_string
1008 );
1009
1010 // close first client
1011 client0.close();
1012 BOOST_CHECK_EQUAL( false, server_holder.get(0)->eof() );
1013 backendStep(3,2);
1014 BOOST_CHECK_EQUAL( true, server_holder.get(0)->eof() );
1015 server_holder.get(0)->close();
1016
1017 // close second connection from server side
1018 BOOST_CHECK_EQUAL( false, client1.eof() );
1019 server_holder.get(1)->close();
1020 backendStep(3,2);
1021 BOOST_CHECK_EQUAL( true, client1.eof() );
1022 client1.close();
1023} // eo UnixSockets_ClientServer()
1024
1025
1026/*
1027BOOST_AUTO_TEST_CASE(Dummy)
1028{
1029 using namespace std;
1030 cout << endl << "Random strings:" << endl;
1031 for (int i=10; i-->0;)
1032 {
1033 cout << " " << makeRandomAsciiString(70)<< endl;
1034 }
1035} // eo Dummy
1036*/
1037
1038BOOST_AUTO_TEST_SUITE_END()