Skip to content

Commit 3bf596f

Browse files
tleacmcsarestyled-commitstcarmelveilleux
authored
Added TC-ACL-2-11 test script (#35163)
Implement the M-ACL / Managed NIM / ARL test plan. The test plan (currently in review form) can be found here: CHIP-Specifications/chip-test-plans#4316 -------- * Added TC-ACL-2-11 test script * Restyled by autopep8 * Restyled by isort * fixed linter issues * review updates * Use network-manager-app for TC_ACL_2_11.py * Fix REPL build commands for network manager * add trace support to network-manager-app --------- Co-authored-by: Restyled.io <commits@restyled.io> Co-authored-by: tennessee.carmelveilleux@gmail.com <tennessee.carmelveilleux@gmail.com>
1 parent fb92e96 commit 3bf596f

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed

.github/workflows/tests.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ jobs:
485485
--target linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test \
486486
--target linux-x64-microwave-oven-ipv6only-no-ble-no-wifi-tsan-clang-test \
487487
--target linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test \
488+
--target linux-x64-network-manager-ipv6only-no-ble-no-wifi-tsan-clang-test \
488489
--target linux-x64-python-bindings \
489490
build \
490491
--copy-artifacts-to objdir-clone \
@@ -498,6 +499,7 @@ jobs:
498499
echo "LIT_ICD_APP: out/linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test/lit-icd-app" >> /tmp/test_env.yaml
499500
echo "CHIP_MICROWAVE_OVEN_APP: out/linux-x64-microwave-oven-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-microwave-oven-app" >> /tmp/test_env.yaml
500501
echo "CHIP_RVC_APP: out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app" >> /tmp/test_env.yaml
502+
echo "NETWORK_MANAGEMENT_APP: out/linux-x64-network-manager-ipv6only-no-ble-no-wifi-tsan-clang-test/matter-network-manager-app" >> /tmp/test_env.yaml
501503
echo "TRACE_APP: out/trace_data/app-{SCRIPT_BASE_NAME}" >> /tmp/test_env.yaml
502504
echo "TRACE_TEST_JSON: out/trace_data/test-{SCRIPT_BASE_NAME}" >> /tmp/test_env.yaml
503505
echo "TRACE_TEST_PERFETTO: out/trace_data/test-{SCRIPT_BASE_NAME}" >> /tmp/test_env.yaml

examples/network-manager-app/linux/args.gni

+2
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ chip_config_network_layer_ble = false
2525

2626
# This enables AccessRestrictionList (ARL) support used by the NIM sample app
2727
chip_enable_access_restrictions = true
28+
29+
matter_enable_tracing_support = true

src/python_testing/TC_ACL_2_11.py

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#
2+
# Copyright (c) 2024 Project CHIP Authors
3+
# All rights reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments
19+
# for details about the block below.
20+
#
21+
# === BEGIN CI TEST ARGUMENTS ===
22+
# test-runner-runs: run1
23+
# test-runner-run/run1/app: ${NETWORK_MANAGEMENT_APP}
24+
# test-runner-run/run1/factoryreset: True
25+
# test-runner-run/run1/quiet: True
26+
# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --commissioning-arl-entries "[{\"endpoint\": 1,\"cluster\": 1105,\"restrictions\": [{\"type\": 0,\"id\": 0}]}]" --arl-entries "[{\"endpoint\": 1,\"cluster\": 1105,\"restrictions\": [{\"type\": 0,\"id\": 0}]}]"
27+
# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto
28+
# === END CI TEST ARGUMENTS ===
29+
30+
import logging
31+
import queue
32+
33+
import chip.clusters as Clusters
34+
from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction
35+
from chip.clusters.ClusterObjects import ALL_ACCEPTED_COMMANDS, ALL_ATTRIBUTES, ALL_CLUSTERS, ClusterEvent
36+
from chip.clusters.Objects import AccessControl
37+
from chip.interaction_model import Status
38+
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
39+
from mobly import asserts
40+
41+
42+
class EventChangeCallback:
43+
def __init__(self, expected_event: ClusterEvent, output: queue.Queue):
44+
self._output = output
45+
self._expected_cluster_id = expected_event.cluster_id
46+
self._expected_event_id = expected_event.event_id
47+
48+
def __call__(self, res: EventReadResult, transaction: SubscriptionTransaction):
49+
if res.Status == Status.Success and res.Header.ClusterId == self._expected_cluster_id and res.Header.EventId == self._expected_event_id:
50+
logging.info(
51+
f'Got subscription report for event {self._expected_event_id} on cluster {self._expected_cluster_id}: {res.Data}')
52+
self._output.put(res)
53+
54+
55+
def WaitForEventReport(q: queue.Queue, expected_event: ClusterEvent):
56+
try:
57+
res = q.get(block=True, timeout=10)
58+
except queue.Empty:
59+
asserts.fail("Failed to receive a report for the event {}".format(expected_event))
60+
61+
asserts.assert_equal(res.Header.ClusterId, expected_event.cluster_id, "Expected cluster ID not found in event report")
62+
asserts.assert_equal(res.Header.EventId, expected_event.event_id, "Expected event ID not found in event report")
63+
64+
65+
class TC_ACL_2_11(MatterBaseTest):
66+
67+
def desc_TC_ACL_2_11(self) -> str:
68+
return "[TC-ACL-2.11] Verification of Managed Device feature"
69+
70+
def steps_TC_ACL_2_11(self) -> list[TestStep]:
71+
steps = [
72+
TestStep(1, "Commissioning, already done"),
73+
TestStep(2, "TH1 reads DUT Endpoint 0 AccessControl cluster CommissioningARL attribute"),
74+
TestStep(3, "TH1 reads DUT Endpoint 0 AccessControl cluster ARL attribute"),
75+
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.",
76+
"If the restriction is Type AttributeAccessForbidden, read the restriction's attribute ID and verify the response is UNSUPPORTED_ACCESS."
77+
"If the restriction is Type AttributeWriteForbidden, write restriction's the attribute ID and verify the response is UNSUPPORTED_ACCESS."
78+
"If the restriction is Type CommandForbidden, invoke the restriction's command ID and verify the response is UNSUPPORTED_ACCESS."),
79+
TestStep(5, "TH1 sends DUT Endpoint 0 AccessControl cluster command ReviewFabricRestrictions"),
80+
TestStep(6, "Wait for up to 1 hour. Follow instructions provided by device maker to remove all access restrictions",
81+
"AccessRestrictionReviewUpdate event is received"),
82+
TestStep(7, "TH1 reads DUT Endpoint 0 AccessControl cluster ARL attribute", "ARL is empty")
83+
]
84+
return steps
85+
86+
@async_test_body
87+
async def test_TC_ACL_2_11(self):
88+
self.step(1)
89+
self.step(2)
90+
await self.read_single_attribute_check_success(
91+
endpoint=0,
92+
cluster=Clusters.AccessControl,
93+
attribute=Clusters.AccessControl.Attributes.CommissioningARL
94+
)
95+
self.step(3)
96+
arl = await self.read_single_attribute_check_success(
97+
endpoint=0,
98+
cluster=Clusters.AccessControl,
99+
attribute=Clusters.AccessControl.Attributes.Arl
100+
)
101+
self.step(4)
102+
103+
care_struct = None
104+
105+
for arl_entry in arl:
106+
E1 = arl_entry.endpoint
107+
C1 = arl_entry.cluster
108+
R1 = arl_entry.restrictions
109+
110+
care_struct = Clusters.AccessControl.Structs.AccessRestrictionEntryStruct(E1, C1, R1)
111+
112+
cluster = ALL_CLUSTERS[C1]
113+
114+
for restriction in R1:
115+
restriction_type = restriction.type
116+
ID1 = restriction.id
117+
118+
attribute = ALL_ATTRIBUTES[C1][ID1]
119+
command = ALL_ACCEPTED_COMMANDS[C1][ID1]
120+
121+
if restriction_type == AccessControl.Enums.AccessRestrictionTypeEnum.kAttributeAccessForbidden:
122+
await self.read_single_attribute_expect_error(cluster=cluster, attribute=attribute, error=Status.UnsupportedAccess, endpoint=E1)
123+
elif restriction_type == AccessControl.Enums.AccessRestrictionTypeEnum.kAttributeWriteForbidden:
124+
status = await self.write_single_attribute(attribute_value=attribute, endpoint_id=E1)
125+
asserts.assert_equal(status, Status.UnsupportedAccess,
126+
f"Failed to verify UNSUPPORTED_ACCESS when writing to Attribute {ID1} Cluster {C1} Endpoint {E1}")
127+
elif restriction_type == AccessControl.Enums.AccessRestrictionTypeEnum.kCommandForbidden:
128+
result = await self.send_single_cmd(cmd=command, endpoint=E1)
129+
asserts.assert_equal(result.status, Status.UnsupportedAccess,
130+
f"Failed to verify UNSUPPORTED_ACCESS when sending command {ID1} to Cluster {C1} Endpoint {E1}")
131+
132+
# Belongs to step 6, but needs to be subscribed before executing step 5: begin
133+
arru_queue = queue.Queue()
134+
arru_cb = EventChangeCallback(Clusters.AccessControl.Events.FabricRestrictionReviewUpdate, arru_queue)
135+
136+
urgent = 1
137+
subscription_arru = await self.default_controller.ReadEvent(nodeid=self.dut_node_id, events=[(0, Clusters.AccessControl.Events.FabricRestrictionReviewUpdate, urgent)], reportInterval=(1, 5), keepSubscriptions=True, autoResubscribe=False)
138+
subscription_arru.SetEventUpdateCallback(callback=arru_cb)
139+
# end
140+
141+
# Belongs to step 7, but needs to be subscribed before executing step 5: begin
142+
arec_queue = queue.Queue()
143+
arec_cb = EventChangeCallback(Clusters.AccessControl.Events.AccessRestrictionEntryChanged, arec_queue)
144+
145+
urgent = 1
146+
subscription_arec = await self.default_controller.ReadEvent(nodeid=self.dut_node_id, events=[(0, Clusters.AccessControl.Events.AccessRestrictionEntryChanged, urgent)], reportInterval=(1, 5), keepSubscriptions=True, autoResubscribe=False)
147+
subscription_arec.SetEventUpdateCallback(callback=arec_cb)
148+
# end
149+
150+
self.step(5)
151+
response = await self.send_single_cmd(cmd=Clusters.AccessControl.Commands.ReviewFabricRestrictions([care_struct]), endpoint=0)
152+
asserts.assert_true(isinstance(response, Clusters.AccessControl.Commands.ReviewFabricRestrictionsResponse),
153+
"Result is not of type ReviewFabricRestrictionsResponse")
154+
155+
self.step(6)
156+
logging.info("Please follow instructions provided by the product maker to remove all ARL entries")
157+
WaitForEventReport(arru_queue, Clusters.AccessControl.Events.FabricRestrictionReviewUpdate)
158+
159+
self.step(7)
160+
cluster = Clusters.AccessControl
161+
attribute = Clusters.AccessControl.Attributes.Arl
162+
arl = await self.read_single_attribute_check_success(
163+
node_id=self.dut_node_id,
164+
endpoint=0,
165+
cluster=cluster,
166+
attribute=attribute
167+
)
168+
asserts.assert_equal(arl, [], "Unexpected Arl; Not empty")
169+
170+
171+
if __name__ == "__main__":
172+
default_matter_test_main()

0 commit comments

Comments
 (0)