Пример #1
0
def test_duplicated_forms():
    """Duplicated Forms are rejected on an Interaction."""

    thing = Thing(id=uuid.uuid4().urn)
    interaction = Action(thing=thing, name="my_interaction")
    thing.add_interaction(interaction)

    href_01 = "/href-01"
    href_02 = "/href-02"

    mtype_01 = "application/json"
    mtype_02 = "text/html"

    form_01 = Form(interaction=interaction,
                   protocol=Protocols.HTTP,
                   href=href_01,
                   content_type=mtype_01)
    form_02 = Form(interaction=interaction,
                   protocol=Protocols.HTTP,
                   href=href_01,
                   content_type=mtype_01)
    form_03 = Form(interaction=interaction,
                   protocol=Protocols.HTTP,
                   href=href_01,
                   content_type=mtype_02)
    form_04 = Form(interaction=interaction,
                   protocol=Protocols.HTTP,
                   href=href_02,
                   content_type=mtype_01)
    form_05 = Form(interaction=interaction,
                   protocol=Protocols.HTTP,
                   href=href_02,
                   content_type=mtype_02)
    form_06 = Form(interaction=interaction,
                   protocol=Protocols.HTTP,
                   href=href_02,
                   content_type=mtype_02)

    interaction.add_form(form_01)

    with pytest.raises(ValueError):
        interaction.add_form(form_02)

    interaction.add_form(form_03)
    interaction.add_form(form_04)
    interaction.add_form(form_05)

    with pytest.raises(ValueError):
        interaction.add_form(form_06)
Пример #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)
Пример #3
0
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
    }
Пример #4
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)
Пример #5
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)
Пример #6
0
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()
Пример #7
0
def test_unique_url_name():
    """URL names are always unique as long as the IDs are."""

    thing_id_base = uuid.uuid4().urn
    thing_ids = [thing_id_base]

    for ch in string.punctuation.replace("-", ""):
        thing_ids.append(thing_id_base.replace("-", ch))

    things = [Thing(id=item) for item in thing_ids]
    url_names = [item.url_name for item in things]

    assert len(url_names) == len(set(url_names))
Пример #8
0
def test_interaction_invalid_name():
    """Invalid names for Interaction objects are rejected."""

    names_valid = ["safename", "safename02", "SafeName_03", "Safe_Name-04"]

    names_invalid = ["!unsafename", "unsafe_name_ñ", "unsafe name", "?"]

    thing = Thing(id=uuid.uuid4().urn)

    for name in names_valid:
        Action(thing=thing, name=name)

    for name in names_invalid:
        with pytest.raises(ValueError):
            Action(thing=thing, name=name)
Пример #9
0
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]
Пример #10
0
def test_from_thing():
    """ThingDescription objects can be built from Thing objects."""

    fake = Faker()

    thing_id = uuid.uuid4().urn
    action_id = uuid.uuid4().hex
    prop_id = uuid.uuid4().hex
    event_id = uuid.uuid4().hex
    action_form_href = fake.url()
    prop_form_href = fake.url()

    thing = Thing(id=thing_id)

    action = Action(thing=thing, name=action_id)
    action_form = Form(interaction=action,
                       protocol=Protocols.HTTP,
                       href=action_form_href)
    action.add_form(action_form)
    thing.add_interaction(action)

    prop = Property(thing=thing, name=prop_id, type="string")
    prop_form = Form(interaction=prop,
                     protocol=Protocols.HTTP,
                     href=prop_form_href)
    prop.add_form(prop_form)
    thing.add_interaction(prop)

    event = Event(thing=thing, name=event_id)
    thing.add_interaction(event)

    json_td = ThingDescription.from_thing(thing)
    td_dict = json_td.to_dict()

    assert td_dict["id"] == thing.id
    assert td_dict["title"] == thing.title
    assert len(td_dict["properties"]) == 1
    assert len(td_dict["actions"]) == 1
    assert len(td_dict["events"]) == 1
    assert len(td_dict["actions"][action_id]["forms"]) == 1
    assert len(td_dict["properties"][prop_id]["forms"]) == 1
    assert td_dict["actions"][action_id]["forms"][0][
        "href"] == action_form_href
    assert td_dict["properties"][prop_id]["forms"][0]["href"] == prop_form_href
Пример #11
0
    def thing_from_model(cls, model):
        """Takes a ThingModel and builds a Thing. 
        Raises if the model has an unexpected type."""

        expected_types = (six.string_types, ThingFragment, ConsumedThing)

        if not isinstance(model, expected_types):
            raise ValueError("Expected one of: {}".format(expected_types))

        if isinstance(model, six.string_types):
            thing = ThingDescription(doc=model).build_thing()
        elif isinstance(model, ThingFragment):
            thing = Thing(thing_fragment=model)
        else:
            thing = model.td.build_thing()

        return thing
Пример #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)
Пример #13
0
def test_find_interaction():
    """Interactions may be retrieved by name on a Thing."""

    thing = Thing(id=uuid.uuid4().urn)

    interaction_01 = Action(thing=thing, name="my_interaction")
    interaction_02 = Action(thing=thing, name="AnotherInteraction")

    thing.add_interaction(interaction_01)
    thing.add_interaction(interaction_02)

    assert thing.find_interaction(interaction_01.name) is interaction_01
    assert thing.find_interaction(interaction_02.name) is interaction_02
    assert thing.find_interaction(slugify(
        interaction_01.name)) is interaction_01
    assert thing.find_interaction(slugify(
        interaction_02.name)) is interaction_02
Пример #14
0
def test_duplicated_interactions():
    """Duplicated Interactions are rejected on a Thing."""

    thing = Thing(id=uuid.uuid4().urn)

    interaction_01 = Action(thing=thing, name="my_interaction")
    interaction_02 = Action(thing=thing, name="AnotherInteraction")
    interaction_03 = Action(thing=thing, name="my_interaction")

    thing.add_interaction(interaction_01)
    thing.add_interaction(interaction_02)

    with pytest.raises(ValueError):
        thing.add_interaction(interaction_03)
Пример #15
0
def test_empty_thing_valid():
    """An empty Thing initialized by default has a valid JSON-LD serialization."""

    thing = Thing(id=uuid.uuid4().urn)
    json_td = ThingDescription.from_thing(thing)
    ThingDescription.validate(json_td.to_dict())
Пример #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)
Пример #17
0
    def build_thing(self):
        """Builds a new Thing object from the serialized Thing Description."""

        return Thing(thing_fragment=self.to_thing_fragment())
Пример #18
0
def test_remove_interaction():
    """Interactions may be removed from a Thing by name."""

    thing = Thing(id=uuid.uuid4().urn)

    interaction_01 = Action(thing=thing, name="my_interaction")
    interaction_02 = Action(thing=thing, name="AnotherInteraction")
    interaction_03 = Action(thing=thing, name="YetAnother_interaction")

    thing.add_interaction(interaction_01)
    thing.add_interaction(interaction_02)
    thing.add_interaction(interaction_03)

    assert thing.find_interaction(interaction_01.name) is not None
    assert thing.find_interaction(interaction_02.name) is not None
    assert thing.find_interaction(interaction_03.name) is not None

    thing.remove_interaction(interaction_01.name)
    thing.remove_interaction(slugify(interaction_03.name))

    assert thing.find_interaction(interaction_01.name) is None
    assert thing.find_interaction(interaction_02.name) is not None
    assert thing.find_interaction(interaction_03.name) is None
Пример #19
0
def exposed_thing():
    """Builds and returns a random ExposedThing."""

    return ExposedThing(servient=Servient(), thing=Thing(id=uuid.uuid4().urn))