Skip to content

Commit d1ec1ac

Browse files
authored
extract matter testing utilities to separate module (#37309)
* extract utilities to separate module and mark them in original module as deprecated * update build file to include utilities * Use UserWarning instead of DeprecationWarning; Add type hint decorators for IDE hover visibility * lint code * fix incorrect signatures and return values * adding missing alias and docstrings to utility methods * fix alias issue * just update all the places where moved functiones are used * remove commented out code * using direct aliases as requested in review * solit utilities to less general modules * isort * rename types.py to matchers.py * rename type_matches to is_type * added docstrings and copyright to packages * style fix * isort * point test_testing imports to original module for now * add doctest for new modules * this should fix build error, doctests will run when the module is imported anyway * import modules as modules only; add ToDo to remove aliases in future * fix imports
1 parent 2bd5aa3 commit d1ec1ac

23 files changed

+426
-141
lines changed

src/python_testing/TC_DA_1_2.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
import chip.clusters as Clusters
4444
from chip.interaction_model import InteractionModelError, Status
4545
from chip.testing.basic_composition import BasicCompositionTests
46-
from chip.testing.matter_testing import (MatterBaseTest, TestStep, async_test_body, default_matter_test_main, hex_from_bytes,
47-
type_matches)
46+
from chip.testing.conversions import hex_from_bytes
47+
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches
4848
from chip.tlv import TLVReader
4949
from cryptography import x509
5050
from cryptography.exceptions import InvalidSignature

src/python_testing/TC_DA_1_5.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
import chip.clusters as Clusters
4141
from chip import ChipDeviceCtrl
4242
from chip.interaction_model import InteractionModelError, Status
43-
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, hex_from_bytes, type_matches
43+
from chip.testing.conversions import hex_from_bytes
44+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, type_matches
4445
from chip.tlv import TLVReader
4546
from cryptography import x509
4647
from cryptography.hazmat.primitives import hashes

src/python_testing/TC_DA_1_7.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
from typing import List, Optional
4242

4343
import chip.clusters as Clusters
44-
from chip.testing.matter_testing import (MatterBaseTest, TestStep, async_test_body, bytes_from_hex, default_matter_test_main,
45-
hex_from_bytes)
44+
from chip.testing.conversions import bytes_from_hex, hex_from_bytes
45+
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
4646
from cryptography.exceptions import InvalidSignature
4747
from cryptography.hazmat.primitives import hashes
4848
from cryptography.hazmat.primitives.asymmetric import ec

src/python_testing/TC_DEMTestBase.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import chip.clusters as Clusters
2121
from chip.interaction_model import InteractionModelError, Status
22-
from chip.testing.matter_testing import utc_time_in_matter_epoch
22+
from chip.testing.timeoperations import utc_time_in_matter_epoch
2323
from mobly import asserts
2424

2525
logger = logging.getLogger(__name__)

src/python_testing/TC_DGGEN_2_4.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@
4040
import chip.clusters as Clusters
4141
from chip.clusters.Types import NullValue
4242
from chip.interaction_model import InteractionModelError
43-
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, default_matter_test_main,
44-
matter_epoch_us_from_utc_datetime, utc_datetime_from_matter_epoch_us,
45-
utc_datetime_from_posix_time_ms)
43+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
44+
from chip.testing.timeoperations import utc_datetime_from_matter_epoch_us, utc_datetime_from_posix_time_ms, utc_time_in_matter_epoch
4645
from mobly import asserts
4746

4847
logger = logging.getLogger(__name__)
@@ -104,7 +103,7 @@ async def test_TC_DGGEN_2_4(self):
104103

105104
self.print_step("1b", "Write current time to DUT")
106105
# Get current time in the correct format to set via command.
107-
th_utc = matter_epoch_us_from_utc_datetime(desired_datetime=None)
106+
th_utc = utc_time_in_matter_epoch(desired_datetime=None)
108107

109108
await self.set_time_in_timesync(th_utc)
110109

src/python_testing/TC_TIMESYNC_2_1.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
import chip.clusters as Clusters
4343
from chip.clusters.Types import NullValue
4444
from chip.testing.matter_testing import (MatterBaseTest, default_matter_test_main, has_attribute, has_cluster,
45-
run_if_endpoint_matches, utc_time_in_matter_epoch)
45+
run_if_endpoint_matches)
46+
from chip.testing.timeoperations import utc_time_in_matter_epoch
4647
from mobly import asserts
4748

4849

src/python_testing/TC_TIMESYNC_2_10.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,12 @@
4343
import chip.clusters as Clusters
4444
from chip.clusters.Types import NullValue
4545
from chip.interaction_model import InteractionModelError
46-
from chip.testing.matter_testing import (MatterBaseTest, SimpleEventCallback, async_test_body, default_matter_test_main,
47-
utc_time_in_matter_epoch)
46+
from chip.testing.matter_testing import MatterBaseTest, SimpleEventCallback, async_test_body, default_matter_test_main
47+
from chip.testing.timeoperations import get_wait_seconds_from_set_time, utc_time_in_matter_epoch
4848
from chip.tlv import uint
4949
from mobly import asserts
5050

5151

52-
def get_wait_seconds_from_set_time(set_time_matter_us: int, wait_seconds: int):
53-
seconds_passed = int((utc_time_in_matter_epoch() - set_time_matter_us)/1000000)
54-
return wait_seconds - seconds_passed
55-
56-
5752
class TC_TIMESYNC_2_10(MatterBaseTest):
5853
async def send_set_time_zone_cmd(self, tz: typing.List[Clusters.Objects.TimeSynchronization.Structs.TimeZoneStruct]) -> Clusters.Objects.TimeSynchronization.Commands.SetTimeZoneResponse:
5954
ret = await self.send_single_cmd(cmd=Clusters.Objects.TimeSynchronization.Commands.SetTimeZone(timeZone=tz), endpoint=self.endpoint)

src/python_testing/TC_TIMESYNC_2_11.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
import chip.clusters as Clusters
4444
from chip.clusters.Types import NullValue
4545
from chip.interaction_model import InteractionModelError
46-
from chip.testing.matter_testing import (MatterBaseTest, SimpleEventCallback, async_test_body, default_matter_test_main,
47-
get_wait_seconds_from_set_time, type_matches, utc_time_in_matter_epoch)
46+
from chip.testing.matter_testing import MatterBaseTest, SimpleEventCallback, async_test_body, default_matter_test_main, type_matches
47+
from chip.testing.timeoperations import get_wait_seconds_from_set_time, utc_time_in_matter_epoch
4848
from chip.tlv import uint
4949
from mobly import asserts
5050

src/python_testing/TC_TIMESYNC_2_12.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
import chip.clusters as Clusters
4444
from chip.clusters.Types import NullValue
4545
from chip.interaction_model import InteractionModelError
46-
from chip.testing.matter_testing import (MatterBaseTest, SimpleEventCallback, async_test_body, default_matter_test_main,
47-
get_wait_seconds_from_set_time, type_matches, utc_time_in_matter_epoch)
46+
from chip.testing.matter_testing import MatterBaseTest, SimpleEventCallback, async_test_body, default_matter_test_main, type_matches
47+
from chip.testing.timeoperations import get_wait_seconds_from_set_time, utc_time_in_matter_epoch
4848
from chip.tlv import uint
4949
from mobly import asserts
5050

src/python_testing/TC_TIMESYNC_2_2.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040
import chip.clusters as Clusters
4141
from chip.clusters.Types import NullValue
4242
from chip.interaction_model import InteractionModelError
43-
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main,
44-
utc_time_in_matter_epoch)
43+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
44+
from chip.testing.timeoperations import compare_time, utc_time_in_matter_epoch
4545
from mobly import asserts
4646

4747

src/python_testing/TC_TIMESYNC_2_4.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040

4141
import chip.clusters as Clusters
4242
from chip.interaction_model import InteractionModelError, Status
43-
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, default_matter_test_main, type_matches,
44-
utc_time_in_matter_epoch)
43+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, type_matches
44+
from chip.testing.timeoperations import utc_time_in_matter_epoch
4545
from mobly import asserts
4646

4747

src/python_testing/TC_TIMESYNC_2_5.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
import chip.clusters as Clusters
4141
from chip.clusters.Types import NullValue
4242
from chip.interaction_model import InteractionModelError, Status
43-
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, utc_time_in_matter_epoch
43+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
44+
from chip.testing.timeoperations import utc_time_in_matter_epoch
4445
from mobly import asserts
4546

4647

src/python_testing/TC_TIMESYNC_2_7.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
import chip.clusters as Clusters
4343
from chip.clusters.Types import NullValue
4444
from chip.interaction_model import InteractionModelError
45-
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main, type_matches,
46-
utc_time_in_matter_epoch)
45+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, type_matches
46+
from chip.testing.timeoperations import compare_time, utc_time_in_matter_epoch
4747
from chip.tlv import uint
4848
from mobly import asserts
4949

src/python_testing/TC_TIMESYNC_2_8.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
import chip.clusters as Clusters
4343
from chip.clusters.Types import NullValue
4444
from chip.interaction_model import InteractionModelError
45-
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main, type_matches,
46-
utc_time_in_matter_epoch)
45+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, type_matches
46+
from chip.testing.timeoperations import compare_time, utc_time_in_matter_epoch
4747
from chip.tlv import uint
4848
from mobly import asserts
4949

src/python_testing/TC_TIMESYNC_2_9.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
import chip.clusters as Clusters
4242
from chip.clusters.Types import NullValue
4343
from chip.interaction_model import InteractionModelError
44-
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main, type_matches,
45-
utc_time_in_matter_epoch)
44+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, type_matches
45+
from chip.testing.timeoperations import compare_time, utc_time_in_matter_epoch
4646
from chip.tlv import uint
4747
from mobly import asserts
4848

src/python_testing/TC_VALCC_4_4.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
import chip.clusters as Clusters
3838
from chip.clusters.Types import NullValue
3939
from chip.interaction_model import InteractionModelError, Status
40-
from chip.testing.matter_testing import (MatterBaseTest, TestStep, async_test_body, default_matter_test_main,
41-
utc_time_in_matter_epoch)
40+
from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
41+
from chip.testing.timeoperations import utc_time_in_matter_epoch
4242
from mobly import asserts
4343

4444

src/python_testing/TestCommissioningTimeSync.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
from chip import ChipDeviceCtrl
2121
from chip.clusters.Types import NullValue
2222
from chip.interaction_model import InteractionModelError, Status
23-
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main, utc_time_in_matter_epoch
23+
from chip.testing.matter_testing import MatterBaseTest, async_test_body, default_matter_test_main
24+
from chip.testing.timeoperations import utc_time_in_matter_epoch
2425
from mobly import asserts
2526

2627
# We don't have a good pipe between the c++ enums in CommissioningDelegate and python

src/python_testing/TestMatterTestingSupport.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222

2323
import chip.clusters as Clusters
2424
from chip.clusters.Types import Nullable, NullValue
25-
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main,
26-
get_wait_seconds_from_set_time, parse_matter_test_args, type_matches,
27-
utc_time_in_matter_epoch)
25+
from chip.testing.matter_testing import (MatterBaseTest, async_test_body, default_matter_test_main, parse_matter_test_args,
26+
type_matches)
2827
from chip.testing.pics import parse_pics, parse_pics_xml
2928
from chip.testing.taglist_and_topology_test import (TagProblem, create_device_type_list_for_root, create_device_type_lists,
3029
find_tag_list_problems, find_tree_roots, flat_list_ok, get_all_children,
3130
get_direct_children_of_root, parts_list_cycles, separate_endpoint_types)
31+
from chip.testing.timeoperations import compare_time, get_wait_seconds_from_set_time, utc_time_in_matter_epoch
3232
from chip.tlv import uint
3333
from mobly import asserts, signals
3434

src/python_testing/matter_testing_infrastructure/BUILD.gn

+3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ pw_python_package("chip-testing-module") {
3939
"chip/testing/basic_composition.py",
4040
"chip/testing/choice_conformance.py",
4141
"chip/testing/conformance.py",
42+
"chip/testing/conversions.py",
4243
"chip/testing/global_attribute_ids.py",
44+
"chip/testing/matchers.py",
4345
"chip/testing/matter_asserts.py",
4446
"chip/testing/matter_testing.py",
4547
"chip/testing/metadata.py",
@@ -48,6 +50,7 @@ pw_python_package("chip-testing-module") {
4850
"chip/testing/spec_parsing.py",
4951
"chip/testing/taglist_and_topology_test.py",
5052
"chip/testing/tasks.py",
53+
"chip/testing/timeoperations.py",
5154
]
5255
tests = [
5356
"chip/testing/test_metadata.py",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#
2+
# Copyright (c) 2025 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+
"""Conversion utilities for Matter testing infrastructure.
19+
20+
This module provides utility functions for converting between different data
21+
representations commonly used in Matter testing.
22+
"""
23+
24+
from binascii import hexlify, unhexlify
25+
26+
import chip.clusters as Clusters
27+
28+
29+
def bytes_from_hex(hex: str) -> bytes:
30+
""" Converts hex string to bytes, handling various formats (colons, spaces, newlines).
31+
32+
Examples:
33+
>>> bytes_from_hex("01:ab:cd")
34+
b'\\x01\\xab\\xcd'
35+
>>> bytes_from_hex("01 ab cd")
36+
b'\\x01\\xab\\xcd'
37+
>>> bytes_from_hex("01abcd")
38+
b'\\x01\\xab\\xcd'
39+
>>> bytes_from_hex("01\\nab\\ncd")
40+
b'\\x01\\xab\\xcd'
41+
"""
42+
return unhexlify("".join(hex.replace(":", "").replace(" ", "").split()))
43+
44+
45+
def hex_from_bytes(b: bytes) -> str:
46+
""" Converts a bytes object to a hexadecimal string.
47+
48+
This function performs the inverse operation of bytes_from_hex(). It converts
49+
a bytes object into a continuous hexadecimal string without any separators.
50+
51+
Args:
52+
b: bytes, the bytes object to convert to hexadecimal
53+
54+
Returns:
55+
str: A string containing the hexadecimal representation of the bytes,
56+
using lowercase letters a-f for hex digits
57+
58+
Examples:
59+
>>> hex_from_bytes(b'\\x01\\xab\\xcd')
60+
'01abcd'
61+
>>> hex_from_bytes(bytes([1, 171, 205])) # Same bytes, different notation
62+
'01abcd'
63+
"""
64+
return hexlify(b).decode("utf-8")
65+
66+
67+
def format_decimal_and_hex(number):
68+
""" Formats a number showing both decimal and hexadecimal representations.
69+
70+
Creates a string representation of a number showing both its decimal value
71+
and its hex representation in parentheses.
72+
73+
Args:
74+
number: int, the number to format
75+
76+
Returns:
77+
str: A formatted string like "123 (0x7b)"
78+
79+
Examples:
80+
>>> format_decimal_and_hex(123)
81+
'123 (0x7b)'
82+
>>> format_decimal_and_hex(0)
83+
'0 (0x00)'
84+
>>> format_decimal_and_hex(255)
85+
'255 (0xff)'
86+
"""
87+
return f'{number} (0x{number:02x})'
88+
89+
90+
def cluster_id_with_name(id):
91+
""" Formats a Matter cluster ID with its name and numeric representation.
92+
93+
Uses format_decimal_and_hex() for numeric formatting and looks up cluster name from registry.
94+
Falls back to "Unknown cluster" if ID not recognized.
95+
96+
Args:
97+
id: int, the Matter cluster identifier
98+
99+
Returns:
100+
str: A formatted string containing the ID and cluster name
101+
102+
Examples:
103+
>>> cluster_id_with_name(6) # OnOff cluster
104+
'6 (0x06) OnOff'
105+
>>> cluster_id_with_name(999999) # Unknown cluster
106+
'999999 (0xf423f) Unknown cluster'
107+
>>> cluster_id_with_name("invalid") # Invalid input
108+
'HERE IS THE PROBLEM'
109+
"""
110+
if id in Clusters.ClusterObjects.ALL_CLUSTERS.keys():
111+
s = Clusters.ClusterObjects.ALL_CLUSTERS[id].__name__
112+
else:
113+
s = "Unknown cluster"
114+
try:
115+
return f'{format_decimal_and_hex(id)} {s}'
116+
except (TypeError, ValueError):
117+
return 'HERE IS THE PROBLEM'
118+
119+
120+
if __name__ == "__main__":
121+
import doctest
122+
doctest.testmod()

0 commit comments

Comments
 (0)