Commit | Line | Data |
---|---|---|
19facd85 TJ |
1 | /* |
2 | Copyright (C) 2004 by Intra2net AG | |
ffbbf9ab | 3 | |
19facd85 TJ |
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 | */ | |
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 | |
55 | using namespace std; | |
56 | using namespace libt2n; | |
ffbbf9ab | 57 | |
e1614a6d GE |
58 | // the server part |
59 | ||
60 | stringstream logstream; | |
61 | bool close_server=false; | |
62 | bool kill_server=false; | |
63 | ||
64 | int 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 | ||
75 | std::string getserverlog(void) | |
76 | { | |
77 | return logstream.str(); | |
78 | } | |
79 | ||
80 | class 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 | ||
108 | class 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 | ||
136 | class 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 | ||
147 | class 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 | ||
175 | class 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 | ||
195 | BOOST_CLASS_EXPORT(serverfunc_res) | |
196 | BOOST_CLASS_EXPORT(getserverlog_res) | |
197 | BOOST_CLASS_EXPORT(cmd_group_x) | |
198 | BOOST_CLASS_EXPORT(serverfunc_cmd) | |
199 | BOOST_CLASS_EXPORT(getserverlog_cmd) | |
ffbbf9ab | 200 | |
e1614a6d GE |
201 | class 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 | 231 | typedef T2nSingletonWrapper<cmd_group_x_client> wraptype; |
ffbbf9ab GE |
232 | |
233 | template<> | |
234 | std::auto_ptr<wraptype> wraptype::SingletonObject = std::auto_ptr<wraptype>(); | |
235 | ||
236 | template<> | |
237 | std::auto_ptr<ConnectionWrapper> wraptype::WrappedConnection = std::auto_ptr<ConnectionWrapper>(); | |
238 | ||
fb3345ad | 239 | |
307b5e74 TJ |
240 | class test_wrapperFixture : public KillChildOnShutdownFixture |
241 | { | |
242 | public: | |
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 | 299 | BOOST_FIXTURE_TEST_SUITE(test_wrapper, test_wrapperFixture) |
ffbbf9ab | 300 | |
307b5e74 TJ |
301 | BOOST_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 |
306 | BOOST_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 |
316 | BOOST_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 |
334 | BOOST_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 |
356 | BOOST_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 |
378 | BOOST_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 |
389 | BOOST_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 |
404 | BOOST_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 | 426 | BOOST_AUTO_TEST_SUITE_END() |
fb3345ad | 427 | |
df94ded3 | 428 | BOOST_FIXTURE_TEST_SUITE(test_wrapper_noserver, KillChildOnShutdownFixture) |
fb3345ad | 429 | |
307b5e74 TJ |
430 | BOOST_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 |
446 | BOOST_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 |
506 | BOOST_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 | 563 | BOOST_AUTO_TEST_SUITE_END() |