Skip to content

Commit

Permalink
chore: change behavior of duplicate checking for object_id
Browse files Browse the repository at this point in the history
178 error on duplicate object
  • Loading branch information
djs0109 authored May 21, 2024
2 parents 5e11553 + eaeb20b commit 84a4fe6
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
### v0.4.2
- update: allow duplicated name in device, check uniqueness of object_id ([#279](https://github.com/RWTH-EBC/FiLiP/pull/279))
- add: validation for JEXL based expression ([#260](https://github.com/RWTH-EBC/FiLiP/pull/260))
- add: tutorials for multi-entity ([#260](https://github.com/RWTH-EBC/FiLiP/pull/260))
- add: add ``update_entity_relationships`` to allow relationship update ([#271](https://github.com/RWTH-EBC/FiLiP/pull/271))
Expand Down
43 changes: 42 additions & 1 deletion filip/models/ngsi_v2/iot.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,46 @@ def validate_device_attributes_expression(self):

return self

@model_validator(mode='after')
def validate_duplicated_device_attributes(self):
"""
Check whether device has identical attributes
Args:
self: dict of Device instance.
Returns:
The dict of Device instance after validation.
"""
for i, attr in enumerate(self.attributes):
for other_attr in self.attributes[:i] + self.attributes[i + 1:]:
if attr.model_dump() == other_attr.model_dump():
raise ValueError(f"Duplicated attributes found: {attr.name}")
return self

@model_validator(mode='after')
def validate_device_attributes_name_object_id(self):
"""
Validate the device regarding the behavior with devices attributes.
According to https://iotagent-node-lib.readthedocs.io/en/latest/api.html and
based on our best practice, following rules are checked
- name is required, but not necessarily unique
- object_id is not required, if given must be unique, i.e. not equal to any
existing object_id and name
Args:
self: dict of Device instance.
Returns:
The dict of Device instance after validation.
"""
for i, attr in enumerate(self.attributes):
for other_attr in self.attributes[:i] + self.attributes[i + 1:]:
if attr.object_id and other_attr.object_id and \
attr.object_id == other_attr.object_id:
raise ValueError(f"object_id {attr.object_id} is not unique")
if attr.object_id and attr.object_id == other_attr.name:
raise ValueError(f"object_id {attr.object_id} is not unique")
return self

def get_attribute(self, attribute_name: str) -> Union[DeviceAttribute,
LazyDeviceAttribute,
StaticDeviceAttribute,
Expand Down Expand Up @@ -479,7 +519,8 @@ def add_attribute(self,
"""
try:
if type(attribute) == DeviceAttribute:
if attribute in self.attributes:
if attribute.model_dump(exclude_none=True) in \
[attr.model_dump(exclude_none=True) for attr in self.attributes]:
raise ValueError

self.attributes.append(attribute)
Expand Down
136 changes: 136 additions & 0 deletions tests/models/test_ngsi_v2_iot.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,142 @@ def test_expression_language(self):

assert len(w) == 2

def test_add_device_attributes(self):
"""
Test the device model regarding the behavior with devices attributes.
According to https://iotagent-node-lib.readthedocs.io/en/latest/api.html and
based on our best practice, following rules are checked
- name is required, but not necessarily unique
- object_id is not required, if given must be unique, i.e. not equal to any
existing object_id and name
"""
def initial_device():
attr = DeviceAttribute(
name="temperature",
type="Number"
)
return Device(
device_id="dummy:01",
entity_name="entity:01",
entity_type="MyEntity",
attributes=[attr]
)

# fail, because attr1 and attr ara identical
device_a = initial_device()
attr1 = DeviceAttribute(
name="temperature",
type="Number"
)
with self.assertRaises(ValueError):
device_a.add_attribute(attribute=attr1)

# fail, because the object_id is duplicated with the name of attr1
device_b = initial_device()
attr2 = DeviceAttribute(
name="temperature",
type="Number",
object_id="temperature"
)
with self.assertRaises(ValueError):
device_b.add_attribute(attribute=attr2)

# success
device_c = initial_device()
attr3 = DeviceAttribute(
name="temperature",
type="Number",
object_id="t1"
)
device_c.add_attribute(attribute=attr3)
# success
attr4 = DeviceAttribute(
name="temperature",
type="Number",
object_id="t2"
)
device_c.add_attribute(attribute=attr4)
# fail, because object id is duplicated
attr5 = DeviceAttribute(
name="temperature2",
type="Number",
object_id="t2"
)
with self.assertRaises(ValueError):
device_c.add_attribute(attribute=attr5)

def test_device_creation(self):
"""
Test the device model regarding the behavior with devices attributes while
creating the devices.
According to https://iotagent-node-lib.readthedocs.io/en/latest/api.html and
based on our best practice, following rules are checked
- name is required, but not necessarily unique
- object_id is not required, if given must be unique, i.e. not equal to any
existing object_id and name
"""

def create_device(attr1_name, attr2_name,
attr1_object_id=None, attr2_object_id=None):
_attr1 = DeviceAttribute(
name=attr1_name,
object_id=attr1_object_id,
type="Number"
)
_attr2 = DeviceAttribute(
name=attr2_name,
object_id=attr2_object_id,
type="Number"
)
return Device(
device_id="dummy:01",
entity_name="entity:01",
entity_type="MyEntity",
attributes=[_attr1, _attr2]
)

# fail, because attr1 and attr ara identical
with self.assertRaises(ValueError):
create_device(
attr1_name="temperature",
attr2_name="temperature",
attr1_object_id=None,
attr2_object_id=None
)

# fail, because the object_id is duplicated with the name of attr1
with self.assertRaises(ValueError):
create_device(
attr1_name="temperature",
attr2_name="temperature",
attr1_object_id=None,
attr2_object_id="temperature"
)

# success
device = create_device(
attr1_name="temperature",
attr2_name="temperature",
attr1_object_id=None,
attr2_object_id="t1"
)
# success
attr4 = DeviceAttribute(
name="temperature",
type="Number",
object_id="t2"
)
device.add_attribute(attribute=attr4)

# fail, because object id is duplicated
with self.assertRaises(ValueError):
create_device(
attr1_name="temperature2",
attr2_name="temperature",
attr1_object_id="t",
attr2_object_id="t"
)

def tearDown(self) -> None:
"""
Cleanup test server
Expand Down

0 comments on commit 84a4fe6

Please sign in to comment.