Skip to content

Commit 0d543c1

Browse files
continue
1 parent 6a7af1b commit 0d543c1

File tree

2 files changed

+314
-4
lines changed

2 files changed

+314
-4
lines changed

src/python_testing/TC_SC_4_3.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -295,15 +295,26 @@ async def test_TC_SC_4_3(self):
295295
self.step(9)
296296

297297
# Check MCORE.COM PICS
298-
is_eth_or_wifi = self.check_pics('MCORE.COM.WIFI') or self.check_pics('MCORE.COM.ETH')
298+
mc_wifi = 'MCORE.COM.WIFI'
299+
mc_eth = 'MCORE.COM.ETH'
300+
mc_thr = 'MCORE.COM.THR'
301+
302+
303+
## wildcard read of cnet clusters, featuremaps all endpoints, does it support wifi/thread?
304+
305+
is_mc_wifi = self.check_pics(mc_wifi)
306+
is_mc_eth = self.check_pics(mc_eth)
307+
is_thr = self.check_pics(mc_thr)
308+
is_eth_or_wifi = is_mc_wifi or is_mc_eth
309+
299310
if is_eth_or_wifi:
311+
mcore_com = mc_wifi if is_mc_wifi else mc_eth if is_mc_eth else None
300312
asserts.assert_true(self.verify_hostname(hostname=server, char_length=12),
301-
f"Hostname for '{server}' is not a 12-character uppercase hexadecimal string")
313+
f"Hostname for '{server}' is not a 12-character uppercase hexadecimal string for PICS {mcore_com}")
302314
else:
303-
is_thr = self.check_pics('MCORE.COM.THR')
304315
if is_thr:
305316
asserts.assert_true(self.verify_hostname(hostname=server, char_length=16),
306-
f"Hostname for '{server}' is not a 16-character uppercase hexadecimal string")
317+
f"Hostname for '{server}' is not a 16-character uppercase hexadecimal string for PICS {mc_thr}")
307318

308319
# ICD TXT KEY
309320
if supports_lit:

src/python_testing/any_test.py

+299
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
#
2+
# Copyright (c) 2023 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: ${ALL_CLUSTERS_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
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 copy
31+
import logging
32+
import time
33+
34+
import chip.clusters as Clusters
35+
from chip.ChipDeviceCtrl import ChipDeviceController
36+
from chip.clusters import ClusterObjects as ClusterObjects
37+
from chip.clusters.Attribute import AttributePath, TypedAttributePath, AsyncReadTransaction
38+
from chip.exceptions import ChipStackError
39+
from chip.interaction_model import Status
40+
from matter_testing_support import AttributeChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main
41+
from mobly import asserts
42+
43+
from chip.clusters import Attribute
44+
from global_attribute_ids import GlobalAttributeIds
45+
46+
47+
import chip.clusters as Clusters
48+
import chip.logging
49+
import chip.native
50+
from chip import discovery
51+
from chip.ChipStack import ChipStack
52+
from chip.clusters import Attribute
53+
from chip.clusters import ClusterObjects as ClusterObjects
54+
from chip.clusters.Attribute import EventReadResult, SubscriptionTransaction, TypedAttributePath
55+
from chip.exceptions import ChipStackError
56+
from chip.interaction_model import InteractionModelError, Status
57+
from chip.setup_payload import SetupPayload
58+
from chip.storage import PersistentStorage
59+
from chip.tracing import TracingContext
60+
from global_attribute_ids import GlobalAttributeIds
61+
from mobly import asserts, base_test, signals, utils
62+
from mobly.config_parser import ENV_MOBLY_LOGPATH, TestRunConfig
63+
from mobly.test_runner import TestRunner
64+
from pics_support import read_pics_from_file
65+
66+
67+
from chip import ChipDeviceCtrl # Needed before chip.FabricAdmin
68+
import chip.FabricAdmin # Needed before chip.CertificateAuthority
69+
import chip.CertificateAuthority
70+
from chip.ChipDeviceCtrl import CommissioningParameters
71+
72+
import pprint
73+
74+
'''
75+
Category:
76+
Functional
77+
78+
Description:
79+
Validates Interaction Data Model (IDM), specifically subscription responses. Some example of tests run:
80+
- Subscriptions with varying MaxIntervalCeiling
81+
- Checks for `InvalidAction` results when subscribing to clusters and attributes without access rights
82+
- Checks that subscription is not established for invalid MinIntervalFloor
83+
- Validates that only correctly filtered data is received when a subscription is established
84+
85+
Full test plan link for details:
86+
https://github.com/CHIP-Specifications/chip-test-plans/blob/master/src/interactiondatamodel.adoc#tc-idm-4-2-subscription-response-messages-from-dut-test-cases-dut_server
87+
'''
88+
89+
90+
class any_test(MatterBaseTest):
91+
92+
def stringify_keys(self, d):
93+
"""Recursively converts keys in the dictionary to string format."""
94+
if isinstance(d, dict):
95+
return {str(key): self.stringify_keys(value) for key, value in d.items()}
96+
elif isinstance(d, list):
97+
return [self.stringify_keys(item) for item in d]
98+
else:
99+
return d
100+
101+
def pretty_print_unconventional_json(self, data):
102+
"""Pretty prints the unconventional JSON-like structure."""
103+
processed_data = self.stringify_keys(data)
104+
print('\n\n\n')
105+
pprint.pprint(processed_data, indent=64, width=100)
106+
print('\n\n\n')
107+
108+
def steps_any_test(self):
109+
return [TestStep(0, "Some action", "Some check") ]
110+
111+
ROOT_NODE_ENDPOINT_ID = 0
112+
113+
async def get_descriptor_server_list(self, ctrl, ep=ROOT_NODE_ENDPOINT_ID):
114+
return await self.read_single_attribute_check_success(
115+
endpoint=ep,
116+
dev_ctrl=ctrl,
117+
cluster=Clusters.Descriptor,
118+
attribute=Clusters.Descriptor.Attributes.ServerList
119+
)
120+
121+
async def get_descriptor_parts_list(self, ctrl, ep=ROOT_NODE_ENDPOINT_ID):
122+
return await self.read_single_attribute_check_success(
123+
endpoint=ep,
124+
dev_ctrl=ctrl,
125+
cluster=Clusters.Descriptor,
126+
attribute=Clusters.Descriptor.Attributes.PartsList
127+
)
128+
129+
async def get_idle_mode_duration_sec(self, ctrl, ep=ROOT_NODE_ENDPOINT_ID):
130+
return await self.read_single_attribute_check_success(
131+
endpoint=ep,
132+
dev_ctrl=ctrl,
133+
cluster=Clusters.IcdManagement,
134+
attribute=Clusters.IcdManagement.Attributes.IdleModeDuration
135+
)
136+
137+
@staticmethod
138+
def verify_attribute_exists(sub, cluster, attribute, ep=ROOT_NODE_ENDPOINT_ID):
139+
sub_attrs = sub
140+
if isinstance(sub, Clusters.Attribute.SubscriptionTransaction):
141+
sub_attrs = sub.GetAttributes()
142+
143+
asserts.assert_true(ep in sub_attrs, "Must have read endpoint %s data" % ep)
144+
asserts.assert_true(cluster in sub_attrs[ep], "Must have read %s cluster data" % cluster.__name__)
145+
asserts.assert_true(attribute in sub_attrs[ep][cluster],
146+
"Must have read back attribute %s" % attribute.__name__)
147+
148+
@staticmethod
149+
def get_typed_attribute_path(attribute, ep=ROOT_NODE_ENDPOINT_ID):
150+
return TypedAttributePath(
151+
Path=AttributePath.from_attribute(
152+
EndpointId=ep,
153+
Attribute=attribute
154+
)
155+
)
156+
157+
async def write_dut_acl(self, ctrl, acl, ep=ROOT_NODE_ENDPOINT_ID):
158+
result = await ctrl.WriteAttribute(self.dut_node_id, [(ep, Clusters.AccessControl.Attributes.Acl(acl))])
159+
asserts.assert_equal(result[ep].Status, Status.Success, "ACL write failed")
160+
161+
async def get_dut_acl(self, ctrl, ep=ROOT_NODE_ENDPOINT_ID):
162+
sub = await ctrl.ReadAttribute(
163+
nodeid=self.dut_node_id,
164+
attributes=[(ep, Clusters.AccessControl.Attributes.Acl)],
165+
keepSubscriptions=False,
166+
fabricFiltered=True
167+
)
168+
169+
acl_list = sub[ep][Clusters.AccessControl][Clusters.AccessControl.Attributes.Acl]
170+
171+
return acl_list
172+
173+
async def add_ace_to_dut_acl(self, ctrl, ace, dut_acl_original):
174+
dut_acl = copy.deepcopy(dut_acl_original)
175+
dut_acl.append(ace)
176+
await self.write_dut_acl(ctrl=ctrl, acl=dut_acl)
177+
178+
@staticmethod
179+
def is_valid_uint32_value(var):
180+
return isinstance(var, int) and 0 <= var <= 0xFFFFFFFF
181+
182+
@staticmethod
183+
def is_valid_uint16_value(var):
184+
return isinstance(var, int) and 0 <= var <= 0xFFFF
185+
186+
@async_test_body
187+
async def test_any_test(self):
188+
189+
# Test setup
190+
cluster_rev_attr = Clusters.BasicInformation.Attributes.ClusterRevision
191+
cluster_rev_attr_typed_path = self.get_typed_attribute_path(cluster_rev_attr)
192+
node_label_attr = Clusters.BasicInformation.Attributes.NodeLabel
193+
node_label_attr_path = [(0, node_label_attr)]
194+
subscription_max_interval_publisher_limit_sec = 0
195+
INVALID_ACTION_ERROR_CODE = 0x580
196+
197+
# Controller 1 setup
198+
# Subscriber/client with admin access to the DUT
199+
# Will write ACL for controller 2 and validate success/error codes
200+
CR1: ChipDeviceController = self.default_controller
201+
202+
# Original DUT ACL used for reseting the ACL on some steps
203+
dut_acl_original = await self.get_dut_acl(CR1)
204+
205+
# Controller 2 setup
206+
# Subscriber/client with limited access to the DUT
207+
# Will validate error status codes
208+
fabric_admin = self.certificate_authority_manager.activeCaList[0].adminList[0]
209+
CR2_nodeid = self.matter_test_config.controller_node_id + 1
210+
CR2: ChipDeviceController = fabric_admin.NewController(
211+
nodeId=CR2_nodeid,
212+
paaTrustStorePath=str(self.matter_test_config.paa_trust_store_path),
213+
)
214+
215+
# *** Step 0 ***
216+
# CR1 reads the ServerList attribute from the Descriptor cluster on EP0. If the ICDManagement cluster ID
217+
# (70,0x46) is present, set SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT_SEC = IdleModeDuration and
218+
# min_interval_floor_s to 0, otherwise, set SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT_SEC = 60 mins and
219+
# min_interval_floor_s to 3.
220+
self.step(0)
221+
222+
223+
224+
225+
226+
227+
228+
229+
230+
231+
232+
233+
234+
235+
236+
237+
238+
239+
240+
241+
attributes = [
242+
# (Clusters.Descriptor),
243+
# (Clusters.NetworkCommissioning.Attributes.FeatureMap),
244+
(Clusters.NetworkCommissioning),
245+
# Attribute.AttributePath(None, None, GlobalAttributeIds.ATTRIBUTE_LIST_ID),
246+
# Attribute.AttributePath(None, None, GlobalAttributeIds.FEATURE_MAP_ID),
247+
# Attribute.AttributePath(None, None, GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID),
248+
]
249+
250+
wildcard: AsyncReadTransaction.ReadResponse = await CR1.Read(
251+
nodeid=self.dut_node_id,
252+
attributes=attributes
253+
)
254+
255+
maps = str(wildcard.attributes.keys().mapping)
256+
self.pretty_print_unconventional_json(maps)
257+
258+
259+
260+
261+
262+
263+
264+
265+
266+
267+
268+
269+
270+
271+
272+
273+
274+
275+
# # Reads the ServerList attribute
276+
# ep0_servers = await self.get_descriptor_server_list(CR1)
277+
278+
# # Check if ep0_servers contains the ICD Management cluster ID (0x0046)
279+
# if Clusters.IcdManagement.id in ep0_servers:
280+
# # Read the IdleModeDuration attribute value from the DUT
281+
# logging.info(
282+
# "CR1 reads from the DUT the IdleModeDuration attribute and sets SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT_SEC = IdleModeDuration")
283+
284+
# idleModeDuration = await self.get_idle_mode_duration_sec(CR1)
285+
# subscription_max_interval_publisher_limit_sec = idleModeDuration
286+
# min_interval_floor_sec = 0
287+
# else:
288+
# # Defaulting SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT_SEC to 60 minutes
289+
# subscription_max_interval_publisher_limit_sec = 60 * 60
290+
# min_interval_floor_sec = 3
291+
292+
# asserts.assert_greater_equal(subscription_max_interval_publisher_limit_sec, 1,
293+
# "SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT_SEC must be at least 1")
294+
295+
# logging.info(
296+
# f"Set SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT_SEC to {subscription_max_interval_publisher_limit_sec} seconds")
297+
298+
if __name__ == "__main__":
299+
default_matter_test_main()

0 commit comments

Comments
 (0)