Skip to content

Commit 0b8ebbf

Browse files
committed
feat(examples): websocket autobahn test suit integration
1 parent ed569d8 commit 0b8ebbf

File tree

22 files changed

+2599
-12
lines changed

22 files changed

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