示例#1
0
def _test_property_change_events(exposed_thing, subscribe_func):
    """Helper function to test client subscriptions to property change events."""
    @tornado.gen.coroutine
    def test_coroutine():
        td = ThingDescription.from_thing(exposed_thing.thing)
        prop_name = next(six.iterkeys(td.properties))

        future_conn = Future()
        future_change = Future()

        prop_value = Faker().sentence()

        def on_next(ev):
            if not future_conn.done():
                future_conn.set_result(True)
                return

            if ev.data.value == prop_value:
                future_change.set_result(True)

        subscription = subscribe_func(prop_name, on_next)

        while not future_conn.done():
            yield tornado.gen.sleep(0)
            yield exposed_thing.write_property(prop_name, Faker().sentence())

        yield exposed_thing.write_property(prop_name, prop_value)

        yield future_change

        assert future_change.result()

        subscription.dispose()

    run_test_coroutine(test_coroutine)
示例#2
0
def client_test_invoke_action_error(servient, protocol_client_cls):
    """Helper function to test Action invocations that raise errors on bindings clients."""

    exposed_thing = next(servient.exposed_things)

    action_name = uuid.uuid4().hex

    err_message = Faker().sentence()

    # noinspection PyUnusedLocal
    def action_handler(parameters):
        raise ValueError(err_message)

    exposed_thing.add_action(action_name, ActionFragmentDict({
        "input": {"type": "number"},
        "output": {"type": "string"}
    }), action_handler)

    servient.refresh_forms()

    td = ThingDescription.from_thing(exposed_thing.thing)

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

        try:
            yield protocol_client.invoke_action(td, action_name, Faker().pyint())
            raise AssertionError("Did not raise Exception")
        except Exception as ex:
            assert err_message in str(ex)

    run_test_coroutine(test_coroutine)
示例#3
0
def _test_event_emission_events(exposed_thing, subscribe_func):
    """Helper function to test client subscription to event emissions."""
    @tornado.gen.coroutine
    def test_coroutine():
        td = ThingDescription.from_thing(exposed_thing.thing)
        event_name = next(six.iterkeys(td.events))

        future_conn = Future()
        future_event = Future()

        payload = Faker().sentence()

        def on_next(ev):
            if not future_conn.done():
                future_conn.set_result(True)
                return

            if ev.data == payload:
                future_event.set_result(True)

        subscription = subscribe_func(event_name, on_next)

        while not future_conn.done():
            yield tornado.gen.sleep(0)
            exposed_thing.emit_event(event_name, Faker().sentence())

        exposed_thing.emit_event(event_name, payload)

        yield future_event

        assert future_event.result()

        subscription.dispose()

    run_test_coroutine(test_coroutine)
示例#4
0
def client_test_invoke_action(servient, protocol_client_cls, timeout=None):
    """Helper function to test Action invocations on bindings clients."""

    exposed_thing = next(servient.exposed_things)

    action_name = uuid.uuid4().hex

    @tornado.gen.coroutine
    def action_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"}
    }), action_handler)

    servient.refresh_forms()

    td = ThingDescription.from_thing(exposed_thing.thing)

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

        input_value = Faker().pyint()

        result = yield protocol_client.invoke_action(td, action_name, input_value, timeout=timeout)
        result_expected = yield action_handler({"input": input_value})

        assert result == result_expected

    run_test_coroutine(test_coroutine)
示例#5
0
def test_start_stop():
    """The DNS-SD service can be started and stopped."""
    @tornado.gen.coroutine
    def test_coroutine():
        dnssd_discovery = DNSSDDiscoveryService()

        yield dnssd_discovery.start()

        assert dnssd_discovery.is_running

        for _ in range(10):
            yield dnssd_discovery.stop()

        assert not dnssd_discovery.is_running

        for _ in range(10):
            yield dnssd_discovery.start()

        assert dnssd_discovery.is_running

        yield dnssd_discovery.stop()

        assert not dnssd_discovery.is_running

    run_test_coroutine(test_coroutine)
示例#6
0
def test_discovery_method_local():
    """All TDs contained in the Servient are returned when using the local
    discovery method without defining the fragment nor the query fields."""

    servient = Servient(dnssd_enabled=False)
    wot = WoT(servient=servient)
    wot.produce(ThingFragment(TD_DICT_01))
    wot.produce(ThingFragment(TD_DICT_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():
        thing_filter = ThingFilterDict(method=DiscoveryMethod.LOCAL)
        observable = wot.discover(thing_filter)

        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()

    run_test_coroutine(test_coroutine)
示例#7
0
def test_on_undefined_property_change(websocket_server):
    """Observing an undefined property results in a subscription error message."""

    url_thing_01 = websocket_server.pop("url_thing_01")

    @tornado.gen.coroutine
    def test_coroutine():
        observe_msg_id = Faker().pyint()
        prop_name_err = uuid.uuid4().hex

        conn = yield tornado.websocket.websocket_connect(url_thing_01)

        msg_observe_req = WebsocketMessageRequest(
            method=WebsocketMethods.ON_PROPERTY_CHANGE,
            params={"name": prop_name_err},
            msg_id=observe_msg_id)

        conn.write_message(msg_observe_req.to_json())

        msg_observe_resp_raw = yield conn.read_message()
        msg_observe_resp = WebsocketMessageResponse.from_raw(
            msg_observe_resp_raw)

        msg_observe_err_raw = yield conn.read_message()
        msg_observe_err = WebsocketMessageError.from_raw(msg_observe_err_raw)

        assert msg_observe_err.code == WebsocketErrors.SUBSCRIPTION_ERROR
        assert msg_observe_err.data["subscription"] == msg_observe_resp.result

    run_test_coroutine(test_coroutine)
示例#8
0
def test_register(asyncio_zeroconf, dnssd_discovery):
    """WoT Servients may be registered for discovery on the DNS-SD service."""
    @tornado.gen.coroutine
    def test_coroutine():
        service_history = asyncio_zeroconf.pop("service_history")

        port_catalogue = find_free_port()
        servient = Servient(catalogue_port=port_catalogue)

        with pytest.raises(ValueError):
            yield dnssd_discovery.register(servient)

        yield dnssd_discovery.start()

        assert not len(service_history)

        yield dnssd_discovery.register(servient)

        while _num_service_instance_items(servient, service_history) < 1:
            yield tornado.gen.sleep(0.1)

        yield dnssd_discovery.stop()

        while _num_service_instance_items(servient, service_history) < 2:
            yield tornado.gen.sleep(0.1)

        _assert_service_added_removed(servient, service_history)

    run_test_coroutine(test_coroutine)
示例#9
0
def test_find(asyncio_zeroconf, dnssd_discovery):
    """Remote WoT Servients may be discovered using the DNS-SD service."""
    @tornado.gen.coroutine
    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))

    run_test_coroutine(test_coroutine)
示例#10
0
def test_register_instance_name(asyncio_zeroconf, dnssd_discovery):
    """WoT Servients may be registered with custom service instance names."""
    @tornado.gen.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)

    run_test_coroutine(test_coroutine)
示例#11
0
def test_start_stop():
    """The MQTT server may be started and stopped."""

    mqtt_server = MQTTServer(broker_url=get_test_broker_url())

    @tornado.gen.coroutine
    def test_coroutine():
        assert not (yield _ping(mqtt_server, timeout=DEFAULT_PING_TIMEOUT))

        yield mqtt_server.start()

        assert (yield _ping(mqtt_server))
        assert (yield _ping(mqtt_server))

        yield mqtt_server.stop()
        yield mqtt_server.start()
        yield mqtt_server.stop()

        assert not (yield _ping(mqtt_server, timeout=DEFAULT_PING_TIMEOUT))

        yield mqtt_server.stop()
        yield mqtt_server.start()
        yield mqtt_server.start()

        assert (yield _ping(mqtt_server))

    run_test_coroutine(test_coroutine)
示例#12
0
def test_action_invoke(mqtt_server):
    """Actions can be invoked using the MQTT binding."""

    exposed_thing = next(mqtt_server.exposed_things)
    action_name = next(six.iterkeys(exposed_thing.thing.actions))
    action = exposed_thing.thing.actions[action_name]

    topic_invoke = build_topic(mqtt_server, action,
                               InteractionVerbs.INVOKE_ACTION)
    topic_result = ActionMQTTHandler.to_result_topic(topic_invoke)

    @tornado.gen.coroutine
    def test_coroutine():
        client_invoke = yield connect_broker(topic_invoke)
        client_result = yield connect_broker(topic_result)

        data = {"id": uuid.uuid4().hex, "input": Faker().pyint()}

        now_ms = int(time.time() * 1000)

        yield client_invoke.publish(topic_invoke,
                                    json.dumps(data).encode(),
                                    qos=QOS_2)

        msg = yield client_result.deliver_message()
        msg_data = json.loads(msg.data.decode())

        assert msg_data.get("id") == data.get("id")
        assert msg_data.get("result") == "{:f}".format(data.get("input"))
        assert msg_data.get("timestamp") >= now_ms

    run_test_coroutine(test_coroutine)
示例#13
0
def test_observe_event(mqtt_server):
    """Events may be observed using the MQTT binding."""

    now_ms = int(time.time() * 1000)

    exposed_thing = next(mqtt_server.exposed_things)
    event_name = next(six.iterkeys(exposed_thing.thing.events))
    event = exposed_thing.thing.events[event_name]
    topic = build_topic(mqtt_server, event, InteractionVerbs.SUBSCRIBE_EVENT)

    @tornado.gen.coroutine
    def test_coroutine():
        client = yield connect_broker(topic)

        emitted_value = Faker().pyint()

        @tornado.gen.coroutine
        def emit_value():
            yield exposed_thing.events[event_name].emit(emitted_value)

        periodic_emit = tornado.ioloop.PeriodicCallback(emit_value, 50)
        periodic_emit.start()

        msg = yield client.deliver_message()

        event_data = json.loads(msg.data.decode())

        assert event_data.get("name") == event_name
        assert event_data.get("data") == emitted_value
        assert event_data.get("timestamp") >= now_ms

        periodic_emit.stop()

    run_test_coroutine(test_coroutine)
示例#14
0
def test_observe_property_changes(mqtt_server):
    """Property updates may be observed using the MQTT binding."""

    exposed_thing = next(mqtt_server.exposed_things)
    prop_name = next(six.iterkeys(exposed_thing.thing.properties))
    prop = exposed_thing.thing.properties[prop_name]
    topic_observe = build_topic(mqtt_server, prop,
                                InteractionVerbs.OBSERVE_PROPERTY)

    @tornado.gen.coroutine
    def test_coroutine():
        client_observe = yield connect_broker(topic_observe)

        updated_value = Faker().sentence()

        @tornado.gen.coroutine
        def write_value():
            yield exposed_thing.properties[prop_name].write(updated_value)

        periodic_write = tornado.ioloop.PeriodicCallback(write_value, 50)
        periodic_write.start()

        msg = yield client_observe.deliver_message()

        assert json.loads(msg.data.decode()).get("value") == updated_value

        periodic_write.stop()

    run_test_coroutine(test_coroutine)
示例#15
0
def test_servient_id():
    """An MQTT server may be identified by a unique Servient ID to avoid topic collisions."""

    broker_url = get_test_broker_url()

    mqtt_srv_01 = MQTTServer(broker_url=broker_url)
    mqtt_srv_02 = MQTTServer(broker_url=broker_url)
    mqtt_srv_03 = MQTTServer(broker_url=broker_url,
                             servient_id=Faker().pystr())

    assert mqtt_srv_01.servient_id and mqtt_srv_02.servient_id and mqtt_srv_03.servient_id
    assert mqtt_srv_01.servient_id == mqtt_srv_02.servient_id
    assert mqtt_srv_01.servient_id != mqtt_srv_03.servient_id

    @tornado.gen.coroutine
    def assert_ping_loop(srv, num_iters=10):
        for _ in range(num_iters):
            assert (yield _ping(srv, timeout=DEFAULT_PING_TIMEOUT))
            yield tornado.gen.sleep(random.uniform(0.1, 0.3))

    @tornado.gen.coroutine
    def test_coroutine():
        yield [mqtt_srv_01.start(), mqtt_srv_03.start()]

        yield [assert_ping_loop(mqtt_srv_01), assert_ping_loop(mqtt_srv_03)]

    run_test_coroutine(test_coroutine)
示例#16
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)
示例#17
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)
示例#18
0
def test_read_property(websocket_server):
    """Properties can be retrieved using Websockets."""

    url_thing_01 = websocket_server.pop("url_thing_01")
    url_thing_02 = websocket_server.pop("url_thing_02")
    prop_name_01 = websocket_server.pop("prop_name_01")
    prop_name_02 = websocket_server.pop("prop_name_02")
    prop_name_03 = websocket_server.pop("prop_name_03")
    prop_value_01 = websocket_server.pop("prop_value_01")
    prop_value_02 = websocket_server.pop("prop_value_02")
    prop_value_03 = websocket_server.pop("prop_value_03")

    @tornado.gen.coroutine
    def test_coroutine():
        conns = yield [
            tornado.websocket.websocket_connect(url_thing_01),
            tornado.websocket.websocket_connect(url_thing_02)
        ]

        request_id_01 = Faker().pyint()
        request_id_02 = Faker().pyint()
        request_id_03 = Faker().pyint()

        ws_request_prop_01 = WebsocketMessageRequest(
            method=WebsocketMethods.READ_PROPERTY,
            params={"name": prop_name_01},
            msg_id=request_id_01)

        ws_request_prop_02 = WebsocketMessageRequest(
            method=WebsocketMethods.READ_PROPERTY,
            params={"name": prop_name_02},
            msg_id=request_id_02)

        ws_request_prop_03 = WebsocketMessageRequest(
            method=WebsocketMethods.READ_PROPERTY,
            params={"name": prop_name_03},
            msg_id=request_id_03)

        conns[0].write_message(ws_request_prop_01.to_json())
        conns[0].write_message(ws_request_prop_02.to_json())
        conns[1].write_message(ws_request_prop_03.to_json())

        raw_resp_01 = yield conns[0].read_message()
        raw_resp_02 = yield conns[0].read_message()
        raw_resp_03 = yield conns[1].read_message()

        ws_resp_01 = WebsocketMessageResponse.from_raw(raw_resp_01)
        ws_resp_02 = WebsocketMessageResponse.from_raw(raw_resp_02)
        ws_resp_03 = WebsocketMessageResponse.from_raw(raw_resp_03)

        assert ws_resp_01.result == prop_value_01
        assert ws_resp_02.result == prop_value_02
        assert ws_resp_03.result == prop_value_03

        yield conns[0].close()
        yield conns[1].close()

    run_test_coroutine(test_coroutine)
示例#19
0
def test_on_property_change(websocket_server):
    """Property changes can be observed using Websockets."""

    url_thing_01 = websocket_server.pop("url_thing_01")
    exposed_thing_01 = websocket_server.pop("exposed_thing_01")
    prop_name = websocket_server.pop("prop_name_01")

    @tornado.gen.coroutine
    def test_coroutine():
        observe_msg_id = Faker().pyint()

        updated_val_01 = Faker().pystr()
        updated_val_02 = Faker().pystr()
        updated_val_03 = Faker().pystr()

        conn = yield tornado.websocket.websocket_connect(url_thing_01)

        msg_observe_req = WebsocketMessageRequest(
            method=WebsocketMethods.ON_PROPERTY_CHANGE,
            params={"name": prop_name},
            msg_id=observe_msg_id)

        conn.write_message(msg_observe_req.to_json())

        msg_observe_resp_raw = yield conn.read_message()
        msg_observe_resp = WebsocketMessageResponse.from_raw(
            msg_observe_resp_raw)

        assert msg_observe_resp.id == observe_msg_id

        subscription_id = msg_observe_resp.result

        def assert_emitted(the_msg_raw, the_expected_val):
            msg_emitted = WebsocketMessageEmittedItem.from_raw(the_msg_raw)

            assert msg_emitted.subscription_id == subscription_id
            assert msg_emitted.data["name"] == prop_name
            assert msg_emitted.data["value"] == the_expected_val

        yield exposed_thing_01.write_property(prop_name, updated_val_01)

        msg_emitted_raw = yield conn.read_message()
        assert_emitted(msg_emitted_raw, updated_val_01)

        yield exposed_thing_01.write_property(prop_name, updated_val_02)
        yield exposed_thing_01.write_property(prop_name, updated_val_03)

        msg_emitted_raw = yield conn.read_message()
        assert_emitted(msg_emitted_raw, updated_val_02)

        msg_emitted_raw = yield conn.read_message()
        assert_emitted(msg_emitted_raw, updated_val_03)

        yield conn.close()

    run_test_coroutine(test_coroutine)
示例#20
0
def test_event_subscription(coap_server):
    """Event emissions can be observed in a CoAP server."""

    exposed_thing = next(coap_server.exposed_things)
    event_name = next(six.iterkeys(exposed_thing.thing.events))
    href = _get_event_href(exposed_thing, event_name, coap_server)

    emitted_values = [{
        "num": Faker().pyint(),
        "str": Faker().sentence()
    } for _ in range(5)]

    def emit_event():
        exposed_thing.emit_event(event_name, payload=emitted_values[0])

    def all_values_emitted():
        return len(emitted_values) == 0

    @tornado.gen.coroutine
    def test_coroutine():
        periodic_set = tornado.ioloop.PeriodicCallback(emit_event, 5)
        periodic_set.start()

        coap_client = yield aiocoap.Context.create_client_context()
        request_msg = aiocoap.Message(code=aiocoap.Code.GET,
                                      uri=href,
                                      observe=0)
        request = coap_client.request(request_msg)
        first_response = yield request.response

        assert not first_response.payload

        while not all_values_emitted():
            payload = yield _next_observation(request)
            data = payload["data"]

            assert payload.get("name") == event_name
            assert "num" in data
            assert "str" in data

            try:
                emitted_idx = next(idx
                                   for idx, item in enumerate(emitted_values)
                                   if item["num"] == data["num"]
                                   and item["str"] == data["str"])

                emitted_values.pop(emitted_idx)
            except StopIteration:
                pass

        request.observation.cancel()
        periodic_set.stop()

    run_test_coroutine(test_coroutine)
示例#21
0
def test_action_clear_invocation(coap_server):
    """Completed Action invocations are removed from the CoAP server after a while."""
    @tornado.gen.coroutine
    def test_coroutine():
        invocation_sleep_secs = 0.1
        assert (invocation_sleep_secs * 1000) > coap_server.action_clear_ms
        response = yield _test_action_invoke(
            coap_server, invocation_sleep=invocation_sleep_secs)
        assert not response.code.is_successful()

    run_test_coroutine(test_coroutine)
示例#22
0
def test_on_event(websocket_server):
    """Events can be observed using Websockets."""

    url_thing_01 = websocket_server.pop("url_thing_01")
    exposed_thing_01 = websocket_server.pop("exposed_thing_01")
    event_name = websocket_server.pop("event_name_01")

    @tornado.gen.coroutine
    def test_coroutine():
        observe_msg_id = Faker().pyint()
        payload_01 = Faker().pydict(10, True, str, float)
        payload_02 = Faker().pydict(10, True, str, float)
        payload_03 = Faker().pydict(10, True, int)

        conn = yield tornado.websocket.websocket_connect(url_thing_01)

        msg_observe_req = WebsocketMessageRequest(
            method=WebsocketMethods.ON_EVENT,
            params={"name": event_name},
            msg_id=observe_msg_id)

        conn.write_message(msg_observe_req.to_json())

        msg_observe_resp_raw = yield conn.read_message()
        msg_observe_resp = WebsocketMessageResponse.from_raw(
            msg_observe_resp_raw)

        assert msg_observe_resp.id == observe_msg_id

        subscription_id = msg_observe_resp.result

        def assert_emitted(the_msg_raw, the_expected_payload):
            msg_emitted = WebsocketMessageEmittedItem.from_raw(the_msg_raw)

            assert msg_emitted.subscription_id == subscription_id
            assert msg_emitted.data == the_expected_payload

        exposed_thing_01.emit_event(event_name, payload_01)

        msg_emitted_raw = yield conn.read_message()
        assert_emitted(msg_emitted_raw, payload_01)

        exposed_thing_01.emit_event(event_name, payload_02)
        exposed_thing_01.emit_event(event_name, payload_03)

        msg_emitted_raw = yield conn.read_message()
        assert_emitted(msg_emitted_raw, payload_02)

        msg_emitted_raw = yield conn.read_message()
        assert_emitted(msg_emitted_raw, payload_03)

        yield conn.close()

    run_test_coroutine(test_coroutine)
示例#23
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)
示例#24
0
def test_write_property(websocket_server):
    """Properties can be updated using Websockets."""

    url_thing_01 = websocket_server.pop("url_thing_01")
    exposed_thing_01 = websocket_server.pop("exposed_thing_01")
    prop_name = websocket_server.pop("prop_name_01")

    @tornado.gen.coroutine
    def test_coroutine():
        conn = yield tornado.websocket.websocket_connect(url_thing_01)

        updated_value = Faker().pystr()
        msg_id = uuid.uuid4().hex

        ws_request = WebsocketMessageRequest(
            method=WebsocketMethods.WRITE_PROPERTY,
            params={
                "name": prop_name,
                "value": updated_value
            },
            msg_id=msg_id)

        value = yield exposed_thing_01.read_property(prop_name)

        assert value != updated_value

        conn.write_message(ws_request.to_json())
        raw_response = yield conn.read_message()
        ws_response = WebsocketMessageResponse.from_raw(raw_response)

        assert ws_response.id == msg_id

        value = yield exposed_thing_01.read_property(prop_name)

        assert value == updated_value

        ws_request_err = WebsocketMessageRequest(
            method=WebsocketMethods.WRITE_PROPERTY,
            params={
                "name": prop_name + Faker().pystr(),
                "value": updated_value
            },
            msg_id=msg_id)

        conn.write_message(ws_request_err.to_json())
        raw_error = yield conn.read_message()
        ws_error = WebsocketMessageError.from_raw(raw_error)

        assert ws_error.code

        yield conn.close()

    run_test_coroutine(test_coroutine)
示例#25
0
def test_read_property(exposed_thing, property_fragment):
    """Properties may be retrieved on ExposedThings."""

    @tornado.gen.coroutine
    def test_coroutine():
        prop_name = Faker().pystr()
        prop_init_value = Faker().sentence()
        exposed_thing.add_property(prop_name, property_fragment, value=prop_init_value)
        value = yield exposed_thing.read_property(prop_name)
        assert value == prop_init_value

    run_test_coroutine(test_coroutine)
示例#26
0
def test_thing_property_get(exposed_thing, property_fragment):
    """Property values can be retrieved on ExposedThings using the map-like interface."""

    @tornado.gen.coroutine
    def test_coroutine():
        prop_name = Faker().pystr()
        prop_init_value = Faker().sentence()
        exposed_thing.add_property(prop_name, property_fragment, value=prop_init_value)
        value = yield exposed_thing.properties[prop_name].read()
        assert value == prop_init_value

    run_test_coroutine(test_coroutine)
示例#27
0
def test_all_protocols_combined(all_protocols_servient):
    """Protocol bindings work as expected when multiple
    servers are combined within the same Servient."""

    exposed_thing = next(all_protocols_servient.exposed_things)
    td = ThingDescription.from_thing(exposed_thing.thing)

    clients = [WebsocketClient(), HTTPClient()]

    if is_coap_supported():
        from wotpy.protocols.coap.client import CoAPClient
        clients.append(CoAPClient())

    if is_mqtt_supported():
        from tests.protocols.mqtt.broker import is_test_broker_online
        from wotpy.protocols.mqtt.client import MQTTClient
        if is_test_broker_online():
            clients.append(MQTTClient())

    prop_name = next(six.iterkeys(td.properties))

    @tornado.gen.coroutine
    def read_property(the_client):
        prop_value = Faker().sentence()

        curr_value = yield the_client.read_property(td, prop_name)
        assert curr_value != prop_value

        yield exposed_thing.properties[prop_name].write(prop_value)

        curr_value = yield the_client.read_property(td, prop_name)
        assert curr_value == prop_value

    @tornado.gen.coroutine
    def write_property(the_client):
        updated_value = Faker().sentence()

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

        yield the_client.write_property(td, prop_name, updated_value)

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

    @tornado.gen.coroutine
    def test_coroutine():
        for client in clients:
            yield read_property(client)
            yield write_property(client)

    run_test_coroutine(test_coroutine)
示例#28
0
def _test_td_change_events(exposed_thing, property_fragment, event_fragment, action_fragment, subscribe_func):
    """Helper function to test subscriptions to TD changes."""

    @tornado.gen.coroutine
    def test_coroutine():
        prop_name = Faker().pystr()
        event_name = Faker().pystr()
        action_name = Faker().pystr()

        complete_futures = {
            (TDChangeType.PROPERTY, TDChangeMethod.ADD): Future(),
            (TDChangeType.PROPERTY, TDChangeMethod.REMOVE): Future(),
            (TDChangeType.EVENT, TDChangeMethod.ADD): Future(),
            (TDChangeType.EVENT, TDChangeMethod.REMOVE): Future(),
            (TDChangeType.ACTION, TDChangeMethod.ADD): Future(),
            (TDChangeType.ACTION, TDChangeMethod.REMOVE): Future()
        }

        def on_next(ev):
            change_type = ev.data.td_change_type
            change_method = ev.data.method
            interaction_name = ev.data.name
            future_key = (change_type, change_method)
            complete_futures[future_key].set_result(interaction_name)

        subscription = subscribe_func(on_next)

        yield tornado.gen.sleep(0)

        exposed_thing.add_event(event_name, event_fragment)

        assert complete_futures[(TDChangeType.EVENT, TDChangeMethod.ADD)].result() == event_name
        assert not complete_futures[(TDChangeType.EVENT, TDChangeMethod.REMOVE)].done()

        exposed_thing.remove_event(name=event_name)
        exposed_thing.add_property(prop_name, property_fragment)

        assert complete_futures[(TDChangeType.EVENT, TDChangeMethod.REMOVE)].result() == event_name
        assert complete_futures[(TDChangeType.PROPERTY, TDChangeMethod.ADD)].result() == prop_name
        assert not complete_futures[(TDChangeType.PROPERTY, TDChangeMethod.REMOVE)].done()

        exposed_thing.remove_property(name=prop_name)
        exposed_thing.add_action(action_name, action_fragment)
        exposed_thing.remove_action(name=action_name)

        assert complete_futures[(TDChangeType.PROPERTY, TDChangeMethod.REMOVE)].result() == prop_name
        assert complete_futures[(TDChangeType.ACTION, TDChangeMethod.ADD)].result() == action_name
        assert complete_futures[(TDChangeType.ACTION, TDChangeMethod.REMOVE)].result() == action_name

        subscription.dispose()

    run_test_coroutine(test_coroutine)
示例#29
0
def test_read_property_unknown(websocket_servient):
    """The Websockets client raises an error when attempting to read an unknown property."""

    exposed_thing = next(websocket_servient.exposed_things)
    td = ThingDescription.from_thing(exposed_thing.thing)

    @tornado.gen.coroutine
    def test_coroutine():
        ws_client = WebsocketClient()

        with pytest.raises(ProtocolClientException):
            yield ws_client.read_property(td, uuid.uuid4().hex)

    run_test_coroutine(test_coroutine)
示例#30
0
def test_thing_not_found(websocket_server):
    """The socket is automatically closed when connecting to an unknown thing."""

    ws_port = websocket_server.pop("ws_port")

    @tornado.gen.coroutine
    def test_coroutine():
        url_unknown = "ws://localhost:{}/{}".format(ws_port, uuid.uuid4().hex)
        conn = yield tornado.websocket.websocket_connect(url_unknown)
        msg = yield conn.read_message()

        assert msg is None

    run_test_coroutine(test_coroutine)