Exemple #1
0
def test_property_fragment():
    """Property fragment dictionaries can be represented and serialized."""

    init = {
        "description":
        "Shows the current status of the lamp",
        "readOnly":
        True,
        "observable":
        False,
        "type":
        "string",
        "security": [{
            "scheme": "nosec"
        }],
        "forms": [{
            "href": "coaps://mylamp.example.com/status",
            "contentType": "application/json"
        }]
    }

    prop_fragment = PropertyFragmentDict(init)

    assert prop_fragment.read_only == init["readOnly"]
    assert prop_fragment.write_only is False
    assert prop_fragment.observable == init["observable"]
    assert isinstance(prop_fragment.data_schema, DataSchemaDict)
    assert prop_fragment.data_schema.type == init["type"]
    assert len(prop_fragment.forms) == len(init["forms"])
    assert prop_fragment.forms[0].href == init["forms"][0]["href"]
    assert prop_fragment.security[0].scheme == init["security"][0]["scheme"]
    assert json.dumps(prop_fragment.to_dict())

    with pytest.raises(Exception):
        PropertyFragmentDict({})
Exemple #2
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)
Exemple #3
0
 def add_prop(pname):
     exposed_thing.add_property(pname,
                                PropertyFragmentDict({
                                    "type": "number",
                                    "observable": True
                                }),
                                value=Faker().pyint())
Exemple #4
0
def client_test_write_property(servient, protocol_client_cls, timeout=None):
    """Helper function to test Property writes on bindings clients."""

    exposed_thing = next(servient.exposed_things)

    prop_name = uuid.uuid4().hex

    exposed_thing.add_property(prop_name, PropertyFragmentDict({
        "type": "string",
        "observable": True
    }), value=Faker().sentence())

    servient.refresh_forms()

    td = ThingDescription.from_thing(exposed_thing.thing)

    @tornado.gen.coroutine
    def test_coroutine():
        protocol_client = protocol_client_cls()
        prop_value = Faker().sentence()

        prev_value = yield exposed_thing.properties[prop_name].read()
        assert prev_value != prop_value

        yield protocol_client.write_property(td, prop_name, prop_value, timeout=timeout)

        curr_value = yield exposed_thing.properties[prop_name].read()
        assert curr_value == prop_value

    run_test_coroutine(test_coroutine)
Exemple #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)
Exemple #6
0
    def properties(self):
        """The properties optional attribute represents a dict with keys
        that correspond to Property names and values of type PropertyFragment."""

        return {
            key: PropertyFragmentDict(val)
            for key, val in six.iteritems(self._init.get("properties", {}))
        }
Exemple #7
0
def _build_property_fragment():
    """Builds and returns a random Property init fragment."""

    return PropertyFragmentDict({
        "description": Faker().sentence(),
        "readOnly": False,
        "observable": True,
        "type": "string"
    })
Exemple #8
0
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)
Exemple #9
0
def client_test_on_property_change(servient, protocol_client_cls):
    """Helper function to test observation of Property updates on bindings clients."""

    exposed_thing = next(servient.exposed_things)

    prop_name = uuid.uuid4().hex

    exposed_thing.add_property(prop_name, PropertyFragmentDict({
        "type": "string",
        "observable": True
    }), value=Faker().sentence())

    servient.refresh_forms()

    td = ThingDescription.from_thing(exposed_thing.thing)

    @tornado.gen.coroutine
    def test_coroutine():
        protocol_client = protocol_client_cls()

        values = [Faker().sentence() for _ in range(10)]
        values_observed = {value: tornado.concurrent.Future() for value in values}

        @tornado.gen.coroutine
        def write_next():
            try:
                next_value = next(val for val, fut in six.iteritems(values_observed) if not fut.done())
                yield exposed_thing.properties[prop_name].write(next_value)
            except StopIteration:
                pass

        def on_next(ev):
            prop_value = ev.data.value
            if prop_value in values_observed and not values_observed[prop_value].done():
                values_observed[prop_value].set_result(True)

        observable = protocol_client.on_property_change(td, prop_name)

        subscription = observable.subscribe_on(IOLoopScheduler()).subscribe(on_next)

        periodic_emit = tornado.ioloop.PeriodicCallback(write_next, 10)
        periodic_emit.start()

        yield list(values_observed.values())

        periodic_emit.stop()
        subscription.dispose()

    run_test_coroutine(test_coroutine)
Exemple #10
0
def client_test_on_property_change_error(servient, protocol_client_cls):
    """Helper function to test propagation of errors raised
    during observation of Property updates on bindings clients."""

    exposed_thing = next(servient.exposed_things)

    prop_name = uuid.uuid4().hex

    exposed_thing.add_property(prop_name, PropertyFragmentDict({
        "type": "string",
        "observable": True
    }), value=Faker().sentence())

    servient.refresh_forms()

    td = ThingDescription.from_thing(exposed_thing.thing)

    @tornado.gen.coroutine
    def test_coroutine():
        protocol_client = protocol_client_cls()

        yield servient.shutdown()

        future_err = tornado.concurrent.Future()

        # noinspection PyUnusedLocal
        def on_next(item):
            future_err.set_exception(Exception("Should not have emitted any items"))

        def on_error(err):
            future_err.set_result(err)

        observable = protocol_client.on_property_change(td, prop_name)

        subscribe_kwargs = {
            "on_next": on_next,
            "on_error": on_error
        }

        subscription = observable.subscribe_on(IOLoopScheduler()).subscribe(**subscribe_kwargs)

        observe_err = yield future_err

        assert isinstance(observe_err, Exception)

        subscription.dispose()

    run_test_coroutine(test_coroutine)
Exemple #11
0
def test_write_non_writable_property(exposed_thing):
    """Attempts to write a non-writable property should return an error."""

    prop_init_non_writable = PropertyFragmentDict({
        "type": "string",
        "readOnly": True
    })

    @tornado.gen.coroutine
    def test_coroutine():
        prop_name = Faker().pystr()
        exposed_thing.add_property(prop_name, prop_init_non_writable)

        with pytest.raises(Exception):
            yield exposed_thing.write_property(prop_name, Faker().pystr())

    run_test_coroutine(test_coroutine)
Exemple #12
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)
Exemple #13
0
def test_thing_fragment_setters():
    """Thing fragment properties can be set."""

    thing_fragment = ThingFragment(THING_INIT)

    with pytest.raises(AttributeError):
        thing_fragment.id = Faker().pystr()

    assert thing_fragment.title == THING_INIT["title"]

    title = Faker().pystr()

    # noinspection PyPropertyAccess
    thing_fragment.title = title

    assert thing_fragment.title != THING_INIT["title"]
    assert thing_fragment.title == title

    prop_fragment = PropertyFragmentDict(description=Faker().pystr(),
                                         type=DataType.NUMBER)
    props_updated = {Faker().pystr(): prop_fragment}

    # noinspection PyPropertyAccess
    thing_fragment.properties = props_updated

    assert next(six.itervalues(
        thing_fragment.properties)).description == prop_fragment.description

    security_updated = [SecuritySchemeDict(scheme=SecuritySchemeType.PSK)]

    # noinspection PyPropertyAccess
    thing_fragment.security = security_updated

    assert thing_fragment.security[0].scheme == security_updated[0].scheme

    version_updated = VersioningDict(instance=Faker().pystr())

    # noinspection PyPropertyAccess
    thing_fragment.version = version_updated

    assert thing_fragment.version.instance == version_updated.instance
Exemple #14
0
    def add_property(self, name, property_init, value=None):
        """Adds a Property defined by the argument and updates the Thing Description.
        Takes an instance of ThingPropertyInit as argument."""

        if isinstance(property_init, dict):
            property_init = PropertyFragmentDict(property_init)

        prop = Property(thing=self._thing, name=name, init_dict=property_init)

        self._thing.add_interaction(prop)
        self._set_property_value(prop, value)

        event_data = ThingDescriptionChangeEventInit(
            td_change_type=TDChangeType.PROPERTY,
            method=TDChangeMethod.ADD,
            name=name,
            data=property_init.to_dict(),
            description=ThingDescription.from_thing(self.thing).to_dict())

        self._events_stream.on_next(
            ThingDescriptionChangeEmittedEvent(init=event_data))
Exemple #15
0
def test_on_property_change_non_observable(exposed_thing):
    """Observe requests to non-observable properties are rejected."""

    prop_init_non_observable = PropertyFragmentDict({
        "type": "string",
        "observable": False
    })

    @tornado.gen.coroutine
    def test_coroutine():
        prop_name = Faker().pystr()
        exposed_thing.add_property(prop_name, prop_init_non_observable)

        observable_prop = exposed_thing.on_property_change(prop_name)

        future_next = Future()
        future_error = Future()

        def on_next(item):
            future_next.set_result(item)

        def on_error(err):
            future_error.set_exception(err)

        subscription = observable_prop.subscribe(on_next=on_next,
                                                 on_error=on_error)

        yield exposed_thing.write_property(prop_name, Faker().pystr())

        with pytest.raises(Exception):
            future_error.result()

        assert not future_next.done()

        subscription.dispose()

    run_test_coroutine(test_coroutine)
Exemple #16
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)