disabled extra debug output
[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             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 (Utils::FileStat(filepath))
403                 {
404                     Utils::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                 AsyncIo::Utils::FileStat 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);