DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Juraj Linkeš" <juraj.linkes@pantheon.tech>
To: thomas@monjalon.net, Honnappa.Nagarahalli@arm.com,
	jspewock@iol.unh.edu, probb@iol.unh.edu, paul.szczepanek@arm.com,
	yoan.picchi@foss.arm.com, Luca.Vizzarro@arm.com
Cc: dev@dpdk.org, "Juraj Linkeš" <juraj.linkes@pantheon.tech>
Subject: [RFC PATCH v1 3/5] dts: process test suites at the beginning of run
Date: Wed, 20 Dec 2023 11:33:29 +0100	[thread overview]
Message-ID: <20231220103331.60888-4-juraj.linkes@pantheon.tech> (raw)
In-Reply-To: <20231220103331.60888-1-juraj.linkes@pantheon.tech>

We initialize test suite/case objects at the start of
the program and store them with custom execution config
(add test case names) in Execution. This change helps
identify errors with test suites earlier, and we have
access to the right data when programs crash earlier.

Signed-off-by: Juraj Linkeš <juraj.linkes@pantheon.tech>
---
 dts/framework/config/__init__.py   |   5 +-
 dts/framework/runner.py            | 309 ++++++++++++++++++++---------
 dts/framework/test_suite.py        |  59 +-----
 dts/tests/TestSuite_smoke_tests.py |   2 +-
 4 files changed, 217 insertions(+), 158 deletions(-)

diff --git a/dts/framework/config/__init__.py b/dts/framework/config/__init__.py
index 497847afb9..d65ac625f8 100644
--- a/dts/framework/config/__init__.py
+++ b/dts/framework/config/__init__.py
@@ -238,7 +238,6 @@ class ExecutionConfiguration:
     system_under_test_node: SutNodeConfiguration
     traffic_generator_node: TGNodeConfiguration
     vdevs: list[str]
-    skip_smoke_tests: bool
 
     @staticmethod
     def from_dict(
@@ -247,9 +246,10 @@ def from_dict(
         build_targets: list[BuildTargetConfiguration] = list(
             map(BuildTargetConfiguration.from_dict, d["build_targets"])
         )
+        if not d.get("skip_smoke_tests", False):
+            d["test_suites"].insert(0, "smoke_tests")
         test_suites: list[TestSuiteConfig] = list(map(TestSuiteConfig.from_dict, d["test_suites"]))
         sut_name = d["system_under_test_node"]["node_name"]
-        skip_smoke_tests = d.get("skip_smoke_tests", False)
         assert sut_name in node_map, f"Unknown SUT {sut_name} in execution {d}"
         system_under_test_node = node_map[sut_name]
         assert isinstance(
@@ -270,7 +270,6 @@ def from_dict(
             build_targets=build_targets,
             perf=d["perf"],
             func=d["func"],
-            skip_smoke_tests=skip_smoke_tests,
             test_suites=test_suites,
             system_under_test_node=system_under_test_node,
             traffic_generator_node=traffic_generator_node,
diff --git a/dts/framework/runner.py b/dts/framework/runner.py
index 5e145a8066..acc3342f0c 100644
--- a/dts/framework/runner.py
+++ b/dts/framework/runner.py
@@ -3,9 +3,14 @@
 # Copyright(c) 2022-2023 PANTHEON.tech s.r.o.
 # Copyright(c) 2022-2023 University of New Hampshire
 
+import importlib
+import inspect
 import logging
+import re
 import sys
-from types import MethodType
+from copy import deepcopy
+from dataclasses import dataclass
+from types import MethodType, ModuleType
 
 from .config import (
     BuildTargetConfiguration,
@@ -13,7 +18,12 @@
     ExecutionConfiguration,
     TestSuiteConfig,
 )
-from .exception import BlockingTestSuiteError, SSHTimeoutError, TestCaseVerifyError
+from .exception import (
+    BlockingTestSuiteError,
+    ConfigurationError,
+    SSHTimeoutError,
+    TestCaseVerifyError,
+)
 from .logger import DTSLOG, getLogger
 from .settings import SETTINGS
 from .test_result import (
@@ -24,25 +34,55 @@
     TestCaseResult,
     TestSuiteResult,
 )
-from .test_suite import TestSuite, get_test_suites
+from .test_suite import TestSuite
 from .testbed_model import SutNode, TGNode
 from .utils import check_dts_python_version
 
 
+@dataclass
+class TestSuiteSetup:
+    test_suite: type[TestSuite]
+    test_cases: list[MethodType]
+
+    def processed_config(self) -> TestSuiteConfig:
+        return TestSuiteConfig(
+            test_suite=self.test_suite.__name__,
+            test_cases=[test_case.__name__ for test_case in self.test_cases],
+        )
+
+
+@dataclass
+class Execution:
+    config: ExecutionConfiguration
+    test_suite_setups: list[TestSuiteSetup]
+
+    def processed_config(self) -> ExecutionConfiguration:
+        """
+        Creating copy of execution config witch add test-case names.
+        """
+        modified_execution_config = deepcopy(self.config)
+        modified_execution_config.test_suites[:] = [
+            test_suite.processed_config() for test_suite in self.test_suite_setups
+        ]
+        return modified_execution_config
+
+
 class DTSRunner:
     _logger: DTSLOG
     _result: DTSResult
-    _configuration: Configuration
+    _executions: list[Execution]
 
     def __init__(self, configuration: Configuration):
         self._logger = getLogger("DTSRunner")
         self._result = DTSResult(self._logger)
-        self._configuration = configuration
+        self._executions = create_executions(configuration.executions)
 
     def run(self):
         """
         The main process of DTS. Runs all build targets in all executions from the main
         config file.
+        Suite execution consists of running all test cases scheduled to be executed.
+        A test case run consists of setup, execution and teardown of said test case.
         """
         # check the python version of the server that run dts
         check_dts_python_version()
@@ -50,22 +90,22 @@ def run(self):
         tg_nodes: dict[str, TGNode] = {}
         try:
             # for all Execution sections
-            for execution in self._configuration.executions:
-                sut_node = sut_nodes.get(execution.system_under_test_node.name)
-                tg_node = tg_nodes.get(execution.traffic_generator_node.name)
+            for execution in self._executions:
+                sut_node = sut_nodes.get(execution.config.system_under_test_node.name)
+                tg_node = tg_nodes.get(execution.config.traffic_generator_node.name)
 
                 try:
                     if not sut_node:
-                        sut_node = SutNode(execution.system_under_test_node)
+                        sut_node = SutNode(execution.config.system_under_test_node)
                         sut_nodes[sut_node.name] = sut_node
                     if not tg_node:
-                        tg_node = TGNode(execution.traffic_generator_node)
+                        tg_node = TGNode(execution.config.traffic_generator_node)
                         tg_nodes[tg_node.name] = tg_node
                     self._result.update_setup(Result.PASS)
                 except Exception as e:
-                    failed_node = execution.system_under_test_node.name
+                    failed_node = execution.config.system_under_test_node.name
                     if sut_node:
-                        failed_node = execution.traffic_generator_node.name
+                        failed_node = execution.config.traffic_generator_node.name
                     self._logger.exception(
                         f"The Creation of node {failed_node} failed."
                     )
@@ -100,29 +140,34 @@ def _run_execution(
         self,
         sut_node: SutNode,
         tg_node: TGNode,
-        execution: ExecutionConfiguration,
+        execution: Execution,
     ) -> None:
         """
         Run the given execution. This involves running the execution setup as well as
         running all build targets in the given execution.
         """
         self._logger.info(
-            f"Running execution with SUT '{execution.system_under_test_node.name}'."
+            "Running execution with SUT "
+            f"'{execution.config.system_under_test_node.name}'."
         )
         execution_result = self._result.add_execution(sut_node.config)
         execution_result.add_sut_info(sut_node.node_info)
 
         try:
-            sut_node.set_up_execution(execution)
+            sut_node.set_up_execution(execution.config)
             execution_result.update_setup(Result.PASS)
         except Exception as e:
             self._logger.exception("Execution setup failed.")
             execution_result.update_setup(Result.FAIL, e)
 
         else:
-            for build_target in execution.build_targets:
+            for build_target in execution.config.build_targets:
                 self._run_build_target(
-                    sut_node, tg_node, build_target, execution, execution_result
+                    sut_node,
+                    tg_node,
+                    build_target,
+                    execution,
+                    execution_result,
                 )
 
         finally:
@@ -138,7 +183,7 @@ def _run_build_target(
         sut_node: SutNode,
         tg_node: TGNode,
         build_target: BuildTargetConfiguration,
-        execution: ExecutionConfiguration,
+        execution: Execution,
         execution_result: ExecutionResult,
     ) -> None:
         """
@@ -171,7 +216,7 @@ def _run_test_suites(
         self,
         sut_node: SutNode,
         tg_node: TGNode,
-        execution: ExecutionConfiguration,
+        execution: Execution,
         build_target_result: BuildTargetResult,
     ) -> None:
         """
@@ -180,16 +225,18 @@ def _run_test_suites(
         If no subset is specified, run all test cases.
         """
         end_build_target = False
-        if not execution.skip_smoke_tests:
-            execution.test_suites[:0] = [TestSuiteConfig.from_dict("smoke_tests")]
-        for test_suite_config in execution.test_suites:
+        for test_suite_setup in execution.test_suite_setups:
             try:
                 self._run_test_suite(
-                    sut_node, tg_node, execution, build_target_result, test_suite_config
+                    sut_node,
+                    tg_node,
+                    test_suite_setup,
+                    build_target_result,
                 )
             except BlockingTestSuiteError as e:
                 self._logger.exception(
-                    f"An error occurred within {test_suite_config.test_suite}. "
+                    "An error occurred within "
+                    f"{test_suite_setup.test_suite.__name__}. "
                     "Skipping build target..."
                 )
                 self._result.add_error(e)
@@ -202,14 +249,10 @@ def _run_test_suite(
         self,
         sut_node: SutNode,
         tg_node: TGNode,
-        execution: ExecutionConfiguration,
+        test_suite_setup: TestSuiteSetup,
         build_target_result: BuildTargetResult,
-        test_suite_config: TestSuiteConfig,
     ) -> None:
         """Runs a single test suite.
-        Setup, execute and teardown the whole suite.
-        Suite execution consists of running all test cases scheduled to be executed.
-        A test cast run consists of setup, execution and teardown of said test case.
 
         Args:
             sut_node: Node to run tests on.
@@ -220,84 +263,67 @@ def _run_test_suite(
         Raises:
             BlockingTestSuiteError: If a test suite that was marked as blocking fails.
         """
+        test_suite = test_suite_setup.test_suite(sut_node, tg_node)
+        test_suite_name = test_suite_setup.test_suite.__name__
+        test_suite_result = build_target_result.add_test_suite(test_suite_name)
         try:
-            full_suite_path = f"tests.TestSuite_{test_suite_config.test_suite}"
-            test_suite_classes = get_test_suites(full_suite_path)
-            suites_str = ", ".join((x.__name__ for x in test_suite_classes))
-            self._logger.debug(
-                f"Found test suites '{suites_str}' in '{full_suite_path}'."
-            )
+            self._logger.info(f"Starting test suite setup: {test_suite_name}")
+            test_suite.set_up_suite()
+            test_suite_result.update_setup(Result.PASS)
+            self._logger.info(f"Test suite setup successful: {test_suite_name}")
         except Exception as e:
-            self._logger.exception("An error occurred when searching for test suites.")
-            self._result.update_setup(Result.ERROR, e)
+            self._logger.exception(f"Test suite setup ERROR: {test_suite_name}")
+            test_suite_result.update_setup(Result.ERROR, e)
 
         else:
-            for test_suite_class in test_suite_classes:
-                test_suite = test_suite_class(
-                    sut_node, tg_node, test_suite_config.test_cases
-                )
-
-                test_suite_name = test_suite.__class__.__name__
-                test_suite_result = build_target_result.add_test_suite(test_suite_name)
-                try:
-                    self._logger.info(f"Starting test suite setup: {test_suite_name}")
-                    test_suite.set_up_suite()
-                    test_suite_result.update_setup(Result.PASS)
-                    self._logger.info(f"Test suite setup successful: {test_suite_name}")
-                except Exception as e:
-                    self._logger.exception(f"Test suite setup ERROR: {test_suite_name}")
-                    test_suite_result.update_setup(Result.ERROR, e)
-
-                else:
-                    self._execute_test_suite(
-                        execution.func, test_suite, test_suite_result
-                    )
+            self._execute_test_suite(
+                test_suite,
+                test_suite_setup.test_cases,
+                test_suite_result,
+            )
 
-                finally:
-                    try:
-                        test_suite.tear_down_suite()
-                        sut_node.kill_cleanup_dpdk_apps()
-                        test_suite_result.update_teardown(Result.PASS)
-                    except Exception as e:
-                        self._logger.exception(
-                            f"Test suite teardown ERROR: {test_suite_name}"
-                        )
-                        self._logger.warning(
-                            f"Test suite '{test_suite_name}' teardown failed, "
-                            f"the next test suite may be affected."
-                        )
-                        test_suite_result.update_setup(Result.ERROR, e)
-                    if (
-                        len(test_suite_result.get_errors()) > 0
-                        and test_suite.is_blocking
-                    ):
-                        raise BlockingTestSuiteError(test_suite_name)
+        finally:
+            try:
+                test_suite.tear_down_suite()
+                sut_node.kill_cleanup_dpdk_apps()
+                test_suite_result.update_teardown(Result.PASS)
+            except Exception as e:
+                self._logger.exception(f"Test suite teardown ERROR: {test_suite_name}")
+                self._logger.warning(
+                    f"Test suite '{test_suite_name}' teardown failed, "
+                    "the next test suite may be affected."
+                )
+                test_suite_result.update_setup(Result.ERROR, e)
+            if len(test_suite_result.get_errors()) > 0 and test_suite.is_blocking:
+                raise BlockingTestSuiteError(test_suite_name)
 
     def _execute_test_suite(
-        self, func: bool, test_suite: TestSuite, test_suite_result: TestSuiteResult
+        self,
+        test_suite: TestSuite,
+        test_cases: list[MethodType],
+        test_suite_result: TestSuiteResult,
     ) -> None:
         """
         Execute all test cases scheduled to be executed in this suite.
         """
-        if func:
-            for test_case_method in test_suite._get_functional_test_cases():
-                test_case_name = test_case_method.__name__
-                test_case_result = test_suite_result.add_test_case(test_case_name)
-                all_attempts = SETTINGS.re_run + 1
-                attempt_nr = 1
-                self._run_test_case(test_suite, test_case_method, test_case_result)
-                while not test_case_result and attempt_nr < all_attempts:
-                    attempt_nr += 1
-                    self._logger.info(
-                        f"Re-running FAILED test case '{test_case_name}'. "
-                        f"Attempt number {attempt_nr} out of {all_attempts}."
-                    )
-                    self._run_test_case(test_suite, test_case_method, test_case_result)
+        for test_case_method in test_cases:
+            test_case_name = test_case_method.__name__
+            test_case_result = test_suite_result.add_test_case(test_case_name)
+            all_attempts = SETTINGS.re_run + 1
+            attempt_nr = 1
+            self._run_test_case(test_case_method, test_suite, test_case_result)
+            while not test_case_result and attempt_nr < all_attempts:
+                attempt_nr += 1
+                self._logger.info(
+                    f"Re-running FAILED test case '{test_case_name}'. "
+                    f"Attempt number {attempt_nr} out of {all_attempts}."
+                )
+                self._run_test_case(test_case_method, test_suite, test_case_result)
 
     def _run_test_case(
         self,
-        test_suite: TestSuite,
         test_case_method: MethodType,
+        test_suite: TestSuite,
         test_case_result: TestCaseResult,
     ) -> None:
         """
@@ -305,7 +331,6 @@ def _run_test_case(
         Exceptions are caught and recorded in logs and results.
         """
         test_case_name = test_case_method.__name__
-
         try:
             # run set_up function for each case
             test_suite.set_up_test_case()
@@ -319,7 +344,7 @@ def _run_test_case(
 
         else:
             # run test case if setup was successful
-            self._execute_test_case(test_case_method, test_case_result)
+            self._execute_test_case(test_case_method, test_suite, test_case_result)
 
         finally:
             try:
@@ -335,7 +360,10 @@ def _run_test_case(
                 test_case_result.update(Result.ERROR)
 
     def _execute_test_case(
-        self, test_case_method: MethodType, test_case_result: TestCaseResult
+        self,
+        test_case_method: MethodType,
+        test_suite: TestSuite,
+        test_case_result: TestCaseResult,
     ) -> None:
         """
         Execute one test case and handle failures.
@@ -343,7 +371,7 @@ def _execute_test_case(
         test_case_name = test_case_method.__name__
         try:
             self._logger.info(f"Starting test case execution: {test_case_name}")
-            test_case_method()
+            test_case_method(test_suite)
             test_case_result.update(Result.PASS)
             self._logger.info(f"Test case execution PASSED: {test_case_name}")
 
@@ -371,3 +399,92 @@ def _exit_dts(self) -> None:
 
         logging.shutdown()
         sys.exit(self._result.get_return_code())
+
+
+def create_executions(
+    execution_configs: list[ExecutionConfiguration],
+) -> list[Execution]:
+    executions: list[Execution] = []
+    for execution_config in execution_configs:
+        test_suite_setups: list[TestSuiteSetup] = []
+
+        for test_suite_config in execution_config.test_suites:
+            testsuite_module_path = f"tests.TestSuite_{test_suite_config.test_suite}"
+            try:
+                suite_module = importlib.import_module(testsuite_module_path)
+            except ModuleNotFoundError as e:
+                raise ConfigurationError(
+                    f"Test suite '{testsuite_module_path}' not found."
+                ) from e
+
+            test_suite = _get_suite_class(suite_module, test_suite_config.test_suite)
+
+            test_cases_to_run = test_suite_config.test_cases
+            test_cases_to_run.extend(SETTINGS.test_cases)
+
+            test_cases = []
+            if execution_config.func:
+                # add functional test cases
+                test_cases.extend(
+                    _get_test_cases(test_suite, r"test_(?!perf_)", test_cases_to_run)
+                )
+
+            if execution_config.perf:
+                # add performance test cases
+                test_cases.extend(
+                    _get_test_cases(test_suite, r"test_perf_", test_cases_to_run)
+                )
+
+            test_suite_setups.append(
+                TestSuiteSetup(test_suite=test_suite, test_cases=test_cases)
+            )
+
+        executions.append(
+            Execution(
+                config=execution_config,
+                test_suite_setups=test_suite_setups,
+            )
+        )
+
+    return executions
+
+
+def _get_suite_class(suite_module: ModuleType, suite_name: str) -> type[TestSuite]:
+    def is_test_suite(object) -> bool:
+        try:
+            if issubclass(object, TestSuite) and object is not TestSuite:
+                return True
+        except TypeError:
+            return False
+        return False
+
+    suite_name_regex = suite_name.replace("_", "").lower()
+    for class_name, suite_class in inspect.getmembers(suite_module, is_test_suite):
+        if not class_name.startswith("Test"):
+            continue
+
+        if suite_name_regex == class_name[4:].lower():
+            return suite_class
+    raise ConfigurationError(
+        f"Cannot find valid test suite in {suite_module.__name__}."
+    )
+
+
+def _get_test_cases(
+    suite_class: type[TestSuite], test_case_regex: str, test_cases_to_run: list[str]
+) -> list[MethodType]:
+    def should_be_executed(test_case_name: str) -> bool:
+        match = bool(re.match(test_case_regex, test_case_name))
+        if test_cases_to_run:
+            return match and test_case_name in test_cases_to_run
+
+        return match
+
+    test_cases = []
+    for test_case_name, test_case_method in inspect.getmembers(
+        suite_class, inspect.isfunction
+    ):
+        if should_be_executed(test_case_name):
+            test_cases.append(test_case_method)
+
+    return test_cases
diff --git a/dts/framework/test_suite.py b/dts/framework/test_suite.py
index e96305deb0..e73206993d 100644
--- a/dts/framework/test_suite.py
+++ b/dts/framework/test_suite.py
@@ -6,20 +6,15 @@
 Base class for creating DTS test cases.
 """
 
-import importlib
-import inspect
-import re
 from ipaddress import IPv4Interface, IPv6Interface, ip_interface
-from types import MethodType
 from typing import Union
 
 from scapy.layers.inet import IP  # type: ignore[import]
 from scapy.layers.l2 import Ether  # type: ignore[import]
 from scapy.packet import Packet, Padding  # type: ignore[import]
 
-from .exception import ConfigurationError, TestCaseVerifyError
+from .exception import TestCaseVerifyError
 from .logger import DTSLOG, getLogger
-from .settings import SETTINGS
 from .testbed_model import SutNode, TGNode
 from .testbed_model.hw.port import Port, PortLink
 from .utils import get_packet_summaries
@@ -47,7 +42,6 @@ class TestSuite(object):
     tg_node: TGNode
     is_blocking = False
     _logger: DTSLOG
-    _test_cases_to_run: list[str]
     _port_links: list[PortLink]
     _sut_port_ingress: Port
     _sut_port_egress: Port
@@ -62,13 +56,10 @@ def __init__(
         self,
         sut_node: SutNode,
         tg_node: TGNode,
-        test_cases_to_run: list[str],
     ):
         self.sut_node = sut_node
         self.tg_node = tg_node
         self._logger = getLogger(self.__class__.__name__)
-        self._test_cases_to_run = test_cases_to_run
-        self._test_cases_to_run.extend(SETTINGS.test_cases)
         self._port_links = []
         self._process_links()
         self._sut_port_ingress, self._tg_port_egress = (
@@ -268,51 +259,3 @@ def _verify_l3_packet(self, received_packet: IP, expected_packet: IP) -> bool:
         if received_packet.src != expected_packet.src or received_packet.dst != expected_packet.dst:
             return False
         return True
-
-    def _get_functional_test_cases(self) -> list[MethodType]:
-        """
-        Get all functional test cases.
-        """
-        return self._get_test_cases(r"test_(?!perf_)")
-
-    def _get_test_cases(self, test_case_regex: str) -> list[MethodType]:
-        """
-        Return a list of test cases matching test_case_regex.
-        """
-        self._logger.debug(f"Searching for test cases in {self.__class__.__name__}.")
-        filtered_test_cases = []
-        for test_case_name, test_case in inspect.getmembers(self, inspect.ismethod):
-            if self._should_be_executed(test_case_name, test_case_regex):
-                filtered_test_cases.append(test_case)
-        cases_str = ", ".join((x.__name__ for x in filtered_test_cases))
-        self._logger.debug(f"Found test cases '{cases_str}' in {self.__class__.__name__}.")
-        return filtered_test_cases
-
-    def _should_be_executed(self, test_case_name: str, test_case_regex: str) -> bool:
-        """
-        Check whether the test case should be executed.
-        """
-        match = bool(re.match(test_case_regex, test_case_name))
-        if self._test_cases_to_run:
-            return match and test_case_name in self._test_cases_to_run
-
-        return match
-
-
-def get_test_suites(testsuite_module_path: str) -> list[type[TestSuite]]:
-    def is_test_suite(object) -> bool:
-        try:
-            if issubclass(object, TestSuite) and object is not TestSuite:
-                return True
-        except TypeError:
-            return False
-        return False
-
-    try:
-        testcase_module = importlib.import_module(testsuite_module_path)
-    except ModuleNotFoundError as e:
-        raise ConfigurationError(f"Test suite '{testsuite_module_path}' not found.") from e
-    return [
-        test_suite_class
-        for _, test_suite_class in inspect.getmembers(testcase_module, is_test_suite)
-    ]
diff --git a/dts/tests/TestSuite_smoke_tests.py b/dts/tests/TestSuite_smoke_tests.py
index 8958f58dac..aa4bae5b17 100644
--- a/dts/tests/TestSuite_smoke_tests.py
+++ b/dts/tests/TestSuite_smoke_tests.py
@@ -10,7 +10,7 @@
 from framework.utils import REGEX_FOR_PCI_ADDRESS
 
 
-class SmokeTests(TestSuite):
+class TestSmokeTests(TestSuite):
     is_blocking = True
     # dicts in this list are expected to have two keys:
     # "pci_address" and "current_driver"
-- 
2.34.1


  parent reply	other threads:[~2023-12-20 10:34 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-20 10:33 [RFC PATCH v1 0/5] test case blocking and logging Juraj Linkeš
2023-12-20 10:33 ` [RFC PATCH v1 1/5] dts: convert dts.py methods to class Juraj Linkeš
2023-12-20 10:33 ` [RFC PATCH v1 2/5] dts: move test suite execution logic to DTSRunner Juraj Linkeš
2023-12-20 10:33 ` Juraj Linkeš [this message]
2023-12-20 10:33 ` [RFC PATCH v1 4/5] dts: block all testcases when earlier setup fails Juraj Linkeš
2023-12-20 10:33 ` [RFC PATCH v1 5/5] dts: refactor logging configuration Juraj Linkeš
2024-01-08 18:47 ` [RFC PATCH v1 0/5] test case blocking and logging Jeremy Spewock
2024-02-06 14:57 ` [PATCH v2 0/7] " Juraj Linkeš
2024-02-06 14:57   ` [PATCH v2 1/7] dts: convert dts.py methods to class Juraj Linkeš
2024-02-06 14:57   ` [PATCH v2 2/7] dts: move test suite execution logic to DTSRunner Juraj Linkeš
2024-02-06 14:57   ` [PATCH v2 3/7] dts: filter test suites in executions Juraj Linkeš
2024-02-12 16:44     ` Jeremy Spewock
2024-02-14  9:55       ` Juraj Linkeš
2024-02-06 14:57   ` [PATCH v2 4/7] dts: reorganize test result Juraj Linkeš
2024-02-06 14:57   ` [PATCH v2 5/7] dts: block all test cases when earlier setup fails Juraj Linkeš
2024-02-06 14:57   ` [PATCH v2 6/7] dts: refactor logging configuration Juraj Linkeš
2024-02-12 16:45     ` Jeremy Spewock
2024-02-14  7:49       ` Juraj Linkeš
2024-02-14 16:51         ` Jeremy Spewock
2024-02-06 14:57   ` [PATCH v2 7/7] dts: improve test suite and case filtering Juraj Linkeš
2024-02-23  7:54 ` [PATCH v3 0/7] test case blocking and logging Juraj Linkeš
2024-02-23  7:54   ` [PATCH v3 1/7] dts: convert dts.py methods to class Juraj Linkeš
2024-02-23  7:54   ` [PATCH v3 2/7] dts: move test suite execution logic to DTSRunner Juraj Linkeš
2024-02-23  7:54   ` [PATCH v3 3/7] dts: filter test suites in executions Juraj Linkeš
2024-02-27 21:21     ` Jeremy Spewock
2024-02-28  9:16       ` Juraj Linkeš
2024-02-23  7:54   ` [PATCH v3 4/7] dts: reorganize test result Juraj Linkeš
2024-02-23  7:55   ` [PATCH v3 5/7] dts: block all test cases when earlier setup fails Juraj Linkeš
2024-02-23  7:55   ` [PATCH v3 6/7] dts: refactor logging configuration Juraj Linkeš
2024-02-23  7:55   ` [PATCH v3 7/7] dts: improve test suite and case filtering Juraj Linkeš
2024-02-27 21:24   ` [PATCH v3 0/7] test case blocking and logging Jeremy Spewock
2024-03-01 10:55 ` [PATCH v4 " Juraj Linkeš
2024-03-01 10:55   ` [PATCH v4 1/7] dts: convert dts.py methods to class Juraj Linkeš
2024-03-01 10:55   ` [PATCH v4 2/7] dts: move test suite execution logic to DTSRunner Juraj Linkeš
2024-03-01 10:55   ` [PATCH v4 3/7] dts: filter test suites in executions Juraj Linkeš
2024-03-01 10:55   ` [PATCH v4 4/7] dts: reorganize test result Juraj Linkeš
2024-03-01 10:55   ` [PATCH v4 5/7] dts: block all test cases when earlier setup fails Juraj Linkeš
2024-03-01 10:55   ` [PATCH v4 6/7] dts: refactor logging configuration Juraj Linkeš
2024-03-01 10:55   ` [PATCH v4 7/7] dts: improve test suite and case filtering Juraj Linkeš
2024-03-01 17:41     ` Jeremy Spewock
2024-03-01 17:43       ` Jeremy Spewock
2024-03-07 11:04         ` Thomas Monjalon
2024-03-01 16:11   ` [PATCH v4 0/7] test case blocking and logging Patrick Robb
2024-03-07 14:55   ` Thomas Monjalon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231220103331.60888-4-juraj.linkes@pantheon.tech \
    --to=juraj.linkes@pantheon.tech \
    --cc=Honnappa.Nagarahalli@arm.com \
    --cc=Luca.Vizzarro@arm.com \
    --cc=dev@dpdk.org \
    --cc=jspewock@iol.unh.edu \
    --cc=paul.szczepanek@arm.com \
    --cc=probb@iol.unh.edu \
    --cc=thomas@monjalon.net \
    --cc=yoan.picchi@foss.arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).