mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
885c1486bb
* test(ci): single-retry policy for enumerated contention-flaky files * fix: satisfy fallow * test(ci): read failures through a lane reporter so timeouts stay distinguishable * test(ci): cover the lane reporter and drop its duplicated boilerplate * chore(fallow): own the retry lane's tool-loaded export seams * test(ci): block retries on non-test failures and classify timeouts structurally * test(ci): decide retry eligibility from runner metadata and route gate verdicts through blockers * refactor(ci): name the retry policy's rules in code instead of comments * test(ci): mark runner-aborted timeouts inside the runner instead of inferring them * test(ci): make timeout provenance a per-run secret, not a writable flag Cover direct task.meta mutation in the real child-Vitest fixture gate. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(ci): retry the failed files in the first run's project and coverage modes Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: drop deleted repo-health file from the retry list after #1480 Rebase onto main post-#1480: the SkillGym/repo-health descope deleted scripts/repo-health/run.test.ts, whose CONTENTION_RETRY_FILES entry would now fail this PR's own missing-file check, and inlined the slow-test budgets into the reporter, resolving the budgets-module import. Envelope comments now point at scripts/lib/lane-envelope.ts instead of the closed #1430. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FUv7bvbWNryuXgSBuqTtep --------- Co-authored-by: Michał Pierzchała <thymikee@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
132 lines
5.4 KiB
TypeScript
132 lines
5.4 KiB
TypeScript
import type { Reporter } from 'vitest/node';
|
|
import { defineConfig } from 'vitest/config';
|
|
import contentionRetryReporter, {
|
|
FAILURE_FILE_ENV,
|
|
} from './scripts/lib/contention-retry-reporter.ts';
|
|
import { SUBPROCESS_STUB_TESTS } from './scripts/lib/contention-retry.ts';
|
|
import slowTestGateReporter from './scripts/vitest-slow-test-reporter.ts';
|
|
|
|
// Tests that stub a real binary (adb/xcrun/npx) by mutating process.env.PATH and
|
|
// then spawn it, so each case waits real subprocess/retry/poll time. Run at the
|
|
// unit suite's default ~7x file parallelism they contend for CPU and their stub
|
|
// spawns get starved past an internal budget, so production takes a generic
|
|
// failure path and returns a different error than the assertion expects — a
|
|
// contention flake whose failing subset shifts between runs (see
|
|
// docs/agents/testing.md "tests must not wait real time"). Serialized below with
|
|
// per-file isolation so only one such file spawns stubs at a time, the same
|
|
// execution contract the pre-split android index.test.ts aggregation provided.
|
|
// The enumerated file list, with each file's contention reason and its owned
|
|
// waiver, lives in scripts/lib/contention-retry.ts — the same constant the CI
|
|
// single-retry policy (#1419) reads, so the two cannot drift.
|
|
export { SUBPROCESS_STUB_TESTS };
|
|
|
|
/** Every project loads the same setup, including the runner-timeout provenance hook. */
|
|
const SETUP_FILES = [
|
|
'scripts/vitest-runner-timeout-setup.ts',
|
|
'src/__tests__/hermetic-env-setup.ts',
|
|
'src/__tests__/process-memo-setup.ts',
|
|
];
|
|
|
|
/** Reporters for every lane; a `--reporter` flag would replace them, so no lane passes one. */
|
|
export function reporters(env: NodeJS.ProcessEnv = process.env): Array<string | Reporter> {
|
|
const gates: Array<string | Reporter> = ['default', slowTestGateReporter()];
|
|
// The failure sink drains the gates' verdicts, so it reports after them.
|
|
return env[FAILURE_FILE_ENV] ? [...gates, contentionRetryReporter()] : gates;
|
|
}
|
|
|
|
export default defineConfig({
|
|
test: {
|
|
// Wall-clock discipline: unit tests must not wait real time. Measured
|
|
// 2026-07-04: the suite's duration was bounded by files sleeping through
|
|
// production timeout budgets. slowTestThreshold surfaces creep in local
|
|
// output; the slow-test reporter enforces the ratchet (pinned offenders
|
|
// only shrink). Isolation stays ON and pool stays forks: measured
|
|
// --no-isolate = 205s wall vs 48s (module state thrashes across files),
|
|
// threads = no change.
|
|
slowTestThreshold: 500,
|
|
reporters: reporters(),
|
|
projects: [
|
|
{
|
|
test: {
|
|
name: 'unit-core',
|
|
// Explicit script entries keep maintained conformance guards in the
|
|
// unit suite without waking every ad-hoc *.test.ts under scripts/.
|
|
include: [
|
|
'src/**/*.test.ts',
|
|
'scripts/__tests__/help-conformance-bench.test.ts',
|
|
'scripts/__tests__/help-conformance-error-recovery-coverage.test.ts',
|
|
'scripts/__tests__/help-conformance-sample-outputs.test.ts',
|
|
'scripts/__tests__/help-conformance-topic-coverage.test.ts',
|
|
// Parses CI configuration only, so this action guard needs no device or subprocess lane.
|
|
'test/ci/upload-agent-device-artifacts.test.ts',
|
|
// The frozen replay-compat corpus (#1417): parse-only, no device or
|
|
// subprocess work, so it belongs in the fast lane next to the
|
|
// grammar it guards.
|
|
'test/replay-compat/corpus.test.ts',
|
|
// The Maestro conformance oracle runs via `node --test` in its own CI
|
|
// job (scripts/maestro-conformance), like the layering guard.
|
|
],
|
|
exclude: [...SUBPROCESS_STUB_TESTS],
|
|
setupFiles: SETUP_FILES,
|
|
},
|
|
},
|
|
{
|
|
// The subprocess-stub tests stub adb/xcrun/npx by mutating process.env
|
|
// (PATH, AGENT_DEVICE_TEST_ARGS_FILE) and wait real subprocess/retry/poll
|
|
// time, so the group runs serialized with per-file isolation — the same
|
|
// execution contract the pre-split android index.test.ts aggregation
|
|
// provided without leaking module caches between split files.
|
|
test: {
|
|
name: 'subprocess-stub',
|
|
include: [...SUBPROCESS_STUB_TESTS],
|
|
setupFiles: SETUP_FILES,
|
|
fileParallelism: false,
|
|
isolate: true,
|
|
maxWorkers: 1,
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: 'provider-integration',
|
|
include: ['test/integration/provider-scenarios/**/*.test.ts'],
|
|
setupFiles: SETUP_FILES,
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: 'interaction-contract',
|
|
include: ['test/integration/interaction-contract/**/*.test.ts'],
|
|
setupFiles: SETUP_FILES,
|
|
},
|
|
},
|
|
{
|
|
test: {
|
|
name: 'output-economy',
|
|
include: ['test/output-economy/**/*.test.ts'],
|
|
setupFiles: SETUP_FILES,
|
|
},
|
|
},
|
|
],
|
|
coverage: {
|
|
provider: 'v8',
|
|
reporter: ['text', 'html', 'lcov', 'json-summary'],
|
|
thresholds: {
|
|
statements: 78,
|
|
lines: 80,
|
|
},
|
|
include: ['src/**/*.ts'],
|
|
exclude: [
|
|
'src/**/*.test.ts',
|
|
'src/**/__tests__/**',
|
|
'src/**/*-types.ts',
|
|
'src/**/types.ts',
|
|
'src/sdk/**',
|
|
'src/bin.ts',
|
|
'src/client/client-types.ts',
|
|
'src/core/interactor-types.ts',
|
|
'src/remote/remote-config.ts',
|
|
],
|
|
},
|
|
},
|
|
});
|