Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
    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)
Esempio n. 4
0
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)
Esempio n. 5
0
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)
Esempio n. 6
0
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)
Esempio n. 7
0
    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)
Esempio n. 8
0
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)
Esempio n. 9
0
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)
Esempio n. 10
0
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)
Esempio n. 11
0
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)
Esempio n. 12
0
    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))
Esempio n. 13
0
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)
Esempio n. 14
0
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)
Esempio n. 15
0
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)
Esempio n. 16
0
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)
Esempio n. 17
0
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)