66 lines
3.2 KiB
TypeScript
66 lines
3.2 KiB
TypeScript
import { afterEach, beforeEach, expect, it, vi } from 'vitest';
|
|
import { newFixture, type Fixture } from '../helpers/fixture.js';
|
|
|
|
let fixture: Fixture;
|
|
beforeEach(async () => {
|
|
vi.resetModules();
|
|
fixture = await newFixture();
|
|
const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js');
|
|
await seedServerRegistry();
|
|
});
|
|
afterEach(async () => fixture.cleanup());
|
|
|
|
const payload = { event: 'round_change', server: 't5_zombie_theater_1', round: 17, players: 4 };
|
|
async function post(body: unknown, contentType = 'application/json') {
|
|
const { POST } = await import('../../src/routes/api/telemetry/+server.js');
|
|
return POST({ request: new Request('http://localhost/api/telemetry', {
|
|
method: 'POST', headers: { 'Content-Type': contentType }, body: JSON.stringify(body)
|
|
}) });
|
|
}
|
|
|
|
it('persists reports, broadcasts updates, and leaves RCON safety data untouched', async () => {
|
|
const { subscribe } = await import('../../src/lib/server/pipeline/bus.js');
|
|
const listener = vi.fn();
|
|
const unsubscribe = subscribe(listener);
|
|
expect((await post(payload)).status).toBe(200);
|
|
expect(listener).toHaveBeenCalledWith(expect.objectContaining({ type: 'server-telemetry' }));
|
|
unsubscribe();
|
|
// A new match can legitimately report a lower round; retries overwrite one row.
|
|
await post({ ...payload, round: 1 });
|
|
await post({ ...payload, round: 1 });
|
|
const { closeDb } = await import('../../src/lib/server/db/index.js');
|
|
closeDb();
|
|
const { listTelemetry } = await import('../../src/lib/server/fleet/telemetry.js');
|
|
expect(listTelemetry()).toEqual([expect.objectContaining({ round: 1, players: 4 })]);
|
|
const { getServer } = await import('../../src/lib/server/fleet/servers.js');
|
|
expect(getServer(payload.server)?.last_players).toBeNull();
|
|
const { GET } = await import('../../src/routes/api/events/servers/+server.js');
|
|
const response = await GET();
|
|
const reader = response.body!.getReader();
|
|
await reader.read(); // greeting
|
|
const snapshot = await reader.read();
|
|
expect(new TextDecoder().decode(snapshot.value)).toContain('"round":1');
|
|
await reader.cancel();
|
|
});
|
|
|
|
it.each([null, [], {}, { ...payload, event: 'other' }, { ...payload, round: -1 },
|
|
{ ...payload, round: 1.5 }, { ...payload, round: '17' }, { ...payload, players: -1 },
|
|
{ ...payload, players: null }])('rejects invalid telemetry: %j', async (body) => {
|
|
expect((await post(body)).status).toBe(400);
|
|
});
|
|
|
|
it('rejects unknown and destroyed servers and non-JSON requests', async () => {
|
|
expect((await post({ ...payload, server: 'unknown' })).status).toBe(404);
|
|
expect((await post(payload, 'text/plain')).status).toBe(415);
|
|
const { setServerField } = await import('../../src/lib/server/fleet/servers.js');
|
|
setServerField(payload.server, 'destroyed_at', new Date().toISOString());
|
|
expect((await post(payload)).status).toBe(404);
|
|
});
|
|
|
|
it('rejects malformed JSON', async () => {
|
|
const { POST } = await import('../../src/routes/api/telemetry/+server.js');
|
|
expect((await POST({ request: new Request('http://localhost/api/telemetry', {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{'
|
|
}) })).status).toBe(400);
|
|
});
|