Skip to content

Commit e6991e5

Browse files
committed
Changes to support remote host test execution
Signed-off-by: Wilczynski, Andrzej <andrzej.wilczynski@intel.com>
1 parent e6c53b0 commit e6991e5

File tree

16 files changed

+151
-85
lines changed

16 files changed

+151
-85
lines changed

tests/validation/mtl_engine/application_base.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import time
77
from abc import ABC, abstractmethod
88

9-
from .config.app_mappings import DEFAULT_PAYLOAD_TYPE_CONFIG, DEFAULT_PORT_CONFIG
9+
from .config.app_mappings import (DEFAULT_PAYLOAD_TYPE_CONFIG,
10+
DEFAULT_PORT_CONFIG)
1011
from .config.universal_params import UNIVERSAL_PARAMS
1112
from .execute import run
1213

@@ -163,6 +164,19 @@ def get_common_video_params(self) -> dict:
163164
),
164165
}
165166

167+
def prepare_execution(self, build: str, host=None, **kwargs):
168+
"""Hook method called before execution to perform framework-specific setup.
169+
170+
Subclasses can override this to write config files, set up environment, etc.
171+
Default implementation does nothing.
172+
173+
Args:
174+
build: Build directory path
175+
host: Host connection object
176+
**kwargs: Additional arguments passed from execute_test
177+
"""
178+
pass
179+
166180
def execute_test(
167181
self,
168182
build: str,
@@ -198,6 +212,14 @@ def execute_test(
198212
raise RuntimeError("create_command() must be called before execute_test()")
199213
framework_name = self.get_framework_name()
200214

215+
# Call framework-specific preparation hook
216+
if not is_dual:
217+
self.prepare_execution(build=build, host=host)
218+
else:
219+
self.prepare_execution(build=build, host=tx_host)
220+
if rx_app:
221+
rx_app.prepare_execution(build=build, host=rx_host)
222+
201223
# Single-host execution
202224
if not is_dual:
203225
cmd = self.add_timeout(self.command, test_time)

tests/validation/mtl_engine/rxtxapp.py

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@
33

44
import json
55
import logging
6-
import os
76

87
from .application_base import Application
98
from .config.app_mappings import APP_NAME_MAP, DEFAULT_NETWORK_CONFIG
10-
from .config.param_mappings import (
11-
RXTXAPP_CMDLINE_PARAM_MAP,
12-
RXTXAPP_CONFIG_PARAM_MAP,
13-
)
9+
from .config.param_mappings import RXTXAPP_CMDLINE_PARAM_MAP
1410
from .config.universal_params import UNIVERSAL_PARAMS
1511

1612
# Create IP dictionaries for backward compatibility using DEFAULT_NETWORK_CONFIG
@@ -37,26 +33,17 @@
3733

3834
from . import rxtxapp_config as legacy_cfg
3935
from .execute import log_fail
40-
4136
# Import legacy helpers so we can emit a backward-compatible JSON config
42-
from .RxTxApp import (
43-
add_interfaces,
44-
check_rx_output,
45-
check_tx_output,
46-
create_empty_config,
47-
)
37+
from .RxTxApp import (add_interfaces, check_rx_output, check_tx_output,
38+
create_empty_config)
4839
except ImportError:
4940
# Fallback for direct execution (when running this module standalone)
5041
import copy
5142

5243
import rxtxapp_config as legacy_cfg
5344
from execute import log_fail
54-
from RxTxApp import (
55-
add_interfaces,
56-
check_rx_output,
57-
check_tx_output,
58-
create_empty_config,
59-
)
45+
from RxTxApp import (add_interfaces, check_rx_output, check_tx_output,
46+
create_empty_config)
6047

6148
logger = logging.getLogger(__name__)
6249

@@ -75,17 +62,7 @@ def create_command(self, **kwargs): # type: ignore[override]
7562
cmd, cfg = self._create_rxtxapp_command_and_config()
7663
self.command = cmd
7764
self.config = cfg
78-
# Write config immediately if path known
79-
config_path = (
80-
self.config_file_path
81-
or self.universal_params.get("config_file")
82-
or "config.json"
83-
)
84-
try:
85-
with open(config_path, "w") as f:
86-
json.dump(cfg, f, indent=2)
87-
except Exception as e:
88-
logger.warning(f"Failed to write RxTxApp config file {config_path}: {e}")
65+
# Config will be written to remote host during execute_test
8966
return self.command, self.config
9067

9168
def _create_rxtxapp_command_and_config(self) -> tuple:
@@ -96,13 +73,12 @@ def _create_rxtxapp_command_and_config(self) -> tuple:
9673
Returns:
9774
Tuple of (command_string, config_dict)
9875
"""
99-
# Use config file path from constructor or default (absolute path)
76+
# Use config file path from constructor or default (relative to build dir on remote host)
10077
if self.config_file_path:
10178
config_file_path = self.config_file_path
10279
else:
103-
config_file_path = os.path.abspath(
104-
DEFAULT_NETWORK_CONFIG["default_config_file"]
105-
)
80+
# Use tests/config.json relative to build directory on remote host
81+
config_file_path = "tests/config.json"
10682

10783
# Build command line with all command-line parameters
10884
executable_path = self.get_executable_path()
@@ -491,6 +467,62 @@ def _populate_session(is_tx: bool):
491467

492468
return config
493469

470+
def prepare_execution(self, build: str, host=None, **kwargs):
471+
"""Write RxTxApp JSON config file to remote host before execution."""
472+
if not host:
473+
raise ValueError("host required for RxTxApp config writing")
474+
475+
if not self.config:
476+
raise RuntimeError(
477+
"create_command() must be called before prepare_execution()"
478+
)
479+
480+
# Write config file to remote host
481+
remote_conn = host.connection
482+
# Extract config file path from command (it's relative)
483+
import re
484+
485+
match = re.search(r"--config_file\s+(\S+)", self.command)
486+
if match:
487+
config_file_relative = match.group(1)
488+
# Make it absolute on remote host by joining with build directory
489+
config_file_path = f"{build}/{config_file_relative}"
490+
else:
491+
config_file_path = f"{build}/tests/config.json"
492+
493+
# Write config to remote host
494+
config_json = json.dumps(self.config, indent=4)
495+
496+
# Use heredoc to write file properly on remote host (avoids quote escaping issues)
497+
try:
498+
from mfd_connect import SSHConnection
499+
500+
if isinstance(remote_conn, SSHConnection):
501+
# Write using heredoc to avoid quote escaping issues with echo
502+
cmd = f"""cat > {config_file_path} << 'EOFCONFIG'
503+
{config_json}
504+
EOFCONFIG"""
505+
remote_conn.execute_command(cmd)
506+
logger.info(f"Wrote RxTxApp config to remote host: {config_file_path}")
507+
else:
508+
# For local or other connection types, use write_text
509+
f = remote_conn.path(config_file_path)
510+
f.write_text(config_json, encoding="utf-8")
511+
logger.info(f"Wrote RxTxApp config to host: {config_file_path}")
512+
except (ImportError, Exception) as e:
513+
logger.warning(
514+
f"Could not use SSH heredoc method ({e}), falling back to write_text"
515+
)
516+
# Fallback to write_text if SSH not available
517+
f = remote_conn.path(config_file_path)
518+
f.write_text(config_json, encoding="utf-8")
519+
logger.info(f"Wrote RxTxApp config to host: {config_file_path}")
520+
521+
# Update command to use absolute path on remote host
522+
self.command = self.command.replace(
523+
f"--config_file {config_file_relative}", f"--config_file {config_file_path}"
524+
)
525+
494526
def validate_results(self) -> bool: # type: ignore[override]
495527
"""
496528
Validate execution results exactly like original RxTxApp.execute_test().
@@ -539,10 +571,8 @@ def _fail(msg: str):
539571

540572
# Import converter check functions if available
541573
try:
542-
from .RxTxApp import (
543-
check_rx_converter_output,
544-
check_tx_converter_output,
545-
)
574+
from .RxTxApp import (check_rx_converter_output,
575+
check_tx_converter_output)
546576

547577
passed = passed and check_tx_converter_output(
548578
config=self.config,

tests/validation/tests/single/st20p/format/test_format_refactored.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import pytest
5-
from common.nicctl import InterfaceSetup
65
from mtl_engine.media_files import yuv_files_422p10le, yuv_files_422rfc10
76
from mtl_engine.rxtxapp import RxTxApp
87

8+
from common.nicctl import InterfaceSetup
9+
910

1011
@pytest.mark.smoke
1112
@pytest.mark.nightly
@@ -201,6 +202,7 @@ def test_tx_rx_conversion_refactored(
201202
)
202203

203204

205+
@pytest.mark.nightly
204206
@pytest.mark.parametrize(
205207
"media_file",
206208
[yuv_files_422rfc10["test_8K"]],

tests/validation/tests/single/st20p/fps/test_fps_refactored.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import pytest
5-
from common.nicctl import InterfaceSetup
65
from mtl_engine.media_files import yuv_files_422rfc10
76
from mtl_engine.rxtxapp import RxTxApp
87

8+
from common.nicctl import InterfaceSetup
9+
910

1011
@pytest.mark.nightly
1112
@pytest.mark.parametrize(
@@ -78,4 +79,6 @@ def test_fps_refactored(
7879
elif fps in ["p100", "p119", "p120"]:
7980
actual_test_time = max(test_time, 10)
8081

81-
app.execute_test(build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture)
82+
app.execute_test(
83+
build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture
84+
)

tests/validation/tests/single/st20p/integrity/test_integrity_refactored.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import logging
5+
from pathlib import Path
56

67
import pytest
7-
from common.nicctl import InterfaceSetup
88
from mfd_common_libs.log_levels import TEST_PASS
99
from mtl_engine.const import LOG_FOLDER
1010
from mtl_engine.execute import log_fail
11-
from mtl_engine.integrity import calculate_yuv_frame_size, check_st20p_integrity
11+
from mtl_engine.integrity import (calculate_yuv_frame_size,
12+
check_st20p_integrity)
1213
from mtl_engine.media_files import yuv_files_422p10le, yuv_files_422rfc10
1314
from mtl_engine.rxtxapp import RxTxApp
14-
from pathlib import Path
15+
16+
from common.nicctl import InterfaceSetup
1517

1618
logger = logging.getLogger(__name__)
1719

@@ -75,7 +77,9 @@ def test_integrity_refactored(
7577
)
7678

7779
actual_test_time = max(test_time, 8)
78-
app.execute_test(build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture)
80+
app.execute_test(
81+
build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture
82+
)
7983

8084
frame_size = calculate_yuv_frame_size(
8185
media_file_info["width"],

tests/validation/tests/single/st20p/interlace/test_interlace_refactored.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import pytest
5-
from common.nicctl import InterfaceSetup
65
from mtl_engine.media_files import yuv_files_interlace
76
from mtl_engine.rxtxapp import RxTxApp
87

8+
from common.nicctl import InterfaceSetup
9+
910

1011
@pytest.mark.nightly
1112
@pytest.mark.parametrize(
@@ -54,4 +55,6 @@ def test_interlace_refactored(
5455

5556
app.create_command(**config_params)
5657
actual_test_time = max(test_time, 10)
57-
app.execute_test(build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture)
58+
app.execute_test(
59+
build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture
60+
)

tests/validation/tests/single/st20p/pacing/test_pacing_refactored.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import pytest
5-
from common.nicctl import InterfaceSetup
65
from mtl_engine.media_files import yuv_files_422rfc10
76
from mtl_engine.rxtxapp import RxTxApp
87

8+
from common.nicctl import InterfaceSetup
9+
910

1011
@pytest.mark.nightly
1112
@pytest.mark.parametrize("pacing", ["narrow", "wide", "linear"])
@@ -67,4 +68,6 @@ def test_pacing_refactored(
6768
actual_test_time = max(test_time, 8)
6869

6970
app.create_command(**config_params)
70-
app.execute_test(build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture)
71+
app.execute_test(
72+
build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture
73+
)

tests/validation/tests/single/st20p/packing/test_packing_refactored.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import pytest
5-
from common.nicctl import InterfaceSetup
65
from mtl_engine.media_files import yuv_files_422rfc10
76
from mtl_engine.rxtxapp import RxTxApp
87

8+
from common.nicctl import InterfaceSetup
9+
910

1011
@pytest.mark.nightly
1112
@pytest.mark.parametrize("packing", ["GPM_SL", "GPM"])
@@ -68,4 +69,6 @@ def test_packing_refactored(
6869
actual_test_time = max(test_time, 8)
6970

7071
app.create_command(**config_params)
71-
app.execute_test(build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture)
72+
app.execute_test(
73+
build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture
74+
)

tests/validation/tests/single/st20p/resolutions/test_resolutions_refactored.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import pytest
5-
from common.nicctl import InterfaceSetup
65
from mtl_engine.media_files import yuv_files_422rfc10
76
from mtl_engine.rxtxapp import RxTxApp
87

8+
from common.nicctl import InterfaceSetup
9+
910

1011
@pytest.mark.nightly
1112
@pytest.mark.parametrize(
@@ -71,4 +72,6 @@ def test_resolutions_refactored(
7172
else:
7273
actual_test_time = max(test_time, 8)
7374

74-
app.execute_test(build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture)
75+
app.execute_test(
76+
build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture
77+
)

tests/validation/tests/single/st20p/test_mode/test_multicast_refactored.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# Copyright(c) 2024-2025 Intel Corporation
33

44
import pytest
5-
from common.nicctl import InterfaceSetup
65
from mtl_engine.media_files import yuv_files_422rfc10
76
from mtl_engine.rxtxapp import RxTxApp
87

8+
from common.nicctl import InterfaceSetup
9+
910

1011
@pytest.mark.nightly
1112
@pytest.mark.parametrize(
@@ -68,4 +69,6 @@ def test_multicast_refactored(
6869
actual_test_time = max(test_time, 8)
6970

7071
app.create_command(**config_params)
71-
app.execute_test(build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture)
72+
app.execute_test(
73+
build=build, test_time=actual_test_time, host=host, netsniff=pcap_capture
74+
)

0 commit comments

Comments
 (0)