def test_send(self): rpc = MsgpackRpc() con_send_mock = mocks.rpc_connection_send(rpc) m1 = MRequest() with self.assertRaises(InvalidMessageError): rpc.send(m1) m1.function = "run" m1.arguments = [] rpc.send(m1) self.assertIsNone(rpc._response_callbacks.get(m1.get_msgid())) con_send_mock.assert_called_once_with(m1.pack()) con_send_mock.reset_mock() def r_cb(): pass rpc.send(m1, r_cb) self.assertEqual(rpc._response_callbacks[m1.get_msgid()], r_cb) con_send_mock.side_effect = BrokenPipeError() with self.assertRaises(BrokenPipeError): rpc.send(m1) with self.assertRaises(InvalidMessageError): rpc.send(None)
def from_msgpack_request(msg: MRequest): """ Generates an ApiRun object from a given MRequest :param msg: A Request received and unpacked with MsgpackRpc. It is assumed, that the strings in msg.body are still in binary format! :return: ApiRun :raises InvalidMessageError: if provided message is not a valid Run call """ if not isinstance(msg.function, str) or msg.function != "run": raise InvalidMessageError( "Invalid run Request, specified method is not run") if not isinstance(msg.arguments, list) or len(msg.arguments) != 3: raise InvalidMessageError("Message body is faulty") if not isinstance(msg.arguments[0], list) or len(msg.arguments[0]) != 2: raise InvalidMessageError("First element of body has to be a list") if msg.arguments[0][0] is not None: raise InvalidMessageError("Plugin identifier set on incomming msg") if not isinstance(msg.arguments[0][1], int): raise InvalidMessageError("Call_id is invaild") if not isinstance(msg.arguments[1], bytes): raise InvalidMessageError("Function name is not bytes") if not isinstance(msg.arguments[2], list): raise InvalidMessageError("Third element of body has to be a list") msg = copy.deepcopy(msg) msg.arguments[1] = msg.arguments[1].decode('ascii') for arg in msg.arguments[2]: if not isinstance(arg, ApiRun._valid_types): raise InvalidMessageError("Invalid Argument type!") call = ApiRun("", msg.arguments[1], msg.arguments[2]) call.msg._msgid = msg._msgid # keep the original msg_id return call
def test_complete_run(self): # In this test a plugin is created and is calling itself. # The called_lock is used to ensure that we receive # the response before the result called_lock = Lock() called_lock.acquire() def add(a: ctypes.c_int64, b: ctypes.c_int64): "add two ints" called_lock.acquire() return a + b RemoteFunction(add) core = Core() plug = Plugin("foo", "bar", "bob", "alice", core) rplug = RemotePlugin("plugin_id", "foo", "bar", "bob", "alice", core) mock_send = mocks.rpc_connection_send(core._rpc) result = rplug.run("add", [7, 8]) # receive request msg = MRequest.from_unpacked(msgpack.unpackb( mock_send.call_args[0][0])) msg.arguments[0][0] = None # remove plugin id msg.arguments[0][1] = 123 # set call id core._rpc._message_callback(msg.pack()) # receive response data = mock_send.call_args_list[1][0][0] core._rpc._message_callback(data) # start execution called_lock.release() # wait for execution to finish plug._active_threads[123].join() # receive result data = mock_send.call_args_list[2][0][0] core._rpc._message_callback(data) self.assertEqual(result.get_result(blocking=True), 15) self.assertEqual(result.get_status(), 2) self.assertEqual(result._error, None) self.assertEqual(result.get_id(), 123)
def __init__(self, plugin_id: str, function_name: str, args: []): super().__init__() if not isinstance(plugin_id, str): raise InvalidApiCallError("plugin identifier has to be a string") if not isinstance(function_name, str): raise InvalidApiCallError("function name has to be a string") if args is None: args = [] for arg in args: if not isinstance(arg, ApiRun._valid_types): raise InvalidApiCallError("Invalid Argument type!") self.msg = MRequest() self.msg.function = "run" self.msg.arguments = [[plugin_id, None], function_name, args]
def test_10_handle_run(self): core = Core() plug = Plugin("foo", "bar", "bob", "alice", core) send = mocks.core_rpc_send(core) # catch results/responses mock = Mock() mock.__name__ = "foo" mock.return_value = "return" plug.functions["foo"] = mock plug.function_meta["foo"] = (["", []]) msg = MRequest() msg.function = "run" msg.arguments = [[None, 123], b'foo', [1, 1.1, "hi"]] error, response = plug._handle_run(msg) self.assertIsNotNone(plug._active_threads.get(123)) plug._active_threads.pop(123).join() mock.assert_called_with([1, 1.1, "hi"]) # request was valid + 1x result self.assertEqual(send.call_count, 1) self.assertEqual(send.call_args_list[0][0][0].arguments[0][0], 123) self.assertEqual(send.call_args_list[0][0][0].arguments[1][0], "return") # (response is sent by msgpack-rpc handler) self.assertEqual(response, [123]) self.assertIsNone(error) send.reset_mock() # reset call count msg.arguments = [[None, 123], b'mock', [1, 1.1, "hi"]] error, response = plug._handle_run(msg) # request was invalid -> error response self.assertEqual(error, [404, "Function does not exist!"]) self.assertIsNone(response) with self.assertRaises(KeyError): plug._active_threads[123] send.reset_mock() # reset call count msg.arguments = [None, b'mock', [1, 1.1, "hi"]] error, response = plug._handle_run(msg) # request was invalid -> error response self.assertEqual(error, [400, "Message is not a valid run call"]) self.assertIsNone(response) with self.assertRaises(KeyError): plug._active_threads[123]
def test_message_callback(self): rpc = MsgpackRpc() mock_send = mocks.rpc_send(rpc) dispatch = mocks.rpc_dispatch(rpc, "run") m_req = MRequest() m_req.function = "run" m_req.arguments = [] dispatch.return_value = (None, []) rpc._message_callback(m_req.pack()) dispatch.assert_called_once_with(m_req) handle_response = mocks.rpc_handle_response(rpc) m_res = MResponse(1) m_res.response = [] rpc._message_callback(m_res.pack()) handle_response.assert_called_once_with(m_res) handle_notify = mocks.rpc_handle_notify(rpc) m_not = MNotify("test", []) rpc._message_callback(m_not.pack()) handle_notify.assert_called_once_with(m_not) handle_notify.side_effect = InvalidMessageError("not") handle_response.side_effect = InvalidMessageError("res") dispatch.side_effect = InvalidMessageError("req") rpc._message_callback(m_req.pack()) self.assertEqual(mock_send.call_args[0][0].error[1], "Could not handle request! req") rpc._message_callback(msgpack.packb(["hi"])) self.assertEqual(mock_send.call_args[0][0].error[0], 400) # handle unexpected exception dispatch.side_effect = TypeError() rpc._message_callback(m_req.pack()) self.assertEqual(mock_send.call_args[0][0].error[1], "Unexpected exception occurred!")
def __init__(self): self.msg = MRequest()
def test_MRequest(self): msg = MRequest() msg.function = "foo" msg.arguments = [] self.assertEqual(msg.pack(), msgpack.packb([0, msg._msgid, "foo", []])) with self.assertRaises(InvalidMessageError): msg.arguments = None msg.pack() with self.assertRaises(InvalidMessageError): msg.function = None msg.arguments = [] msg.pack() pass
def test_30_run_from_msgpack_request(self): msg = MRequest() msg.function = "run" msg.arguments = [[None, 123], b'fun', []] call = ApiRun.from_msgpack_request(msg) self.assertEqual(call.__class__, ApiRun("a", "b", []).__class__) self.assertEqual(call.msg.arguments[1], msg.arguments[1].decode('ascii')) msg.function = None with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.function = "run" msg.arguments = [[None], b'fun', []] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = [[b'id should not be set', 123], b'fun', []] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = ["not a list", b'fun', []] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = [[None, 123], b'fun', "not a list"] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = [[None, "not an int"], b'fun', []] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = [[None, 123], "not bytes", []] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = 123 with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = [] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg) msg.arguments = [[None, 123], b'fun', [None]] with self.assertRaises(InvalidMessageError): ApiRun.from_msgpack_request(msg)