// -*- c++ -*- // Generated by assa-genesis //------------------------------------------------------------------------------ // $Id: connector2_test.cpp,v 1.10 2006/07/20 02:30:55 vlg Exp $ //------------------------------------------------------------------------------ // ConnectCancelTest.cpp //------------------------------------------------------------------------------ // Copyright (c) 2002,2005 by Vladislav Grinchenko // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version // 2 of the License, or (at your option) any later version. //------------------------------------------------------------------------------ // // Date : Wed Dec 11 14:06:16 2002 // //------------------------------------------------------------------------------ static const char help_msg[]= " \n" " NAME: \n" " \n" " connector2_test \n" " \n" " DESCRIPTION: \n" " \n" " This is the test for Bug # 651712 (Connector sync mode bug): \n" " \n" " When Connector connects successfully with remote service and \n" " ServiceHandler returns -1 from its open() call, the return value \n" " is ignored. \n" " Instead, Connector::connect() should return -1 to the application-level \n" " calling code. \n" " \n" " First, the test spans off 'echos' server and then connects to it twice. \n" " First time 'echos' ServiceHandler returns -1 from its open(). \n" " The return value is tested to see if indeed -1 is returned to the \n" " application code. Second time around, the connection establishment \n" " is successful and we write a greeting message to 'echos' server, \n" " read and validate the reply and exit. \n" " \n" " USAGE: \n" " \n" " shell> connector2_test [OPTIONS] \n" " \n" " OPTIONS: \n" " \n" " -p, --port NAME - Port number for echos to listen to requests. \n" " -D, --log-file NAME - Write debug to NAME file \n" " -d, --log-stdout - Write debug to standard output \n" " -z, --log-size NUM - Maximum size debug file can reach (dfl: is 10Mb) \n" " -m, --mask MASK - Mask (default: ALL = 0x7fffffff) \n" " -h, --help - Print this messag \n" " -v, --version - Print version number \n"; //------------------------------------------------------------------------------ #if !defined (WIN32) #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include using std::string; #include #include #include #include #include #include #include #include #include using namespace ASSA; //------------------------------------------------------------------------------ // Echo //------------------------------------------------------------------------------ class Echo : public ServiceHandler { public: Echo () : m_msg ("Privet, Vlad") { trace("Echo::Echo"); } virtual int open (); virtual int handle_read (int fd_); virtual int handle_close (int fd_); private: static u_int m_invocation; std::string m_msg; }; u_int Echo::m_invocation = 0; //------------------------------------------------------------------------------ // ConnectCancelTest //------------------------------------------------------------------------------ class ConnectCancelTest : public ASSA::GenServer, public ASSA::Singleton { public: ConnectCancelTest (); ~ConnectCancelTest (); virtual void init_service (); virtual void process_events (); std::string get_build_dir () const { return m_build_dir; } void test_failed () { set_exit_value (1); } private: std::string m_build_dir; Echo* m_echo; INETAddress* m_address; pid_t m_echo_pid; Connector m_connector; }; /* Useful definitions */ #define CONNECTCANCELTEST ConnectCancelTest::get_instance() #define REACTOR CONNECTCANCELTEST->get_reactor() // Static declarations mandated by Singleton class ASSA_DECL_SINGLETON(ConnectCancelTest); //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ int Echo:: open () { trace("Echo::open"); if (m_invocation++ == 0) { DL((APP,"First attempt = return -1\n")); return -1; } DL((APP,"Second attempt = return 0\n")); IPv4Socket& s = *this; Assure_exit (s.write (m_msg.c_str (), m_msg.size ()) == m_msg.size ()); s << flush; REACTOR->registerIOHandler (this, s.getHandler (), READ_EVENT); return 0; } int Echo:: handle_close (int) { trace("Echo::close"); CONNECTCANCELTEST->stop_service (); } int Echo:: handle_read (int fd_) { trace("Echo::handle_read"); IPv4Socket& s = *this; char* buf = new char [m_msg.size () +1]; u_int expected = m_msg.size (); char* nextbyte = buf; int ret = 0; while ((ret = s.read (nextbyte, expected)) > 0) { nextbyte += ret; expected -= ret; if (expected == 0) { *nextbyte = '\0'; break; } } if (buf == m_msg) { std::cout << "Test 2 passed" << std::endl; DL((APP,"Test 2 passed\n")); delete [] buf; return -1; } else { std::cout << "Test 2 failed" << std::endl; DL ((APP,"Test 2 failed\n")); DL ((APP,"Expected = \"%s\"\n", m_msg.c_str ())); DL ((APP,"Received = \"%s\"\n", buf)); CONNECTCANCELTEST->test_failed (); } return -1; } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ ConnectCancelTest:: ConnectCancelTest () : m_address (NULL), m_echo_pid (0) { // ---Configuration--- rm_opt ('f', "config-file" ); rm_opt ('n', "instance" ); // ---Process bookkeeping--- rm_opt ('b', "daemon" ); rm_opt ('l', "pidfile" ); rm_opt ('L', "ommit-pidfile"); /*--- * By defauil disable all debugging *---*/ m_mask = ASSA::APP; m_log_file = "connector2_test.log"; add_opt (0, "build-dir", &m_build_dir); } ConnectCancelTest:: ~ConnectCancelTest () { trace("ConnectCancelTest::~ConnectCancelTest"); if (m_echo) { delete m_echo; m_echo = NULL; } if (m_address) { delete m_address; m_address = NULL; } } void ConnectCancelTest:: init_service () { trace("ConnectCancelTest::init_service"); if (m_build_dir.length () == 0) { m_build_dir = ASSA::Utils::get_cwd_name (); } DL((APP,"build-dir = \"%s\"\n", m_build_dir.c_str ())); m_address = new INETAddress (get_port ().c_str ()); if (m_address->bad ()) { std::cerr << "Missing --port=NUM option\n"; exit (1); } std::string exec_name (get_build_dir () + "/echos"); Fork ss (Fork::KILL_ON_EXIT, Fork::IGNORE_STATUS); if (ss.isChild ()) { ::execlp (exec_name.c_str (), exec_name.c_str (), "--port", get_port ().c_str (), "--mask=0x7fffffff", NULL); std::cerr << "Failed to execlp(" << exec_name << std::endl; exit (1); } else if (ss.isParent ()) { m_echo_pid = ss.getChildPID (); ASSA::Utils::sleep_for_seconds (2); } DL((ASSA::APP,"Service has been initialized\n")); } void ConnectCancelTest:: process_events () { trace("ConnectCancelTest::process_events"); m_echo = new Echo; TimeVal timeout (5.0); if (m_connector.open (timeout) < 0) { std::cout << "open (" << get_port () << "@" << m_address->getHostName () << " failed" << std::endl; set_exit_value (1); return; } /** Test 1: connection ok, but Echo rejects it. */ if (m_connector.connect (m_echo, *m_address) != -1) { std::cout << "Test 1 failed" << std::endl; DL((APP,"Test 1 failed\n")); set_exit_value (1); return; } std::cout << "Test 1 passed" << std::endl; DL((APP,"Test 1 passed\n")); /** Test 2: connection ok, and Echo accepts it. */ if (m_connector.connect (m_echo, *m_address) < 0) { std::cerr << "Test 2 failed" << std::endl; DL((APP,"Test 2 failed\n")); set_exit_value (1); return; } while (service_is_active ()) { m_reactor.waitForEvents (); } // Shut the service down m_reactor.stopReactor (); DL((ASSA::APP,"Service stopped!\n")); } #endif /* !defined WIN32 */ int main (int argc, char* argv[]) { #if !defined (WIN32) static const char release[] = "VERSION"; int patch_level = 0; std::cout << "= Running connector2_test Test =\n\n"; CONNECTCANCELTEST->set_version (release, patch_level); CONNECTCANCELTEST->set_author ("Vladislav Grinchenko"); CONNECTCANCELTEST->set_flags (ASSA::GenServer::RMLOG); CONNECTCANCELTEST->init (&argc, argv, help_msg); CONNECTCANCELTEST->init_service (); CONNECTCANCELTEST->process_events (); return CONNECTCANCELTEST->get_exit_value (); #endif /* !defined WIN32 */ return 0; }