mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
182 lines
5.9 KiB
TypeScript
182 lines
5.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
ManagedVoiceClientRegistry,
|
|
normalizeManagedVoiceClientScope,
|
|
normalizeManagedVoiceHost,
|
|
} from "./managed-voice-clients.js";
|
|
|
|
describe("managed voice client scope normalization", () => {
|
|
it("normalizes DNS host casing, whitespace, and trailing root dots", () => {
|
|
expect(normalizeManagedVoiceHost(" Voice.Example.COM... ")).toBe(
|
|
"voice.example.com",
|
|
);
|
|
expect(
|
|
normalizeManagedVoiceClientScope({
|
|
host: "VOICE.EXAMPLE.COM.",
|
|
voicePort: 9987,
|
|
}),
|
|
).toEqual({ host: "voice.example.com", voicePort: 9987 });
|
|
});
|
|
|
|
it("treats bracketed and equivalent expanded IPv6 literals as one host", () => {
|
|
expect(normalizeManagedVoiceHost("[2001:0DB8:0:0:0:0:0:1]")).toBe(
|
|
"2001:db8::1",
|
|
);
|
|
expect(normalizeManagedVoiceHost("2001:db8::1")).toBe("2001:db8::1");
|
|
});
|
|
|
|
it("rejects empty hosts and invalid voice ports", () => {
|
|
expect(
|
|
normalizeManagedVoiceClientScope({ host: " . ", voicePort: 9987 }),
|
|
).toBeNull();
|
|
expect(
|
|
normalizeManagedVoiceClientScope({ host: "example.com", voicePort: 0 }),
|
|
).toBeNull();
|
|
expect(
|
|
normalizeManagedVoiceClientScope({
|
|
host: "example.com",
|
|
voicePort: 65_536,
|
|
}),
|
|
).toBeNull();
|
|
});
|
|
|
|
});
|
|
|
|
describe("ManagedVoiceClientRegistry", () => {
|
|
it("finds clients through normalized forms of the same scope", () => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
const owner = Symbol("connection");
|
|
|
|
expect(
|
|
registry.register(
|
|
{ host: " Voice.Example.COM. ", voicePort: 9987 },
|
|
42,
|
|
owner,
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
registry.has({ host: "voice.example.com", voicePort: 9987 }, 42),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("keeps different voice ports and hosts in separate scopes", () => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
registry.register(
|
|
{ host: "voice.example.com", voicePort: 9987 },
|
|
7,
|
|
Symbol("connection"),
|
|
);
|
|
|
|
expect(
|
|
registry.has({ host: "voice.example.com", voicePort: 9988 }, 7),
|
|
).toBe(false);
|
|
expect(
|
|
registry.has({ host: "other.example.com", voicePort: 9987 }, 7),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("finds a managed bot by stable client UID across network endpoints", () => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
const owner = Symbol("connection");
|
|
|
|
registry.register(
|
|
{ host: "127.0.0.1", voicePort: 9987 },
|
|
17,
|
|
owner,
|
|
" managed-client-uid= ",
|
|
);
|
|
|
|
expect(registry.hasClientUid("managed-client-uid=")).toBe(true);
|
|
expect(
|
|
registry.has({ host: "192.168.1.10", voicePort: 20_000 }, 17),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("keeps a shared managed UID until its last owner unregisters", () => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
const scope = { host: "203.0.113.4", voicePort: 9987 };
|
|
const first = Symbol("first connection");
|
|
const second = Symbol("second connection");
|
|
registry.register(scope, 18, first, "shared-client-uid=");
|
|
registry.register(scope, 19, second, "shared-client-uid=");
|
|
|
|
expect(registry.unregister(scope, 18, first, "shared-client-uid=")).toBe(true);
|
|
expect(registry.hasClientUid("shared-client-uid=")).toBe(true);
|
|
expect(registry.unregister(scope, 19, second, "shared-client-uid=")).toBe(true);
|
|
expect(registry.hasClientUid("shared-client-uid=")).toBe(false);
|
|
});
|
|
|
|
it("ignores missing or empty client UIDs", () => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
registry.register(
|
|
{ host: "203.0.113.4", voicePort: 9987 },
|
|
19,
|
|
Symbol("connection"),
|
|
" ",
|
|
);
|
|
|
|
expect(registry.hasClientUid(undefined)).toBe(false);
|
|
expect(registry.hasClientUid(" ")).toBe(false);
|
|
});
|
|
|
|
it("uses an IPv6-safe scope key", () => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
registry.register(
|
|
{ host: "[2001:0db8:0:0:0:0:0:1]", voicePort: 9987 },
|
|
9,
|
|
Symbol("connection"),
|
|
);
|
|
|
|
expect(
|
|
registry.has({ host: "2001:db8::1", voicePort: 9987 }, 9),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("does not let a delayed old disconnect remove a replacement", () => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
const scope = { host: "voice.example.com", voicePort: 9987 };
|
|
const oldConnection = Symbol("old connection");
|
|
const newConnection = Symbol("new connection");
|
|
|
|
registry.register(scope, 12, oldConnection, "managed-client-uid=");
|
|
registry.register(scope, 12, newConnection, "managed-client-uid=");
|
|
|
|
// The old UID owner is removed, but the replacement still owns both the
|
|
// scoped id and the shared stable UID.
|
|
expect(
|
|
registry.unregister(scope, 12, oldConnection, "managed-client-uid="),
|
|
).toBe(true);
|
|
expect(registry.has(scope, 12)).toBe(true);
|
|
expect(registry.hasClientUid("managed-client-uid=")).toBe(true);
|
|
expect(
|
|
registry.unregister(scope, 12, newConnection, "managed-client-uid="),
|
|
).toBe(true);
|
|
expect(registry.has(scope, 12)).toBe(false);
|
|
expect(registry.hasClientUid("managed-client-uid=")).toBe(false);
|
|
});
|
|
|
|
it.each([0, -1, 1.5, Number.NaN, Number.POSITIVE_INFINITY])(
|
|
"ignores invalid client id %s",
|
|
(clientId) => {
|
|
const registry = new ManagedVoiceClientRegistry();
|
|
const scope = { host: "voice.example.com", voicePort: 9987 };
|
|
const owner = Symbol("connection");
|
|
|
|
expect(registry.register(scope, clientId, owner)).toBe(false);
|
|
expect(registry.has(scope, clientId)).toBe(false);
|
|
expect(registry.unregister(scope, clientId, owner)).toBe(false);
|
|
},
|
|
);
|
|
|
|
it("has no shared module-level state between registry instances", () => {
|
|
const first = new ManagedVoiceClientRegistry();
|
|
const second = new ManagedVoiceClientRegistry();
|
|
const scope = { host: "voice.example.com", voicePort: 9987 };
|
|
|
|
first.register(scope, 3, Symbol("connection"));
|
|
|
|
expect(first.has(scope, 3)).toBe(true);
|
|
expect(second.has(scope, 3)).toBe(false);
|
|
});
|
|
});
|