Skip to content

Commit 17b1a38

Browse files
authored
MACL: Add checks that ARL / CommissioningARL are populated or not populated as required by the test (project-chip#35413)
* Add check for unpopulated ARLs * linter * Add check to TC-ACL-2.11 for populated ARLs
1 parent 58ed63d commit 17b1a38

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
lines changed

src/python_testing/TC_ACL_2_11.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import queue
3232

3333
import chip.clusters as Clusters
34+
from basic_composition_support import arls_populated
3435
from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction, ValueDecodeFailure
3536
from chip.clusters.ClusterObjects import ALL_ACCEPTED_COMMANDS, ALL_ATTRIBUTES, ALL_CLUSTERS, ClusterEvent
3637
from chip.clusters.Objects import AccessControl
@@ -82,7 +83,7 @@ def desc_TC_ACL_2_11(self) -> str:
8283

8384
def steps_TC_ACL_2_11(self) -> list[TestStep]:
8485
steps = [
85-
TestStep(1, "Commissioning, already done"),
86+
TestStep(1, "Commissioning (already done) and precondition checks", is_commissioning=True),
8687
TestStep(2, "TH1 reads DUT Endpoint 0 AccessControl cluster CommissioningARL attribute"),
8788
TestStep(3, "TH1 reads DUT Endpoint 0 AccessControl cluster ARL attribute"),
8889
TestStep(4, "For each entry in ARL, iterate over each restriction and attempt access the restriction's ID on the Endpoint and Cluster in the ARL entry.",
@@ -102,6 +103,14 @@ async def test_TC_ACL_2_11(self):
102103
dev_ctrl = self.default_controller
103104
dut_node_id = self.dut_node_id
104105
self.step(1)
106+
107+
wildcard_read = (await dev_ctrl.Read(self.dut_node_id, [()]))
108+
has_arl, has_carl = arls_populated(wildcard_read.tlvAttributes)
109+
asserts.assert_true(
110+
has_arl, "ARL attribute must contain at least one restriction to run this test. Please follow manufacturer-specific steps to add access restrictions and re-run this test")
111+
asserts.assert_true(
112+
has_carl, "CommissioningARL attribute must contain at least one restriction to run this test. Please follow manufacturer-specific steps to add access restrictions and re-run this test")
113+
105114
self.step(2)
106115
await self.read_single_attribute_check_success(
107116
endpoint=0,

src/python_testing/TestConformanceTest.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from typing import Any
1919

2020
import chip.clusters as Clusters
21+
from basic_composition_support import arls_populated
2122
from conformance_support import ConformanceDecision
2223
from global_attribute_ids import GlobalAttributeIds
2324
from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
@@ -191,7 +192,7 @@ def _create_minimal_dt(self, device_type_id: int) -> dict[int, dict[int, Any]]:
191192
endpoint_tlv[Clusters.Descriptor.id] = attrs
192193
return endpoint_tlv
193194

194-
def add_macl(self, root_endpoint: dict[int, dict[int, Any]]):
195+
def add_macl(self, root_endpoint: dict[int, dict[int, Any]], populate_arl: bool = False, populate_commissioning_arl: bool = False):
195196
ac = Clusters.AccessControl
196197
root_endpoint[ac.id][ac.Attributes.FeatureMap.attribute_id] = ac.Bitmaps.Feature.kManagedDevice
197198
root_endpoint[ac.id][ac.Attributes.Arl.attribute_id] = []
@@ -202,6 +203,14 @@ def add_macl(self, root_endpoint: dict[int, dict[int, Any]]):
202203
root_endpoint[ac.id][ac.Attributes.GeneratedCommandList.attribute_id].append(
203204
ac.Commands.ReviewFabricRestrictionsResponse.command_id)
204205

206+
generic_restriction = ac.Structs.AccessRestrictionStruct(
207+
type=ac.Enums.AccessRestrictionTypeEnum.kAttributeAccessForbidden, id=1)
208+
entry = ac.Structs.CommissioningAccessRestrictionEntryStruct(endpoint=1, cluster=2, restrictions=generic_restriction)
209+
if populate_arl:
210+
root_endpoint[ac.id][ac.Attributes.Arl.attribute_id] = [entry]
211+
if populate_commissioning_arl:
212+
root_endpoint[ac.id][ac.Attributes.CommissioningARL.attribute_id] = [entry]
213+
205214
@async_test_body
206215
async def test_macl_handling(self):
207216
nim_id = self._get_device_type_id('network infrastructure manager')
@@ -231,6 +240,45 @@ async def test_macl_handling(self):
231240

232241
# TODO: what happens if there is a NIM and a non-NIM endpoint?
233242

243+
@async_test_body
244+
async def test_macl_restrictions(self):
245+
246+
nim_id = self._get_device_type_id('network infrastructure manager')
247+
root_node_id = self._get_device_type_id('root node')
248+
249+
root = self._create_minimal_dt(device_type_id=root_node_id)
250+
nim = self._create_minimal_dt(device_type_id=nim_id)
251+
self.endpoints_tlv = {0: root, 1: nim}
252+
253+
# device with no macl
254+
have_arl, have_carl = arls_populated(self.endpoints_tlv)
255+
asserts.assert_false(have_arl, "Unexpected ARL found")
256+
asserts.assert_false(have_carl, "Unexpected CommissioningARL found")
257+
258+
# device with unpopulated macl
259+
self.add_macl(root)
260+
have_arl, have_carl = arls_populated(self.endpoints_tlv)
261+
asserts.assert_false(have_arl, "Unexpected ARL found")
262+
asserts.assert_false(have_carl, "Unexpected CommissioningARL found")
263+
264+
# device with populated ARL
265+
self.add_macl(root, populate_arl=True)
266+
have_arl, have_carl = arls_populated(self.endpoints_tlv)
267+
asserts.assert_true(have_arl, "Did not find expected ARL")
268+
asserts.assert_false(have_carl, "Unexpected CommissioningARL found")
269+
270+
# device with populated commissioning ARL
271+
self.add_macl(root, populate_commissioning_arl=True)
272+
have_arl, have_carl = arls_populated(self.endpoints_tlv)
273+
asserts.assert_false(have_arl, "Unexpected ARL found")
274+
asserts.assert_true(have_carl, "Did not find expected Commissioning ARL")
275+
276+
# device with both
277+
self.add_macl(root, populate_arl=True, populate_commissioning_arl=True)
278+
have_arl, have_carl = arls_populated(self.endpoints_tlv)
279+
asserts.assert_true(have_arl, "Did not find expected ARL")
280+
asserts.assert_true(have_carl, "Did not find expected Commissioning ARL")
281+
234282

235283
if __name__ == "__main__":
236284
default_matter_test_main()

src/python_testing/basic_composition_support.py

+24
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,30 @@
2626
from pprint import pformat, pprint
2727
from typing import Any, Optional
2828

29+
import chip.clusters as Clusters
2930
import chip.clusters.ClusterObjects
3031
import chip.tlv
3132
from chip.clusters.Attribute import ValueDecodeFailure
3233
from mobly import asserts
3334

3435

36+
def arls_populated(tlv_data: dict[int, Any]) -> tuple[bool, bool]:
37+
""" Returns a tuple indicating if the ARL and CommissioningARL are populated.
38+
Requires a wildcard read of the device TLV.
39+
"""
40+
# ACL is always on endpoint 0
41+
if 0 not in tlv_data or Clusters.AccessControl.id not in tlv_data[0]:
42+
return (False, False)
43+
# Both attributes are mandatory for this feature, so if one doesn't exist, neither should the other.
44+
if Clusters.AccessControl.Attributes.Arl.attribute_id not in tlv_data[0][Clusters.AccessControl.id][Clusters.AccessControl.Attributes.AttributeList.attribute_id]:
45+
return (False, False)
46+
47+
have_arl = tlv_data[0][Clusters.AccessControl.id][Clusters.AccessControl.Attributes.Arl.attribute_id]
48+
have_carl = tlv_data[0][Clusters.AccessControl.id][Clusters.AccessControl.Attributes.CommissioningARL.attribute_id]
49+
50+
return (have_arl, have_carl)
51+
52+
3553
def MatterTlvToJson(tlv_data: dict[int, Any]) -> dict[str, Any]:
3654
"""Given TLV data for a specific cluster instance, convert to the Matter JSON format."""
3755

@@ -169,6 +187,12 @@ async def setup_class_helper(self, allow_pase: bool = True):
169187
logging.info("Start of actual tests")
170188
logging.info("###########################################################")
171189

190+
have_arl, have_carl = arls_populated(self.endpoints_tlv)
191+
asserts.assert_false(
192+
have_arl, "ARL cannot be populated for this test - Please follow manufacturer-specific steps to remove the access restrictions and re-run this test")
193+
asserts.assert_false(
194+
have_carl, "CommissioningARL cannot be populated for this test - Please follow manufacturer-specific steps to remove the access restrictions and re-run this test")
195+
172196
def get_test_name(self) -> str:
173197
"""Return the function name of the caller. Used to create logging entries."""
174198
return sys._getframe().f_back.f_code.co_name

0 commit comments

Comments
 (0)