Skip to content

Commit 28bc3d2

Browse files
Add: smoke tests workflow (#1215)
Co-authored-by: KarolinaPomian <[email protected]> Co-authored-by: KarolinaPomian <[email protected]>
1 parent b581962 commit 28bc3d2

File tree

14 files changed

+295
-41
lines changed

14 files changed

+295
-41
lines changed

.github/workflows/smoke-tests.yml

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
name: smoke-tests-bare-metal
2+
on:
3+
workflow_dispatch:
4+
push:
5+
branches:
6+
- main
7+
- 'maint-**'
8+
pull_request:
9+
branches:
10+
- main
11+
- 'maint-**'
12+
env:
13+
BUILD_TYPE: 'Release'
14+
DPDK_VERSION: '25.03'
15+
DPDK_REBUILD: 'false'
16+
permissions:
17+
contents: read
18+
jobs:
19+
validation-build-mtl:
20+
runs-on: [Linux, self-hosted, DPDK]
21+
timeout-minutes: 60
22+
outputs:
23+
pipenv-activate: ${{ steps.pipenv-install.outputs.VIRTUAL_ENV }}
24+
steps:
25+
- name: 'preparation: Harden Runner'
26+
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
27+
with:
28+
egress-policy: audit
29+
- name: 'preparation: Restore valid repository owner and print env'
30+
if: always()
31+
run: |
32+
sudo chown -R "${USER}" "$(pwd)" || true
33+
env | grep TEST_ || true
34+
- name: 'preparation: Checkout MTL'
35+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
36+
with:
37+
ref: 'pstaszczuk/smoke-tests'
38+
- name: 'preparation: Checkout DPDK'
39+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
40+
if: env.DPDK_REBUILD == 'true'
41+
with:
42+
repository: 'DPDK/dpdk'
43+
ref: 'v${{ env.DPDK_VERSION }}'
44+
path: 'dpdk'
45+
- name: 'preparation: Checkout openh264'
46+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
47+
with:
48+
repository: 'cisco/openh264'
49+
ref: 'openh264v2.4.0'
50+
path: 'openh264'
51+
- name: 'preparation: Checkout FFmpeg'
52+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
53+
with:
54+
repository: 'FFmpeg/FFmpeg'
55+
ref: 'release/7.0'
56+
path: 'ffmpeg'
57+
- name: 'configuration: Install the build dependency'
58+
run: |
59+
sudo apt update
60+
sudo apt-get remove -y pipenv || true
61+
sudo apt-get install -y \
62+
git gcc meson tar zip \
63+
pkg-config \
64+
python3 \
65+
python3-pyelftools \
66+
python3-virtualenv \
67+
python3-pip \
68+
libnuma-dev \
69+
libjson-c-dev \
70+
libpcap-dev \
71+
libgtest-dev \
72+
libsdl2-dev \
73+
libsdl2-ttf-dev \
74+
libssl-dev \
75+
systemtap-sdt-dev \
76+
libbpf-dev \
77+
libelf1 \
78+
gstreamer1.0-plugins-base \
79+
gstreamer1.0-plugins-good \
80+
gstreamer1.0-tools \
81+
gstreamer1.0-libav \
82+
libgstreamer1.0-dev \
83+
libgstreamer-plugins-base1.0-dev
84+
- name: 'configuration: Apply dpdk patches'
85+
if: env.DPDK_REBUILD == 'true'
86+
run: |
87+
patch -d "dpdk" -p1 -i <(cat patches/dpdk/${{ env.DPDK_VERSION }}/*.patch)
88+
- name: 'installation: Build dpdk'
89+
working-directory: dpdk
90+
if: env.DPDK_REBUILD == 'true'
91+
run: |
92+
meson build
93+
ninja -C build
94+
sudo ninja -C build install
95+
- name: 'installation: Build mtl'
96+
run: |
97+
./build.sh
98+
sudo ldconfig
99+
- name: 'installation: Build openh264'
100+
working-directory: openh264
101+
run: |
102+
make -j "$(nproc)"
103+
sudo make install
104+
sudo ldconfig
105+
- name: 'installation: Build FFmpeg'
106+
working-directory: ffmpeg
107+
run: |
108+
git am ../ecosystem/ffmpeg_plugin/7.0/*.patch
109+
cp ../ecosystem/ffmpeg_plugin/mtl_*.c -rf libavdevice/
110+
cp ../ecosystem/ffmpeg_plugin/mtl_*.h -rf libavdevice/
111+
./configure --enable-shared --disable-static --enable-nonfree --enable-pic --enable-gpl --enable-libopenh264 --enable-encoder=libopenh264 --enable-mtl
112+
make -j "$(nproc)"
113+
sudo make install
114+
sudo ldconfig
115+
- name: 'installation: Build GStreamer'
116+
working-directory: ecosystem/gstreamer_plugin
117+
run: |
118+
./build.sh
119+
- name: 'installation: Install pipenv environment'
120+
working-directory: tests/validation
121+
id: pipenv-install
122+
run: |
123+
python3 -m venv venv
124+
source venv/bin/activate
125+
pip install -r requirements.txt
126+
echo "VIRTUAL_ENV=$PWD/venv/bin/activate" >> "$GITHUB_ENV"
127+
validation-run-tests:
128+
needs: [validation-build-mtl]
129+
runs-on: [Linux, self-hosted, DPDK]
130+
timeout-minutes: 720
131+
env:
132+
PYTEST_RETRIES: '3'
133+
steps:
134+
- name: 'preparation: Harden Runner'
135+
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
136+
with:
137+
egress-policy: audit
138+
- name: 'preparation: Evaluate choosen validation-test-port-p and validation-test-port-r'
139+
run: |
140+
eval "export TEST_PORT_P=TEST_VF_PORT_P_0"
141+
eval "export TEST_PORT_R=TEST_VF_PORT_P_1"
142+
echo "TEST_PORT_P=${TEST_PORT_P}" >> "$GITHUB_ENV"
143+
echo "TEST_PORT_R=${TEST_PORT_R}" >> "$GITHUB_ENV"
144+
echo "TEST_PORT_P=${TEST_PORT_P}"
145+
echo "TEST_PORT_R=${TEST_PORT_R}"
146+
- name: 'preparation: Kill MtlManager and pytest routines'
147+
run: |
148+
sudo killall -SIGINT pipenv || true
149+
sudo killall -SIGINT pytest || true
150+
sudo killall -SIGINT MtlManager || true
151+
- name: 'preparation: Create VFs'
152+
run: |
153+
sudo rmmod irdma || true
154+
sudo ./script/nicctl.sh create_vf "${TEST_PF_PORT_P}" || true
155+
sudo ./script/nicctl.sh create_vf "${TEST_PF_PORT_R}" || true
156+
- name: 'preparation: Start MtlManager at background'
157+
run: |
158+
sudo MtlManager &
159+
- name: 'execution: Run validation-bare-metal tests in virtual environment'
160+
run: |
161+
sudo tests/validation/venv/bin/python3 -m pytest --topology_config=tests/validation/configs/topology_config.yaml --test_config=tests/validation/configs/test_config.yaml -m smoke --template=html/index.html --report=report.html
162+
- name: "upload report"
163+
id: upload-report
164+
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
165+
with:
166+
name: smoke-tests-report
167+
path: |
168+
report.html
169+
- name: "Add report to summary"
170+
if: always()
171+
run: |
172+
{
173+
echo "## Smoke Tests Report"
174+
echo ""
175+
# Check if JSON report exists
176+
if [ -f "report.json" ]; then
177+
# Parse JSON report
178+
PASSED=$(jq '.summary.passed // 0' report.json)
179+
FAILED=$(jq '.summary.failed // 0' report.json)
180+
SKIPPED=$(jq '.summary.skipped // 0' report.json)
181+
ERROR=$(jq '.summary.errors // 0' report.json)
182+
# Add summary stats
183+
echo "| Status | Count |"
184+
echo "| ------ | ----- |"
185+
echo "| ✅ Passed | ${PASSED:-0} |"
186+
echo "| ❌ Failed | ${FAILED:-0} |"
187+
echo "| ⚠️ Error | ${ERROR:-0} |"
188+
echo "| ⏭️ Skipped | ${SKIPPED:-0} |"
189+
echo ""
190+
# Add test result details if available
191+
TOTAL=$((${PASSED:-0} + ${FAILED:-0} + ${ERROR:-0} + ${SKIPPED:-0}))
192+
echo "**Total Tests:** $TOTAL"
193+
echo ""
194+
if [ "${FAILED:-0}" -gt 0 ] || [ "${ERROR:-0}" -gt 0 ]; then
195+
echo "❌ **Some tests failed!** Please check the detailed report."
196+
else
197+
echo "✅ **All tests passed!**"
198+
fi
199+
echo ""
200+
# Add link to full report artifact
201+
echo "📄 [Download Full HTML Report](https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/artifacts/${{ steps.upload-report.outputs.artifact-id }})"
202+
else
203+
echo "❌ No report.json file was generated"
204+
fi
205+
} >> "$GITHUB_STEP_SUMMARY"
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
build: /path/to/Media-Transport-Library
2-
mtl_path: /path/to/Media-Transport-Library
3-
media_path: /path/to/media
1+
build: .
2+
mtl_path: .
3+
media_path: /mnt/media
44
capture_cfg:
55
enable: false
66
test_name: test_name
7-
pcap_dir: /path/to/pcap_files
7+
pcap_dir: /home/ubuntu/pcap_files
88
capture_time: 5
99
interface: null
1010
ramdisk:
11-
pcap_dir: /path/to/pcap_files
11+
pcap_dir: /home/ubuntu/pcap_files
1212
tmpfs_size: 768G
1313
tmpfs_name: tmpfs_name
1414
use_sudo: true

tests/validation/configs/topology_config.yaml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,5 @@ hosts:
99
- pci_device: 8086:1592
1010
interface_index: 0 # all
1111
connections:
12-
- ip_address: ip_address
13-
connection_type: SSHConnection
14-
connection_options:
15-
port: 22
16-
username: username
17-
password: passowrd
12+
- ip_address: 127.0.0.1
13+
connection_type: LocalConnection

tests/validation/conftest.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def mtl_path(test_config: dict) -> str:
6565

6666
@pytest.fixture(scope="session", autouse=True)
6767
def keep(request):
68-
keep = request.config.getoption("--keep")
68+
keep = request.config.getoption("--keep", None)
6969
if keep is None:
7070
keep = "none"
7171
if keep.lower() not in ["all", "failed", "none"]:
@@ -76,7 +76,7 @@ def keep(request):
7676

7777
@pytest.fixture(scope="session", autouse=True)
7878
def dmesg(request):
79-
dmesg = request.config.getoption("--dmesg")
79+
dmesg = request.config.getoption("--dmesg", None)
8080
if dmesg is None:
8181
dmesg = "keep"
8282
if dmesg.lower() not in ["clear", "keep"]:
@@ -182,7 +182,10 @@ def log_session():
182182
os.makedirs(path, exist_ok=True)
183183
os.symlink(folder, path_symlink)
184184
yield
185-
shutil.copy("pytest.log", f"{LOG_FOLDER}/latest/pytest.log")
185+
if os.path.exists("pytest.log"):
186+
shutil.copy("pytest.log", f"{LOG_FOLDER}/latest/pytest.log")
187+
else:
188+
logging.warning("pytest.log not found, skipping copy")
186189
csv_write_report(f"{LOG_FOLDER}/latest/report.csv")
187190

188191

tests/validation/mtl_engine/RxTxApp.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import time
1111

1212
from create_pcap_file.tcpdump import TcpDumpRecorder
13+
from mfd_connect import SSHConnection
1314

1415
from . import rxtxapp_config
1516
from .execute import log_fail, run
@@ -523,8 +524,9 @@ def execute_test(
523524
remote_conn = remote_host.connection
524525
config_file = f"{build}/tests/config.json"
525526
f = remote_conn.path(config_file)
526-
json_content = config_json.replace('"', '\\"')
527-
f.write_text(json_content)
527+
if isinstance(remote_conn, SSHConnection):
528+
config_json = config_json.replace('"', '\\"')
529+
f.write_text(config_json, encoding="utf-8")
528530
config_path = os.path.join(build, config_file)
529531
log_to_file(f"Config file written to remote host: {config_path}", host, build)
530532

@@ -743,8 +745,9 @@ def execute_perf_test(
743745
remote_conn = host.connection
744746
config_file = f"{build}/tests/config.json"
745747
f = remote_conn.path(config_file)
746-
json_content = config_json.replace('"', '\\"')
747-
f.write_text(json_content)
748+
if isinstance(remote_conn, SSHConnection):
749+
config_json = config_json.replace('"', '\\"')
750+
f.write_text(config_json, encoding="utf-8")
748751
config_path = os.path.join(build, config_file)
749752
log_to_file(
750753
f"Performance config file written to remote host: {config_path}", host, build
@@ -1679,13 +1682,11 @@ def execute_dual_test(
16791682

16801683
# Prepare TX config
16811684
tx_f = tx_host.connection.path(build, "tests", "tx_config.json")
1682-
tx_json_content = tx_config.replace('"', '\\"')
1683-
tx_f.write_text(tx_json_content)
1685+
tx_f.write_text(tx_config, encoding="utf-8")
16841686

16851687
# Prepare RX config
1686-
rx_f = tx_host.connection.path(build, "tests", "tx_config.json")
1687-
rx_json_content = rx_config.replace('"', '\\"')
1688-
rx_f.write_text(rx_json_content)
1688+
rx_f = tx_host.connection.path(build, "tests", "rx_config.json")
1689+
rx_f.write_text(rx_config, encoding="utf-8")
16891690

16901691
# Adjust test_time for high-res/fps/replicas
16911692
if (

tests/validation/mtl_engine/ffmpeg_app.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import re
99
import time
1010

11+
from mfd_connect import SSHConnection
1112
from mtl_engine.RxTxApp import prepare_tcpdump
1213

1314
from . import rxtxapp_config
@@ -78,9 +79,9 @@ def log_to_file(message: str, host, build: str):
7879

7980
if f.exists():
8081
current_content = f.read_text()
81-
f.write_text(current_content + log_entry)
82+
f.write_text(current_content + log_entry, encoding="utf-8")
8283
else:
83-
f.write_text(log_entry)
84+
f.write_text(log_entry, encoding="utf-8")
8485

8586

8687
def execute_test(
@@ -821,8 +822,9 @@ def generate_rxtxapp_rx_config(
821822
config_json = json.dumps(config, indent=4)
822823
remote_conn = host.connection
823824
f = remote_conn.path(config_file)
824-
json_content = config_json.replace('"', '\\"')
825-
f.write_text(json_content)
825+
if isinstance(remote_conn, SSHConnection):
826+
config_json = config_json.replace('"', '\\"')
827+
f.write_text(config_json, encoding="utf-8")
826828

827829
logger.info("Config file written successfully")
828830
log_to_file(f"Generated RX config file: {config_file}", host, build)
@@ -887,8 +889,9 @@ def generate_rxtxapp_rx_config_multiple(
887889
config_json = json.dumps(config, indent=4)
888890
remote_conn = host.connection
889891
f = remote_conn.path(config_file)
890-
json_content = config_json.replace('"', '\\"')
891-
f.write_text(json_content)
892+
if isinstance(remote_conn, SSHConnection):
893+
config_json = config_json.replace('"', '\\"')
894+
f.write_text(config_json, encoding="utf-8")
892895

893896
logger.info("Multiple config file written successfully")
894897
log_to_file(f"Generated RX multiple config file: {config_file}", host, build)
@@ -950,8 +953,9 @@ def generate_rxtxapp_tx_config(
950953
config_json = json.dumps(config, indent=4)
951954
remote_conn = host.connection
952955
f = remote_conn.path(config_file)
953-
json_content = config_json.replace('"', '\\"')
954-
f.write_text(json_content)
956+
if isinstance(remote_conn, SSHConnection):
957+
config_json = config_json.replace('"', '\\"')
958+
f.write_text(config_json, encoding="utf-8")
955959

956960
logger.info("TX Config file written successfully")
957961
log_to_file(f"Generated TX config file: {config_file}", host, build)

tests/validation/pytest.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
[pytest]
2-
log_file = pytest.log
2+
log_file=./tests/validation/pytest.log
3+
markers=
4+
smoke: mark test as part of the smoke test suite

tests/validation/tests/single/ffmpeg/test_rx_ffmpeg_tx_ffmpeg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
[
1414
("i1080p25", 2),
1515
("i1080p50", 2),
16-
("i1080p60", 4),
16+
pytest.param("i1080p60", 4, marks=pytest.mark.smoke),
1717
("i2160p60", 6),
1818
],
1919
)

0 commit comments

Comments
 (0)