Hi Koushik,

Apologies for the long wait. To start off, could you please address the AI Code Review as it raised a few concerns:

http://mails.dpdk.org/archives/test-report/2026-August/1029040.html

The patch will also require rebasing.

On 11/08/2026 19:55, Koushik Bhargav Nimoji wrote:
diff --git a/dts/framework/test_result.py b/dts/framework/test_result.py
index 21faa55dc1..13ed8f671c 100644
--- a/dts/framework/test_result.py
+++ b/dts/framework/test_result.py
@@ -117,6 +117,7 @@ class ResultNode(BaseModel):
      label: str
      children: list[Union["ResultNode", ResultLeaf]] = 
Field(default_factory=list)
      parent: Union["ResultNode", None] = None
+    ports: list[dict[str, str]] | None = None

This attribute lacks the appropriate documentation. Also unless I missed something, I am not sure how this belongs to this patch. Can you please clarify?

def add_child(self, label: str) -> "ResultNode":
          """Creates and append a child node to the model.
diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
index c20a0fa885..b23930b953 100644
--- a/dts/framework/test_run.py
+++ b/dts/framework/test_run.py
@@ -115,7 +115,7 @@
  from framework.remote_session.dpdk import DPDKBuildEnvironment, 
DPDKRuntimeEnvironment
  from framework.settings import SETTINGS
  from framework.test_result import Result, ResultNode, TestRunResult
-from framework.test_suite import BaseConfig, TestCase, TestCaseType, TestSuite
+from framework.test_suite import BaseConfig, TestCase, TestCaseType, 
TestSuite, TestSuiteType
  from framework.testbed_model.capability import (
      Capability,
      get_supported_capabilities,
@@ -375,11 +375,6 @@ def next(self) -> State | None:
              ctx.topology.bind_cryptodevs("dpdk")
ctx.topology.configure_ports("sut", "dpdk")
-        if ctx.func_tg and ctx.topology.type is not LinkTopology.NO_LINK:
-            ctx.func_tg.setup(ctx.topology)
-        if ctx.perf_tg and ctx.topology.type is not LinkTopology.NO_LINK:
-            ctx.perf_tg.setup(ctx.topology)
-
          self.result.ports = [
              port.to_dict() for port in ctx.topology.sut_ports + 
ctx.topology.tg_ports
          ]
@@ -506,12 +501,34 @@ class TestSuiteSetup(TestSuiteState):
      """Test suite setup."""
logger_name: ClassVar[str] = "test_suite_setup"
+    test_run: TestRun

Unsure why this is necessary, given it's already inherited by TestSuiteState.

def before(self) -> None:
          """Hook before the state is processed."""
          super().before()
          self.logger.set_custom_log_file(self.test_suite.name)
+ ctx = self.test_run.ctx
+        testsuite_type = self.test_suite.testsuite_type

nit: stick to the snake case, so test_suite_type

+        if (
+            ctx.topology.type is not LinkTopology.NO_LINK
+            and testsuite_type is not TestSuiteType.CRYPTO
+        ):
+            if testsuite_type == TestSuiteType.FUNC:
+                required_tg, other_tg = ctx.func_tg, ctx.perf_tg
+            else:
+                required_tg, other_tg = ctx.perf_tg, ctx.func_tg
+
+            if other_tg and other_tg.is_setup:
+                other_tg.teardown()
+
+                if testsuite_type == TestSuiteType.FUNC and ctx.tg_node:
+                    for port in ctx.topology.tg_ports:
+                        ctx.tg_node.main_session.bind_ports_to_driver([port], 
port.config.os_driver)

I am a bit confused why this happens here. The driver to be bound to should be governed by the TG that uses such ports. Could be os_driver, could be dpdk_driver, regardless of Scapy and TRex.

+
+            if required_tg and not required_tg.is_setup:
+                required_tg.setup(ctx.topology)
+
      @property
      def description(self) -> str:
          """State description."""
diff --git a/dts/framework/test_suite.py b/dts/framework/test_suite.py
index 69ce26040a..554fe3a475 100644
--- a/dts/framework/test_suite.py
+++ b/dts/framework/test_suite.py
@@ -45,6 +45,17 @@ class BaseConfig(FrozenModel):
      """Base for a custom test suite configuration."""
+class TestSuiteType(Enum):
+    """Enum to specify test suite type."""
+
+    FUNC = auto()
+    PERF = auto()
+    CRYPTO = auto()
+
+
+TestSuiteClassType = TypeVar("TestSuiteClassType", bound=type["TestSuite"])
+
+
  class TestSuite(TestProtocol):
      """The base class with building blocks needed by most test cases.
@@ -85,6 +96,30 @@ class TestSuite(TestProtocol):
      _sut_ip_address_egress: Union[IPv4Interface, IPv6Interface]
      _tg_ip_address_ingress: Union[IPv4Interface, IPv6Interface]
      _tg_ip_address_egress: Union[IPv4Interface, IPv6Interface]
+    testsuite_type: ClassVar[TestSuiteType]
nit: snake_case
+
+    @classmethod
+    def make_decorator(
+        cls, testsuite_type: TestSuiteType
nit: snake_case
+    ) -> Callable[[TestSuiteClassType], TestSuiteClassType]:
+        """Creates a decorator for test suites.
+
+        The decorator casts the decorated function as :class:`TestSuite`,
+        sets it as `testsuite_type` and initializes a variable to
+        determine the type of test suite.
+
+        Args:
+            testsuite_type: A functional, performance, or cryptodev test suite.
nit: snake_case
+
+        Returns:
+            The decorator of a functional, performance, or cryptodev test 
suite.
+        """
+
+        def _decorator(testsuite_cls: TestSuiteClassType) -> 
TestSuiteClassType:
+            testsuite_cls.testsuite_type = testsuite_type
+            return testsuite_cls
nit: snake_case
+
+        return _decorator

So the above function doesn't really use cls, making it a @static_method instead of a @class_method. Given static_method is discouraged, it ultimately means that this method should rather be a module-level function. But I do understand that we'd also prefer to have consistency and this is already done for TestCase. So I am ok with either.

def __init__(self, config: BaseConfig) -> None:
          """Initialize the test suite testbed information and basic 
configuration.
@@ -270,6 +305,11 @@ def _adjust_addresses(self, packets: list[Packet], expected: 
bool = False) -> li
          return ret_packets
+#: Test suite type decorators
+func_suite: Callable[[Any], type["TestSuite"]] = 
TestSuite.make_decorator(TestSuiteType.FUNC)
+perf_suite: Callable[[Any], type["TestSuite"]] = 
TestSuite.make_decorator(TestSuiteType.PERF)
+crypto_suite: Callable[[Any], type["TestSuite"]] = 
TestSuite.make_decorator(TestSuiteType.CRYPTO)
+
  #: The generic type for a method of an instance of TestSuite
  TestSuiteMethodType = TypeVar("TestSuiteMethodType", 
bound=Callable[[TestSuite], None])
Many thanks,
Luca

Reply via email to