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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
def test_ssl_context(self_signed_ssl_context): """An SSL context can be passed to the WebSockets server to enable encryption.""" exposed_thing = ExposedThing(servient=Servient(), thing=Thing(id=uuid.uuid4().urn)) prop_name = uuid.uuid4().hex exposed_thing.add_property(prop_name, PropertyFragmentDict({ "type": "string", "observable": True }), value=Faker().pystr()) port = find_free_port() server = WebsocketServer(port=port, ssl_context=self_signed_ssl_context) server.add_exposed_thing(exposed_thing) @tornado.gen.coroutine def test_coroutine(): yield server.start() ws_url = build_websocket_url(exposed_thing, server, port) assert WebsocketSchemes.WSS in ws_url with pytest.raises(ssl.SSLError): http_req = tornado.httpclient.HTTPRequest(ws_url, method="GET") yield tornado.websocket.websocket_connect(http_req) http_req = tornado.httpclient.HTTPRequest(ws_url, method="GET", validate_cert=False) conn = yield tornado.websocket.websocket_connect(http_req) request_id = Faker().pyint() msg_req = WebsocketMessageRequest( method=WebsocketMethods.READ_PROPERTY, params={"name": prop_name}, msg_id=request_id) conn.write_message(msg_req.to_json()) msg_resp_raw = yield conn.read_message() msg_resp = WebsocketMessageResponse.from_raw(msg_resp_raw) assert msg_resp.id == request_id value = yield exposed_thing.read_property(prop_name) assert value == msg_resp.result yield conn.close() yield server.stop() run_test_coroutine(test_coroutine)
def 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)
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)
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)
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)
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)
def test_discovery_method_multicast_dnssd(): """Things can be discovered usin the multicast method supported by DNS-SD.""" catalogue_port_01 = find_free_port() catalogue_port_02 = find_free_port() instance_name_01 = "servient-01-{}".format(Faker().pystr()) instance_name_02 = "servient-02-{}".format(Faker().pystr()) servient_01 = Servient(catalogue_port=catalogue_port_01, dnssd_enabled=True, dnssd_instance_name=instance_name_01) servient_02 = Servient(catalogue_port=catalogue_port_02, dnssd_enabled=True, dnssd_instance_name=instance_name_02) future_done, found = tornado.concurrent.Future(), [] def resolve(): len(found) == 2 and not future_done.done() and future_done.set_result( True) @tornado.gen.coroutine def test_coroutine(): wot_01 = yield servient_01.start() wot_02 = yield servient_02.start() wot_01.produce(ThingFragment(TD_DICT_01)).expose() wot_01.produce(ThingFragment(TD_DICT_02)).expose() thing_filter = ThingFilterDict(method=DiscoveryMethod.MULTICAST) observable = wot_02.discover(thing_filter, dnssd_find_kwargs={ "min_results": 1, "timeout": 5 }) subscription = observable.subscribe( on_next=lambda td_str: found.append(ThingDescription(td_str) ) or resolve()) yield future_done assert_equal_td_sequences(found, [TD_DICT_01, TD_DICT_02]) subscription.dispose() yield servient_01.shutdown() yield servient_02.shutdown() run_test_coroutine(test_coroutine)
def test_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)
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)
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)
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)
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)
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)
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)