Migrate from cppunit to Boost.test
[libt2n] / test / reconnect.cpp
CommitLineData
19facd85
TJ
1/*
2Copyright (C) 2004 by Intra2net AG
af84dfb5 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*/
af84dfb5
GE
22#include <sys/types.h>
23#include <unistd.h>
24#include <errno.h>
25#include <signal.h>
26#include <stdio.h>
4c3662a0 27#include <time.h>
af84dfb5
GE
28
29#include <iostream>
30#include <string>
31#include <sstream>
32#include <stdexcept>
33
307b5e74
TJ
34#define BOOST_TEST_DYN_LINK
35#include <boost/test/unit_test.hpp>
af84dfb5
GE
36
37#include <socket_client.hxx>
38#include <socket_server.hxx>
39
307b5e74
TJ
40#include "test_fixtures.hxx"
41
af84dfb5
GE
42#ifdef HAVE_CONFIG_H
43#include <config.h>
44#endif
45
46using namespace std;
47using namespace libt2n;
af84dfb5
GE
48
49// this is an evil hack to get access to real_write, don't ever do this in an app!!!
50class real_write_connection: public socket_server_connection
51{
52 public:
53 void real_write(const std::string& data)
54 { socket_write(data); }
55};
56
307b5e74 57class test_reconnectFixture : public KillChildOnShutdownFixture
af84dfb5 58{
307b5e74 59protected:
af84dfb5
GE
60 void send_raw_socket(string hello_string, socket_server* ss, int conn_id)
61 {
62 socket_server_connection *ssc=dynamic_cast<socket_server_connection*>(ss->get_connection(conn_id));
63
64 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
65 real_write_connection *rwc=(real_write_connection*)ssc;
66 rwc->real_write(hello_string);
67 }
68
307b5e74
TJ
69public:
70 test_reconnectFixture()
af84dfb5 71 {
307b5e74
TJ
72 }
73
74 ~test_reconnectFixture()
75 {
76 }
77};
78
79BOOST_FIXTURE_TEST_SUITE(test_reconnect, test_reconnectFixture)
80
81BOOST_AUTO_TEST_CASE(simple_reconnect)
82{
83 switch(child_pid=fork())
84 {
85 case -1:
af84dfb5 86 {
307b5e74
TJ
87 BOOST_FAIL("fork error");
88 break;
89 }
90 case 0:
91 // child
92 {
93 try
af84dfb5 94 {
307b5e74 95 socket_server ss("./socket");
af84dfb5 96
307b5e74 97 time_t t0 = time(NULL);
af84dfb5 98
307b5e74
TJ
99 // max 10 sec
100 while (time(NULL) < t0 + 10 )
101 {
102 ss.fill_buffer(1000000);
441d41fe 103
307b5e74
TJ
104 string data;
105 unsigned int cid;
441d41fe 106
307b5e74
TJ
107 if(ss.get_packet(data,cid))
108 {
109 server_connection* con=ss.get_connection(cid);
af84dfb5 110
307b5e74
TJ
111 if (data=="QUIT")
112 break;
af84dfb5 113
307b5e74
TJ
114 if (data=="x")
115 con->write(string().insert(0,100,'X'));
116 else
117 con->write(string().insert(0,100,'Y'));
af84dfb5
GE
118 }
119 }
307b5e74
TJ
120 } catch(...)
121 {
122 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
123 }
124
307b5e74
TJ
125 // don't call atexit and stuff
126 _exit(0);
127 }
af84dfb5 128
307b5e74
TJ
129 default:
130 // parent
131 {
132 // don't kill us on broken pipe
133 signal(SIGPIPE, SIG_IGN);
af84dfb5 134
307b5e74
TJ
135 // wait till server is up
136 sleep(1);
137 socket_client_connection sc("./socket");
af84dfb5 138
307b5e74 139 sc.write("abc");
af84dfb5 140
307b5e74 141 string data;
af84dfb5 142
307b5e74
TJ
143 while (!sc.get_packet(data))
144 sc.fill_buffer(1000000);
af84dfb5 145
307b5e74 146 sc.reconnect();
af84dfb5 147
307b5e74 148 sc.write("x");
af84dfb5 149
307b5e74
TJ
150 while (!sc.get_packet(data))
151 sc.fill_buffer(1000000);
152
153 BOOST_CHECK_EQUAL(string().insert(0,100,'X'),data);
af84dfb5
GE
154 }
155 }
307b5e74 156}
af84dfb5 157
307b5e74
TJ
158BOOST_AUTO_TEST_CASE(reconnect_with_close)
159{
160 switch(child_pid=fork())
af84dfb5 161 {
307b5e74 162 case -1:
af84dfb5 163 {
307b5e74
TJ
164 BOOST_FAIL("fork error");
165 break;
166 }
167 case 0:
168 // child
169 {
170 try
af84dfb5 171 {
307b5e74 172 socket_server ss("./socket");
af84dfb5 173
307b5e74 174 time_t t0 = time(NULL);
af84dfb5 175
307b5e74
TJ
176 // max 10 sec
177 while (time(NULL) < t0 + 10 )
178 {
179 ss.fill_buffer(1000000);
af84dfb5 180
307b5e74
TJ
181 string data;
182 unsigned int cid;
af84dfb5 183
307b5e74
TJ
184 if(ss.get_packet(data,cid))
185 {
186 server_connection* con=ss.get_connection(cid);
441d41fe 187
307b5e74
TJ
188 if (data=="QUIT")
189 break;
441d41fe 190
307b5e74
TJ
191 if (data=="x")
192 con->write(string().insert(0,100,'X'));
193 else
194 con->write(string().insert(0,100,'Y'));
af84dfb5
GE
195 }
196 }
307b5e74
TJ
197 } catch(...)
198 {
199 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
200 }
201
307b5e74
TJ
202 // don't call atexit and stuff
203 _exit(0);
204 }
af84dfb5 205
307b5e74
TJ
206 default:
207 // parent
208 {
209 // don't kill us on broken pipe
210 signal(SIGPIPE, SIG_IGN);
af84dfb5 211
307b5e74
TJ
212 // wait till server is up
213 sleep(1);
214 socket_client_connection sc("./socket");
af84dfb5 215
307b5e74 216 sc.write("abc");
af84dfb5 217
307b5e74 218 string data;
af84dfb5 219
307b5e74
TJ
220 while (!sc.get_packet(data))
221 sc.fill_buffer(1000000);
af84dfb5 222
307b5e74 223 sc.close();
af84dfb5 224
307b5e74
TJ
225 // empty buffer
226 sc.get_packet(data);
af84dfb5 227
307b5e74 228 sc.reconnect();
af84dfb5 229
307b5e74 230 sc.write("x");
af84dfb5 231
307b5e74
TJ
232 while (!sc.get_packet(data))
233 sc.fill_buffer(1000000);
234
235 BOOST_CHECK_EQUAL(string().insert(0,100,'X'),data);
af84dfb5
GE
236 }
237 }
307b5e74 238}
af84dfb5 239
307b5e74
TJ
240BOOST_AUTO_TEST_CASE(reconnect_buffer_complete)
241{
242 switch(child_pid=fork())
af84dfb5 243 {
307b5e74 244 case -1:
af84dfb5 245 {
307b5e74
TJ
246 BOOST_FAIL("fork error");
247 break;
248 }
249 case 0:
250 // child
251 {
252 try
af84dfb5 253 {
307b5e74 254 socket_server ss("./socket");
af84dfb5 255
307b5e74 256 time_t t0 = time(NULL);
af84dfb5 257
307b5e74
TJ
258 // max 10 sec
259 while (time(NULL) < t0 + 10 )
260 {
261 ss.fill_buffer(1000000);
441d41fe 262
307b5e74
TJ
263 string data;
264 unsigned int cid;
441d41fe 265
307b5e74
TJ
266 if(ss.get_packet(data,cid))
267 {
268 server_connection* con=ss.get_connection(cid);
af84dfb5 269
307b5e74
TJ
270 if (data=="QUIT")
271 break;
af84dfb5 272
307b5e74
TJ
273 if (data=="x")
274 con->write(string().insert(0,100,'X'));
af84dfb5
GE
275 }
276 }
307b5e74
TJ
277 } catch(...)
278 {
279 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
280 }
281
307b5e74
TJ
282 // don't call atexit and stuff
283 _exit(0);
284 }
af84dfb5 285
307b5e74
TJ
286 default:
287 // parent
288 {
289 // don't kill us on broken pipe
290 signal(SIGPIPE, SIG_IGN);
af84dfb5 291
307b5e74
TJ
292 // wait till server is up
293 sleep(1);
294 socket_client_connection sc("./socket");
af84dfb5 295
307b5e74 296 sc.write("x");
af84dfb5 297
307b5e74 298 string data;
af84dfb5 299
307b5e74
TJ
300 while (!sc.packet_available())
301 sc.fill_buffer(1000000);
af84dfb5 302
307b5e74 303 sc.reconnect();
af84dfb5 304
307b5e74
TJ
305 BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, "packet not there");
306
307 BOOST_CHECK_MESSAGE(data == string().insert(0,100,'X'), "data incorrect");
af84dfb5
GE
308 }
309 }
307b5e74 310}
af84dfb5 311
307b5e74
TJ
312BOOST_AUTO_TEST_CASE(reconnect_buffer_several_complete)
313{
314 const int packets=3;
af84dfb5 315
307b5e74
TJ
316 switch(child_pid=fork())
317 {
318 case -1:
af84dfb5 319 {
307b5e74
TJ
320 BOOST_FAIL("fork error");
321 break;
322 }
323 case 0:
324 // child
325 {
326 try
af84dfb5 327 {
307b5e74
TJ
328 socket_server ss("./socket");
329
330 time_t t0 = time(NULL);
331
332 // max 10 sec
333 while (time(NULL) < t0 + 10 )
af84dfb5 334 {
307b5e74 335 ss.fill_buffer(1000000);
af84dfb5 336
307b5e74
TJ
337 string data;
338 unsigned int cid;
af84dfb5 339
307b5e74 340 if(ss.get_packet(data,cid))
af84dfb5 341 {
307b5e74 342 server_connection* con=ss.get_connection(cid);
af84dfb5 343
307b5e74
TJ
344 if (data=="QUIT")
345 break;
af84dfb5 346
307b5e74 347 if (data=="x")
af84dfb5 348 {
307b5e74
TJ
349 for (int i=0; i<packets; i++)
350 con->write(string().insert(0,100,'X'));
af84dfb5
GE
351 }
352 }
353 }
307b5e74
TJ
354 } catch(...)
355 {
356 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
357 }
358
307b5e74
TJ
359 // don't call atexit and stuff
360 _exit(0);
361 }
af84dfb5 362
307b5e74
TJ
363 default:
364 // parent
365 {
366 // don't kill us on broken pipe
367 signal(SIGPIPE, SIG_IGN);
af84dfb5 368
307b5e74
TJ
369 // wait till server is up
370 sleep(1);
371 socket_client_connection sc("./socket");
af84dfb5 372
307b5e74 373 sc.write("x");
af84dfb5 374
307b5e74
TJ
375 // retrieve packets for 3 seconds
376 time_t t0 = time(NULL);
af84dfb5 377
307b5e74
TJ
378 // max 3 sec
379 while (time(NULL) < t0 + 3 )
380 sc.fill_buffer(1000000);
af84dfb5 381
307b5e74 382 // we now should have packets complete packets in the buffer
af84dfb5 383
307b5e74 384 sc.reconnect();
af84dfb5 385
307b5e74 386 // are these packets still there?
af84dfb5 387
307b5e74
TJ
388 for (int i=0; i < packets; i++)
389 {
390 string data;
af84dfb5 391
307b5e74
TJ
392 ostringstream os;
393 os << "packet " << i << " not there";
af84dfb5 394
307b5e74 395 BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, os.str());
af84dfb5 396
307b5e74
TJ
397 os.str("");
398 os << "packet " << i << " incorrect";
399
400 BOOST_CHECK_MESSAGE(string().insert(0,100,'X') == data, os.str());
af84dfb5
GE
401 }
402 }
403 }
307b5e74 404}
af84dfb5 405
307b5e74
TJ
406BOOST_AUTO_TEST_CASE(reconnect_buffer_no_incomplete1)
407{
408 switch(child_pid=fork())
af84dfb5 409 {
307b5e74 410 case -1:
af84dfb5 411 {
307b5e74
TJ
412 BOOST_FAIL("fork error");
413 break;
414 }
415 case 0:
416 // child
417 {
418 try
af84dfb5 419 {
307b5e74
TJ
420 socket_server ss("./socket");
421
422 time_t t0 = time(NULL);
423
424 // max 10 sec
425 while (time(NULL) < t0 + 10 )
af84dfb5 426 {
307b5e74 427 ss.fill_buffer(1000000);
af84dfb5 428
307b5e74
TJ
429 string data;
430 unsigned int cid;
af84dfb5 431
307b5e74 432 if(ss.get_packet(data,cid))
af84dfb5 433 {
307b5e74 434 server_connection* con=ss.get_connection(cid);
af84dfb5 435
307b5e74
TJ
436 if (data=="QUIT")
437 break;
af84dfb5 438
307b5e74 439 if (data=="x")
af84dfb5 440 {
307b5e74
TJ
441 con->write(string().insert(0,100,'X'));
442 send_raw_socket("aaaab",&ss,cid);
af84dfb5
GE
443 }
444 }
445 }
307b5e74
TJ
446 } catch(...)
447 {
448 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
449 }
450
307b5e74
TJ
451 // don't call atexit and stuff
452 _exit(0);
453 }
af84dfb5 454
307b5e74
TJ
455 default:
456 // parent
457 {
458 // don't kill us on broken pipe
459 signal(SIGPIPE, SIG_IGN);
af84dfb5 460
307b5e74
TJ
461 // wait till server is up
462 sleep(1);
463 socket_client_connection sc("./socket");
af84dfb5 464
307b5e74 465 sc.write("x");
af84dfb5 466
307b5e74
TJ
467 // retrieve packets for 3 seconds
468 time_t t0 = time(NULL);
af84dfb5 469
307b5e74
TJ
470 // max 3 sec
471 while (time(NULL) < t0 + 3 )
472 sc.fill_buffer(1000000);
af84dfb5 473
307b5e74 474 // we now should have one complete packet and some stuff in the buffer
af84dfb5 475
307b5e74
TJ
476 string data;
477 sc.get_packet(data);
af84dfb5 478
307b5e74 479 BOOST_CHECK_MESSAGE((sc.peek_packet(data))>0, "no incomplete packet");
af84dfb5 480
307b5e74
TJ
481 sc.reconnect();
482
483 BOOST_CHECK_MESSAGE((int)sc.peek_packet(data) == 0, "incomplete packet not removed");
af84dfb5
GE
484 }
485 }
307b5e74 486}
af84dfb5 487
307b5e74
TJ
488BOOST_AUTO_TEST_CASE(reconnect_buffer_no_incomplete2)
489{
490 switch(child_pid=fork())
af84dfb5 491 {
307b5e74 492 case -1:
af84dfb5 493 {
307b5e74
TJ
494 BOOST_FAIL("fork error");
495 break;
496 }
497 case 0:
498 // child
499 {
500 try
af84dfb5 501 {
307b5e74
TJ
502 socket_server ss("./socket");
503
504 time_t t0 = time(NULL);
505
506 // max 10 sec
507 while (time(NULL) < t0 + 10 )
af84dfb5 508 {
307b5e74 509 ss.fill_buffer(1000000);
af84dfb5 510
307b5e74
TJ
511 string data;
512 unsigned int cid;
af84dfb5 513
307b5e74 514 if(ss.get_packet(data,cid))
af84dfb5 515 {
307b5e74 516 server_connection* con=ss.get_connection(cid);
af84dfb5 517
307b5e74
TJ
518 if (data=="QUIT")
519 break;
af84dfb5 520
307b5e74 521 if (data=="x")
af84dfb5 522 {
307b5e74 523 con->write(string().insert(0,100,'X'));
441d41fe 524
307b5e74 525 string blob=string().insert(0,100,'Y');
af84dfb5 526
307b5e74
TJ
527 // one byte will be missing...
528 int size=blob.size()+1;
529 char sizetransfer[sizeof(int)+1];
530 memcpy(sizetransfer,(void*)&size,sizeof(int));
531 sizetransfer[sizeof(int)+1]=0;
af84dfb5 532
307b5e74 533 string packet=string(sizetransfer)+blob;
af84dfb5 534
307b5e74 535 send_raw_socket(packet,&ss,cid);
af84dfb5
GE
536 }
537 }
538 }
307b5e74
TJ
539 } catch(...)
540 {
541 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
542 }
543
307b5e74
TJ
544 // don't call atexit and stuff
545 _exit(0);
546 }
af84dfb5 547
307b5e74
TJ
548 default:
549 // parent
550 {
551 // don't kill us on broken pipe
552 signal(SIGPIPE, SIG_IGN);
af84dfb5 553
307b5e74
TJ
554 // wait till server is up
555 sleep(1);
556 socket_client_connection sc("./socket");
af84dfb5 557
307b5e74 558 sc.write("x");
af84dfb5 559
307b5e74
TJ
560 // retrieve packets for 3 seconds
561 time_t t0 = time(NULL);
af84dfb5 562
307b5e74
TJ
563 // max 3 sec
564 while (time(NULL) < t0 + 3 )
565 sc.fill_buffer(1000000);
af84dfb5 566
307b5e74 567 // we now should have one complete packet and some stuff in the buffer
af84dfb5 568
307b5e74 569 sc.reconnect();
af84dfb5 570
307b5e74 571 string data;
af84dfb5 572
307b5e74
TJ
573 BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, "packet not there");
574 BOOST_CHECK_MESSAGE(string().insert(0,100,'X') == data, "data incorrect");
575
576 BOOST_CHECK_MESSAGE((int)sc.peek_packet(data) == 0, "incomplete packet not removed");
af84dfb5
GE
577 }
578 }
307b5e74 579}
af84dfb5 580
307b5e74 581BOOST_AUTO_TEST_SUITE_END()