def client_failure(self, error, *args, **kwargs): """ This is called from Twisted upon an error """ # pylint: disable=unused-argument client = args[0] client["error"] = error log_text(self._logger.error, __name__, "client:{0} failed to start: {1}".format(args[0]["name"], error)) return ConnectionError(str(error))
def server_failure(self, error, *args, **kwargs): """ This is called when a server fails to connect """ # pylint: disable=unused-argument server = args[0] server["error"] = error log_text(self._logger.error, __name__, "server:{0} failed to start: {1}".format(args[0]["name"], error)) return ConnectionError(str(error))
def server_success(self, result, *args, **kwargs): """ This is called when a server starts listening """ # pylint: disable=unused-argument server = args[0] server["listener"] = result log_text(self._logger.info, __name__, "server:{0} listening on port {1}".format(server["name"], server["port"]))
def server_failure(self, error, *args, **kwargs): """ This is called when a server fails to connect """ # pylint: disable=unused-argument server = args[0] server['error'] = error log_text( self._logger.error, __name__, 'server:{0} failed to start: {1}'.format(args[0]['name'], error)) return ConnectionError(str(error))
def client_failure(self, error, *args, **kwargs): """ This is called from Twisted upon an error """ # pylint: disable=unused-argument client = args[0] client['error'] = error log_text( self._logger.error, __name__, 'client:{0} failed to start: {1}'.format(args[0]['name'], error)) return ConnectionError(str(error))
def client_success(self, result, *args, **kwargs): """ This is called from Twisted upon connection """ # pylint: disable=unused-argument client = args[0] client["connected"] = "success" log_text( self._logger.info, __name__, "client:{0} connected to {1}:{2}".format(client["name"], client["host"], client["port"]), )
def server_success(self, result, *args, **kwargs): """ This is called when a server starts listening """ # pylint: disable=unused-argument server = args[0] server['listener'] = result log_text( self._logger.info, __name__, 'server:{0} listening on port {1}'.format(server['name'], server['port']))
def client_success(self, result, *args, **kwargs): """ This is called from Twisted upon connection """ # pylint: disable=unused-argument client = args[0] client['connected'] = 'success' log_text( self._logger.info, __name__, 'client:{0} connected to {1}:{2}'.format(client['name'], client['host'], client['port']))
def buildProtocol(self, addr): """ Creates and pulls together the components to build up the full interface. This is called from Twisted. """ # pylint: disable=unused-argument log_text(self._logger.info, None, "Connected: {0} : {1}".format(self.__class__, self._name)) transport = self.create_transport(self._name, self._node_config, self._link_config) self.servers.append(transport) return transport
def buildProtocol(self, addr): """ Creates and pulls together the components to build up the full interface. This is called from Twisted. """ # pylint: disable=unused-argument log_text(self._logger.info, None, 'Connected: {0} : {1}'.format(self.__class__, self._name)) transport = self.create_transport(self._name, self._node_config, self._link_config) self.servers.append(transport) return transport
def _start_client(self, client): """ This is a helper function that needs to get called on the reactor thread. Arguments: client: The client dict(). """ log_text(self._logger.info, None, 'client:{0} attempting {1}:{2}'.format( client['name'], client['host'], client['port'])) endpoint = clientFromString( reactor, b"tcp:{0}:{1}:timeout=10".format(client['host'], client['port'])) node = client['node'] deferred = connectProtocol(endpoint, node) deferred.addCallbacks(node.client_success, callbackArgs=(client,), errback=node.client_failure, errbackArgs=(client,))
def on_data_received(self, data): """ Passes data to the parser. Once a message has been fully read in, the on_message callback is called. When an error is detected in a message, on_error is called. Args: data: The binary data that has been received. This may either be a binary string or a single byte ot data. """ # pylint: disable=too-many-branches,too-many-statements if self.is_receiving_data is True: self._buffer += data return try: self.is_receiving_data = True self._buffer += data # Keep looping while we have unprocessed data # We start processing only once we have an entire field # (e.g. 'id=value') in the buffer, otherwise wait for more # data. # The problem with the current approach is that if there is a # binary field with an incorrect length, we may read past # the end of the message. # BUGBUG: Need to fix this. A quick hack may be to # try to peek to see what the tag id is and do something # with that. On the other hand this may just be a problem # with the protocol (should probably specify a maximum # allowable length of a binary field as a sanity check) while (len(self._buffer) > 0 and self._buffer.find(b'\x01', self._binary_length + 1) != -1): # Need to make sure that we have the entire binary field # before continuing the processing if (self._binary_length > 0 and len(self._buffer) < self._binary_length): break # break up the field delim = self._buffer.find(b'\x01', self._binary_length + 1) field = self._buffer[:delim] self._buffer = self._buffer[delim+1:] tag_id, value = self._parse_field(field) # Is this the start of a message? if tag_id == 8: if self.is_parsing: raise FIXParserError('unexpected tag: 8') self.is_parsing = True elif not self.is_parsing: raise FIXParserError('message must start with tag 8') if self._debug: log_text(self._logger.debug, None, "tag {0} = {1}".format(tag_id, repr(value))) self._update_length(field, tag_id, value) self._update_checksum(field, tag_id, value) self._update_binary(field, tag_id, value) # The tag value gets assigned here. Due to grouping # the container where the update takes place gets # changed # self._message[tag_id] = value self._update_field(tag_id, value) # Is this the end of a message? if tag_id == 10: self._receiver.on_message_received(self._message, self._message_length, self._checksum) self.reset() except FIXLengthTooLongError, err: self.reset(flush_buffer=True) self._receiver.on_error_received(err)
def main(): """ Main entrypoint for the tool. This will be called from the command-line script. """ _setup_logging_config() logger = logging.getLogger(__name__) test_thread = None controller = None def term_signal_handler(num, frame): """ The signal-handler for the Twisted reactor. We assume that all signals are to shutdown the reactor and cancel the running tests. """ # pylint: disable=unused-argument if controller is not None: controller.cancel_test() # The actual stop gets called in the finally portion # of the run loop. # reactor.callInThread(reactor.stop) def start_test_thread(call_function): """ This will be called on the reactor thread to start up the testcase thread. """ test_thread = threading.Thread(target=call_function) test_thread.start() arg_results = _parse_command_line_args() if arg_results.version is True: print "{0}, version {1}".format(sys.argv[0], VERSION_STRING) sys.exit(2) if arg_results.debug is True: logger.setLevel(logging.DEBUG) # Twisted logging observer = log.PythonLoggingObserver() observer.start() file_name = arg_results.config_file if not os.path.isfile(file_name): print "Cannot find the configuration file: {0}".format(file_name) sys.exit(2) config_file = FileConfig(file_name) # load/create the TestCaseController controller_class = _find_controller(arg_results.test_name) log_text(logger.info, None, '================') log_text(logger.info, None, 'Starting test: ' + str(datetime.datetime.now().date())) log_text(logger.info, None, ' Module: ' + arg_results.test_name) log_text(logger.info, None, ' Controller: ' + controller_class.__name__) log_text(logger.info, None, ' Config: ' + file_name) controller = controller_class(config=config_file, test_params=arg_results.args) log_text(logger.info, None, '') log_text(logger.info, None, ' Test case: ' + controller.testcase_id) log_text(logger.info, None, ' Description: ' + controller.description) log_text(logger.info, None, '================') # startup the servers (they don't really startup until reactor.run()) for server in controller.servers().values(): log_text(logger.info, None, 'server:{0} starting on port {1}'.format(server['name'], server['port'])) endpoint = serverFromString(reactor, b"tcp:{0}".format(server['port'])) factory = server['factory'] deferred = endpoint.listen(factory) deferred.addCallbacks(factory.server_success, callbackArgs=(server,), errback=factory.server_failure, errbackArgs=(server,)) for sig in [signal.SIGINT, signal.SIGHUP, signal.SIGTERM, signal.SIGQUIT]: signal.signal(sig, term_signal_handler) reactor.callWhenRunning(start_test_thread, controller._execute_test) reactor.run() if test_thread is not None: test_thread.join() log_text(logger.info, None, '================') log_text(logger.info, None, "Test status: {0}\n".format(controller.test_status)) sys.exit(controller.exit_value)
def connectionLost(self, reason=None): # pylint: disable=unused-argument log_text(self._logger.info, self.name, "Connection lost")
def connectionMade(self): log_text(self._logger.info, self.name, "Connection made")
def on_data_received(self, data): """ Passes data to the parser. Once a message has been fully read in, the on_message callback is called. When an error is detected in a message, on_error is called. Args: data: The binary data that has been received. This may either be a binary string or a single byte ot data. """ # pylint: disable=too-many-branches,too-many-statements if self.is_receiving_data is True: self._buffer += data return try: self.is_receiving_data = True self._buffer += data # Keep looping while we have unprocessed data # We start processing only once we have an entire field # (e.g. 'id=value') in the buffer, otherwise wait for more # data. # The problem with the current approach is that if there is a # binary field with an incorrect length, we may read past # the end of the message. # BUGBUG: Need to fix this. A quick hack may be to # try to peek to see what the tag id is and do something # with that. On the other hand this may just be a problem # with the protocol (should probably specify a maximum # allowable length of a binary field as a sanity check) while (len(self._buffer) > 0 and self._buffer.find(b'\x01', self._binary_length + 1) != -1): # Need to make sure that we have the entire binary field # before continuing the processing if (self._binary_length > 0 and len(self._buffer) < self._binary_length): break # break up the field delim = self._buffer.find(b'\x01', self._binary_length + 1) field = self._buffer[:delim] self._buffer = self._buffer[delim + 1:] tag_id, value = self._parse_field(field) # Is this the start of a message? if tag_id == 8: if self.is_parsing: raise FIXParserError('unexpected tag: 8') self.is_parsing = True elif not self.is_parsing: raise FIXParserError('message must start with tag 8') if self._debug: log_text(self._logger.debug, None, "tag {0} = {1}".format(tag_id, repr(value))) self._update_length(field, tag_id, value) self._update_checksum(field, tag_id, value) self._update_binary(field, tag_id, value) # The tag value gets assigned here. Due to grouping # the container where the update takes place gets # changed # self._message[tag_id] = value self._update_field(tag_id, value) # Is this the end of a message? if tag_id == 10: self._receiver.on_message_received(self._message, self._message_length, self._checksum) self.reset() except FIXLengthTooLongError, err: self.reset(flush_buffer=True) self._receiver.on_error_received(err)
def main(): """ Main entrypoint for the tool. This will be called from the command-line script. """ _setup_logging_config() logger = logging.getLogger(__name__) test_thread = None controller = None def term_signal_handler(num, frame): """ The signal-handler for the Twisted reactor. We assume that all signals are to shutdown the reactor and cancel the running tests. """ # pylint: disable=unused-argument if controller is not None: controller.cancel_test() # The actual stop gets called in the finally portion # of the run loop. # reactor.callInThread(reactor.stop) def start_test_thread(call_function): """ This will be called on the reactor thread to start up the testcase thread. """ test_thread = threading.Thread(target=call_function) test_thread.start() arg_results = _parse_command_line_args() if arg_results.version is True: print "{0}, version {1}".format(sys.argv[0], VERSION_STRING) sys.exit(2) if arg_results.debug is True: logger.setLevel(logging.DEBUG) # Twisted logging observer = log.PythonLoggingObserver() observer.start() file_name = arg_results.config_file if not os.path.isfile(file_name): print "Cannot find the configuration file: {0}".format(file_name) sys.exit(2) config_file = FileConfig(file_name) # load/create the TestCaseController controller_class = _find_controller(arg_results.test_name) log_text(logger.info, None, '================') log_text(logger.info, None, 'Starting test: ' + str(datetime.datetime.now().date())) log_text(logger.info, None, ' Module: ' + arg_results.test_name) log_text(logger.info, None, ' Controller: ' + controller_class.__name__) log_text(logger.info, None, ' Config: ' + file_name) controller = controller_class(config=config_file, test_params=arg_results.args) log_text(logger.info, None, '') log_text(logger.info, None, ' Test case: ' + controller.testcase_id) log_text(logger.info, None, ' Description: ' + controller.description) log_text(logger.info, None, '================') # startup the servers (they don't really startup until reactor.run()) for server in controller.servers().values(): log_text( logger.info, None, 'server:{0} starting on port {1}'.format(server['name'], server['port'])) endpoint = serverFromString(reactor, b"tcp:{0}".format(server['port'])) factory = server['factory'] deferred = endpoint.listen(factory) deferred.addCallbacks(factory.server_success, callbackArgs=(server, ), errback=factory.server_failure, errbackArgs=(server, )) for sig in [signal.SIGINT, signal.SIGHUP, signal.SIGTERM, signal.SIGQUIT]: signal.signal(sig, term_signal_handler) reactor.callWhenRunning(start_test_thread, controller._execute_test) reactor.run() if test_thread is not None: test_thread.join() log_text(logger.info, None, '================') log_text(logger.info, None, "Test status: {0}\n".format(controller.test_status)) sys.exit(controller.exit_value)