TC-DGGEN-3.2: Add (#32995)

* TC-DGGEN-3.2: Add

* Apply suggestions from code review

* lint

* move save out of expected outcome

* Restyled by autopep8

* spelling

* Apply suggestions from code review

---------

Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/src/python_testing/TC_DGGEN_3_2.py b/src/python_testing/TC_DGGEN_3_2.py
new file mode 100644
index 0000000..7e5af6c
--- /dev/null
+++ b/src/python_testing/TC_DGGEN_3_2.py
@@ -0,0 +1,48 @@
+#
+#    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.
+#
+
+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_DGGEN_3_2(MatterBaseTest):
+    def steps_TC_DGGEN_3_2(self):
+        return [TestStep(0, "Commission DUT (already done)", is_commissioning=True),
+                TestStep(1, "TH reads the MaxPathsPerInvoke attribute from the Basic Information Cluster from DUT. Save the value as `max_paths_per_invoke",
+                         "Read is successful"),
+                TestStep(2, "TH reads FeatureMap attribute from the General Diagnostics Cluster from DUT",
+                         "Verify that the FeatureMap value has the DMTEST feature bit (0) set to 1 if `max_path_per_invoke` > 1")
+                ]
+
+    @async_test_body
+    async def test_TC_DGGEN_3_2(self):
+        # commissioning - already done
+        self.step(0)
+
+        self.step(1)
+        max_paths_per_invoke = await self.read_single_attribute_check_success(cluster=Clusters.BasicInformation, attribute=Clusters.BasicInformation.Attributes.MaxPathsPerInvoke)
+
+        self.step(2)
+        feature_map = await self.read_single_attribute_check_success(cluster=Clusters.GeneralDiagnostics, attribute=Clusters.GeneralDiagnostics.Attributes.FeatureMap)
+        if max_paths_per_invoke > 1:
+            asserts.assert_true(feature_map & Clusters.GeneralDiagnostics.Bitmaps.Feature.kDataModelTest,
+                                "DMTEST feature must be set if MaxPathsPerInvoke > 1")
+
+
+if __name__ == "__main__":
+    default_matter_test_main()
diff --git a/src/python_testing/test_testing/MockTestRunner.py b/src/python_testing/test_testing/MockTestRunner.py
index 79f6e21..451e38d 100644
--- a/src/python_testing/test_testing/MockTestRunner.py
+++ b/src/python_testing/test_testing/MockTestRunner.py
@@ -37,9 +37,9 @@
 
 
 class MockTestRunner():
-    def __init__(self, filename: str, classname: str, test: str):
+    def __init__(self, filename: str, classname: str, test: str, endpoint: int):
         self.config = MatterTestConfig(
-            tests=[test], endpoint=1, dut_node_ids=[1])
+            tests=[test], endpoint=endpoint, dut_node_ids=[1])
         self.stack = MatterStackState(self.config)
         self.default_controller = self.stack.certificate_authorities[0].adminList[0].NewController(
             nodeId=self.config.controller_node_id,
diff --git a/src/python_testing/test_testing/test_TC_DGGEN_3_2.py b/src/python_testing/test_testing/test_TC_DGGEN_3_2.py
new file mode 100644
index 0000000..34b8051
--- /dev/null
+++ b/src/python_testing/test_testing/test_TC_DGGEN_3_2.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env -S python3 -B
+#
+#    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.
+#
+
+import sys
+from dataclasses import dataclass
+
+import chip.clusters as Clusters
+from chip.clusters import Attribute
+from MockTestRunner import MockTestRunner
+
+
+@dataclass
+class TestSpec():
+    max_paths: int
+    dmtest_feature_map: int
+    expect_pass: bool
+
+
+TEST_CASES = [
+    TestSpec(1, 0, True),
+    TestSpec(1, 1, True),
+    TestSpec(2, 0, False),
+    TestSpec(2, 1, True),
+]
+
+
+def test_spec_to_attribute_cache(test_spec: TestSpec) -> Attribute.AsyncReadTransaction.ReadResponse:
+    bi = Clusters.BasicInformation
+    bi_attr = bi.Attributes
+    gd = Clusters.GeneralDiagnostics
+    gd_attr = gd.Attributes
+    resp = Attribute.AsyncReadTransaction.ReadResponse({}, [], {})
+    resp.attributes = {0: {bi: {bi_attr.MaxPathsPerInvoke: test_spec.max_paths},
+                           gd: {gd_attr.FeatureMap: test_spec.dmtest_feature_map}}}
+    return resp
+
+
+def main():
+    test_runner = MockTestRunner('TC_DGGEN_3_2', 'TC_DGGEN_3_2', 'test_TC_DGGEN_3_2', 0)
+    failures = []
+    for idx, t in enumerate(TEST_CASES):
+        ok = test_runner.run_test_with_mock_read(test_spec_to_attribute_cache(t)) == t.expect_pass
+        if not ok:
+            failures.append(f"Test case failure: {idx} {t}")
+
+    test_runner.Shutdown()
+    print(
+        f"Test of tests: run {len(TEST_CASES)}, test response correct: {len(TEST_CASES) - len(failures)} test response incorrect: {len(failures)}")
+    for f in failures:
+        print(f)
+
+    return 1 if failures else 0
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/src/python_testing/test_testing/test_TC_TMP_2_1.py b/src/python_testing/test_testing/test_TC_TMP_2_1.py
index 5693ace..fe888a4 100644
--- a/src/python_testing/test_testing/test_TC_TMP_2_1.py
+++ b/src/python_testing/test_testing/test_TC_TMP_2_1.py
@@ -160,7 +160,7 @@
 
 
 def main():
-    test_runner = MockTestRunner('TC_TMP_2_1', 'TC_TMP_2_1', 'test_TC_TMP_2_1')
+    test_runner = MockTestRunner('TC_TMP_2_1', 'TC_TMP_2_1', 'test_TC_TMP_2_1', 1)
     failures = []
     for idx, t in enumerate(TEST_CASES):
         ok = test_runner.run_test_with_mock_read(test_spec_to_attribute_cache(t)) == t.expect_pass