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