package api import ( "encoding/json" "testing" "github.com/datarhei/core/v16/restream/app" ) // TestProcessConfigWebRTCRoundtrip locks down the API DTO ↔ restream // app.Config mapping for the per-process WebRTC block. // // Regression: the M2 cut shipped without WebRTC on ProcessConfig, so // JSON arriving at POST /api/v3/process was silently stripped of // `webrtc.enabled`, the restream config never saw it, the start hook // never bound a Source, and WHEP returned 404. This test fails on the // pre-fix code (Marshal would yield `app.ConfigWebRTC{}`) and passes // once the DTO carries the field. func TestProcessConfigWebRTCRoundtrip(t *testing.T) { // 1. JSON in → DTO → app.Config body := []byte(`{ "id":"p","input":[{"id":"i","address":"x"}],"output":[{"id":"o","address":"-"}], "webrtc":{"enabled":true,"video_pt":102,"audio_pt":111,"force_transcode":true} }`) var dto ProcessConfig if err := json.Unmarshal(body, &dto); err != nil { t.Fatalf("unmarshal: %v", err) } if !dto.WebRTC.Enabled { t.Fatalf("DTO.WebRTC.Enabled lost on JSON decode: %+v", dto.WebRTC) } cfg := dto.Marshal() if !cfg.WebRTC.Enabled || cfg.WebRTC.VideoPT != 102 || cfg.WebRTC.AudioPT != 111 || !cfg.WebRTC.ForceTranscode { t.Fatalf("app.Config.WebRTC mapped wrong: %+v", cfg.WebRTC) } // 2. app.Config → DTO → JSON out stored := &app.Config{ ID: "p", Input: []app.ConfigIO{{ID: "i", Address: "x"}}, Output: []app.ConfigIO{{ID: "o", Address: "-"}}, WebRTC: app.ConfigWebRTC{ Enabled: true, VideoPT: 102, AudioPT: 111, ForceTranscode: true, }, } var dto2 ProcessConfig dto2.Unmarshal(stored) if !dto2.WebRTC.Enabled || dto2.WebRTC.VideoPT != 102 { t.Fatalf("Unmarshal lost WebRTC: %+v", dto2.WebRTC) } out, err := json.Marshal(dto2) if err != nil { t.Fatalf("marshal: %v", err) } // Decode again and compare. var dto3 ProcessConfig if err := json.Unmarshal(out, &dto3); err != nil { t.Fatalf("re-unmarshal: %v", err) } if dto3.WebRTC != dto.WebRTC { t.Fatalf("roundtrip diverged: in=%+v out=%+v", dto.WebRTC, dto3.WebRTC) } } // TestProcessConfigWebRTCDefaults: when "webrtc" is absent in the // inbound JSON, Marshal must still produce a valid app.Config — the // zero ConfigWebRTC means "disabled" and the start hook should no-op. func TestProcessConfigWebRTCDefaults(t *testing.T) { body := []byte(`{"id":"p","input":[{"id":"i","address":"x"}],"output":[{"id":"o","address":"-"}]}`) var dto ProcessConfig if err := json.Unmarshal(body, &dto); err != nil { t.Fatalf("unmarshal: %v", err) } cfg := dto.Marshal() if cfg.WebRTC.Enabled { t.Fatalf("default should be disabled, got %+v", cfg.WebRTC) } }