Skip to content

Proxy: Refactor for testability; add SRT/WHIP E2E and unit tests#4675

Merged
winlinvip merged 15 commits into
ossrs:developfrom
winlinvip:develop
May 17, 2026
Merged

Proxy: Refactor for testability; add SRT/WHIP E2E and unit tests#4675
winlinvip merged 15 commits into
ossrs:developfrom
winlinvip:develop

Conversation

@winlinvip
Copy link
Copy Markdown
Member

  • Refactor the Go proxy for dependency injection: every proxy server, the
    bootstrap, the signal handler, the load balancers, and AMF0 now accept
    functional-option seams (factories/closures) so tests can inject fakes
    without binding real sockets, talking to real Redis, or racing on package
    globals.
  • Drop the package-global lb.SrsLoadBalancer. The bootstrap creates the LB
    locally and threads it through every proxy server constructor. Two old
    global indirections in internal/signal and internal/rtmp/amf0 are
    likewise replaced by per-instance fields.
  • Rename internal/serverinternal/proxy and rename the lb public
    surface for clarity: SRSLoadBalancer is split into OriginService /
    HLSService / RTCService and recomposed as OriginLoadBalancer;
    SRSServerOriginServer; all proxy server types gain a Proxy
    qualifier (e.g. RTMPServerRTMPProxyServer).
  • Extract the Redis client behind a new internal/redisclient package with
    a minimal RedisClient interface and a counterfeiter fake.
  • Add counterfeiter fakes (proxyfakes, lbfakes, redisclientfakes) and
    ~7.5k lines of unit tests covering bootstrap, memory + Redis LBs, all five
    proxy servers, the signal handler, and AMF0.
  • Add two new E2E flows — proxy-e2e-srt-test.sh (SRT publish through proxy,
    verify SRT/RTMP/HTTP-FLV/HLS playback) and proxy-e2e-whip-test.sh (WHIP
    publish, verify RTMP/HTTP-FLV/HLS via origin rtc_to_rtmp) — plus
    setup-ffmpeg-with-whip.sh, a macOS builder for an ffmpeg with openssl-DTLS
    WHIP and SRT support that the two scripts auto-invoke when needed.
  • Workspace reorg: move memory/ and skills/ to the repo root so all agent
    tools (Claude / Codex / Kiro / OpenClaw) share one source of truth via
    symlinks. Sync docs/proxy/proxy-load-balancer.md and
    memory/srs-codebase-map.md with the new names.

No protocol, log, HTTP API, or wire-format changes. Refactor only — all
externally observable proxy behavior is unchanged.

winlinvip and others added 15 commits May 10, 2026 18:09
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New `proxy-e2e-srt-test.sh`: publishes SRT through the proxy and
  verifies SRT, RTMP, HTTP-FLV, and HLS playback (origin's `srt_to_rtmp`
  + HTTP remux + HLS). WebRTC WHEP is intentionally a placeholder.
  Pre-check requires an ffmpeg with libsrt and prints the exact
  homebrew-ffmpeg `--with-srt` recipe when missing, since the default
  `brew install ffmpeg` does not include SRT support.
- `proxy-e2e-transmux-test.sh`: drop the srs-bench `srs_test` dependency
  and the `PROXY_TRANSMUX_TEST_RTC` env. WebRTC WHEP step becomes a
  placeholder, matching the SRT script style. Removes the now-unused
  Step 3 build of the WebRTC regression tool and renumbers the
  remaining steps.
- `.openclaw/memory/srs-codebase-map.md`: register the new SRT script.
- `.openclaw/skills/srs-develop/SKILL.md`: list the SRT script in the
  proxy verification flow and update the transmux description so it no
  longer mentions WebRTC verification or the dropped env var.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Randomize proxy E2E stream names to avoid stale shared state between runs, and make the WHIP HLS check skip the first possibly incomplete segment before requiring audio/video playback.

Verified with the full srs-develop proxy script set: proxy unit coverage and all proxy E2E scripts passed.

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Create the origin load balancer in proxy bootstrap and pass it explicitly into protocol servers and system API handlers. Also keep load balancer implementations package-private and rename the default debugging origin helper.

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
…bals.

- Split OriginLoadBalancer into OriginService / HLSService / RTCService;
  the original interface now embeds the three role interfaces. Generate
  counterfeiter fakes for all four.
- Extract internal/redisclient: RedisClient interface + New() factory.
  internal/lb/redis.go no longer imports github.com/go-redis/redis/v8.
- Add unit tests for lb.go (OriginServer.ID/String/Format/NewOriginServer)
  and for the full memory + redis load balancers.
- Replace package-level test seams (memoryKeepaliveInterval, newRedisClient,
  redisKeepaliveInterval, signal.signalNotify/osExit, rtmp.createBuffer) with
  per-instance struct fields so concurrent tests can't race on them.
- Promote signal.InstallSignals / InstallForceQuit onto a new signal.Handler
  type; update bootstrap to construct one.
- Move rtmp createBuffer onto amf0ObjectBase as bufFactory; the three AMF0
  marshalers and their tests use the per-instance factory.
- Make proxy test scripts locate the workspace by walking up to go.mod
  instead of brittle '../../../..' counting (symlink-aware).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refactor internal/proxy/rtmp.go to expose functional-option seams
(listen, newConnection, newHandshake, newProtocol, newBackend, dial)
and widen the proxy server and connection to net.Listener / net.Conn
so fakes can be injected. Tighten the identify switch in serve() to
a real switch on CommandName.

Add internal/proxy/rtmp_test.go covering rtmpProxyServer (constructor
defaults, options, Close, listen error, endpoint normalization,
accept-loop, graceful shutdown), rtmpConnection (defaults, serve
handshake/protocol error paths, identify-loop branches, newBackend
invocation contract), and rtmpClientToBackend (Close, Connect happy
and error paths, publish, play). rtmp.go statement coverage rises to
76.9% with every function exercised.
Introduce listenUDP and backendURL functional-option seams on
webRTCProxyServer and a dialBackendUDP seam on rtcConnection, mirroring
the pattern already used by rtmpProxyServer. The seams default to the
real net.ListenUDP / http URL builder / net.Dialer so production
behavior is unchanged, but unit tests can now inject fakes.

Cover webRTCProxyServer with focused tests: constructor defaults
(including the three default-backendURL branches), Close with no
listener, Run's listen error / endpoint normalization / graceful
shutdown, HandleApiForWHIP and HandleApiForWHEP CORS preflight, Pick
error, full happy-path against an httptest backend asserting SDP port
rewrite and StoreWebRTC wiring, proxyApiToBackend error paths
(backendURL error, non-2xx, malformed answer), and handleClientUDP's
non-STUN, RTP-like, short-STUN, cached-username, LB-load, LB-error,
and cached-address paths. internal/proxy package coverage rises from
~23% to 43.4%.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the listener and backend dial seams already in place on rtc.go so
the SRT proxy is unit-testable without binding real UDP sockets:
- srsSRTProxyServer.listener: *net.UDPConn -> net.PacketConn, with a
  new listenUDP factory injected via functional option.
- SRTConnection.backendUDP: *net.UDPConn -> io.ReadWriteCloser, with a
  new dialBackendUDP factory; connectBackend uses it instead of
  building a net.UDPAddr and calling net.DialUDP directly.
- handleClientUDP / HandlePacket / handleHandshake take net.Addr
  instead of *net.UDPAddr; writes go through PacketConn.WriteTo.
- Fix a latent SA4001: v.handshake3 = &*handshake3p was no copy at
  all, so the subsequent SynCookie rewrite mutated the just-decoded
  backend packet. Replace with an explicit value copy.

Adds internal/proxy/srt_test.go covering SRTHandshakePacket marshal
roundtrip and stream-id parsing (100%), SRTConnection handshake-0,
handshake-2 full replay, and connectBackend error paths, plus
srsSRTProxyServer constructor/lifecycle and handleClientUDP routing.
Reuses fakeBackendUDP / fakePacketConn / blockingUDPListener from
rtc_test.go for consistency.

Verified with proxy-utest.sh and the full proxy-e2e suite (rtmp,
cluster, redis, transmux, srt, whip).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@winlinvip winlinvip merged commit f491c1e into ossrs:develop May 17, 2026
12 checks passed
winlinvip added a commit that referenced this pull request May 17, 2026
- Refactor the Go proxy for dependency injection: every proxy server,
the bootstrap, the signal handler, the load balancers, and AMF0 now accept
functional-option seams (factories/closures) so tests can inject fakes
without binding real sockets, talking to real Redis, or racing on
package globals.

- Drop the package-global `lb.SrsLoadBalancer`. The bootstrap creates
the LB locally and threads it through every proxy server constructor. Two old
global indirections in `internal/signal` and `internal/rtmp/amf0` are
likewise replaced by per-instance fields.

- Rename `internal/server` → `internal/proxy` and rename the `lb` public
surface for clarity: `SRSLoadBalancer` is split into `OriginService` /
`HLSService` / `RTCService` and recomposed as `OriginLoadBalancer`;
`SRSServer` → `OriginServer`; all proxy server types gain a `Proxy`
qualifier (e.g. `RTMPServer` → `RTMPProxyServer`).

- Extract the Redis client behind a new `internal/redisclient` package
with a minimal `RedisClient` interface and a counterfeiter fake.

- Add counterfeiter fakes (`proxyfakes`, `lbfakes`, `redisclientfakes`)
and ~7.5k lines of unit tests covering bootstrap, memory + Redis LBs, all
five proxy servers, the signal handler, and AMF0.

- Add two new E2E flows — `proxy-e2e-srt-test.sh` (SRT publish through
proxy, verify SRT/RTMP/HTTP-FLV/HLS playback) and `proxy-e2e-whip-test.sh`
(WHIP publish, verify RTMP/HTTP-FLV/HLS via origin `rtc_to_rtmp`) — plus
`setup-ffmpeg-with-whip.sh`, a macOS builder for an ffmpeg with
openssl-DTLS WHIP and SRT support that the two scripts auto-invoke when needed.

- Workspace reorg: move `memory/` and `skills/` to the repo root so all
agent tools (Claude / Codex / Kiro / OpenClaw) share one source of truth via
symlinks. Sync `docs/proxy/proxy-load-balancer.md` and
`memory/srs-codebase-map.md` with the new names.

No protocol, log, HTTP API, or wire-format changes. Refactor only — all
  externally observable proxy behavior is unchanged.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
winlinvip added a commit that referenced this pull request May 17, 2026
…0.146 (#4675)

- Refactor the Go proxy for dependency injection: every proxy server,
the bootstrap, the signal handler, the load balancers, and AMF0 now accept
functional-option seams (factories/closures) so tests can inject fakes
without binding real sockets, talking to real Redis, or racing on
package globals.

- Drop the package-global `lb.SrsLoadBalancer`. The bootstrap creates
the LB locally and threads it through every proxy server constructor. Two old
global indirections in `internal/signal` and `internal/rtmp/amf0` are
likewise replaced by per-instance fields.

- Rename `internal/server` → `internal/proxy` and rename the `lb` public
surface for clarity: `SRSLoadBalancer` is split into `OriginService` /
`HLSService` / `RTCService` and recomposed as `OriginLoadBalancer`;
`SRSServer` → `OriginServer`; all proxy server types gain a `Proxy`
qualifier (e.g. `RTMPServer` → `RTMPProxyServer`).

- Extract the Redis client behind a new `internal/redisclient` package
with a minimal `RedisClient` interface and a counterfeiter fake.

- Add counterfeiter fakes (`proxyfakes`, `lbfakes`, `redisclientfakes`)
and ~7.5k lines of unit tests covering bootstrap, memory + Redis LBs, all
five proxy servers, the signal handler, and AMF0.

- Add two new E2E flows — `proxy-e2e-srt-test.sh` (SRT publish through
proxy, verify SRT/RTMP/HTTP-FLV/HLS playback) and `proxy-e2e-whip-test.sh`
(WHIP publish, verify RTMP/HTTP-FLV/HLS via origin `rtc_to_rtmp`) — plus
`setup-ffmpeg-with-whip.sh`, a macOS builder for an ffmpeg with
openssl-DTLS WHIP and SRT support that the two scripts auto-invoke when needed.

- Workspace reorg: move `memory/` and `skills/` to the repo root so all
agent tools (Claude / Codex / Kiro / OpenClaw) share one source of truth via
symlinks. Sync `docs/proxy/proxy-load-balancer.md` and
`memory/srs-codebase-map.md` with the new names.

No protocol, log, HTTP API, or wire-format changes. Refactor only — all
  externally observable proxy behavior is unchanged.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
winlinvip added a commit that referenced this pull request May 17, 2026
…0.148 (#4675)

- Refactor the Go proxy for dependency injection: every proxy server,
the bootstrap, the signal handler, the load balancers, and AMF0 now accept
functional-option seams (factories/closures) so tests can inject fakes
without binding real sockets, talking to real Redis, or racing on
package globals.

- Drop the package-global `lb.SrsLoadBalancer`. The bootstrap creates
the LB locally and threads it through every proxy server constructor. Two old
global indirections in `internal/signal` and `internal/rtmp/amf0` are
likewise replaced by per-instance fields.

- Rename `internal/server` → `internal/proxy` and rename the `lb` public
surface for clarity: `SRSLoadBalancer` is split into `OriginService` /
`HLSService` / `RTCService` and recomposed as `OriginLoadBalancer`;
`SRSServer` → `OriginServer`; all proxy server types gain a `Proxy`
qualifier (e.g. `RTMPServer` → `RTMPProxyServer`).

- Extract the Redis client behind a new `internal/redisclient` package
with a minimal `RedisClient` interface and a counterfeiter fake.

- Add counterfeiter fakes (`proxyfakes`, `lbfakes`, `redisclientfakes`)
and ~7.5k lines of unit tests covering bootstrap, memory + Redis LBs, all
five proxy servers, the signal handler, and AMF0.

- Add two new E2E flows — `proxy-e2e-srt-test.sh` (SRT publish through
proxy, verify SRT/RTMP/HTTP-FLV/HLS playback) and `proxy-e2e-whip-test.sh`
(WHIP publish, verify RTMP/HTTP-FLV/HLS via origin `rtc_to_rtmp`) — plus
`setup-ffmpeg-with-whip.sh`, a macOS builder for an ffmpeg with
openssl-DTLS WHIP and SRT support that the two scripts auto-invoke when needed.

- Workspace reorg: move `memory/` and `skills/` to the repo root so all
agent tools (Claude / Codex / Kiro / OpenClaw) share one source of truth via
symlinks. Sync `docs/proxy/proxy-load-balancer.md` and
`memory/srs-codebase-map.md` with the new names.

No protocol, log, HTTP API, or wire-format changes. Refactor only — all
  externally observable proxy behavior is unchanged.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
winlinvip added a commit that referenced this pull request May 17, 2026
…0.148 (#4675)

- Refactor the Go proxy for dependency injection: every proxy server,
the bootstrap, the signal handler, the load balancers, and AMF0 now accept
functional-option seams (factories/closures) so tests can inject fakes
without binding real sockets, talking to real Redis, or racing on
package globals.

- Drop the package-global `lb.SrsLoadBalancer`. The bootstrap creates
the LB locally and threads it through every proxy server constructor. Two old
global indirections in `internal/signal` and `internal/rtmp/amf0` are
likewise replaced by per-instance fields.

- Rename `internal/server` → `internal/proxy` and rename the `lb` public
surface for clarity: `SRSLoadBalancer` is split into `OriginService` /
`HLSService` / `RTCService` and recomposed as `OriginLoadBalancer`;
`SRSServer` → `OriginServer`; all proxy server types gain a `Proxy`
qualifier (e.g. `RTMPServer` → `RTMPProxyServer`).

- Extract the Redis client behind a new `internal/redisclient` package
with a minimal `RedisClient` interface and a counterfeiter fake.

- Add counterfeiter fakes (`proxyfakes`, `lbfakes`, `redisclientfakes`)
and ~7.5k lines of unit tests covering bootstrap, memory + Redis LBs, all
five proxy servers, the signal handler, and AMF0.

- Add two new E2E flows — `proxy-e2e-srt-test.sh` (SRT publish through
proxy, verify SRT/RTMP/HTTP-FLV/HLS playback) and `proxy-e2e-whip-test.sh`
(WHIP publish, verify RTMP/HTTP-FLV/HLS via origin `rtc_to_rtmp`) — plus
`setup-ffmpeg-with-whip.sh`, a macOS builder for an ffmpeg with
openssl-DTLS WHIP and SRT support that the two scripts auto-invoke when needed.

- Workspace reorg: move `memory/` and `skills/` to the repo root so all
agent tools (Claude / Codex / Kiro / OpenClaw) share one source of truth via
symlinks. Sync `docs/proxy/proxy-load-balancer.md` and
`memory/srs-codebase-map.md` with the new names.

No protocol, log, HTTP API, or wire-format changes. Refactor only — all
  externally observable proxy behavior is unchanged.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant