Update exception message. Atleast boost 1.44.0 uses this one
[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}
fb3345ad 427
df94ded3 428BOOST_AUTO_TEST_SUITE_END()
fb3345ad 429
df94ded3 430BOOST_FIXTURE_TEST_SUITE(test_wrapper_noserver, KillChildOnShutdownFixture)
fb3345ad 431
307b5e74
TJ
432BOOST_AUTO_TEST_CASE(ignore_noserver)
433{
434 wraptype::set_connection(auto_ptr<ConnectionWrapper>
435 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
fb3345ad 436
307b5e74 437 // wraptype::get_connection_wrapper()->set_logging(&cerr,debug);
fb3345ad 438
307b5e74 439 // there is no server
fb3345ad 440
307b5e74 441 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
fb3345ad 442
307b5e74 443 // result is constructed with default constructor on error-and-ignore -> i=0
fb3345ad 444
307b5e74
TJ
445 BOOST_CHECK_EQUAL(0,i);
446}
fb3345ad 447
307b5e74
TJ
448BOOST_AUTO_TEST_CASE(ignore_finds_lateserver)
449{
450 wraptype::set_connection(auto_ptr<ConnectionWrapper>
451 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
fb3345ad 452
307b5e74
TJ
453 // there is no server
454 t2n_exec(&cmd_group_x_client::serverfunc)(1);
455
456 // launch a server
457 close_server=false;
458 kill_server=false;
459
460 switch(child_pid=fork())
461 {
462 case -1:
fb3345ad 463 {
307b5e74
TJ
464 BOOST_FAIL("fork error");
465 break;
466 }
467 case 0:
468 // child
469 {
470 try
fb3345ad 471 {
307b5e74
TJ
472 int i=0;
473 while(i < 10 && !kill_server)
fb3345ad 474 {
307b5e74 475 close_server=false;
441d41fe 476
307b5e74
TJ
477 socket_server ss("./socket");
478 group_command_server<cmd_group_x> cs(ss);
479 ss.set_logging(&logstream,debug);
441d41fe 480
307b5e74
TJ
481 // max 10 sec
482 for (; !close_server && !kill_server && i < 10; i++)
483 cs.handle(1000000);
fb3345ad 484 }
307b5e74 485 } catch(...)
fb3345ad 486 {
307b5e74 487 std::cerr << "exception in child. ignoring\n";
fb3345ad 488 }
fb3345ad 489
307b5e74
TJ
490 // don't call atexit and stuff
491 _exit(0);
492 }
fb3345ad 493
307b5e74
TJ
494 default:
495 // parent
496 {
497 // wait till server is up
498 sleep(1);
499 }
b5922184 500 }
fb3345ad 501
307b5e74
TJ
502 // server should be active
503 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
b5922184 504
307b5e74
TJ
505 BOOST_CHECK_EQUAL(2,i);
506}
b5922184 507
307b5e74
TJ
508BOOST_AUTO_TEST_CASE(ignore_wrongserver)
509{
510 wraptype::set_connection(auto_ptr<ConnectionWrapper>
511 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
b5922184 512
307b5e74
TJ
513 // launch a server
514
515 switch(child_pid=fork())
516 {
517 case -1:
b5922184 518 {
307b5e74
TJ
519 BOOST_FAIL("fork error");
520 break;
521 }
522 case 0:
523 // child
524 {
525 try
b5922184 526 {
307b5e74 527 socket_server ss("./socket");
b5922184 528
307b5e74 529 // server sends garbage
b5922184 530
307b5e74
TJ
531 ostringstream hello;
532 hello << "XYZ 123";
b5922184 533
307b5e74 534 ss.add_callback(new_connection,bind(&test_wrapper_noserver::ignore_wrongserver::send_hello, boost::ref(*this), hello.str(),&ss, _1));
b5922184 535
307b5e74
TJ
536 // max 10 sec
537 for (int i=0; i < 10; i++)
538 ss.fill_buffer(1000000);
539 } catch(...)
b5922184 540 {
307b5e74 541 std::cerr << "exception in child. ignoring\n";
b5922184 542 }
b5922184 543
307b5e74
TJ
544 // don't call atexit and stuff
545 _exit(0);
546 }
b5922184 547
307b5e74
TJ
548 default:
549 // parent
550 {
551 // wait till server is up
552 sleep(1);
553 }
554 }
b5922184 555
307b5e74 556 // there is no valid server
b5922184 557
307b5e74 558 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
fb3345ad 559
307b5e74 560 // result is constructed with default constructor on error-and-ignore -> i=0
fb3345ad 561
307b5e74
TJ
562 BOOST_CHECK_EQUAL(0,i);
563}
fb3345ad 564
307b5e74 565BOOST_AUTO_TEST_SUITE_END()