mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
Applied from a deadcode (RTA from mains, all build tags) sweep with
per-symbol adversarial verification:
Deleted (nothing but their own self-tests used them):
- admin.Handler (deprecated since Phase 6; production mounts NewHandler)
plus its two self-tests
- ws.Hub.broadcastVoiceStateUpdate + wrapper + two self-tests (pre-V2
leftover; the live voice_state path is the hub voice routines)
- ws.VoiceLeaveEvent + methods ('retained as scaffolding', never
constructed in production; MsgTypeVoiceLeaveBC stays — live via the
leave routine)
- ws.parseIdentity (production calls parseParticipantIdentity directly;
ParseIdentityForTest now exercises the real parser)
- telemetry.Float64 (String/Int64 are used; the float case is covered by
the otel-tagged internal test, re-addable when a caller appears)
Moved into export_test.go so they leave the production binary (all
callers are same-package tests): the eight ws test-client constructors
and voice/E2EE setters from ws/client.go, admin.SetBackupBaseDir
(new admin/export_test.go), api.SecurityHeaders (test-only wrapper;
production uses SecurityHeadersWithTLS — docs/api.md updated to the
real name). Client.getVoiceJoinToken/setVoiceChID inlined into their
existing ForTest wrappers; TestSetVoiceChID_* self-tests deleted.
Kept after verification: updater.SetBaseURL (11 cross-package test call
sites) and telemetry.resetAppMetricsForInit (live under -tags otel —
untagged deadcode false positive).
Full gate green: gofmt/vet, 4 build-tag variants, full suite, deadlock,
race.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
431 lines
12 KiB
Go
431 lines
12 KiB
Go
package ws_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/owncord/server/db"
|
|
"github.com/owncord/server/ws"
|
|
)
|
|
|
|
// ─── IsUserConnected ────────────────────────────────────────────────────────
|
|
|
|
func TestIsUserConnected_NotConnected(t *testing.T) {
|
|
hub, _ := newCoverageHub(t)
|
|
|
|
if hub.IsUserConnected(9999) {
|
|
t.Error("expected false for unregistered user")
|
|
}
|
|
}
|
|
|
|
func TestIsUserConnected_Connected(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "connected-user")
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
hub.Register(c)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
if !hub.IsUserConnected(user.ID) {
|
|
t.Error("expected true for registered user")
|
|
}
|
|
}
|
|
|
|
func TestIsUserConnected_AfterUnregister(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "unreg-user")
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
hub.Register(c)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
hub.Unregister(c)
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
if hub.IsUserConnected(user.ID) {
|
|
t.Error("expected false after unregister")
|
|
}
|
|
}
|
|
|
|
// ─── qualityBitrate ─────────────────────────────────────────────────────────
|
|
|
|
func TestQualityBitrate_KnownPresets(t *testing.T) {
|
|
tests := []struct {
|
|
quality string
|
|
want int
|
|
}{
|
|
{"low", 32000},
|
|
{"medium", 64000},
|
|
{"high", 128000},
|
|
}
|
|
for _, tc := range tests {
|
|
got := ws.QualityBitrateForTest(tc.quality)
|
|
if got != tc.want {
|
|
t.Errorf("qualityBitrate(%q) = %d, want %d", tc.quality, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestQualityBitrate_UnknownFallsBackToMedium(t *testing.T) {
|
|
got := ws.QualityBitrateForTest("ultra")
|
|
if got != 64000 {
|
|
t.Errorf("qualityBitrate('ultra') = %d, want 64000 (medium fallback)", got)
|
|
}
|
|
}
|
|
|
|
func TestQualityBitrate_EmptyFallsBackToMedium(t *testing.T) {
|
|
got := ws.QualityBitrateForTest("")
|
|
if got != 64000 {
|
|
t.Errorf("qualityBitrate('') = %d, want 64000 (medium fallback)", got)
|
|
}
|
|
}
|
|
|
|
// ─── buildDMChannelOpen ─────────────────────────────────────────────────────
|
|
|
|
func TestBuildDMChannelOpen_NilRecipient(t *testing.T) {
|
|
result := ws.BuildDMChannelOpenForTest(1, nil)
|
|
if result != nil {
|
|
t.Error("expected nil for nil recipient")
|
|
}
|
|
}
|
|
|
|
func TestBuildDMChannelOpen_ValidRecipient(t *testing.T) {
|
|
avatar := "avatar.png"
|
|
user := &db.User{
|
|
ID: 42,
|
|
Username: "testuser",
|
|
Avatar: &avatar,
|
|
Status: "online",
|
|
}
|
|
|
|
result := ws.BuildDMChannelOpenForTest(100, user)
|
|
if result == nil {
|
|
t.Fatal("expected non-nil result for valid recipient")
|
|
}
|
|
if !json.Valid(result) {
|
|
t.Fatalf("result is not valid JSON: %s", result)
|
|
}
|
|
|
|
var msg struct {
|
|
Type string `json:"type"`
|
|
Payload struct {
|
|
ChannelID int64 `json:"channel_id"`
|
|
Recipient struct {
|
|
ID int64 `json:"id"`
|
|
Username string `json:"username"`
|
|
Avatar string `json:"avatar"`
|
|
Status string `json:"status"`
|
|
} `json:"recipient"`
|
|
} `json:"payload"`
|
|
}
|
|
if err := json.Unmarshal(result, &msg); err != nil {
|
|
t.Fatalf("unmarshal: %v", err)
|
|
}
|
|
if msg.Payload.ChannelID != 100 {
|
|
t.Errorf("ChannelID = %d, want 100", msg.Payload.ChannelID)
|
|
}
|
|
if msg.Payload.Recipient.ID != 42 {
|
|
t.Errorf("Recipient.ID = %d, want 42", msg.Payload.Recipient.ID)
|
|
}
|
|
if msg.Payload.Recipient.Username != "testuser" {
|
|
t.Errorf("Username = %q, want 'testuser'", msg.Payload.Recipient.Username)
|
|
}
|
|
if msg.Payload.Recipient.Avatar != "avatar.png" {
|
|
t.Errorf("Avatar = %q, want 'avatar.png'", msg.Payload.Recipient.Avatar)
|
|
}
|
|
}
|
|
|
|
func TestBuildDMChannelOpen_NilAvatar(t *testing.T) {
|
|
user := &db.User{
|
|
ID: 43,
|
|
Username: "noavatar",
|
|
Avatar: nil,
|
|
Status: "offline",
|
|
}
|
|
|
|
result := ws.BuildDMChannelOpenForTest(200, user)
|
|
if result == nil {
|
|
t.Fatal("expected non-nil result")
|
|
}
|
|
|
|
var msg struct {
|
|
Payload struct {
|
|
Recipient struct {
|
|
Avatar string `json:"avatar"`
|
|
} `json:"recipient"`
|
|
} `json:"payload"`
|
|
}
|
|
_ = json.Unmarshal(result, &msg)
|
|
if msg.Payload.Recipient.Avatar != "" {
|
|
t.Errorf("Avatar = %q, want empty string for nil avatar", msg.Payload.Recipient.Avatar)
|
|
}
|
|
}
|
|
|
|
// ─── handleVoiceMute via HandleMessageForTest ───────────────────────────────
|
|
|
|
func TestHandleVoiceMute_NotInVoice2(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "mute-not-in-voice")
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
hub.RegisterNowForTest(c)
|
|
|
|
payload := `{"muted":true}`
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_mute", "payload": json.RawMessage(payload)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
// Should receive an error about not being in a voice channel.
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
Payload struct {
|
|
Message string `json:"message"`
|
|
} `json:"payload"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error message when not in voice channel")
|
|
}
|
|
}
|
|
|
|
// ─── handleVoiceDeafen not in voice ─────────────────────────────────────────
|
|
|
|
func TestHandleVoiceDeafen_NotInVoice2(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "deafen-not-voice")
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
hub.RegisterNowForTest(c)
|
|
|
|
payload := `{"deafened":true}`
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_deafen", "payload": json.RawMessage(payload)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error message when not in voice channel")
|
|
}
|
|
}
|
|
|
|
// ─── handleVoiceCamera not in voice ─────────────────────────────────────────
|
|
|
|
func TestHandleVoiceCamera_NotInVoice2(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "cam-not-voice")
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
hub.RegisterNowForTest(c)
|
|
|
|
payload := `{"enabled":true}`
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_camera", "payload": json.RawMessage(payload)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error message when not in voice channel")
|
|
}
|
|
}
|
|
|
|
// ─── handleVoiceScreenshare not in voice ────────────────────────────────────
|
|
|
|
func TestHandleVoiceScreenshare_NotInVoice2(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "share-not-voice")
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
hub.RegisterNowForTest(c)
|
|
|
|
payload := `{"enabled":true}`
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_screenshare", "payload": json.RawMessage(payload)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error message when not in voice channel")
|
|
}
|
|
}
|
|
|
|
// ─── handleVoiceMute/Deafen bad payload ─────────────────────────────────────
|
|
|
|
func TestHandleVoiceMute_BadPayload(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "mute-bad-payload")
|
|
chanID, _ := database.CreateChannel("mute-bp-ch", "voice", "", "", 0)
|
|
_ = database.JoinVoiceChannel(user.ID, chanID)
|
|
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
ws.SetClientVoiceChID(c, chanID)
|
|
hub.RegisterNowForTest(c)
|
|
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_mute", "payload": json.RawMessage(`{invalid json`)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error for bad payload")
|
|
}
|
|
}
|
|
|
|
func TestHandleVoiceDeafen_BadPayload(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "deafen-bad-payload")
|
|
chanID, _ := database.CreateChannel("deafen-bp-ch", "voice", "", "", 0)
|
|
_ = database.JoinVoiceChannel(user.ID, chanID)
|
|
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
ws.SetClientVoiceChID(c, chanID)
|
|
hub.RegisterNowForTest(c)
|
|
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_deafen", "payload": json.RawMessage(`not json`)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error for bad payload")
|
|
}
|
|
}
|
|
|
|
// ─── handleVoiceCamera bad payload ──────────────────────────────────────────
|
|
|
|
func TestHandleVoiceCamera_BadPayload(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "cam-bad-payload")
|
|
chanID, _ := database.CreateChannel("cam-bp-ch", "voice", "", "", 0)
|
|
_ = database.JoinVoiceChannel(user.ID, chanID)
|
|
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
ws.SetClientVoiceChID(c, chanID)
|
|
ws.SetClientVoiceStateForTest(c, chanID, "join-token-fake")
|
|
hub.RegisterNowForTest(c)
|
|
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_camera", "payload": json.RawMessage(`{bad`)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error for bad payload")
|
|
}
|
|
}
|
|
|
|
// ─── handleVoiceScreenshare bad payload ─────────────────────────────────────
|
|
|
|
func TestHandleVoiceScreenshare_BadPayload(t *testing.T) {
|
|
hub, database := newCoverageHub(t)
|
|
user := seedCoverageOwner(t, database, "share-bad-payload")
|
|
chanID, _ := database.CreateChannel("share-bp-ch", "voice", "", "", 0)
|
|
_ = database.JoinVoiceChannel(user.ID, chanID)
|
|
|
|
send := make(chan []byte, 16)
|
|
c := ws.NewTestClientWithUser(hub, user, 0, send)
|
|
ws.SetClientVoiceChID(c, chanID)
|
|
ws.SetClientVoiceStateForTest(c, chanID, "join-token-fake")
|
|
hub.RegisterNowForTest(c)
|
|
|
|
raw, _ := json.Marshal(map[string]any{"type": "voice_screenshare", "payload": json.RawMessage(`{bad`)})
|
|
hub.HandleMessageForTest(c, raw)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
found := false
|
|
for len(send) > 0 {
|
|
msg := <-send
|
|
var m struct {
|
|
Type string `json:"type"`
|
|
}
|
|
_ = json.Unmarshal(msg, &m)
|
|
if m.Type == "error" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected error for bad payload")
|
|
}
|
|
}
|
|
|
|
// ─── leaveVoiceChannelWithRetry empty token ─────────────────────────────────
|
|
|
|
func TestLeaveVoiceChannelWithRetry_EmptyToken(t *testing.T) {
|
|
hub, _ := newCoverageHub(t)
|
|
|
|
err := ws.LeaveVoiceChannelWithRetryForTest(hub, 1, 1, "")
|
|
if err != nil {
|
|
t.Errorf("expected nil error for empty token, got %v", err)
|
|
}
|
|
}
|