libt2n: (tomj) don't use std::auto_ptr in command_client, the pointer will get lost...
[libt2n] / test / timeout.cpp
CommitLineData
45a2ebc9
GE
1/***************************************************************************
2 * Copyright (C) 2004 by Intra2net AG *
3 * info@intra2net.com *
4 * *
5 ***************************************************************************/
6
7#include <sys/types.h>
8#include <unistd.h>
9#include <errno.h>
10#include <signal.h>
11#include <stdio.h>
12
13#include <iostream>
14#include <string>
15#include <sstream>
16#include <stdexcept>
17
18#include <boost/bind.hpp>
19
20#include <cppunit/extensions/TestFactoryRegistry.h>
21#include <cppunit/ui/text/TestRunner.h>
22#include <cppunit/extensions/HelperMacros.h>
23
24#include <boost/archive/binary_oarchive.hpp>
25#include <boost/archive/binary_iarchive.hpp>
26#include <boost/archive/xml_oarchive.hpp>
27#include <boost/archive/xml_iarchive.hpp>
28#include <boost/serialization/serialization.hpp>
29
30#include <container.hxx>
31#include <socket_client.hxx>
32#include <socket_server.hxx>
33#include <command_client.hxx>
34#include <command_server.hxx>
35
36#ifdef HAVE_CONFIG_H
37#include <config.h>
38#endif
39
40using namespace std;
41using namespace libt2n;
42using namespace CppUnit;
43
44string testfunc2(const string& str)
45{
46 if (str=="throw")
47 throw libt2n::t2n_runtime_error("throw me around");
48 string ret(str);
49 ret+=", testfunc() was here";
50 return ret;
51}
52
53class testfunc2_res : public libt2n::result
54{
55 private:
56 string res;
57
58 friend class boost::serialization::access;
59 template<class Archive>
60 void serialize(Archive & ar, const unsigned int version)
61 {
62 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
63 ar & BOOST_SERIALIZATION_NVP(res);
64 }
65
66 public:
67 testfunc2_res()
68 { }
69
70 testfunc2_res(const string& str)
71 {
72 res=str;
73 }
74
75 string get_data()
76 {
77 return res;
78 }
79};
80
81
82class testfunc2_cmd : public libt2n::command
83{
84 private:
85 string param;
86
87 friend class boost::serialization::access;
88 template<class Archive>
89 void serialize(Archive & ar, const unsigned int version)
90 {
91 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
92 ar & BOOST_SERIALIZATION_NVP(param);
93 }
94
95 public:
96 testfunc2_cmd()
97 { }
98
99 testfunc2_cmd(const string& str)
100 {
101 param=str;
102 }
103
104 libt2n::result* operator()()
105 {
106 return new testfunc2_res(testfunc2(param));
107 }
108};
109
110#include <boost/serialization/export.hpp>
111
112BOOST_CLASS_EXPORT(testfunc2_cmd)
113BOOST_CLASS_EXPORT(testfunc2_res)
114
115// this is an evil hack to get access to real_write, don't ever do this in an app!!!
116class real_write_connection: public socket_server_connection
117{
118 public:
119 void real_write(const std::string& data)
120 { socket_write(data); }
121};
122
c7857475
GE
123// this is an evil hack to get access to real_write, don't ever do this in an app!!!
124class real_write_client_connection: public socket_client_connection
125{
126 public:
127 void real_write(const std::string& data)
128 { socket_write(data); }
129};
130
45a2ebc9
GE
131class test_timeout : public TestFixture
132{
133 CPPUNIT_TEST_SUITE(test_timeout);
134
c7857475 135 CPPUNIT_TEST(ConnectTimeout);
45a2ebc9
GE
136 CPPUNIT_TEST(HelloTimeoutNothing);
137 CPPUNIT_TEST(HelloTimeoutSlowData);
138 CPPUNIT_TEST(CommandTimeout);
139 CPPUNIT_TEST(CommandSlowResponse);
c7857475 140 CPPUNIT_TEST(DisconnectOnWrite);
039e52da 141 CPPUNIT_TEST(WriteTwice);
c7857475
GE
142 CPPUNIT_TEST(DisconnectOnRead);
143 CPPUNIT_TEST(BreakAccept);
45a2ebc9
GE
144
145 CPPUNIT_TEST_SUITE_END();
146
b5922184
GE
147 pid_t child_pid;
148
45a2ebc9
GE
149 public:
150
151 typedef uint32_t packet_size_indicator;
152
153 void setUp()
154 { }
155
156 void tearDown()
b5922184
GE
157 {
158 // make sure the server-child is dead before the next test runs
159 kill(child_pid,SIGKILL);
160 sleep(1);
161 }
45a2ebc9
GE
162
163 void send_hello(string hello_string, socket_server* ss, unsigned int conn_id)
164 {
165 server_connection *sc=ss->get_connection(conn_id);
166 sc->write(hello_string);
167 }
168
169 void send_slow_raw_socket(string data, socket_server* ss, unsigned int conn_id)
170 {
171 socket_server_connection *ssc=dynamic_cast<socket_server_connection*>(ss->get_connection(conn_id));
172
173 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
174 real_write_connection *rwc=(real_write_connection*)ssc;
175
176 // we write one char each 0.2 sec
177 for (int pos=0; pos < data.size(); pos++)
178 {
179 string onebyte;
180 onebyte+=data[pos];
181 rwc->real_write(onebyte);
182 usleep(200000);
183 }
184 }
185
c7857475
GE
186 void ConnectTimeout()
187 {
b5922184 188 switch(child_pid=fork())
c7857475
GE
189 {
190 case -1:
191 {
192 CPPUNIT_FAIL("fork error");
193 break;
194 }
195 case 0:
196 // child
197 {
198 socket_server ss("./socket");
199
200 // don't call atexit and stuff
201 _exit(0);
202 }
203
204 default:
205 // parent
206 {
207 string data;
208
209 // wait till server is up
210 sleep(1);
211
212 string errormsg;
213
fb3345ad 214 socket_client_connection sc("./socket");
c7857475 215
b5922184
GE
216 CPPUNIT_ASSERT_EQUAL_MESSAGE("connection not closed",true,sc.connection::is_closed());
217
218 CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong errormessage",string("no more retries left after connect error"),sc.get_last_error_msg());
c7857475
GE
219 }
220 }
221 }
222
45a2ebc9
GE
223 void HelloTimeoutNothing()
224 {
b5922184 225 switch(child_pid=fork())
45a2ebc9
GE
226 {
227 case -1:
228 {
229 CPPUNIT_FAIL("fork error");
230 break;
231 }
232 case 0:
233 // child
234 {
235 socket_server ss("./socket");
236
237 // max 10 sec
238 for (int i=0; i < 10; i++)
239 ss.fill_buffer(1000000);
240 // don't call atexit and stuff
241 _exit(0);
242 }
243
244 default:
245 // parent
246 {
247 string data;
248
249 // wait till server is up
250 sleep(1);
251 socket_client_connection sc("./socket");
b5922184 252 command_client cc(&sc,1000000,1000000);
45a2ebc9 253
b5922184 254 t2n_exception* ep=cc.get_constuctor_exception();
45a2ebc9 255
b5922184
GE
256 string errormsg;
257 if (ep)
258 errormsg=ep->what();
45a2ebc9
GE
259
260 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
261 }
262 }
263 }
264
265 void HelloTimeoutSlowData()
266 {
b5922184 267 switch(child_pid=fork())
45a2ebc9
GE
268 {
269 case -1:
270 {
271 CPPUNIT_FAIL("fork error");
272 break;
273 }
274 case 0:
275 // child
276 {
277 socket_server ss("./socket");
278
279 // create a valid packet
280 ostringstream hello;
281 hello << "T2Nv" << PROTOCOL_VERSION << ';';
282 int byteordercheck=1;
283 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
284 hello << ';';
285
286 packet_size_indicator psize=htonl(hello.str().size());
287 std::string send_data(hello.str());
288 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
289
290 ss.add_callback(new_connection,bind(&test_timeout::send_slow_raw_socket, boost::ref(*this), send_data,&ss, _1));
291
292 // max 10 sec
293 for (int i=0; i < 10; i++)
294 ss.fill_buffer(1000000);
295 // don't call atexit and stuff
296 _exit(0);
297 }
298
299 default:
300 // parent
301 {
302 string data;
303
304 // wait till server is up
305 sleep(1);
306 socket_client_connection sc("./socket");
b5922184 307 command_client cc(&sc,1000000,1000000);
45a2ebc9 308
b5922184 309 t2n_exception* ep=cc.get_constuctor_exception();
45a2ebc9 310
b5922184
GE
311 string errormsg;
312 if (ep)
313 errormsg=ep->what();
45a2ebc9
GE
314
315 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
316 }
317 }
318 }
319
320 void CommandTimeout()
321 {
b5922184 322 switch(child_pid=fork())
45a2ebc9
GE
323 {
324 case -1:
325 {
326 CPPUNIT_FAIL("fork error");
327 break;
328 }
329 case 0:
330 // child
331 {
332 socket_server ss("./socket");
333
334 ostringstream hello;
335 hello << "T2Nv" << PROTOCOL_VERSION << ';';
336 int byteordercheck=1;
337 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
338 hello << ';';
339
340 ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1));
341
342 // max 10 sec
343 for (int i=0; i < 10; i++)
344 ss.fill_buffer(1000000);
345 // don't call atexit and stuff
346 _exit(0);
347 }
348
349 default:
350 // parent
351 {
352 string data;
353
354 // wait till server is up
355 sleep(1);
356 socket_client_connection sc("./socket");
357
fb3345ad 358 command_client cc(&sc,1000000,1000000);
45a2ebc9
GE
359 result_container rc;
360
361 string errormsg;
362
363 try
364 {
365 cc.send_command(new testfunc2_cmd("hello"),rc);
366 }
367 catch(t2n_transfer_error &e)
368 { errormsg=e.what(); }
369 catch(...)
370 { throw; }
371
372 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
373 }
374 }
375 }
376
377 void CommandSlowResponse()
378 {
b5922184 379 switch(child_pid=fork())
45a2ebc9
GE
380 {
381 case -1:
382 {
383 CPPUNIT_FAIL("fork error");
384 break;
385 }
386 case 0:
387 // child
388 {
389 socket_server ss("./socket");
390
391 ostringstream hello;
392 hello << "T2Nv" << PROTOCOL_VERSION << ';';
393 int byteordercheck=1;
394 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
395 hello << ';';
396
397 ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1));
398
399 // max 10 sec
400 for (int i=0; i < 10; i++)
401 {
402 ss.fill_buffer(1000000);
403
404 string data;
405 unsigned int cid;
406
407 if(ss.get_packet(data,cid))
408 {
409 // create a valid packet & send
410 string response="abcdefghijklmnopqrstuvwxyz";
411 packet_size_indicator psize=htonl(response.size());
412 std::string send_data(response);
413 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
414 send_slow_raw_socket(send_data,&ss,cid);
415 }
416 }
417 // don't call atexit and stuff
418 _exit(0);
419 }
420
421 default:
422 // parent
423 {
424 string data;
425
426 // wait till server is up
427 sleep(1);
428 socket_client_connection sc("./socket");
429
fb3345ad 430 command_client cc(&sc,1000000,1000000);
45a2ebc9
GE
431 result_container rc;
432
433 string errormsg;
434
435 try
436 {
437 cc.send_command(new testfunc2_cmd("hello"),rc);
438 }
439 catch(t2n_transfer_error &e)
440 { errormsg=e.what(); }
441 catch(...)
442 { throw; }
443
444 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
445 }
446 }
447 }
448
c7857475
GE
449 void DisconnectOnWrite()
450 {
b5922184 451 switch(child_pid=fork())
c7857475
GE
452 {
453 case -1:
454 {
455 CPPUNIT_FAIL("fork error");
456 break;
457 }
458 case 0:
459 // child
460 {
461 socket_server ss("./socket");
462
463 // bail out as soon as we get something
464 ss.fill_buffer(-1);
465 // don't call atexit and stuff
466 _exit(0);
467 }
468
469 default:
470 // parent
471 {
472 string data;
473
474 // don't kill us on broken pipe
475 signal(SIGPIPE, SIG_IGN);
476
477 // wait till server is up
478 sleep(1);
479 socket_client_connection sc("./socket");
480
481 string errormsg;
482
e72e07f3 483 string huge(5000000,'x');
c7857475
GE
484
485 try
486 {
487 sc.write(huge);
488 }
489 catch(t2n_transfer_error &e)
490 { errormsg=e.what(); }
491 catch(...)
492 { throw; }
493
494 CPPUNIT_ASSERT_EQUAL(string("write() returned Broken pipe"),errormsg);
495 }
496 }
497 }
498
039e52da
GE
499 void WriteTwice()
500 {
501 switch(child_pid=fork())
502 {
503 case -1:
504 {
505 CPPUNIT_FAIL("fork error");
506 break;
507 }
508 case 0:
509 // child
510 {
511 socket_server ss("./socket");
512
513 // bail out as soon as we get something
514 ss.fill_buffer(-1);
56f3994d 515 ss.fill_buffer(-1);
039e52da
GE
516 // don't call atexit and stuff
517 _exit(0);
518 }
519
520 default:
521 // parent
522 {
523 string data;
524
525 // don't kill us on broken pipe
526 signal(SIGPIPE, SIG_IGN);
527
528 // wait till server is up
529 sleep(1);
530 socket_client_connection sc("./socket");
531
532 string errormsg;
533
534 sc.write("somedata");
535
536 sleep(1);
537
538 // server should disconnect now
539 try
540 {
541 sc.write("other data");
542 }
543 catch(t2n_transfer_error &e)
544 { errormsg=e.what(); }
545 catch(...)
546 { throw; }
547
548 CPPUNIT_ASSERT_EQUAL(string("write() returned Broken pipe"),errormsg);
549 }
550 }
551 }
552
c7857475
GE
553 void DisconnectOnRead()
554 {
b5922184 555 pid_t pid2;
c7857475 556
b5922184 557 switch(child_pid=fork())
c7857475
GE
558 {
559 case -1:
560 {
561 CPPUNIT_FAIL("fork error");
562 break;
563 }
564 case 0:
565 // child
566 {
567 // wait till server is up
568 sleep(1);
569
570 socket_client_connection sc("./socket");
571
572 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
573 real_write_client_connection *rwc=(real_write_client_connection*)&sc;
574 rwc->real_write(string(10000,'x'));
575
576 // don't call atexit and stuff
577 _exit(0);
578 }
579
580 default:
581 // parent
582 {
583 // don't kill us on broken pipe
584 signal(SIGPIPE, SIG_IGN);
585
586 socket_server ss("./socket");
587
588 time_t t0 = time(NULL);
589
590 // max 5 sec
591 while (time(NULL) < t0 + 5 )
592 {
593 ss.fill_buffer(1000000);
594
595 string data;
596 ss.get_packet(data);
597 }
598
599 // are we still alive and able to process data?
600
fb3345ad 601 switch(pid2=fork())
c7857475
GE
602 {
603 case -1:
604 {
605 CPPUNIT_FAIL("fork error");
606 break;
607 }
608 case 0:
609 // child
610 {
611 socket_client_connection *sc=new socket_client_connection("./socket");
612 sc->write(string(10000,'x'));
613 delete sc;
614 // socket is closed regularly
615
616 // don't run regular cleanup, otherwise cppunit stuff gets called
617 _exit(0);
618 }
619
620 default:
621 // parent
622 {
623 string received;
624
625 t0 = time(NULL);
626
627 // max 10 sec
628 while (time(NULL) < t0 + 10 )
629 {
630 ss.fill_buffer(1000000);
631
632 if (ss.get_packet(received))
633 break;
634 }
635
636 CPPUNIT_ASSERT_EQUAL(string(10000,'x'),received);
637 }
638 }
639 }
640 }
fb3345ad 641 kill(pid2,SIGKILL);
c7857475
GE
642 }
643
644 void BreakAccept()
645 {
b5922184 646 pid_t pid2;
c7857475 647
b5922184 648 switch(child_pid=fork())
c7857475
GE
649 {
650 case -1:
651 {
652 CPPUNIT_FAIL("fork error");
653 break;
654 }
655 case 0:
656 // child
657 {
658 // wait till server is really up and waiting
659 sleep(2);
660
661 // connect with very tight timeout and only 1 retry
662 socket_client_connection sc("./socket",50,1);
663
664 // don't call atexit and stuff
665 _exit(0);
666 }
667
668 default:
669 // parent
670 {
671 // don't kill us on broken pipe
672 signal(SIGPIPE, SIG_IGN);
673
674 socket_server ss("./socket");
675
676 // server is "working" while client wants to connect
677 sleep(5);
678
679 time_t t0 = time(NULL);
680
681 // max 5 sec
682 while (time(NULL) < t0 + 5 )
683 {
684 ss.fill_buffer(1000000);
685
686 string data;
687 ss.get_packet(data);
688 }
689
690 // are we still alive and able to process data?
691
fb3345ad 692 switch(pid2=fork())
c7857475
GE
693 {
694 case -1:
695 {
696 CPPUNIT_FAIL("fork error");
697 break;
698 }
699 case 0:
700 // child
701 {
702 socket_client_connection *sc=new socket_client_connection("./socket");
703 sc->write(string(10000,'x'));
704 delete sc;
705 // socket is closed regularly
706
707 // don't run regular cleanup, otherwise cppunit stuff gets called
708 _exit(0);
709 }
710
711 default:
712 // parent
713 {
714 string received;
715
716 t0 = time(NULL);
717
718 // max 10 sec
719 while (time(NULL) < t0 + 10 )
720 {
721 ss.fill_buffer(1000000);
722
723 if (ss.get_packet(received))
724 break;
725 }
726
727 CPPUNIT_ASSERT_EQUAL(string(10000,'x'),received);
728 }
729 }
730 }
731 }
fb3345ad 732 kill(pid2,SIGKILL);
c7857475 733 }
45a2ebc9
GE
734};
735
736CPPUNIT_TEST_SUITE_REGISTRATION(test_timeout);