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