make kill() and pid() part of the public interface of ProcessImplementation
[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/signal.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
796 BOOST_AUTO_TEST_CASE(CallOut1)
797 {
798     Counter count;
799
800     callOut( boost::bind(&Counter::advance, &count), 1 );
801     backend->doOneStep( 10 );
802
803     BOOST_CHECK_EQUAL( 0, count.value );
804     backend->doOneStep( 1100 );
805
806     BOOST_CHECK_EQUAL( 1, count.value );
807 } // eo CallOut1()
808
809
810
811 BOOST_AUTO_TEST_CASE(CallOut2)
812 {
813     Counter count;
814
815     callOut( boost::bind(&Counter::advance, &count), 0.5 );
816     backend->doOneStep( 10 );
817
818     BOOST_CHECK_EQUAL( 0, count.value );
819     backend->doOneStep( 800 );
820
821     BOOST_CHECK_EQUAL( 1, count.value );
822 } // eo CallOut2()
823
824
825
826 BOOST_AUTO_TEST_CASE(RemoveCallOut1)
827 {
828     Counter count;
829
830     CallOutId id= callOut( boost::bind(&Counter::advance, &count), 1 );
831     backend->doOneStep( 10 );
832
833     BOOST_CHECK_EQUAL( 0, count.value );
834     bool res1 = removeCallOut(id);
835     bool res2 = removeCallOut(id);
836
837     BOOST_CHECK_EQUAL( true, res1 );
838     BOOST_CHECK_EQUAL( false, res2 );
839
840     backend->doOneStep( 1100 );
841
842     BOOST_CHECK_EQUAL( 0, count.value );
843 } // eo RemoveCallOut1()
844
845
846
847 BOOST_AUTO_TEST_CASE(FrozenCall_Thaw)
848 {
849     Counter count;
850
851     CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
852     backend->doOneStep( 10 );
853
854     BOOST_CHECK_EQUAL( 0, count.value );
855     id.thaw();
856
857     backend->doOneStep( 1100 );
858
859     BOOST_CHECK_EQUAL( 1, count.value );
860 } // eo FrozenCall_Thaw()
861
862
863
864 BOOST_AUTO_TEST_CASE(FrozenCall_Decay)
865 {
866     Counter count;
867
868     CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
869     backend->doOneStep( 10 );
870
871     BOOST_CHECK_EQUAL( 0, count.value );
872     BOOST_CHECK_EQUAL( true, id.active() );
873     backend->doOneStep( 1100 );
874
875     BOOST_CHECK_EQUAL( 0, count.value );
876     BOOST_CHECK_EQUAL( false, id.active() );
877 } // eo FrozenCall_Decay()
878
879
880
881 BOOST_AUTO_TEST_CASE(UnixSockets_ClientServer)
882 {
883     std::string path= getCheckFilepath("UDS_CS");
884
885     UnixIOSocketHolder server_holder;
886     UnixServerSocket< TestUnixIOSocket > server_port;
887     UnixIOSocketPtr server;
888     TestUnixIOSocket client0;
889     TestUnixIOSocket client1;
890
891     bool res1 = server_port.open(path, 0600);
892     BOOST_CHECK_EQUAL( true, res1 );
893
894     {
895         AsyncIo::Utils::FileStat stat(path,false);
896         BOOST_REQUIRE( stat.is_socket() );
897         BOOST_CHECK_EQUAL( 0600u, (stat.mode() & 0777));
898     }
899
900     server_port.setNewConnectionCallback(
901         boost::bind( &UnixIOSocketHolder::store, &server_holder, _1)
902     );
903
904     // open a first client
905     bool res2= client0.open(path);
906     BOOST_CHECK_EQUAL( true, res2 );
907
908     BOOST_CHECK_EQUAL(0u, server_holder.size() );
909     backendStep(5,1);
910     BOOST_CHECK_EQUAL(1u, server_holder.size() );
911     BOOST_REQUIRE( server_holder.get(0).get() );
912
913     client0.sendData("a simple test string.");
914     backendStep(3,2);
915
916     BOOST_CHECK_EQUAL(
917         std::string("a simple test string."),
918         server_holder.get(0)->m_received_string
919     );
920     server_holder.get(0)->sendData("reply 1");
921     backendStep(3,2);
922     BOOST_CHECK_EQUAL( std::string("reply 1"), client0.m_received_string );
923
924     // open a second client
925     res2= client1.open(path);
926     BOOST_CHECK_EQUAL( true, res2 );
927     backendStep(5,1);
928     BOOST_CHECK_EQUAL(2u, server_holder.size() );
929     BOOST_REQUIRE( server_holder.get(1).get() );
930
931     server_holder.get(1)->sendData("::reply 2");
932     backendStep(3,2);
933     BOOST_CHECK_EQUAL( std::string("::reply 2"), client1.m_received_string );
934
935     client1.sendData("another simple test string. 124");
936     backendStep(3,2);
937
938     BOOST_CHECK_EQUAL(
939         std::string("another simple test string. 124"),
940         server_holder.get(1)->m_received_string
941     );
942
943     // close first client
944     client0.close();
945     BOOST_CHECK_EQUAL( false, server_holder.get(0)->eof() );
946     backendStep(3,2);
947     BOOST_CHECK_EQUAL( true, server_holder.get(0)->eof() );
948     server_holder.get(0)->close();
949
950     // close second connection from server side
951     BOOST_CHECK_EQUAL( false, client1.eof() );
952     server_holder.get(1)->close();
953     backendStep(3,2);
954     BOOST_CHECK_EQUAL( true, client1.eof() );
955     client1.close();
956 } // eo UnixSockets_ClientServer()
957
958
959 /*
960 BOOST_AUTO_TEST_CASE(Dummy)
961 {
962     using namespace std;
963     cout << endl << "Random strings:" << endl;
964     for (int i=10; i-->0;)
965     {
966         cout << "  " << makeRandomAsciiString(70)<< endl;
967     }
968 } // eo Dummy
969 */
970
971 BOOST_AUTO_TEST_SUITE_END()