Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import {
|
|
buildReseedCommand,
|
|
buildRelaunchCommands,
|
|
readRosterAgentNames,
|
|
runFrameworkReseed,
|
|
} from './update-checker.js';
|
|
|
|
/**
|
|
* F3-m3 / R13: `mosaic update` re-seeds the framework + (opt-in) relaunches
|
|
* durable agents so shipped launcher/runtime changes activate. These cover the
|
|
* pure builders + the missing-installer guard (the exec path is integration).
|
|
*/
|
|
|
|
describe('buildReseedCommand', () => {
|
|
it('invokes the package install.sh in data-safe sync-only keep mode', () => {
|
|
const out = buildReseedCommand('/pkg/framework', '/home/u/.config/mosaic');
|
|
expect(out.installer).toBe('/pkg/framework/install.sh');
|
|
expect(out.command).toBe('bash /pkg/framework/install.sh');
|
|
expect(out.env).toEqual({
|
|
MOSAIC_SYNC_ONLY: '1',
|
|
MOSAIC_INSTALL_MODE: 'keep',
|
|
MOSAIC_HOME: '/home/u/.config/mosaic',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('buildRelaunchCommands', () => {
|
|
it('builds a systemctl --user restart per agent unit', () => {
|
|
expect(buildRelaunchCommands(['orchestrator', 'coder0'])).toEqual([
|
|
['systemctl', '--user', 'restart', 'mosaic-agent@orchestrator.service'],
|
|
['systemctl', '--user', 'restart', 'mosaic-agent@coder0.service'],
|
|
]);
|
|
});
|
|
|
|
it('is empty for an empty roster', () => {
|
|
expect(buildRelaunchCommands([])).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('readRosterAgentNames', () => {
|
|
let home: string;
|
|
|
|
beforeEach(() => {
|
|
home = mkdtempSync(join(tmpdir(), 'mosaic-roster-'));
|
|
});
|
|
afterEach(() => {
|
|
rmSync(home, { recursive: true, force: true });
|
|
});
|
|
|
|
it('returns [] when no roster exists', () => {
|
|
expect(readRosterAgentNames(home)).toEqual([]);
|
|
});
|
|
|
|
it('extracts agent names from roster.yaml', () => {
|
|
mkdirSync(join(home, 'fleet'), { recursive: true });
|
|
writeFileSync(
|
|
join(home, 'fleet', 'roster.yaml'),
|
|
[
|
|
'version: 1',
|
|
'agents:',
|
|
' - name: orchestrator',
|
|
' runtime: pi',
|
|
' - name: coder0',
|
|
' runtime: claude',
|
|
' - name: "reviewer-1"',
|
|
' runtime: codex',
|
|
].join('\n') + '\n',
|
|
);
|
|
expect(readRosterAgentNames(home)).toEqual(['orchestrator', 'coder0', 'reviewer-1']);
|
|
});
|
|
});
|
|
|
|
describe('runFrameworkReseed', () => {
|
|
it('reports not-ok (not throw) when the installer is absent', () => {
|
|
const missing = mkdtempSync(join(tmpdir(), 'mosaic-noinstaller-'));
|
|
const res = runFrameworkReseed(missing, join(missing, 'home'));
|
|
expect(res.ok).toBe(false);
|
|
expect(res.reason).toContain('installer not found');
|
|
rmSync(missing, { recursive: true, force: true });
|
|
});
|
|
});
|