def test_put(self): # single attribute t = Task("testTask", self.proc) resp = Return(0, None, None) resp.set_value('testVal') # cheat and add the response before the blocking call to put t.q.put(resp) t.stop() t.put(self.attr, "testValue") self.assertEqual(len(t._futures), 0) self.assertEqual(self.proc.q.qsize(), 1)
def test_post(self): t = Task("testTask", self.proc) resp1 = Return(0, None, None) resp1.set_value('testVal') resp2 = Error(1, None, None) # cheat and add the responses before the blocking call to put t.q.put(resp1) t.q.put(resp2) t.stop() t.post(self.method, "testParm") t.post(self.method, "testParm2") self.assertEqual(len(t._futures), 0) self.assertEqual(self.proc.q.qsize(), 2)
def test_post(self): t = Task("testTask", self.proc) resp1 = Return(1, None, None) resp1.set_value(dict(ret='testVal')) resp2 = Error(2, None, "") # cheat and add the responses before the blocking call to put t.q.put(resp1) t.q.put(resp2) t.stop() t.post(self.method, {"a": "testParm"}) self.assertRaises(ResponseError, t.post, self.method, {"a": "testParm2"}) self.assertEqual(len(t._futures), 0) self.assertEqual(self.proc.q.qsize(), 2)
def test_on_message(self, _): self.WS = WebsocketClientComms(self.p, params) request = MagicMock() self.WS.requests[11] = request response = Return(11, MagicMock(), "me") message = """{ "typeid": "malcolm:core/Return:1.0", "id": 11, "value": "me" }""" self.WS.on_message(message) self.assertEquals(request.response_queue.put.call_count, 1) actual = request.response_queue.put.call_args[0][0] self.assertEquals(actual.to_dict(), response.to_dict())
def test_exception(self): # timeout due to no response arriving f0 = Future(self.task) f1 = Future(self.task) self.task._futures = {0: f0, 1: f1} self.assertRaises(queue.Empty, f0.exception, 0) # return after waiting for response object resp0 = Return(0, None, None) resp0.set_value('testVal') resp1 = Error(1, None, None) resp1.set_message('test Error') self.task.q.put(resp0) self.task.q.put(resp1) self.assertEqual(f1.exception(), 'test Error')
def test_exception(self): # timeout due to no response arriving f0 = Future(self.task) f1 = Future(self.task) self.task._futures = {0: f0, 1: f1} self.assertRaises(queue.Empty, f0.exception, 0) # return after waiting for response object resp0 = Return(0, None, None) resp0.set_value('testVal') resp1 = Error(1, None, None) resp1.set_message('test Error') self.task.q.put(resp0) self.task.q.put(resp1) with self.assertRaises(ValueError) as cm: f1.exception() self.assertEqual(str(cm.exception), 'test Error')
def test_when_matches(self): self.o._q.put(Update(1, "value1")) self.o._q.put(Return(1)) self.o.when_matches(["block", "attr", "value"], "value1", timeout=0.01) assert self.controller.handle_request.call_args_list == [ call(Subscribe(1, ["block", "attr", "value"])), call(Unsubscribe(1)) ]
def test_wait_all_missing_futures(self): # unsolicited response t = Task("testTask", self.proc) f1 = Future(t) resp10 = Return(10, None, None) t.q.put(resp10) t.q.put(Task.TASK_STOP) self.assertRaises(RuntimeWarning, t.wait_all, f1, 0) # same future twice f2 = Future(t) t._futures = {1: f2} resp1 = Return(1, None, None) t.q.put(resp1) t.q.put(Task.TASK_STOP) t.wait_all(f2, 0) t.wait_all(f2, 0)
def test_wait_all_missing_futures(self): # unsolicited response t = Task("testTask", self.proc) f1 = Future(t) resp10 = Return(10, None, None) t.q.put(resp10) t.q.put(Spawnable.STOP) self.assertRaises(StopIteration, t.wait_all, f1, 0) # same future twice f2 = Future(t) t._futures = {1: f2} resp1 = Return(1, None, None) t.q.put(resp1) t.q.put(Spawnable.STOP) t.wait_all(f2, 0) t.wait_all(f2, 0)
def test_respond_with_return(self): self.request.respond_with_return(value=5) call_arg = self.response_queue.put.call_args_list[0][0][0].to_dict() expected_response = Return(self.request.id_, self.request.context, value=5).to_dict() self.assertEqual(call_arg, expected_response)
def respond_with_return(self, value=None): """ Create a Return Response object to handle the request Args: value(): Value to set endpoint to """ response = Return(self.id, self.context, value=value) self._respond(response)
def test_many_puts(self): fs = [ self.o.put_async(["block", "attr", "value"], 32), self.o.put_async(["block", "attr2", "value"], 32) ] with self.assertRaises(TimeoutError): self.o.wait_all_futures(fs, 0.01) assert [f.done() for f in fs] == [False, False] self.o._q.put(Return(2, None)) assert [f.done() for f in fs] == [False, False] with self.assertRaises(TimeoutError): self.o.wait_all_futures(fs, 0.01) assert [f.done() for f in fs] == [False, True] self.o._q.put(Return(1, None)) self.o.wait_all_futures(fs, 0.01) assert [f.done() for f in fs] == [True, True] self.o.wait_all_futures(fs, 0.01) assert [f.done() for f in fs] == [True, True]
def test_post(self): self.controller.validate_result.return_value = 22 self.o._q.put(Return(1, dict(a=2))) result = self.o.post(["block", "method"], dict(b=32)) self.controller.handle_request.assert_called_once_with( Post(1, ["block", "method"], dict(b=32))) self.controller.validate_result.assert_called_once_with( "method", dict(a=2)) assert result == 22
def test_when_matches_func(self): self.o._q.put(Update(1, "value1")) self.o._q.put(Return(1)) def f(value): return value.startswith("v") self.o.when_matches(["block", "attr", "value"], f, timeout=0.01) self.assert_handle_request_called_with( Subscribe(1, ["block", "attr", "value"]), Unsubscribe(1))
def test_many_puts(self): fs = [ self.o.put_async(["block", "attr", "value"], 32), self.o.put_async(["block", "attr2", "value"], 32) ] with self.assertRaises(TimeoutError) as cm: self.o.wait_all_futures(fs, 0.01) assert str(cm.exception) == \ "Timeout waiting for [block.attr.value.put_value(32), block.attr2.value.put_value(32)]" assert [f.done() for f in fs] == [False, False] self.o._q.put(Return(2, None)) assert [f.done() for f in fs] == [False, False] with self.assertRaises(TimeoutError): self.o.wait_all_futures(fs, 0.01) assert [f.done() for f in fs] == [False, True] self.o._q.put(Return(1, None)) self.o.wait_all_futures(fs, 0.01) assert [f.done() for f in fs] == [True, True] self.o.wait_all_futures(fs, 0.01) assert [f.done() for f in fs] == [True, True]
def execute_put(self, request): # Connect to the channel c = pvaccess.Channel(request["endpoint"][0]) # Create the path request from the endpoints (not including the block name endpoint) path = ".".join(request["endpoint"][1:]) self.log_debug("path: %s", path) # Perform a put, but there is no response available c.put(request["value"], path) # Now create the Return object and populate it with the response return_object = Return(id_=request["id"], value="No return value from put") return return_object
def test_put_many(self): # many attributes t = Task("testTask", self.proc) resp1 = Return(1, None, None) resp1.set_value('testVal1') resp2 = Return(2, None, None) resp2.set_value('testVal2') # cheat and add the response before the blocking call to put t.q.put(resp1) t.q.put(resp2) t.stop() t.put_many(self.block, dict(testAttr="testValue", testAttr2="testValue2")) self.assertEqual(len(t._futures), 0) self.assertEqual(self.proc.q.qsize(), 2)
def test_subscribe_cb_failure(self): def cb(value): raise MyWarning() f = self.o.subscribe(["block", "attr", "value"], cb) self.o._q.put(Update(1, "value1")) with self.assertRaises(MyWarning): self.o.wait_all_futures(f, 0.01) assert not f.done() self.o._q.put(Update(1, "value1")) with self.assertRaises(MyWarning): self.o.wait_all_futures(f, 0.01) assert not f.done() self.o._q.put(Return(1)) self.o.wait_all_futures(f, 0.01) assert f.done()
def test_send_to_client(self): self.PVA = PvaServerComms(self.p) self.PVA._update_cache = MagicMock() rpc_mock1 = MagicMock() rpc_mock2 = MagicMock() self.PVA._rpcs[1] = rpc_mock1 self.PVA._rpcs[2] = rpc_mock2 response1 = Return(id_=1) self.PVA.send_to_client(response1) rpc_mock1.notify_reply.assert_has_calls([call(response1)]) response2 = Error(id_=2) self.PVA.send_to_client(response2) rpc_mock2.notify_reply.assert_has_calls([call(response2)]) response3 = Delta(id_=3) self.PVA.send_to_client(response3) self.PVA._update_cache.assert_has_calls([call(response3)])
def test_Return(self): context = Mock() r = Return(123, context) self.assertEquals(123, r.id_) self.assertEquals("malcolm:core/Return:1.0", r.typeid) self.assertEquals(context, r.context) self.assertIsNone(r.value) r = Return(123, Mock(), {"key": "value"}) self.assertEquals({"key": "value"}, r.value) r.set_value({"key": "value2"}) self.assertEquals({"key": "value2"}, r.value)
def test_subscription_with_callback_calling_unsubscribe(self): # This test was designed to trigger a bug. Concluding a future inside a # callback, as is done here by unsubscribe() followed by sleep(0), would # not be recognised by the call to wait_all_futures(...). This would # result in an indefinite hang. def cb(value): self.o.unsubscribe_all() self.o._q.put(Return(1)) # Return from subscribe self.o.sleep(0) # Service futures self.o.subscribe(["block", "attr", "value"], cb) # id=1 self.o._q.put(Update(1, "original_value")) # Update from initial value future = self.o.put_async(["block", "attr2", "value"], "new") # id=2 self.o._q.put(Return(2)) # Return from put to attr2 self.o.wait_all_futures(future)
def test_subscribe(self): cb = MagicMock() f = self.o.subscribe(["block", "attr", "value"], cb, self.o, "arg2") self.assert_handle_request_called_with( Subscribe(1, ["block", "attr", "value"])) self.o._q.put(Update(1, "value1")) with self.assertRaises(TimeoutError): self.o.wait_all_futures(f, 0.01) cb.assert_called_once_with("value1", ANY, "arg2") # since args = self.o it should be a weak proxy in second argument cb.call_args[0][1] # TODO: giles cant work out how to check weakproxy equivalence?? # self.assertEquals(param1, self.o) cb.reset_mock() self.o._q.put(Update(1, "value2")) self.o._q.put(Return(1)) self.o.wait_all_futures(f, 0.01) cb.assert_called_once_with("value2", ANY, "arg2") assert f.result(0.01) is None
def execute_get(self, request): # Connect to the channel c = pvaccess.Channel(request["endpoint"][0]) # Create the path request from the endpoints (not including the block name endpoint) path = ".".join(request["endpoint"][1:]) self.log_debug("path: %s", path) # Perform a get and record the response response = c.get(path) self.log_debug("Response: %s", response) # Now create the Return object and populate it with the response value = response.toDict(True) if 'typeid' in value: if value['typeid'] == 'malcolm:core/Error:1.0': return_object = Error(id_=request["id"], message=value['message']) else: return_object = Return(id_=request["id"], value=value) else: return_object = Error(id_=request["id"], message="No valid return typeid") return return_object
def test_wait_all(self): t = Task("testTask", self.proc) f1 = Future(t) f2 = Future(t) f3 = Future(t) f0 = Future(t) t._futures = {0: f0, 1: f1, 2: f2, 3: f3} f_wait1 = [f2, f0] self.assertRaises(queue.Empty, t.wait_all, f_wait1, 0) resp0 = Return(0, None, None) resp0.set_value('testVal') resp2 = Error(2, None, None) t.q.put(resp0) t.q.put(resp2) self.assertRaises(ValueError, t.wait_all, f_wait1, 0) self.assertEqual(t._futures, {1: f1, 3: f3}) self.assertEqual(f0.done(), True) self.assertEqual(f1.done(), False) self.assertEqual(f2.done(), True) self.assertEqual(f3.done(), False) self.assertEqual(self.proc.q.qsize(), 0) resp3 = Delta(3, None, None) t.q.put(resp3) f_wait1 = [f3] self.assertRaises(ValueError, t.wait_all, f_wait1, 0.01) t.stop() self.assertRaises(StopIteration, t.wait_all, f_wait1, 0.01) resp1 = Return(1, None, None) resp1.set_value('testVal') t.q.put(resp1) self.assertRaises(queue.Empty, t.wait_all, f_wait1, 0.01) self.assertEqual(t._futures, {}) t._futures = {0: f0, 1: f1, 2: f2} t.q.put(resp1) t.q.put(Spawnable.STOP) self.assertEqual(f1.result(), 'testVal')
def handle_request(self, request): """ Process the request depending on the type Args: request(Request): Request object specifying action """ self.log_debug("Received request %s", request) try: assert isinstance(request, Post) or isinstance(request, Put), \ "Expected Post or Put request, received %s" % request.typeid child_name = request.endpoint[1] child = self[child_name] writeable_function = self._writeable_functions[child_name] result = child.handle_request(request, writeable_function) response = Return(request.id, request.context, result) except Exception as e: # pylint:disable=broad-except self.log_exception("Exception while handling %s" % request) response = Error(request.id, request.context, str(e)) self._parent.block_respond(response, request.response_queue)
def test_put_many(self): # many attributes t = Task("testTask", self.proc) resp1 = Return(1, None, None) resp1.set_value('testVal1') resp2 = Return(2, None, None) resp2.set_value('testVal2') # cheat and add the response before the blocking call to put t.q.put(resp1) t.q.put(resp2) t.stop() t.put_many(self.block, dict( testAttr="testValue", testAttr2="testValue2")) self.assertEqual(len(t._futures), 0) self.assertEqual(self.proc.q.qsize(), 2)
def execute_rpc(self, request): method = pvaccess.PvObject({'method': pvaccess.STRING}) method.set({'method': request["endpoint"][1]}) # Connect to the channel and create the RPC client rpc = pvaccess.RpcClient(request["endpoint"][0], method) # Construct the pv object from the parameters params = self.dict_to_pv_object(request["parameters"]) self.log_debug("PvObject parameters: %s", params) # Call the method on the RPC object response = rpc.invoke(params) self.log_debug("Response: %s", response) # Now create the Return object and populate it with the response value = response.toDict(True) if 'typeid' in value: if value['typeid'] == 'malcolm:core/Error:1.0': return_object = Error(id_=request["id"], message=value['message']) else: return_object = Return(id_=request["id"], value=value) else: return_object = Error(id_=request["id"], message="No valid return typeid") return return_object
def test_pva_rpc_implementation(self): server = MagicMock() request = {"method": "test_method"} pva = PvaRpcImplementation(1, request, "test.block", server) self.assertEqual(pva._id, 1) self.assertEqual(pva._block, "test.block") self.assertEqual(pva._request, request) self.assertEqual(pva._server, server) self.assertEqual(pva._method, "test_method") pre_parse = { "dict1": {"item1", 1}, "list1": [1, 2, 3], "tuple1": ({ "item2": 2, "item3": 3 }, 2) } post_parse = { "dict1": {"item1", 1}, "list1": [1, 2, 3], "tuple1": { "item2": 2, "item3": 3 } } self.assertEqual(pva.parse_variants(pre_parse), post_parse) response = Return(id_=2, value="test.value") pva.notify_reply(response) pv = MagicMock() pva.execute(pv) server.process.q.put.assert_called_once() pv.toDict.assert_called_once() pva._lock = MagicMock() pva.check_lock() pva._lock.acquire.assert_has_calls([call(False)]) pva._event = MagicMock() pva.wait_for_reply() pva._event.wait.assert_called_once()
def test_pva_rpc_implementation(self): self.p = MagicMock() self.p = MagicMock() pva = PvaRpcImplementation(1, self.p, "test.block", "test.method") self.assertEqual(pva._id, 1) self.assertEqual(pva._block, "test.block") self.assertEqual(pva._method, "test.method") self.assertEqual(pva._server, self.p) response = Return(id_=2, value="test.value") pva.notify_reply(response) self.pv = MagicMock() pva.execute(self.pv) self.p.process.q.put.assert_called_once() self.pv.toDict.assert_called_once() pva._lock = MagicMock() pva.check_lock() pva._lock.acquire.assert_has_calls([call(False)]) pva._event = MagicMock() pva.wait_for_reply() pva._event.wait.assert_called_once()
def test_wait_all(self): t = Task("testTask", self.proc) f1 = Future(t) f2 = Future(t) f3 = Future(t) f0 = Future(t) t._futures = {0: f0, 1: f1, 2: f2, 3: f3} f_wait1 = [f2, f0] self.assertRaises(queue.Empty, t.wait_all, f_wait1, 0) resp0 = Return(0, None, None) resp0.set_value('testVal') resp2 = Error(2, None, None) t.q.put(resp0) t.q.put(resp2) t.wait_all( f_wait1, 0) self.assertEqual(t._futures, {1: f1, 3: f3}) self.assertEqual(f0.done(), True) self.assertEqual(f1.done(), False) self.assertEqual(f2.done(), True) self.assertEqual(f3.done(), False) self.assertEqual(self.proc.q.qsize(), 0) resp3 = Delta(3, None, None) t.q.put(resp3) f_wait1 = [f3] self.assertRaises(ValueError, t.wait_all, f_wait1, 0.01) t.stop() self.assertRaises(RuntimeWarning, t.wait_all, f_wait1, 0.01) resp1 = Return(1, None, None) resp1.set_value('testVal') t.q.put(resp1) self.assertRaises(queue.Empty, t.wait_all, f_wait1, 0.01) self.assertEqual(t._futures, {}) t._futures = {0: f0, 1: f1, 2: f2} t.q.put(resp1) t.q.put(Task.TASK_STOP) self.assertEqual(f1.result(), 'testVal')
def test_handle_response_return(self): response = Return(value="yay") self.item.handle_response(response) assert self.item.get_state() == self.item.IDLE
def test_put(self): self.o._q.put(Return(1, 33)) ret = self.o.put(["block", "attr", "value"], 32) self.assert_handle_request_called_with( Put(1, ["block", "attr", "value"], 32)) assert ret == 33
def test_post(self): self.o._q.put(Return(1, dict(a=2))) result = self.o.post(["block", "method"], dict(b=32)) self.assert_handle_request_called_with( Post(1, ["block", "method"], dict(b=32))) assert result == dict(a=2)
def test_handle_response_return(self): response = Return(None, None, "yay") self.item.handle_response(response) self.assertEqual(self.item.get_state(), self.item.IDLE)
def test_Return(self): r = Return(35) assert r.typeid == "malcolm:core/Return:1.0" assert r.id == 35 assert r.value is None assert get_doc_json("return") == r.to_dict()
def test_respond_with_return(self): cb, response = self.o.return_response(value=5) assert cb == self.callback assert response.to_dict() == Return(id=32, value=5).to_dict()
def test_Return_value(self): r = Return(32, "Running") assert r.typeid == "malcolm:core/Return:1.0" assert r.id == 32 assert r.value == "Running" assert get_doc_json("return_state_value") == r.to_dict()