2 Copyright (C) 2004 by Intra2net AG
4 The software in this package is distributed under the GNU General
5 Public License version 2 (with a special exception described below).
7 A copy of GNU General Public License (GPL) is included in this distribution,
8 in the file COPYING.GPL.
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.
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.
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.
22 #include <sys/types.h>
33 #include <cppunit/extensions/TestFactoryRegistry.h>
34 #include <cppunit/ui/text/TestRunner.h>
35 #include <cppunit/extensions/HelperMacros.h>
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>
44 #include <container.hxx>
45 #include <socket_client.hxx>
46 #include <socket_server.hxx>
47 #include <command_client.hxx>
48 #include <command_server.hxx>
49 #include <client_wrapper.hxx>
50 #include <socket_wrapper.hxx>
57 using namespace libt2n;
58 using namespace CppUnit;
62 stringstream logstream;
63 bool close_server=false;
64 bool kill_server=false;
77 std::string getserverlog(void)
79 return logstream.str();
82 class serverfunc_res : public libt2n::result
87 friend class boost::serialization::access;
88 template<class Archive>
89 void serialize(Archive & ar, const unsigned int version)
91 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
92 ar & BOOST_SERIALIZATION_NVP(res);
110 class getserverlog_res : public libt2n::result
115 friend class boost::serialization::access;
116 template<class Archive>
117 void serialize(Archive & ar, const unsigned int version)
119 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
120 ar & BOOST_SERIALIZATION_NVP(res);
127 getserverlog_res(std::string s)
132 std::string get_data()
138 class cmd_group_x : public command
141 friend class boost::serialization::access;
142 template<class Archive>
143 void serialize(Archive & ar, const unsigned int version)
145 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
149 class serverfunc_cmd : public cmd_group_x
154 friend class boost::serialization::access;
155 template<class Archive>
156 void serialize(Archive & ar, const unsigned int version)
158 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(cmd_group_x);
159 ar & BOOST_SERIALIZATION_NVP(param);
166 serverfunc_cmd(int i)
171 libt2n::result* operator()()
173 return new serverfunc_res(serverfunc(param));
177 class getserverlog_cmd : public cmd_group_x
180 friend class boost::serialization::access;
181 template<class Archive>
182 void serialize(Archive & ar, const unsigned int version)
184 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(cmd_group_x);
191 libt2n::result* operator()()
193 return new getserverlog_res(getserverlog());
197 BOOST_CLASS_EXPORT(serverfunc_res)
198 BOOST_CLASS_EXPORT(getserverlog_res)
199 BOOST_CLASS_EXPORT(cmd_group_x)
200 BOOST_CLASS_EXPORT(serverfunc_cmd)
201 BOOST_CLASS_EXPORT(getserverlog_cmd)
203 class cmd_group_x_client : public command_client
206 cmd_group_x_client(libt2n::client_connection *_c,
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)
212 int serverfunc(int i)
214 libt2n::result_container rc;
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();
222 std::string getserverlog(void)
224 libt2n::result_container rc;
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();
233 typedef T2nSingletonWrapper<cmd_group_x_client> wraptype;
236 std::auto_ptr<wraptype> wraptype::SingletonObject = std::auto_ptr<wraptype>();
239 std::auto_ptr<ConnectionWrapper> wraptype::WrappedConnection = std::auto_ptr<ConnectionWrapper>();
241 class test_wrapper : public TestFixture
243 CPPUNIT_TEST_SUITE(test_wrapper);
245 CPPUNIT_TEST(no_init_exception); // must be called first!!!
246 CPPUNIT_TEST(simple_wrap);
247 CPPUNIT_TEST(double_use);
248 CPPUNIT_TEST(double_use_with_close);
249 CPPUNIT_TEST(reconnect_after_close);
250 CPPUNIT_TEST(reconnect_not_possible);
251 CPPUNIT_TEST(ignore_server_disconnect);
252 CPPUNIT_TEST(ignore_handler_reconnects);
254 CPPUNIT_TEST_SUITE_END();
265 switch(child_pid=fork())
269 CPPUNIT_FAIL("fork error");
278 while(i < 10 && !kill_server)
282 socket_server ss("./socket");
283 group_command_server<cmd_group_x> cs(ss);
284 ss.set_logging(&logstream,debug);
287 for (; !close_server && !kill_server && i < 10; i++)
292 std::cerr << "exception in child. ignoring\n";
295 // don't call atexit and stuff
302 // wait till server is up
311 // make sure the server-child is dead before the next test runs
312 kill(child_pid,SIGKILL);
316 void no_init_exception()
318 CPPUNIT_ASSERT_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),std::logic_error);
323 wraptype::set_connection(auto_ptr<ConnectionWrapper>
324 (new BasicSocketWrapper("./socket")));
326 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
328 CPPUNIT_ASSERT_EQUAL(2,i);
333 // only one connection used?
334 wraptype::set_connection(auto_ptr<ConnectionWrapper>
335 (new BasicSocketWrapper("./socket")));
337 t2n_exec(&cmd_group_x_client::serverfunc)(17);
338 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
340 // count the number of times that "new connection accepted" appears in the server log
341 string::size_type p=0;
343 while ((p=out.find("new connection accepted",p))++ != string::npos)
346 CPPUNIT_ASSERT_EQUAL(1,cnt);
349 void double_use_with_close()
351 wraptype::set_connection(auto_ptr<ConnectionWrapper>
352 (new BasicSocketWrapper("./socket")));
354 t2n_exec(&cmd_group_x_client::serverfunc)(17);
356 // closes the connection from the client side
357 wraptype::set_connection(auto_ptr<ConnectionWrapper>
358 (new BasicSocketWrapper("./socket")));
360 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
362 // count the number of times that "new connection accepted" appears in the server log
363 string::size_type p=0;
365 while ((p=out.find("new connection accepted",p))++ != string::npos)
368 CPPUNIT_ASSERT_EQUAL(2,cnt);
371 void reconnect_after_close()
373 wraptype::set_connection(auto_ptr<ConnectionWrapper>
374 (new ReconnectSocketWrapper("./socket")));
376 wraptype::get_connection_wrapper()->set_command_timeout_usec(3000000);
377 wraptype::get_connection_wrapper()->set_hello_timeout_usec(3000000);
379 // 42 closes connection on the server side
380 t2n_exec(&cmd_group_x_client::serverfunc)(42);
382 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
384 // count the number of times that "new connection accepted" appears in the server log
385 string::size_type p=0;
387 while ((p=out.find("new connection accepted",p))++ != string::npos)
390 CPPUNIT_ASSERT_EQUAL(2,cnt);
393 void reconnect_not_possible()
395 wraptype::set_connection(auto_ptr<ConnectionWrapper>
396 (new ReconnectSocketWrapper("./socket")));
398 // the server doens't like the beast
399 t2n_exec(&cmd_group_x_client::serverfunc)(666);
401 CPPUNIT_ASSERT_THROW(t2n_exec(&cmd_group_x_client::serverfunc)(1),t2n_communication_error);
404 void ignore_server_disconnect()
406 wraptype::set_connection(auto_ptr<ConnectionWrapper>
407 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
409 // the server doens't like the beast
410 t2n_exec(&cmd_group_x_client::serverfunc)(666);
412 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
414 // result is constructed with default constructor on error-and-ignore -> i=0
416 CPPUNIT_ASSERT_EQUAL(0,i);
419 void ignore_handler_reconnects()
421 wraptype::set_connection(auto_ptr<ConnectionWrapper>
422 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
424 wraptype::get_connection_wrapper()->set_command_timeout_usec(3000000);
425 wraptype::get_connection_wrapper()->set_hello_timeout_usec(3000000);
427 // 42 closes connection on the server side
428 t2n_exec(&cmd_group_x_client::serverfunc)(42);
430 string out=t2n_exec(&cmd_group_x_client::getserverlog)();
432 // count the number of times that "new connection accepted" appears in the server log
433 string::size_type p=0;
435 while ((p=out.find("new connection accepted",p))++ != string::npos)
438 CPPUNIT_ASSERT_EQUAL(2,cnt);
443 CPPUNIT_TEST_SUITE_REGISTRATION(test_wrapper);
446 class test_wrapper_noserver : public TestFixture
448 CPPUNIT_TEST_SUITE(test_wrapper_noserver);
450 CPPUNIT_TEST(ignore_noserver);
451 CPPUNIT_TEST(ignore_finds_lateserver);
452 CPPUNIT_TEST(ignore_wrongserver);
454 CPPUNIT_TEST_SUITE_END();
467 // make sure the server-child is dead before the next test runs
470 kill(child_pid,SIGKILL);
475 void ignore_noserver()
477 wraptype::set_connection(auto_ptr<ConnectionWrapper>
478 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
480 // wraptype::get_connection_wrapper()->set_logging(&cerr,debug);
482 // there is no server
484 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
486 // result is constructed with default constructor on error-and-ignore -> i=0
488 CPPUNIT_ASSERT_EQUAL(0,i);
491 void ignore_finds_lateserver()
493 wraptype::set_connection(auto_ptr<ConnectionWrapper>
494 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
496 // there is no server
497 t2n_exec(&cmd_group_x_client::serverfunc)(1);
503 switch(child_pid=fork())
507 CPPUNIT_FAIL("fork error");
516 while(i < 10 && !kill_server)
520 socket_server ss("./socket");
521 group_command_server<cmd_group_x> cs(ss);
522 ss.set_logging(&logstream,debug);
525 for (; !close_server && !kill_server && i < 10; i++)
530 std::cerr << "exception in child. ignoring\n";
533 // don't call atexit and stuff
540 // wait till server is up
545 // server should be active
546 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
548 CPPUNIT_ASSERT_EQUAL(2,i);
551 void send_hello(string hello_string, socket_server* ss, int conn_id)
553 server_connection *sc=ss->get_connection(conn_id);
554 sc->write(hello_string);
557 void ignore_wrongserver()
559 wraptype::set_connection(auto_ptr<ConnectionWrapper>
560 (new ReconnectIgnoreFailureSocketWrapper("./socket")));
564 switch(child_pid=fork())
568 CPPUNIT_FAIL("fork error");
576 socket_server ss("./socket");
578 // server sends garbage
583 ss.add_callback(new_connection,bind(&test_wrapper_noserver::send_hello, boost::ref(*this), hello.str(),&ss, _1));
586 for (int i=0; i < 10; i++)
587 ss.fill_buffer(1000000);
590 std::cerr << "exception in child. ignoring\n";
593 // don't call atexit and stuff
600 // wait till server is up
605 // there is no valid server
607 int i=t2n_exec(&cmd_group_x_client::serverfunc)(1);
609 // result is constructed with default constructor on error-and-ignore -> i=0
611 CPPUNIT_ASSERT_EQUAL(0,i);
617 CPPUNIT_TEST_SUITE_REGISTRATION(test_wrapper_noserver);