def test_function_method_executor_request(): """test of requests in FunctionMethodExecutor class """ name = 'test_method' executor = FunctionMethodExecutor(PythonLogger(), name, add) assert executor.name == name assert executor.function == add # pylint: disable=comparison-with-callable session = MockSession() msgid = 37 params = [2, 3] request = Request(MsgType.REQUEST, msgid, name, params) response_data = executor.process_request(session, request) response = validate_message(unpack_object(response_data)) assert response.msgtype == MsgType.RESPONSE assert response.msgid == msgid assert response.error is None assert response.result == 5 msgid = 37 params = [2] request = Request(MsgType.REQUEST, msgid, name, params) response_data = executor.process_request(session, request) response = validate_message(unpack_object(response_data)) assert response.msgtype == MsgType.RESPONSE assert response.msgid == msgid assert response.error is not None
def _check_parse_error(data: Any): """check that parse error is raised when parsing data Parameters ---------- data : Any data """ with pytest.raises(MPRPCException) as err: validate_message(data) assert isinstance(err.value.args[0], ErrorInfo) assert err.value.args[0].code == int(ErrorCode.PARSE_ERROR)
def test_parse_notification(): """test of parsing notification messages """ msgtype = 2 method = 'abc' params = [1, 'test', 3.14] data = [msgtype, method, params] notification = validate_message(data) assert isinstance(notification, Notification) assert notification.msgtype == MsgType.NOTIFICATION assert notification.method == method assert notification.params == params data = [msgtype, method] _check_parse_error(data) data = [msgtype, method, params, None] _check_parse_error(data) data = [msgtype, b'abc', params] _check_parse_error(data) data = [msgtype, method, {'abc': 0}] _check_parse_error(data)
def test_parse_response(): """test of parsing response messages """ msgtype = 1 msgid = 37 error = None result = 'result text' data = [msgtype, msgid, error, result] res = validate_message(data) assert isinstance(res, Response) assert res.msgtype == int(MsgType.RESPONSE) assert res.msgid == msgid assert res.error == error assert res.result == result data = [msgtype, msgid, error] _check_parse_error(data) data = [msgtype, msgid, error, result, None] _check_parse_error(data) data = [msgtype, '37', error, result] _check_parse_error(data) data = [msgtype, -1, error, result] _check_parse_error(data)
def test_parse_request(): """test of parsing request messages """ msgtype = 0 msgid = 37 method = 'abc' params = [1, 'test', 3.14] data = [msgtype, msgid, method, params] req = validate_message(data) assert isinstance(req, Request) assert req.msgtype == MsgType.REQUEST assert req.msgid == msgid assert req.method == method assert req.params == params data = [msgtype, msgid, method] _check_parse_error(data) data = [msgtype, msgid, method, params, None] _check_parse_error(data) data = [msgtype, '37', method, params] _check_parse_error(data) data = [msgtype, -1, method, params] _check_parse_error(data) data = [msgtype, msgid, b'abc', params] _check_parse_error(data) data = [msgtype, msgid, method, 5] _check_parse_error(data)
def test_pack_notification(): """test of pack_notification function """ method = 'abc' params = [1, 'param'] data = pack_notification(method=method, params=params) notification = validate_message(unpack_object(data)) assert notification == Notification(MsgType.NOTIFICATION, method, params)
def test_pack_request(): """test of pack_request function """ msgid = 37 method = 'abc' params = [1, 'param'] data = pack_request(msgid=msgid, method=method, params=params) req = validate_message(unpack_object(data)) assert req == Request(MsgType.REQUEST, msgid, method, params)
def test_pack_response(): """test of pack_response function """ msgid = 37 data = pack_response(msgid=msgid) res = validate_message(unpack_object(data)) assert res == Response(MsgType.RESPONSE, msgid, None, None) result = 'abc' data = pack_response(msgid=msgid, result=result) res = validate_message(unpack_object(data)) assert res == Response(MsgType.RESPONSE, msgid, None, result) error = 123 data = pack_response(msgid=msgid, error=error) res = validate_message(unpack_object(data)) assert res == Response(MsgType.RESPONSE, msgid, error, None)
def test_simple_method_server_request_invalid_method(): """test of requests for non-existing methods to SimpleMethodServer class """ name = 'test_method' executor = FunctionMethodExecutor(PythonLogger(), name, add) server = SimpleMethodServer(PythonLogger(), [executor]) session = MockSession() msgid = 37 name = 'invalid_method' params = [2, 3] request = pack_request(msgid, name, params) err = None has_response = None response = None processed = Event() def handler(err_in: ErrorInfo, has_response_in: bool, response_in: MessageData): """handler """ nonlocal err nonlocal has_response nonlocal response nonlocal processed err = err_in has_response = has_response_in response = response_in processed.set() server.async_process_message(session, request, handler) timeout = 10.0 processed.wait(timeout=timeout) assert processed.is_set() assert err is not None assert not err assert has_response assert response is not None response = validate_message(unpack_object(response)) assert response.msgtype == MsgType.RESPONSE assert response.msgid == msgid assert response.error is not None
def process_message(self, session: Session, data: MessageData) -> MessageData: """process a message Parameters ---------- session : Session session data : MessageData message Returns ------- MessageData response data (if exists). """ try: msg = validate_message(unpack_object(data)) if isinstance(msg, Request): if msg.method not in self.__methods: self.__logger.error('method %s not found', msg.method) return pack_response(msg.msgid, error='method {} not found'.format( msg.method)) return self.__methods[msg.method].process_request(session, msg) if isinstance(msg, Notification): if msg.method not in self.__methods: self.__logger.error('method %s not found', msg.method) return None self.__methods[msg.method].process_notification(session, msg) return None raise MPRPCException( ErrorInfo(ErrorCode.INVALID_MESSAGE, 'message must be a request or response')) except MPRPCException as err: self.__logger.error('%s', err) raise except Exception as err: self.__logger.error('%s', err) raise MPRPCException( ErrorInfo(ErrorCode.UNEXPECTED_ERROR, 'error in server: {}'.format(err))) from err
def _process_message(self, err: ErrorInfo, data: MessageData): """process a message Parameters ---------- err : ErrorInfo error data : MessageData message data """ try: if err: raise MPRPCException(err) msg = validate_message(unpack_object(data)) if not isinstance(msg, Response): raise MPRPCException( ErrorInfo(ErrorCode.INVALID_MESSAGE, 'received a message which is not a response')) msgid = msg.msgid with self.__lock: if msgid not in self.__requests: self.__logger.warn( 'invalid msgid in received response: %d', msgid) future = self.__requests[msgid] del self.__requests[msgid] if msg.error: future.set_exception(ServerError(msg.error)) return future.set_result(msg.result) except MPRPCException as exc: self.__logger.error('%s', exc) with self.__lock: for future in self.__requests.values(): future.set_exception(MPRPCException(err)) self.__requests = dict() return
def test_server(): """test of Server class """ logger = PythonLogger(LogLevel.TRACE) name = 'add' logger = PythonLogger() executor = FunctionMethodExecutor(logger, name, add) method_server = SimpleMethodServer(logger, [executor]) server_config = ServerConfig() server_config.tcp_acceptors = [TCPAcceptorConfig()] server = Server(logger, server_config, method_server) server.start() client_config = ClientConfig() response_error = None response_data = None response_received_event = Event() def client_process_message(error: ErrorInfo, data: MessageData): nonlocal response_error nonlocal response_data nonlocal response_received_event response_error = error response_data = data response_received_event.set() client = PythonClientHelper(logger, client_config, client_process_message) client.start() request_error = None request_sent_event = Event() def on_request_sent(error: ErrorInfo): nonlocal request_error nonlocal request_sent_event request_error = error request_sent_event.set() msgid = 37 data = pack_request(msgid, name, [2, 3]) client.async_send(data, on_request_sent) timeout = 10.0 request_sent_event.wait(timeout=timeout) assert request_sent_event.is_set() assert not request_error response_received_event.wait(timeout=timeout) assert response_received_event.is_set() assert not response_error response = validate_message(unpack_object(response_data)) assert response.msgtype == MsgType.RESPONSE assert response.msgid == msgid assert response.error is None assert response.result == 5 client.stop() server.stop()