113 lines
5.1 KiB
TypeScript
113 lines
5.1 KiB
TypeScript
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();
|
|
delete process.env.RCON_PASSWORD;
|
|
});
|
|
afterEach(async () => {
|
|
await fixture.cleanup();
|
|
});
|
|
function request(content: string, reuse = false, releaseVersion = '1.0.0') {
|
|
const form = new FormData();
|
|
form.append('releaseVersion', releaseVersion);
|
|
form.append('content', new File([content], 'hud.gsc'));
|
|
if (reuse) form.append('reuseExisting', 'true');
|
|
return new Request('http://localhost/api/scripts/inspect', { method: 'POST', body: form });
|
|
}
|
|
async function seed() {
|
|
const mod = await import('../../src/lib/server/fleet/scripts.js');
|
|
return {
|
|
...mod,
|
|
...mod.createScript({
|
|
releaseVersion: '1.0.0',
|
|
name: 'HUD',
|
|
targetRelPath: 'hud.gsc',
|
|
scopeType: 'game',
|
|
scopeValue: 't5',
|
|
content: Buffer.from('main(){}')
|
|
})
|
|
};
|
|
}
|
|
|
|
describe('script upload review', () => {
|
|
it('inspects content against all versions without creating records or including plugins', async () => {
|
|
const { script, version, uploadNewVersion, createScript, listVersions } = await seed();
|
|
uploadNewVersion(script.id, Buffer.from('changed(){}'), undefined, '1.0.1');
|
|
createScript({
|
|
name: 'Plugin',
|
|
targetRelPath: 'plugin.dll',
|
|
kind: 'plugin',
|
|
content: Buffer.from('main(){}')
|
|
});
|
|
const { POST } = await import('../../src/routes/api/scripts/inspect/+server.js');
|
|
const res = await POST({ request: request('main(){}') });
|
|
expect(await res.json()).toEqual({
|
|
sha256: version.sha256,
|
|
duplicates: [
|
|
{ scriptId: script.id, versionId: version.id, version: 1, release_version: '1.0.0' }
|
|
]
|
|
});
|
|
expect(listVersions(script.id)).toHaveLength(2);
|
|
expect((await POST({ request: request('') })).status).toBe(400);
|
|
});
|
|
it('reuses identical historical content and creates changed versions while preserving scope', async () => {
|
|
const { script, version, uploadNewVersion, listVersions, getScript } = await seed();
|
|
uploadNewVersion(script.id, Buffer.from('changed(){}'), undefined, '1.0.2');
|
|
const { POST } = await import('../../src/routes/api/scripts/[id]/versions/+server.js');
|
|
const invoke = (content: string, release = '1.0.0') =>
|
|
POST({ params: { id: String(script.id) }, request: request(content, true, release) });
|
|
const res = await invoke('main(){}');
|
|
expect(await res.json()).toMatchObject({
|
|
ok: true,
|
|
reused: true,
|
|
version: { id: version.id, version: 1 }
|
|
});
|
|
expect(listVersions(script.id)).toHaveLength(2);
|
|
const added = await invoke('third(){}', '1.1.0');
|
|
expect(await added.json()).toMatchObject({ ok: true, version: { version: 3 } });
|
|
expect(listVersions(script.id)).toHaveLength(3);
|
|
expect(getScript(script.id)).toMatchObject({ scope_type: 'game', scope_value: 't5' });
|
|
expect((await invoke('')).status).toBe(400);
|
|
expect(listVersions(script.id)).toHaveLength(3);
|
|
});
|
|
it('rejects new versions when a beta becomes active after the upload preview', async () => {
|
|
const { script, version, listVersions } = await seed();
|
|
const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js');
|
|
await seedServerRegistry();
|
|
const { openBeta } = await import('../../src/lib/server/fleet/beta.js');
|
|
await openBeta({
|
|
scripts: [{ scriptId: script.id, scriptVersionId: version.id }],
|
|
servers: ['t5_zombie_theater_1'],
|
|
waitForHealth: false,
|
|
waitForMatch: false
|
|
});
|
|
const { POST } = await import('../../src/routes/api/scripts/[id]/versions/+server.js');
|
|
const res = await POST({
|
|
params: { id: String(script.id) },
|
|
request: request('changed(){}', true)
|
|
});
|
|
expect(res.status).toBe(409);
|
|
expect(listVersions(script.id)).toHaveLength(1);
|
|
});
|
|
it('lists promoted and latest version metadata separately without file contents', async () => {
|
|
const { script, version, uploadNewVersion } = await seed();
|
|
const latest = uploadNewVersion(script.id, Buffer.from('changed(){}'), undefined, '1.0.3');
|
|
const { db } = await import('../../src/lib/server/db/index.js');
|
|
db()
|
|
.prepare('UPDATE scripts SET current_version_id = ? WHERE id = ?')
|
|
.run(version.id, script.id);
|
|
const { GET } = await import('../../src/routes/api/scripts/+server.js');
|
|
const body = await (
|
|
await GET({ url: new URL('http://localhost/api/scripts?kind=script') })
|
|
).json();
|
|
expect(body.scripts[0]).toMatchObject({
|
|
currentVersion: { id: version.id, version: 1 },
|
|
latestVersion: { id: latest.id, version: 2 }
|
|
});
|
|
expect(body.scripts[0].currentVersion).not.toHaveProperty('content');
|
|
});
|
|
});
|