|
23 | 23 | import chip.clusters.ClusterObjects
|
24 | 24 | import chip.tlv
|
25 | 25 | from basic_composition_support import BasicCompositionTests
|
| 26 | +from chip import ChipUtility |
26 | 27 | from chip.clusters.Attribute import ValueDecodeFailure
|
| 28 | +from chip.clusters.ClusterObjects import ClusterAttributeDescriptor, ClusterObjectFieldDescriptor |
| 29 | +from chip.interaction_model import InteractionModelError, Status |
| 30 | +from chip.tlv import uint |
27 | 31 | from global_attribute_ids import GlobalAttributeIds
|
28 | 32 | from matter_testing_support import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, MatterBaseTest,
|
29 | 33 | async_test_body, default_matter_test_main)
|
|
32 | 36 | find_tree_roots, get_all_children, get_direct_children_of_root, parts_list_cycles,
|
33 | 37 | separate_endpoint_types)
|
34 | 38 |
|
| 39 | +# The above code is importing various classes from the "ClusterObjects" module and assigning them to |
| 40 | +# variables. These classes are likely used for creating and managing clusters of objects in a program. |
| 41 | + |
35 | 42 |
|
36 | 43 | def check_int_in_range(min_value: int, max_value: int, allow_null: bool = False) -> Callable:
|
37 | 44 | """Returns a checker for whether `obj` is an int that fits in a range."""
|
@@ -165,7 +172,43 @@ def test_TC_DT_1_1(self):
|
165 | 172 | if not success:
|
166 | 173 | self.fail_current_test("At least one endpoint was missing the descriptor cluster.")
|
167 | 174 |
|
168 |
| - def test_TC_IDM_10_1(self): |
| 175 | + async def _read_non_standard_attribute_check_unsupported_read(self, endpoint_id, cluster_id, attribute_id) -> bool: |
| 176 | + @dataclass |
| 177 | + class TempAttribute(ClusterAttributeDescriptor): |
| 178 | + @ChipUtility.classproperty |
| 179 | + def cluster_id(cls) -> int: |
| 180 | + return cluster_id |
| 181 | + |
| 182 | + @ChipUtility.classproperty |
| 183 | + def attribute_id(cls) -> int: |
| 184 | + return attribute_id |
| 185 | + |
| 186 | + @ChipUtility.classproperty |
| 187 | + def attribute_type(cls) -> ClusterObjectFieldDescriptor: |
| 188 | + return ClusterObjectFieldDescriptor(Type=uint) |
| 189 | + |
| 190 | + @ChipUtility.classproperty |
| 191 | + def standard_attribute(cls) -> bool: |
| 192 | + return False |
| 193 | + |
| 194 | + value: 'uint' = 0 |
| 195 | + |
| 196 | + result = await self.default_controller.Read(nodeid=self.dut_node_id, attributes=[(endpoint_id, TempAttribute)]) |
| 197 | + try: |
| 198 | + attr_ret = result.tlvAttributes[endpoint_id][cluster_id][attribute_id] |
| 199 | + except KeyError: |
| 200 | + attr_ret = None |
| 201 | + |
| 202 | + print(attr_ret) |
| 203 | + |
| 204 | + error_type_ok = attr_ret is not None and isinstance( |
| 205 | + attr_ret, Clusters.Attribute.ValueDecodeFailure) and isinstance(attr_ret.Reason, InteractionModelError) |
| 206 | + |
| 207 | + got_expected_error = error_type_ok and attr_ret.Reason.status == Status.UnsupportedRead |
| 208 | + return got_expected_error |
| 209 | + |
| 210 | + @async_test_body |
| 211 | + async def test_TC_IDM_10_1(self): |
169 | 212 | self.print_step(1, "Perform a wildcard read of attributes on all endpoints - already done")
|
170 | 213 |
|
171 | 214 | @dataclass
|
@@ -236,15 +279,19 @@ class RequiredMandatoryAttribute:
|
236 | 279 | logging.debug(
|
237 | 280 | f"Checking presence of claimed supported {attribute_string} on {location.as_cluster_string(self.cluster_mapper)}: {'found' if has_attribute else 'not_found'}")
|
238 | 281 |
|
239 |
| - # Check attribute is actually present. |
240 | 282 | if not has_attribute:
|
241 |
| - # TODO: Handle detecting write-only attributes from schema. |
242 |
| - if "WriteOnly" in attribute_string: |
243 |
| - continue |
244 |
| - |
245 |
| - self.record_error(self.get_test_name(), location=location, |
246 |
| - problem=f"Did not find {attribute_string} on {location.as_cluster_string(self.cluster_mapper)} when it was claimed in AttributeList ({attribute_list})", spec_location="AttributeList Attribute") |
247 |
| - success = False |
| 283 | + # Check if this is a write-only attribute by trying to read it. |
| 284 | + # If it's present and write-only it should return an UNSUPPORTED_READ error. All other errors are a failure. |
| 285 | + # Because these can be MEI attributes, we need to build the ClusterAttributeDescriptor manually since it's |
| 286 | + # not guaranteed to be generated. Since we expect an error back anyway, the type doesn't matter. |
| 287 | + |
| 288 | + write_only_attribute = await self._read_non_standard_attribute_check_unsupported_read( |
| 289 | + endpoint_id=endpoint_id, cluster_id=cluster_id, attribute_id=attribute_id) |
| 290 | + |
| 291 | + if not write_only_attribute: |
| 292 | + self.record_error(self.get_test_name(), location=location, |
| 293 | + problem=f"Did not find {attribute_string} on {location.as_cluster_string(self.cluster_mapper)} when it was claimed in AttributeList ({attribute_list})", spec_location="AttributeList Attribute") |
| 294 | + success = False |
248 | 295 | continue
|
249 | 296 |
|
250 | 297 | attribute_value = cluster[attribute_id]
|
|
0 commit comments