Three artifacts that close out the easier half of the M4 milestone:
1. .forgejo/workflows/test.yml — CI on every push and PR. Three jobs:
- lint-and-vet: go vet + go build (~30s)
- test: go test -race -short ./... + a no-race coverage
pass that uploads coverage.out as an artifact
- webrtc-smoke: TestIntegration_FiveViewerFanout and the rest of
the WebRTC subsystem tests in isolation, so a
failure on the egress path stays readable in the
log.
Pinned to Go 1.24 to match go.mod. The forge has a
forgejo-runner sibling container; this YAML uses GitHub Actions
syntax which Forgejo Actions accepts unchanged.
2. test/whep-player.html — self-contained browser WHEP subscriber for
manual smoke testing. RTCPeerConnection (recvonly V+A) + fetch()
POST/DELETE/PATCH against /api/v3/whep/:id, ICE/PC state pills,
inbound-bitrate sampling at 1 Hz, codec hint pulled from the answer
SDP, JWT token field, ?url=&token= shareable query string. No
external deps; works from file:// or any static host.
3. test/TESTING.md — short doc that ties together the in-process race
tests, the browser player, and the existing Pion CLI helper at
test/whep-client/. Notes the latency p95 gate as a follow-up.
Latency gate (FFmpeg drawtext frame counter + decode-side pixel
sampling, p95 < 300ms RTMP / < 200ms SRT) is queued for a separate
PR — it's a several-hundred-line addition in its own right and
shouldn't block CI from landing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2 KiB
Testing the WebRTC egress path
In-process (CI)
go test -race -count=1 ./app/webrtc/... ./core/webrtc/...
The integration tests under app/webrtc/ allocate UDP ports on
loopback, spin up an Echo handler, attach a Pion subscriber, and
spray synthetic RTP into the registered Source. TestIntegration_FiveViewerFanout
covers the 5-concurrent-viewer acceptance path from the M3 design.
Manual / browser
whep-player.html is a self-contained WHEP subscriber a human can
point at any live deploy. Open it directly in a browser:
file:///path/to/datarhei-dragonfork-core/test/whep-player.html
…or copy it onto a static host (no server-side dependency). It accepts
the WHEP URL and an optional bearer token (the deploy uses Core's
JWT, so paste an access_token from POST /api/login). It POSTs an
SDP offer with a recvonly video + audio transceiver, applies the
answer, and renders the stream in <video>. Stats panel shows ICE +
PeerConnection states, the codec pulled from the answer SDP, and a
1-Hz inbound-bitrate sample. Disconnect issues a WHEP DELETE on
the resource URL the server returned in Location.
Shareable URL:
file:///.../whep-player.html?url=http://10.0.0.25:8090/api/v3/whep/myStream&token=eyJhbGciOi...
Pion CLI helper
test/whep-client/ is the same handshake in Go, useful for scripting
or running on the same machine as Core for an apples-to-apples loopback
test:
cd test/whep-client
go build -o /tmp/whep-client .
/tmp/whep-client -url http://10.0.0.25:8090/api/v3/whep/myStream -token "$JWT" -timeout 15s
Exits 0 once both video and audio tracks have received their first RTP packet. Used in the M2 deploy verification on TrueNAS.
Latency p95 gate
Not yet wired into CI as of this milestone; tracked as a follow-on. The
design (docs/design/2026-04-16-datarhei-dragon-fork-webrtc-design.md §7)
calls for a publisher that burns a frame counter via FFmpeg drawtext,
a decoder that samples a known bounding box, and a CI threshold of
p95 < 300ms (RTMP) / p95 < 200ms (SRT).