Migrate from cppunit to Boost.test
[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
307b5e74
TJ
33#define BOOST_TEST_DYN_LINK
34#include <boost/test/unit_test.hpp>
ffbbf9ab 35
e1614a6d
GE
36#include <boost/archive/binary_oarchive.hpp>
37#include <boost/archive/binary_iarchive.hpp>
38#include <boost/archive/xml_oarchive.hpp>
39#include <boost/archive/xml_iarchive.hpp>
40#include <boost/serialization/serialization.hpp>
41#include <boost/serialization/export.hpp>
42
43#include <container.hxx>
44#include <socket_client.hxx>
45#include <socket_server.hxx>
ffbbf9ab 46#include <command_client.hxx>
e1614a6d 47#include <command_server.hxx>
ffbbf9ab
GE
48#include <client_wrapper.hxx>
49#include <socket_wrapper.hxx>
50
307b5e74
TJ
51#include "test_fixtures.hxx"
52
ffbbf9ab
GE
53#ifdef HAVE_CONFIG_H
54#include <config.h>
55#endif
56
57using namespace std;
58using namespace libt2n;
ffbbf9ab 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
fb3345ad 241
307b5e74
TJ
242class test_wrapperFixture : public KillChildOnShutdownFixture
243{
244public:
245 test_wrapperFixture()
e1614a6d 246 {
fb3345ad
GE
247 close_server=false;
248 kill_server=false;
e1614a6d 249
fb3345ad 250 switch(child_pid=fork())
e1614a6d
GE
251 {
252 case -1:
253 {
307b5e74 254 BOOST_FAIL("fork error");
e1614a6d
GE
255 break;
256 }
257 case 0:
258 // child
259 {
441d41fe 260 try
e1614a6d 261 {
441d41fe
TJ
262 int i=0;
263 while(i < 10 && !kill_server)
264 {
265 close_server=false;
266
267 socket_server ss("./socket");
268 group_command_server<cmd_group_x> cs(ss);
269 ss.set_logging(&logstream,debug);
270
271 // max 10 sec
272 for (; !close_server && !kill_server && i < 10; i++)
273 cs.handle(1000000);
274 }
275 } catch(...)
276 {
277 std::cerr << "exception in child. ignoring\n";
e1614a6d
GE
278 }
279
280 // don't call atexit and stuff
281 _exit(0);
282 }
283
284 default:
285 // parent
286 {
307b5e74
TJ
287 // don't kill us on broken pipe
288 signal(SIGPIPE, SIG_IGN);
289
e1614a6d
GE
290 // wait till server is up
291 sleep(1);
e1614a6d
GE
292 }
293 }
294 }
ffbbf9ab 295
307b5e74 296 ~test_wrapperFixture()
fb3345ad 297 {
fb3345ad 298 }
307b5e74 299};
fb3345ad 300
307b5e74 301BOOST_FIXTURE_TEST_SUITE(test_wrapper, test_wrapperFixture)
ffbbf9ab 302
307b5e74
TJ
303BOOST_AUTO_TEST_CASE(no_init_exception) // must be called first!
304{
305 BOOST_REQUIRE_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),std::logic_error);
306}
e1614a6d 307
307b5e74
TJ
308BOOST_AUTO_TEST_CASE(simple_wrap)
309{
310 wraptype::set_connection(auto_ptr<ConnectionWrapper>
311 (new BasicSocketWrapper("./socket")));
e1614a6d 312
307b5e74 313 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
e1614a6d 314
307b5e74
TJ
315 BOOST_CHECK_EQUAL(2,i);
316}
e1614a6d 317
307b5e74
TJ
318BOOST_AUTO_TEST_CASE(double_use)
319{
320 // only one connection used?
321 wraptype::set_connection(auto_ptr<ConnectionWrapper>
322 (new BasicSocketWrapper("./socket")));
e1614a6d 323
307b5e74
TJ
324 t2n_exec(&cmd_group_x_client::serverfunc)(17);
325 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
e1614a6d 326
307b5e74
TJ
327 // count the number of times that "new connection accepted" appears in the server log
328 string::size_type p=0;
329 int cnt=0;
330 while ((p=out.find("new connection accepted",p))++ != string::npos)
331 cnt++;
e1614a6d 332
307b5e74
TJ
333 BOOST_CHECK_EQUAL(1,cnt);
334}
e1614a6d 335
307b5e74
TJ
336BOOST_AUTO_TEST_CASE(double_use_with_close)
337{
338 wraptype::set_connection(auto_ptr<ConnectionWrapper>
339 (new BasicSocketWrapper("./socket")));
e1614a6d 340
307b5e74 341 t2n_exec(&cmd_group_x_client::serverfunc)(17);
e1614a6d 342
307b5e74
TJ
343 // closes the connection from the client side
344 wraptype::set_connection(auto_ptr<ConnectionWrapper>
345 (new BasicSocketWrapper("./socket")));
e1614a6d 346
307b5e74 347 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
e1614a6d 348
307b5e74
TJ
349 // count the number of times that "new connection accepted" appears in the server log
350 string::size_type p=0;
351 int cnt=0;
352 while ((p=out.find("new connection accepted",p))++ != string::npos)
353 cnt++;
e1614a6d 354
307b5e74
TJ
355 BOOST_CHECK_EQUAL(2,cnt);
356}
e1614a6d 357
307b5e74
TJ
358BOOST_AUTO_TEST_CASE(reconnect_after_close)
359{
360 wraptype::set_connection(auto_ptr<ConnectionWrapper>
361 (new ReconnectSocketWrapper("./socket")));
e1614a6d 362
307b5e74
TJ
363 wraptype::get_connection_wrapper()->set_command_timeout_usec(3000000);
364 wraptype::get_connection_wrapper()->set_hello_timeout_usec(3000000);
e1614a6d 365
307b5e74
TJ
366 // 42 closes connection on the server side
367 t2n_exec(&cmd_group_x_client::serverfunc)(42);
e1614a6d 368
307b5e74 369 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
e1614a6d 370
307b5e74
TJ
371 // count the number of times that "new connection accepted" appears in the server log
372 string::size_type p=0;
373 int cnt=0;
374 while ((p=out.find("new connection accepted",p))++ != string::npos)
375 cnt++;
e1614a6d 376
307b5e74
TJ
377 BOOST_CHECK_EQUAL(2,cnt);
378}
e1614a6d 379
307b5e74
TJ
380BOOST_AUTO_TEST_CASE(reconnect_not_possible)
381{
382 wraptype::set_connection(auto_ptr<ConnectionWrapper>
383 (new ReconnectSocketWrapper("./socket")));
ffbbf9ab 384
307b5e74
TJ
385 // the server doens't like the beast
386 t2n_exec(&cmd_group_x_client::serverfunc)(666);
ffbbf9ab 387
307b5e74
TJ
388 BOOST_REQUIRE_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),t2n_communication_error);
389}
fb3345ad 390
307b5e74
TJ
391BOOST_AUTO_TEST_CASE(ignore_server_disconnect)
392{
393 wraptype::set_connection(auto_ptr<ConnectionWrapper>
394 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
fb3345ad 395
307b5e74
TJ
396 // the server doens't like the beast
397 t2n_exec(&cmd_group_x_client::serverfunc)(666);
fb3345ad 398
307b5e74 399 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
fb3345ad 400
307b5e74 401 // result is constructed with default constructor on error-and-ignore -> i=0
fb3345ad 402
307b5e74
TJ
403 BOOST_CHECK_EQUAL(0,i);
404}
fb3345ad 405
307b5e74
TJ
406BOOST_AUTO_TEST_CASE(ignore_handler_reconnects)
407{
408 wraptype::set_connection(auto_ptr<ConnectionWrapper>
409 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
fb3345ad 410
307b5e74
TJ
411 wraptype::get_connection_wrapper()->set_command_timeout_usec(3000000);
412 wraptype::get_connection_wrapper()->set_hello_timeout_usec(3000000);
fb3345ad 413
307b5e74
TJ
414 // 42 closes connection on the server side
415 t2n_exec(&cmd_group_x_client::serverfunc)(42);
fb3345ad 416
307b5e74 417 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
fb3345ad 418
307b5e74
TJ
419 // count the number of times that "new connection accepted" appears in the server log
420 string::size_type p=0;
421 int cnt=0;
422 while ((p=out.find("new connection accepted",p))++ != string::npos)
423 cnt++;
fb3345ad 424
307b5e74
TJ
425 BOOST_CHECK_EQUAL(2,cnt);
426}
427BOOST_AUTO_TEST_SUITE_END()
ffbbf9ab 428
fb3345ad
GE
429
430
307b5e74 431class test_wrapper_noserverFixture : public KillChildOnShutdownFixture
fb3345ad 432{
307b5e74
TJ
433protected:
434 void send_hello(string hello_string, socket_server* ss, int conn_id)
b5922184 435 {
307b5e74
TJ
436 server_connection *sc=ss->get_connection(conn_id);
437 sc->write(hello_string);
b5922184 438 }
fb3345ad 439
307b5e74
TJ
440public:
441 test_wrapper_noserverFixture()
b5922184 442 {
b5922184 443 }
fb3345ad 444
307b5e74 445 ~test_wrapper_noserverFixture()
fb3345ad 446 {
307b5e74
TJ
447 }
448};
fb3345ad 449
307b5e74 450BOOST_FIXTURE_TEST_SUITE(test_wrapper_noserver, test_wrapper_noserverFixture)
fb3345ad 451
307b5e74
TJ
452BOOST_AUTO_TEST_CASE(ignore_noserver)
453{
454 wraptype::set_connection(auto_ptr<ConnectionWrapper>
455 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
fb3345ad 456
307b5e74 457 // wraptype::get_connection_wrapper()->set_logging(&cerr,debug);
fb3345ad 458
307b5e74 459 // there is no server
fb3345ad 460
307b5e74 461 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
fb3345ad 462
307b5e74 463 // result is constructed with default constructor on error-and-ignore -> i=0
fb3345ad 464
307b5e74
TJ
465 BOOST_CHECK_EQUAL(0,i);
466}
fb3345ad 467
307b5e74
TJ
468BOOST_AUTO_TEST_CASE(ignore_finds_lateserver)
469{
470 wraptype::set_connection(auto_ptr<ConnectionWrapper>
471 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
fb3345ad 472
307b5e74
TJ
473 // there is no server
474 t2n_exec(&cmd_group_x_client::serverfunc)(1);
475
476 // launch a server
477 close_server=false;
478 kill_server=false;
479
480 switch(child_pid=fork())
481 {
482 case -1:
fb3345ad 483 {
307b5e74
TJ
484 BOOST_FAIL("fork error");
485 break;
486 }
487 case 0:
488 // child
489 {
490 try
fb3345ad 491 {
307b5e74
TJ
492 int i=0;
493 while(i < 10 && !kill_server)
fb3345ad 494 {
307b5e74 495 close_server=false;
441d41fe 496
307b5e74
TJ
497 socket_server ss("./socket");
498 group_command_server<cmd_group_x> cs(ss);
499 ss.set_logging(&logstream,debug);
441d41fe 500
307b5e74
TJ
501 // max 10 sec
502 for (; !close_server && !kill_server && i < 10; i++)
503 cs.handle(1000000);
fb3345ad 504 }
307b5e74 505 } catch(...)
fb3345ad 506 {
307b5e74 507 std::cerr << "exception in child. ignoring\n";
fb3345ad 508 }
fb3345ad 509
307b5e74
TJ
510 // don't call atexit and stuff
511 _exit(0);
512 }
fb3345ad 513
307b5e74
TJ
514 default:
515 // parent
516 {
517 // wait till server is up
518 sleep(1);
519 }
b5922184 520 }
fb3345ad 521
307b5e74
TJ
522 // server should be active
523 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
b5922184 524
307b5e74
TJ
525 BOOST_CHECK_EQUAL(2,i);
526}
b5922184 527
307b5e74
TJ
528BOOST_AUTO_TEST_CASE(ignore_wrongserver)
529{
530 wraptype::set_connection(auto_ptr<ConnectionWrapper>
531 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
b5922184 532
307b5e74
TJ
533 // launch a server
534
535 switch(child_pid=fork())
536 {
537 case -1:
b5922184 538 {
307b5e74
TJ
539 BOOST_FAIL("fork error");
540 break;
541 }
542 case 0:
543 // child
544 {
545 try
b5922184 546 {
307b5e74 547 socket_server ss("./socket");
b5922184 548
307b5e74 549 // server sends garbage
b5922184 550
307b5e74
TJ
551 ostringstream hello;
552 hello << "XYZ 123";
b5922184 553
307b5e74 554 ss.add_callback(new_connection,bind(&test_wrapper_noserver::ignore_wrongserver::send_hello, boost::ref(*this), hello.str(),&ss, _1));
b5922184 555
307b5e74
TJ
556 // max 10 sec
557 for (int i=0; i < 10; i++)
558 ss.fill_buffer(1000000);
559 } catch(...)
b5922184 560 {
307b5e74 561 std::cerr << "exception in child. ignoring\n";
b5922184 562 }
b5922184 563
307b5e74
TJ
564 // don't call atexit and stuff
565 _exit(0);
566 }
b5922184 567
307b5e74
TJ
568 default:
569 // parent
570 {
571 // wait till server is up
572 sleep(1);
573 }
574 }
b5922184 575
307b5e74 576 // there is no valid server
b5922184 577
307b5e74 578 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
fb3345ad 579
307b5e74 580 // result is constructed with default constructor on error-and-ignore -> i=0
fb3345ad 581
307b5e74
TJ
582 BOOST_CHECK_EQUAL(0,i);
583}
fb3345ad 584
307b5e74 585BOOST_AUTO_TEST_SUITE_END()