Files
J3vbandClaude Fable 5 f2966c2527 chore(server): delete production-dead code; move test helpers to export_test
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>
2026-07-23 15:28:41 +02:00

269 lines
9.0 KiB
Go

package ws
import (
"bytes"
"testing"
)
func TestClientErrorFormat(t *testing.T) {
err := ClientError{Code: "BAD_REQUEST", Message: "field missing"}
want := "BAD_REQUEST: field missing"
if got := err.Error(); got != want {
t.Errorf("Error() = %q, want %q", got, want)
}
}
func TestClientErrorImplementsError(t *testing.T) {
var _ error = ClientError{}
}
func TestResultEmpty(t *testing.T) {
r := Result{}
if r.Events != nil {
t.Error("expected nil Events")
}
if r.Error != nil {
t.Error("expected nil Error")
}
if r.Reply != nil {
t.Error("expected nil Reply")
}
}
func TestResultWithError(t *testing.T) {
r := Result{Error: ClientError{Code: "RATE_LIMITED", Message: "slow down"}}
if r.Error == nil {
t.Fatal("expected non-nil Error")
}
ce, ok := r.Error.(ClientError)
if !ok {
t.Fatal("expected ClientError type")
}
if ce.Code != "RATE_LIMITED" {
t.Errorf("Code = %q, want %q", ce.Code, "RATE_LIMITED")
}
}
func TestResultWithReply(t *testing.T) {
reply := []byte(`{"type":"chat_send_ok","id":"req-1"}`)
r := Result{Reply: reply}
if !bytes.Equal(r.Reply, reply) {
t.Errorf("Reply = %q, want %q", r.Reply, reply)
}
}
func TestResultWithEvents(t *testing.T) {
evt := PresenceEvent{payload: []byte(`{"type":"presence"}`)}
r := Result{Events: []Event{evt}}
if len(r.Events) != 1 {
t.Fatalf("len(Events) = %d, want 1", len(r.Events))
}
if r.Events[0].EventType() != MsgTypePresence {
t.Errorf("EventType() = %q, want %q", r.Events[0].EventType(), MsgTypePresence)
}
}
// ── EventType tests ─────────────────────────────────────────────────────────
func TestEventTypes(t *testing.T) {
tests := []struct {
name string
event Event
wantType string
}{
{"MessageSentChannelEvent", MessageSentChannelEvent{}, MsgTypeChatMessage},
{"MessageSentDMEvent", MessageSentDMEvent{}, MsgTypeChatMessage},
{"MessageEditedChannelEvent", MessageEditedChannelEvent{}, MsgTypeChatEdited},
{"MessageEditedDMEvent", MessageEditedDMEvent{}, MsgTypeChatEdited},
{"MessageDeletedChannelEvent", MessageDeletedChannelEvent{}, MsgTypeChatDeleted},
{"MessageDeletedDMEvent", MessageDeletedDMEvent{}, MsgTypeChatDeleted},
{"TypingChannelEvent", TypingChannelEvent{}, MsgTypeTyping},
{"TypingDMEvent", TypingDMEvent{}, MsgTypeTyping},
{"PresenceEvent", PresenceEvent{}, MsgTypePresence},
{"ReactionChannelEvent", ReactionChannelEvent{}, MsgTypeReactionUpdate},
{"ReactionDMEvent", ReactionDMEvent{}, MsgTypeReactionUpdate},
{"VoiceStateEvent", VoiceStateEvent{}, MsgTypeVoiceState},
{"VoiceE2EEAnnounceEvent", VoiceE2EEAnnounceEvent{}, MsgTypeVoiceE2EEAnnounceBC},
{"VoiceE2EEOfferGuardedEvent", VoiceE2EEOfferGuardedEvent{}, MsgTypeVoiceE2EEOfferRelay},
{"DMChannelOpenEvent", DMChannelOpenEvent{}, MsgTypeDMChannelOpen},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.event.EventType(); got != tt.wantType {
t.Errorf("EventType() = %q, want %q", got, tt.wantType)
}
})
}
}
// ── Routing interface tests ─────────────────────────────────────────────────
func TestChannelEventInterface(t *testing.T) {
events := []struct {
name string
event ChannelEvent
chID int64
}{
{"MessageSentChannelEvent", MessageSentChannelEvent{channelID: 10, payload: []byte("p")}, 10},
{"MessageEditedChannelEvent", MessageEditedChannelEvent{channelID: 20, payload: []byte("q")}, 20},
{"MessageDeletedChannelEvent", MessageDeletedChannelEvent{channelID: 30, payload: []byte("r")}, 30},
{"ReactionChannelEvent", ReactionChannelEvent{channelID: 40, payload: []byte("s")}, 40},
}
for _, tt := range events {
t.Run(tt.name, func(t *testing.T) {
if tt.event.ChannelID() != tt.chID {
t.Errorf("ChannelID() = %d, want %d", tt.event.ChannelID(), tt.chID)
}
if tt.event.Payload() == nil {
t.Error("Payload() should not be nil")
}
})
}
}
func TestExcludeSenderEventInterface(t *testing.T) {
evt := TypingChannelEvent{channelID: 5, excludeUserID: 42, payload: []byte("typing")}
var iface ExcludeSenderEvent = evt
if iface.ChannelID() != 5 {
t.Errorf("ChannelID() = %d, want 5", iface.ChannelID())
}
if iface.ExcludeUserID() != 42 {
t.Errorf("ExcludeUserID() = %d, want 42", iface.ExcludeUserID())
}
if string(iface.Payload()) != "typing" {
t.Errorf("Payload() = %q, want %q", iface.Payload(), "typing")
}
}
func TestSequencedDMEventInterface(t *testing.T) {
events := []struct {
name string
event SequencedDMEvent
chID int64
pIDs []int64
}{
{"MessageSentDMEvent", MessageSentDMEvent{channelID: 100, participantIDs: []int64{1, 2}, payload: []byte("m")}, 100, []int64{1, 2}},
{"MessageEditedDMEvent", MessageEditedDMEvent{channelID: 101, participantIDs: []int64{3, 4}, payload: []byte("e")}, 101, []int64{3, 4}},
{"MessageDeletedDMEvent", MessageDeletedDMEvent{channelID: 102, participantIDs: []int64{5, 6}, payload: []byte("d")}, 102, []int64{5, 6}},
{"ReactionDMEvent", ReactionDMEvent{channelID: 103, participantIDs: []int64{7, 8}, payload: []byte("r")}, 103, []int64{7, 8}},
}
for _, tt := range events {
t.Run(tt.name, func(t *testing.T) {
if tt.event.ChannelID() != tt.chID {
t.Errorf("ChannelID() = %d, want %d", tt.event.ChannelID(), tt.chID)
}
got := tt.event.ParticipantIDs()
if len(got) != len(tt.pIDs) {
t.Fatalf("ParticipantIDs() len = %d, want %d", len(got), len(tt.pIDs))
}
for i, id := range tt.pIDs {
if got[i] != id {
t.Errorf("ParticipantIDs()[%d] = %d, want %d", i, got[i], id)
}
}
if tt.event.Payload() == nil {
t.Error("Payload() should not be nil")
}
})
}
}
func TestSequencedDMEventDefensiveCopy(t *testing.T) {
orig := []int64{1, 2, 3}
evt := MessageSentDMEvent{participantIDs: orig}
got := evt.ParticipantIDs()
got[0] = 999
if evt.participantIDs[0] == 999 {
t.Error("ParticipantIDs() did not return a defensive copy")
}
}
func TestUserTargetedEventInterface(t *testing.T) {
events := []struct {
name string
event UserTargetedEvent
target int64
}{
{"TypingDMEvent", TypingDMEvent{targetUserID: 50, payload: []byte("t")}, 50},
{"DMChannelOpenEvent", DMChannelOpenEvent{targetUserID: 70, payload: []byte("d")}, 70},
}
for _, tt := range events {
t.Run(tt.name, func(t *testing.T) {
if tt.event.TargetUserID() != tt.target {
t.Errorf("TargetUserID() = %d, want %d", tt.event.TargetUserID(), tt.target)
}
if tt.event.Payload() == nil {
t.Error("Payload() should not be nil")
}
})
}
}
func TestBroadcastAllEventInterface(t *testing.T) {
events := []struct {
name string
event BroadcastAllEvent
}{
{"PresenceEvent", PresenceEvent{payload: []byte("p")}},
{"VoiceStateEvent", VoiceStateEvent{payload: []byte("vs")}},
}
for _, tt := range events {
t.Run(tt.name, func(t *testing.T) {
if tt.event.Payload() == nil {
t.Error("Payload() should not be nil")
}
})
}
}
func TestVoiceChannelEventInterface(t *testing.T) {
evt := VoiceE2EEAnnounceEvent{voiceChannelID: 15, excludeUserID: 7, payload: []byte("ann")}
var iface VoiceChannelEvent = evt
if iface.VoiceChannelID() != 15 {
t.Errorf("VoiceChannelID() = %d, want 15", iface.VoiceChannelID())
}
if iface.ExcludeUserID() != 7 {
t.Errorf("ExcludeUserID() = %d, want 7", iface.ExcludeUserID())
}
if string(iface.Payload()) != "ann" {
t.Errorf("Payload() = %q, want %q", iface.Payload(), "ann")
}
}
func TestVoiceChannelGuardedEventInterface(t *testing.T) {
evt := VoiceE2EEOfferGuardedEvent{voiceChannelID: 20, targetUserID: 5, payload: []byte("offer")}
var iface VoiceChannelGuardedEvent = evt
if iface.VoiceChannelID() != 20 {
t.Errorf("VoiceChannelID() = %d, want 20", iface.VoiceChannelID())
}
if iface.TargetUserID() != 5 {
t.Errorf("TargetUserID() = %d, want 5", iface.TargetUserID())
}
if string(iface.Payload()) != "offer" {
t.Errorf("Payload() = %q, want %q", iface.Payload(), "offer")
}
}
// ── SequencedDMEvent checked before ChannelEvent ────────────────────────────
func TestDMEventsImplementBothInterfaces(t *testing.T) {
// SequencedDMEvent types also satisfy ChannelEvent (they have ChannelID + Payload).
// This test documents that EmitEvents must check SequencedDMEvent first.
dmEvents := []Event{
MessageSentDMEvent{channelID: 1, participantIDs: []int64{1, 2}, payload: []byte("x")},
MessageEditedDMEvent{channelID: 2, participantIDs: []int64{3, 4}, payload: []byte("y")},
MessageDeletedDMEvent{channelID: 3, participantIDs: []int64{5, 6}, payload: []byte("z")},
ReactionDMEvent{channelID: 4, participantIDs: []int64{7, 8}, payload: []byte("w")},
}
for _, evt := range dmEvents {
// Must satisfy SequencedDMEvent.
if _, ok := evt.(SequencedDMEvent); !ok {
t.Errorf("%T does not implement SequencedDMEvent", evt)
}
// Must also satisfy ChannelEvent (since they have ChannelID + Payload).
if _, ok := evt.(ChannelEvent); !ok {
t.Errorf("%T does not implement ChannelEvent", evt)
}
}
}