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