Files
electric-cherry/tests/unit/plugin-versions.test.ts
T

129 lines
5.5 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();
});
const plugin = {
name: 't6-gsc-utils',
kind: 'plugin' as const,
targetRelPath: 't6-gsc-utils.dll',
content: Buffer.from([0, 1, 2, 3])
};
describe('plugin release versions', () => {
it('keeps release tags independent of upload order and preserves binary identity', async () => {
const { createScript, uploadNewVersion, listVersions } =
await import('../../src/lib/server/fleet/scripts.js');
const { script, version } = createScript({ ...plugin, releaseVersion: ' v3.1.0 ' });
expect(version).toMatchObject({ version: 1, release_version: 'v3.1.0' });
const older = uploadNewVersion(
script.id,
Buffer.from([4, 5]),
'Known good release',
'v3.0.4'
);
const rebuild = uploadNewVersion(script.id, Buffer.from([6, 7]), 'Rebuilt', 'v3.0.4');
expect(listVersions(script.id).map((v) => [v.version, v.release_version])).toEqual([
[3, 'v3.0.4'],
[2, 'v3.0.4'],
[1, 'v3.1.0']
]);
expect(older.sha256).not.toBe(rebuild.sha256);
expect(
(await import('../../src/lib/server/fleet/scripts.js')).getVersionContent(version.id)
).toEqual(plugin.content);
});
it('allows unlabeled uploads and non-semver release tags', async () => {
const { createScript, uploadNewVersion } =
await import('../../src/lib/server/fleet/scripts.js');
const { script, version } = createScript(plugin);
expect(version.release_version).toBeNull();
expect(
uploadNewVersion(script.id, plugin.content, undefined, ' ').release_version
).toBeNull();
expect(
uploadNewVersion(script.id, plugin.content, undefined, '2026.09-rc1').release_version
).toBe('2026.09-rc1');
});
it('rejects invalid labels before storing an artifact or new upload', async () => {
const { createScript, uploadNewVersion, listScripts, listVersions } =
await import('../../src/lib/server/fleet/scripts.js');
expect(() => createScript({ ...plugin, releaseVersion: 'x'.repeat(81) })).toThrow(
/release version/
);
expect(listScripts()).toHaveLength(0);
const { script } = createScript(plugin);
expect(() => uploadNewVersion(script.id, plugin.content, undefined, 'v3\n.1')).toThrow(
/release version/
);
expect(listVersions(script.id)).toHaveLength(1);
});
it('migrates an existing database without changing its stored versions', async () => {
const { createScript, getVersion } = await import('../../src/lib/server/fleet/scripts.js');
const { db, closeDb } = await import('../../src/lib/server/db/index.js');
const { version } = createScript(plugin);
db().exec('ALTER TABLE script_versions DROP COLUMN release_version');
closeDb();
expect(getVersion(version.id)).toMatchObject({
id: version.id,
version: 1,
release_version: null,
sha256: version.sha256
});
expect(
(await import('../../src/lib/server/fleet/scripts.js')).getVersionContent(version.id)
).toEqual(plugin.content);
closeDb();
expect(getVersion(version.id)!.release_version).toBeNull();
});
it('round trips release versions through plugin creation, version upload, list and detail APIs', async () => {
const plugins = await import('../../src/routes/api/plugins/+server.js');
const detail = await import('../../src/routes/api/scripts/[id]/+server.js');
const uploads = await import('../../src/routes/api/scripts/[id]/versions/+server.js');
const url = new URL('http://localhost/api/plugins');
const form = new FormData();
form.set('name', plugin.name);
form.set('releaseVersion', 'v3.1.0');
form.set('content', new File([plugin.content], plugin.targetRelPath));
const created = await plugins.POST({
url,
request: new Request(url, { method: 'POST', body: form })
});
expect(created.status).toBe(200);
const { script } = await created.json();
const listed = await (await plugins.GET({ url })).json();
expect(listed.scripts[0].latestVersion.release_version).toBe('v3.1.0');
const next = new FormData();
next.set('releaseVersion', 'v3.1.1');
next.set('content', new File([new Uint8Array([4, 5])], plugin.targetRelPath));
const uploaded = await uploads.POST({
params: { id: String(script.id) },
request: new Request(url, { method: 'POST', body: next })
});
expect(uploaded.status).toBe(200);
expect((await uploaded.json()).version).toMatchObject({
version: 2,
release_version: 'v3.1.1'
});
const result = await (await detail.GET({ params: { id: String(script.id) } })).json();
expect(result.versions.map((v: { release_version: string }) => v.release_version)).toEqual([
'v3.1.1',
'v3.1.0'
]);
expect(result.versions[0]).not.toHaveProperty('content');
});
});