From 842791dc8d3c60c1a2ea67c8396696c2f7acfdab Mon Sep 17 00:00:00 2001
From: Oleksandr Sirko <wisenss@gmail.com>
Date: Fri, 7 Feb 2025 19:23:34 +0100
Subject: [PATCH 1/6] initial effort to write test

---
 src/python_testing/TC_DGETH_2_2.py | 143 +++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100644 src/python_testing/TC_DGETH_2_2.py

diff --git a/src/python_testing/TC_DGETH_2_2.py b/src/python_testing/TC_DGETH_2_2.py
new file mode 100644
index 00000000000000..1532005eb02195
--- /dev/null
+++ b/src/python_testing/TC_DGETH_2_2.py
@@ -0,0 +1,143 @@
+#
+#  Copyright (c) 2025 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:
+#     app: ${ALL_CLUSTERS_APP}
+#     app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json
+#     script-args: >
+#       --PICS src/app/tests/suites/certification/ci-pics-values
+#       --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
+#     factory-reset: true
+#     quiet: true
+# === END CI TEST ARGUMENTS ===
+#
+import logging
+import chip.clusters as Clusters
+
+from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, run_if_endpoint_matches, has_feature, has_cluster
+
+from mobly import asserts
+
+
+class TC_DGETH_2_2(MatterBaseTest):
+    """
+    [TC-DGETH-2.2] Command Received [DUT as Server]
+
+    This test case verifies the behavior of the commands received by the DUT as a server.
+    See the test plan steps for details on each command and expected outcome.
+    """
+
+    async def read_dgeth_attribute_expect_success(self, endpoint, attribute):
+        cluster = Clusters.Objects.EthernetNetworkDiagnostics
+        return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute)
+
+    async def send_reset_counts_command(self):
+        cluster = Clusters.Objects.EthernetNetworkDiagnostics
+        return await self.send_single_cmd(cmd=cluster.Commands.ResetCounts(), endpoint=0)
+
+    def desc_TC_DGETH_2_2(self) -> str:
+        return "[TC-DGETH-2.2] Command Received [DUT as Server]"
+
+    def pics_TC_DGETH_2_2(self) -> list[str]:
+        return ["DGETH.S"]
+
+    def steps_TC_DGETH_2_2(self) -> list[TestStep]:
+        return [
+            TestStep(1, "Commissioning, already done", is_commissioning=True),
+            TestStep(2, "Read PHYRate 10 times to generate traffic"),
+            TestStep(3, "Read initial PacketRxCount"),
+            TestStep(4, "Read initial PacketTxCount"),
+            TestStep(5, "Read initial TxErrCount"),
+            TestStep(6, "Read initial CollisionCount"),
+            TestStep(7, "Read initial OverrunCount"),
+            TestStep(8, "Send ResetCounts command"),
+            TestStep(9, "Verify PacketRxCount reset"),
+            TestStep(10, "Verify PacketTxCount reset"),
+            TestStep(11, "Verify TxErrCount reset"),
+            TestStep(12, "Verify CollisionCount reset"),
+            TestStep(13, "Verify OverrunCount reset")
+        ]
+
+    @run_if_endpoint_matches(has_cluster(Clusters.Objects.EthernetNetworkDiagnostics))
+    async def test_TC_DGETH_2_2(self):
+        endpoint = self.get_endpoint()
+        cluster = Clusters.Objects.EthernetNetworkDiagnostics
+        attributes = Clusters.EthernetNetworkDiagnostics.Attributes
+
+        # Step 1: Commission DUT (already done)
+        self.step(1)
+
+        attribute_list = await self.read_dgeth_attribute_expect_success(endpoint, attributes.AttributeList)
+
+        # Step 2: Generate traffic with PHYRate reads
+        self.step(2)
+        if self.pics_guard(attributes.PHYRate.attribute_id in attribute_list):
+            for _ in range(10):
+                await self.read_dgeth_attribute_expect_success(endpoint, attributes.AttributeList)
+
+        # Steps 3-7: Read initial values
+        initial_values = {}
+        for step, attr in [(3, attributes.PacketRxCount),
+                           (4, attributes.PacketTxCount),
+                           (5, attributes.TxErrCount),
+                           (6, attributes.CollisionCount),
+                           (7, attributes.OverrunCount)]:
+            self.step(step)
+            if self.pics_guard(attr.attribute_id in attribute_list):
+                initial_values[attr] = await self.read_dgeth_attribute_expect_success(endpoint, attr)
+        # Print initial values for debugging
+        self.step(8)
+        for attr, value in initial_values.items():
+            logging.info(f"Initial {attr.__name__}: {value}")
+
+        # Step 8: Send ResetCounts command
+        self.step(8)
+        await self.send_reset_counts_command()
+
+        # Steps 9-13: Verify post-reset values
+        verification_map = {
+            9: (attributes.PacketRxCount, lambda a, b: a < b),
+            10: (attributes.PacketTxCount, lambda a, b: a < b),
+            11: (attributes.TxErrCount, lambda a, b: a <= b),
+            12: (attributes.CollisionCount, lambda a, b: a <= b),
+            13: (attributes.OverrunCount, lambda a, b: a <= b)
+        }
+
+        for step, (attr, comparator) in verification_map.items():
+            self.step(step)
+            if self.pics_guard(attr.attribute_id in attribute_list):
+                post_value = await self.read_dgeth_attribute_expect_success(endpoint, attr)
+                initial_value = initial_values.get(attr)
+
+                asserts.assert_true(
+                    comparator(post_value, initial_value),
+                    f"{attr.__name__} post-reset value {post_value} failed check against initial {initial_value}"
+                )
+
+
+if __name__ == "__main__":
+    default_matter_test_main()

From 5c09a11be65a25a994f4bf97e093d86fc8c0c000 Mon Sep 17 00:00:00 2001
From: Oleksandr Sirko <wisenss@gmail.com>
Date: Fri, 7 Feb 2025 22:04:00 +0100
Subject: [PATCH 2/6] remove debug step

---
 src/python_testing/TC_DGETH_2_2.py | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/src/python_testing/TC_DGETH_2_2.py b/src/python_testing/TC_DGETH_2_2.py
index 1532005eb02195..cfe04d9392c4b4 100644
--- a/src/python_testing/TC_DGETH_2_2.py
+++ b/src/python_testing/TC_DGETH_2_2.py
@@ -35,11 +35,8 @@
 #     quiet: true
 # === END CI TEST ARGUMENTS ===
 #
-import logging
 import chip.clusters as Clusters
-
-from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, run_if_endpoint_matches, has_feature, has_cluster
-
+from chip.testing.matter_testing import MatterBaseTest, TestStep, default_matter_test_main, has_cluster, run_if_endpoint_matches
 from mobly import asserts
 
 
@@ -85,7 +82,6 @@ def steps_TC_DGETH_2_2(self) -> list[TestStep]:
     @run_if_endpoint_matches(has_cluster(Clusters.Objects.EthernetNetworkDiagnostics))
     async def test_TC_DGETH_2_2(self):
         endpoint = self.get_endpoint()
-        cluster = Clusters.Objects.EthernetNetworkDiagnostics
         attributes = Clusters.EthernetNetworkDiagnostics.Attributes
 
         # Step 1: Commission DUT (already done)
@@ -109,10 +105,6 @@ async def test_TC_DGETH_2_2(self):
             self.step(step)
             if self.pics_guard(attr.attribute_id in attribute_list):
                 initial_values[attr] = await self.read_dgeth_attribute_expect_success(endpoint, attr)
-        # Print initial values for debugging
-        self.step(8)
-        for attr, value in initial_values.items():
-            logging.info(f"Initial {attr.__name__}: {value}")
 
         # Step 8: Send ResetCounts command
         self.step(8)

From 9e14c4af17eb9f3a40f25d135ec3f410b3607355 Mon Sep 17 00:00:00 2001
From: Oleksandr Sirko <wisenss@gmail.com>
Date: Mon, 10 Feb 2025 11:28:47 +0100
Subject: [PATCH 3/6] remove yaml, now has a python implementation

---
 .../certification/Test_TC_DGETH_2_2.yaml      | 234 ------------------
 src/app/tests/suites/ciTests.json             |   2 +-
 2 files changed, 1 insertion(+), 235 deletions(-)
 delete mode 100644 src/app/tests/suites/certification/Test_TC_DGETH_2_2.yaml

diff --git a/src/app/tests/suites/certification/Test_TC_DGETH_2_2.yaml b/src/app/tests/suites/certification/Test_TC_DGETH_2_2.yaml
deleted file mode 100644
index 8751ef754a552f..00000000000000
--- a/src/app/tests/suites/certification/Test_TC_DGETH_2_2.yaml
+++ /dev/null
@@ -1,234 +0,0 @@
-# Copyright (c) 2021 Project CHIP Authors
-#
-# 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.
-
-name: 47.2.2. [TC-DGETH-2.2] Command Received [DUT as Server]
-
-PICS:
-    - DGETH.S
-
-config:
-    nodeId: 0x12344321
-    cluster: "Ethernet Network Diagnostics"
-    endpoint: 0
-
-tests:
-    - label: "Step 1: Wait for the commissioned device to be retrieved"
-      cluster: "DelayCommands"
-      command: "WaitForCommissionee"
-      arguments:
-          values:
-              - name: "nodeId"
-                value: nodeId
-
-    - label: "Step 2a.1: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.2: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.3: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.4: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.5: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.6: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.7: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.8: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.9: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2a.10: TH reads PHYRate attribute from DUT"
-      PICS: DGETH.S.A0000
-      command: "readAttribute"
-      attribute: "PHYRate"
-      response:
-          constraints:
-              type: enum8
-              minValue: 0
-              maxValue: 9
-
-    - label: "Step 2b: TH reads PacketRxCount attribute value from DUT"
-      PICS: DGETH.S.A0002
-      command: "readAttribute"
-      attribute: "PacketRxCount"
-      response:
-          saveAs: PacketRxCountValue
-
-    - label: "Step 2c: TH reads PacketTxCount attribute value from DUT"
-      PICS: DGETH.S.A0003
-      command: "readAttribute"
-      attribute: "PacketTxCount"
-      response:
-          saveAs: PacketTxCountValue
-
-    - label: "Step 2d: TH reads TxErrCount attribute value from DUT"
-      PICS: DGETH.S.A0004
-      command: "readAttribute"
-      attribute: "TxErrCount"
-      response:
-          saveAs: TxErrCountValue
-
-    - label: "Step 2e: TH reads CollisionCount attribute value from DUT"
-      PICS: DGETH.S.A0005
-      command: "readAttribute"
-      attribute: "CollisionCount"
-      response:
-          saveAs: CollisionCountValue
-
-    - label: "Step 2f: TH reads OverrunCount attribute value from DUT"
-      PICS: DGETH.S.A0006
-      command: "readAttribute"
-      attribute: "OverrunCount"
-      response:
-          saveAs: OverrunCountValue
-
-    #issue #13648
-    - label: "Step 2g: Sends ResetCounts command"
-      PICS: DGETH.S.C00.Rsp
-      command: "ResetCounts"
-
-    #https://github.com/CHIP-Specifications/chip-certification-tool/issues/702#issuecomment-1427974329
-    - label: "Step 2h: TH reads PacketRxCount attribute value from DUT"
-      PICS: DGETH.S.A0002 && PICS_SKIP_SAMPLE_APP
-      verification: |
-          ./chip-tool ethernetnetworkdiagnostics read packet-rx-count 1 0
-
-          Verify the value of PacketRxCount is less than the value from step 2b on TH(chip-tool) log
-
-          [1657259203.212932][2661:2666] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0037 Attribute 0x0000_0002 DataVersion: 4077191321
-          [1657259203.213000][2661:2666] CHIP:TOO:   PacketRxCount: 30
-      cluster: "LogCommands"
-      command: "UserPrompt"
-      arguments:
-          values:
-              - name: "message"
-                value: "Enter 'y' after success"
-              - name: "expectedValue"
-                value: "y"
-
-    #https://github.com/CHIP-Specifications/chip-certification-tool/issues/702#issuecomment-1427974329
-    - label: "Step 2i: TH reads PacketTxCount attribute value from DUT"
-      PICS: DGETH.S.A0003 && PICS_SKIP_SAMPLE_APP
-      verification: |
-          ./chip-tool ethernetnetworkdiagnostics read packet-tx-count 1 0
-
-          Verify the value of PacketTxCount is less than the value from step 2c on TH(chip-tool) log
-
-          [1657259233.211240][2668:2673] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0037 Attribute 0x0000_0003 DataVersion: 4077191321
-          [1657259233.211315][2668:2673] CHIP:TOO:   PacketTxCount: 96
-      cluster: "LogCommands"
-      command: "UserPrompt"
-      arguments:
-          values:
-              - name: "message"
-                value: "Enter 'y' after success"
-              - name: "expectedValue"
-                value: "y"
-
-    - label: "Step 2j: TH reads TxErrCount attribute value from DUT"
-      PICS: DGETH.S.A0004
-      command: "readAttribute"
-      attribute: "TxErrCount"
-      response:
-          constraints:
-              maxValue: TxErrCountValue
-
-    - label: "Step 2k: TH reads CollisionCount attribute value from DUT"
-      PICS: DGETH.S.A0005
-      command: "readAttribute"
-      attribute: "CollisionCount"
-      response:
-          constraints:
-              maxValue: CollisionCountValue
-
-    - label: "Step 2l: TH reads OverrunCount attribute value from DUT"
-      PICS: DGETH.S.A0006
-      command: "readAttribute"
-      attribute: "OverrunCount"
-      response:
-          constraints:
-              maxValue: OverrunCountValue
diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json
index 9fa23f8a516aa5..b128a4a7d6d35e 100644
--- a/src/app/tests/suites/ciTests.json
+++ b/src/app/tests/suites/ciTests.json
@@ -47,7 +47,7 @@
     ],
     "Descriptor": [],
     "DeviceEnergyManagementMode": ["Test_TC_DEMM_2_1"],
-    "EthernetNetworkDiagnostics": ["Test_TC_DGETH_2_1", "Test_TC_DGETH_2_2"],
+    "EthernetNetworkDiagnostics": ["Test_TC_DGETH_2_1"],
     "DiagnosticsLogs": [],
     "EnergyEVSE": ["Test_TC_EEVSE_2_1"],
     "EnergyEVSEMode": [

From 7924600bafca8fe871746c4387f1d2df9f2137e7 Mon Sep 17 00:00:00 2001
From: Oleksandr Sirko <wisenss@gmail.com>
Date: Mon, 10 Feb 2025 14:04:02 +0100
Subject: [PATCH 4/6] endpoint flaf for CI

---
 src/python_testing/TC_DGETH_2_2.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/python_testing/TC_DGETH_2_2.py b/src/python_testing/TC_DGETH_2_2.py
index cfe04d9392c4b4..13bd586dabda4c 100644
--- a/src/python_testing/TC_DGETH_2_2.py
+++ b/src/python_testing/TC_DGETH_2_2.py
@@ -31,6 +31,7 @@
 #       --passcode 20202021
 #       --trace-to json:${TRACE_TEST_JSON}.json
 #       --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto
+#       --endpoint 0
 #     factory-reset: true
 #     quiet: true
 # === END CI TEST ARGUMENTS ===

From d68b2d31bd333610ec8b0261e752ba5188c0682c Mon Sep 17 00:00:00 2001
From: Oleksandr Sirko <wisenss@gmail.com>
Date: Tue, 11 Feb 2025 12:29:04 +0100
Subject: [PATCH 5/6] debug log

---
 src/python_testing/TC_DGETH_2_2.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/python_testing/TC_DGETH_2_2.py b/src/python_testing/TC_DGETH_2_2.py
index 13bd586dabda4c..79fc594f696485 100644
--- a/src/python_testing/TC_DGETH_2_2.py
+++ b/src/python_testing/TC_DGETH_2_2.py
@@ -37,9 +37,12 @@
 # === END CI TEST ARGUMENTS ===
 #
 import chip.clusters as Clusters
+import logging
 from chip.testing.matter_testing import MatterBaseTest, TestStep, default_matter_test_main, has_cluster, run_if_endpoint_matches
 from mobly import asserts
 
+logger = logging.getLogger(__name__)
+
 
 class TC_DGETH_2_2(MatterBaseTest):
     """
@@ -106,10 +109,12 @@ async def test_TC_DGETH_2_2(self):
             self.step(step)
             if self.pics_guard(attr.attribute_id in attribute_list):
                 initial_values[attr] = await self.read_dgeth_attribute_expect_success(endpoint, attr)
+                logger.info(f"Initial {attr.__name__} value: {initial_values[attr]}")
 
         # Step 8: Send ResetCounts command
         self.step(8)
         await self.send_reset_counts_command()
+        logger.info("Reset counts command sent")
 
         # Steps 9-13: Verify post-reset values
         verification_map = {
@@ -125,6 +130,7 @@ async def test_TC_DGETH_2_2(self):
             if self.pics_guard(attr.attribute_id in attribute_list):
                 post_value = await self.read_dgeth_attribute_expect_success(endpoint, attr)
                 initial_value = initial_values.get(attr)
+                logger.info(f"Post-reset {attr.__name__} value: {post_value} (initial: {initial_value})")
 
                 asserts.assert_true(
                     comparator(post_value, initial_value),

From 467ed3df8e90015a67941db344030384b54b6579 Mon Sep 17 00:00:00 2001
From: Oleksandr Sirko <wisenss@gmail.com>
Date: Tue, 11 Feb 2025 12:33:33 +0100
Subject: [PATCH 6/6] isort

---
 src/python_testing/TC_DGETH_2_2.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/python_testing/TC_DGETH_2_2.py b/src/python_testing/TC_DGETH_2_2.py
index 79fc594f696485..3a5d63ededbe8e 100644
--- a/src/python_testing/TC_DGETH_2_2.py
+++ b/src/python_testing/TC_DGETH_2_2.py
@@ -15,6 +15,8 @@
 #  limitations under the License.
 #
 
+import logging
+
 # See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments
 # for details about the block below.
 #
@@ -37,7 +39,6 @@
 # === END CI TEST ARGUMENTS ===
 #
 import chip.clusters as Clusters
-import logging
 from chip.testing.matter_testing import MatterBaseTest, TestStep, default_matter_test_main, has_cluster, run_if_endpoint_matches
 from mobly import asserts