Add Prettier and ESLint tooling (Refs #77)
This commit is contained in:
@@ -3,14 +3,21 @@ import { newFixture, type Fixture } from '../helpers/fixture.js';
|
||||
import { prepareNativeHost } from '../helpers/native-host.js';
|
||||
|
||||
let fixture: Fixture;
|
||||
beforeEach(async () => { vi.resetModules(); fixture = await newFixture([]); });
|
||||
afterEach(async () => { await fixture.cleanup(); });
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
fixture = await newFixture([]);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await fixture.cleanup();
|
||||
});
|
||||
const settings = { game: 't6', mapSlug: 'town', maximum: 1, mode: 'create-destroy' };
|
||||
async function setup(mode = 'create-destroy') {
|
||||
if (mode.startsWith('create')) await prepareNativeHost();
|
||||
const { db } = await import('../../src/lib/server/db/index.js');
|
||||
const scaling = await import('../../src/lib/server/autoscaling/index.js');
|
||||
db().prepare("INSERT INTO server_keys(id,game,pluto_key) VALUES('key-1','t6','test-key')").run();
|
||||
db()
|
||||
.prepare("INSERT INTO server_keys(id,game,pluto_key) VALUES('key-1','t6','test-key')")
|
||||
.run();
|
||||
const input = { ...settings, mode };
|
||||
const saved = scaling.saveScaling(input);
|
||||
return { db, scaling, saved, input };
|
||||
@@ -18,31 +25,53 @@ async function setup(mode = 'create-destroy') {
|
||||
|
||||
it('deletes policy evidence atomically while preserving lobbies, keys, and unrelated policies', async () => {
|
||||
const { db, scaling, saved } = await setup();
|
||||
db().prepare("INSERT INTO servers(name,game,map_slug,map) VALUES('t6_zombie_town_1','t6','town','zm_transit')").run();
|
||||
db()
|
||||
.prepare(
|
||||
"INSERT INTO servers(name,game,map_slug,map) VALUES('t6_zombie_town_1','t6','town','zm_transit')"
|
||||
)
|
||||
.run();
|
||||
await scaling.runAutoscaling();
|
||||
db().prepare("INSERT INTO server_keys(id,game,pluto_key) VALUES('other-key','t5','other-key')").run();
|
||||
db()
|
||||
.prepare("INSERT INTO server_keys(id,game,pluto_key) VALUES('other-key','t5','other-key')")
|
||||
.run();
|
||||
const otherSettings = { ...settings, game: 't5', mapSlug: 'theater', mode: 'off' };
|
||||
const other = scaling.saveScaling(otherSettings);
|
||||
for (const table of ['autoscaling_decisions', 'autoscaling_members', 'autoscaling_samples']) expect(db().prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE policy_id=?`).get(saved.id)).toEqual({ n: 1 });
|
||||
for (const table of ['autoscaling_decisions', 'autoscaling_members', 'autoscaling_samples'])
|
||||
expect(
|
||||
db().prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE policy_id=?`).get(saved.id)
|
||||
).toEqual({ n: 1 });
|
||||
scaling.deleteScaling(saved.id, saved.revision);
|
||||
expect(scaling.getScalingPolicy(saved.id)).toBeUndefined();
|
||||
expect(scaling.listScalingPolicies().map(p => p.id)).toEqual([other.id]);
|
||||
for (const table of ['autoscaling_decisions', 'autoscaling_members', 'autoscaling_samples', 'autoscaling_authorizations']) expect(db().prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE policy_id=?`).get(saved.id)).toEqual({ n: 0 });
|
||||
expect(scaling.listScalingPolicies().map((p) => p.id)).toEqual([other.id]);
|
||||
for (const table of [
|
||||
'autoscaling_decisions',
|
||||
'autoscaling_members',
|
||||
'autoscaling_samples',
|
||||
'autoscaling_authorizations'
|
||||
])
|
||||
expect(
|
||||
db().prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE policy_id=?`).get(saved.id)
|
||||
).toEqual({ n: 0 });
|
||||
expect(db().prepare('SELECT name FROM servers').all()).toEqual([{ name: 't6_zombie_town_1' }]);
|
||||
expect(db().prepare('SELECT COUNT(*) AS n FROM server_keys').get()).toEqual({ n: 2 });
|
||||
expect(db().prepare('PRAGMA foreign_key_check').all()).toEqual([]);
|
||||
expect(scaling.saveScaling({ ...settings, mode: 'off' }).id).not.toBe(saved.id);
|
||||
});
|
||||
|
||||
it.each(['off', 'create-destroy'])('deletes a settled %s policy even after key loss and releases ownership', async mode => {
|
||||
const { db, scaling, saved } = await setup(mode);
|
||||
db().prepare('DELETE FROM server_keys').run();
|
||||
scaling.deleteScaling(saved.id, saved.revision);
|
||||
const { scalingOwner } = await import('../../src/lib/server/autoscaling/ownership.js');
|
||||
expect(scalingOwner('t6', 'town')).toBeNull();
|
||||
expect(await scaling.runAutoscaling()).toBe(false);
|
||||
expect(db().prepare('SELECT COUNT(*) AS n FROM server_deployments').get()).toEqual({ n: 0 });
|
||||
});
|
||||
it.each(['off', 'create-destroy'])(
|
||||
'deletes a settled %s policy even after key loss and releases ownership',
|
||||
async (mode) => {
|
||||
const { db, scaling, saved } = await setup(mode);
|
||||
db().prepare('DELETE FROM server_keys').run();
|
||||
scaling.deleteScaling(saved.id, saved.revision);
|
||||
const { scalingOwner } = await import('../../src/lib/server/autoscaling/ownership.js');
|
||||
expect(scalingOwner('t6', 'town')).toBeNull();
|
||||
expect(await scaling.runAutoscaling()).toBe(false);
|
||||
expect(db().prepare('SELECT COUNT(*) AS n FROM server_deployments').get()).toEqual({
|
||||
n: 0
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('rejects stale revisions and preserves the latest settings', async () => {
|
||||
const { scaling, saved } = await setup();
|
||||
@@ -56,21 +85,47 @@ it('rejects stale revisions and preserves the latest settings', async () => {
|
||||
it('blocks deletion with pending intent, then keeps Provisioning history after pause and settlement', async () => {
|
||||
const { db, scaling, saved } = await setup('create-destroy');
|
||||
await scaling.runAutoscaling();
|
||||
const { operation_id: id } = db().prepare('SELECT operation_id FROM autoscaling_decisions WHERE resolved=0').get() as { operation_id: string };
|
||||
expect(() => scaling.deleteScaling(saved.id, saved.revision)).toThrow('outstanding Provisioning');
|
||||
const { operation_id: id } = db()
|
||||
.prepare('SELECT operation_id FROM autoscaling_decisions WHERE resolved=0')
|
||||
.get() as { operation_id: string };
|
||||
expect(() => scaling.deleteScaling(saved.id, saved.revision)).toThrow(
|
||||
'outstanding Provisioning'
|
||||
);
|
||||
expect(scaling.getScalingPolicy(saved.id)?.mode).toBe('create-destroy');
|
||||
const off = { ...settings, mode: 'off' };
|
||||
const paused = scaling.saveScaling(off, saved.id, saved.revision);
|
||||
scaling.deleteScaling(saved.id, paused.revision);
|
||||
const { getDeployment } = await import('../../src/lib/server/provisioning/history.js');
|
||||
expect(getDeployment(id)).toMatchObject({ deployment: { state: 'cancelled' }, sources: [expect.objectContaining({ kind: 'autoscaling', source_id: saved.id, label: 'Deleted autoscaling policy', href: null })] });
|
||||
expect(getDeployment(id)).toMatchObject({
|
||||
deployment: { state: 'cancelled' },
|
||||
sources: [
|
||||
expect.objectContaining({
|
||||
kind: 'autoscaling',
|
||||
source_id: saved.id,
|
||||
label: 'Deleted autoscaling policy',
|
||||
href: null
|
||||
})
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('validates delete requests and returns conflict, not-found, and success statuses', async () => {
|
||||
const { scaling, saved } = await setup();
|
||||
const { POST } = await import('../../src/routes/api/autoscaling/+server.js');
|
||||
const request = (body: object) => POST({ request: new Request('http://localhost/api/autoscaling', { method: 'POST', body: JSON.stringify({ action: 'delete', ...body }) }) });
|
||||
for (const body of [{}, { id: saved.id }, { id: saved.id, revision: '1' }, { id: saved.id, revision: 0 }]) expect((await request(body)).status).toBe(400);
|
||||
const request = (body: object) =>
|
||||
POST({
|
||||
request: new Request('http://localhost/api/autoscaling', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ action: 'delete', ...body })
|
||||
})
|
||||
});
|
||||
for (const body of [
|
||||
{},
|
||||
{ id: saved.id },
|
||||
{ id: saved.id, revision: '1' },
|
||||
{ id: saved.id, revision: 0 }
|
||||
])
|
||||
expect((await request(body)).status).toBe(400);
|
||||
expect((await request({ id: saved.id, revision: saved.revision + 1 })).status).toBe(409);
|
||||
expect((await request({ id: saved.id, revision: saved.revision })).status).toBe(200);
|
||||
expect(scaling.getScalingPolicy(saved.id)).toBeUndefined();
|
||||
|
||||
Reference in New Issue
Block a user