103 new tests across 7 files: - setup/status: emitStatus output structure - setup/packages: loadPackageList (real files), loadAllPackageLists - setup/tailscale: maybeEnableTailscaleInJail enabled/disabled/pkg-fail paths - setup/bastille-helpers: bastille(), jailRoot, jailExists, resolveJailName - setup/hosts: syncLocalHosts with jail discovery and skip logic - src/upstream/classify: classifyUpstreamFiles, classificationHint, summarizeCommit - src/upstream/git: getUpstreamConfig, isGitRepo, listRemotes, readEnvFlag/writeEnvFlag, countCommitsBetween, listCommitHashes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --- Build: FAIL | Tests: pass — Tests 1493 passed (1493)
110 lines
3.9 KiB
TypeScript
110 lines
3.9 KiB
TypeScript
/**
|
|
* setup/packages.test.ts — loadPackageList and loadAllPackageLists tests.
|
|
*
|
|
* loadPackageList reads real files from infra/packages/ — no mocking needed.
|
|
* loadAllPackageLists is tested with mocked readEnvFile and mocked fs.
|
|
*
|
|
* Run with: npx vitest run setup/packages.test.ts
|
|
*/
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Mocks for loadAllPackageLists (readEnvFile + fs for loadPackageList)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
vi.mock('../src/env.js', () => ({
|
|
readEnvFile: vi.fn().mockReturnValue({}),
|
|
}));
|
|
|
|
vi.mock('../src/logger.js', () => ({
|
|
logger: { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
}));
|
|
|
|
import { loadPackageList, loadAllPackageLists } from './packages.js';
|
|
import { readEnvFile } from '../src/env.js';
|
|
|
|
const mockReadEnvFile = vi.mocked(readEnvFile);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// loadPackageList — uses real infra/packages/ files
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('loadPackageList — real files', () => {
|
|
it('loads host-baseline.txt and returns a non-empty array', () => {
|
|
const pkgs = loadPackageList('host-baseline.txt');
|
|
expect(pkgs.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('strips comment lines (starting with #)', () => {
|
|
const pkgs = loadPackageList('host-baseline.txt');
|
|
expect(pkgs.every((p) => !p.startsWith('#'))).toBe(true);
|
|
});
|
|
|
|
it('strips blank lines', () => {
|
|
const pkgs = loadPackageList('host-baseline.txt');
|
|
expect(pkgs.every((p) => p.trim().length > 0)).toBe(true);
|
|
});
|
|
|
|
it('includes "git" in host-baseline', () => {
|
|
const pkgs = loadPackageList('host-baseline.txt');
|
|
expect(pkgs).toContain('git');
|
|
});
|
|
|
|
it('loads worker-jail.txt without error', () => {
|
|
expect(() => loadPackageList('worker-jail.txt')).not.toThrow();
|
|
});
|
|
|
|
it('loads git-jail.txt without error', () => {
|
|
expect(() => loadPackageList('git-jail.txt')).not.toThrow();
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// loadAllPackageLists
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('loadAllPackageLists', () => {
|
|
beforeEach(() => {
|
|
mockReadEnvFile.mockReset().mockReturnValue({});
|
|
delete process.env.FEATURE_TAILSCALE;
|
|
});
|
|
|
|
it('returns a non-empty deduplicated array', () => {
|
|
const all = loadAllPackageLists();
|
|
expect(all.length).toBeGreaterThan(0);
|
|
// Check deduplication: no duplicates
|
|
expect(new Set(all).size).toBe(all.length);
|
|
});
|
|
|
|
it('does not add extra tailscale entry when FEATURE_TAILSCALE is off (may still be in host-baseline)', () => {
|
|
mockReadEnvFile.mockReturnValue({ FEATURE_TAILSCALE: 'NO' });
|
|
const withFlag = (() => {
|
|
mockReadEnvFile.mockReturnValue({ FEATURE_TAILSCALE: 'YES' });
|
|
return loadAllPackageLists();
|
|
})();
|
|
mockReadEnvFile.mockReturnValue({ FEATURE_TAILSCALE: 'NO' });
|
|
const withoutFlag = loadAllPackageLists();
|
|
// Result should be same length or shorter when flag is off
|
|
expect(withoutFlag.length).toBeLessThanOrEqual(withFlag.length);
|
|
});
|
|
|
|
it('result is deduplicated regardless of FEATURE_TAILSCALE', () => {
|
|
mockReadEnvFile.mockReturnValue({ FEATURE_TAILSCALE: 'YES' });
|
|
const all = loadAllPackageLists();
|
|
expect(new Set(all).size).toBe(all.length);
|
|
});
|
|
|
|
it('includes tailscale when process.env.FEATURE_TAILSCALE=YES', () => {
|
|
// tailscale already in host-baseline, but flag path still exercises the branch
|
|
process.env.FEATURE_TAILSCALE = 'YES';
|
|
const all = loadAllPackageLists();
|
|
expect(all).toContain('tailscale');
|
|
delete process.env.FEATURE_TAILSCALE;
|
|
});
|
|
|
|
it('includes packages from all package lists', () => {
|
|
const all = loadAllPackageLists();
|
|
// git appears in host-baseline
|
|
expect(all).toContain('git');
|
|
});
|
|
});
|