test(webrtc): add metrics unit tests
Some checks failed
ci / race tests (push) Blocked by required conditions
ci / WebRTC smoke (5-viewer fanout) (push) Blocked by required conditions
ci / WebRTC latency p95 gate (push) Blocked by required conditions
ci / vet + build (push) Has been cancelled

This commit is contained in:
Zac Gaetano 2026-05-06 15:58:50 -04:00
parent 47a28bf9d4
commit 1748f9102d

149
app/webrtc/metrics_test.go Normal file
View file

@ -0,0 +1,149 @@
package webrtc
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/labstack/echo/v4"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/datarhei/core/v16/config"
)
func newTestHandler(t *testing.T) (*Handler, *prometheus.Registry) {
t.Helper()
s, err := New(config.DataWebRTC{Enable: true}, nil)
if err != nil {
t.Fatalf("New: %v", err)
}
h := NewHandler(s, 0)
reg := prometheus.NewRegistry()
h.InitMetrics(reg, "test")
return h, reg
}
// TestMetrics_Subscribe404BumpsCounter checks that a 404 on unknown stream
// increments the request counter with the correct labels.
func TestMetrics_Subscribe404BumpsCounter(t *testing.T) {
h, reg := newTestHandler(t)
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/whep/ghost", strings.NewReader("v=0\r\n"))
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetParamNames("id")
c.SetParamValues("ghost")
_ = h.Subscribe(c)
if rec.Code != http.StatusNotFound {
t.Fatalf("expected 404, got %d", rec.Code)
}
if err := testutil.GatherAndCompare(reg, strings.NewReader(`
# HELP dragonfork_webrtc_whep_requests_total Count of WHEP HTTP requests by route, HTTP status code, and stream.
# TYPE dragonfork_webrtc_whep_requests_total counter
dragonfork_webrtc_whep_requests_total{code="404",core="test",route="subscribe",stream_id="ghost"} 1
`), "dragonfork_webrtc_whep_requests_total"); err != nil {
t.Fatal(err)
}
}
// TestMetrics_GlobalCapBumpsCapRejection checks that a global cap 503 fires
// the cap_rejections counter with scope=global.
func TestMetrics_GlobalCapBumpsCapRejection(t *testing.T) {
s, err := New(config.DataWebRTC{Enable: true}, nil)
if err != nil {
t.Fatalf("New: %v", err)
}
// maxPeers=1, but inject a stream so we get past lookup
s.mu.Lock()
s.streams["mystream"] = &processStream{id: "mystream"}
s.mu.Unlock()
h := NewHandlerWithCaps(s, 1, 0)
reg := prometheus.NewRegistry()
h.InitMetrics(reg, "test")
// Force count to be at cap
h.count = 1
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/whep/mystream", strings.NewReader("v=0\r\n"))
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetParamNames("id")
c.SetParamValues("mystream")
_ = h.Subscribe(c)
if rec.Code != http.StatusServiceUnavailable {
t.Fatalf("expected 503, got %d", rec.Code)
}
n := testutil.ToFloat64(h.met.capRejections.WithLabelValues("", "global"))
if n != 1 {
t.Fatalf("cap_rejections{scope=global}: want 1, got %v", n)
}
}
// TestMetrics_CodecMismatchBumpsCounter checks that a 406 SDP with no H264
// increments codec_mismatches{kind=h264}.
func TestMetrics_CodecMismatchBumpsCounter(t *testing.T) {
s, err := New(config.DataWebRTC{Enable: true}, nil)
if err != nil {
t.Fatalf("New: %v", err)
}
s.mu.Lock()
s.streams["cam"] = &processStream{id: "cam"}
s.mu.Unlock()
h := NewHandler(s, 0)
reg := prometheus.NewRegistry()
h.InitMetrics(reg, "test")
// SDP with Opus but no H264
sdp := "v=0\r\na=rtpmap:111 opus/48000/2\r\n"
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/whep/cam", strings.NewReader(sdp))
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetParamNames("id")
c.SetParamValues("cam")
_ = h.Subscribe(c)
if rec.Code != http.StatusNotAcceptable {
t.Fatalf("expected 406, got %d", rec.Code)
}
n := testutil.ToFloat64(h.met.codecMismatches.WithLabelValues("cam", "h264"))
if n != 1 {
t.Fatalf("codec_mismatches{kind=h264}: want 1, got %v", n)
}
}
// TestMetrics_Stats returns consistent snapshots at zero and with streams.
func TestMetrics_Stats(t *testing.T) {
h, _ := newTestHandler(t)
got := h.Stats()
if got.StreamCount != 0 {
t.Fatalf("expected 0 streams, got %d", got.StreamCount)
}
if got.UDPPortsInUse != 0 {
t.Fatalf("expected 0 udp ports, got %d", got.UDPPortsInUse)
}
// Inject a stream to verify counts update
h.sub.mu.Lock()
h.sub.streams["test"] = &processStream{id: "test"}
h.sub.mu.Unlock()
got = h.Stats()
if got.StreamCount != 1 {
t.Fatalf("expected 1 stream, got %d", got.StreamCount)
}
if got.UDPPortsInUse != 2 {
t.Fatalf("expected 2 udp ports, got %d", got.UDPPortsInUse)
}
}