mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
Audits what actually has tests, then closes the gaps it found. Full write-up with before/after numbers in docs/audit-test-coverage-2026-07-25.md. Measurement first: `go test ./... -coverprofile` (what CI runs) instruments each package only for itself, so code exercised through another package's tests reads as uncovered — `service` reported 36.7% against a real 85%. All analysis here uses -coverpkg=./..., and both views now have Makefile targets. Features that had zero coverage at every layer: - user blocking (db + service + the /api/v1/blocks routes) - auth lockout persistence — the DB round-trip that survives a restart - plugin install/enable/disable/uninstall and the plugin KV namespace - event replay bounds (GetMaxEventSeq, PruneEventsOlderThan) - LiveKit participant_joined webhook (replayed-token guard), the room-service client, and proxyWebSocket/copyWS - ws_proxy.rs and livekit_proxy.rs — pure helpers extracted, matching the existing tofu.rs pattern, so cert-pin and header-injection checks are testable Gaps that were hidden rather than absent: - Server/admin reported 0.3% coverage with 307 tests passing. TestSpawnDetached_* re-execs the test binary; the child inherited GOCOVERDIR and the parent's stdout, clobbering the profile and printing "[no tests to run]". Now 71.4%, and CI's uploaded artifact is correct. - vitest.config.ts excluded 2.2k LOC unexplained, including two files that already had tests. Trimmed to three entries, each justified inline. - api.HandleLiveKitHealthForTest re-implemented the handler it claimed to expose, so eight call sites tested a copy. Added a hook to the real one. Two bugs found and pinned rather than silently patched: logctx.WithGroup nests req_id under the group, and drag-reorder.ts takes one listener ref per channel but releases one per sidebar, so the count never reaches zero. Coverage: client 92.93% -> 94.87% statements (3371 -> 3572 tests) even after un-excluding hidden files; Rust 47 -> 74 tests; Go zero-coverage functions ~70 -> 21, with plugin 61->77%, admin 67->86%, db 76->84%, service 85->91%. Verified: go vet, all four build-tag variants, go test -race, -tags deadlock, vitest --coverage, cargo test --lib, cargo clippy --all-targets, playwright. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AEETs3Vh6sAHHb1jMBL75g
221 lines
5.8 KiB
Go
221 lines
5.8 KiB
Go
package ws_test
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/livekit/protocol/livekit"
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"github.com/owncord/server/config"
|
|
"github.com/owncord/server/ws"
|
|
)
|
|
|
|
// LiveKitClient.ListParticipants, CountVideoTracks and HealthCheck had no
|
|
// coverage — CountVideoTracks in particular gates MaxVideo enforcement, so a
|
|
// miscount silently changes who is allowed to turn a camera on.
|
|
//
|
|
// The room service client speaks Twirp over HTTP, so these tests stand up an
|
|
// httptest server that replies with real protobuf-encoded responses.
|
|
|
|
// twirpServer returns an httptest server that answers every Twirp RPC with the
|
|
// supplied protobuf message, and a client pointed at it.
|
|
func twirpServer(t *testing.T, status int, reply proto.Message) *ws.LiveKitClient {
|
|
t.Helper()
|
|
|
|
var body []byte
|
|
if reply != nil {
|
|
var err error
|
|
body, err = proto.Marshal(reply)
|
|
if err != nil {
|
|
t.Fatalf("marshal reply: %v", err)
|
|
}
|
|
}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
if status != http.StatusOK {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
_, _ = w.Write([]byte(`{"code":"internal","msg":"boom"}`))
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/protobuf")
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write(body)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
client, err := ws.NewLiveKitClient(&config.VoiceConfig{
|
|
LiveKitAPIKey: "testkeytestkeytest",
|
|
LiveKitAPISecret: "testsecrettestsecrettestsecret",
|
|
LiveKitURL: "ws://" + srv.Listener.Addr().String(),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("NewLiveKitClient: %v", err)
|
|
}
|
|
return client
|
|
}
|
|
|
|
func TestLiveKitClient_ListParticipants_Empty(t *testing.T) {
|
|
client := twirpServer(t, http.StatusOK, &livekit.ListParticipantsResponse{})
|
|
|
|
got, err := client.ListParticipants(42)
|
|
if err != nil {
|
|
t.Fatalf("ListParticipants: %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Errorf("ListParticipants = %v, want empty", got)
|
|
}
|
|
}
|
|
|
|
func TestLiveKitClient_ListParticipants_ReturnsParticipants(t *testing.T) {
|
|
client := twirpServer(t, http.StatusOK, &livekit.ListParticipantsResponse{
|
|
Participants: []*livekit.ParticipantInfo{
|
|
{Identity: "user-1:tok"},
|
|
{Identity: "user-2:tok"},
|
|
},
|
|
})
|
|
|
|
got, err := client.ListParticipants(42)
|
|
if err != nil {
|
|
t.Fatalf("ListParticipants: %v", err)
|
|
}
|
|
if len(got) != 2 {
|
|
t.Fatalf("ListParticipants returned %d participants, want 2", len(got))
|
|
}
|
|
if got[0].Identity != "user-1:tok" {
|
|
t.Errorf("participant[0].Identity = %q, want %q", got[0].Identity, "user-1:tok")
|
|
}
|
|
}
|
|
|
|
func TestLiveKitClient_ListParticipants_ServerError(t *testing.T) {
|
|
client := twirpServer(t, http.StatusInternalServerError, nil)
|
|
|
|
if _, err := client.ListParticipants(42); err == nil {
|
|
t.Error("ListParticipants against a failing server returned nil error")
|
|
}
|
|
}
|
|
|
|
func TestLiveKitClient_CountVideoTracks(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
participants []*livekit.ParticipantInfo
|
|
want int
|
|
}{
|
|
{
|
|
name: "no participants",
|
|
want: 0,
|
|
},
|
|
{
|
|
name: "audio only",
|
|
participants: []*livekit.ParticipantInfo{
|
|
{Tracks: []*livekit.TrackInfo{{Type: livekit.TrackType_AUDIO}}},
|
|
},
|
|
want: 0,
|
|
},
|
|
{
|
|
name: "one video among audio",
|
|
participants: []*livekit.ParticipantInfo{
|
|
{Tracks: []*livekit.TrackInfo{
|
|
{Type: livekit.TrackType_AUDIO},
|
|
{Type: livekit.TrackType_VIDEO},
|
|
}},
|
|
},
|
|
want: 1,
|
|
},
|
|
{
|
|
name: "video counted across participants",
|
|
participants: []*livekit.ParticipantInfo{
|
|
{Tracks: []*livekit.TrackInfo{{Type: livekit.TrackType_VIDEO}}},
|
|
{Tracks: []*livekit.TrackInfo{
|
|
{Type: livekit.TrackType_VIDEO},
|
|
{Type: livekit.TrackType_VIDEO},
|
|
}},
|
|
{Tracks: []*livekit.TrackInfo{{Type: livekit.TrackType_AUDIO}}},
|
|
},
|
|
want: 3,
|
|
},
|
|
{
|
|
name: "participant with no tracks",
|
|
participants: []*livekit.ParticipantInfo{
|
|
{Identity: "user-1"},
|
|
{Tracks: []*livekit.TrackInfo{{Type: livekit.TrackType_VIDEO}}},
|
|
},
|
|
want: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
client := twirpServer(t, http.StatusOK, &livekit.ListParticipantsResponse{
|
|
Participants: tt.participants,
|
|
})
|
|
|
|
got, err := client.CountVideoTracks(7)
|
|
if err != nil {
|
|
t.Fatalf("CountVideoTracks: %v", err)
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("CountVideoTracks = %d, want %d", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLiveKitClient_CountVideoTracks_PropagatesError(t *testing.T) {
|
|
client := twirpServer(t, http.StatusInternalServerError, nil)
|
|
|
|
got, err := client.CountVideoTracks(7)
|
|
if err == nil {
|
|
t.Fatal("CountVideoTracks against a failing server returned nil error")
|
|
}
|
|
if got != 0 {
|
|
t.Errorf("count = %d on error, want 0", got)
|
|
}
|
|
}
|
|
|
|
func TestLiveKitClient_HealthCheck_Success(t *testing.T) {
|
|
client := twirpServer(t, http.StatusOK, &livekit.ListRoomsResponse{})
|
|
|
|
ok, err := client.HealthCheck(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("HealthCheck: %v", err)
|
|
}
|
|
if !ok {
|
|
t.Error("HealthCheck = false against a healthy server")
|
|
}
|
|
}
|
|
|
|
func TestLiveKitClient_HealthCheck_ServerError(t *testing.T) {
|
|
client := twirpServer(t, http.StatusInternalServerError, nil)
|
|
|
|
ok, err := client.HealthCheck(context.Background())
|
|
if err == nil {
|
|
t.Fatal("HealthCheck against a failing server returned nil error")
|
|
}
|
|
if ok {
|
|
t.Error("HealthCheck = true despite an error")
|
|
}
|
|
}
|
|
|
|
func TestLiveKitClient_HealthCheck_Unreachable(t *testing.T) {
|
|
client, err := ws.NewLiveKitClient(&config.VoiceConfig{
|
|
LiveKitAPIKey: "testkeytestkeytest",
|
|
LiveKitAPISecret: "testsecrettestsecrettestsecret",
|
|
LiveKitURL: "ws://127.0.0.1:1",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("NewLiveKitClient: %v", err)
|
|
}
|
|
|
|
ok, err := client.HealthCheck(context.Background())
|
|
if err == nil {
|
|
t.Fatal("HealthCheck against an unreachable server returned nil error")
|
|
}
|
|
if ok {
|
|
t.Error("HealthCheck = true against an unreachable server")
|
|
}
|
|
}
|