disabled extra debug output
[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 *
7e586023 22 * (c) Copyright 2007-2009 by Intra2net AG
cd9ddaee
RP
23 */
24
cbcb9570 25//#define NOISEDEBUG
cd9ddaee
RP
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>
7e586023
RP
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;
7e586023
RP
68
69
cd9ddaee 70 Counter() : value(0) { DOUT("Counter construct");}
7e586023 71
cd9ddaee 72 void reset() { value=0;}
7e586023 73
cd9ddaee
RP
74 void advance()
75 {
76 DOUT(" advance called");
77 ++value;
78 }
7e586023 79
cd9ddaee
RP
80 int operator()()
81 {
82 DOUT(" () called");
83 return ++value;
84 }
85}; // eo struct Counter
86
87
88class TestTimer : public TimerBase
89{
90 public:
7e586023 91
cd9ddaee
RP
92 TestTimer()
93 : m_counter(0u)
94 {
95 } // eo TestTimer()
7e586023
RP
96
97
cd9ddaee
RP
98 void setDelta(long msec)
99 {
100 setDeltaWhenTime(0,msec);
101 activate();
102 } // eo setDelta(long)
7e586023
RP
103
104
cd9ddaee 105 unsigned m_counter;
7e586023 106
cd9ddaee 107 protected:
7e586023 108
cd9ddaee
RP
109 virtual void execute()
110 {
111 ++m_counter;
112 } // eo execute()
7e586023 113
cd9ddaee
RP
114}; // eo class TestTimer
115
116
117
118struct ReceivedData
119{
120 std::vector<std::string> m_received_vector;
121 std::string m_received_string;
7e586023 122
cd9ddaee
RP
123 unsigned long m_count_lines;
124 unsigned long m_data_size;
7e586023
RP
125
126
cd9ddaee
RP
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&)
7e586023 143
cd9ddaee
RP
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
7e586023 158
cd9ddaee 159 protected:
7e586023 160
cd9ddaee
RP
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>&)
7e586023 185
cd9ddaee
RP
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>&)
7e586023 196
cd9ddaee
RP
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:
7e586023 215
cd9ddaee
RP
216 void slotReceivedData()
217 {
218 receiveData(m_input_buffer);
219 m_input_buffer.clear();
220 } // eo slotReceivedData()
7e586023 221
cd9ddaee
RP
222}; // eo class TestProcess
223
224
225
226class TestUnixIOSocket
227: public UnixIOSocket
228, public ReceivedData
229{
230 public:
7e586023 231
cd9ddaee
RP
232 TestUnixIOSocket()
233 : UnixIOSocket()
234 {
235 m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) );
236 } // eo TestUnixIOSocket()
7e586023
RP
237
238
cd9ddaee
RP
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()
7e586023
RP
247
248
cd9ddaee
RP
249 void sendData(const std::string& data)
250 {
251 lowSend(data);
252 } // eo sendData(const std::string&)
7e586023 253
cd9ddaee 254 protected:
7e586023 255
cd9ddaee
RP
256 void slotReceivedData()
257 {
258 receiveData(m_input_buffer);
259 m_input_buffer.clear();
260 } // eo slotReceivedData()
7e586023 261
cd9ddaee
RP
262}; // eo class TestUnixIOSocket
263
264typedef boost::shared_ptr< TestUnixIOSocket > TestUnixIOSocketPtr;
265
266
267class UnixIOSocketHolder
268: public std::vector< UnixIOSocketPtr >
269{
270 public:
7e586023 271
cd9ddaee
RP
272 void operator()(UnixIOSocketPtr ptr)
273 {
274 push_back(ptr);
275 }
7e586023 276
cd9ddaee
RP
277 void storeBase (IOImplementationPtr ptr)
278 {
279 push_back(boost::dynamic_pointer_cast< UnixIOSocket >(ptr) );
280 }
7e586023 281
cd9ddaee
RP
282 void store (UnixIOSocketPtr ptr)
283 {
284 push_back(ptr);
285 }
7e586023 286
cd9ddaee
RP
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;
7e586023 309
cd9ddaee
RP
310 boost::uniform_int<> discreter(0, chars.size()-1);
311 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > idxgen(g_random_gen, discreter);
7e586023 312
cd9ddaee 313 for(; len-->0;) s+= chars.at( idxgen() );
7e586023 314
cd9ddaee
RP
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);
7e586023 326
cd9ddaee
RP
327 CPPUNIT_TEST(EmptyBackendStepCall);
328 CPPUNIT_TEST(NonEmptyBackendStepCall);
329 CPPUNIT_TEST(SingleTimerShot);
330 CPPUNIT_TEST(SimpleTimerShot);
331 CPPUNIT_TEST(SimpleTimerShot2);
7e586023 332
cd9ddaee
RP
333 CPPUNIT_TEST(EmptyWantTest);
334 CPPUNIT_TEST(SimplePipeTest);
335 CPPUNIT_TEST(SimplePipePump);
7e586023 336
cd9ddaee
RP
337 CPPUNIT_TEST(SimpleProcessTestBinTrue);
338 CPPUNIT_TEST(SimpleProcessTestBinFalse);
339 CPPUNIT_TEST(SimpleProcessTestEcho);
340 CPPUNIT_TEST(SimpleProcessTestStderr);
341 CPPUNIT_TEST(SignaledProcessTermination);
7e586023
RP
342
343
cd9ddaee
RP
344 CPPUNIT_TEST(CallOut1);
345 CPPUNIT_TEST(CallOut2);
346 CPPUNIT_TEST(RemoveCallOut1);
7e586023 347
cd9ddaee
RP
348 CPPUNIT_TEST(FrozenCall_Thaw);
349 CPPUNIT_TEST(FrozenCall_Decay);
7e586023
RP
350
351
cd9ddaee
RP
352 CPPUNIT_TEST(UnixSockets_ClientServer);
353
7e586023 354
cd9ddaee
RP
355 //CPPUNIT_TEST(Dummy);
356 CPPUNIT_TEST_SUITE_END();
7e586023 357
cd9ddaee 358 protected:
7e586023 359
cd9ddaee
RP
360 Backend *backend;
361 std::set<std::string> used_check_files;
7e586023
RP
362
363
cd9ddaee
RP
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
7e586023
RP
373
374
cd9ddaee
RP
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
7e586023
RP
384
385
cd9ddaee
RP
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
7e586023
RP
393
394
cd9ddaee
RP
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);
7e586023 402 if (Utils::FileStat(filepath))
cd9ddaee 403 {
7e586023 404 Utils::unlink(filepath);
cd9ddaee
RP
405 }
406 }
407 used_check_files.clear();
408 } // eo removeCheckFiles
7e586023
RP
409
410
411
cd9ddaee 412 public:
7e586023 413
cd9ddaee
RP
414 void setUp()
415 {
416 backend = Backend::getBackend();
417 installChildHandler();
418 used_check_files.clear();
419 } // eo setUp
7e586023
RP
420
421
cd9ddaee
RP
422 void tearDown()
423 {
424 restoreChildHandler();
425 removeCheckFiles();
426 } // eo tearDown
7e586023
RP
427
428
cd9ddaee
RP
429 /*
430 * the tests:
431 */
7e586023
RP
432
433
cd9ddaee
RP
434 /*
435 ** basics:
436 */
7e586023
RP
437
438
cd9ddaee
RP
439 void EmptyBackendStepCall()
440 {
441 CPPUNIT_ASSERT( backend );
7e586023 442
cd9ddaee
RP
443 // a backend call without active objects should return false:
444 bool result = backend->doOneStep(0);
7e586023 445
cd9ddaee
RP
446 CPPUNIT_ASSERT_EQUAL( false, result );
447 } // eo EmptyBackendStepCall
7e586023
RP
448
449
cd9ddaee
RP
450
451 void NonEmptyBackendStepCall()
452 {
453 CPPUNIT_ASSERT(backend);
7e586023 454
cd9ddaee
RP
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
7e586023
RP
468
469
470
cd9ddaee
RP
471 /**
472 * check for timer to execute immediatly.
473 */
474 void SingleTimerShot()
475 {
476 CPPUNIT_ASSERT(backend);
7e586023 477
cd9ddaee
RP
478 TestTimer timer;
479 timer.setDelta(0); // shot now!
7e586023 480
cd9ddaee 481 bool result = backend->doOneStep(10);
7e586023 482
cd9ddaee
RP
483 CPPUNIT_ASSERT_EQUAL( true, result );
484 // the timer should be executed once:
485 CPPUNIT_ASSERT_EQUAL( 1u, timer.m_counter );
7e586023 486
cd9ddaee 487 result = backend->doOneStep(0);
7e586023 488
cd9ddaee
RP
489 CPPUNIT_ASSERT_EQUAL( false, result );
490 // the timer should not be executed again:
491 CPPUNIT_ASSERT_EQUAL( 1u, timer.m_counter );
7e586023 492
cd9ddaee 493 } // eo SingleTimerShot()
7e586023
RP
494
495
496
cd9ddaee
RP
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);
7e586023 504
cd9ddaee
RP
505 SimpleTimer timer1;
506 Counter counter1;
507 timer1.addAction( boost::bind(&Counter::advance,&counter1) );
508 CPPUNIT_ASSERT_EQUAL(false, timer1.active());
7e586023 509
cd9ddaee
RP
510 timer1.startTimerMS( 100 );
511 CPPUNIT_ASSERT_EQUAL(true, timer1.active());
7e586023 512
cd9ddaee
RP
513 res=backend->doOneStep( 1000 );
514 CPPUNIT_ASSERT_EQUAL( true, res );
7e586023 515
cd9ddaee
RP
516 CPPUNIT_ASSERT_EQUAL( 1, counter1.value );
517 } // eo SimpleTimerShot
7e586023
RP
518
519
520
cd9ddaee
RP
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);
7e586023 528
cd9ddaee
RP
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());
7e586023 537
cd9ddaee
RP
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());
7e586023 544
cd9ddaee
RP
545 res=backend->doOneStep( 1000 );
546 CPPUNIT_ASSERT_EQUAL( true, res );
7e586023 547
cd9ddaee
RP
548 CPPUNIT_ASSERT_EQUAL(false, timer1.active());
549 CPPUNIT_ASSERT_EQUAL(true, timer2.active());
550 CPPUNIT_ASSERT_EQUAL(true, timer3.active());
7e586023 551
cd9ddaee
RP
552 CPPUNIT_ASSERT_EQUAL( 1, counter1.value );
553 CPPUNIT_ASSERT_EQUAL( 0, counter2.value );
554 CPPUNIT_ASSERT_EQUAL( 0, counter3.value );
7e586023 555
cd9ddaee
RP
556 // now stop the next timer:
557 timer3.stopTimer();
558 CPPUNIT_ASSERT_EQUAL(false, timer3.active());
7e586023 559
cd9ddaee
RP
560 res=backend->doOneStep( 1000 );
561 CPPUNIT_ASSERT_EQUAL( true, res );
7e586023 562
cd9ddaee
RP
563 CPPUNIT_ASSERT_EQUAL( 1, counter1.value );
564 CPPUNIT_ASSERT_EQUAL( 1, counter2.value );
565 CPPUNIT_ASSERT_EQUAL( 0, counter3.value );
566 } // eo SimpleTimerShot2
7e586023
RP
567
568
569
570
cd9ddaee
RP
571 /*
572 ** I/O tests:
573 */
7e586023 574
cd9ddaee
RP
575 void EmptyWantTest()
576 {
577 IOImplementation io;
7e586023 578
cd9ddaee
RP
579 CPPUNIT_ASSERT_EQUAL(false, io.wantRead() );
580 CPPUNIT_ASSERT_EQUAL(false, io.wantWrite() );
581 } // eo EmptyWantTest
7e586023
RP
582
583
cd9ddaee
RP
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 * .
7e586023 597 *
cd9ddaee
RP
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");
7e586023 603
cd9ddaee 604 CPPUNIT_ASSERT(backend);
7e586023 605
cd9ddaee 606 TestPipe pipe1, pipe2;
7e586023 607
cd9ddaee 608 bool res= pipe1.makePipe(pipe2);
7e586023 609
cd9ddaee
RP
610 CPPUNIT_ASSERT_EQUAL(true, res);
611 CPPUNIT_ASSERT_EQUAL(true, pipe1.opened());
612 CPPUNIT_ASSERT_EQUAL(true, pipe2.opened());
7e586023 613
cd9ddaee
RP
614 res= backend->doOneStep(0);
615 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 616
cd9ddaee 617 pipe1.sendString(test_string);
7e586023 618
cd9ddaee
RP
619 res= backend->doOneStep(0);
620 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 621
cd9ddaee 622 CPPUNIT_ASSERT_EQUAL( test_string, pipe2.m_received_string );
7e586023 623
cd9ddaee 624 pipe2.sendString(test_string2);
7e586023 625
cd9ddaee
RP
626 res= backend->doOneStep(0);
627 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 628
cd9ddaee 629 CPPUNIT_ASSERT_EQUAL( test_string2, pipe1.m_received_string );
7e586023 630
cd9ddaee
RP
631 pipe1.close();
632 CPPUNIT_ASSERT_EQUAL(false, pipe1.opened());
7e586023 633
cd9ddaee
RP
634 res= backend->doOneStep(0);
635 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 636
cd9ddaee
RP
637 CPPUNIT_ASSERT_EQUAL(true, pipe2.eof());
638 } // eo SimplePipeTest
7e586023
RP
639
640
641
cd9ddaee
RP
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);
7e586023 649
cd9ddaee 650 TestPipe pipe1, pipe2;
7e586023 651
cd9ddaee 652 bool res= pipe1.makePipe(pipe2);
7e586023 653
cd9ddaee
RP
654 CPPUNIT_ASSERT_EQUAL(true, res);
655 CPPUNIT_ASSERT_EQUAL(true, pipe1.opened());
656 CPPUNIT_ASSERT_EQUAL(true, pipe2.opened());
7e586023 657
cd9ddaee
RP
658 res= backend->doOneStep(0);
659 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 660
cd9ddaee 661 std::string test_string= makeRandomAsciiString(256*1024);
7e586023 662
cd9ddaee 663 pipe1.sendString(test_string);
7e586023 664
cd9ddaee
RP
665 res= backend->doOneStep(0);
666 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 667
cd9ddaee
RP
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 };
7e586023 673
cd9ddaee
RP
674 pipe1.close();
675 CPPUNIT_ASSERT_EQUAL(false, pipe1.opened());
7e586023 676
cd9ddaee
RP
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 }
7e586023 682
cd9ddaee
RP
683 CPPUNIT_ASSERT_EQUAL( test_string.size(), pipe2.m_received_string.size() );
684 CPPUNIT_ASSERT_EQUAL( test_string, pipe2.m_received_string );
7e586023 685
cd9ddaee
RP
686 CPPUNIT_ASSERT_EQUAL(true, pipe2.eof());
687 } // eo SimplePipePump
7e586023
RP
688
689
690
cd9ddaee
RP
691 /**
692 * fork a subprocess (/bin/true) and test exit code.
693 */
694 void SimpleProcessTestBinTrue()
695 {
696 bool res;
697 CPPUNIT_ASSERT(backend);
7e586023 698
cd9ddaee 699 TestProcess proc("/bin/true");
7e586023 700
cd9ddaee
RP
701 res= proc.startProcess();
702 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 703
cd9ddaee
RP
704 res= backend->doOneStep(200);
705 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 706
cd9ddaee
RP
707 for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;)
708 {
6bf0faed 709 backend->doOneStep(15);
cd9ddaee 710 }
7e586023 711
cd9ddaee
RP
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
7e586023
RP
716
717
cd9ddaee
RP
718 /**
719 * fork a subprocess (/bin/false) and test exit code.
720 */
721 void SimpleProcessTestBinFalse()
722 {
723 bool res;
724 CPPUNIT_ASSERT(backend);
7e586023 725
cd9ddaee 726 TestProcess proc("/bin/false");
7e586023 727
cd9ddaee
RP
728 res= proc.startProcess();
729 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 730
cd9ddaee
RP
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 736 }
7e586023 737
cd9ddaee
RP
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
7e586023
RP
743
744
cd9ddaee
RP
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);
7e586023 753
cd9ddaee
RP
754 TestProcess proc(
755 "/bin/echo",
756 TransientPushBackFiller<std::string, std::vector >()("Eine")("Zeichenkette")
757 );
7e586023 758
cd9ddaee
RP
759 res= proc.startProcess();
760 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 761
cd9ddaee
RP
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 }
7e586023 768
cd9ddaee
RP
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
7e586023
RP
774
775
776
cd9ddaee
RP
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
7e586023
RP
819
820
821
cd9ddaee
RP
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);
7e586023 829
cd9ddaee
RP
830 TestProcess proc("/bin/sleep","2");
831 res= proc.startProcess();
832 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 833
cd9ddaee
RP
834 res= backend->doOneStep(10);
835 CPPUNIT_ASSERT_EQUAL(true, res);
836 CPPUNIT_ASSERT_EQUAL( ProcessState(ProcessState::running), proc.processState() );
7e586023 837
cd9ddaee 838 res= backend->doOneStep(50);
7e586023 839
cd9ddaee
RP
840 // now send the process an USR1 (which terminates the process)
841 res=proc.kill( Signal::USR1 );
842 CPPUNIT_ASSERT_EQUAL(true, res);
7e586023 843
cd9ddaee
RP
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);
7e586023 846
cd9ddaee
RP
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
7e586023
RP
851
852
853
cd9ddaee
RP
854 void CallOut1()
855 {
856 Counter count;
7e586023 857
cd9ddaee
RP
858 callOut( boost::bind(&Counter::advance, &count), 1 );
859 backend->doOneStep( 10 );
7e586023 860
cd9ddaee
RP
861 CPPUNIT_ASSERT_EQUAL( 0, count.value );
862 backend->doOneStep( 1100 );
7e586023 863
cd9ddaee
RP
864 CPPUNIT_ASSERT_EQUAL( 1, count.value );
865 } // eo CallOut1()
7e586023
RP
866
867
868
cd9ddaee
RP
869 void CallOut2()
870 {
871 Counter count;
7e586023 872
cd9ddaee
RP
873 callOut( boost::bind(&Counter::advance, &count), 0.5 );
874 backend->doOneStep( 10 );
7e586023 875
cd9ddaee
RP
876 CPPUNIT_ASSERT_EQUAL( 0, count.value );
877 backend->doOneStep( 800 );
7e586023 878
cd9ddaee
RP
879 CPPUNIT_ASSERT_EQUAL( 1, count.value );
880 } // eo CallOut2()
7e586023
RP
881
882
883
cd9ddaee
RP
884 void RemoveCallOut1()
885 {
886 Counter count;
7e586023 887
cd9ddaee
RP
888 CallOutId id= callOut( boost::bind(&Counter::advance, &count), 1 );
889 backend->doOneStep( 10 );
7e586023 890
cd9ddaee
RP
891 CPPUNIT_ASSERT_EQUAL( 0, count.value );
892 bool res1 = removeCallOut(id);
893 bool res2 = removeCallOut(id);
7e586023 894
cd9ddaee
RP
895 CPPUNIT_ASSERT_EQUAL( true, res1 );
896 CPPUNIT_ASSERT_EQUAL( false, res2 );
7e586023 897
cd9ddaee 898 backend->doOneStep( 1100 );
7e586023 899
cd9ddaee
RP
900 CPPUNIT_ASSERT_EQUAL( 0, count.value );
901 } // eo RemoveCallOut1()
7e586023
RP
902
903
904
cd9ddaee
RP
905 void FrozenCall_Thaw()
906 {
907 Counter count;
7e586023 908
cd9ddaee
RP
909 CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
910 backend->doOneStep( 10 );
7e586023 911
cd9ddaee
RP
912 CPPUNIT_ASSERT_EQUAL( 0, count.value );
913 id.thaw();
7e586023 914
cd9ddaee 915 backend->doOneStep( 1100 );
7e586023 916
cd9ddaee
RP
917 CPPUNIT_ASSERT_EQUAL( 1, count.value );
918 } // eo FrozenCall_Thaw()
7e586023
RP
919
920
921
cd9ddaee
RP
922 void FrozenCall_Decay()
923 {
924 Counter count;
7e586023 925
cd9ddaee
RP
926 CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
927 backend->doOneStep( 10 );
7e586023 928
cd9ddaee
RP
929 CPPUNIT_ASSERT_EQUAL( 0, count.value );
930 CPPUNIT_ASSERT_EQUAL( true, id.active() );
931 backend->doOneStep( 1100 );
7e586023 932
cd9ddaee
RP
933 CPPUNIT_ASSERT_EQUAL( 0, count.value );
934 CPPUNIT_ASSERT_EQUAL( false, id.active() );
935 } // eo FrozenCall_Decay()
7e586023
RP
936
937
938
cd9ddaee
RP
939 void UnixSockets_ClientServer()
940 {
941 std::string path= getCheckFilepath("UDS_CS");
7e586023 942
cd9ddaee
RP
943 UnixIOSocketHolder server_holder;
944 UnixServerSocket< TestUnixIOSocket > server_port;
945 UnixIOSocketPtr server;
946 TestUnixIOSocket client0;
947 TestUnixIOSocket client1;
7e586023 948
cd9ddaee
RP
949 bool res1 = server_port.open(path, 0600);
950 CPPUNIT_ASSERT_EQUAL( true, res1 );
7e586023 951
cd9ddaee 952 {
0630284f 953 AsyncIo::Utils::FileStat stat(path,false);
cd9ddaee
RP
954 CPPUNIT_ASSERT( stat.is_socket() );
955 CPPUNIT_ASSERT_EQUAL( 0600u, (stat.mode() & 0777));
956 }
7e586023 957
cd9ddaee
RP
958 server_port.setNewConnectionCallback(
959 boost::bind( &UnixIOSocketHolder::store, &server_holder, _1)
960 );
7e586023 961
cd9ddaee
RP
962 // open a first client
963 bool res2= client0.open(path);
964 CPPUNIT_ASSERT_EQUAL( true, res2 );
7e586023 965
cd9ddaee
RP
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() );
7e586023 970
cd9ddaee
RP
971 client0.sendData("a simple test string.");
972 backendStep(3,2);
7e586023 973
cd9ddaee
RP
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 );
7e586023 981
cd9ddaee
RP
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() );
7e586023 988
cd9ddaee
RP
989 server_holder.get(1)->sendData("::reply 2");
990 backendStep(3,2);
991 CPPUNIT_ASSERT_EQUAL( std::string("::reply 2"), client1.m_received_string );
7e586023 992
cd9ddaee
RP
993 client1.sendData("another simple test string. 124");
994 backendStep(3,2);
7e586023 995
cd9ddaee
RP
996 CPPUNIT_ASSERT_EQUAL(
997 std::string("another simple test string. 124"),
998 server_holder.get(1)->m_received_string
999 );
7e586023 1000
cd9ddaee
RP
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();
7e586023 1007
cd9ddaee
RP
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()
7e586023
RP
1015
1016
cd9ddaee
RP
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
7e586023
RP
1026
1027
cd9ddaee
RP
1028}; // eo class TestSimpleioBasics
1029
1030
1031CPPUNIT_TEST_SUITE_REGISTRATION(TestSimpleioBasics);