Change license from LGPL to GPL version 2 + linking exception. This fixes C++ templat...
[libt2n] / test / wrapper.cpp
CommitLineData
19facd85
TJ
1/*
2Copyright (C) 2004 by Intra2net AG
ffbbf9ab 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*/
ffbbf9ab
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 <cppunit/extensions/TestFactoryRegistry.h>
34#include <cppunit/ui/text/TestRunner.h>
35#include <cppunit/extensions/HelperMacros.h>
36
e1614a6d
GE
37#include <boost/archive/binary_oarchive.hpp>
38#include <boost/archive/binary_iarchive.hpp>
39#include <boost/archive/xml_oarchive.hpp>
40#include <boost/archive/xml_iarchive.hpp>
41#include <boost/serialization/serialization.hpp>
42#include <boost/serialization/export.hpp>
43
44#include <container.hxx>
45#include <socket_client.hxx>
46#include <socket_server.hxx>
ffbbf9ab 47#include <command_client.hxx>
e1614a6d 48#include <command_server.hxx>
ffbbf9ab
GE
49#include <client_wrapper.hxx>
50#include <socket_wrapper.hxx>
51
52#ifdef HAVE_CONFIG_H
53#include <config.h>
54#endif
55
56using namespace std;
57using namespace libt2n;
58using namespace CppUnit;
59
e1614a6d
GE
60// the server part
61
62stringstream logstream;
63bool close_server=false;
64bool kill_server=false;
65
66int serverfunc(int i)
67{
68 // magic commands
69 if (i==42)
70 close_server=true;
71 if (i==666)
72 kill_server=true;
73
74 return i+1;
75}
76
77std::string getserverlog(void)
78{
79 return logstream.str();
80}
81
82class serverfunc_res : public libt2n::result
83{
84 private:
85 int res;
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::result);
92 ar & BOOST_SERIALIZATION_NVP(res);
93 }
94
95 public:
96 serverfunc_res()
97 { }
98
99 serverfunc_res(int i)
100 {
101 res=i;
102 }
103
104 int get_data()
105 {
106 return res;
107 }
108};
109
110class getserverlog_res : public libt2n::result
111{
112 private:
113 std::string res;
114
115 friend class boost::serialization::access;
116 template<class Archive>
117 void serialize(Archive & ar, const unsigned int version)
118 {
119 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
120 ar & BOOST_SERIALIZATION_NVP(res);
121 }
122
123 public:
124 getserverlog_res()
125 { }
126
127 getserverlog_res(std::string s)
128 {
129 res=s;
130 }
131
132 std::string get_data()
133 {
134 return res;
135 }
136};
137
138class cmd_group_x : public command
139{
140 private:
141 friend class boost::serialization::access;
142 template<class Archive>
143 void serialize(Archive & ar, const unsigned int version)
144 {
145 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
146 }
147};
148
149class serverfunc_cmd : public cmd_group_x
150{
151 private:
152 int param;
153
154 friend class boost::serialization::access;
155 template<class Archive>
156 void serialize(Archive & ar, const unsigned int version)
157 {
158 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(cmd_group_x);
159 ar & BOOST_SERIALIZATION_NVP(param);
160 }
161
162 public:
163 serverfunc_cmd()
164 { }
165
166 serverfunc_cmd(int i)
167 {
168 param=i;
169 }
170
171 libt2n::result* operator()()
172 {
173 return new serverfunc_res(serverfunc(param));
174 }
175};
176
177class getserverlog_cmd : public cmd_group_x
ffbbf9ab 178{
e1614a6d
GE
179 private:
180 friend class boost::serialization::access;
181 template<class Archive>
182 void serialize(Archive & ar, const unsigned int version)
183 {
184 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(cmd_group_x);
185 }
186
ffbbf9ab 187 public:
e1614a6d
GE
188 getserverlog_cmd()
189 { }
ffbbf9ab 190
e1614a6d
GE
191 libt2n::result* operator()()
192 {
193 return new getserverlog_res(getserverlog());
194 }
195};
196
197BOOST_CLASS_EXPORT(serverfunc_res)
198BOOST_CLASS_EXPORT(getserverlog_res)
199BOOST_CLASS_EXPORT(cmd_group_x)
200BOOST_CLASS_EXPORT(serverfunc_cmd)
201BOOST_CLASS_EXPORT(getserverlog_cmd)
ffbbf9ab 202
e1614a6d
GE
203class cmd_group_x_client : public command_client
204{
205 public:
fb3345ad 206 cmd_group_x_client(libt2n::client_connection *_c,
e1614a6d
GE
207 long long _command_timeout_usec=command_timeout_usec_default,
208 long long _hello_timeout_usec=hello_timeout_usec_default)
209 : libt2n::command_client(_c,_command_timeout_usec,_hello_timeout_usec)
210 {}
211
212 int serverfunc(int i)
ffbbf9ab 213 {
e1614a6d
GE
214 libt2n::result_container rc;
215
216 send_command(new serverfunc_cmd(i), rc);
217 serverfunc_res* res=dynamic_cast<serverfunc_res*>(rc.get_result());
218 if (!res) throw libt2n::t2n_communication_error("result object of wrong type");
219 return res->get_data();
220 }
221
222 std::string getserverlog(void)
223 {
224 libt2n::result_container rc;
225
226 send_command(new getserverlog_cmd(), rc);
227 getserverlog_res* res=dynamic_cast<getserverlog_res*>(rc.get_result());
228 if (!res) throw libt2n::t2n_communication_error("result object of wrong type");
229 return res->get_data();
ffbbf9ab
GE
230 }
231};
232
e1614a6d 233typedef T2nSingletonWrapper<cmd_group_x_client> wraptype;
ffbbf9ab
GE
234
235template<>
236std::auto_ptr<wraptype> wraptype::SingletonObject = std::auto_ptr<wraptype>();
237
238template<>
239std::auto_ptr<ConnectionWrapper> wraptype::WrappedConnection = std::auto_ptr<ConnectionWrapper>();
240
241class test_wrapper : public TestFixture
242{
243 CPPUNIT_TEST_SUITE(test_wrapper);
244
e1614a6d 245 CPPUNIT_TEST(no_init_exception); // must be called first!!!
ffbbf9ab 246 CPPUNIT_TEST(simple_wrap);
e1614a6d
GE
247 CPPUNIT_TEST(double_use);
248 CPPUNIT_TEST(double_use_with_close);
249 CPPUNIT_TEST(reconnect_after_close);
250 CPPUNIT_TEST(reconnect_not_possible);
fb3345ad
GE
251 CPPUNIT_TEST(ignore_server_disconnect);
252 CPPUNIT_TEST(ignore_handler_reconnects);
e1614a6d 253
ffbbf9ab
GE
254 CPPUNIT_TEST_SUITE_END();
255
256 public:
257
fb3345ad
GE
258 pid_t child_pid;
259
ffbbf9ab 260 void setUp()
e1614a6d 261 {
fb3345ad
GE
262 close_server=false;
263 kill_server=false;
e1614a6d 264
fb3345ad 265 switch(child_pid=fork())
e1614a6d
GE
266 {
267 case -1:
268 {
269 CPPUNIT_FAIL("fork error");
270 break;
271 }
272 case 0:
273 // child
274 {
441d41fe 275 try
e1614a6d 276 {
441d41fe
TJ
277 int i=0;
278 while(i < 10 && !kill_server)
279 {
280 close_server=false;
281
282 socket_server ss("./socket");
283 group_command_server<cmd_group_x> cs(ss);
284 ss.set_logging(&logstream,debug);
285
286 // max 10 sec
287 for (; !close_server && !kill_server && i < 10; i++)
288 cs.handle(1000000);
289 }
290 } catch(...)
291 {
292 std::cerr << "exception in child. ignoring\n";
e1614a6d
GE
293 }
294
295 // don't call atexit and stuff
296 _exit(0);
297 }
298
299 default:
300 // parent
301 {
302 // wait till server is up
303 sleep(1);
304
305 }
306 }
307 }
ffbbf9ab
GE
308
309 void tearDown()
fb3345ad
GE
310 {
311 // make sure the server-child is dead before the next test runs
312 kill(child_pid,SIGKILL);
313 sleep(1);
314 }
315
316 void no_init_exception()
317 {
318 CPPUNIT_ASSERT_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),std::logic_error);
319 }
ffbbf9ab
GE
320
321 void simple_wrap()
322 {
e1614a6d
GE
323 wraptype::set_connection(auto_ptr<ConnectionWrapper>
324 (new BasicSocketWrapper("./socket")));
325
326 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
327
328 CPPUNIT_ASSERT_EQUAL(2,i);
329 }
330
e1614a6d
GE
331 void double_use()
332 {
333 // only one connection used?
334 wraptype::set_connection(auto_ptr<ConnectionWrapper>
335 (new BasicSocketWrapper("./socket")));
336
337 t2n_exec(&cmd_group_x_client::serverfunc)(17);
338 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
339
340 // count the number of times that "new connection accepted" appears in the server log
341 string::size_type p=0;
342 int cnt=0;
343 while ((p=out.find("new connection accepted",p))++ != string::npos)
344 cnt++;
345
346 CPPUNIT_ASSERT_EQUAL(1,cnt);
347 }
348
349 void double_use_with_close()
350 {
351 wraptype::set_connection(auto_ptr<ConnectionWrapper>
352 (new BasicSocketWrapper("./socket")));
353
354 t2n_exec(&cmd_group_x_client::serverfunc)(17);
355
356 // closes the connection from the client side
357 wraptype::set_connection(auto_ptr<ConnectionWrapper>
358 (new BasicSocketWrapper("./socket")));
359
360 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
361
362 // count the number of times that "new connection accepted" appears in the server log
363 string::size_type p=0;
364 int cnt=0;
365 while ((p=out.find("new connection accepted",p))++ != string::npos)
366 cnt++;
367
368 CPPUNIT_ASSERT_EQUAL(2,cnt);
369 }
370
371 void reconnect_after_close()
372 {
373 wraptype::set_connection(auto_ptr<ConnectionWrapper>
374 (new ReconnectSocketWrapper("./socket")));
375
376 wraptype::get_connection_wrapper()->set_command_timeout_usec(3000000);
377 wraptype::get_connection_wrapper()->set_hello_timeout_usec(3000000);
378
379 // 42 closes connection on the server side
380 t2n_exec(&cmd_group_x_client::serverfunc)(42);
381
382 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
383
384 // count the number of times that "new connection accepted" appears in the server log
385 string::size_type p=0;
386 int cnt=0;
387 while ((p=out.find("new connection accepted",p))++ != string::npos)
388 cnt++;
389
390 CPPUNIT_ASSERT_EQUAL(2,cnt);
391 }
392
393 void reconnect_not_possible()
394 {
395 wraptype::set_connection(auto_ptr<ConnectionWrapper>
396 (new ReconnectSocketWrapper("./socket")));
397
398 // the server doens't like the beast
399 t2n_exec(&cmd_group_x_client::serverfunc)(666);
ffbbf9ab 400
e1614a6d 401 CPPUNIT_ASSERT_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),t2n_communication_error);
ffbbf9ab
GE
402 }
403
fb3345ad
GE
404 void ignore_server_disconnect()
405 {
406 wraptype::set_connection(auto_ptr<ConnectionWrapper>
407 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
408
409 // the server doens't like the beast
410 t2n_exec(&cmd_group_x_client::serverfunc)(666);
411
412 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
413
414 // result is constructed with default constructor on error-and-ignore -> i=0
415
416 CPPUNIT_ASSERT_EQUAL(0,i);
417 }
418
419 void ignore_handler_reconnects()
420 {
421 wraptype::set_connection(auto_ptr<ConnectionWrapper>
422 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
423
424 wraptype::get_connection_wrapper()->set_command_timeout_usec(3000000);
425 wraptype::get_connection_wrapper()->set_hello_timeout_usec(3000000);
426
427 // 42 closes connection on the server side
428 t2n_exec(&cmd_group_x_client::serverfunc)(42);
429
430 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
431
432 // count the number of times that "new connection accepted" appears in the server log
433 string::size_type p=0;
434 int cnt=0;
435 while ((p=out.find("new connection accepted",p))++ != string::npos)
436 cnt++;
437
438 CPPUNIT_ASSERT_EQUAL(2,cnt);
439 }
440
ffbbf9ab
GE
441};
442
443CPPUNIT_TEST_SUITE_REGISTRATION(test_wrapper);
fb3345ad
GE
444
445
446class test_wrapper_noserver : public TestFixture
447{
448 CPPUNIT_TEST_SUITE(test_wrapper_noserver);
449
450 CPPUNIT_TEST(ignore_noserver);
451 CPPUNIT_TEST(ignore_finds_lateserver);
b5922184 452 CPPUNIT_TEST(ignore_wrongserver);
fb3345ad
GE
453
454 CPPUNIT_TEST_SUITE_END();
455
456 public:
457
458 pid_t child_pid;
459
460 void setUp()
b5922184
GE
461 {
462 child_pid=0;
463 }
fb3345ad
GE
464
465 void tearDown()
b5922184
GE
466 {
467 // make sure the server-child is dead before the next test runs
468 if (child_pid != 0)
469 {
470 kill(child_pid,SIGKILL);
471 sleep(1);
472 }
473 }
fb3345ad
GE
474
475 void ignore_noserver()
476 {
477 wraptype::set_connection(auto_ptr<ConnectionWrapper>
478 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
479
480 // wraptype::get_connection_wrapper()->set_logging(&cerr,debug);
481
482 // there is no server
483
484 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
485
486 // result is constructed with default constructor on error-and-ignore -> i=0
487
488 CPPUNIT_ASSERT_EQUAL(0,i);
489 }
490
491 void ignore_finds_lateserver()
492 {
493 wraptype::set_connection(auto_ptr<ConnectionWrapper>
494 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
495
496 // there is no server
497 t2n_exec(&cmd_group_x_client::serverfunc)(1);
498
499 // launch a server
fb3345ad
GE
500 close_server=false;
501 kill_server=false;
502
503 switch(child_pid=fork())
504 {
505 case -1:
506 {
507 CPPUNIT_FAIL("fork error");
508 break;
509 }
510 case 0:
511 // child
512 {
441d41fe 513 try
fb3345ad 514 {
441d41fe
TJ
515 int i=0;
516 while(i < 10 && !kill_server)
517 {
518 close_server=false;
519
520 socket_server ss("./socket");
521 group_command_server<cmd_group_x> cs(ss);
522 ss.set_logging(&logstream,debug);
523
524 // max 10 sec
525 for (; !close_server && !kill_server && i < 10; i++)
526 cs.handle(1000000);
527 }
528 } catch(...)
529 {
530 std::cerr << "exception in child. ignoring\n";
fb3345ad
GE
531 }
532
533 // don't call atexit and stuff
534 _exit(0);
535 }
536
537 default:
538 // parent
539 {
540 // wait till server is up
541 sleep(1);
542 }
543 }
544
545 // server should be active
546 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
547
548 CPPUNIT_ASSERT_EQUAL(2,i);
b5922184 549 }
fb3345ad 550
b5922184
GE
551 void send_hello(string hello_string, socket_server* ss, int conn_id)
552 {
553 server_connection *sc=ss->get_connection(conn_id);
554 sc->write(hello_string);
555 }
556
557 void ignore_wrongserver()
558 {
559 wraptype::set_connection(auto_ptr<ConnectionWrapper>
560 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
561
562 // launch a server
563
564 switch(child_pid=fork())
565 {
566 case -1:
567 {
568 CPPUNIT_FAIL("fork error");
569 break;
570 }
571 case 0:
572 // child
573 {
441d41fe
TJ
574 try
575 {
576 socket_server ss("./socket");
b5922184 577
441d41fe 578 // server sends garbage
b5922184 579
441d41fe
TJ
580 ostringstream hello;
581 hello << "XYZ 123";
b5922184 582
441d41fe
TJ
583 ss.add_callback(new_connection,bind(&test_wrapper_noserver::send_hello, boost::ref(*this), hello.str(),&ss, _1));
584
585 // max 10 sec
586 for (int i=0; i < 10; i++)
587 ss.fill_buffer(1000000);
588 } catch(...)
589 {
590 std::cerr << "exception in child. ignoring\n";
591 }
b5922184 592
b5922184
GE
593 // don't call atexit and stuff
594 _exit(0);
595 }
596
597 default:
598 // parent
599 {
600 // wait till server is up
601 sleep(1);
602 }
603 }
604
605 // there is no valid server
606
607 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
608
609 // result is constructed with default constructor on error-and-ignore -> i=0
610
611 CPPUNIT_ASSERT_EQUAL(0,i);
fb3345ad
GE
612 }
613
614
615};
616
617CPPUNIT_TEST_SUITE_REGISTRATION(test_wrapper_noserver);