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_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()
def __init__(self, doc): """Constructor. Validates that the document conforms to the TD schema.""" self._doc = json.loads(doc) if isinstance(doc, (six.string_types, bytes)) else doc self._thing_fragment = ThingFragment(self._doc) self.validate(doc=self._thing_fragment.to_dict())
def test_discovery_fragment(): """The Thing filter fragment attribute enables discovering Things by matching TD fields.""" servient = Servient(dnssd_enabled=False) wot = WoT(servient=servient) wot.produce(ThingFragment(TD_DICT_01)) wot.produce(ThingFragment(TD_DICT_02)) def first(thing_filter): """Returns the first TD discovery for the given Thing filter.""" future_done, found = tornado.concurrent.Future(), [] def resolve(): not future_done.done() and future_done.set_result(True) @tornado.gen.coroutine def discover_first(): observable = wot.discover(thing_filter) subscription = observable.subscribe( on_next=lambda td_str: found.append(ThingDescription(td_str) ) or resolve()) yield future_done subscription.dispose() assert len(found) raise tornado.gen.Return(found[0]) return tornado.ioloop.IOLoop.current().run_sync( discover_first, timeout=TIMEOUT_DISCOVER) fragment_td_pairs = [({ "name": TD_DICT_01.get("name") }, TD_DICT_01), ({ "version": { "instance": "2.0.0" } }, TD_DICT_02), ({ "id": TD_DICT_02.get("id") }, TD_DICT_02), ({ "security": [{ "scheme": "psk" }] }, TD_DICT_01)] for fragment, td_expected in fragment_td_pairs: td_found = first( ThingFilterDict(method=DiscoveryMethod.LOCAL, fragment=fragment)) assert_equal_tds(td_found, td_expected)
def __init__(self, thing_fragment=None, **kwargs): self._thing_fragment = thing_fragment if thing_fragment else ThingFragment( **kwargs) self._properties = {} self._actions = {} self._events = {} self._init_fragment_interactions()
def test_thing_fragment(): """Thing fragment dictionaries can be represented and serialized.""" thing_fragment = ThingFragment(THING_INIT) assert thing_fragment.id == THING_INIT["id"] assert thing_fragment.title == THING_INIT["title"] assert thing_fragment.description == THING_INIT["description"] assert isinstance(next(six.itervalues(thing_fragment.properties)), PropertyFragmentDict) assert isinstance(next(six.itervalues(thing_fragment.actions)), ActionFragmentDict) assert isinstance(next(six.itervalues(thing_fragment.events)), EventFragmentDict) assert json.dumps(thing_fragment.to_dict()) assert next(six.itervalues(thing_fragment.to_dict()["properties"]))["type"] assert thing_fragment.version.instance == THING_INIT["version"]["instance"] with pytest.raises(Exception): ThingFragment({})
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()
def test_produce_model_thing_template(): """Things can be produced from ThingTemplate instances.""" thing_id = Faker().url() thing_name = Faker().sentence() thing_template = ThingFragment({"id": thing_id, "name": thing_name}) servient = Servient() wot = WoT(servient=servient) exp_thing = wot.produce(thing_template) assert servient.get_exposed_thing(thing_id) assert exp_thing.id == thing_id assert exp_thing.name == thing_name
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
def thing_fragment(self): """The ThingFragment dictionary of this Thing.""" def interaction_to_json(intrct): """Returns the JSON serialization of an Interaction instance.""" ret = intrct.interaction_fragment.to_dict() ret.update({ "forms": [form.form_dict.to_dict() for form in intrct.forms] }) return ret doc = self._thing_fragment.to_dict() doc.update({ "properties": { key: interaction_to_json(val) for key, val in six.iteritems(self.properties) } }) doc.update({ "actions": { key: interaction_to_json(val) for key, val in six.iteritems(self.actions) } }) doc.update({ "events": { key: interaction_to_json(val) for key, val in six.iteritems(self.events) } }) return ThingFragment(doc)
class ThingDescription(object): """Class that represents a Thing Description document. Contains logic to validate and transform a Thing to a serialized TD and vice versa.""" def __init__(self, doc): """Constructor. Validates that the document conforms to the TD schema.""" self._doc = json.loads(doc) if isinstance(doc, (six.string_types, bytes)) else doc self._thing_fragment = ThingFragment(self._doc) self.validate(doc=self._thing_fragment.to_dict()) @classmethod def validate(cls, doc): """Validates the given Thing Description document against its schema. Raises ValidationError if validation fails.""" try: jsonschema.validate(doc, SCHEMA_THING) except (jsonschema.ValidationError, TypeError) as ex: raise InvalidDescription(str(ex)) @classmethod def from_thing(cls, thing): """Builds an instance of a JSON-serialized Thing Description from a Thing object.""" return ThingDescription(thing.thing_fragment.to_dict()) def __getattr__(self, name): """Search for members that raised an AttributeError in the internal ThingFragment before propagating the exception.""" return getattr(self._thing_fragment, name) def to_dict(self): """Returns the JSON Thing Description as a dict.""" return self._thing_fragment.to_dict() def to_str(self): """Returns the JSON Thing Description as a string.""" return json.dumps(self._thing_fragment.to_dict()) def to_thing_fragment(self): """Returns a ThingFragment dictionary built from this TD.""" return self._thing_fragment def build_thing(self): """Builds a new Thing object from the serialized Thing Description.""" return Thing(thing_fragment=self.to_thing_fragment()) def get_forms(self, name): """Returns a list of FormDict for the interaction that matches the given name.""" if name in self.properties: return self.get_property_forms(name) if name in self.actions: return self.get_action_forms(name) if name in self.events: return self.get_event_forms(name) return [] def get_property_forms(self, name): """Returns a list of FormDict for the property that matches the given name.""" return self.properties[name].forms def get_action_forms(self, name): """Returns a list of FormDict for the action that matches the given name.""" return self.actions[name].forms def get_event_forms(self, name): """Returns a list of FormDict for the event that matches the given name.""" return self.events[name].forms