Files
Alex Langenfeld d864efb07b test: tighten CI health signals (#4107)
## Summary & Motivation

- Manifest coverage now declares an entry for every matrix app, uses real Vitest skips instead of silent early returns, and fails when a targeted app's manifest is missing, unknown, or unparseable.
- Retries are scoped to deployment e2e runs (`DEPLOYMENT_URL` set), so a flaky unit or integration test can no longer be hidden by a second attempt.
- The stop-workflow cookbook parks on a sleep between iterations, giving the hook an observable barrier to race instead of a fixed delay, and the AbortController hook test waits on queue state rather than a 10ms timer.
- The world-postgres direct-storage fixture drives its run to a terminal state so the conformance worker doesn't recover and replay an unregistered workflow.
- Generated e2e result sidecars are ignored and the committed copies removed; they're CI artifacts, not fixtures.

## Test Plan

Existing coverage runs in CI. With retries disabled: the cookbook agent suite passed 8/8, the two stop-workflow tests passed 10/10, and the AbortController hook replay test passed 25/25 under `CI=1`. The manifest suite skips 52 apps explicitly when nothing is built, and fails on unknown or missing targeted apps. The Docker-backed Postgres spec could not run locally (Testcontainers found no container runtime); `@workflow/world-postgres` typechecks.
2026-09-11 12:39:17 -05:00

130 lines
4.4 KiB
TypeScript

import { execSync } from 'node:child_process';
import { PostgreSqlContainer } from '@testcontainers/postgresql';
import {
eventIdToSlot,
FIRST_EVENT_SLOT,
SPEC_VERSION_CURRENT,
} from '@workflow/world';
import { createTestSuite } from '@workflow/world-testing';
import { afterAll, beforeAll, expect, test } from 'vitest';
// Skip these tests on Windows since it relies on a docker container
if (process.platform === 'win32') {
test.skip('skipped on Windows since it relies on a docker container', () => {});
} else {
let container: Awaited<ReturnType<PostgreSqlContainer['start']>>;
beforeAll(async () => {
container = await new PostgreSqlContainer('postgres:15-alpine').start();
const dbUrl = container.getConnectionUri();
process.env.WORKFLOW_POSTGRES_URL = dbUrl;
process.env.DATABASE_URL = dbUrl;
execSync('pnpm db:push', {
stdio: 'inherit',
cwd: process.cwd(),
env: process.env,
});
}, 120_000);
afterAll(async () => {
if (container) {
await container.stop();
}
});
test('smoke', () => {});
// Sealed-log noop tolerance (specVersion 7): world-postgres allocates
// positions from its own counter and never seals holes itself, but a
// `noop` is a legal resident of any spec-7 slot log, and the storage layer
// must round-trip one — store it at its slot, list it back in order, and
// keep numbering past it. Direct storage access (not the conformance
// server): only a backend sealer would ever write one, and the public
// CreateEventSchema excludes it.
test('stores, lists, and numbers past a noop event', async () => {
// Storage layer only — createWorld would also spin up the queue and the
// streamer's dedicated LISTEN client, which have no shutdown hook here
// and would die noisily when afterAll stops the container.
const { createClient } = await import('../dist/drizzle/index.js');
const { createEventsStorage } = await import('../dist/storage.js');
const { Pool } = await import('pg');
const pool = new Pool({
connectionString: process.env.WORKFLOW_POSTGRES_URL,
max: 2,
});
const world = { events: createEventsStorage(createClient(pool)) };
const serialized = (value: unknown) =>
({ data: JSON.stringify(value), encoding: 'json' }) as any;
const created = await world.events.create('', {
eventType: 'run_created',
specVersion: SPEC_VERSION_CURRENT,
eventData: {
deploymentId: 'dpl_noop',
workflowName: 'noopWorkflow',
input: serialized([]),
},
} as any);
const runId = created.event!.runId;
await world.events.create(runId, {
eventType: 'run_started',
specVersion: SPEC_VERSION_CURRENT,
} as any);
await world.events.create(runId, {
eventType: 'noop',
specVersion: SPEC_VERSION_CURRENT,
eventData: { sealed: true },
} as any);
await world.events.create(runId, {
eventType: 'step_created',
correlationId: 'step_after_noop',
specVersion: SPEC_VERSION_CURRENT,
eventData: { stepName: 'afterNoop', input: serialized([]) },
} as any);
const result = await world.events.list({
runId,
pagination: { limit: 100 },
});
expect(result.data.map((event: any) => event.eventType)).toEqual([
'run_created',
'run_started',
'noop',
'step_created',
]);
expect(
result.data.map((event: any) => eventIdToSlot(event.eventId))
).toEqual([
FIRST_EVENT_SLOT,
FIRST_EVENT_SLOT + 1,
FIRST_EVENT_SLOT + 2,
FIRST_EVENT_SLOT + 3,
]);
// Leave the direct-storage fixture terminal. The conformance tests below
// start a real queue worker against the same database; an unfinished run
// would be recovered and replayed even though its synthetic workflow is
// intentionally not registered by that server.
await world.events.create(runId, {
eventType: 'step_started',
correlationId: 'step_after_noop',
specVersion: SPEC_VERSION_CURRENT,
} as any);
await world.events.create(runId, {
eventType: 'step_completed',
correlationId: 'step_after_noop',
specVersion: SPEC_VERSION_CURRENT,
eventData: { result: serialized(null) },
} as any);
await world.events.create(runId, {
eventType: 'run_completed',
specVersion: SPEC_VERSION_CURRENT,
eventData: { output: serialized(null) },
} as any);
await pool.end();
}, 60_000);
createTestSuite('./dist/index.js');
}