Make unit test compilable without libi2ncommon
[libasyncio] / unittest / test_simpleio_basics.cpp
CommitLineData
8c15b8c7
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
cd9ddaee
RP
20/** @file
21 *
22 * (c) Copyright 2007 by Intra2net AG
cd9ddaee
RP
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
4f6228c3
RP
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>
0630284f
TJ
42#include <asyncio_system_tools.hpp>
43#include <asyncio_containerfunc.hpp>
cd9ddaee
RP
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
56using namespace I2n;
aba4c34d 57using namespace AsyncIo;
cd9ddaee
RP
58
59
60using namespace CppUnit;
61
62namespace {
63
64
65struct 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
88class 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
118struct 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
148class 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
164class 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
175class 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
226class 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
264typedef boost::shared_ptr< TestUnixIOSocket > TestUnixIOSocketPtr;
265
266
267class 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).
297boost::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 */
305std::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
323class 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);
0630284f 402 //FIXME: if (path_exists(filepath))
cd9ddaee 403 {
0630284f 404 unlink(filepath.c_str());
cd9ddaee
RP
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 {
6bf0faed 709 backend->doOneStep(15);
cd9ddaee
RP
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 {
6bf0faed 735 backend->doOneStep(15);
cd9ddaee
RP
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 {
0630284f 953 AsyncIo::Utils::FileStat stat(path,false);
cd9ddaee 954 CPPUNIT_ASSERT( stat.is_socket() );
0630284f 955 //FIXME: CPPUNIT_ASSERT_EQUAL( 0600u, (stat.mode() & 0777));
cd9ddaee
RP
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
1031CPPUNIT_TEST_SUITE_REGISTRATION(TestSimpleioBasics);