/*************************************************************************** * 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 using namespace std; using namespace libt2n; using namespace CppUnit; class test_callback : public TestFixture { CPPUNIT_TEST_SUITE(test_callback); CPPUNIT_TEST(ServerNewConnCallback); CPPUNIT_TEST(ServerConnClosedCallback); CPPUNIT_TEST(ServerConnDeletedCallback); CPPUNIT_TEST(ServerCallbackOrder); CPPUNIT_TEST(ClientConnClosedCallback); CPPUNIT_TEST(ClientConnDeletedCallback); CPPUNIT_TEST_SUITE_END(); std::vector callback_done; public: void setUp() { callback_done.resize(__events_end); } void tearDown() { callback_done.clear(); } void callback_func(callback_event_type ev, int conn_id) { // we don't care for the conn_id, we just mark the callback as done if (callback_done[ev]) throw runtime_error("callback already done for this event"); callback_done[ev]=true; } void ServerNewConnCallback() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { string data; // wait till server is up sleep(1); { socket_client_connection sc("./socket"); sc.write("ABC"); // wait half a sec sc.fill_buffer(500000); sc.get_packet(data); // close the connection } // don't call atexit and stuff _exit(0); } default: // parent { socket_server ss("./socket"); ss.add_callback(new_connection,bind(&test_callback::callback_func, boost::ref(*this), new_connection, _1)); // max 3 sec for (int i=0; i < 3; i++) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); con->write("XYZ"); } } CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[new_connection])); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_closed])); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_deleted])); } } } void ServerConnClosedCallback() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { string data; // wait till server is up sleep(1); { socket_client_connection sc("./socket"); sc.write("ABC"); // wait half a sec sc.fill_buffer(500000); sc.get_packet(data); // close the connection } // don't call atexit and stuff _exit(0); } default: // parent { socket_server ss("./socket"); ss.add_callback(connection_closed,bind(&test_callback::callback_func, boost::ref(*this), connection_closed, _1)); // max 3 sec for (int i=0; i < 3; i++) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); con->write("XYZ"); } } CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[new_connection])); CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_closed])); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_deleted])); } } } void ServerConnDeletedCallback() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { string data; // wait till server is up sleep(1); { socket_client_connection sc("./socket"); sc.write("ABC"); // wait half a sec sc.fill_buffer(500000); sc.get_packet(data); // close the connection } // don't call atexit and stuff _exit(0); } default: // parent { socket_server ss("./socket"); ss.add_callback(connection_deleted,bind(&test_callback::callback_func, boost::ref(*this), connection_deleted, _1)); // max 3 sec for (int i=0; i < 3; i++) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); con->write("XYZ"); } ss.cleanup(); } ss.cleanup(); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[new_connection])); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_closed])); CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_deleted])); } } } void ServerCallbackOrder() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { string data; // wait till server is up sleep(1); { socket_client_connection sc("./socket"); sc.write("1"); // wait half a sec sc.fill_buffer(500000); sc.get_packet(data); sc.write("2"); // close the connection } // don't call atexit and stuff _exit(0); } default: // parent { socket_server ss("./socket"); ss.add_callback(connection_closed,bind(&test_callback::callback_func, boost::ref(*this), connection_closed, _1)); ss.add_callback(connection_deleted,bind(&test_callback::callback_func, boost::ref(*this), connection_deleted, _1)); bool got_1=false; for (int i=0; i < 4; i++) { ss.fill_buffer(500000); string data; unsigned int cid; if(!got_1 && ss.get_packet(data,cid)) { server_connection* con=ss.get_connection(cid); con->write("XYZ"); got_1=true; // don't call get_packet anymore } ss.cleanup(); } ss.cleanup(); CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_closed])); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_deleted])); for (int i=0; i < 4; i++) { ss.fill_buffer(500000); string data; unsigned int cid; ss.get_packet(data,cid); ss.cleanup(); } ss.cleanup(); CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_closed])); CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_deleted])); } } } void ClientConnClosedCallback() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); // max 3 sec for (int i=0; i < 3; i++) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) break; } // don't call atexit and stuff _exit(0); } default: // parent { string data; // wait till server is up sleep(1); socket_client_connection sc("./socket"); sc.add_callback(connection_closed,bind(&test_callback::callback_func, boost::ref(*this), connection_closed, 0)); sc.write("ABC"); // wait half a sec sc.fill_buffer(500000); sc.get_packet(data); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[new_connection])); CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_closed])); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_deleted])); } } } void ClientConnDeletedCallback() { pid_t pid; switch(pid=fork()) { case -1: { CPPUNIT_FAIL("fork error"); break; } case 0: // child { socket_server ss("./socket"); // max 3 sec for (int i=0; i < 3; i++) { ss.fill_buffer(1000000); string data; unsigned int cid; if(ss.get_packet(data,cid)) break; } // don't call atexit and stuff _exit(0); } default: // parent { string data; // wait till server is up sleep(1); { socket_client_connection sc("./socket"); sc.add_callback(connection_deleted,bind(&test_callback::callback_func, boost::ref(*this), connection_deleted, 0)); sc.write("ABC"); // wait half a sec sc.fill_buffer(500000); sc.get_packet(data); } CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[new_connection])); CPPUNIT_ASSERT_EQUAL(false,static_cast(callback_done[connection_closed])); CPPUNIT_ASSERT_EQUAL(true,static_cast(callback_done[connection_deleted])); } } } }; CPPUNIT_TEST_SUITE_REGISTRATION(test_callback);