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