chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { afterEach, describe, expect, it, vi } from 'vitest';
import { createShellExecutor } from '../src/executor.js';
afterEach(() => {
vi.unstubAllEnvs();
});
/**
* @param {import('../src/workflow.js').WorkflowStep[]} steps
* @param {{timeoutMs?: number, env?: Record<string, string>}} [options]
*/
async function run(steps, options = {}) {
/** @type {string[]} */
const log = [];
const executor = createShellExecutor(
options.timeoutMs ? { timeoutMs: options.timeoutMs } : {},
);
const results = await executor({
dir: process.cwd(),
steps,
env: options.env ?? {},
onLog: (chunk) => log.push(chunk),
});
return { results, log: log.join('') };
}
describe('createShellExecutor', () => {
it('runs every step and reports each exit code', async () => {
const { results } = await run([
{ name: 'first', run: 'true' },
{ name: 'second', run: 'true' },
]);
expect(results.map((r) => [r.name, r.exitCode])).toEqual([
['first', 0],
['second', 0],
]);
expect(results.every((r) => r.durationMs >= 0)).toBe(true);
});
it('stops at the first failing step', async () => {
const { results } = await run([
{ name: 'fails', run: 'exit 3' },
{ name: 'never runs', run: 'true' },
]);
expect(results).toHaveLength(1);
expect(results[0].exitCode).toBe(3);
});
it('captures stdout and stderr', async () => {
const { log } = await run([
{ name: 'talk', run: 'echo out; echo err 1>&2' },
]);
expect(log).toContain('out');
expect(log).toContain('err');
expect(log).toContain('=== talk ===');
});
it('passes the run environment to the step', async () => {
const { log } = await run([{ name: 'env', run: 'echo "$MARKER"' }], {
env: { MARKER: 'from-workflow' },
});
expect(log).toContain('from-workflow');
});
it('withholds the runner credentials from the step', async () => {
vi.stubEnv('PDSJS_CI_IDENTIFIER', 'runner.example.com');
vi.stubEnv('PDSJS_CI_PASSWORD', 'runner-app-password');
const { log } = await run([
{
name: 'env',
run: 'echo "id=${PDSJS_CI_IDENTIFIER:-absent} pw=${PDSJS_CI_PASSWORD:-absent}"',
},
]);
expect(log).toContain('id=absent pw=absent');
});
it('reports a timed out step as a failure', async () => {
const { results, log } = await run([{ name: 'hang', run: 'sleep 5' }], {
timeoutMs: 100,
});
expect(results[0].exitCode).not.toBe(0);
expect(log).toContain('timed out');
});
});