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