Files
Warp/server/internal/setup/rtc_test.go
T
tajniak81andClaude Opus 5.5 76dfc98a86
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
Group voice and video calls with MatrixRTC and LiveKit
Every call in the web client now goes through MatrixRTC with a LiveKit
SFU, the model Element Call and Element X use; the legacy 1:1 m.call.*
calls are gone. In a room of two the other person is rung and can answer
or decline; in a bigger room a banner offers to join the call. Calls show
a grid of participant tiles with mute, camera, screen sharing and leave,
and media is end-to-end encrypted in encrypted rooms.

Server:
- MSC4140 delayed events (send/state with a delay, plus the
  delayed_events list/restart/cancel/send API), stored and scheduled, so
  a member whose client drops off is taken out of the call.
- POST /user/{userId}/openid/request_token, which lk-jwt-service uses to
  hand out LiveKit tokens.
- org.matrix.msc4143.rtc_foci in /.well-known/matrix/client, configured
  under client_api.rtc.
- Room presets let members send call membership state.
- Migration 0014 for both SQL dialects.

Deploy: LiveKit and lk-jwt-service in compose (calls.yml) and the helm
chart. Docs: docs/calls.md, configuration and deployment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:33:29 +02:00

88 lines
3.3 KiB
Go

package setup_test
import (
"net/http"
"testing"
"github.com/dariuszjaniak/warp/server/internal/config"
)
// TestWellKnownClientAdvertisesLiveKit: group call clients find the SFU
// they publish to in the discovery document (MSC4143).
func TestWellKnownClientAdvertisesLiveKit(t *testing.T) {
srv := newTestServer(t, func(c *config.Config) {
c.ClientAPI.RTC.LiveKitServiceURL = "https://livekit-jwt.warp.example/"
})
rec := get(t, srv, http.MethodGet, "/.well-known/matrix/client")
if rec.Code != http.StatusOK {
t.Fatalf("status = %d", rec.Code)
}
body := decode[struct {
Foci []map[string]string `json:"org.matrix.msc4143.rtc_foci"`
}](t, rec)
if len(body.Foci) != 1 || body.Foci[0]["type"] != "livekit" ||
body.Foci[0]["livekit_service_url"] != "https://livekit-jwt.warp.example" {
t.Errorf("rtc_foci = %v", body.Foci)
}
}
func TestWellKnownClientOmitsRTCFociByDefault(t *testing.T) {
srv := newTestServer(t, nil)
body := decode[map[string]any](t, get(t, srv, http.MethodGet, "/.well-known/matrix/client"))
if _, present := body["org.matrix.msc4143.rtc_foci"]; present {
t.Error("rtc_foci must be omitted when no LiveKit service is configured")
}
}
func TestRTCConfigValidation(t *testing.T) {
cfg := config.Default()
cfg.Global.ServerName = "warp.example"
cfg.ClientAPI.RTC.LiveKitServiceURL = "livekit-jwt.warp.example"
if err := cfg.Validate(); err == nil {
t.Error("a LiveKit service URL without a scheme was accepted")
}
cfg.ClientAPI.RTC.LiveKitServiceURL = ""
cfg.ClientAPI.DelayedEvents.MaxPerUser = 0
if err := cfg.Validate(); err == nil {
t.Error("delayed events with no room for any were accepted")
}
}
// TestGroupCallRoutesAreWiredUp: with a signing key (and so rooms) the
// server advertises delayed events, serves their endpoints, and hands out
// OpenID tokens the userinfo endpoint accepts.
func TestGroupCallRoutesAreWiredUp(t *testing.T) {
srv := newSigningServer(t, func(c *config.Config) {
c.Registration.Enabled = true
c.ClientAPI.RateLimit.Enabled = false
})
features := decode[map[string]any](t, get(t, srv, http.MethodGet, "/_matrix/client/versions"))["unstable_features"].(map[string]any)
if features["org.matrix.msc4140"] != true {
t.Errorf("unstable_features = %v", features)
}
token := registerThrough(t, srv, "alice")
if rec := getWithToken(t, srv, "/_matrix/client/unstable/org.matrix.msc4140/delayed_events", token); rec.Code != http.StatusOK {
t.Errorf("delayed_events: %d %s", rec.Code, rec.Body.String())
}
rec := post(t, srv, "/_matrix/client/v3/user/@alice:warp.example/openid/request_token", map[string]any{}, token)
if rec.Code != http.StatusOK {
t.Fatalf("request_token: %d %s", rec.Code, rec.Body.String())
}
openID := decode[map[string]any](t, rec)["access_token"].(string)
rec = get(t, srv, http.MethodGet, "/_matrix/federation/v1/openid/userinfo?access_token="+openID)
if rec.Code != http.StatusOK {
t.Errorf("userinfo: %d %s", rec.Code, rec.Body.String())
}
}
func TestDelayedEventsCanBeSwitchedOff(t *testing.T) {
srv := newSigningServer(t, func(c *config.Config) {
c.ClientAPI.DelayedEvents.MaxDelay = 0
})
features := decode[map[string]any](t, get(t, srv, http.MethodGet, "/_matrix/client/versions"))["unstable_features"].(map[string]any)
if _, present := features["org.matrix.msc4140"]; present {
t.Errorf("unstable_features = %v", features)
}
}