make kill() and pid() part of the public interface of ProcessImplementation
[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 *
436fb144 22 * (c) Copyright 2007-2010 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
4f6228c3
RP
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>
7e586023
RP
38#include <asyncio_system_tools.hpp>
39#include <asyncio_containerfunc.hpp>
436fb144 40
cd9ddaee
RP
41#include <boost/signal.hpp>
42#include <boost/bind.hpp>
43#include <boost/random.hpp>
44
436fb144
TJ
45#define BOOST_TEST_MAIN
46#define BOOST_TEST_DYN_LINK
47#include <boost/test/unit_test.hpp>
cd9ddaee
RP
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 58
cd9ddaee
RP
59namespace {
60
61
62struct Counter
63{
64 int value;
7e586023
RP
65
66
cd9ddaee 67 Counter() : value(0) { DOUT("Counter construct");}
7e586023 68
cd9ddaee 69 void reset() { value=0;}
7e586023 70
cd9ddaee
RP
71 void advance()
72 {
73 DOUT(" advance called");
74 ++value;
75 }
7e586023 76
cd9ddaee
RP
77 int operator()()
78 {
79 DOUT(" () called");
80 return ++value;
81 }
82}; // eo struct Counter
83
84
85class TestTimer : public TimerBase
86{
87 public:
7e586023 88
cd9ddaee
RP
89 TestTimer()
90 : m_counter(0u)
91 {
92 } // eo TestTimer()
7e586023
RP
93
94
cd9ddaee
RP
95 void setDelta(long msec)
96 {
97 setDeltaWhenTime(0,msec);
98 activate();
99 } // eo setDelta(long)
7e586023
RP
100
101
cd9ddaee 102 unsigned m_counter;
7e586023 103
cd9ddaee 104 protected:
7e586023 105
cd9ddaee
RP
106 virtual void execute()
107 {
108 ++m_counter;
109 } // eo execute()
7e586023 110
cd9ddaee
RP
111}; // eo class TestTimer
112
113
114
115struct ReceivedData
116{
117 std::vector<std::string> m_received_vector;
118 std::string m_received_string;
7e586023 119
cd9ddaee
RP
120 unsigned long m_count_lines;
121 unsigned long m_data_size;
7e586023
RP
122
123
cd9ddaee
RP
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&)
7e586023 140
cd9ddaee
RP
141}; // eo struct ReceivedData
142
143
144
145class 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
7e586023 155
cd9ddaee 156 protected:
7e586023 157
cd9ddaee
RP
158}; // eo class TestPipe
159
160
161class 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
172class 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>&)
7e586023 182
cd9ddaee
RP
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>&)
7e586023 193
cd9ddaee
RP
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
cd9ddaee 205 protected:
7e586023 206
cd9ddaee
RP
207 void slotReceivedData()
208 {
209 receiveData(m_input_buffer);
210 m_input_buffer.clear();
211 } // eo slotReceivedData()
7e586023 212
cd9ddaee
RP
213}; // eo class TestProcess
214
215
216
217class TestUnixIOSocket
218: public UnixIOSocket
219, public ReceivedData
220{
221 public:
7e586023 222
cd9ddaee
RP
223 TestUnixIOSocket()
224 : UnixIOSocket()
225 {
226 m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) );
227 } // eo TestUnixIOSocket()
7e586023
RP
228
229
cd9ddaee 230 TestUnixIOSocket(
6ac1fb46 231 int fd, const std::string& path
cd9ddaee 232 )
6ac1fb46 233 : UnixIOSocket(fd, path)
cd9ddaee
RP
234 {
235 m_signal_read.connect( boost::bind(&TestUnixIOSocket::slotReceivedData, this) );
236 } // eo TestUnixIOSocket()
7e586023
RP
237
238
cd9ddaee
RP
239 void sendData(const std::string& data)
240 {
241 lowSend(data);
242 } // eo sendData(const std::string&)
7e586023 243
cd9ddaee 244 protected:
7e586023 245
cd9ddaee
RP
246 void slotReceivedData()
247 {
248 receiveData(m_input_buffer);
249 m_input_buffer.clear();
250 } // eo slotReceivedData()
7e586023 251
cd9ddaee
RP
252}; // eo class TestUnixIOSocket
253
254typedef boost::shared_ptr< TestUnixIOSocket > TestUnixIOSocketPtr;
255
256
257class UnixIOSocketHolder
258: public std::vector< UnixIOSocketPtr >
259{
260 public:
7e586023 261
cd9ddaee
RP
262 void operator()(UnixIOSocketPtr ptr)
263 {
264 push_back(ptr);
265 }
7e586023 266
cd9ddaee
RP
267 void storeBase (IOImplementationPtr ptr)
268 {
269 push_back(boost::dynamic_pointer_cast< UnixIOSocket >(ptr) );
270 }
7e586023 271
cd9ddaee
RP
272 void store (UnixIOSocketPtr ptr)
273 {
274 push_back(ptr);
275 }
7e586023 276
cd9ddaee
RP
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).
287boost::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 */
295std::string makeRandomAsciiString(std::string::size_type len)
296{
297 static std::string chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz=+-*/%(){}<>.,:;\\");
298 std::string s;
7e586023 299
cd9ddaee
RP
300 boost::uniform_int<> discreter(0, chars.size()-1);
301 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > idxgen(g_random_gen, discreter);
7e586023 302
cd9ddaee 303 for(; len-->0;) s+= chars.at( idxgen() );
7e586023 304
cd9ddaee
RP
305 return s;
306} // eo makeRandomAsciiString
307
308
309} // eo namespace <anonymous>
310
311
436fb144 312class SimpleioBasicsFixture
cd9ddaee 313{
436fb144
TJ
314protected:
315 Backend *backend;
316 std::set<std::string> used_check_files;
7e586023 317
436fb144
TJ
318 template<class Callable>
319 bool backendLoopUntil( Callable condition, int maxLoops=100 )
320 {
321 for (int i=std::max(maxLoops,1); i-->0 && ! condition();)
cd9ddaee 322 {
436fb144
TJ
323 backend->doOneStep(10);
324 }
325 return condition();
326 } // eo backendLoopUntil
7e586023
RP
327
328
436fb144
TJ
329 bool backendStep(int msTimeout= 10, int count=1)
330 {
331 bool res= true;
332 for(;count-->0 && res;)
cd9ddaee 333 {
436fb144
TJ
334 res= backend->doOneStep(msTimeout);
335 }
336 return res;
337 } // eo backendStep
7e586023
RP
338
339
436fb144
TJ
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
7e586023
RP
347
348
436fb144
TJ
349 void removeCheckFiles()
350 {
351 for(std::set<std::string>::iterator it= used_check_files.begin();
352 it != used_check_files.end();
353 ++it)
cd9ddaee 354 {
436fb144
TJ
355 std::string filepath(*it);
356 if (Utils::FileStat(filepath))
cd9ddaee 357 {
436fb144 358 Utils::unlink(filepath);
cd9ddaee 359 }
436fb144
TJ
360 }
361 used_check_files.clear();
362 } // eo removeCheckFiles
7e586023 363
436fb144
TJ
364public:
365 SimpleioBasicsFixture()
366 {
367 backend = Backend::getBackend();
368 installChildHandler();
369 used_check_files.clear();
370 }
7e586023 371
436fb144
TJ
372 ~SimpleioBasicsFixture()
373 {
374 restoreChildHandler();
375 removeCheckFiles();
376 }
377};
7e586023 378
436fb144 379BOOST_FIXTURE_TEST_SUITE(TestSimpleioBasics, SimpleioBasicsFixture)
7e586023 380
436fb144
TJ
381BOOST_AUTO_TEST_CASE(EmptyBackendStepCall)
382{
383 BOOST_REQUIRE( backend );
7e586023 384
436fb144
TJ
385 // a backend call without active objects should return false:
386 bool result = backend->doOneStep(0);
7e586023 387
436fb144
TJ
388 BOOST_CHECK_EQUAL( false, result );
389} // eo EmptyBackendStepCall
7e586023 390
7e586023 391
7e586023 392
436fb144
TJ
393BOOST_AUTO_TEST_CASE(NonEmptyBackendStepCall)
394{
395 BOOST_REQUIRE(backend);
7e586023 396
436fb144
TJ
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
7e586023 410
cd9ddaee 411
7e586023 412
436fb144
TJ
413/**
414 * check for timer to execute immediatly.
415 */
416BOOST_AUTO_TEST_CASE(SingleTimerShot)
417{
418 BOOST_REQUIRE(backend);
7e586023 419
436fb144
TJ
420 TestTimer timer;
421 timer.setDelta(0); // shot now!
7e586023 422
436fb144 423 bool result = backend->doOneStep(10);
7e586023 424
436fb144
TJ
425 BOOST_CHECK_EQUAL( true, result );
426 // the timer should be executed once:
427 BOOST_CHECK_EQUAL( 1u, timer.m_counter );
7e586023 428
436fb144 429 result = backend->doOneStep(0);
7e586023 430
436fb144
TJ
431 BOOST_CHECK_EQUAL( false, result );
432 // the timer should not be executed again:
433 BOOST_CHECK_EQUAL( 1u, timer.m_counter );
7e586023 434
436fb144 435} // eo SingleTimerShot()
7e586023 436
7e586023 437
7e586023 438
436fb144
TJ
439/**
440 * tests a simple timer class to be executed with a timeout.
441 */
442BOOST_AUTO_TEST_CASE(SimpleTimerShot)
443{
444 bool res;
445 BOOST_REQUIRE(backend);
7e586023 446
436fb144
TJ
447 SimpleTimer timer1;
448 Counter counter1;
449 timer1.addAction( boost::bind(&Counter::advance,&counter1) );
450 BOOST_CHECK_EQUAL(false, timer1.active());
7e586023 451
436fb144
TJ
452 timer1.startTimerMS( 100 );
453 BOOST_CHECK_EQUAL(true, timer1.active());
7e586023 454
436fb144
TJ
455 res=backend->doOneStep( 1000 );
456 BOOST_CHECK_EQUAL( true, res );
7e586023 457
436fb144
TJ
458 BOOST_CHECK_EQUAL( 1, counter1.value );
459} // eo SimpleTimerShot
7e586023 460
7e586023 461
7e586023 462
436fb144
TJ
463/**
464 * tests 3 timers; after the first was active, disable another and check if the remaining one fires.
465 */
466BOOST_AUTO_TEST_CASE(SimpleTimerShot2)
467{
468 bool res;
469 BOOST_REQUIRE(backend);
7e586023 470
436fb144
TJ
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());
7e586023 479
436fb144
TJ
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());
7e586023 486
436fb144
TJ
487 res=backend->doOneStep( 1000 );
488 BOOST_CHECK_EQUAL( true, res );
7e586023 489
436fb144
TJ
490 BOOST_CHECK_EQUAL(false, timer1.active());
491 BOOST_CHECK_EQUAL(true, timer2.active());
492 BOOST_CHECK_EQUAL(true, timer3.active());
7e586023 493
436fb144
TJ
494 BOOST_CHECK_EQUAL( 1, counter1.value );
495 BOOST_CHECK_EQUAL( 0, counter2.value );
496 BOOST_CHECK_EQUAL( 0, counter3.value );
7e586023 497
436fb144
TJ
498 // now stop the next timer:
499 timer3.stopTimer();
500 BOOST_CHECK_EQUAL(false, timer3.active());
7e586023 501
436fb144
TJ
502 res=backend->doOneStep( 1000 );
503 BOOST_CHECK_EQUAL( true, res );
7e586023 504
436fb144
TJ
505 BOOST_CHECK_EQUAL( 1, counter1.value );
506 BOOST_CHECK_EQUAL( 1, counter2.value );
507 BOOST_CHECK_EQUAL( 0, counter3.value );
508} // eo SimpleTimerShot2
7e586023 509
7e586023 510
7e586023
RP
511
512
436fb144
TJ
513/*
514** I/O tests:
515*/
7e586023 516
436fb144
TJ
517BOOST_AUTO_TEST_CASE(EmptyWantTest)
518{
519 IOImplementation io;
7e586023 520
436fb144
TJ
521 BOOST_CHECK_EQUAL(false, io.wantRead() );
522 BOOST_CHECK_EQUAL(false, io.wantWrite() );
523} // eo EmptyWantTest
7e586023 524
7e586023 525
436fb144
TJ
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 */
541BOOST_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");
7e586023 545
436fb144 546 BOOST_REQUIRE(backend);
7e586023 547
436fb144 548 TestPipe pipe1, pipe2;
7e586023 549
436fb144 550 bool res= pipe1.makePipe(pipe2);
7e586023 551
436fb144
TJ
552 BOOST_CHECK_EQUAL(true, res);
553 BOOST_CHECK_EQUAL(true, pipe1.opened());
554 BOOST_CHECK_EQUAL(true, pipe2.opened());
7e586023 555
436fb144
TJ
556 res= backend->doOneStep(0);
557 BOOST_CHECK_EQUAL(true, res);
7e586023 558
436fb144 559 pipe1.sendString(test_string);
7e586023 560
436fb144
TJ
561 res= backend->doOneStep(0);
562 BOOST_CHECK_EQUAL(true, res);
7e586023 563
436fb144 564 BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string );
7e586023 565
436fb144 566 pipe2.sendString(test_string2);
7e586023 567
436fb144
TJ
568 res= backend->doOneStep(0);
569 BOOST_CHECK_EQUAL(true, res);
7e586023 570
436fb144 571 BOOST_CHECK_EQUAL( test_string2, pipe1.m_received_string );
7e586023 572
436fb144
TJ
573 pipe1.close();
574 BOOST_CHECK_EQUAL(false, pipe1.opened());
7e586023 575
436fb144
TJ
576 res= backend->doOneStep(0);
577 BOOST_CHECK_EQUAL(true, res);
7e586023 578
436fb144
TJ
579 BOOST_CHECK_EQUAL(true, pipe2.eof());
580} // eo SimplePipeTest
7e586023
RP
581
582
7e586023 583
436fb144
TJ
584/**
585 * sends a larger data chunk through a pipe.
586 * This tests if sending and receiving data in (smaller internal) chunks works.
587 */
588BOOST_AUTO_TEST_CASE(SimplePipePump)
589{
590 BOOST_REQUIRE(backend);
7e586023 591
436fb144 592 TestPipe pipe1, pipe2;
7e586023 593
436fb144 594 bool res= pipe1.makePipe(pipe2);
7e586023 595
436fb144
TJ
596 BOOST_CHECK_EQUAL(true, res);
597 BOOST_CHECK_EQUAL(true, pipe1.opened());
598 BOOST_CHECK_EQUAL(true, pipe2.opened());
7e586023 599
436fb144
TJ
600 res= backend->doOneStep(0);
601 BOOST_CHECK_EQUAL(true, res);
7e586023 602
436fb144 603 std::string test_string= makeRandomAsciiString(256*1024);
7e586023 604
436fb144 605 pipe1.sendString(test_string);
7e586023 606
436fb144
TJ
607 res= backend->doOneStep(0);
608 BOOST_CHECK_EQUAL(true, res);
7e586023 609
436fb144
TJ
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 };
7e586023 615
436fb144
TJ
616 pipe1.close();
617 BOOST_CHECK_EQUAL(false, pipe1.opened());
7e586023 618
436fb144
TJ
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 }
7e586023 624
436fb144
TJ
625 BOOST_CHECK_EQUAL( test_string.size(), pipe2.m_received_string.size() );
626 BOOST_CHECK_EQUAL( test_string, pipe2.m_received_string );
7e586023 627
436fb144
TJ
628 BOOST_CHECK_EQUAL(true, pipe2.eof());
629} // eo SimplePipePump
7e586023
RP
630
631
7e586023 632
436fb144
TJ
633/**
634 * fork a subprocess (/bin/true) and test exit code.
635 */
636BOOST_AUTO_TEST_CASE(SimpleProcessTestBinTrue)
637{
638 bool res;
639 BOOST_REQUIRE(backend);
7e586023 640
436fb144 641 TestProcess proc("/bin/true");
7e586023 642
436fb144
TJ
643 res= proc.startProcess();
644 BOOST_CHECK_EQUAL(true, res);
7e586023 645
436fb144
TJ
646 res= backend->doOneStep(200);
647 BOOST_CHECK_EQUAL(true, res);
7e586023 648
436fb144
TJ
649 for(int i=20; i-->0 && proc.processState() != ProcessState::stopped;)
650 {
651 backend->doOneStep(15);
652 }
7e586023 653
436fb144
TJ
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
7e586023 658
7e586023 659
436fb144
TJ
660/**
661 * fork a subprocess (/bin/false) and test exit code.
662 */
663BOOST_AUTO_TEST_CASE(SimpleProcessTestBinFalse)
664{
665 bool res;
666 BOOST_REQUIRE(backend);
7e586023 667
436fb144 668 TestProcess proc("/bin/false");
7e586023 669
436fb144
TJ
670 res= proc.startProcess();
671 BOOST_CHECK_EQUAL(true, res);
7e586023 672
436fb144
TJ
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 }
7e586023 679
436fb144
TJ
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
7e586023 685
7e586023 686
436fb144
TJ
687/**
688 * fork an echo subprocess and read back the output.
689 */
690BOOST_AUTO_TEST_CASE(SimpleProcessTestEcho)
691{
692 DOUT("enter SimpleProcessTestEcho");
693 bool res;
694 BOOST_REQUIRE(backend);
7e586023 695
436fb144
TJ
696 TestProcess proc(
697 "/bin/echo",
698 TransientPushBackFiller<std::string, std::vector >()("Eine")("Zeichenkette")
699 );
7e586023 700
436fb144
TJ
701 res= proc.startProcess();
702 BOOST_CHECK_EQUAL(true, res);
7e586023 703
436fb144
TJ
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 }
7e586023 710
436fb144
TJ
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
7e586023
RP
716
717
cd9ddaee 718
436fb144
TJ
719/**
720 * fork a bash subprocess, echo something on stderr and read back the output.
721 */
722BOOST_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");
7e586023 753
436fb144
TJ
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
7e586023
RP
761
762
7e586023 763
436fb144
TJ
764/**
765 * checks termination of process by signal and if the signal is returned.
766 */
767BOOST_AUTO_TEST_CASE(SignaledProcessTermination)
768{
769 bool res;
770 BOOST_REQUIRE(backend);
7e586023 771
436fb144
TJ
772 TestProcess proc("/bin/sleep","2");
773 res= proc.startProcess();
774 BOOST_CHECK_EQUAL(true, res);
7e586023 775
436fb144
TJ
776 res= backend->doOneStep(10);
777 BOOST_CHECK_EQUAL(true, res);
778 BOOST_CHECK_EQUAL( ProcessState(ProcessState::running), proc.processState() );
7e586023 779
436fb144 780 res= backend->doOneStep(50);
7e586023 781
436fb144
TJ
782 // now send the process an USR1 (which terminates the process)
783 res=proc.kill( Signal::USR1 );
784 BOOST_CHECK_EQUAL(true, res);
7e586023 785
436fb144
TJ
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);
7e586023 788
436fb144
TJ
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
7e586023
RP
793
794
7e586023 795
436fb144
TJ
796BOOST_AUTO_TEST_CASE(CallOut1)
797{
798 Counter count;
7e586023 799
436fb144
TJ
800 callOut( boost::bind(&Counter::advance, &count), 1 );
801 backend->doOneStep( 10 );
7e586023 802
436fb144
TJ
803 BOOST_CHECK_EQUAL( 0, count.value );
804 backend->doOneStep( 1100 );
7e586023 805
436fb144
TJ
806 BOOST_CHECK_EQUAL( 1, count.value );
807} // eo CallOut1()
7e586023
RP
808
809
7e586023 810
436fb144
TJ
811BOOST_AUTO_TEST_CASE(CallOut2)
812{
813 Counter count;
7e586023 814
436fb144
TJ
815 callOut( boost::bind(&Counter::advance, &count), 0.5 );
816 backend->doOneStep( 10 );
7e586023 817
436fb144
TJ
818 BOOST_CHECK_EQUAL( 0, count.value );
819 backend->doOneStep( 800 );
7e586023 820
436fb144
TJ
821 BOOST_CHECK_EQUAL( 1, count.value );
822} // eo CallOut2()
7e586023
RP
823
824
7e586023 825
436fb144
TJ
826BOOST_AUTO_TEST_CASE(RemoveCallOut1)
827{
828 Counter count;
7e586023 829
436fb144
TJ
830 CallOutId id= callOut( boost::bind(&Counter::advance, &count), 1 );
831 backend->doOneStep( 10 );
7e586023 832
436fb144
TJ
833 BOOST_CHECK_EQUAL( 0, count.value );
834 bool res1 = removeCallOut(id);
835 bool res2 = removeCallOut(id);
7e586023 836
436fb144
TJ
837 BOOST_CHECK_EQUAL( true, res1 );
838 BOOST_CHECK_EQUAL( false, res2 );
7e586023 839
436fb144 840 backend->doOneStep( 1100 );
7e586023 841
436fb144
TJ
842 BOOST_CHECK_EQUAL( 0, count.value );
843} // eo RemoveCallOut1()
7e586023
RP
844
845
7e586023 846
436fb144
TJ
847BOOST_AUTO_TEST_CASE(FrozenCall_Thaw)
848{
849 Counter count;
7e586023 850
436fb144
TJ
851 CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
852 backend->doOneStep( 10 );
7e586023 853
436fb144
TJ
854 BOOST_CHECK_EQUAL( 0, count.value );
855 id.thaw();
7e586023 856
436fb144 857 backend->doOneStep( 1100 );
7e586023 858
436fb144
TJ
859 BOOST_CHECK_EQUAL( 1, count.value );
860} // eo FrozenCall_Thaw()
7e586023
RP
861
862
7e586023 863
436fb144
TJ
864BOOST_AUTO_TEST_CASE(FrozenCall_Decay)
865{
866 Counter count;
7e586023 867
436fb144
TJ
868 CallOutId id= frozenCall( boost::bind(&Counter::advance, &count), 1 );
869 backend->doOneStep( 10 );
7e586023 870
436fb144
TJ
871 BOOST_CHECK_EQUAL( 0, count.value );
872 BOOST_CHECK_EQUAL( true, id.active() );
873 backend->doOneStep( 1100 );
7e586023 874
436fb144
TJ
875 BOOST_CHECK_EQUAL( 0, count.value );
876 BOOST_CHECK_EQUAL( false, id.active() );
877} // eo FrozenCall_Decay()
7e586023
RP
878
879
7e586023 880
436fb144
TJ
881BOOST_AUTO_TEST_CASE(UnixSockets_ClientServer)
882{
883 std::string path= getCheckFilepath("UDS_CS");
7e586023 884
436fb144
TJ
885 UnixIOSocketHolder server_holder;
886 UnixServerSocket< TestUnixIOSocket > server_port;
887 UnixIOSocketPtr server;
888 TestUnixIOSocket client0;
889 TestUnixIOSocket client1;
7e586023 890
436fb144
TJ
891 bool res1 = server_port.open(path, 0600);
892 BOOST_CHECK_EQUAL( true, res1 );
7e586023 893
436fb144
TJ
894 {
895 AsyncIo::Utils::FileStat stat(path,false);
896 BOOST_REQUIRE( stat.is_socket() );
897 BOOST_CHECK_EQUAL( 0600u, (stat.mode() & 0777));
898 }
7e586023 899
436fb144
TJ
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()
7e586023 957
cd9ddaee 958
436fb144
TJ
959/*
960BOOST_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*/
cd9ddaee 970
436fb144 971BOOST_AUTO_TEST_SUITE_END()