Files

432 lines
13 KiB
Go
Raw Permalink Normal View History

package ws_test
import (
"context"
"encoding/json"
"testing"
"github.com/J3vb/OwnCord/Server/db"
"github.com/J3vb/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)
waitRegistered(t, hub, c)
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)
waitRegistered(t, hub, c)
hub.Unregister(c)
waitFor(t, waitTimeout, func() bool { return !hub.IsUserConnected(user.ID) },
"client to be unregistered")
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.
// Error replies are sent synchronously by handleMessage — already buffered.
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)
// Error replies are sent synchronously by handleMessage — already buffered.
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)
// Error replies are sent synchronously by handleMessage — already buffered.
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)
// Error replies are sent synchronously by handleMessage — already buffered.
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(context.Background(), "mute-bp-ch", "voice", "", "", 0)
_ = database.JoinVoiceChannel(context.Background(), 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)
// Error replies are sent synchronously by handleMessage — already buffered.
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(context.Background(), "deafen-bp-ch", "voice", "", "", 0)
_ = database.JoinVoiceChannel(context.Background(), 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)
// Error replies are sent synchronously by handleMessage — already buffered.
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(context.Background(), "cam-bp-ch", "voice", "", "", 0)
_ = database.JoinVoiceChannel(context.Background(), 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)
// Error replies are sent synchronously by handleMessage — already buffered.
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(context.Background(), "share-bp-ch", "voice", "", "", 0)
_ = database.JoinVoiceChannel(context.Background(), 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)
// Error replies are sent synchronously by handleMessage — already buffered.
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)
}
}