def all_protocols_servient(): """Returns a Servient configured to use all available protocol bindings.""" servient = Servient(catalogue_port=None) http_port = find_free_port() http_server = HTTPServer(port=http_port) servient.add_server(http_server) ws_port = find_free_port() ws_server = WebsocketServer(port=ws_port) servient.add_server(ws_server) if is_coap_supported(): from wotpy.protocols.coap.server import CoAPServer coap_port = find_free_port() coap_server = CoAPServer(port=coap_port) servient.add_server(coap_server) if is_mqtt_supported(): from wotpy.protocols.mqtt.server import MQTTServer from tests.protocols.mqtt.broker import get_test_broker_url, is_test_broker_online if is_test_broker_online(): mqtt_server = MQTTServer(broker_url=get_test_broker_url()) servient.add_server(mqtt_server) @tornado.gen.coroutine def start(): raise tornado.gen.Return((yield servient.start())) wot = tornado.ioloop.IOLoop.current().run_sync(start) td_dict = { "id": uuid.uuid4().urn, "title": uuid.uuid4().hex, "properties": { uuid.uuid4().hex: { "observable": True, "type": "string" } } } td = ThingDescription(td_dict) exposed_thing = wot.produce(td.to_str()) exposed_thing.expose() yield servient @tornado.gen.coroutine def shutdown(): yield servient.shutdown() tornado.ioloop.IOLoop.current().run_sync(shutdown)
def test_discovery_method_multicast_dnssd(): """Things can be discovered usin the multicast method supported by DNS-SD.""" catalogue_port_01 = find_free_port() catalogue_port_02 = find_free_port() instance_name_01 = "servient-01-{}".format(Faker().pystr()) instance_name_02 = "servient-02-{}".format(Faker().pystr()) servient_01 = Servient(catalogue_port=catalogue_port_01, dnssd_enabled=True, dnssd_instance_name=instance_name_01) servient_02 = Servient(catalogue_port=catalogue_port_02, dnssd_enabled=True, dnssd_instance_name=instance_name_02) future_done, found = tornado.concurrent.Future(), [] def resolve(): len(found) == 2 and not future_done.done() and future_done.set_result( True) @tornado.gen.coroutine def test_coroutine(): wot_01 = yield servient_01.start() wot_02 = yield servient_02.start() wot_01.produce(ThingFragment(TD_DICT_01)).expose() wot_01.produce(ThingFragment(TD_DICT_02)).expose() thing_filter = ThingFilterDict(method=DiscoveryMethod.MULTICAST) observable = wot_02.discover(thing_filter, dnssd_find_kwargs={ "min_results": 1, "timeout": 5 }) subscription = observable.subscribe( on_next=lambda td_str: found.append(ThingDescription(td_str) ) or resolve()) yield future_done assert_equal_td_sequences(found, [TD_DICT_01, TD_DICT_02]) subscription.dispose() yield servient_01.shutdown() yield servient_02.shutdown() run_test_coroutine(test_coroutine)
def test_coroutine(): service_history = asyncio_zeroconf.pop("service_history") port_catalogue = find_free_port() servient = Servient(catalogue_port=port_catalogue) instance_name = Faker().sentence() instance_name = instance_name.strip('.')[:32] yield dnssd_discovery.start() yield dnssd_discovery.register(servient, instance_name=instance_name) while _num_service_instance_items(servient, service_history, instance_name) < 1: yield tornado.gen.sleep(0.1) yield dnssd_discovery.stop() while _num_service_instance_items(servient, service_history, instance_name) < 2: yield tornado.gen.sleep(0.1) assert len([ item[1].startswith(instance_name) for item in service_history ]) == 2 with pytest.raises(Exception): _assert_service_added_removed(servient, service_history) _assert_service_added_removed(servient, service_history, instance_name)
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 dnssd_servient(): """Builds a Servient with both the TD catalogue and the DNS-SD service enabled.""" servient = Servient(catalogue_port=find_free_port(), dnssd_enabled=True, dnssd_instance_name=Faker().pystr()) yield servient @tornado.gen.coroutine def shutdown(): yield servient.shutdown() tornado.ioloop.IOLoop.current().run_sync(shutdown)
def test_coroutine(): service_history = asyncio_zeroconf.pop("service_history") port_catalogue = find_free_port() servient = Servient(catalogue_port=port_catalogue) yield dnssd_discovery.start() yield dnssd_discovery.register(servient) yield dnssd_discovery.unregister(servient) while _num_service_instance_items(servient, service_history) < 2: yield tornado.gen.sleep(0.1) _assert_service_added_removed(servient, service_history)
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 test_start_stop(): """The CoAP server can be started and stopped.""" coap_port = find_free_port() coap_server = CoAPServer(port=coap_port) ping_uri = "coap://127.0.0.1:{}/.well-known/core".format(coap_port) @tornado.gen.coroutine def ping(): try: coap_client = yield aiocoap.Context.create_client_context() request_msg = aiocoap.Message(code=aiocoap.Code.GET, uri=ping_uri) response = yield tornado.gen.with_timeout( datetime.timedelta(seconds=2), coap_client.request(request_msg).response) except Exception: raise tornado.gen.Return(False) raise tornado.gen.Return(response.code.is_successful()) @tornado.gen.coroutine def test_coroutine(): assert not (yield ping()) yield coap_server.start() assert (yield ping()) assert (yield ping()) for _ in range(5): yield coap_server.stop() assert not (yield ping()) yield coap_server.stop() for _ in range(5): yield coap_server.start() assert (yield ping()) run_test_coroutine(test_coroutine)
def test_produce_from_url(td_example_tornado_app): """ExposedThings can be created from URLs that provide Thing Description documents.""" app_port = find_free_port() td_example_tornado_app.listen(app_port) url_valid = "http://localhost:{}/".format(app_port) url_error = "http://localhost:{}/{}".format(app_port, Faker().pystr()) wot = WoT(servient=Servient()) @tornado.gen.coroutine def test_coroutine(): exposed_thing = yield wot.produce_from_url(url_valid) assert exposed_thing.thing.id == TD_EXAMPLE.get("id") with pytest.raises(Exception): yield wot.produce_from_url(url_error) run_test_coroutine(test_coroutine)
def servient(request): """Returns an empty WoT Servient.""" catalogue_port = find_free_port() if request.param.get( 'catalogue_enabled') else None servient = Servient(catalogue_port=catalogue_port) @tornado.gen.coroutine def start(): yield servient.start() tornado.ioloop.IOLoop.current().run_sync(start) yield servient @tornado.gen.coroutine def shutdown(): yield servient.shutdown() tornado.ioloop.IOLoop.current().run_sync(shutdown)
def test_coroutine(): aio_zc = asyncio_zeroconf.pop("zeroconf") ipaddr = Faker().ipv4_private() port = find_free_port() service_name = "{}.{}".format(Faker().pystr(), DNSSDDiscoveryService.WOT_SERVICE_TYPE) server = "{}.local.".format(Faker().pystr()) info = ServiceInfo(DNSSDDiscoveryService.WOT_SERVICE_TYPE, service_name, address=socket.inet_aton(ipaddr), port=port, properties={}, server=server) yield aio_zc.register_service(info) with pytest.raises(ValueError): yield dnssd_discovery.find() yield dnssd_discovery.start() assert (ipaddr, port) in (yield dnssd_discovery.find(timeout=3))
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 coap_servient(): """Returns a Servient that exposes a CoAP server and one ExposedThing.""" from wotpy.protocols.coap.server import CoAPServer coap_port = find_free_port() the_coap_server = CoAPServer(port=coap_port) servient = Servient(catalogue_port=None) servient.add_server(the_coap_server) @tornado.gen.coroutine def start(): raise tornado.gen.Return((yield servient.start())) wot = tornado.ioloop.IOLoop.current().run_sync(start) property_name_01 = uuid.uuid4().hex action_name_01 = uuid.uuid4().hex event_name_01 = uuid.uuid4().hex td_dict = { "id": uuid.uuid4().urn, "title": uuid.uuid4().hex, "properties": { property_name_01: { "observable": True, "type": "string" } }, "actions": { action_name_01: { "input": { "type": "number" }, "output": { "type": "number" }, } }, "events": { event_name_01: { "type": "string" } }, } td = ThingDescription(td_dict) exposed_thing = wot.produce(td.to_str()) exposed_thing.expose() @tornado.gen.coroutine def action_handler(parameters): input_value = parameters.get("input") raise tornado.gen.Return(int(input_value) * 2) exposed_thing.set_action_handler(action_name_01, action_handler) yield servient @tornado.gen.coroutine def shutdown(): yield servient.shutdown() tornado.ioloop.IOLoop.current().run_sync(shutdown)
def test_consumed_client_protocols_preference(): """The Servient selects different protocol clients to consume Things depending on the protocol choices displayed on the Thing Description.""" servient = Servient(catalogue_port=None) @tornado.gen.coroutine def servient_start(): raise tornado.gen.Return((yield servient.start())) @tornado.gen.coroutine def servient_shutdown(): yield servient.shutdown() http_port = find_free_port() http_server = HTTPServer(port=http_port) servient.add_server(http_server) ws_port = find_free_port() ws_server = WebsocketServer(port=ws_port) servient.add_server(ws_server) client_server_map = { HTTPClient: http_server, WebsocketClient: ws_server } wot = tornado.ioloop.IOLoop.current().run_sync(servient_start) prop_name = uuid.uuid4().hex td_produce = ThingDescription({ "id": uuid.uuid4().urn, "name": uuid.uuid4().hex, "properties": { prop_name: { "observable": True, "type": "string" } } }) exposed_thing = wot.produce(td_produce.to_str()) exposed_thing.expose() td_forms_all = ThingDescription.from_thing(exposed_thing.thing) client_01 = servient.select_client(td_forms_all, prop_name) client_01_class = client_01.__class__ assert client_01_class in six.iterkeys(client_server_map) tornado.ioloop.IOLoop.current().run_sync(servient_shutdown) servient.remove_server(client_server_map[client_01_class].protocol) tornado.ioloop.IOLoop.current().run_sync(servient_start) td_forms_removed = ThingDescription.from_thing(exposed_thing.thing) client_02 = servient.select_client(td_forms_removed, prop_name) client_02_class = client_02.__class__ assert client_02_class != client_01_class assert client_02_class in six.iterkeys(client_server_map) tornado.ioloop.IOLoop.current().run_sync(servient_shutdown)
def test_servient_start_stop(): """The servient and contained ExposedThings can be started and stopped.""" fake = Faker() ws_port = find_free_port() ws_server = WebsocketServer(port=ws_port) servient = Servient() servient.disable_td_catalogue() servient.add_server(ws_server) @tornado.gen.coroutine def start(): raise tornado.gen.Return((yield servient.start())) wot = tornado.ioloop.IOLoop.current().run_sync(start) thing_id = uuid.uuid4().urn name_prop_string = fake.user_name() name_prop_boolean = fake.user_name() td_doc = { "id": thing_id, "title": Faker().sentence(), "properties": { name_prop_string: { "observable": True, "type": "string" }, name_prop_boolean: { "observable": True, "type": "boolean" } } } td_str = json.dumps(td_doc) exposed_thing = wot.produce(td_str) exposed_thing.expose() value_boolean = fake.pybool() value_string = fake.pystr() @tornado.gen.coroutine def get_property(prop_name): """Gets the given property using the WS Link contained in the thing description.""" td = ThingDescription.from_thing(exposed_thing.thing) consumed_thing = ConsumedThing(servient, td=td) value = yield consumed_thing.read_property(prop_name) raise tornado.gen.Return(value) @tornado.gen.coroutine def assert_thing_active(): """Asserts that the retrieved property values are as expected.""" retrieved_boolean = yield get_property(name_prop_boolean) retrieved_string = yield get_property(name_prop_string) assert retrieved_boolean == value_boolean assert retrieved_string == value_string @tornado.gen.coroutine def test_coroutine(): yield exposed_thing.write_property(name=name_prop_boolean, value=value_boolean) yield exposed_thing.write_property(name=name_prop_string, value=value_string) yield assert_thing_active() exposed_thing.destroy() with pytest.raises(Exception): yield assert_thing_active() with pytest.raises(Exception): exposed_thing.expose() yield servient.shutdown() run_test_coroutine(test_coroutine)
def websocket_servient(): """Returns a Servient that exposes a Websockets server and one ExposedThing.""" ws_port = find_free_port() ws_server = WebsocketServer(port=ws_port) servient = Servient(catalogue_port=None) servient.add_server(ws_server) @tornado.gen.coroutine def start(): raise tornado.gen.Return((yield servient.start())) wot = tornado.ioloop.IOLoop.current().run_sync(start) property_name_01 = uuid.uuid4().hex property_name_02 = uuid.uuid4().hex action_name_01 = uuid.uuid4().hex event_name_01 = uuid.uuid4().hex td_dict = { "id": uuid.uuid4().urn, "name": uuid.uuid4().hex, "properties": { property_name_01: { "observable": True, "type": "string" }, property_name_02: { "observable": True, "type": "string" } }, "actions": { action_name_01: { "input": { "type": "object" }, "output": { "type": "string" }, } }, "events": { event_name_01: { "type": "string" } }, } td = ThingDescription(td_dict) exposed_thing = wot.produce(td.to_str()) exposed_thing.expose() @tornado.gen.coroutine def action_handler(parameters): input_value = parameters.get("input") arg_b = input_value.get("arg_b") or uuid.uuid4().hex raise tornado.gen.Return(input_value.get("arg_a") + arg_b) exposed_thing.set_action_handler(action_name_01, action_handler) yield servient @tornado.gen.coroutine def shutdown(): yield servient.shutdown() tornado.ioloop.IOLoop.current().run_sync(shutdown)