Skip to content

Commit 6a50440

Browse files
committed
feat(examples): websocket autobahn test suit integration
1 parent fb37ea6 commit 6a50440

27 files changed

+3270
-2
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
name: "websocket-autobahn: build/linux-tests"
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
types: [opened, synchronize, reopened, labeled]
9+
10+
jobs:
11+
linux_websocket_autobahn:
12+
runs-on: ubuntu-22.04
13+
if: github.event_name == 'push' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'websocket-autobahn'))
14+
15+
env:
16+
TEST_DIR: components/esp_websocket_client/tests/autobahn-testsuite
17+
TESTEE_DIR: components/esp_websocket_client/tests/autobahn-testsuite/testee
18+
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
23+
- name: Start Autobahn Fuzzing Server
24+
run: |
25+
mkdir -p ${{ env.TEST_DIR }}/reports/clients
26+
27+
HOST_IP=$(ip route get 8.8.8.8 | grep -oP 'src \K\S+' || hostname -I | awk '{print $1}' || echo "172.17.0.1")
28+
echo "Host IP address: $HOST_IP"
29+
echo "HOST_IP=$HOST_IP" >> $GITHUB_ENV
30+
31+
docker run -d \
32+
--name fuzzing-server \
33+
--network host \
34+
-v ${{ github.workspace }}/${{ env.TEST_DIR }}/config:/config:ro \
35+
-v ${{ github.workspace }}/${{ env.TEST_DIR }}/reports:/reports \
36+
crossbario/autobahn-testsuite:latest \
37+
wstest -m fuzzingserver -s /config/fuzzingserver.json
38+
39+
echo "Waiting for fuzzing server..."
40+
for i in {1..5}; do
41+
if curl -f http://localhost:9001/info >/dev/null 2>&1; then
42+
echo "Fuzzing server ready!"
43+
exit 0
44+
fi
45+
echo "Attempt $i/5 – waiting 2s..."
46+
sleep 2
47+
done
48+
49+
echo "Server start failed. Container logs:"
50+
docker logs fuzzing-server
51+
exit 1
52+
53+
- name: Build test (Linux target)
54+
working-directory: ${{ env.TESTEE_DIR }}
55+
run: |
56+
docker run --rm \
57+
-v ${{ github.workspace }}:/work \
58+
-w /work/${{ env.TESTEE_DIR }} \
59+
espressif/idf:latest \
60+
bash -c "
61+
. \$IDF_PATH/export.sh
62+
cp sdkconfig.ci.linux sdkconfig.defaults
63+
echo 'Building...'
64+
idf.py build
65+
"
66+
67+
- name: Verify fuzzing server connectivity
68+
run: |
69+
HOST_IP=${HOST_IP:-$(ip route get 8.8.8.8 | grep -oP 'src \K\S+' || hostname -I | awk '{print $1}' || echo "172.17.0.1")}
70+
echo "Testing connectivity to $HOST_IP:9001"
71+
72+
docker run --rm \
73+
--network host \
74+
espressif/idf:latest \
75+
bash -c "
76+
curl -f http://$HOST_IP:9001/info || {
77+
echo 'ERROR: Cannot connect to fuzzing server at $HOST_IP:9001'
78+
exit 1
79+
}
80+
echo 'Fuzzing server is accessible'
81+
"
82+
83+
- name: Run Autobahn tests
84+
run: |
85+
docker run --rm \
86+
--network host \
87+
-v ${{ github.workspace }}:/work \
88+
-w /work/${{ env.TESTEE_DIR }}/build \
89+
espressif/idf:latest \
90+
bash -c "
91+
apt-get update && apt-get install -y file curl net-tools || true
92+
93+
HOST_IP=\$(ip route get 8.8.8.8 2>/dev/null | grep -oP 'src \\K\\S+' || hostname -I | awk '{print \$1}' || echo '172.17.0.1')
94+
curl -f http://\${HOST_IP}:9001/info || {
95+
echo \"ERROR: Server not reachable at \${HOST_IP}:9001\"
96+
exit 1
97+
}
98+
99+
echo 'Running autobahn_testee.elf'
100+
WS_URI=\"ws://\${HOST_IP}:9001\"
101+
echo \"WebSocket URI: \${WS_URI}\"
102+
(sleep 0.5; printf \"\${WS_URI}\\n\") | timeout 30m ./autobahn_testee.elf || {
103+
EXIT_CODE=\$?
104+
echo 'Test failed'
105+
exit \$EXIT_CODE
106+
}
107+
echo 'All Autobahn tests passed!'
108+
"
109+
110+
- name: Show reports
111+
if: always()
112+
working-directory: ${{ env.TEST_DIR }}
113+
run: |
114+
if [ -d reports/clients ]; then
115+
ls -la reports/clients/
116+
else
117+
echo "No reports"
118+
fi
119+
120+
- name: Generate summary
121+
if: always()
122+
working-directory: ${{ env.TEST_DIR }}
123+
run: python3 scripts/generate_summary.py || true
124+
125+
- name: Upload reports
126+
if: always()
127+
uses: actions/upload-artifact@v4
128+
with:
129+
name: autobahn-reports-linux-${{ github.run_id }}
130+
path: ${{ env.TEST_DIR }}/reports/**
131+
if-no-files-found: warn
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
name: "websocket-autobahn: build/target-tests"
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
types: [opened, synchronize, reopened, labeled]
9+
10+
jobs:
11+
build_websocket_autobahn:
12+
if: contains(github.event.pull_request.labels.*.name, 'websocket-autobahn') || github.event_name == 'push'
13+
name: Build
14+
strategy:
15+
matrix:
16+
idf_ver: ["release-v5.5", "latest"]
17+
idf_target: ["esp32"]
18+
runs-on: ubuntu-22.04
19+
container: espressif/idf:${{ matrix.idf_ver }}
20+
env:
21+
TEST_DIR: components/esp_websocket_client/examples/autobahn-testsuite/testee
22+
steps:
23+
- name: Checkout esp-protocols
24+
uses: actions/checkout@v4
25+
with:
26+
submodules: recursive
27+
- name: Build autobahn testee with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
28+
working-directory: ${{ env.TEST_DIR }}
29+
env:
30+
IDF_TARGET: ${{ matrix.idf_target }}
31+
shell: bash
32+
run: |
33+
. ${IDF_PATH}/export.sh
34+
test -f sdkconfig.ci.target.plain_tcp && cat sdkconfig.ci.target.plain_tcp >> sdkconfig.defaults || echo "No sdkconfig.ci.plain_tcp"
35+
idf.py set-target ${{ matrix.idf_target }}
36+
idf.py build
37+
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
38+
working-directory: ${{ env.TEST_DIR }}/build
39+
env:
40+
IDF_TARGET: ${{ matrix.idf_target }}
41+
shell: bash
42+
run: |
43+
. ${IDF_PATH}/export.sh
44+
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
45+
- uses: actions/upload-artifact@v4
46+
with:
47+
name: autobahn_testee_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
48+
path: |
49+
${{ env.TEST_DIR }}/build/bootloader/bootloader.bin
50+
${{ env.TEST_DIR }}/build/partition_table/partition-table.bin
51+
${{ env.TEST_DIR }}/build/*.bin
52+
${{ env.TEST_DIR }}/build/*.elf
53+
${{ env.TEST_DIR }}/build/flasher_args.json
54+
${{ env.TEST_DIR }}/build/config/sdkconfig.h
55+
${{ env.TEST_DIR }}/build/config/sdkconfig.json
56+
if-no-files-found: error
57+
58+
# run-target-autobahn:
59+
# # Skip running on forks since it won't have access to secrets
60+
# if: |
61+
# github.repository == 'espressif/esp-protocols' &&
62+
# ( contains(github.event.pull_request.labels.*.name, 'autobahn') || github.event_name == 'push' )
63+
# name: Target test
64+
# needs: build_autobahn
65+
# strategy:
66+
# fail-fast: false
67+
# matrix:
68+
# idf_ver: ["latest"]
69+
# idf_target: ["esp32"]
70+
# runs-on:
71+
# - self-hosted
72+
# - ESP32-ETHERNET-KIT
73+
# env:
74+
# TEST_DIR: components/esp_websocket_client/examples/autobahn-testsuite
75+
# TESTEE_DIR: components/esp_websocket_client/examples/autobahn-testsuite/testee
76+
# steps:
77+
# - uses: actions/checkout@v4
78+
# with:
79+
# submodules: recursive
80+
# - uses: actions/download-artifact@v4
81+
# with:
82+
# name: autobahn_testee_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
83+
# path: ${{ env.TESTEE_DIR }}/build
84+
# - name: Install Docker Compose
85+
# run: |
86+
# sudo apt-get update
87+
# sudo apt-get install -y docker-compose-plugin || sudo apt-get install -y docker-compose
88+
# # Ensure user has permission to use Docker (if not already in docker group)
89+
# sudo usermod -aG docker $USER || true
90+
# # Start Docker service if not running
91+
# sudo systemctl start docker || true
92+
# - name: Start Autobahn Fuzzing Server
93+
# working-directory: ${{ env.TEST_DIR }}
94+
# run: |
95+
# # Get host IP address for ESP32 to connect to
96+
# HOST_IP=$(hostname -I | awk '{print $1}')
97+
# echo "HOST_IP=$HOST_IP" >> $GITHUB_ENV
98+
# echo "Autobahn server will be accessible at ws://$HOST_IP:9001"
99+
#
100+
# # Start the fuzzing server using pre-built image
101+
# # For CI, we may need to specify platform if architecture differs
102+
# echo "Starting Autobahn fuzzing server..."
103+
# # Set platform for CI if needed (uncomment if you get exec format error)
104+
# # export DOCKER_DEFAULT_PLATFORM=linux/amd64
105+
# docker compose up -d || docker-compose up -d
106+
#
107+
# # Wait for server to be ready
108+
# echo "Waiting for fuzzing server to start..."
109+
# sleep 10
110+
#
111+
# # Check if container is running and healthy
112+
# if ! docker ps | grep -q ws-fuzzing-server; then
113+
# echo "Error: Fuzzing server failed to start"
114+
# echo "Container logs:"
115+
# docker compose logs || docker-compose logs
116+
# echo "Checking available Python executables in container:"
117+
# docker compose run --rm fuzzing-server which python python3 || true
118+
# exit 1
119+
# fi
120+
#
121+
# # Verify the server is actually responding
122+
# echo "Checking if server is responding..."
123+
# sleep 5
124+
# if ! curl -s http://localhost:8080 > /dev/null 2>&1; then
125+
# echo "Warning: Server may not be fully ready, but container is running"
126+
# docker compose logs --tail=20 || docker-compose logs --tail=20
127+
# fi
128+
#
129+
# echo "✓ Fuzzing server started successfully"
130+
# - name: Flash ESP32 Testee
131+
# working-directory: ${{ env.TESTEE_DIR }}/build
132+
# env:
133+
# IDF_TARGET: ${{ matrix.idf_target }}
134+
# run: |
135+
# python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 flash_image.bin
136+
# - name: Run Autobahn Tests
137+
# working-directory: ${{ env.TESTEE_DIR }}
138+
# env:
139+
# PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
140+
# run: |
141+
# # Detect ESP32 port if not set in environment
142+
# if [ -z "${ESP_PORT:-}" ]; then
143+
# for port in /dev/ttyUSB* /dev/ttyACM*; do
144+
# if [ -e "$port" ]; then
145+
# export ESP_PORT="$port"
146+
# echo "Detected ESP32 port: $ESP_PORT"
147+
# break
148+
# fi
149+
# done
150+
# fi
151+
#
152+
# # Default to /dev/ttyUSB0 if still not found
153+
# export ESP_PORT="${ESP_PORT:-/dev/ttyUSB0}"
154+
#
155+
# if [ ! -e "$ESP_PORT" ]; then
156+
# echo "Error: ESP32 port not found. Please set ESP_PORT environment variable."
157+
# echo "Available ports:"
158+
# ls -la /dev/tty* || true
159+
# exit 1
160+
# fi
161+
#
162+
# echo "Using ESP32 port: $ESP_PORT"
163+
# export PYENV_ROOT="$HOME/.pyenv"
164+
# export PATH="$PYENV_ROOT/bin:$PATH"
165+
# eval "$(pyenv init --path)"
166+
# eval "$(pyenv init -)"
167+
# if ! pyenv versions --bare | grep -q '^3\.12\.6$'; then
168+
# echo "Installing Python 3.12.6..."
169+
# pyenv install -s 3.12.6
170+
# fi
171+
# if ! pyenv virtualenvs --bare | grep -q '^myenv$'; then
172+
# echo "Creating pyenv virtualenv 'myenv'..."
173+
# pyenv virtualenv 3.12.6 myenv
174+
# fi
175+
# pyenv activate myenv
176+
# python --version
177+
# pip install --prefer-binary pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool pyserial
178+
# pip install --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
179+
#
180+
# echo "Starting Autobahn test suite on ESP32..."
181+
# echo "Tests may take 15-30 minutes to complete..."
182+
#
183+
# # Send server URI via serial (stdin) and monitor for completion
184+
# # Script is in the parent directory (TEST_DIR) from TESTEE_DIR
185+
# SERVER_URI="ws://$HOST_IP:9001"
186+
# echo "Sending server URI to ESP32: $SERVER_URI"
187+
# python3 ../scripts/monitor_serial.py --port "$ESP_PORT" --uri "$SERVER_URI" --timeout 2400
188+
# - name: Collect Test Reports
189+
# working-directory: ${{ env.TEST_DIR }}
190+
# if: always()
191+
# run: |
192+
# # Stop the fuzzing server
193+
# docker compose down || docker-compose down
194+
#
195+
# # Check if reports were generated
196+
# if [ -d "reports/clients" ]; then
197+
# echo "✓ Test reports found"
198+
# ls -la reports/clients/
199+
# else
200+
# echo "⚠ No test reports found in reports/clients/"
201+
# fi
202+
# - name: Generate Test Summary
203+
# working-directory: ${{ env.TEST_DIR }}
204+
# if: always()
205+
# run: |
206+
# # Generate summary from test results
207+
# # Check for JSON files in both reports/ and reports/clients/
208+
# if [ -d "reports" ] && ( [ -n "$(ls -A reports/*.json 2>/dev/null)" ] || [ -n "$(ls -A reports/clients/*.json 2>/dev/null)" ] ); then
209+
# echo "Generating test summary..."
210+
# python3 scripts/generate_summary.py
211+
# echo ""
212+
# echo "Summary generated successfully!"
213+
# if [ -f "reports/summary.html" ]; then
214+
# echo "HTML summary available at: reports/summary.html"
215+
# fi
216+
# else
217+
# echo "⚠ No JSON test results found, skipping summary generation"
218+
# fi
219+
# - uses: actions/upload-artifact@v4
220+
# if: always()
221+
# with:
222+
# name: autobahn_reports_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
223+
# path: |
224+
# ${{ env.TEST_DIR }}/reports/**
225+
# if-no-files-found: warn

common_components/linux_compat/esp_timer/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
idf_component_register(SRCS esp_timer_linux.c timer_task.cpp
2-
INCLUDE_DIRS include)
2+
INCLUDE_DIRS include
3+
REQUIRES esp_common)
34

45
set_target_properties(${COMPONENT_LIB} PROPERTIES
56
CXX_STANDARD 17

common_components/linux_compat/esp_timer/include/esp_timer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <stdbool.h>
99
#include <stdint.h>
1010
#include "bsd/string.h"
11+
#include "esp_err.h"
1112

1213
#ifdef __cplusplus
1314
extern "C" {

0 commit comments

Comments
 (0)