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