118 lines
5.2 KiB
TypeScript
118 lines
5.2 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { newFixture, type Fixture } from '../helpers/fixture.js';
|
|
import { gameEvent } from '../helpers/telemetry.js';
|
|
|
|
let fixture: Fixture;
|
|
beforeEach(async () => {
|
|
vi.resetModules();
|
|
fixture = await newFixture([]);
|
|
});
|
|
afterEach(async () => {
|
|
await fixture.cleanup();
|
|
});
|
|
|
|
describe('host detail instances', () => {
|
|
it('returns only current instances belonging to the requested host and refreshes their health', async () => {
|
|
const { createHost } = await import('../../src/lib/server/hosts/index.js');
|
|
const host = createHost({ name: 'Selected host' });
|
|
const other = createHost({ name: 'Other host' });
|
|
const { db } = await import('../../src/lib/server/db/index.js');
|
|
const now = new Date().toISOString();
|
|
const add = (name: string, hostId: string, retired = false, destroyed = false) => {
|
|
db()
|
|
.prepare(
|
|
`INSERT INTO native_instances (id, server, host_id, generation, library_id, image, port, created_at, retired_at)
|
|
VALUES (?, ?, ?, 1, 'library', 'runtime:test', 28960, ?, ?)`
|
|
)
|
|
.run(name, name, hostId, now, retired ? now : null);
|
|
db()
|
|
.prepare(
|
|
`INSERT INTO servers (name,
|
|
container_state, container_checked_at, last_seen_at, last_players, destroyed_at)
|
|
VALUES (?, 'running', ?, ?, 2, ?)`
|
|
)
|
|
.run(name, now, now, destroyed ? now : null);
|
|
};
|
|
add('running', host.id);
|
|
add('unavailable', host.id);
|
|
add('other-host', other.id);
|
|
add('retired', host.id, true);
|
|
add('destroyed', host.id, false, true);
|
|
db()
|
|
.prepare(
|
|
`INSERT INTO native_instances (id, server, host_id, library_id, image, port, created_at, retired_at)
|
|
VALUES ('old-placement', 'other-host', ?, 'library', 'runtime:test', 28960, ?, ?)`
|
|
)
|
|
.run(host.id, now, now);
|
|
db().prepare("UPDATE servers SET container_state='exited' WHERE name='unavailable'").run();
|
|
|
|
const { hostOverview } = await import('../../src/lib/server/hosts/overview.js');
|
|
const overview = hostOverview();
|
|
expect(overview.find((row) => row.id === host.id)).toMatchObject({
|
|
serverCount: 2,
|
|
playerCount: 2,
|
|
unreportedInstances: 1
|
|
});
|
|
expect(overview.find((row) => row.id === other.id)).toMatchObject({
|
|
serverCount: 1,
|
|
playerCount: 2,
|
|
unreportedInstances: 0
|
|
});
|
|
const { GET: list } = await import('../../src/routes/api/hosts/+server.js');
|
|
const listed = await list({ request: new Request('https://ec.test/api/hosts') }).json();
|
|
expect(listed.serverNow).toEqual(expect.any(Number));
|
|
expect(listed.hosts.find((row: { id: string }) => row.id === host.id)).toMatchObject({
|
|
serverCount: 2,
|
|
playerCount: 2,
|
|
unreportedInstances: 1
|
|
});
|
|
const { GET } = await import('../../src/routes/api/hosts/[id]/+server.js');
|
|
const read = async (id: string) =>
|
|
await GET({
|
|
request: new Request(`https://ec.test/api/hosts/${id}`),
|
|
params: { id }
|
|
}).json();
|
|
const body = await read(host.id);
|
|
expect(body.instances.map((instance: { name: string }) => instance.name)).toEqual([
|
|
'running',
|
|
'unavailable'
|
|
]);
|
|
expect(body.instances[0]).toMatchObject({ health: 'online', last_players: 2 });
|
|
expect(body.instances[1]).toMatchObject({ health: 'offline', last_players: null });
|
|
expect(body.serverNow).toEqual(expect.any(Number));
|
|
|
|
db().prepare("UPDATE servers SET last_players=0 WHERE name='running'").run();
|
|
expect((await read(host.id)).instances[0].last_players).toBe(0);
|
|
expect(
|
|
(await read(other.id)).instances.map((instance: { name: string }) => instance.name)
|
|
).toEqual(['other-host']);
|
|
const empty = createHost({ name: 'Empty host' });
|
|
expect((await read(empty.id)).instances).toEqual([]);
|
|
expect(hostOverview().find((row) => row.id === empty.id)).toMatchObject({
|
|
serverCount: 0,
|
|
playerCount: 0,
|
|
unreportedInstances: 0
|
|
});
|
|
const report = { ...gameEvent('heartbeat', 15, 4, 'running'), receivedAt: now };
|
|
db()
|
|
.prepare(
|
|
'INSERT INTO server_telemetry (server, round, players, received_at, payload) VALUES (?, ?, ?, ?, ?)'
|
|
)
|
|
.run('running', 15, 4, now, JSON.stringify(report));
|
|
expect(hostOverview().find((row) => row.id === host.id)).toMatchObject({
|
|
playerCount: 4,
|
|
unreportedInstances: 1
|
|
});
|
|
db().prepare("DELETE FROM server_telemetry WHERE server='running'").run();
|
|
db()
|
|
.prepare(
|
|
"UPDATE servers SET last_seen_at='2000-01-01T00:00:00Z',last_players=99 WHERE name='running'"
|
|
)
|
|
.run();
|
|
expect(hostOverview().find((row) => row.id === host.id)).toMatchObject({
|
|
playerCount: 0,
|
|
unreportedInstances: 2
|
|
});
|
|
});
|
|
});
|