mirror of
https://github.com/civitai/civitai.git
synced 2026-09-20 22:08:18 +08:00
fix/test-cache-virtual-ids
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
75312960da |
fix(test-cache): stop three id shapes from making a test permanently uncacheable
A happy-dom test goes through the web transform, so a node builtin it imports
resolves to `__vite-browser-external:crypto` — an id no path can name. The key
fingerprinted it as a file, got `missing`, and the reporter read that as a module
deleted during the run. All 44 happy-dom test files in the repo were recorded on
no run and re-ran on every one. Vite virtual ids (a `\0` prefix, a plugin scheme)
fail the same way, so the rule is written for the shape, not the one spelling.
`src/hooks/useDateLocale.ts` imports `dayjs/locale/${tag}.js`, which the
computed-import rule treats as opaque — but whatever it computes resolves under
node_modules, which the lockfile already covers. Narrowed to a template whose
literal head is a bare specifier, excluding `@civitai/*` (a workspace symlink
into packages/), any head carrying a `:` (`node:${mod}` can be child_process)
and `./` or `~/`. That one file made another 44 test files uncacheable.
`toRel` also THREW on a POSIX `file://` id on Windows, where fileURLToPath raises
ERR_INVALID_FILE_URL_PATH. That is red on main today, in this file's own POSIX
invariant test, on every Windows run.
The e2e gains a happy-dom fixture so the control is end to end rather than a
predicate assertion: reverting the first fix fails it with
`expected { recorded: 1, notRecorded: { "imported module gone": 1 } } to deeply
equal { recorded: 2, notRecorded: {} }`.
Verified: full unit suite 1927 passed | 3 skipped (1930), exit 0, 0 false skips;
typecheck 0 errors; test:lint-rules 47 files, 660 tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
2df0241a4f |
feat(test-cache): skip unit test files unchanged since they last passed (#4971)
* feat(test-cache): shadow-record what a content-keyed result cache would skip Phase 1 of a test-result cache: nothing is skipped. A vitest reporter keys each test file on the content of every first-party module it depends on, plus the inputs no import records (lockfile, vitest config, tsconfig, node, platform), and records files that passed in full. A later run whose key matches is one the cache WOULD skip; if that file then fails, the key missed a dependency and the run is logged as a false skip. Dependencies come from vite's server-side ssr module graph, not diagnostic().importDurations: on a fixture, importDurations missed an `await import()` made inside a test body, and the ssr graph caught it cold and warm. The graph also leaves out the subtree behind a vi.mock factory, which never executes, while keeping the mocked module itself. The store lives in the COMMON git dir, shared by every worktree, and keys use repo-relative paths, so one tree's green run covers every tree whose files are identical. Files that read the filesystem, spawn processes, or import a non-literal specifier always run (243 of 1,880, 6.5% of modelled worker time). The queue gains a hot-configurable cache mode (`test config --cache shadow`, TEST_CACHE_MODE in the skill .env). In shadow mode a queued unit run gets the primary checkout's reporter appended, plus `--reporter=default` when the caller named none, so turning it on never strips a run's normal output. Fixture sequence, each step as predicted: cold 0 skipped; unchanged 1/1; runtime-imported dep changed 0; unchanged again 1/1; dep behind a mock changed still 1/1; env-driven failure with an unchanged key flagged as 1 false skip. 89-file yardstick, cold then warm: 89/89 passed both times, warm would skip 85/89 (98% of worker time), 0 false skips. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(test-cache): skip unit test files unchanged since they last passed Turns the shadow recorder into a real cache. Before a queued unit run, a custom sequencer re-fingerprints each test file's recorded dependencies and drops the files whose key still matches a recorded pass; vitest runs exactly the list the sequencer returns. Reusing the OLD dependency list is sound: gaining a dependency means editing a file already in the list, which changes the key. A key covers the test file, every first-party module it imports (from vite's module graph, in whichever environment loaded it, so happy-dom files count too), every file or directory it read at runtime (a setup-file fs tracker, directories fingerprinted by their whole subtree), and the lockfile, configs, node, platform, vitest and the cache's own code. Records are shared by every worktree through the common git dir, up to 8 per test file, so two trees on different code both stay fast. Still always run: files that spawn, glob, or import a computed specifier (19 files, 0.7% of modelled worker time). Known blind spot: environment variables are not in the key. A random ~5% of skippable files run anyway. If one fails, the cache predicted a pass it could not deliver; it writes TRIPPED.json and runs everything until a human removes it. Modes off|shadow|on are hot-configurable on the queue (`test config --cache on`); never on in CI, never applied to a named-files run. Measured, 89-file yardstick: cold 294s, warm 24s (85 skipped, 3 re-sampled, 0 false skips). Fixture scenarios: runtime-imported dep edited, fixture file edited, dependency of a happy-dom test edited each re-ran exactly the affected file; an env-driven failure was flagged as a false skip and tripped the cache. Fixes found by those checks: a fully cached run exited 1 ("no test files"); 44 happy-dom files were never cached; a builtin heuristic dropped top-level directories like `src` from the key. Full unit suite, cache off: Test Files 1 failed | 1904 passed | 3 skipped (1908); the one failure is rest-error-envelope-ledger, which fails identically on origin/main CI. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(test-cache): close three false-skip paths found by review Adversarial review of |