def http_server(): """Builds an HTTPServer instance that contains an ExposedThing.""" exposed_thing = ExposedThing(servient=Servient(), thing=Thing(id=uuid.uuid4().urn)) exposed_thing.add_property(uuid.uuid4().hex, PropertyFragmentDict({ "type": "number", "observable": True }), value=Faker().pyint()) exposed_thing.add_property(uuid.uuid4().hex, PropertyFragmentDict({ "type": "number", "observable": True }), value=Faker().pyint()) exposed_thing.add_event(uuid.uuid4().hex, EventFragmentDict({"type": "object"})) action_name = uuid.uuid4().hex @tornado.gen.coroutine def triple(parameters): input_value = parameters.get("input") yield tornado.gen.sleep(0) raise tornado.gen.Return(input_value * 3) exposed_thing.add_action( action_name, ActionFragmentDict({ "input": { "type": "number" }, "output": { "type": "number" } }), triple) port = find_free_port() server = HTTPServer(port=port) server.add_exposed_thing(exposed_thing) @tornado.gen.coroutine def start(): yield server.start() tornado.ioloop.IOLoop.current().run_sync(start) yield server @tornado.gen.coroutine def stop(): yield server.stop() tornado.ioloop.IOLoop.current().run_sync(stop)
def test_ssl_context(self_signed_ssl_context): """An SSL context can be passed to the WebSockets server to enable encryption.""" exposed_thing = ExposedThing(servient=Servient(), thing=Thing(id=uuid.uuid4().urn)) prop_name = uuid.uuid4().hex exposed_thing.add_property(prop_name, PropertyFragmentDict({ "type": "string", "observable": True }), value=Faker().pystr()) port = find_free_port() server = WebsocketServer(port=port, ssl_context=self_signed_ssl_context) server.add_exposed_thing(exposed_thing) @tornado.gen.coroutine def test_coroutine(): yield server.start() ws_url = build_websocket_url(exposed_thing, server, port) assert WebsocketSchemes.WSS in ws_url with pytest.raises(ssl.SSLError): http_req = tornado.httpclient.HTTPRequest(ws_url, method="GET") yield tornado.websocket.websocket_connect(http_req) http_req = tornado.httpclient.HTTPRequest(ws_url, method="GET", validate_cert=False) conn = yield tornado.websocket.websocket_connect(http_req) request_id = Faker().pyint() msg_req = WebsocketMessageRequest( method=WebsocketMethods.READ_PROPERTY, params={"name": prop_name}, msg_id=request_id) conn.write_message(msg_req.to_json()) msg_resp_raw = yield conn.read_message() msg_resp = WebsocketMessageResponse.from_raw(msg_resp_raw) assert msg_resp.id == request_id value = yield exposed_thing.read_property(prop_name) assert value == msg_resp.result yield conn.close() yield server.stop() run_test_coroutine(test_coroutine)
def consumed_exposed_pair(): """Returns a dict with two keys: * consumed_thing: A ConsumedThing instance. The Servient instance that contains this ConsumedThing has been patched to use the ExposedThingProxyClient Protocol Binding client. * exposed_thing: The ExposedThing behind the previous ConsumedThing (for assertion purposes).""" servient = Servient() exp_thing = ExposedThing(servient=servient, thing=Thing(id=uuid.uuid4().urn)) servient.select_client = MagicMock( return_value=ExposedThingProxyClient(exp_thing)) @tornado.gen.coroutine def lower(parameters): input_value = parameters.get("input") yield tornado.gen.sleep(0) raise tornado.gen.Return(str(input_value).lower()) exp_thing.add_property(uuid.uuid4().hex, _build_property_fragment()) exp_thing.add_action(uuid.uuid4().hex, _build_action_fragment(), lower) exp_thing.add_event(uuid.uuid4().hex, _build_event_fragment()) td = ThingDescription.from_thing(exp_thing.thing) return { "consumed_thing": ConsumedThing(servient=servient, td=td), "exposed_thing": exp_thing }
def test_ssl_context(self_signed_ssl_context): """An SSL context can be passed to the HTTP server to enable encryption.""" exposed_thing = ExposedThing(servient=Servient(), thing=Thing(id=uuid.uuid4().urn)) prop_name = uuid.uuid4().hex exposed_thing.add_property(prop_name, PropertyFragmentDict({ "type": "string", "observable": True }), value=Faker().pystr()) port = find_free_port() server = HTTPServer(port=port, ssl_context=self_signed_ssl_context) server.add_exposed_thing(exposed_thing) href = _get_property_href(exposed_thing, prop_name, server) assert HTTPSchemes.HTTPS in href @tornado.gen.coroutine def test_coroutine(): yield server.start() prop_value = Faker().pystr() yield exposed_thing.properties[prop_name].write(prop_value) http_client = tornado.httpclient.AsyncHTTPClient() with pytest.raises(ssl.SSLError): yield http_client.fetch( tornado.httpclient.HTTPRequest(href, method="GET")) http_request = tornado.httpclient.HTTPRequest(href, method="GET", validate_cert=False) response = yield http_client.fetch(http_request) assert json.loads(response.body).get("value") == prop_value yield server.stop() run_test_coroutine(test_coroutine)
def produce(self, model): """Accepts a model argument of type ThingModel and returns an ExposedThing object, locally created based on the provided initialization parameters.""" thing = self.thing_from_model(model) exposed_thing = ExposedThing(servient=self._servient, thing=thing) self._servient.add_exposed_thing(exposed_thing) return exposed_thing
def mqtt_server(request): """Builds a MQTTServer instance that contains an ExposedThing.""" from wotpy.protocols.mqtt.server import MQTTServer from tests.protocols.mqtt.broker import get_test_broker_url exposed_thing = ExposedThing(servient=Servient(), thing=Thing(id=uuid.uuid4().urn)) exposed_thing.add_property(uuid.uuid4().hex, PropertyFragmentDict({ "type": "string", "observable": True }), value=Faker().sentence()) exposed_thing.add_event(uuid.uuid4().hex, EventFragmentDict({"type": "number"})) action_name = uuid.uuid4().hex @tornado.gen.coroutine def handler(parameters): input_value = parameters.get("input") yield tornado.gen.sleep(random.random() * 0.1) raise tornado.gen.Return("{:f}".format(input_value)) exposed_thing.add_action( action_name, ActionFragmentDict({ "input": { "type": "number" }, "output": { "type": "string" } }), handler) server = MQTTServer(broker_url=get_test_broker_url(), **request.param) server.add_exposed_thing(exposed_thing) @tornado.gen.coroutine def start(): yield server.start() tornado.ioloop.IOLoop.current().run_sync(start) yield server @tornado.gen.coroutine def stop(): yield server.stop() tornado.ioloop.IOLoop.current().run_sync(stop)
def test_thing_fragment_getters_setters(): """ThingFragment attributes can be get and set from the ExposedThing.""" thing_fragment = ThingFragment({ "id": uuid.uuid4().urn, "name": Faker().pystr(), "description": Faker().pystr(), "properties": { uuid.uuid4().hex: { "description": Faker().pystr(), "type": DataType.STRING } } }) thing = Thing(thing_fragment=thing_fragment) exp_thing = ExposedThing(servient=Servient(), thing=thing) assert exp_thing.name == thing_fragment.name assert exp_thing.description == thing_fragment.description assert list(exp_thing.properties) == list( six.iterkeys(thing_fragment.properties)) name_original = thing_fragment.name name_updated = Faker().pystr() description_original = thing_fragment.description description_updated = Faker().pystr() exp_thing.name = name_updated exp_thing.description = description_updated assert exp_thing.name == name_updated assert exp_thing.name != name_original assert exp_thing.description == description_updated assert exp_thing.description != description_original with pytest.raises(AttributeError): # noinspection PyPropertyAccess exp_thing.id = Faker().pystr() with pytest.raises(AttributeError): # noinspection PyPropertyAccess exp_thing.properties = Faker().pylist() with pytest.raises(AttributeError): # noinspection PyPropertyAccess exp_thing.actions = Faker().pylist() with pytest.raises(AttributeError): # noinspection PyPropertyAccess exp_thing.events = Faker().pylist()
def _test_equivalent_interaction_names(base_name, transform_name): """Helper function to test that interaction names are equivalent given a certain transformation function.""" thing = Thing(id=uuid.uuid4().urn) exp_thing = ExposedThing(servient=Servient(), thing=thing) prop_name = "property" + base_name prop_name_transform = transform_name(prop_name) prop_default_value = Faker().pybool() exp_thing.add_property(prop_name, {"type": DataType.BOOLEAN}, value=prop_default_value) with pytest.raises(ValueError): exp_thing.add_property(prop_name_transform, {"type": DataType.BOOLEAN}) @tornado.gen.coroutine def assert_prop_read(): assert (yield exp_thing.properties[prop_name].read()) is prop_default_value assert (yield exp_thing.properties[prop_name_transform].read()) is prop_default_value tornado.ioloop.IOLoop.current().run_sync(assert_prop_read) action_name = "action" + base_name action_name_transform = transform_name(action_name) exp_thing.add_action(action_name, {}) with pytest.raises(ValueError): exp_thing.add_action(action_name_transform, {}) assert exp_thing.actions[action_name] assert exp_thing.actions[action_name_transform] event_name = "event" + base_name event_name_transform = transform_name(event_name) exp_thing.add_event(event_name, {}) with pytest.raises(ValueError): exp_thing.add_event(event_name_transform, {}) assert exp_thing.events[event_name] assert exp_thing.events[event_name_transform]
def websocket_server(): """Builds a WebsocketServer instance with some ExposedThings.""" servient = Servient() thing_01_id = uuid.uuid4().urn thing_02_id = uuid.uuid4().urn exposed_thing_01 = ExposedThing(servient=servient, thing=Thing(id=thing_01_id)) exposed_thing_02 = ExposedThing(servient=servient, thing=Thing(id=thing_02_id)) prop_name_01 = uuid.uuid4().hex prop_name_02 = uuid.uuid4().hex prop_name_03 = uuid.uuid4().hex event_name_01 = uuid.uuid4().hex action_name_01 = uuid.uuid4().hex prop_value_01 = Faker().sentence() prop_value_02 = Faker().sentence() prop_value_03 = Faker().sentence() prop_init_01 = PropertyFragmentDict({"type": "string", "observable": True}) prop_init_02 = PropertyFragmentDict({"type": "string", "observable": True}) prop_init_03 = PropertyFragmentDict({"type": "string", "observable": True}) event_init_01 = EventFragmentDict({"type": "object"}) action_init_01 = ActionFragmentDict({ "input": { "type": "string" }, "output": { "type": "string" } }) def async_lower(parameters): loop = tornado.ioloop.IOLoop.current() input_value = parameters.get("input") return loop.run_in_executor(None, lambda x: time.sleep(0.1) or x.lower(), input_value) exposed_thing_01.add_property(prop_name_01, prop_init_01, value=prop_value_01) exposed_thing_01.add_property(prop_name_02, prop_init_02, value=prop_value_02) exposed_thing_01.add_event(event_name_01, event_init_01) exposed_thing_01.add_action(action_name_01, action_init_01, async_lower) exposed_thing_02.add_property(prop_name_03, prop_init_03, value=prop_value_03) ws_port = find_free_port() ws_server = WebsocketServer(port=ws_port) ws_server.add_exposed_thing(exposed_thing_01) ws_server.add_exposed_thing(exposed_thing_02) @tornado.gen.coroutine def start(): yield ws_server.start() tornado.ioloop.IOLoop.current().run_sync(start) url_thing_01 = build_websocket_url(exposed_thing_01, ws_server, ws_port) url_thing_02 = build_websocket_url(exposed_thing_02, ws_server, ws_port) yield { "exposed_thing_01": exposed_thing_01, "exposed_thing_02": exposed_thing_02, "prop_name_01": prop_name_01, "prop_init_01": prop_init_01, "prop_value_01": prop_value_01, "prop_name_02": prop_name_02, "prop_init_02": prop_init_02, "prop_value_02": prop_value_02, "prop_name_03": prop_name_03, "prop_init_03": prop_init_03, "prop_value_03": prop_value_03, "event_name_01": event_name_01, "event_init_01": event_init_01, "action_name_01": action_name_01, "action_init_01": action_init_01, "ws_server": ws_server, "url_thing_01": url_thing_01, "url_thing_02": url_thing_02, "ws_port": ws_port } @tornado.gen.coroutine def stop(): yield ws_server.stop() tornado.ioloop.IOLoop.current().run_sync(stop)
def exposed_thing(): """Builds and returns a random ExposedThing.""" return ExposedThing(servient=Servient(), thing=Thing(id=uuid.uuid4().urn))