1
0
mirror of https://github.com/ossrs/srs.git synced 2026-10-24 09:59:20 +03:00
Files
srs/skills/srs-develop/scripts/proxy-e2e-test.sh
Winlin 55b4218a6b Skills: Isolate test ports and test ST on every OS. v8.0.57 (#4761)
Improve test isolation and cross-platform testing, and update the AI
skills. No SRS media server or proxy code changes; only tests, test
tools and skills change.

## Test ports

Every test layer gets its own port range below the Linux ephemeral range
(32768+), so tests run in parallel, alongside a human SRS or Docker
container, and a client socket never takes a port a test picked.

- Each test script takes one optional `SRS_TEST_PORT_BASE` and defaults
to its own 100-port slot: 11000-11700 for the eight proxy E2E scripts,
12100-12800 for the config-file, reload, GB28181 and RTC scripts. This
replaces `SRS_E2E_PORT_OFFSET` and the per-port `SRS_GB_*`,
`SRS_PLAIN_*` and `SRS_RTX_*` variables, so a Full tier sets no port
variables.
- The regression SRS runs on 13000+ through the `SRS_*_LISTEN` env, with
its pid and log in `/tmp/srs-regression`. `srs_test` adds
`-srs-rtmp-port`, `-srs-api-port` and `-srs-rtsp-port`, so it no longer
needs 1935, 1985 or 8554.
- Black-box tests allocate from 21000-25999 (`SRS_BLACKBOX_PORTS`), and
the custom-port RTSP case now allocates its port too. C++ utests use
26000-29999 (`SRS_UTEST_PORTS`).
- The Port Plan in `integration-tests.md` is the source of truth, with
every range, its owner, and the ports bound and still free.

## State Threads on every OS

- New `st-test.sh` detects the platforms and runs every ST test on each:
the local OS first, then Linux in Docker and Windows x64 in parallel,
with a summary per OS and the platforms not tested and why.
`st-test-runner.sh` runs one build.
- New `st-windows-test.sh`, opted in by `SRS_TEST_WINDOWS_HOST`, mirrors
the local checkout on a Windows host over SSH. It syncs a commit by
pushing to the branch's upstream, never `origin`.
- `full-tier-lock.sh` takes `--product`, so ST runs hold their own lock
and run in parallel with SRS tiers.

## Skills

- `srs-autopilot`: `tasks/tracker.md` lists every task file and its
state, and this skill's rows are owned by `SRS`. Each task gets its own
worktree and branch in every repository it changes. Tests are reported
by OS and CPU.
- `srs-develop`: `testable-code.md` covers the test platforms and
running tests in a subagent. New Step 5 verifies ST on Windows. Issue
titles start with the owning component: `SRS:`, `Proxy:`, `ST:` or
`Oryx:`.
- `internal-codemap-for-srs` and `internal-docs-for-srs`: the C++ test
map moves into `cpp-server.md`, `go-server.md` adds the Go proxy tests,
and the docs list the native Windows x64 coroutine doc and
`md_win64.asm`.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:46:29 -04:00

208 lines
6.5 KiB
Bash
Executable File

#!/bin/bash
# E2E test for RTMP proxy: starts proxy + SRS origin, publishes an RTMP stream,
# verifies playback via ffprobe, then cleans up all processes.
set -e
SCRIPT_DIR="$(cd -P "$(dirname "$0")" && pwd)"
# Walk up from SCRIPT_DIR looking for go.mod. This avoids brittle "../../../.."
# counting when the skills directory is reached via a symlink (which changes
# the symbolic vs. physical depth).
WORKSPACE="$SCRIPT_DIR"
while [[ "$WORKSPACE" != "/" && ! -f "$WORKSPACE/go.mod" ]]; do
WORKSPACE="$(dirname "$WORKSPACE")"
done
if [[ ! -f "$WORKSPACE/go.mod" ]]; then
echo "Error: go.mod not found walking up from: $SCRIPT_DIR" >&2
exit 1
fi
# Ports — use high ports to avoid conflicts with running services.
# The proxy starts ALL servers, so we must assign unique ports for each.
# SRS_TEST_PORT_BASE, by default this script's slot in the Port Plan, moves every port,
# so the scripts can run in parallel.
PORT_BASE=${SRS_TEST_PORT_BASE:-11000}
PROXY_RTMP_PORT=$((PORT_BASE + 0))
PROXY_HTTP_API_PORT=$((PORT_BASE + 1))
PROXY_HTTP_SERVER_PORT=$((PORT_BASE + 2))
PROXY_WEBRTC_PORT=$((PORT_BASE + 3))
PROXY_SRT_PORT=$((PORT_BASE + 4))
PROXY_SYSTEM_API_PORT=$((PORT_BASE + 5))
SOURCE_FLV="$WORKSPACE/trunk/doc/source.flv"
SRS_BINARY="$WORKSPACE/trunk/objs/srs"
source "$SCRIPT_DIR/proxy-e2e-origin.sh"
# Randomize per run so each invocation starts from clean origin state (HLS
# segments, RTMP source, proxy stream registry) and never shares state with
# sibling E2E tests that publish to "live/livestream".
STREAM_URL="live/rtmp$(date +%s)"
# PIDs to clean up on exit.
PROXY_PID=""
ORIGIN_PID=""
FFMPEG_PID=""
cleanup() {
echo ""
echo "=== Cleaning up ==="
for pid in $PROXY_PID $ORIGIN_PID $FFMPEG_PID; do
if kill -0 "$pid" 2>/dev/null; then
kill "$pid" 2>/dev/null || true
fi
done
sleep 1
for pid in $PROXY_PID $ORIGIN_PID $FFMPEG_PID; do
if kill -0 "$pid" 2>/dev/null; then
kill -9 "$pid" 2>/dev/null || true
fi
done
echo "Cleanup done."
}
trap cleanup EXIT
echo "=== E2E RTMP Proxy Test ==="
echo "Workspace: $WORKSPACE"
echo ""
# --- Pre-checks ---
if [[ ! -f "$SOURCE_FLV" ]]; then
echo "Error: test source not found: $SOURCE_FLV" >&2
exit 1
fi
if ! command -v ffmpeg &>/dev/null; then
echo "Error: ffmpeg not found in PATH" >&2
exit 1
fi
if ! command -v ffprobe &>/dev/null; then
echo "Error: ffprobe not found in PATH" >&2
exit 1
fi
# Origin ports (from srs_proxy_origin 1 in proxy-e2e-origin.sh).
ORIGIN_RTMP_PORT=$((PORT_BASE + 20))
ORIGIN_HTTP_PORT=$((PORT_BASE + 21))
ORIGIN_API_PORT=$((PORT_BASE + 22))
ORIGIN_RTC_PORT=$((PORT_BASE + 23))
ORIGIN_SRT_PORT=$((PORT_BASE + 24))
# --- Step 0: Clean up stale state ---
# Kill any leftover processes on our ports (proxy + origin).
ALL_PORTS="$PROXY_RTMP_PORT $PROXY_HTTP_API_PORT $PROXY_HTTP_SERVER_PORT $PROXY_WEBRTC_PORT $PROXY_SRT_PORT $PROXY_SYSTEM_API_PORT $ORIGIN_RTMP_PORT $ORIGIN_HTTP_PORT $ORIGIN_API_PORT $ORIGIN_RTC_PORT $ORIGIN_SRT_PORT"
for port in $ALL_PORTS; do
# Kill only listeners: a client of the port, such as another test's player, is not ours.
lsof -ti TCP:"$port" -sTCP:LISTEN 2>/dev/null | xargs kill 2>/dev/null || true
lsof -nP -iUDP:"$port" 2>/dev/null | awk -v p=":$port" 'NR > 1 && $9 !~ /->/ && $9 ~ p "$" {print $2}' | xargs kill 2>/dev/null || true
done
sleep 1
# --- Step 1: Build proxy ---
echo "=== Step 1: Building proxy ==="
cd "$WORKSPACE"
make -s 2>&1
echo "Proxy built: $WORKSPACE/srs-proxy"
# --- Step 2: Build SRS origin (if not already built) ---
if [[ ! -f "$SRS_BINARY" ]]; then
echo "=== Step 2: Building SRS origin ==="
cd "$WORKSPACE/trunk"
./configure --simulator=on && make 2>&1 | tail -3
echo "SRS origin built: $SRS_BINARY"
else
echo "=== Step 2: SRS origin already built ==="
fi
# --- Step 3: Start proxy ---
echo "=== Step 3: Starting proxy (RTMP :$PROXY_RTMP_PORT, System API :$PROXY_SYSTEM_API_PORT) ==="
cd "$WORKSPACE"
env PROXY_RTMP_SERVER=$PROXY_RTMP_PORT \
PROXY_HTTP_API=$PROXY_HTTP_API_PORT \
PROXY_HTTP_SERVER=$PROXY_HTTP_SERVER_PORT \
PROXY_WEBRTC_SERVER=$PROXY_WEBRTC_PORT \
PROXY_SRT_SERVER=$PROXY_SRT_PORT \
PROXY_SYSTEM_API=$PROXY_SYSTEM_API_PORT \
PROXY_LOAD_BALANCER_TYPE=memory \
./bin/srs-proxy >/tmp/srs-proxy-e2e.log 2>&1 &
PROXY_PID=$!
echo "Proxy PID: $PROXY_PID"
sleep 1
if ! kill -0 "$PROXY_PID" 2>/dev/null; then
echo "Error: proxy failed to start. Logs:" >&2
cat /tmp/srs-proxy-e2e.log >&2
exit 1
fi
echo "Proxy started."
# --- Step 4: Start SRS origin ---
echo "=== Step 4: Starting SRS origin ==="
ulimit -n 10000 2>/dev/null || true
cd "$WORKSPACE/trunk"
srs_proxy_origin 1 >/tmp/srs-origin-e2e.log 2>&1 &
ORIGIN_PID=$!
echo "SRS origin PID: $ORIGIN_PID"
# Wait for SRS to register with proxy: the first heartbeat is sent at startup, then every 9s.
echo "Waiting for SRS origin to register with proxy (up to 15s)..."
for i in $(seq 1 15); do
if grep -q "Register SRS media server" /tmp/srs-proxy-e2e.log 2>/dev/null; then
break
fi
sleep 1
done
if ! grep -q "Register SRS media server" /tmp/srs-proxy-e2e.log 2>/dev/null; then
echo "Error: SRS origin did not register with proxy after 15s. Proxy logs:" >&2
cat /tmp/srs-proxy-e2e.log >&2
exit 1
fi
if ! kill -0 "$ORIGIN_PID" 2>/dev/null; then
echo "Error: SRS origin failed to start. Logs:" >&2
cat /tmp/srs-origin-e2e.log >&2
exit 1
fi
echo "SRS origin started and registered."
# --- Step 5: Publish RTMP stream ---
echo "=== Step 5: Publishing RTMP stream to proxy ==="
ffmpeg -stream_loop -1 -re -i "$SOURCE_FLV" -c copy -f flv \
"rtmp://localhost:$PROXY_RTMP_PORT/$STREAM_URL" >/tmp/srs-ffmpeg-e2e.log 2>&1 &
FFMPEG_PID=$!
echo "FFmpeg publisher PID: $FFMPEG_PID"
# Wait for stream to stabilize.
sleep 5
if ! kill -0 "$FFMPEG_PID" 2>/dev/null; then
echo "Error: FFmpeg publisher failed. Logs:" >&2
cat /tmp/srs-ffmpeg-e2e.log >&2
exit 1
fi
echo "Stream publishing."
# --- Step 6: Verify RTMP playback ---
echo "=== Step 6: Verifying RTMP playback via proxy ==="
PROBE_OUTPUT=$(ffprobe -v error -show_streams \
"rtmp://localhost:$PROXY_RTMP_PORT/$STREAM_URL" 2>&1 || true)
if echo "$PROBE_OUTPUT" | grep -q "codec_type=video"; then
echo "PASS: Video stream detected."
else
echo "FAIL: No video stream detected." >&2
echo "ffprobe output:" >&2
echo "$PROBE_OUTPUT" >&2
exit 1
fi
if echo "$PROBE_OUTPUT" | grep -q "codec_type=audio"; then
echo "PASS: Audio stream detected."
else
echo "FAIL: No audio stream detected." >&2
echo "ffprobe output:" >&2
echo "$PROBE_OUTPUT" >&2
exit 1
fi
echo ""
echo "=== E2E RTMP Proxy Test PASSED ==="