DPDK patches and discussions
 help / color / mirror / Atom feed
From: jspewock@iol.unh.edu
To: dev@dpdk.org
Cc: Jeremy Spewock <jspewock@iol.unh.edu>
Subject: [RFC v2 1/2] dts: add smoke tests
Date: Fri, 12 May 2023 15:25:43 -0400	[thread overview]
Message-ID: <20230512192540.401-3-jspewock@iol.unh.edu> (raw)
In-Reply-To: <20230512192540.401-2-jspewock@iol.unh.edu>

From: Jeremy Spewock <jspewock@iol.unh.edu>

Adds a new test suite for running smoke tests that verify general
configuration aspects of the system under test. If any of these tests
fail, the DTS execution terminates as part of a "fail-fast" model.

Signed-off-by: Jeremy Spewock <jspewock@iol.unh.edu>
---
 dts/conf.yaml                                 |  9 ++
 dts/framework/config/__init__.py              | 21 +++++
 dts/framework/config/conf_yaml_schema.json    | 32 ++++++-
 dts/framework/dts.py                          | 19 +++-
 dts/framework/exception.py                    | 11 +++
 dts/framework/remote_session/os_session.py    |  6 +-
 .../remote_session/remote/__init__.py         | 28 ++++++
 dts/framework/test_result.py                  | 13 ++-
 dts/framework/test_suite.py                   | 24 ++++-
 dts/framework/testbed_model/__init__.py       |  5 +
 .../interactive_apps/__init__.py              |  6 ++
 .../interactive_apps/interactive_command.py   | 57 +++++++++++
 .../interactive_apps/testpmd_driver.py        | 24 +++++
 dts/framework/testbed_model/node.py           |  2 +
 dts/framework/testbed_model/sut_node.py       |  6 ++
 dts/tests/TestSuite_smoke_tests.py            | 94 +++++++++++++++++++
 16 files changed, 348 insertions(+), 9 deletions(-)
 create mode 100644 dts/framework/testbed_model/interactive_apps/__init__.py
 create mode 100644 dts/framework/testbed_model/interactive_apps/interactive_command.py
 create mode 100644 dts/framework/testbed_model/interactive_apps/testpmd_driver.py
 create mode 100644 dts/tests/TestSuite_smoke_tests.py

diff --git a/dts/conf.yaml b/dts/conf.yaml
index a9bd8a3e..042ef954 100644
--- a/dts/conf.yaml
+++ b/dts/conf.yaml
@@ -10,13 +10,22 @@ executions:
         compiler_wrapper: ccache
     perf: false
     func: true
+    nics: #physical devices to be used for testing
+      - addresses:
+          - "0000:11:00.0"
+          - "0000:11:00.1"
+        driver: "i40e"
+    vdevs: #names of virtual devices to be used for testing
+      - "crypto_openssl"
     test_suites:
+      - smoke_tests
       - hello_world
     system_under_test: "SUT 1"
 nodes:
   - name: "SUT 1"
     hostname: sut1.change.me.localhost
     user: root
+    password: ""
     arch: x86_64
     os: linux
     lcores: ""
diff --git a/dts/framework/config/__init__.py b/dts/framework/config/__init__.py
index ebb0823f..f3b8b6e3 100644
--- a/dts/framework/config/__init__.py
+++ b/dts/framework/config/__init__.py
@@ -106,6 +106,21 @@ def from_dict(d: dict) -> "NodeConfiguration":
             hugepages=hugepage_config,
         )
 
+@dataclass(slots=True, frozen=True)
+class NICConfiguration:
+    addresses: list[str]
+    driver: str
+
+    @staticmethod
+    def from_dict(d:dict) -> "NICConfiguration":
+        return NICConfiguration(
+            addresses=[addr for addr in d.get("addresses", [])],
+            driver=d.get("driver")
+        )
+    @staticmethod
+    def from_list(l:list[dict]) -> list["NICConfiguration"]:
+        return [] + [NICConfiguration.from_dict(x) for x in l]
+
 
 @dataclass(slots=True, frozen=True)
 class BuildTargetConfiguration:
@@ -157,6 +172,8 @@ class ExecutionConfiguration:
     func: bool
     test_suites: list[TestSuiteConfig]
     system_under_test: NodeConfiguration
+    nics: list[NICConfiguration]
+    vdevs: list[str]
 
     @staticmethod
     def from_dict(d: dict, node_map: dict) -> "ExecutionConfiguration":
@@ -166,7 +183,9 @@ def from_dict(d: dict, node_map: dict) -> "ExecutionConfiguration":
         test_suites: list[TestSuiteConfig] = list(
             map(TestSuiteConfig.from_dict, d["test_suites"])
         )
+        nic_conf: NICConfiguration = NICConfiguration.from_list(d['nics'])
         sut_name = d["system_under_test"]
+        list_of_vdevs = d["vdevs"]
         assert sut_name in node_map, f"Unknown SUT {sut_name} in execution {d}"
 
         return ExecutionConfiguration(
@@ -174,7 +193,9 @@ def from_dict(d: dict, node_map: dict) -> "ExecutionConfiguration":
             perf=d["perf"],
             func=d["func"],
             test_suites=test_suites,
+            nics=nic_conf,
             system_under_test=node_map[sut_name],
+            vdevs=list_of_vdevs
         )
 
 
diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index ca2d4a1e..603859de 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -40,6 +40,18 @@
         "mscv"
       ]
     },
+    "single_nic" : {
+      "type":"object",
+      "description": "an object that holds nic information",
+      "properties": {
+        "addresses": {
+          "type":"array",
+          "items": {
+            "type":"string"
+          }
+        }
+      }
+    },
     "build_target": {
       "type": "object",
       "description": "Targets supported by DTS",
@@ -97,7 +109,8 @@
     "test_suite": {
       "type": "string",
       "enum": [
-        "hello_world"
+        "hello_world",
+        "smoke_tests"
       ]
     },
     "test_target": {
@@ -211,6 +224,23 @@
               ]
             }
           },
+          "nics": {
+            "type": "array",
+            "items": {
+              "oneOf": [
+                {
+                  "$ref": "#/definitions/single_nic"
+                }
+              ]
+            }
+          },
+          "vdevs": {
+            "description": "Names of vdevs to be used in execution",
+            "type": "array",
+            "items": {
+              "type":"string"
+            }
+          },
           "system_under_test": {
             "$ref": "#/definitions/node_name"
           }
diff --git a/dts/framework/dts.py b/dts/framework/dts.py
index 05022845..0d03e158 100644
--- a/dts/framework/dts.py
+++ b/dts/framework/dts.py
@@ -5,6 +5,8 @@
 
 import sys
 
+from .exception import BlockingTestSuiteError
+
 from .config import CONFIGURATION, BuildTargetConfiguration, ExecutionConfiguration
 from .logger import DTSLOG, getLogger
 from .test_result import BuildTargetResult, DTSResult, ExecutionResult, Result
@@ -49,6 +51,7 @@ def run_all() -> None:
                     nodes[sut_node.name] = sut_node
 
             if sut_node:
+                #SMOKE TEST EXECUTION GOES HERE!
                 _run_execution(sut_node, execution, result)
 
     except Exception as e:
@@ -118,7 +121,7 @@ def _run_build_target(
 
     try:
         sut_node.set_up_build_target(build_target)
-        result.dpdk_version = sut_node.dpdk_version
+        # result.dpdk_version = sut_node.dpdk_version
         build_target_result.update_setup(Result.PASS)
     except Exception as e:
         dts_logger.exception("Build target setup failed.")
@@ -146,6 +149,7 @@ def _run_suites(
     with possibly only a subset of test cases.
     If no subset is specified, run all test cases.
     """
+    end_execution = False
     for test_suite_config in execution.test_suites:
         try:
             full_suite_path = f"tests.TestSuite_{test_suite_config.test_suite}"
@@ -160,13 +164,24 @@ def _run_suites(
 
         else:
             for test_suite_class in test_suite_classes:
+                #HERE NEEDS CHANGING
                 test_suite = test_suite_class(
                     sut_node,
                     test_suite_config.test_cases,
                     execution.func,
                     build_target_result,
+                    sut_node._build_target_config,
+                    result
                 )
-                test_suite.run()
+                try:
+                    test_suite.run()
+                except BlockingTestSuiteError as e:
+                    dts_logger.exception("An error occurred within a blocking TestSuite, execution will now end.")
+                    result.add_error(e)
+                    end_execution = True
+        #if a blocking test failed and we need to bail out of suite executions
+        if end_execution:
+            break
 
 
 def _exit_dts() -> None:
diff --git a/dts/framework/exception.py b/dts/framework/exception.py
index ca353d98..4e3f63d1 100644
--- a/dts/framework/exception.py
+++ b/dts/framework/exception.py
@@ -25,6 +25,7 @@ class ErrorSeverity(IntEnum):
     SSH_ERR = 4
     DPDK_BUILD_ERR = 10
     TESTCASE_VERIFY_ERR = 20
+    BLOCKING_TESTSUITE_ERR = 25
 
 
 class DTSError(Exception):
@@ -144,3 +145,13 @@ def __init__(self, value: str):
 
     def __str__(self) -> str:
         return repr(self.value)
+
+class BlockingTestSuiteError(DTSError):
+    suite_name: str
+    severity: ClassVar[ErrorSeverity]  = ErrorSeverity.BLOCKING_TESTSUITE_ERR
+
+    def __init__(self, suite_name:str) -> None:
+        self.suite_name = suite_name
+
+    def __str__(self) -> str:
+        return f"Blocking suite {self.suite_name} failed."
diff --git a/dts/framework/remote_session/os_session.py b/dts/framework/remote_session/os_session.py
index 4c48ae25..22776bc1 100644
--- a/dts/framework/remote_session/os_session.py
+++ b/dts/framework/remote_session/os_session.py
@@ -12,7 +12,9 @@
 from framework.testbed_model import LogicalCore
 from framework.utils import EnvVarsDict, MesonArgs
 
-from .remote import CommandResult, RemoteSession, create_remote_session
+from .remote import CommandResult, RemoteSession, create_remote_session, create_interactive_session
+
+from paramiko import SSHClient
 
 
 class OSSession(ABC):
@@ -26,6 +28,7 @@ class OSSession(ABC):
     name: str
     _logger: DTSLOG
     remote_session: RemoteSession
+    _interactive_session: SSHClient
 
     def __init__(
         self,
@@ -37,6 +40,7 @@ def __init__(
         self.name = name
         self._logger = logger
         self.remote_session = create_remote_session(node_config, name, logger)
+        self._interactive_session = create_interactive_session(node_config, name, logger)
 
     def close(self, force: bool = False) -> None:
         """
diff --git a/dts/framework/remote_session/remote/__init__.py b/dts/framework/remote_session/remote/__init__.py
index 8a151221..abca8edc 100644
--- a/dts/framework/remote_session/remote/__init__.py
+++ b/dts/framework/remote_session/remote/__init__.py
@@ -9,8 +9,36 @@
 from .remote_session import CommandResult, RemoteSession
 from .ssh_session import SSHSession
 
+from paramiko import SSHClient, AutoAddPolicy
+from framework.utils import GREEN
 
 def create_remote_session(
     node_config: NodeConfiguration, name: str, logger: DTSLOG
 ) -> RemoteSession:
     return SSHSession(node_config, name, logger)
+
+def create_interactive_session(
+    node_config: NodeConfiguration, name: str, logger: DTSLOG
+) -> SSHClient:
+    """
+    Creates a paramiko SSH session that is designed to be used for interactive shells
+
+    This session is meant to be used on an "as needed" basis and may never be utilized
+    """
+    client: SSHClient = SSHClient()
+    client.set_missing_host_key_policy(AutoAddPolicy)
+    ip: str = node_config.hostname
+    logger.info(GREEN(f"Connecting to host {ip}"))
+    #Preset to 22 because paramiko doesn't accept None
+    port: int = 22
+    if ":" in node_config.hostname:
+            ip, port = node_config.hostname.split(":")
+            port = int(port)
+    client.connect(
+        ip,
+        username=node_config.user,
+        port=port,
+        password=node_config.password or "",
+        timeout=20 if port else 10
+    )
+    return client
diff --git a/dts/framework/test_result.py b/dts/framework/test_result.py
index 74391982..77202ae2 100644
--- a/dts/framework/test_result.py
+++ b/dts/framework/test_result.py
@@ -8,6 +8,7 @@
 import os.path
 from collections.abc import MutableSequence
 from enum import Enum, auto
+from typing import Dict
 
 from .config import (
     OS,
@@ -67,12 +68,13 @@ class Statistics(dict):
     Using a dict provides a convenient way to format the data.
     """
 
-    def __init__(self, dpdk_version):
+    def __init__(self, output_info: Dict[str, str] | None):
         super(Statistics, self).__init__()
         for result in Result:
             self[result.name] = 0
         self["PASS RATE"] = 0.0
-        self["DPDK VERSION"] = dpdk_version
+        if output_info:
+            for info_key, info_val in output_info.items(): self[info_key] = info_val
 
     def __iadd__(self, other: Result) -> "Statistics":
         """
@@ -258,6 +260,7 @@ class DTSResult(BaseResult):
     """
 
     dpdk_version: str | None
+    output: dict | None
     _logger: DTSLOG
     _errors: list[Exception]
     _return_code: ErrorSeverity
@@ -267,6 +270,7 @@ class DTSResult(BaseResult):
     def __init__(self, logger: DTSLOG):
         super(DTSResult, self).__init__()
         self.dpdk_version = None
+        self.output = None
         self._logger = logger
         self._errors = []
         self._return_code = ErrorSeverity.NO_ERR
@@ -296,7 +300,10 @@ def process(self) -> None:
             for error in self._errors:
                 self._logger.debug(repr(error))
 
-        self._stats_result = Statistics(self.dpdk_version)
+        self._stats_result = Statistics(self.output)
+        #add information gathered from the smoke tests to the statistics
+        # for info_key, info_val in smoke_test_info.items(): self._stats_result[info_key] = info_val
+        # print(self._stats_result)
         self.add_stats(self._stats_result)
         with open(self._stats_filename, "w+") as stats_file:
             stats_file.write(str(self._stats_result))
diff --git a/dts/framework/test_suite.py b/dts/framework/test_suite.py
index 0705f38f..1518fb8a 100644
--- a/dts/framework/test_suite.py
+++ b/dts/framework/test_suite.py
@@ -10,11 +10,14 @@
 import inspect
 import re
 from types import MethodType
+from typing import Dict
 
-from .exception import ConfigurationError, SSHTimeoutError, TestCaseVerifyError
+from .config import BuildTargetConfiguration
+
+from .exception import BlockingTestSuiteError, ConfigurationError, SSHTimeoutError, TestCaseVerifyError
 from .logger import DTSLOG, getLogger
 from .settings import SETTINGS
-from .test_result import BuildTargetResult, Result, TestCaseResult, TestSuiteResult
+from .test_result import BuildTargetResult, DTSResult, Result, TestCaseResult, TestSuiteResult
 from .testbed_model import SutNode
 
 
@@ -37,10 +40,12 @@ class TestSuite(object):
     """
 
     sut_node: SutNode
+    is_blocking = False
     _logger: DTSLOG
     _test_cases_to_run: list[str]
     _func: bool
     _result: TestSuiteResult
+    _dts_result: DTSResult
 
     def __init__(
         self,
@@ -48,6 +53,8 @@ def __init__(
         test_cases: list[str],
         func: bool,
         build_target_result: BuildTargetResult,
+        build_target_conf: BuildTargetConfiguration,
+        dts_result: DTSResult
     ):
         self.sut_node = sut_node
         self._logger = getLogger(self.__class__.__name__)
@@ -55,6 +62,8 @@ def __init__(
         self._test_cases_to_run.extend(SETTINGS.test_cases)
         self._func = func
         self._result = build_target_result.add_test_suite(self.__class__.__name__)
+        self.build_target_info = build_target_conf
+        self._dts_result = dts_result
 
     def set_up_suite(self) -> None:
         """
@@ -118,6 +127,9 @@ def run(self) -> None:
                     f"the next test suite may be affected."
                 )
                 self._result.update_setup(Result.ERROR, e)
+            if len(self._result.get_errors()) > 0 and self.is_blocking:
+                raise BlockingTestSuiteError(test_suite_name)
+            
 
     def _execute_test_suite(self) -> None:
         """
@@ -137,6 +149,7 @@ def _execute_test_suite(self) -> None:
                         f"Attempt number {attempt_nr} out of {all_attempts}."
                     )
                     self._run_test_case(test_case_method, test_case_result)
+                
 
     def _get_functional_test_cases(self) -> list[MethodType]:
         """
@@ -232,6 +245,11 @@ def _execute_test_case(
             test_case_result.update(Result.SKIP)
             raise KeyboardInterrupt("Stop DTS")
 
+    def write_to_statistics_file(self, output: Dict[str, str]):
+        if self._dts_result.output != None:
+            self._dts_result.output.update(output)
+        else:
+            self._dts_result.output = output
 
 def get_test_suites(testsuite_module_path: str) -> list[type[TestSuite]]:
     def is_test_suite(object) -> bool:
@@ -252,3 +270,5 @@ def is_test_suite(object) -> bool:
         test_suite_class
         for _, test_suite_class in inspect.getmembers(testcase_module, is_test_suite)
     ]
+
+
diff --git a/dts/framework/testbed_model/__init__.py b/dts/framework/testbed_model/__init__.py
index f54a9470..63f17cc3 100644
--- a/dts/framework/testbed_model/__init__.py
+++ b/dts/framework/testbed_model/__init__.py
@@ -20,3 +20,8 @@
 )
 from .node import Node
 from .sut_node import SutNode
+
+from .interactive_apps import (
+    InteractiveScriptHandler,
+    TestpmdDriver
+)
diff --git a/dts/framework/testbed_model/interactive_apps/__init__.py b/dts/framework/testbed_model/interactive_apps/__init__.py
new file mode 100644
index 00000000..0382d7e0
--- /dev/null
+++ b/dts/framework/testbed_model/interactive_apps/__init__.py
@@ -0,0 +1,6 @@
+from .interactive_command import (
+    InteractiveScriptHandler
+)
+from .testpmd_driver import (
+    TestpmdDriver
+)
\ No newline at end of file
diff --git a/dts/framework/testbed_model/interactive_apps/interactive_command.py b/dts/framework/testbed_model/interactive_apps/interactive_command.py
new file mode 100644
index 00000000..7467911b
--- /dev/null
+++ b/dts/framework/testbed_model/interactive_apps/interactive_command.py
@@ -0,0 +1,57 @@
+# import paramiko
+from paramiko import SSHClient, Channel, channel
+from framework.settings import SETTINGS
+
+class InteractiveScriptHandler:
+
+    _ssh_client: SSHClient
+    _stdin: channel.ChannelStdinFile
+    _ssh_channel: Channel
+
+    def __init__(self, ssh_client: SSHClient, timeout:float = SETTINGS.timeout) -> None:
+        self._ssh_client = ssh_client
+        self._ssh_channel = self._ssh_client.invoke_shell()
+        self._stdin = self._ssh_channel.makefile_stdin("wb")
+        self._ssh_channel.settimeout(timeout)
+
+    def send_command(self, command:str) -> None:
+        """
+        Send command to channel without recording output.
+
+        This method will not verify any input or output, it will
+        simply assume the command succeeded
+        """
+        self._stdin.write(command + '\n')
+        self._stdin.flush()
+
+    def send_command_get_output(self, command:str, expect:str) -> str:
+        """
+        Send a command and get all output before the expected ending string.
+
+        **NOTE**
+        Lines that expect input are not included in the stdout buffer so they cannot be
+        used for expect. For example, if you were prompted to log into something
+        with a username and password, you cannot expect "username:" because it wont
+        yet be in the stdout buffer. A work around for this could be consuming an
+        extra newline character to force the current prompt into the stdout buffer.
+
+        *Return*
+            All output before expected string
+        """
+        stdout = self._ssh_channel.makefile("r")
+        self._stdin.write(command + '\n')
+        self._stdin.flush()
+        out:str = ""
+        for line in stdout:
+            out += str(line)
+            if expect in str(line):
+                break
+        stdout.close() #close the buffer to flush the output
+        return out
+
+    def close(self):
+        self._stdin.close()
+        self._ssh_channel.close()
+
+    def __del__(self):
+        self.close()
diff --git a/dts/framework/testbed_model/interactive_apps/testpmd_driver.py b/dts/framework/testbed_model/interactive_apps/testpmd_driver.py
new file mode 100644
index 00000000..1993eae6
--- /dev/null
+++ b/dts/framework/testbed_model/interactive_apps/testpmd_driver.py
@@ -0,0 +1,24 @@
+from framework.testbed_model.interactive_apps import InteractiveScriptHandler
+
+from pathlib import PurePath
+
+class TestpmdDriver:
+    prompt:str = "testpmd>"
+    interactive_handler: InteractiveScriptHandler
+
+    def __init__(self, handler: InteractiveScriptHandler, dpdk_build_dir:PurePath, eal_flags:str = "", cmd_line_options:str = "") -> None:
+        """
+        Sets the handler to drive the SSH session and starts testpmd
+        """
+        self.interactive_handler = handler
+        # self.interactive_handler.send_command("sudo su")
+        # self.interactive_handler.send_command("cd /root/testpmd-testing/dpdk/build")
+        self.interactive_handler.send_command_get_output(f"{dpdk_build_dir}/app/dpdk-testpmd {eal_flags} -- -i {cmd_line_options}\n", self.prompt)
+
+    def send_command(self, command:str, expect:str = prompt) -> str:
+        """
+        Specific way of handling the command for testpmd
+
+        An extra newline character is consumed in order to force the current line into the stdout buffer
+        """
+        return self.interactive_handler.send_command_get_output(command + "\n", expect)
\ No newline at end of file
diff --git a/dts/framework/testbed_model/node.py b/dts/framework/testbed_model/node.py
index d48fafe6..c5147e0e 100644
--- a/dts/framework/testbed_model/node.py
+++ b/dts/framework/testbed_model/node.py
@@ -40,6 +40,7 @@ class Node(object):
     lcores: list[LogicalCore]
     _logger: DTSLOG
     _other_sessions: list[OSSession]
+    _execution_config: ExecutionConfiguration
 
     def __init__(self, node_config: NodeConfiguration):
         self.config = node_config
@@ -64,6 +65,7 @@ def set_up_execution(self, execution_config: ExecutionConfiguration) -> None:
         """
         self._setup_hugepages()
         self._set_up_execution(execution_config)
+        self._execution_config = execution_config
 
     def _set_up_execution(self, execution_config: ExecutionConfiguration) -> None:
         """
diff --git a/dts/framework/testbed_model/sut_node.py b/dts/framework/testbed_model/sut_node.py
index 2b2b50d9..8c39a66d 100644
--- a/dts/framework/testbed_model/sut_node.py
+++ b/dts/framework/testbed_model/sut_node.py
@@ -14,6 +14,7 @@
 
 from .hw import LogicalCoreCount, LogicalCoreList, VirtualDevice
 from .node import Node
+from .interactive_apps import InteractiveScriptHandler
 
 
 class SutNode(Node):
@@ -261,6 +262,11 @@ def run_dpdk_app(
         return self.main_session.send_command(
             f"{app_path} {eal_args}", timeout, verify=True
         )
+    def create_interactive_session_handler(self) -> InteractiveScriptHandler:
+        """
+        Create a handler for interactive sessions
+        """
+        return InteractiveScriptHandler(self.main_session._interactive_session)
 
 
 class EalParameters(object):
diff --git a/dts/tests/TestSuite_smoke_tests.py b/dts/tests/TestSuite_smoke_tests.py
new file mode 100644
index 00000000..bacf289d
--- /dev/null
+++ b/dts/tests/TestSuite_smoke_tests.py
@@ -0,0 +1,94 @@
+from framework.test_suite import TestSuite
+from framework.testbed_model.sut_node import SutNode
+
+from framework.testbed_model.interactive_apps import TestpmdDriver
+
+def get_compiler_version(compiler_name: str, sut_node: SutNode) -> str:
+    match compiler_name:
+            case "gcc":
+                return sut_node.main_session.send_command(f"{compiler_name} --version", 60).stdout.split("\n")[0]
+            case "clang":
+                return sut_node.main_session.send_command(f"{compiler_name} --version", 60).stdout.split("\n")[0]
+            case "msvc":
+                return sut_node.main_session.send_command(f"cl", 60).stdout
+            case "icc":
+                return sut_node.main_session.send_command(f"{compiler_name} -V", 60).stdout
+
+class SmokeTests(TestSuite):
+    is_blocking = True
+
+    def set_up_suite(self) -> None:
+        """
+        Setup:
+            build all DPDK
+        """
+        self.dpdk_build_dir_path = self.sut_node.remote_dpdk_build_dir
+    
+
+    def test_unit_tests(self) -> None:
+        """
+        Test:
+            run the fast-test unit-test suite through meson
+        """
+        self.sut_node.main_session.send_command(f"meson test -C {self.dpdk_build_dir_path} --suite fast-tests", 300)
+
+    def test_driver_tests(self) -> None:
+        """
+        Test:
+            run the driver-test unit-test suite through meson
+        """
+        list_of_vdevs = ""
+        for dev in self.sut_node._execution_config.vdevs:
+            list_of_vdevs += f"{dev},"
+        print(list_of_vdevs)
+        if len(list_of_vdevs) > 0:
+            self.sut_node.main_session.send_command(f"meson test -C {self.dpdk_build_dir_path} --suite driver-tests --test-args \"--vdev {list_of_vdevs}\"", 300)
+        else:
+            self.sut_node.main_session.send_command(f"meson test -C {self.dpdk_build_dir_path} --suite driver-tests", 300)
+
+    def test_gather_info(self) -> None:
+        """
+        Test:
+            gather information about the system and send output to statistics.txt
+        """
+        out = {}
+        
+        out['OS'] = self.sut_node.main_session.send_command("awk -F= '$1==\"NAME\" {print $2}' /etc/os-release", 60).stdout
+        out["OS VERSION"] = self.sut_node.main_session.send_command("awk -F= '$1==\"VERSION\" {print $2}' /etc/os-release", 60, True).stdout
+        out["COMPILER VERSION"] = get_compiler_version(self.build_target_info.compiler.name, self.sut_node)
+        out["DPDK VERSION"] = self.sut_node.dpdk_version
+        if self.build_target_info.os.name == "linux":
+            out['KERNEL VERSION'] = self.sut_node.main_session.send_command("uname -r", 60).stdout
+        elif self.build_target_info.os.name == "windows":
+            out['KERNEL VERSION'] = self.sut_node.main_session.send_command("uname -a", 60).stdout
+        self.write_to_statistics_file(out)
+
+
+
+    def test_start_testpmd(self) -> None:
+        """
+        Creates and instance of the testpmd driver to run the testpmd app
+        """
+        driver: TestpmdDriver = TestpmdDriver(self.sut_node.create_interactive_session_handler(), self.dpdk_build_dir_path)
+
+        print(driver.send_command("show port summary all"))
+
+    def test_device_bound_to_driver(self) -> None:
+        """
+        Test:
+            ensure that all drivers listed in the config are bound to the correct drivers
+        """
+        for nic in self.sut_node._execution_config.nics:
+            for address in nic.addresses:
+                out = self.sut_node.main_session.send_command(f"{self.dpdk_build_dir_path}/../usertools/dpdk-devbind.py --status | grep {address}", 60)
+                self.verify(
+                    len(out.stdout) != 0,
+                    f"Failed to find configured device ({address}) using dpdk-devbind.py",
+                )
+                for string in out.stdout.split(" "):
+                    if 'drv=' in string:
+                        self.verify(
+                            string.split("=")[1] == nic.driver.strip(),
+                            f'Driver for device {address} does not match driver listed in configuration (bound to {string.split("=")[1]})',
+                        )
+        
\ No newline at end of file
-- 
2.40.1


  reply	other threads:[~2023-05-12 19:27 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-12 19:25 [RFC v2 0/2] add DTS " jspewock
2023-05-12 19:25 ` jspewock [this message]
2023-05-23  8:05   ` [RFC v2 1/2] dts: add " Juraj Linkeš
2023-05-23  8:33     ` Juraj Linkeš
2023-05-24 20:44     ` Jeremy Spewock
2023-05-25  8:33       ` Juraj Linkeš
2023-05-25 18:02         ` Jeremy Spewock
2023-05-26  7:36           ` Juraj Linkeš
2023-05-26 13:24             ` Jeremy Spewock
2023-05-24 10:03   ` Juraj Linkeš
2023-05-25 15:40     ` Jeremy Spewock
2023-05-12 19:25 ` [RFC v2 2/2] dts: added paramiko to dependencies jspewock

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=20230512192540.401-3-jspewock@iol.unh.edu \
    --to=jspewock@iol.unh.edu \
    --cc=dev@dpdk.org \
    /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).