Remove code duplication in test fixtures
[libt2n] / test / reconnect.cpp
1 /*
2 Copyright (C) 2004 by Intra2net AG
3
4 The software in this package is distributed under the GNU General
5 Public License version 2 (with a special exception described below).
6
7 A copy of GNU General Public License (GPL) is included in this distribution,
8 in the file COPYING.GPL.
9
10 As a special exception, if other files instantiate templates or use macros
11 or inline functions from this file, or you compile this file and link it
12 with other works to produce a work based on this file, this file
13 does not by itself cause the resulting work to be covered
14 by the GNU General Public License.
15
16 However the source code for this file must still be made available
17 in accordance with section (3) of the GNU General Public License.
18
19 This exception does not invalidate any other reasons why a work based
20 on 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
46 using namespace std;
47 using namespace libt2n;
48
49 BOOST_FIXTURE_TEST_SUITE(test_reconnect, KillChildOnShutdownFixture)
50
51 BOOST_AUTO_TEST_CASE(simple_reconnect)
52 {
53     switch(child_pid=fork())
54     {
55         case -1:
56         {
57             BOOST_FAIL("fork error");
58             break;
59         }
60         case 0:
61         // child
62         {
63             try
64             {
65                 socket_server ss("./socket");
66
67                 time_t t0 = time(NULL);
68
69                 // max 10 sec
70                 while (time(NULL) < t0 + 10 )
71                 {
72                     ss.fill_buffer(1000000);
73
74                     string data;
75                     unsigned int cid;
76
77                     if(ss.get_packet(data,cid))
78                     {
79                         server_connection* con=ss.get_connection(cid);
80
81                         if (data=="QUIT")
82                             break;
83
84                         if (data=="x")
85                             con->write(string().insert(0,100,'X'));
86                         else
87                             con->write(string().insert(0,100,'Y'));
88                     }
89                 }
90             } catch(...)
91             {
92                 std::cerr << "exception in child. ignoring\n";
93             }
94
95             // don't call atexit and stuff
96             _exit(0);
97         }
98
99         default:
100         // parent
101         {
102             // don't kill us on broken pipe
103             signal(SIGPIPE, SIG_IGN);
104
105             // wait till server is up
106             sleep(1);
107             socket_client_connection sc("./socket");
108
109             sc.write("abc");
110
111             string data;
112
113             while (!sc.get_packet(data))
114                 sc.fill_buffer(1000000);
115
116             sc.reconnect();
117
118             sc.write("x");
119
120             while (!sc.get_packet(data))
121                 sc.fill_buffer(1000000);
122
123             BOOST_CHECK_EQUAL(string().insert(0,100,'X'),data);
124         }
125     }
126 }
127
128 BOOST_AUTO_TEST_CASE(reconnect_with_close)
129 {
130     switch(child_pid=fork())
131     {
132         case -1:
133         {
134             BOOST_FAIL("fork error");
135             break;
136         }
137         case 0:
138         // child
139         {
140             try
141             {
142                 socket_server ss("./socket");
143
144                 time_t t0 = time(NULL);
145
146                 // max 10 sec
147                 while (time(NULL) < t0 + 10 )
148                 {
149                     ss.fill_buffer(1000000);
150
151                     string data;
152                     unsigned int cid;
153
154                     if(ss.get_packet(data,cid))
155                     {
156                         server_connection* con=ss.get_connection(cid);
157
158                         if (data=="QUIT")
159                             break;
160
161                         if (data=="x")
162                             con->write(string().insert(0,100,'X'));
163                         else
164                             con->write(string().insert(0,100,'Y'));
165                     }
166                 }
167             } catch(...)
168             {
169                 std::cerr << "exception in child. ignoring\n";
170             }
171
172             // don't call atexit and stuff
173             _exit(0);
174         }
175
176         default:
177         // parent
178         {
179             // don't kill us on broken pipe
180             signal(SIGPIPE, SIG_IGN);
181
182             // wait till server is up
183             sleep(1);
184             socket_client_connection sc("./socket");
185
186             sc.write("abc");
187
188             string data;
189
190             while (!sc.get_packet(data))
191                 sc.fill_buffer(1000000);
192
193             sc.close();
194
195             // empty buffer
196             sc.get_packet(data);
197
198             sc.reconnect();
199
200             sc.write("x");
201
202             while (!sc.get_packet(data))
203                 sc.fill_buffer(1000000);
204
205             BOOST_CHECK_EQUAL(string().insert(0,100,'X'),data);
206         }
207     }
208 }
209
210 BOOST_AUTO_TEST_CASE(reconnect_buffer_complete)
211 {
212     switch(child_pid=fork())
213     {
214         case -1:
215         {
216             BOOST_FAIL("fork error");
217             break;
218         }
219         case 0:
220         // child
221         {
222             try
223             {
224                 socket_server ss("./socket");
225
226                 time_t t0 = time(NULL);
227
228                 // max 10 sec
229                 while (time(NULL) < t0 + 10 )
230                 {
231                     ss.fill_buffer(1000000);
232
233                     string data;
234                     unsigned int cid;
235
236                     if(ss.get_packet(data,cid))
237                     {
238                         server_connection* con=ss.get_connection(cid);
239
240                         if (data=="QUIT")
241                             break;
242
243                         if (data=="x")
244                             con->write(string().insert(0,100,'X'));
245                     }
246                 }
247             } catch(...)
248             {
249                 std::cerr << "exception in child. ignoring\n";
250             }
251
252             // don't call atexit and stuff
253             _exit(0);
254         }
255
256         default:
257         // parent
258         {
259             // don't kill us on broken pipe
260             signal(SIGPIPE, SIG_IGN);
261
262             // wait till server is up
263             sleep(1);
264             socket_client_connection sc("./socket");
265
266             sc.write("x");
267
268             string data;
269
270             while (!sc.packet_available())
271                 sc.fill_buffer(1000000);
272
273             sc.reconnect();
274
275             BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, "packet not there");
276
277             BOOST_CHECK_MESSAGE(data == string().insert(0,100,'X'), "data incorrect");
278         }
279     }
280 }
281
282 BOOST_AUTO_TEST_CASE(reconnect_buffer_several_complete)
283 {
284     const int packets=3;
285
286     switch(child_pid=fork())
287     {
288         case -1:
289         {
290             BOOST_FAIL("fork error");
291             break;
292         }
293         case 0:
294         // child
295         {
296             try
297             {
298                 socket_server ss("./socket");
299
300                 time_t t0 = time(NULL);
301
302                 // max 10 sec
303                 while (time(NULL) < t0 + 10 )
304                 {
305                     ss.fill_buffer(1000000);
306
307                     string data;
308                     unsigned int cid;
309
310                     if(ss.get_packet(data,cid))
311                     {
312                         server_connection* con=ss.get_connection(cid);
313
314                         if (data=="QUIT")
315                             break;
316
317                         if (data=="x")
318                         {
319                             for (int i=0; i<packets; i++)
320                                 con->write(string().insert(0,100,'X'));
321                         }
322                     }
323                 }
324             } catch(...)
325             {
326                 std::cerr << "exception in child. ignoring\n";
327             }
328
329             // don't call atexit and stuff
330             _exit(0);
331         }
332
333         default:
334         // parent
335         {
336             // don't kill us on broken pipe
337             signal(SIGPIPE, SIG_IGN);
338
339             // wait till server is up
340             sleep(1);
341             socket_client_connection sc("./socket");
342
343             sc.write("x");
344
345             // retrieve packets for 3 seconds
346             time_t t0 = time(NULL);
347
348             // max 3 sec
349             while (time(NULL) < t0 + 3 )
350                 sc.fill_buffer(1000000);
351
352             // we now should have packets complete packets in the buffer
353
354             sc.reconnect();
355
356             // are these packets still there?
357
358             for (int i=0; i < packets; i++)
359             {
360                 string data;
361
362                 ostringstream os;
363                 os << "packet " << i << " not there";
364
365                 BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, os.str());
366
367                 os.str("");
368                 os << "packet " << i << " incorrect";
369
370                 BOOST_CHECK_MESSAGE(string().insert(0,100,'X') == data, os.str());
371             }
372         }
373     }
374 }
375
376 BOOST_AUTO_TEST_CASE(reconnect_buffer_no_incomplete1)
377 {
378     switch(child_pid=fork())
379     {
380         case -1:
381         {
382             BOOST_FAIL("fork error");
383             break;
384         }
385         case 0:
386         // child
387         {
388             try
389             {
390                 socket_server ss("./socket");
391
392                 time_t t0 = time(NULL);
393
394                 // max 10 sec
395                 while (time(NULL) < t0 + 10 )
396                 {
397                     ss.fill_buffer(1000000);
398
399                     string data;
400                     unsigned int cid;
401
402                     if(ss.get_packet(data,cid))
403                     {
404                         server_connection* con=ss.get_connection(cid);
405
406                         if (data=="QUIT")
407                             break;
408
409                         if (data=="x")
410                         {
411                             con->write(string().insert(0,100,'X'));
412                             send_raw_socket("aaaab",&ss,cid);
413                         }
414                     }
415                 }
416             } catch(...)
417             {
418                 std::cerr << "exception in child. ignoring\n";
419             }
420
421             // don't call atexit and stuff
422             _exit(0);
423         }
424
425         default:
426         // parent
427         {
428             // don't kill us on broken pipe
429             signal(SIGPIPE, SIG_IGN);
430
431             // wait till server is up
432             sleep(1);
433             socket_client_connection sc("./socket");
434
435             sc.write("x");
436
437             // retrieve packets for 3 seconds
438             time_t t0 = time(NULL);
439
440             // max 3 sec
441             while (time(NULL) < t0 + 3 )
442                 sc.fill_buffer(1000000);
443
444             // we now should have one complete packet and some stuff in the buffer
445
446             string data;
447             sc.get_packet(data);
448
449             BOOST_CHECK_MESSAGE((sc.peek_packet(data))>0, "no incomplete packet");
450
451             sc.reconnect();
452
453             BOOST_CHECK_MESSAGE((int)sc.peek_packet(data) == 0, "incomplete packet not removed");
454         }
455     }
456 }
457
458 BOOST_AUTO_TEST_CASE(reconnect_buffer_no_incomplete2)
459 {
460     switch(child_pid=fork())
461     {
462         case -1:
463         {
464             BOOST_FAIL("fork error");
465             break;
466         }
467         case 0:
468         // child
469         {
470             try
471             {
472                 socket_server ss("./socket");
473
474                 time_t t0 = time(NULL);
475
476                 // max 10 sec
477                 while (time(NULL) < t0 + 10 )
478                 {
479                     ss.fill_buffer(1000000);
480
481                     string data;
482                     unsigned int cid;
483
484                     if(ss.get_packet(data,cid))
485                     {
486                         server_connection* con=ss.get_connection(cid);
487
488                         if (data=="QUIT")
489                             break;
490
491                         if (data=="x")
492                         {
493                             con->write(string().insert(0,100,'X'));
494
495                             string blob=string().insert(0,100,'Y');
496
497                             // one byte will be missing...
498                             int size=blob.size()+1;
499                             char sizetransfer[sizeof(int)+1];
500                             memcpy(sizetransfer,(void*)&size,sizeof(int));
501                             sizetransfer[sizeof(int)+1]=0;
502
503                             string packet=string(sizetransfer)+blob;
504
505                             send_raw_socket(packet,&ss,cid);
506                         }
507                     }
508                 }
509             } catch(...)
510             {
511                 std::cerr << "exception in child. ignoring\n";
512             }
513
514             // don't call atexit and stuff
515             _exit(0);
516         }
517
518         default:
519         // parent
520         {
521             // don't kill us on broken pipe
522             signal(SIGPIPE, SIG_IGN);
523
524             // wait till server is up
525             sleep(1);
526             socket_client_connection sc("./socket");
527
528             sc.write("x");
529
530             // retrieve packets for 3 seconds
531             time_t t0 = time(NULL);
532
533             // max 3 sec
534             while (time(NULL) < t0 + 3 )
535                 sc.fill_buffer(1000000);
536
537             // we now should have one complete packet and some stuff in the buffer
538
539             sc.reconnect();
540
541             string data;
542
543             BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, "packet not there");
544             BOOST_CHECK_MESSAGE(string().insert(0,100,'X') == data, "data incorrect");
545
546             BOOST_CHECK_MESSAGE((int)sc.peek_packet(data) == 0, "incomplete packet not removed");
547         }
548     }
549 }
550
551 BOOST_AUTO_TEST_SUITE_END()