/*************************************************************************** * Copyright (C) 2004 by Intra2net AG * * info@intra2net.com * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif using namespace std; using namespace libt2n; using namespace CppUnit; string testfunc2(const string& str) { if (str=="throw") throw libt2n::t2n_runtime_error("throw me around"); string ret(str); ret+=", testfunc() was here"; return ret; } class testfunc2_res : public libt2n::result { private: string res; friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result); ar & BOOST_SERIALIZATION_NVP(res); } public: testfunc2_res() { } testfunc2_res(const string& str) { res=str; } string get_data() { return res; } }; class testfunc2_cmd : public libt2n::command { private: string param; friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command); ar & BOOST_SERIALIZATION_NVP(param); } public: testfunc2_cmd() { } testfunc2_cmd(const string& str) { param=str; } libt2n::result* operator()() { return new testfunc2_res(testfunc2(param)); } }; #include BOOST_CLASS_EXPORT(testfunc2_cmd) BOOST_CLASS_EXPORT(testfunc2_res) // this is an evil hack to get access to real_write, don't ever do this in an app!!! class real_write_connection: public socket_server_connection { public: void real_write(const std::string& data) { socket_write(data); } }; class test_timeout : public TestFixture { CPPUNIT_TEST_SUITE(test_timeout); CPPUNIT_TEST(HelloTimeoutNothing); CPPUNIT_TEST(HelloTimeoutSlowData); CPPUNIT_TEST(CommandTimeout); CPPUNIT_TEST(CommandSlowResponse); CPPUNIT_TEST_SUITE_END(); public: typedef uint32_t packet_size_indicator; void setUp() { } void tearDown() { } void send_hello(string hello_string, socket_server* ss, unsigned int conn_id) { server_connection *sc=ss->get_connection(conn_id); sc->write(hello_string); } void send_slow_raw_socket(string data, socket_server* ss, unsigned int conn_id) { socket_server_connection *ssc=dynamic_cast(ss->get_connection(conn_id)); // this is an evil hack to get access to real_write, don't ever do this in an app!!! real_write_connection *rwc=(real_write_connection*)ssc; // we write one char each 0.2 sec for (int pos=0; pos < data.size(); pos++) { string onebyte; onebyte+=data[pos]; rwc->real_write(onebyte); usleep(200000); } } void HelloTimeoutNothing() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); // max 10 sec for (int i=0; i < 10; i++) ss.fill_buffer(1000000); // don't call atexit and stuff _exit(0); } default: // parent { string data; // wait till server is up sleep(1); socket_client_connection sc("./socket"); string errormsg; try { command_client cc(sc,1000000,1000000); } catch(t2n_transfer_error &e) { errormsg=e.what(); } catch(...) { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); } } } void HelloTimeoutSlowData() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); // create a valid packet ostringstream hello; hello << "T2Nv" << PROTOCOL_VERSION << ';'; int byteordercheck=1; hello.write((char*)&byteordercheck,sizeof(byteordercheck)); hello << ';'; packet_size_indicator psize=htonl(hello.str().size()); std::string send_data(hello.str()); send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator)); ss.add_callback(new_connection,bind(&test_timeout::send_slow_raw_socket, boost::ref(*this), send_data,&ss, _1)); // max 10 sec for (int i=0; i < 10; i++) ss.fill_buffer(1000000); // don't call atexit and stuff _exit(0); } default: // parent { string data; // wait till server is up sleep(1); socket_client_connection sc("./socket"); string errormsg; try { command_client cc(sc,1000000,1000000); } catch(t2n_transfer_error &e) { errormsg=e.what(); } catch(...) { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); } } } void CommandTimeout() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); ostringstream hello; hello << "T2Nv" << PROTOCOL_VERSION << ';'; int byteordercheck=1; hello.write((char*)&byteordercheck,sizeof(byteordercheck)); hello << ';'; ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1)); // max 10 sec for (int i=0; i < 10; i++) ss.fill_buffer(1000000); // don't call atexit and stuff _exit(0); } default: // parent { string data; // wait till server is up sleep(1); socket_client_connection sc("./socket"); command_client cc(sc,1000000,1000000); result_container rc; string errormsg; try { cc.send_command(new testfunc2_cmd("hello"),rc); } catch(t2n_transfer_error &e) { errormsg=e.what(); } catch(...) { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); } } } void CommandSlowResponse() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); ostringstream hello; hello << "T2Nv" << PROTOCOL_VERSION << ';'; int byteordercheck=1; hello.write((char*)&byteordercheck,sizeof(byteordercheck)); hello << ';'; ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1)); // max 10 sec for (int i=0; i < 10; i++) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { // create a valid packet & send string response="abcdefghijklmnopqrstuvwxyz"; packet_size_indicator psize=htonl(response.size()); std::string send_data(response); send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator)); send_slow_raw_socket(send_data,&ss,cid); } } // don't call atexit and stuff _exit(0); } default: // parent { string data; // wait till server is up sleep(1); socket_client_connection sc("./socket"); command_client cc(sc,1000000,1000000); result_container rc; string errormsg; try { cc.send_command(new testfunc2_cmd("hello"),rc); } catch(t2n_transfer_error &e) { errormsg=e.what(); } catch(...) { throw; } CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg); } } } }; CPPUNIT_TEST_SUITE_REGISTRATION(test_timeout);