From 883072d66a614f3351ffbce72cf1243f39fb81f5 Mon Sep 17 00:00:00 2001 From: pcoleman Date: Tue, 16 Jul 2024 09:44:06 +0100 Subject: [PATCH 01/16] Add water heater mode cluster test scripts --- src/python_testing/TC_EWATERHTRM_1_2.py | 109 ++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/python_testing/TC_EWATERHTRM_1_2.py diff --git a/src/python_testing/TC_EWATERHTRM_1_2.py b/src/python_testing/TC_EWATERHTRM_1_2.py new file mode 100644 index 00000000000000..90c50dc1e40819 --- /dev/null +++ b/src/python_testing/TC_EWATERHTRM_1_2.py @@ -0,0 +1,109 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + +import logging + +import chip.clusters as Clusters +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_EWATERHTRM_1_2(MatterBaseTest): + + async def read_mod_attribute_expect_success(self, endpoint, attribute): + cluster = Clusters.Objects.WaterHeaterMode + return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) + + def desc_TC_EWATERHTRM_1_2(self) -> str: + return "[TC-EWATERHTRM-1.2] Cluster attributes with DUT as Server" + + def steps_TC_EWATERHTRM_1_2(self) -> list[TestStep]: + steps = [ + TestStep(1, "Commissioning, already done", is_commissioning=True), + TestStep(2, "Read the SupportedModes attribute"), + TestStep(3, "Read the CurrentMode attribute"), + ] + return steps + + def pics_TC_EWATERHTRM_1_2(self) -> list[str]: + pics = [ + "EWATERHTRM.S", + ] + return pics + + @async_test_body + async def test_TC_EWATERHTRM_1_2(self): + + endpoint = self.user_params.get("endpoint", 1) + + attributes = Clusters.WaterHeaterMode.Attributes + + self.step(1) + + self.step(2) + supported_modes = await self.read_mod_attribute_expect_success(endpoint=endpoint, attribute=attributes.SupportedModes) + asserts.assert_greater_equal(len(supported_modes), 2, "SupportedModes must have at least 2 entries!") + asserts.assert_less_equal(len(supported_modes), 255, "SupportedModes must have at most 255 entries!") + modes = set([m.mode for m in supported_modes]) + asserts.assert_equal(len(modes), len(supported_modes), "SupportedModes must have unique mode values") + + labels = set([m.label for m in supported_modes]) + asserts.assert_equal(len(labels), len(supported_modes), "SupportedModes must have unique mode label values") + + # common mode tags + commonTags = {0x0: 'Off', + 0x1: 'Manual', + 0x2: 'Timed'} + + # derived cluster defined tags + # kUnknownEnumValue may not be defined + try: + derivedTags = [tag.value for tag in Clusters.WaterHeaterMode.Enums.ModeTag + if tag is not Clusters.WaterHeaterMode.Enums.ModeTag.kUnknownEnumValue] + except AttributeError: + derivedTags = Clusters.WaterHeaterMode.Enums.ModeTag + + logging.info("Derived tags: %s" % derivedTags) + + for m in supported_modes: + for t in m.modeTags: + is_mfg = (0x8000 <= t.value and t.value <= 0xBFFF) + asserts.assert_true(t.value in commonTags.keys() or t.value in derivedTags or is_mfg, + "Found a SupportedModes entry with invalid mode tag value!") + if t.value == Clusters.WaterHeaterMode.Enums.ModeTag.kOff: + off_present = True + logging.info("Found normal mode tag %s with tag value %s", m.mode, t.value) + + asserts.assert_true(off_present, "SupportedModes does not have an entry of Off(0x4000)") + + self.step(3) + current_mode = await self.read_mod_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentMode) + logging.info("CurrentMode: %s" % current_mode) + asserts.assert_true(current_mode in modes, "CurrentMode is not a supported mode!") + + +if __name__ == "__main__": + default_matter_test_main() From 512501512808b656b48c73d83037ab098682920c Mon Sep 17 00:00:00 2001 From: pcoleman Date: Mon, 22 Jul 2024 13:23:12 +0100 Subject: [PATCH 02/16] Add TC_EWATERHTRM_2_1.py --- src/python_testing/TC_EWATERHTRM_2_1.py | 162 ++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/python_testing/TC_EWATERHTRM_2_1.py diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py new file mode 100644 index 00000000000000..8e902aad662d67 --- /dev/null +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -0,0 +1,162 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${WATER_HEATER_MANAGEMENT_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + +import logging +from time import sleep + +import chip.clusters as Clusters +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches +from chip.interaction_model import Status +from mobly import asserts + + +class TC_EWATERHTRM_2_1(MatterBaseTest): + + def __init__(self, *args): + super().__init__(*args) + self.endpoint = 0 + self.mode_ok = 0 + self.mode_fail = 0 + + def steps_TC_EWATERHTRM_2_1(self) -> list[TestStep]: + steps = [ + TestStep(1, "Commissioning, already done", is_commissioning=True), + TestStep(2, "Read the SupportedModes attribute"), + TestStep(3, "Read the CurrentMode attribute"), + TestStep(4, "Send ChangeToMode command with NewMode"), + TestStep(5, "Manually put the device in a state from which it will FAIL to transition"), + TestStep(6, "Read CurrentMode attribute"), + TestStep(7, "Send ChangeToMode command with NewMode"), + TestStep(8, "Read CurrentMode attribute"), + TestStep(9, "Manually put the device in a state from which it will SUCCESSFULLY transition"), + TestStep(10, "Read CurrentMode attribute"), + TestStep(11, "Send ChangeToMode command with NewMode"), + TestStep(12, "Read CurrentMode attribute"), + TestStep(13, "Send ChangeToMode command with NewMode set to an invalid mode"), + TestStep(14, "Read CurrentMode attribute"), + ] + return steps + + async def read_mod_attribute_expect_success(self, endpoint, attribute): + cluster = Clusters.Objects.WaterHeaterMode + return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) + + async def send_change_to_mode_cmd(self, newMode) -> Clusters.Objects.WaterHeaterMode.Commands.ChangeToModeResponse: + ret = await self.send_single_cmd(cmd=Clusters.Objects.WaterHeaterMode.Commands.ChangeToMode(newMode=newMode), endpoint=self.endpoint) + asserts.assert_true(type_matches(ret, Clusters.Objects.WaterHeaterMode.Commands.ChangeToModeResponse), + "Unexpected return type for Water Heater Mode ChangeToMode") + return ret + + def pics_TC_EWATERHTRM_2_1(self) -> list[str]: + return ["EWATERHTRM.S"] + + @async_test_body + async def test_TC_EWATERHTRM_2_1(self): + + ModeOff = 0 + ModeManual = 1 + ModeTimed = 2 + + self.endpoint = self.matter_test_config.endpoint + + attributes = Clusters.WaterHeaterMode.Attributes + + self.step(1) + + self.step(2) + + supported_modes = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.SupportedModes) + + logging.info(f"SupportedModes: {supported_modes}") + + asserts.assert_greater_equal(len(supported_modes), 2, "SupportedModes must have at least two entries!") + + modes = [m.mode for m in supported_modes] + + self.step(3) + + old_current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + + logging.info(f"CurrentMode: {old_current_mode}") + + # pick a value that's not on the list of supported modes + invalid_mode = max(modes) + 1 + + self.step(4) + + ret = await self.send_change_to_mode_cmd(newMode=old_current_mode) + logging.info(f"ret.status {ret.status}") + asserts.assert_true(ret.status == Status.Success, "Changing the mode to the current mode should be a no-op") + + # Steps 5-9 are not performed as EWATERHTRM.S.M.CAN_TEST_MODE_FAILURE is false + self.step(5) + self.step(6) + self.step(7) + self.step(8) + self.step(9) + + self.step(10) + + old_current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + + logging.info(f"CurrentMode: {old_current_mode}") + + self.step(11) + + ret = await self.send_change_to_mode_cmd(newMode=ModeManual) + asserts.assert_true(ret.status == Status.Success, + f"Changing to mode {ModeManual}must succeed due to the current state of the device") + + self.step(12) + + current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + + logging.info(f"CurrentMode: {current_mode}") + + asserts.assert_true(current_mode == ModeManual, + "CurrentMode doesn't match the argument of the successful ChangeToMode command!") + + self.step(13) + + ret = await self.send_change_to_mode_cmd(newMode=invalid_mode) + logging.info(f"ret {ret}") + asserts.assert_true(ret.status == Status.Failure, + f"Attempt to change to invalid mode {invalid_mode} didn't fail as expected") + + self.step(14) + + current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + + logging.info(f"CurrentMode: {current_mode}") + + asserts.assert_true(current_mode == ModeManual, "CurrentMode changed after failed ChangeToMode command!") + + +if __name__ == "__main__": + default_matter_test_main() From fb6885c3ffaffc6a63de1a1af7891fbcd67abc53 Mon Sep 17 00:00:00 2001 From: pcoleman Date: Mon, 22 Jul 2024 13:38:41 +0100 Subject: [PATCH 03/16] Fix lint errors --- src/python_testing/TC_EWATERHTRM_2_1.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py index 8e902aad662d67..7e4d0ddfd30a35 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -28,7 +28,6 @@ # === END CI TEST ARGUMENTS === import logging -from time import sleep import chip.clusters as Clusters from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches @@ -41,8 +40,6 @@ class TC_EWATERHTRM_2_1(MatterBaseTest): def __init__(self, *args): super().__init__(*args) self.endpoint = 0 - self.mode_ok = 0 - self.mode_fail = 0 def steps_TC_EWATERHTRM_2_1(self) -> list[TestStep]: steps = [ @@ -79,15 +76,17 @@ def pics_TC_EWATERHTRM_2_1(self) -> list[str]: @async_test_body async def test_TC_EWATERHTRM_2_1(self): - ModeOff = 0 + # Valid modes. Only ModeManual referred to in this test + # ModeOff = 0 ModeManual = 1 - ModeTimed = 2 + # ModeTimed = 2 self.endpoint = self.matter_test_config.endpoint attributes = Clusters.WaterHeaterMode.Attributes self.step(1) + # Commission DUT - already done self.step(2) From 2b9ba5e01f3d67a893951070a74fea6f881845ac Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 22 Jul 2024 12:39:20 +0000 Subject: [PATCH 04/16] Restyled by isort --- src/python_testing/TC_EWATERHTRM_2_1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py index 7e4d0ddfd30a35..0aee92babd5d30 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -30,8 +30,8 @@ import logging import chip.clusters as Clusters -from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches from chip.interaction_model import Status +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches from mobly import asserts From 9714248caf79e29f33cfa4d4fff980714b074986 Mon Sep 17 00:00:00 2001 From: James Harrow Date: Sun, 28 Jul 2024 18:46:05 +0100 Subject: [PATCH 05/16] Renamed read_mod_attribute_expect_success to read_mode_attribute_expect_success --- src/python_testing/TC_EWATERHTRM_1_2.py | 4 ++-- src/python_testing/TC_EWATERHTRM_2_1.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/python_testing/TC_EWATERHTRM_1_2.py b/src/python_testing/TC_EWATERHTRM_1_2.py index 90c50dc1e40819..e006155c27f523 100644 --- a/src/python_testing/TC_EWATERHTRM_1_2.py +++ b/src/python_testing/TC_EWATERHTRM_1_2.py @@ -33,7 +33,7 @@ class TC_EWATERHTRM_1_2(MatterBaseTest): - async def read_mod_attribute_expect_success(self, endpoint, attribute): + async def read_mode_attribute_expect_success(self, endpoint, attribute): cluster = Clusters.Objects.WaterHeaterMode return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) @@ -100,7 +100,7 @@ async def test_TC_EWATERHTRM_1_2(self): asserts.assert_true(off_present, "SupportedModes does not have an entry of Off(0x4000)") self.step(3) - current_mode = await self.read_mod_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentMode) + current_mode = await self.read_mode_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentMode) logging.info("CurrentMode: %s" % current_mode) asserts.assert_true(current_mode in modes, "CurrentMode is not a supported mode!") diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py index 0aee92babd5d30..68166d8311174f 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -60,7 +60,7 @@ def steps_TC_EWATERHTRM_2_1(self) -> list[TestStep]: ] return steps - async def read_mod_attribute_expect_success(self, endpoint, attribute): + async def read_mode_attribute_expect_success(self, endpoint, attribute): cluster = Clusters.Objects.WaterHeaterMode return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) @@ -90,7 +90,7 @@ async def test_TC_EWATERHTRM_2_1(self): self.step(2) - supported_modes = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.SupportedModes) + supported_modes = await self.read_mode_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.SupportedModes) logging.info(f"SupportedModes: {supported_modes}") @@ -100,7 +100,7 @@ async def test_TC_EWATERHTRM_2_1(self): self.step(3) - old_current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + old_current_mode = await self.read_mode_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) logging.info(f"CurrentMode: {old_current_mode}") @@ -122,7 +122,7 @@ async def test_TC_EWATERHTRM_2_1(self): self.step(10) - old_current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + old_current_mode = await self.read_mode_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) logging.info(f"CurrentMode: {old_current_mode}") @@ -134,7 +134,7 @@ async def test_TC_EWATERHTRM_2_1(self): self.step(12) - current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + current_mode = await self.read_mode_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) logging.info(f"CurrentMode: {current_mode}") @@ -150,7 +150,7 @@ async def test_TC_EWATERHTRM_2_1(self): self.step(14) - current_mode = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) + current_mode = await self.read_mode_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) logging.info(f"CurrentMode: {current_mode}") From c9f5b408ce52d9e7900816b1bb986c0ec1d601ed Mon Sep 17 00:00:00 2001 From: James Harrow Date: Sun, 28 Jul 2024 18:52:13 +0100 Subject: [PATCH 06/16] Changed test runner to run All-clusters-app where waterheater mode is implemented. --- src/python_testing/TC_EWATERHTRM_1_2.py | 2 +- src/python_testing/TC_EWATERHTRM_2_1.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python_testing/TC_EWATERHTRM_1_2.py b/src/python_testing/TC_EWATERHTRM_1_2.py index e006155c27f523..677faf71772fc2 100644 --- a/src/python_testing/TC_EWATERHTRM_1_2.py +++ b/src/python_testing/TC_EWATERHTRM_1_2.py @@ -17,7 +17,7 @@ # === BEGIN CI TEST ARGUMENTS === # test-runner-runs: run1 -# test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP} +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} # test-runner-run/run1/factoryreset: True # test-runner-run/run1/quiet: True # test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py index 68166d8311174f..8aa8ab92bdfd71 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -20,7 +20,7 @@ # # === BEGIN CI TEST ARGUMENTS === # test-runner-runs: run1 -# test-runner-run/run1/app: ${WATER_HEATER_MANAGEMENT_APP} +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} # test-runner-run/run1/factoryreset: True # test-runner-run/run1/quiet: True # test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json From 927a3efeba4dde4f52c4ac61fe4971b3a2615aeb Mon Sep 17 00:00:00 2001 From: James Harrow Date: Sun, 28 Jul 2024 18:55:05 +0100 Subject: [PATCH 07/16] Added Test scripts to CI test.yaml (TC_EWATERHTRM_1_2.py & TC_EWATERHTRM_2_2.py) --- .github/workflows/tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d6ff5d341cd070..60a718e73397eb 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -533,6 +533,8 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEVSE_2_5.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_2.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EWATERHTRM_1_2.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EWATERHTRM_2_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_3.py' From ebd1509bfed977a09b075731a4bf1d7a86e1d33a Mon Sep 17 00:00:00 2001 From: James Harrow Date: Sun, 28 Jul 2024 22:56:28 +0100 Subject: [PATCH 08/16] Corrected checking of modes for WaterHeaterModes which must be included, and corrected the common modes. --- src/python_testing/TC_EWATERHTRM_1_2.py | 75 ++++++++++++++++++++----- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/src/python_testing/TC_EWATERHTRM_1_2.py b/src/python_testing/TC_EWATERHTRM_1_2.py index 677faf71772fc2..3196ac9d4faf47 100644 --- a/src/python_testing/TC_EWATERHTRM_1_2.py +++ b/src/python_testing/TC_EWATERHTRM_1_2.py @@ -64,19 +64,30 @@ async def test_TC_EWATERHTRM_1_2(self): self.step(1) self.step(2) - supported_modes = await self.read_mod_attribute_expect_success(endpoint=endpoint, attribute=attributes.SupportedModes) - asserts.assert_greater_equal(len(supported_modes), 2, "SupportedModes must have at least 2 entries!") - asserts.assert_less_equal(len(supported_modes), 255, "SupportedModes must have at most 255 entries!") + supported_modes = await self.read_mode_attribute_expect_success(endpoint=endpoint, attribute=attributes.SupportedModes) + asserts.assert_greater_equal(len(supported_modes), 2, + "SupportedModes must have at least 2 entries!") + asserts.assert_less_equal(len(supported_modes), 255, + "SupportedModes must have at most 255 entries!") modes = set([m.mode for m in supported_modes]) - asserts.assert_equal(len(modes), len(supported_modes), "SupportedModes must have unique mode values") + asserts.assert_equal(len(modes), len(supported_modes), + "SupportedModes must have unique mode values") labels = set([m.label for m in supported_modes]) - asserts.assert_equal(len(labels), len(supported_modes), "SupportedModes must have unique mode label values") + asserts.assert_equal(len(labels), len(supported_modes), + "SupportedModes must have unique mode label values") # common mode tags - commonTags = {0x0: 'Off', - 0x1: 'Manual', - 0x2: 'Timed'} + commonTags = {0x0: 'Auto', + 0x1: 'Quick', + 0x2: 'Quiet', + 0x3: 'LowNoise', + 0x4: 'LowEnergy', + 0x5: 'Vacation', + 0x6: 'Min', + 0x7: 'Max', + 0x8: 'Night', + 0x9: 'Day'} # derived cluster defined tags # kUnknownEnumValue may not be defined @@ -88,21 +99,59 @@ async def test_TC_EWATERHTRM_1_2(self): logging.info("Derived tags: %s" % derivedTags) + # According to the Mode spec: + # At least one entry in the SupportedModes attribute SHALL include the Manual mode tag in the ModeTags field list. + # At least one entry in the SupportedModes attribute SHALL include the Off mode tag in the ModeTags field list. + # An entry in the SupportedModes attribute that includes one of an Off, Manual, or Timed tag + # SHALL NOT also include an additional instance of any one of these tag types. + off_present = 0 + manual_present = 0 + timed_present = 0 + for m in supported_modes: + off_manual_timed_present_in_this_mode = 0 for t in m.modeTags: is_mfg = (0x8000 <= t.value and t.value <= 0xBFFF) asserts.assert_true(t.value in commonTags.keys() or t.value in derivedTags or is_mfg, "Found a SupportedModes entry with invalid mode tag value!") if t.value == Clusters.WaterHeaterMode.Enums.ModeTag.kOff: - off_present = True - logging.info("Found normal mode tag %s with tag value %s", m.mode, t.value) - - asserts.assert_true(off_present, "SupportedModes does not have an entry of Off(0x4000)") + off_present += 1 + off_manual_timed_present_in_this_mode += 1 + logging.info( + "Found Off mode tag %s with tag value %s", m.mode, t.value) + + if t.value == Clusters.WaterHeaterMode.Enums.ModeTag.kManual: + manual_present += 1 + off_manual_timed_present_in_this_mode += 1 + logging.info( + "Found Manual mode tag %s with tag value %s", m.mode, t.value) + + if t.value == Clusters.WaterHeaterMode.Enums.ModeTag.kTimed: + timed_present += 1 + off_manual_timed_present_in_this_mode += 1 + logging.info( + "Found Timed mode tag %s with tag value %s", m.mode, t.value) + + asserts.assert_less_equal(off_manual_timed_present_in_this_mode, 1, + f"The supported mode ({m.mode}) should only include one of OFF, MANUAL or TIMED, but includes more than one.") + + asserts.assert_greater(off_present, 0, + "SupportedModes does not have an entry of Off(0x4000)") + asserts.assert_greater(manual_present, 0, + "SupportedModes does not have an entry of Manual(0x4001)") + + asserts.assert_less_equal(off_present, 1, + "SupportedModes cannot have more than one instance of Off(0x4000)") + asserts.assert_less_equal(manual_present, 1, + "SupportedModes cannot have more than one instance of Manual(0x4001)") + asserts.assert_less_equal(timed_present, 1, + "SupportedModes cannot have more than one instance of Timed(0x4002)") self.step(3) current_mode = await self.read_mode_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentMode) logging.info("CurrentMode: %s" % current_mode) - asserts.assert_true(current_mode in modes, "CurrentMode is not a supported mode!") + asserts.assert_true(current_mode in modes, + "CurrentMode is not a supported mode!") if __name__ == "__main__": From cabc6d1215a812cd2fad9714931a0b0bb6214109 Mon Sep 17 00:00:00 2001 From: James Harrow Date: Sun, 28 Jul 2024 22:59:09 +0100 Subject: [PATCH 09/16] Alignment (autowrapping) --- src/python_testing/TC_EWATERHTRM_2_1.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py index 8aa8ab92bdfd71..fa23b892fa8933 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -94,7 +94,8 @@ async def test_TC_EWATERHTRM_2_1(self): logging.info(f"SupportedModes: {supported_modes}") - asserts.assert_greater_equal(len(supported_modes), 2, "SupportedModes must have at least two entries!") + asserts.assert_greater_equal(len(supported_modes), 2, + "SupportedModes must have at least two entries!") modes = [m.mode for m in supported_modes] @@ -111,7 +112,8 @@ async def test_TC_EWATERHTRM_2_1(self): ret = await self.send_change_to_mode_cmd(newMode=old_current_mode) logging.info(f"ret.status {ret.status}") - asserts.assert_true(ret.status == Status.Success, "Changing the mode to the current mode should be a no-op") + asserts.assert_true(ret.status == Status.Success, + "Changing the mode to the current mode should be a no-op") # Steps 5-9 are not performed as EWATERHTRM.S.M.CAN_TEST_MODE_FAILURE is false self.step(5) @@ -154,7 +156,8 @@ async def test_TC_EWATERHTRM_2_1(self): logging.info(f"CurrentMode: {current_mode}") - asserts.assert_true(current_mode == ModeManual, "CurrentMode changed after failed ChangeToMode command!") + asserts.assert_true(current_mode == ModeManual, + "CurrentMode changed after failed ChangeToMode command!") if __name__ == "__main__": From cb83726e8a46485bad697572b374b1ddd9a7dad4 Mon Sep 17 00:00:00 2001 From: jamesharrow <93921463+jamesharrow@users.noreply.github.com> Date: Mon, 29 Jul 2024 07:57:50 +0100 Subject: [PATCH 10/16] Update tests.yaml - fixed test script name --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 60a718e73397eb..8654764a7ba678 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -534,7 +534,7 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EWATERHTRM_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EWATERHTRM_2_2.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EWATERHTRM_2_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_3.py' From 01dae06baed57089f3a294fe8fb25afc0a7e2c1a Mon Sep 17 00:00:00 2001 From: pcoleman Date: Mon, 29 Jul 2024 22:02:23 +0100 Subject: [PATCH 11/16] Address review comments from Andrei --- src/python_testing/TC_EWATERHTRM_1_2.py | 7 +------ src/python_testing/TC_EWATERHTRM_2_1.py | 5 ++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/python_testing/TC_EWATERHTRM_1_2.py b/src/python_testing/TC_EWATERHTRM_1_2.py index 3196ac9d4faf47..4820b652d52955 100644 --- a/src/python_testing/TC_EWATERHTRM_1_2.py +++ b/src/python_testing/TC_EWATERHTRM_1_2.py @@ -90,12 +90,7 @@ async def test_TC_EWATERHTRM_1_2(self): 0x9: 'Day'} # derived cluster defined tags - # kUnknownEnumValue may not be defined - try: - derivedTags = [tag.value for tag in Clusters.WaterHeaterMode.Enums.ModeTag - if tag is not Clusters.WaterHeaterMode.Enums.ModeTag.kUnknownEnumValue] - except AttributeError: - derivedTags = Clusters.WaterHeaterMode.Enums.ModeTag + derivedTags = [tag.value for tag in Clusters.WaterHeaterMode.Enums.ModeTag] logging.info("Derived tags: %s" % derivedTags) diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py index fa23b892fa8933..f1928faec95da3 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -97,8 +97,6 @@ async def test_TC_EWATERHTRM_2_1(self): asserts.assert_greater_equal(len(supported_modes), 2, "SupportedModes must have at least two entries!") - modes = [m.mode for m in supported_modes] - self.step(3) old_current_mode = await self.read_mode_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentMode) @@ -106,13 +104,14 @@ async def test_TC_EWATERHTRM_2_1(self): logging.info(f"CurrentMode: {old_current_mode}") # pick a value that's not on the list of supported modes + modes = [m.mode for m in supported_modes] invalid_mode = max(modes) + 1 self.step(4) ret = await self.send_change_to_mode_cmd(newMode=old_current_mode) logging.info(f"ret.status {ret.status}") - asserts.assert_true(ret.status == Status.Success, + asserts.assert_equal(ret.status, Status.Success, "Changing the mode to the current mode should be a no-op") # Steps 5-9 are not performed as EWATERHTRM.S.M.CAN_TEST_MODE_FAILURE is false From ec9b92fce05e727f9d02fe28cc6a1320ceb72732 Mon Sep 17 00:00:00 2001 From: pcoleman Date: Tue, 30 Jul 2024 08:07:25 +0100 Subject: [PATCH 12/16] Address comments from Cecille --- src/python_testing/TC_EWATERHTRM_1_2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_testing/TC_EWATERHTRM_1_2.py b/src/python_testing/TC_EWATERHTRM_1_2.py index 4820b652d52955..15885e5379925a 100644 --- a/src/python_testing/TC_EWATERHTRM_1_2.py +++ b/src/python_testing/TC_EWATERHTRM_1_2.py @@ -50,7 +50,7 @@ def steps_TC_EWATERHTRM_1_2(self) -> list[TestStep]: def pics_TC_EWATERHTRM_1_2(self) -> list[str]: pics = [ - "EWATERHTRM.S", + "WHM.S", ] return pics From d6318f6073b7291f5720833dae9e569f0e838bfb Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 30 Jul 2024 07:07:47 +0000 Subject: [PATCH 13/16] Restyled by autopep8 --- src/python_testing/TC_EWATERHTRM_2_1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_EWATERHTRM_2_1.py index f1928faec95da3..9e7863c9c7e225 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_EWATERHTRM_2_1.py @@ -112,7 +112,7 @@ async def test_TC_EWATERHTRM_2_1(self): ret = await self.send_change_to_mode_cmd(newMode=old_current_mode) logging.info(f"ret.status {ret.status}") asserts.assert_equal(ret.status, Status.Success, - "Changing the mode to the current mode should be a no-op") + "Changing the mode to the current mode should be a no-op") # Steps 5-9 are not performed as EWATERHTRM.S.M.CAN_TEST_MODE_FAILURE is false self.step(5) From 8bf5dcaa68ab7b0599c1f18647f2d529b457c842 Mon Sep 17 00:00:00 2001 From: pcoleman Date: Tue, 30 Jul 2024 08:23:45 +0100 Subject: [PATCH 14/16] Rename tests as PICS=WHM --- .github/workflows/tests.yaml | 5 +++-- .../{TC_EWATERHTRM_1_2.py => TC_WHM_1_2.py} | 12 ++++++------ .../{TC_EWATERHTRM_2_1.py => TC_WHM_2_1.py} | 12 ++++++------ 3 files changed, 15 insertions(+), 14 deletions(-) rename src/python_testing/{TC_EWATERHTRM_1_2.py => TC_WHM_1_2.py} (95%) rename src/python_testing/{TC_EWATERHTRM_2_1.py => TC_WHM_2_1.py} (95%) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1852d5f6c1b670..33e104c570b282 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -540,8 +540,6 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEVSE_2_5.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EWATERHTRM_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EWATERHTRM_2_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_3.py' @@ -600,6 +598,9 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_4.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SC_7_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SWTCH.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_WHM_1_2.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_WHM_2_1.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_LVL_2_3.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TCP_Tests.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestConformanceSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' diff --git a/src/python_testing/TC_EWATERHTRM_1_2.py b/src/python_testing/TC_WHM_1_2.py similarity index 95% rename from src/python_testing/TC_EWATERHTRM_1_2.py rename to src/python_testing/TC_WHM_1_2.py index 15885e5379925a..aaa8d30002bb71 100644 --- a/src/python_testing/TC_EWATERHTRM_1_2.py +++ b/src/python_testing/TC_WHM_1_2.py @@ -31,16 +31,16 @@ from mobly import asserts -class TC_EWATERHTRM_1_2(MatterBaseTest): +class TC_WHM_1_2(MatterBaseTest): async def read_mode_attribute_expect_success(self, endpoint, attribute): cluster = Clusters.Objects.WaterHeaterMode return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) - def desc_TC_EWATERHTRM_1_2(self) -> str: - return "[TC-EWATERHTRM-1.2] Cluster attributes with DUT as Server" + def desc_TC_WHM_1_2(self) -> str: + return "[TC-WHM-1.2] Cluster attributes with DUT as Server" - def steps_TC_EWATERHTRM_1_2(self) -> list[TestStep]: + def steps_TC_WHM_1_2(self) -> list[TestStep]: steps = [ TestStep(1, "Commissioning, already done", is_commissioning=True), TestStep(2, "Read the SupportedModes attribute"), @@ -48,14 +48,14 @@ def steps_TC_EWATERHTRM_1_2(self) -> list[TestStep]: ] return steps - def pics_TC_EWATERHTRM_1_2(self) -> list[str]: + def pics_TC_WHM_1_2(self) -> list[str]: pics = [ "WHM.S", ] return pics @async_test_body - async def test_TC_EWATERHTRM_1_2(self): + async def test_TC_WHM_1_2(self): endpoint = self.user_params.get("endpoint", 1) diff --git a/src/python_testing/TC_EWATERHTRM_2_1.py b/src/python_testing/TC_WHM_2_1.py similarity index 95% rename from src/python_testing/TC_EWATERHTRM_2_1.py rename to src/python_testing/TC_WHM_2_1.py index 9e7863c9c7e225..ac5124357c9f5a 100644 --- a/src/python_testing/TC_EWATERHTRM_2_1.py +++ b/src/python_testing/TC_WHM_2_1.py @@ -35,13 +35,13 @@ from mobly import asserts -class TC_EWATERHTRM_2_1(MatterBaseTest): +class TC_WHM_2_1(MatterBaseTest): def __init__(self, *args): super().__init__(*args) self.endpoint = 0 - def steps_TC_EWATERHTRM_2_1(self) -> list[TestStep]: + def steps_TC_WHM_2_1(self) -> list[TestStep]: steps = [ TestStep(1, "Commissioning, already done", is_commissioning=True), TestStep(2, "Read the SupportedModes attribute"), @@ -70,11 +70,11 @@ async def send_change_to_mode_cmd(self, newMode) -> Clusters.Objects.WaterHeater "Unexpected return type for Water Heater Mode ChangeToMode") return ret - def pics_TC_EWATERHTRM_2_1(self) -> list[str]: - return ["EWATERHTRM.S"] + def pics_TC_WHM_2_1(self) -> list[str]: + return ["WHM.S"] @async_test_body - async def test_TC_EWATERHTRM_2_1(self): + async def test_TC_WHM_2_1(self): # Valid modes. Only ModeManual referred to in this test # ModeOff = 0 @@ -114,7 +114,7 @@ async def test_TC_EWATERHTRM_2_1(self): asserts.assert_equal(ret.status, Status.Success, "Changing the mode to the current mode should be a no-op") - # Steps 5-9 are not performed as EWATERHTRM.S.M.CAN_TEST_MODE_FAILURE is false + # Steps 5-9 are not performed as WHM.S.M.CAN_TEST_MODE_FAILURE is false self.step(5) self.step(6) self.step(7) From 88178a36cd1d38dacdbb6428b0c08b943ef7cd70 Mon Sep 17 00:00:00 2001 From: pcoleman Date: Tue, 30 Jul 2024 09:33:59 +0100 Subject: [PATCH 15/16] Adding a TODO --- src/python_testing/TC_WHM_2_1.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/python_testing/TC_WHM_2_1.py b/src/python_testing/TC_WHM_2_1.py index ac5124357c9f5a..0d39d23cc2e1ea 100644 --- a/src/python_testing/TC_WHM_2_1.py +++ b/src/python_testing/TC_WHM_2_1.py @@ -115,6 +115,7 @@ async def test_TC_WHM_2_1(self): "Changing the mode to the current mode should be a no-op") # Steps 5-9 are not performed as WHM.S.M.CAN_TEST_MODE_FAILURE is false + # TODO - see issue 34565 self.step(5) self.step(6) self.step(7) From 9166de5feffde0cf087dc119eefe20a8e3398040 Mon Sep 17 00:00:00 2001 From: pcoleman Date: Tue, 30 Jul 2024 14:56:42 +0100 Subject: [PATCH 16/16] Remove unnecessary blank line --- .github/workflows/tests.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 33e104c570b282..bd89c463fe8012 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -600,7 +600,6 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SWTCH.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_WHM_1_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_WHM_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_LVL_2_3.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TCP_Tests.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestConformanceSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'