test(ci): stabilize runner-sensitive isolated tests

- isolate tokens and session-tracker tests in child processes

- make child scripts resolve repo modules from the test location

- avoid machine-specific paths in the repo
This commit is contained in:
Tam Nhu Tran
2026-04-16 00:08:46 -04:00
parent 3b17bc934a
commit 2ba3a0ab02
2 changed files with 181 additions and 65 deletions
@@ -1,56 +1,111 @@
import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; import { describe, expect, it } from 'bun:test';
import * as fs from 'fs'; import * as fs from 'fs';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import { import { spawnSync } from 'child_process';
registerSession, import { pathToFileURL } from 'url';
unregisterSession,
getProxyStatus,
} from '../../../src/cliproxy/session-tracker';
describe('session-tracker target metadata', () => { const REPO_ROOT = path.resolve(import.meta.dir, '../../..');
let tmpDir: string; const SESSION_TRACKER_URL = pathToFileURL(
let originalCcsHome: string | undefined; path.join(REPO_ROOT, 'src/cliproxy/session-tracker.ts')
const port = 28317; ).href;
beforeEach(() => { function withScopedSessionTrackerHome<T>(run: (tempHome: string) => T): T {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-session-target-test-')); const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-session-target-test-'));
originalCcsHome = process.env.CCS_HOME; try {
process.env.CCS_HOME = tmpDir; return run(tempHome);
}); } finally {
fs.rmSync(tempHome, { recursive: true, force: true });
}
}
afterEach(() => { function runSessionTrackerScenario(
if (originalCcsHome !== undefined) { tempHome: string,
process.env.CCS_HOME = originalCcsHome; targets: string[]
} else { ): {
delete process.env.CCS_HOME; running: boolean;
target?: string;
sessionCount?: number;
} {
const script = `
import {
registerSession,
unregisterSession,
getProxyStatus,
} from ${JSON.stringify(SESSION_TRACKER_URL)};
const port = 28317;
const sessionIds = [];
for (const target of ${JSON.stringify(targets)}) {
sessionIds.push(registerSession(port, process.pid, undefined, undefined, target));
} }
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('returns single target when all sessions share same target', () => {
const s1 = registerSession(port, process.pid, undefined, undefined, 'droid');
const s2 = registerSession(port, process.pid, undefined, undefined, 'droid');
const status = getProxyStatus(port); const status = getProxyStatus(port);
expect(status.running).toBe(true); for (const sessionId of sessionIds) {
expect(status.target).toBe('droid'); unregisterSession(sessionId, port);
expect(status.sessionCount).toBe(2); }
unregisterSession(s1, port); console.log(JSON.stringify({
unregisterSession(s2, port); running: status.running,
target: status.target ?? null,
sessionCount: status.sessionCount ?? null,
}));
`;
const scriptPath = path.join(tempHome, `session-target-child-${Date.now()}.mjs`);
fs.writeFileSync(scriptPath, script, 'utf8');
const result = spawnSync('/bin/bash', ['-lc', `bun ${JSON.stringify(scriptPath)}`], {
cwd: REPO_ROOT,
env: {
...process.env,
CCS_HOME: tempHome,
CCS_DIR: '',
},
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
});
if (result.status !== 0) {
throw new Error(
`child session-tracker scenario failed: ${JSON.stringify({
command: `bun ${scriptPath}`,
status: result.status,
signal: result.signal,
error: result.error?.message ?? null,
stdout: result.stdout,
stderr: result.stderr,
})}`
);
}
const lines = result.stdout
.split('\n')
.map((line) => line.trim())
.filter(Boolean);
return JSON.parse(lines.at(-1) || '{}') as {
running: boolean;
target?: string;
sessionCount?: number;
};
}
describe('session-tracker target metadata', () => {
it('returns single target when all sessions share same target', () => {
withScopedSessionTrackerHome((tempHome) => {
const status = runSessionTrackerScenario(tempHome, ['droid', 'droid']);
expect(status.running).toBe(true);
expect(status.target).toBe('droid');
expect(status.sessionCount).toBe(2);
});
}); });
it('returns mixed when active sessions use different targets', () => { it('returns mixed when active sessions use different targets', () => {
const s1 = registerSession(port, process.pid, undefined, undefined, 'claude'); withScopedSessionTrackerHome((tempHome) => {
const s2 = registerSession(port, process.pid, undefined, undefined, 'droid'); const status = runSessionTrackerScenario(tempHome, ['claude', 'droid']);
expect(status.running).toBe(true);
const status = getProxyStatus(port); expect(status.target).toBe('mixed');
expect(status.running).toBe(true); expect(status.sessionCount).toBe(2);
expect(status.target).toBe('mixed'); });
expect(status.sessionCount).toBe(2);
unregisterSession(s1, port);
unregisterSession(s2, port);
}); });
}); });
@@ -2,64 +2,125 @@ import { describe, expect, it } from 'bun:test';
import * as fs from 'fs'; import * as fs from 'fs';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import { handleTokensCommand } from '../../../src/commands/tokens-command'; import { spawnSync } from 'child_process';
import { getConfigYamlPath, loadUnifiedConfig } from '../../../src/config/unified-config-loader'; import { pathToFileURL } from 'url';
import { runWithScopedCcsHome, setGlobalConfigDir } from '../../../src/utils/config-manager'; import { setGlobalConfigDir } from '../../../src/utils/config-manager';
async function withScopedTokensHome<T>(run: (tempHome: string) => Promise<T>): Promise<T> { const REPO_ROOT = path.resolve(import.meta.dir, '../../..');
const TOKENS_COMMAND_URL = pathToFileURL(
path.join(REPO_ROOT, 'src/commands/tokens-command.ts')
).href;
const UNIFIED_CONFIG_LOADER_URL = pathToFileURL(
path.join(REPO_ROOT, 'src/config/unified-config-loader.ts')
).href;
function withScopedTokensHome<T>(run: (tempHome: string) => T): T {
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-tokens-rotation-')); const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-tokens-rotation-'));
setGlobalConfigDir(undefined); setGlobalConfigDir(undefined);
try { try {
return await runWithScopedCcsHome(tempHome, async () => await run(tempHome)); return run(tempHome);
} finally { } finally {
setGlobalConfigDir(undefined); setGlobalConfigDir(undefined);
fs.rmSync(tempHome, { recursive: true, force: true }); fs.rmSync(tempHome, { recursive: true, force: true });
} }
} }
function runTokensCommandInChild(tempHome: string, args: string[]) {
const script = `
import { handleTokensCommand } from ${JSON.stringify(TOKENS_COMMAND_URL)};
import { loadUnifiedConfig } from ${JSON.stringify(UNIFIED_CONFIG_LOADER_URL)};
const exitCode = await handleTokensCommand(${JSON.stringify(args)});
const config = loadUnifiedConfig();
const managementSecret = config?.cliproxy.auth?.management_secret ?? null;
console.log(JSON.stringify({
exitCode,
apiKey: config?.cliproxy.auth?.api_key ?? null,
managementSecretLength: typeof managementSecret === 'string' ? managementSecret.length : 0,
}));
`;
const scriptPath = path.join(tempHome, `tokens-child-${Date.now()}.mjs`);
fs.writeFileSync(scriptPath, script, 'utf8');
const result = spawnSync('/bin/bash', ['-lc', `bun ${JSON.stringify(scriptPath)}`], {
cwd: REPO_ROOT,
env: {
...process.env,
CCS_HOME: tempHome,
CCS_DIR: '',
NO_COLOR: '1',
},
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
});
if (result.status !== 0) {
throw new Error(
`child tokens command failed: ${JSON.stringify({
command: `bun ${scriptPath}`,
status: result.status,
signal: result.signal,
error: result.error?.message ?? null,
stdout: result.stdout,
stderr: result.stderr,
})}`
);
}
const lines = result.stdout
.split('\n')
.map((line) => line.trim())
.filter(Boolean);
const payload = JSON.parse(lines.at(-1) || '{}') as {
exitCode: number;
apiKey: string | null;
managementSecretLength: number;
};
return { payload, stdout: result.stdout, stderr: result.stderr };
}
describe('tokens command auth rotation', () => { describe('tokens command auth rotation', () => {
it('applies api-key and regenerated secret in a single invocation', async () => { it('applies api-key and regenerated secret in a single invocation', () => {
await withScopedTokensHome(async () => { withScopedTokensHome((tempHome) => {
const exitCode = await handleTokensCommand([ const { payload } = runTokensCommandInChild(tempHome, [
'--api-key', '--api-key',
'ccs-custom-key-123', 'ccs-custom-key-123',
'--regenerate-secret', '--regenerate-secret',
]); ]);
const configYamlPath = path.join(tempHome, '.ccs', 'config.yaml');
const config = loadUnifiedConfig();
const managementSecret = config?.cliproxy.auth?.management_secret;
const configYamlPath = getConfigYamlPath();
const diagnostics = { const diagnostics = {
exitCode, exitCode: payload.exitCode,
configYamlPath, configYamlPath,
configExists: fs.existsSync(configYamlPath), configExists: fs.existsSync(configYamlPath),
apiKey: config?.cliproxy.auth?.api_key ?? null, apiKey: payload.apiKey,
managementSecretLength: (managementSecret ?? '').length, managementSecretLength: payload.managementSecretLength,
}; };
if ( if (
exitCode !== 0 || payload.exitCode !== 0 ||
config?.cliproxy.auth?.api_key !== 'ccs-custom-key-123' || payload.apiKey !== 'ccs-custom-key-123' ||
typeof managementSecret !== 'string' || payload.managementSecretLength <= 20
(managementSecret ?? '').length <= 20
) { ) {
throw new Error(`tokens rotation diagnostics: ${JSON.stringify(diagnostics)}`); throw new Error(`tokens rotation diagnostics: ${JSON.stringify(diagnostics)}`);
} }
}); });
}); });
it('rejects conflicting manual and generated secret flags', async () => { it('rejects conflicting manual and generated secret flags', () => {
await withScopedTokensHome(async () => { withScopedTokensHome((tempHome) => {
const exitCode = await handleTokensCommand([ const { payload } = runTokensCommandInChild(tempHome, [
'--secret', '--secret',
'manual-secret', 'manual-secret',
'--regenerate-secret', '--regenerate-secret',
]); ]);
expect(exitCode).toBe(1); expect(payload.exitCode).toBe(1);
expect(fs.existsSync(getConfigYamlPath())).toBe(false); expect(fs.existsSync(path.join(tempHome, '.ccs', 'config.yaml'))).toBe(false);
}); });
}); });
}); });