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) } }