clawdie-ai/setup/packages.test.ts
Clawdie AI bd61a5ab94 test: add setup and upstream module unit tests
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)
2026-04-15 05:32:50 +00:00

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');
});
});