91 lines
3.6 KiB
TypeScript
91 lines
3.6 KiB
TypeScript
import { cp, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
import { tmpdir } from 'node:os';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
import {
|
|
SHIPPED_FLEET_ARTIFACT_DISPOSITIONS,
|
|
validateShippedFleetArtifactDispositions,
|
|
} from './example-profile-dispositions.js';
|
|
|
|
const frameworkFleet = resolve(
|
|
dirname(fileURLToPath(import.meta.url)),
|
|
'..',
|
|
'..',
|
|
'framework',
|
|
'fleet',
|
|
);
|
|
|
|
const EXPECTED_DISPOSITIONS = [
|
|
'examples/coding.yaml:v1-fixture',
|
|
'examples/general.yaml:v1-fixture',
|
|
'examples/hybrid.yaml:v1-fixture',
|
|
'examples/local-canary.yaml:v1-fixture',
|
|
'examples/minimal.yaml:v1-fixture',
|
|
'examples/operator-interaction.yaml:v1-fixture',
|
|
'examples/research.yaml:v1-fixture',
|
|
'profiles/business.yaml:canonical-profile',
|
|
'profiles/marketing.yaml:canonical-profile',
|
|
'profiles/personal-assistant.yaml:canonical-profile',
|
|
'profiles/research.yaml:canonical-profile',
|
|
'profiles/software-delivery.yaml:canonical-profile',
|
|
'services/operator-interaction.yaml:canonical-service-policy',
|
|
];
|
|
|
|
const declared = SHIPPED_FLEET_ARTIFACT_DISPOSITIONS.map(
|
|
({ path, disposition }): string => `${path}:${disposition}`,
|
|
);
|
|
|
|
describe('shipped fleet example/profile/service disposition validation', (): void => {
|
|
it('enumerates every inventory artifact with an explicit executable disposition', (): void => {
|
|
expect(declared).toEqual(EXPECTED_DISPOSITIONS);
|
|
});
|
|
|
|
it('validates every shipped artifact through its declared v1 or canonical path', async (): Promise<void> => {
|
|
const results = await validateShippedFleetArtifactDispositions({ frameworkFleet });
|
|
|
|
expect(results.map(({ path, disposition }): string => `${path}:${disposition}`)).toEqual(
|
|
EXPECTED_DISPOSITIONS,
|
|
);
|
|
expect(results.filter(({ disposition }): boolean => disposition === 'v1-fixture')).toHaveLength(
|
|
7,
|
|
);
|
|
expect(
|
|
results.filter(({ disposition }): boolean => disposition === 'canonical-profile'),
|
|
).toHaveLength(5);
|
|
expect(
|
|
results.find(({ path }): boolean => path === 'services/operator-interaction.yaml'),
|
|
).toMatchObject({
|
|
disposition: 'canonical-service-policy',
|
|
});
|
|
});
|
|
|
|
let temporaryFleet: string | undefined;
|
|
afterEach(async (): Promise<void> => {
|
|
if (temporaryFleet) await rm(temporaryFleet, { recursive: true, force: true });
|
|
temporaryFleet = undefined;
|
|
});
|
|
|
|
it('fails closed when a shipped artifact lacks a declared disposition', async (): Promise<void> => {
|
|
temporaryFleet = await mkdtemp(join(tmpdir(), 'mosaic-dispositions-'));
|
|
await cp(frameworkFleet, temporaryFleet, { recursive: true });
|
|
await writeFile(join(temporaryFleet, 'examples', 'undeclared.yaml'), 'version: 1\n');
|
|
|
|
await expect(
|
|
validateShippedFleetArtifactDispositions({ frameworkFleet: temporaryFleet }),
|
|
).rejects.toThrow(/undeclared shipped fleet artifact.*examples\/undeclared.yaml/i);
|
|
});
|
|
|
|
it('rejects a v1 fixture when its explicit version declaration is removed', async (): Promise<void> => {
|
|
temporaryFleet = await mkdtemp(join(tmpdir(), 'mosaic-dispositions-'));
|
|
await cp(frameworkFleet, temporaryFleet, { recursive: true });
|
|
const fixturePath = join(temporaryFleet, 'examples', 'coding.yaml');
|
|
const fixture = await readFile(fixturePath, 'utf8');
|
|
await writeFile(fixturePath, fixture.replace(/^version: 1\n/, ''));
|
|
|
|
await expect(
|
|
validateShippedFleetArtifactDispositions({ frameworkFleet: temporaryFleet }),
|
|
).rejects.toThrow(/Fleet roster version must be 1/);
|
|
});
|
|
});
|