Initial commit — SvelteKit fleet manager for T5 Plutonium servers
Ports push_scripts.sh (1497 lines of bash) to a SvelteKit + SQLite web app that manages a fleet of T5 Plutonium servers running on Komodo. Same push and beta workflow as the shell script, with a live SSE pipeline view, a !rt-token-gated auth modal that hard-pauses deployments on stale tokens, per-file audit diffs, and a Komodo-container deployment target. - Push/beta engines port the exact filter, held-by-beta, conflict, and stale-backup rules from the shell script - SQLite (better-sqlite3) replaces script_metadata.json; a one-shot importer moves legacy state over on first boot - 16 vitest tests cover push add/update/skip, beta open→rollback, open→promote, conflict guards, sweep frozen/manual branches, and IW4M login/status parsing - docker/ + komodo/stack.toml deploy as a managed container on the same host as the game servers, /root/zombies bind-mounted at the same path the shell script used
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { newFixture, type Fixture } from '../helpers/fixture.js';
|
||||
|
||||
let fixture: Fixture;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
fixture = await newFixture();
|
||||
process.env.IW4M_ADDRESS = 'http://iw4m.test';
|
||||
process.env.IW4M_CLIENT_ID = '1';
|
||||
vi.stubGlobal('fetch', vi.fn());
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fixture.cleanup();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe('loginWithToken', () => {
|
||||
it('returns cookie + expiry on 2xx', async () => {
|
||||
(globalThis.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
new Response('', {
|
||||
status: 200,
|
||||
headers: { 'Set-Cookie': '.AspNetCore.Cookies=abc; path=/; httponly' }
|
||||
})
|
||||
);
|
||||
const { loginWithToken } = await import('../../src/lib/server/integrations/iw4m.js');
|
||||
const res = await loginWithToken('abcd');
|
||||
expect(res.ok).toBe(true);
|
||||
if (res.ok) {
|
||||
expect(res.cookie).toContain('.AspNetCore.Cookies=abc');
|
||||
expect(res.expiresAt).toBeGreaterThan(Date.now());
|
||||
}
|
||||
});
|
||||
|
||||
it('returns rejected on 401', async () => {
|
||||
(globalThis.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(new Response('', { status: 401 }));
|
||||
const { loginWithToken } = await import('../../src/lib/server/integrations/iw4m.js');
|
||||
const res = await loginWithToken('abcd');
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) expect(res.reason).toBe('rejected');
|
||||
});
|
||||
|
||||
it('returns unreachable on network error', async () => {
|
||||
(globalThis.fetch as ReturnType<typeof vi.fn>).mockRejectedValueOnce(new Error('ECONNREFUSED'));
|
||||
const { loginWithToken } = await import('../../src/lib/server/integrations/iw4m.js');
|
||||
const res = await loginWithToken('abcd');
|
||||
expect(res.ok).toBe(false);
|
||||
if (!res.ok) expect(res.reason).toBe('unreachable');
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchStatus', () => {
|
||||
it('normalizes camelCase / PascalCase entries', async () => {
|
||||
(globalThis.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
new Response(
|
||||
JSON.stringify([
|
||||
{ id: 1, port: 3072, name: 'kino der toten', currentPlayers: 3 },
|
||||
{ Id: 2, Port: 3073, Name: 'ascension', CurrentPlayers: 0 }
|
||||
]),
|
||||
{ status: 200, headers: { 'Content-Type': 'application/json' } }
|
||||
)
|
||||
);
|
||||
const { fetchStatus } = await import('../../src/lib/server/integrations/iw4m.js');
|
||||
const res = await fetchStatus();
|
||||
expect(res.ok).toBe(true);
|
||||
if (res.ok) {
|
||||
expect(res.entries[0].currentPlayers).toBe(3);
|
||||
expect(res.entries[1].name).toBe('ascension');
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user