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