def test_hello_good_input(self): q = Queue() request = Post(id=44, path=["hello_block", "greet"], parameters=dict(name="thing")) request.set_callback(q.put) self.controller.handle_request(request) response = q.get(timeout=1.0) self.assertIsInstance(response, Return) assert response.id == 44 assert response.value == "Hello thing"
def rpc(self, pv, op): # type: (SharedPV, ServerOperation) -> None value = op.value() if value.getID() == "epics:nt/NTURI:1.0": # We got an NTURI, get path from path and parameters from query assert value.scheme == "pva", \ "Can only handle NTURI with scheme=pva" prefix = self.controller.mri + "." assert value.path.startswith(prefix), \ "NTURI path '%s' doesn't start with '%s'" % (value.path, prefix) method = value.path[len(prefix):] parameters = convert_value_to_dict(value.query) else: # We got something else, take path from pvRequest method and our mri # and parameters from the full value if self.field is not None: # We already know the method name method = self.field else: # Get the path and string "value" from the put value method = op.pvRequest().get("method") assert method, "No 'method' in pvRequest:\n%s" % op.pvRequest() parameters = convert_value_to_dict(value) path = [self.controller.mri, method] view = self.controller.block_view()[method] assert isinstance(view, Method), \ "%s.%s is not a Method so cannot do RPC" % tuple(path) add_wrapper = method_return_unpacked() in view.tags post = Post(path=path, parameters=parameters) def handle_post_response(response): # type: (Response) -> None if isinstance(response, Return): if add_wrapper: # Method gave us return unpacked (bare string or other type) # so we must wrap it in a structure to send it ret = {"return": response.value} else: ret = response.value serialized = serialize_object(ret) v = convert_dict_to_value(serialized) op.done(v) else: if isinstance(response, Error): message = stringify_error(response.message) else: message = "BadResponse: %s" % response.to_dict() op.done(error=message) post.set_callback(handle_post_response) self.controller.handle_request(post).get()
def test_concurrency(self): msg1 = Post(id=0, path=["hello", "greet"], parameters=dict(name="me", sleep=2)).to_dict() msg2 = Post(id=1, path=["hello", "error"]).to_dict() IOLoopHelper.call(self.send_messages, [msg1, msg2]) resp = self.result.get(timeout=1) assert resp == dict(typeid="malcolm:core/Error:1.0", id=1, message="RuntimeError: You called method error()") resp = self.result.get(timeout=3) assert resp == dict(typeid="malcolm:core/Return:1.0", id=0, value="Hello me")
def set_value(self, value): args = {} for item in self.children: args[item.endpoint[-1]] = item.get_value() item.reset_value() self._state = self.RUNNING request = Post(self, None, self.endpoint, args) return request
def post(self, endpoint_str): # called from tornado thread path = endpoint_str.split("/") parameters = json_decode(self.get_body_argument("parameters")) request = Post(path=path, parameters=parameters, callback=self.on_response) self._server_part.on_request(request)
def test_concurrent(self): q = Queue() request = Subscribe(id=40, path=["hello_block", "greet"], delta=True) request.set_callback(q.put) self.controller.handle_request(request) # Get the initial subscribe value inital = q.get(timeout=0.1) self.assertIsInstance(inital, Delta) assert inital.changes[0][1]["took"]["value"] == dict(sleep=0, name="") assert inital.changes[0][1]["returned"]["value"] == {"return": ""} # Do a greet request = Post(id=44, path=["hello_block", "greet"], parameters=dict(name="me", sleep=1)) request.set_callback(q.put) self.controller.handle_request(request) # Then an error request = Post(id=45, path=["hello_block", "error"]) request.set_callback(q.put) self.controller.handle_request(request) # We should quickly get the error response first response = q.get(timeout=1.0) self.assertIsInstance(response, Error) assert response.id == 45 # Then the long running greet delta response = q.get(timeout=3.0) self.assertIsInstance(response, Delta) assert len(response.changes) == 2 assert response.changes[0][0] == ["took"] took = response.changes[0][1] assert took.value == dict(sleep=1, name="me") assert took.present == ["name", "sleep"] assert took.alarm == Alarm.ok assert response.changes[1][0] == ["returned"] returned = response.changes[1][1] assert returned.value == {"return": "Hello me"} assert returned.present == ["return"] assert returned.alarm == Alarm.ok # Check it took about 1s to run assert abs(1 - (returned.timeStamp.to_time() - took.timeStamp.to_time())) < 0.4 # And it's response response = q.get(timeout=1.0) self.assertIsInstance(response, Return) assert response.id == 44 assert response.value == "Hello me"
def post(self, endpoint_str): # called from tornado thread path = endpoint_str.split("/") parameters = json_decode(self.request.body.decode()) request = Post(path=path, parameters=parameters) self.report_request(request) response = yield self._queue.get() self.handle_response(response)
def set_value(self, value): args = {} for item in self.children: args[item.endpoint[-1]] = item.get_value() item.reset_value() self._state = self.RUNNING request = Post(path=self.endpoint, parameters=args, callback=self.handle_response) return request
def test_counter_subscribe(self): q = Queue() # Subscribe to the value sub = Subscribe(id=20, path=["counting", "counter"], delta=False) sub.set_callback(q.put) self.controller.handle_request(sub) # Check initial return response = q.get(timeout=1.0) self.assertIsInstance(response, Update) assert response.id == 20 assert response.value["typeid"] == "epics:nt/NTScalar:1.0" assert response.value["value"] == 0 # Post increment() post = Post(id=21, path=["counting", "increment"]) post.set_callback(q.put) self.controller.handle_request(post) # Check the value updates... response = q.get(timeout=1) self.assertIsInstance(response, Update) assert response.id == 20 assert response.value["value"] == 1 # ... then we get the return response = q.get(timeout=1) self.assertIsInstance(response, Return) assert response.id == 21 assert response.value is None # Check we can put too put = Put(id=22, path=["counting", "counter", "value"], value=31) put.set_callback(q.put) self.controller.handle_request(put) # Check the value updates... response = q.get(timeout=1) self.assertIsInstance(response, Update) assert response.id == 20 assert response.value["value"] == 31 # ... then we get the return response = q.get(timeout=1) self.assertIsInstance(response, Return) assert response.id == 22 assert response.value is None # And that there isn't anything else with self.assertRaises(TimeoutError): q.get(timeout=0.05)
def send_post(self, mri, method_name, **params): """Abstract method to dispatch a Post to the server Args: mri (str): The mri of the Block method_name (str): The name of the Method within the Block params: The parameters to send Returns: The return results from the server """ q = Queue() request = Post(path=[mri, method_name], parameters=params) request.set_callback(q.put) IOLoopHelper.call(self._send_request, request) response = q.get() if isinstance(response, Error): raise response.message else: return response.value
def test_concurrent(self): q = Queue() request = Post(id=44, path=["hello_block", "greet"], parameters=dict(name="me", sleep=1)) request.set_callback(q.put) self.controller.handle_request(request) request = Post(id=45, path=["hello_block", "error"]) request.set_callback(q.put) self.controller.handle_request(request) response = q.get(timeout=1.0) self.assertIsInstance(response, Error) assert response.id == 45 response = q.get(timeout=3.0) self.assertIsInstance(response, Return) assert response.id == 44 assert response.value == "Hello me"
def call_server_method(self, method_name, parameters, returns): """Call method_name on the server Args: method_name (str): Name of the method parameters (Map): Map of arguments to be called with returns (Map): Returns map to fill and return """ self.log_debug(dict(parameters)) q = self.process.create_queue() request = Post(None, q, [self.block.name, method_name], parameters) self.client_comms.q.put(request) response = q.get() assert isinstance(response, Return), \ "Expected Return, got %s" % response.typeid if "typeid" in response.value: response.value.pop("typeid") returns.update(response.value) return returns
def test_counter_subscribe(self): q = Queue() sub = Subscribe(id=20, path=["counting", "counter"], delta=False, callback=q.put) self.controller.handle_request(sub) response = q.get(timeout=1.0) self.assertIsInstance(response, Update) assert response.id == 20 assert response.value["typeid"] == "epics:nt/NTScalar:1.0" assert response.value["value"] == 0 post = Post(id=21, path=["counting", "increment"], callback=q.put) self.controller.handle_request(post) response = q.get(timeout=1) self.assertIsInstance(response, Update) assert response.id == 20 assert response.value["value"] == 1 response = q.get(timeout=1) self.assertIsInstance(response, Return) assert response.id == 21 assert response.value == None with self.assertRaises(TimeoutError): q.get(timeout=0.05)
def rpc(self, pv: SharedPV, op: ServerOperation) -> None: value = op.value() if value.getID() == "epics:nt/NTURI:1.0": # We got an NTURI, get path from path and parameters from query assert value.scheme == "pva", "Can only handle NTURI with scheme=pva" prefix = self.controller.mri + "." assert value.path.startswith( prefix ), f"NTURI path '{value.path}' doesn't start with '{prefix}'" method = value.path[len(prefix):] parameters = convert_value_to_dict(value.query) else: # We got something else, take path from pvRequest method and our mri # and parameters from the full value if self.field is not None: # We already know the method name method = self.field else: # Get the path and string "value" from the put value method = op.pvRequest().get("method") assert method, f"No 'method' in pvRequest:\n{op.pvRequest()}" parameters = convert_value_to_dict(value) path = [self.controller.mri, method] view = self.controller.block_view()[method] assert isinstance( view, Method), "%s.%s is not a Method so cannot do RPC" % tuple(path) add_wrapper = method_return_unpacked() in view.meta.tags self.controller.log.debug( f"{self.controller.mri}: RPC method {method} called with " f"params {parameters}") post = Post(path=path, parameters=parameters) def handle_post_response(response: Response) -> None: if isinstance(response, Return): ret: Any if add_wrapper: # Method gave us return unpacked (bare string or other type) # so we must wrap it in a structure to send it ret = {"return": response.value} else: ret = response.value v = convert_dict_to_value(ret) if ret: self.controller.log.debug( f"{self.controller.mri}: RPC method {method} returned with " f"value {ret}") else: self.controller.log.debug( f"{self.controller.mri}: RPC method {method} returned") op.done(v) else: if isinstance(response, Error): message = stringify_error(response.message) self.controller.log.debug( f"{self.controller.mri}: RPC method {method} resulted in " f"error ({message})") else: message = f"BadResponse: {response.to_dict()}" self.controller.log.debug( f"{self.controller.mri}: RPC method {method} got a bad " f"response ({message})") op.done(error=message) post.set_callback(handle_post_response) self.controller.handle_request(post).get()
def post(self, endpoint_str): # called from tornado thread path = endpoint_str.split("/") parameters = json_decode(self.get_body_argument("parameters")) request = Post(path=path, parameters=parameters) self.report_request(request)
def post(self, endpoint_str): endpoint = endpoint_str.split("/") parameters = json.loads(self.get_body_argument("parameters")) request = Post(self, None, endpoint, parameters) self.servercomms.on_request(request)
def test_handle_request(self): q = Queue() request = Get(id=41, path=["mri", "myAttribute"]) request.set_callback(q.put) self.o.handle_request(request) response = q.get(timeout=0.1) self.assertIsInstance(response, Return) assert response.id == 41 assert response.value["value"] == "hello_block" self.part.my_attribute.meta.writeable = False request = Put( id=42, path=["mri", "myAttribute"], value="hello_block2", get=True ) request.set_callback(q.put) self.o.handle_request(request) response = q.get(timeout=0.1) self.assertIsInstance(response, Error) # not writeable assert response.id == 42 self.part.my_attribute.meta.writeable = True self.o.handle_request(request) response = q.get(timeout=0.1) self.assertIsInstance(response, Return) assert response.id == 42 assert response.value == "hello_block2" request = Post(id=43, path=["mri", "method"]) request.set_callback(q.put) self.o.handle_request(request) response = q.get(timeout=0.1) self.assertIsInstance(response, Return) assert response.id == 43 assert response.value == "world" # cover the controller._handle_post path for parameters request = Post(id=43, path=["mri", "method"], parameters={"dummy": 1}) request.set_callback(q.put) self.o.handle_request(request) response = q.get(timeout=0.1) self.assertIsInstance(response, Error) assert response.id == 43 assert ( str(response.message) == "Given keys ['dummy'], some of which aren't in allowed keys []" ) request = Subscribe(id=44, path=["mri", "myAttribute"], delta=False) request.set_callback(q.put) self.o.handle_request(request) response = q.get(timeout=0.1) self.assertIsInstance(response, Update) assert response.id == 44 assert response.value["typeid"] == "epics:nt/NTScalar:1.0" assert response.value["value"] == "hello_block2" request = Unsubscribe(id=44) request.set_callback(q.put) self.o.handle_request(request) response = q.get(timeout=0.1) self.assertIsInstance(response, Return) assert response.id == 44