review(56): Darkwing round 2 packet, approve (#1545 comment 27123)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
1afe07062349b097b955f0391bffb839b083492d02644421def6c39cc19ff4a4 agents/rocko/work/queue-56/byte-check.sh
|
||||
09788e902a54207ef5f94de1c8b7f2f31c049fb028fa68847115da83060d90f9 agents/rocko/work/queue-56/delta-check.sh
|
||||
15d575cc45313906114f7edda9379b66af7624d9e894bb98812deb7acf5d87ba agents/rocko/work/queue-56/seed.sh
|
||||
146b236a37bf665979e28f1794c4c4437b6e85feb43b892e8d9d697506fc453f packages/runs/package.json
|
||||
895dd393a43221ffb12a5dc1b76ab61118b5562a5d7acbc50450ebb3ea6388d3 packages/runs/README.md
|
||||
f686212fa10e8541a1d8055fe30d65558a516245276aa53ecefd97bd7ca0a20c packages/runs/src/errors.mjs
|
||||
eb7063a8ee0417699b45f4bfec69c3ffcde8b3b276956ca4fea266ec0abd6b23 packages/runs/src/index.mjs
|
||||
3f9d025f0615a08edd440bb2aa6cea48f21cafa1f680332fffca3c7ee586cc65 packages/runs/src/paths.mjs
|
||||
ba64e50c3a63e693fc313278ff6cf440234649a6719dd9229bce20272a518ec1 packages/runs/src/runs.mjs
|
||||
ae546df81c6da7ef51680e23a12c01f08c5a6dc1b68cdf26c8d4210772149940 packages/runs/src/state.mjs
|
||||
7c941596020b14d8627ccb09b66e0e51195318e86add60eba9d2c4409e6f8dd6 packages/runs/tests/helpers.mjs
|
||||
fbaa092b5c8a1b54bc52c090da71f0da4313b4a8221fd7a2e89404a2a1b04633 packages/runs/tests/runs.test.mjs
|
||||
d0f33cb945cb5960847cd9e9af05f5a85731cb68bc5131efb084a7ecea81591f packages/runs/tests/state.test.mjs
|
||||
be5d1bdf95340e6c4a697531a225f08b40901ad1b570da7371efe7994e3e1413 packages/runs/tests/task-cli.test.mjs
|
||||
4873187609897c643e62acf7f1d074fa3c03369fe6702b9b0c7776138e776401 scripts/mosaic-task.mjs
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
# Row 56 gate: packages/runs node suite, then every scripts/test-*.sh with Docker unreachable.
|
||||
export TMPDIR=~/darkwing-scratch/r56b/tmp DOCKER_HOST=unix:///nonexistent.sock
|
||||
cd ~/darkwing-scratch/r56b/cand
|
||||
O=~/darkwing-scratch/r56b/out
|
||||
: > $O/summary.txt
|
||||
echo "start $(date -u +%FT%TZ)" >> $O/summary.txt
|
||||
env -u NODE_TEST_CONTEXT node --test packages/runs/tests/*.test.mjs > $O/node-runs.txt 2>&1; e=$?
|
||||
echo "node-runs exit=$e $(grep -E '^ℹ (pass|fail)' $O/node-runs.txt | tr '\n' ' ')" >> $O/summary.txt
|
||||
for f in scripts/test-*.sh; do
|
||||
s=$(basename $f .sh)
|
||||
$f > $O/$s.txt 2>&1; e=$?
|
||||
echo "$s exit=$e $(grep -E 'passed, [0-9]+ failed' $O/$s.txt | tail -1)" >> $O/summary.txt
|
||||
done
|
||||
echo "end $(date -u +%FT%TZ)" >> $O/summary.txt
|
||||
echo DONE >> $O/summary.txt
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/scripts/mosaic-task.mjs b/scripts/mosaic-task.mjs
|
||||
index cf8399a0..b5a9564e 100755
|
||||
--- a/scripts/mosaic-task.mjs
|
||||
+++ b/scripts/mosaic-task.mjs
|
||||
@@ -486,7 +486,7 @@ function listRuns() {
|
||||
}
|
||||
|
||||
function showRun(runId) {
|
||||
- if (!isRunId(runId)) {
|
||||
+ if (false) {
|
||||
fail(4, `invalid run id: ${JSON.stringify(runId)} (expected r-<id>)`);
|
||||
}
|
||||
const resolved = loadConfig();
|
||||
@@ -0,0 +1,73 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.187366ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.073148ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.667967ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.065405ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.710197ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.212073ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.794819ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.87404ms)
|
||||
✔ readRunDocument reads only the three run documents (0.73155ms)
|
||||
✔ a link inside the data root is followed (1.101065ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.92173ms)
|
||||
✔ a run directory linked out of the data root is never read (1.182722ms)
|
||||
✔ a document linked out of the data root reads as null (1.519156ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.971294ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.602539ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.602411ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.836417ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.588817ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.764263ms)
|
||||
✔ a link to the data root's parent is outside it (0.478523ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.303967ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (1.087459ms)
|
||||
✔ the readers write nothing (3.286472ms)
|
||||
✔ no pointer is null (2.356044ms)
|
||||
✔ the pointer release.sh writes reads back (1.496897ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.651413ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.669957ms)
|
||||
✔ a state file linked out of the data root refuses (2.02127ms)
|
||||
✔ a state directory linked out of the data root refuses (1.056491ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.702711ms)
|
||||
✔ a missing log is empty (1.296972ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.656559ms)
|
||||
✔ last must be a positive integer (0.721034ms)
|
||||
✔ the state readers write nothing (1.365288ms)
|
||||
✔ list prints each run in the established format (100.715833ms)
|
||||
✔ show prints the run in the established format (108.835407ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (180.126942ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (192.410504ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (163.544111ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (74.327067ms)
|
||||
✖ show refuses an invalid id before reading the config (172.108882ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1064.413393
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:104:1
|
||||
✖ show refuses an invalid id before reading the config (172.108882ms)
|
||||
AssertionError [ERR_ASSERTION]: mosaic-task: configuration problem (exit 3); run scripts/bootstrap.sh or fix config.json
|
||||
|
||||
|
||||
3 !== 4
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:109:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 3,
|
||||
expected: 4,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs
|
||||
index 1dbb5539..f7c5f4ea 100644
|
||||
--- a/packages/runs/src/paths.mjs
|
||||
+++ b/packages/runs/src/paths.mjs
|
||||
@@ -43,7 +43,8 @@ export function readJsonObject(dataRoot, ...parts) {
|
||||
if (file === null) return null;
|
||||
const value = JSON.parse(fs.readFileSync(file, "utf8"));
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
||||
- } catch {
|
||||
+ } catch (error) {
|
||||
+ if (error instanceof RunsError) throw error;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.400398ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.988221ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.707746ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.622032ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (1.758806ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.221436ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.088578ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.038079ms)
|
||||
✔ readRunDocument reads only the three run documents (0.884663ms)
|
||||
✔ a link inside the data root is followed (2.038475ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.134007ms)
|
||||
✖ a run directory linked out of the data root is never read (0.752745ms)
|
||||
✖ a document linked out of the data root reads as null (0.763986ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.653651ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.478299ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.531338ms)
|
||||
✖ a link loop refuses instead of reading as missing (0.601651ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.458441ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.547674ms)
|
||||
✔ a link to the data root's parent is outside it (0.51465ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.836887ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.736515ms)
|
||||
✔ the readers write nothing (2.225785ms)
|
||||
✔ no pointer is null (2.030231ms)
|
||||
✔ the pointer release.sh writes reads back (1.320527ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (135.180496ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.722154ms)
|
||||
✔ a state file linked out of the data root refuses (1.394205ms)
|
||||
✔ a state directory linked out of the data root refuses (0.524668ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.412215ms)
|
||||
✔ a missing log is empty (0.308456ms)
|
||||
✔ the log reads oldest first and counts malformed lines (0.862537ms)
|
||||
✔ last must be a positive integer (0.41004ms)
|
||||
✔ the state readers write nothing (0.697997ms)
|
||||
✔ list prints each run in the established format (102.363954ms)
|
||||
✔ show prints the run in the established format (99.691103ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (133.511964ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (188.487781ms)
|
||||
✖ show refuses a run linked out of the data root; list reports it unknown (167.45552ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (88.153586ms)
|
||||
✔ show refuses an invalid id before reading the config (62.195932ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 37
|
||||
ℹ fail 4
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 905.338616
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:119:1
|
||||
✖ a run directory linked out of the data root is never read (0.752745ms)
|
||||
Error [RunsError]: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-LFk8Oo/data/runs/r-20260101T000000Z-aaaaaa/result.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-LFk8Oo/data)
|
||||
at resolveInside (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:33:11)
|
||||
at readJsonObject (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:42:18)
|
||||
at file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:46:13
|
||||
at Array.map (<anonymous>)
|
||||
at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:44:31)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:125:20)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:129:1
|
||||
✖ a document linked out of the data root reads as null (0.763986ms)
|
||||
Error [RunsError]: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ge63ie/data/runs/r-20260101T000000Z-aaaaaa/result.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ge63ie/data)
|
||||
at resolveInside (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:33:11)
|
||||
at readJsonObject (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:42:18)
|
||||
at readRunDocument (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:37:10)
|
||||
at readRunRecord (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:67:13)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:136:18)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:168:1
|
||||
✖ a link loop refuses instead of reading as missing (0.601651ms)
|
||||
Error [RunsError]: cannot resolve /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-HLtM1w/data/runs/r-20260101T000000Z-aaaaaa/result.json: ELOOP
|
||||
at resolveInside (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:30:11)
|
||||
at readJsonObject (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:42:18)
|
||||
at file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:46:13
|
||||
at Array.map (<anonymous>)
|
||||
at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:44:31)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:174:20)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:82:1
|
||||
✖ show refuses a run linked out of the data root; list reports it unknown (167.45552ms)
|
||||
AssertionError [ERR_ASSERTION]: mosaic-task: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-QZ52Qw/data/runs/r-20260101T000000Z-aaaaaa/result.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-QZ52Qw/data)
|
||||
|
||||
|
||||
4 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:92:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 4,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs
|
||||
index 03730c33..5096f921 100644
|
||||
--- a/packages/runs/src/runs.mjs
|
||||
+++ b/packages/runs/src/runs.mjs
|
||||
@@ -52,7 +52,6 @@ export function listRunRecords(dataRoot) {
|
||||
export function readRunRecord(dataRoot, runId) {
|
||||
requireRunId(runId);
|
||||
// The runs directory first, so a refusal names the link that escapes.
|
||||
- if (resolveInside(dataRoot, RUNS_DIRNAME) === null) return null;
|
||||
const dir = resolveInside(dataRoot, RUNS_DIRNAME, runId);
|
||||
if (dir === null) return null;
|
||||
let artifacts;
|
||||
@@ -0,0 +1,103 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.065207ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.698841ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.630984ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.49914ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.076647ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.038104ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.613748ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.680147ms)
|
||||
✔ readRunDocument reads only the three run documents (0.554692ms)
|
||||
✔ a link inside the data root is followed (0.956197ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.633126ms)
|
||||
✔ a run directory linked out of the data root is never read (0.687083ms)
|
||||
✔ a document linked out of the data root reads as null (0.817475ms)
|
||||
✖ a runs directory linked out of the data root refuses (1.147289ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.420625ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.432331ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.580696ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.420343ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.505363ms)
|
||||
✔ a link to the data root's parent is outside it (0.365301ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.728115ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.572555ms)
|
||||
✔ the readers write nothing (2.015551ms)
|
||||
✔ no pointer is null (2.257117ms)
|
||||
✔ the pointer release.sh writes reads back (1.314201ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (132.331487ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.218663ms)
|
||||
✔ a state file linked out of the data root refuses (0.870713ms)
|
||||
✔ a state directory linked out of the data root refuses (0.504281ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.501277ms)
|
||||
✔ a missing log is empty (0.321384ms)
|
||||
✔ the log reads oldest first and counts malformed lines (0.866945ms)
|
||||
✔ last must be a positive integer (0.46119ms)
|
||||
✔ the state readers write nothing (0.714278ms)
|
||||
✔ list prints each run in the established format (77.057222ms)
|
||||
✔ show prints the run in the established format (65.031466ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (124.475617ms)
|
||||
✖ list and show refuse a runs directory linked out of the data root (170.366112ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (163.564218ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (76.840622ms)
|
||||
✔ show refuses an invalid id before reading the config (49.249577ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 39
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 801.494548
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:143:1
|
||||
✖ a runs directory linked out of the data root refuses (1.147289ms)
|
||||
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /runs resolves outside the data root/. Input:
|
||||
|
||||
'RunsError: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ZzTrSZ/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ZzTrSZ/data)'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:149:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: RunsError: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ZzTrSZ/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ZzTrSZ/data)
|
||||
at resolveInside (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:33:11)
|
||||
at readRunRecord (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:55:15)
|
||||
at file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:149:23
|
||||
at getActual (node:assert:580:5)
|
||||
at strict.throws (node:assert:728:24)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:149:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19),
|
||||
expected: /runs resolves outside the data root/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:70:1
|
||||
✖ list and show refuse a runs directory linked out of the data root (170.366112ms)
|
||||
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /^mosaic-task: .*runs resolves outside the data root/. Input:
|
||||
|
||||
'mosaic-task: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-p4YqkE/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-p4YqkE/data)\n'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:78:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 'mosaic-task: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-p4YqkE/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-p4YqkE/data)\n',
|
||||
expected: /^mosaic-task: .*runs resolves outside the data root/,
|
||||
operator: 'match',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..3c78f1a3 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -79,5 +79,5 @@ export function readActivationLog(dataRoot, { last } = {}) {
|
||||
if (entry === null) malformed += 1;
|
||||
else entries.push(entry);
|
||||
}
|
||||
- return { entries: last === undefined ? entries : entries.slice(-last), malformed };
|
||||
+ return { entries: last === undefined ? entries : entries.slice(0, last), malformed };
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.07446ms)
|
||||
✔ a missing data root or runs directory lists nothing (9.100856ms)
|
||||
✔ runs as a regular file lists nothing, as before (5.813261ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (17.34251ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (1.86616ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (26.002078ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (3.693151ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.008653ms)
|
||||
✔ readRunDocument reads only the three run documents (0.813628ms)
|
||||
✔ a link inside the data root is followed (1.508103ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.817532ms)
|
||||
✔ a run directory linked out of the data root is never read (1.130005ms)
|
||||
✔ a document linked out of the data root reads as null (22.199116ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.18345ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.698018ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.773861ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.009039ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.659472ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.692031ms)
|
||||
✔ a link to the data root's parent is outside it (0.58212ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.167948ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.76835ms)
|
||||
✔ the readers write nothing (3.410202ms)
|
||||
✔ no pointer is null (5.069465ms)
|
||||
✔ the pointer release.sh writes reads back (6.698682ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (48.474502ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.375452ms)
|
||||
✔ a state file linked out of the data root refuses (0.982791ms)
|
||||
✔ a state directory linked out of the data root refuses (0.595852ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.475898ms)
|
||||
✔ a missing log is empty (1.243422ms)
|
||||
✖ the log reads oldest first and counts malformed lines (2.965998ms)
|
||||
✔ last must be a positive integer (0.75225ms)
|
||||
✔ the state readers write nothing (1.350016ms)
|
||||
✔ list prints each run in the established format (78.922855ms)
|
||||
✔ show prints the run in the established format (95.821873ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (127.675112ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (177.883313ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (197.934639ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (99.346507ms)
|
||||
✔ show refuses an invalid id before reading the config (67.610285ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 908.204283
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:87:1
|
||||
✖ the log reads oldest first and counts malformed lines (2.965998ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
+ at: '2026-09-03T20:57:00Z',
|
||||
+ event: 'package',
|
||||
+ imageTag: 'mosaic-poc-agent:0.84.4-r0.0.12',
|
||||
+ release: '0.0.12'
|
||||
- at: '2026-09-03T20:57:50Z',
|
||||
- event: 'refused',
|
||||
- imageTag: 'mosaic-poc-agent:0.84.4-r0.0.11',
|
||||
- note: 'health check failed (fault-injected)',
|
||||
- release: '0.0.11'
|
||||
},
|
||||
{
|
||||
+ at: '2026-09-03T20:57:47Z',
|
||||
+ event: 'activate',
|
||||
+ imageTag: 'mosaic-poc-agent:0.84.4-r0.0.12',
|
||||
+ release: '0.0.12'
|
||||
- at: '2026-09-03T20:58:15Z',
|
||||
- event: 'rollback',
|
||||
- imageTag: 'mosaic-poc-agent:0.84.4-r0.0.11',
|
||||
- release: '0.0.11'
|
||||
}
|
||||
],
|
||||
malformed: 7
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:111:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { entries: [ [Object], [Object] ], malformed: 7 },
|
||||
expected: { entries: [ [Object], [Object] ], malformed: 7 },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..73c4093f 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -56,7 +56,6 @@ function logEntry(line) {
|
||||
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return null;
|
||||
if (Object.keys(entry).some((key) => !LOG_KEYS.includes(key))) return null;
|
||||
if (!["at", "event", "release", "imageTag"].every((key) => typeof entry[key] === "string")) return null;
|
||||
- if (entry.note !== undefined && typeof entry.note !== "string") return null;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.868216ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.86021ms)
|
||||
✔ runs as a regular file lists nothing, as before (8.40054ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.308516ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (12.488337ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (2.16147ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.338434ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.147922ms)
|
||||
✔ readRunDocument reads only the three run documents (0.986952ms)
|
||||
✔ a link inside the data root is followed (1.887611ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.157689ms)
|
||||
✔ a run directory linked out of the data root is never read (1.147918ms)
|
||||
✔ a document linked out of the data root reads as null (1.04803ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.885659ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.747769ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.85256ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.911623ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.49244ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.674212ms)
|
||||
✔ a link to the data root's parent is outside it (0.66393ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.041093ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.720282ms)
|
||||
✔ the readers write nothing (2.783068ms)
|
||||
✔ no pointer is null (3.212571ms)
|
||||
✔ the pointer release.sh writes reads back (8.322256ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (20.560714ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.915186ms)
|
||||
✔ a state file linked out of the data root refuses (3.438269ms)
|
||||
✔ a state directory linked out of the data root refuses (0.97389ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.862097ms)
|
||||
✔ a missing log is empty (0.580293ms)
|
||||
✖ the log reads oldest first and counts malformed lines (3.096371ms)
|
||||
✔ last must be a positive integer (0.860788ms)
|
||||
✔ the state readers write nothing (1.568966ms)
|
||||
✔ list prints each run in the established format (103.556364ms)
|
||||
✔ show prints the run in the established format (99.367753ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (132.794709ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (165.176683ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (179.243689ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (97.090709ms)
|
||||
✔ show refuses an invalid id before reading the config (45.621371ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 892.03822
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:87:1
|
||||
✖ the log reads oldest first and counts malformed lines (3.096371ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
... Skipped lines
|
||||
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
at: '2026-09-03T20:57:00Z',
|
||||
event: 'package',
|
||||
...
|
||||
{
|
||||
+ at: '2026-09-03T20:57:47Z',
|
||||
+ event: 'activate',
|
||||
+ imageTag: 'mosaic-poc-agent:0.84.4-r0.0.12',
|
||||
+ note: null,
|
||||
+ release: '0.0.12'
|
||||
+ },
|
||||
+ {
|
||||
at: '2026-09-03T20:57:50Z',
|
||||
event: 'refused',
|
||||
imageTag: 'mosaic-poc-agent:0.84.4-r0.0.11',
|
||||
note: 'health check failed (fault-injected)',
|
||||
release: '0.0.11'
|
||||
...
|
||||
],
|
||||
+ malformed: 6
|
||||
- malformed: 7
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:110:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { entries: [ [Object], [Object], [Object], [Object], [Object] ], malformed: 6 },
|
||||
expected: { entries: [ [Object], [Object], [Object], [Object] ], malformed: 7 },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs
|
||||
index 03730c33..e02fea8e 100644
|
||||
--- a/packages/runs/src/runs.mjs
|
||||
+++ b/packages/runs/src/runs.mjs
|
||||
@@ -23,7 +23,7 @@ export function listRunIds(dataRoot) {
|
||||
try {
|
||||
names = fs.readdirSync(root);
|
||||
} catch (error) {
|
||||
- if (isMissing(error)) return [];
|
||||
+ return [];
|
||||
throw new RunsError(`cannot read ${root}: ${error.code ?? error.message}`);
|
||||
}
|
||||
return names.filter((name) => name.startsWith("r-")).sort();
|
||||
@@ -0,0 +1,68 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.15727ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.956821ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.653312ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.813695ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.027323ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.453954ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.14821ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.817061ms)
|
||||
✔ readRunDocument reads only the three run documents (0.720775ms)
|
||||
✔ a link inside the data root is followed (1.127818ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.797552ms)
|
||||
✔ a run directory linked out of the data root is never read (0.790744ms)
|
||||
✔ a document linked out of the data root reads as null (1.158428ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.708719ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.456699ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.530538ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.815137ms)
|
||||
✖ an unreadable runs directory refuses instead of listing nothing (1.594931ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.811632ms)
|
||||
✔ a link to the data root's parent is outside it (0.524666ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.997613ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.610554ms)
|
||||
✔ the readers write nothing (3.04337ms)
|
||||
✔ no pointer is null (2.483326ms)
|
||||
✔ the pointer release.sh writes reads back (1.671155ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.225357ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.654324ms)
|
||||
✔ a state file linked out of the data root refuses (2.682094ms)
|
||||
✔ a state directory linked out of the data root refuses (0.672495ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.52315ms)
|
||||
✔ a missing log is empty (0.407223ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.064471ms)
|
||||
✔ last must be a positive integer (0.626993ms)
|
||||
✔ the state readers write nothing (1.360837ms)
|
||||
✔ list prints each run in the established format (93.09785ms)
|
||||
✔ show prints the run in the established format (76.906223ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (134.282509ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (173.332729ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (176.342642ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (102.946334ms)
|
||||
✔ show refuses an invalid id before reading the config (57.272253ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 877.786601
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:177:1
|
||||
✖ an unreadable runs directory refuses instead of listing nothing (1.594931ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:183:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..ea5b6e96 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -18,6 +18,7 @@ function readStateFile(dataRoot, name) {
|
||||
try {
|
||||
return { file, text: fs.readFileSync(file, "utf8") };
|
||||
} catch (error) {
|
||||
+ return null;
|
||||
throw new RunsError(`cannot read ${file}: ${error.code ?? error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.695864ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.111524ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.687688ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.876875ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.457534ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.739748ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.186074ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.159887ms)
|
||||
✔ readRunDocument reads only the three run documents (1.675916ms)
|
||||
✔ a link inside the data root is followed (1.744427ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.031912ms)
|
||||
✔ a run directory linked out of the data root is never read (1.011737ms)
|
||||
✔ a document linked out of the data root reads as null (1.210562ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.875407ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.538894ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.616345ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.019959ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.963002ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.667147ms)
|
||||
✔ a link to the data root's parent is outside it (0.500073ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.863784ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.689777ms)
|
||||
✔ the readers write nothing (2.395707ms)
|
||||
✔ no pointer is null (1.987192ms)
|
||||
✔ the pointer release.sh writes reads back (1.500792ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (4.484566ms)
|
||||
✖ a pointer that is a directory refuses with exit 4 (1.455589ms)
|
||||
✔ a state file linked out of the data root refuses (1.342733ms)
|
||||
✔ a state directory linked out of the data root refuses (0.904937ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.979319ms)
|
||||
✔ a missing log is empty (0.601833ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.626737ms)
|
||||
✔ last must be a positive integer (0.825438ms)
|
||||
✔ the state readers write nothing (0.984388ms)
|
||||
✔ list prints each run in the established format (103.938354ms)
|
||||
✔ show prints the run in the established format (99.605055ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (141.552513ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (263.632285ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (241.004316ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (92.044439ms)
|
||||
✔ show refuses an invalid id before reading the config (48.767538ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1064.094476
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:51:1
|
||||
✖ a pointer that is a directory refuses with exit 4 (1.455589ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:54:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..a73160bf 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -37,7 +37,7 @@ export function readActivePointer(dataRoot) {
|
||||
const invalid = (why) => new RunsError(`release pointer ${why} (${state.file})`, 2);
|
||||
if (typeof pointer !== "object" || pointer === null || Array.isArray(pointer)) throw invalid("must be a JSON object");
|
||||
for (const key of Object.keys(pointer)) {
|
||||
- if (!POINTER_KEYS.includes(key)) throw invalid(`has an unsupported key: "${key}"`);
|
||||
+ if (false) throw invalid(`has an unsupported key: "${key}"`);
|
||||
}
|
||||
if (pointer.pointerVersion !== 1) throw invalid(`has unsupported pointerVersion ${JSON.stringify(pointer.pointerVersion)}`);
|
||||
for (const key of ["release", "imageTag", "activatedAt"]) {
|
||||
@@ -0,0 +1,68 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (2.597935ms)
|
||||
✔ a missing data root or runs directory lists nothing (7.197028ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.660483ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.967792ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.465777ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.16948ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.822948ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.725039ms)
|
||||
✔ readRunDocument reads only the three run documents (0.682165ms)
|
||||
✔ a link inside the data root is followed (1.147589ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.764645ms)
|
||||
✔ a run directory linked out of the data root is never read (0.777721ms)
|
||||
✔ a document linked out of the data root reads as null (0.934673ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.660635ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.494374ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.543282ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.711437ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.727803ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.685592ms)
|
||||
✔ a link to the data root's parent is outside it (0.407671ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (4.167937ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.916379ms)
|
||||
✔ the readers write nothing (3.641306ms)
|
||||
✔ no pointer is null (5.346721ms)
|
||||
✔ the pointer release.sh writes reads back (1.585894ms)
|
||||
✖ a pointer that isn't the version 1 shape refuses with exit 2 (28.811661ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.063525ms)
|
||||
✔ a state file linked out of the data root refuses (1.952364ms)
|
||||
✔ a state directory linked out of the data root refuses (0.628002ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.543924ms)
|
||||
✔ a missing log is empty (3.99435ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.194387ms)
|
||||
✔ last must be a positive integer (0.54103ms)
|
||||
✔ the state readers write nothing (1.220604ms)
|
||||
✔ list prints each run in the established format (94.412961ms)
|
||||
✔ show prints the run in the established format (121.913576ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (161.486907ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (220.557107ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (192.17414ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (106.896964ms)
|
||||
✔ show refuses an invalid id before reading the config (58.262537ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1040.073192
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:32:1
|
||||
✖ a pointer that isn't the version 1 shape refuses with exit 2 (28.811661ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception: /unsupported key: "extra"/
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:47:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs
|
||||
index 1dbb5539..fe56cb9b 100644
|
||||
--- a/packages/runs/src/paths.mjs
|
||||
+++ b/packages/runs/src/paths.mjs
|
||||
@@ -11,7 +11,7 @@ export function isMissing(error) {
|
||||
|
||||
function isInside(root, target) {
|
||||
const relative = path.relative(root, target);
|
||||
- return relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
||||
+ return false || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
||||
}
|
||||
|
||||
// Resolves <dataRoot>/<parts...> through any symbolic links and returns the
|
||||
@@ -0,0 +1,49 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.6626ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.557802ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.993455ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (2.10845ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.526378ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.74364ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (3.435233ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.009532ms)
|
||||
✔ readRunDocument reads only the three run documents (0.836393ms)
|
||||
✔ a link inside the data root is followed (1.471449ms)
|
||||
✔ a data root that is itself a link is trusted as configured (4.897625ms)
|
||||
✔ a run directory linked out of the data root is never read (1.428292ms)
|
||||
✔ a document linked out of the data root reads as null (1.498822ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.935108ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.709396ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.882846ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.058619ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (2.11653ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.930758ms)
|
||||
✔ a link to the data root's parent is outside it (1.598177ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.288405ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.870374ms)
|
||||
✔ the readers write nothing (3.744027ms)
|
||||
✔ no pointer is null (2.085388ms)
|
||||
✔ the pointer release.sh writes reads back (5.493014ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (15.128508ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (5.23987ms)
|
||||
✔ a state file linked out of the data root refuses (1.810665ms)
|
||||
✔ a state directory linked out of the data root refuses (0.998991ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.803279ms)
|
||||
✔ a missing log is empty (0.565342ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.636209ms)
|
||||
✔ last must be a positive integer (0.735553ms)
|
||||
✔ the state readers write nothing (2.258054ms)
|
||||
✔ list prints each run in the established format (116.9074ms)
|
||||
✔ show prints the run in the established format (92.239762ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (138.161653ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (180.575601ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (155.863719ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (66.034048ms)
|
||||
✔ show refuses an invalid id before reading the config (45.978715ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 873.417164
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/scripts/mosaic-task.mjs b/scripts/mosaic-task.mjs
|
||||
index cf8399a0..7c4bfb80 100755
|
||||
--- a/scripts/mosaic-task.mjs
|
||||
+++ b/scripts/mosaic-task.mjs
|
||||
@@ -462,7 +462,7 @@ function readRuns(read) {
|
||||
try {
|
||||
return read();
|
||||
} catch (error) {
|
||||
- if (error instanceof RunsError) fail(error.exitCode, error.message);
|
||||
+ if (false) fail(error.exitCode, error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.160098ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.712897ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.650182ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.113564ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.406922ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.572189ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.777226ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.754688ms)
|
||||
✔ readRunDocument reads only the three run documents (0.682826ms)
|
||||
✔ a link inside the data root is followed (1.118588ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.860124ms)
|
||||
✔ a run directory linked out of the data root is never read (1.212714ms)
|
||||
✔ a document linked out of the data root reads as null (1.539772ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.792065ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.634973ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.819447ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.025891ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.73579ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.654308ms)
|
||||
✔ a link to the data root's parent is outside it (0.431647ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.90279ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.544152ms)
|
||||
✔ the readers write nothing (2.666725ms)
|
||||
✔ no pointer is null (1.95949ms)
|
||||
✔ the pointer release.sh writes reads back (1.316236ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (1.881776ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.406961ms)
|
||||
✔ a state file linked out of the data root refuses (1.07326ms)
|
||||
✔ a state directory linked out of the data root refuses (0.649188ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.583015ms)
|
||||
✔ a missing log is empty (0.436768ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.10825ms)
|
||||
✔ last must be a positive integer (0.518269ms)
|
||||
✔ the state readers write nothing (0.908431ms)
|
||||
✔ list prints each run in the established format (88.182372ms)
|
||||
✔ show prints the run in the established format (90.40074ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (163.139175ms)
|
||||
✖ list and show refuse a runs directory linked out of the data root (86.669533ms)
|
||||
✖ show refuses a run linked out of the data root; list reports it unknown (87.589376ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (78.640786ms)
|
||||
✔ show refuses an invalid id before reading the config (41.75937ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 39
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 697.746994
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:70:1
|
||||
✖ list and show refuse a runs directory linked out of the data root (86.669533ms)
|
||||
AssertionError [ERR_ASSERTION]: list
|
||||
|
||||
1 !== 4
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:76:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 1,
|
||||
expected: 4,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:82:1
|
||||
✖ show refuses a run linked out of the data root; list reports it unknown (87.589376ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
1 !== 4
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:88:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 1,
|
||||
expected: 4,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs
|
||||
index 03730c33..943dadfa 100644
|
||||
--- a/packages/runs/src/runs.mjs
|
||||
+++ b/packages/runs/src/runs.mjs
|
||||
@@ -59,7 +59,6 @@ export function readRunRecord(dataRoot, runId) {
|
||||
try {
|
||||
artifacts = fs.readdirSync(dir);
|
||||
} catch (error) {
|
||||
- if (isMissing(error)) return null;
|
||||
throw new RunsError(`cannot read ${dir}: ${error.code ?? error.message}`);
|
||||
}
|
||||
return {
|
||||
@@ -0,0 +1,65 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.019792ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.537162ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.626401ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.70396ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (1.605381ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (0.978894ms)
|
||||
✖ readRunRecord is null for a missing run, a dangling link or a file (0.782736ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.618964ms)
|
||||
✔ readRunDocument reads only the three run documents (0.639582ms)
|
||||
✔ a link inside the data root is followed (0.953467ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.675656ms)
|
||||
✔ a run directory linked out of the data root is never read (0.689555ms)
|
||||
✔ a document linked out of the data root reads as null (0.894036ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.600981ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.422303ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.542892ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.66723ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.512036ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.626632ms)
|
||||
✔ a link to the data root's parent is outside it (0.403352ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.81109ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.63346ms)
|
||||
✔ the readers write nothing (2.24943ms)
|
||||
✔ no pointer is null (1.762831ms)
|
||||
✔ the pointer release.sh writes reads back (1.161502ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (1.684703ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.066646ms)
|
||||
✔ a state file linked out of the data root refuses (0.95879ms)
|
||||
✔ a state directory linked out of the data root refuses (0.598971ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.443066ms)
|
||||
✔ a missing log is empty (0.346331ms)
|
||||
✔ the log reads oldest first and counts malformed lines (0.900263ms)
|
||||
✔ last must be a positive integer (0.433079ms)
|
||||
✔ the state readers write nothing (0.791434ms)
|
||||
✔ list prints each run in the established format (78.266364ms)
|
||||
✔ show prints the run in the established format (69.618235ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (112.18599ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (147.542974ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (133.430679ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (76.660284ms)
|
||||
✔ show refuses an invalid id before reading the config (45.844203ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 718.130278
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:75:1
|
||||
✖ readRunRecord is null for a missing run, a dangling link or a file (0.782736ms)
|
||||
Error [RunsError]: cannot read /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-b3hgCt/data/runs/r-20260101T000100Z-bbbbbb: ENOTDIR
|
||||
at readRunRecord (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:62:11)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:83:16)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
exitCode: 4
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs
|
||||
index 1dbb5539..7ce9d52c 100644
|
||||
--- a/packages/runs/src/paths.mjs
|
||||
+++ b/packages/runs/src/paths.mjs
|
||||
@@ -24,7 +24,7 @@ export function resolveInside(dataRoot, ...parts) {
|
||||
let real;
|
||||
try {
|
||||
root = fs.realpathSync(dataRoot);
|
||||
- real = fs.realpathSync(target);
|
||||
+ real = path.resolve(target);
|
||||
} catch (error) {
|
||||
if (isMissing(error)) return null;
|
||||
throw new RunsError(`cannot resolve ${target}: ${error.code ?? error.message}`);
|
||||
@@ -0,0 +1,353 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.054784ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.652336ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.551128ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.225706ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (1.355194ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (0.964287ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.660858ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.691905ms)
|
||||
✔ readRunDocument reads only the three run documents (0.56909ms)
|
||||
✔ a link inside the data root is followed (0.880389ms)
|
||||
✖ a data root that is itself a link is trusted as configured (0.699319ms)
|
||||
✖ a run directory linked out of the data root is never read (1.673175ms)
|
||||
✖ a document linked out of the data root reads as null (0.958721ms)
|
||||
✖ a runs directory linked out of the data root refuses (0.510659ms)
|
||||
✖ a relative link that climbs out of the data root refuses (0.603903ms)
|
||||
✖ a sibling whose name starts with the data root's name is outside it (0.702796ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.614909ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.453137ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.602137ms)
|
||||
✖ a link to the data root's parent is outside it (0.550265ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.752446ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.486875ms)
|
||||
✔ the readers write nothing (2.072302ms)
|
||||
✖ no pointer is null (1.751412ms)
|
||||
✔ the pointer release.sh writes reads back (1.046095ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (1.648482ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.585862ms)
|
||||
✖ a state file linked out of the data root refuses (1.759557ms)
|
||||
✖ a state directory linked out of the data root refuses (0.604972ms)
|
||||
✖ a state directory linked out to nothing reads as no release and an empty log (0.425196ms)
|
||||
✖ a missing log is empty (0.475951ms)
|
||||
✔ the log reads oldest first and counts malformed lines (0.961794ms)
|
||||
✔ last must be a positive integer (0.506807ms)
|
||||
✔ the state readers write nothing (0.83569ms)
|
||||
✔ list prints each run in the established format (82.854009ms)
|
||||
✔ show prints the run in the established format (77.561091ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (119.793186ms)
|
||||
✖ list and show refuse a runs directory linked out of the data root (92.256203ms)
|
||||
✖ show refuses a run linked out of the data root; list reports it unknown (80.040594ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (72.307362ms)
|
||||
✔ show refuses an invalid id before reading the config (47.222817ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 14
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 641.071641
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:111:1
|
||||
✖ a data root that is itself a link is trusted as configured (0.699319ms)
|
||||
Error [RunsError]: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-J1fCqk/alias/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-J1fCqk/data)
|
||||
at resolveInside (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:33:11)
|
||||
at listRunIds (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:20:16)
|
||||
at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:44:10)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:116:20)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:119:1
|
||||
✖ a run directory linked out of the data root is never read (1.673175ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
{
|
||||
+ result: {
|
||||
+ durationMs: 1000,
|
||||
+ exitCode: 0,
|
||||
+ expectedExact: null,
|
||||
+ finishedAt: '2026-01-01T00:00:01.000Z',
|
||||
+ missionId: null,
|
||||
+ model: 'm',
|
||||
+ provider: 'zai',
|
||||
+ reason: null,
|
||||
+ request: 'hi',
|
||||
+ response: 'hi',
|
||||
+ runId: 'r-20260101T000000Z-aaaaaa',
|
||||
+ runVersion: 1,
|
||||
+ session: null,
|
||||
+ sessionForkFrom: null,
|
||||
+ signal: null,
|
||||
+ startedAt: '2026-01-01T00:00:00.000Z',
|
||||
+ status: 'succeeded',
|
||||
+ taskId: 't-one',
|
||||
+ tools: null,
|
||||
+ workspace: null
|
||||
+ },
|
||||
- result: null,
|
||||
runId: 'r-20260101T000000Z-aaaaaa'
|
||||
}
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:125:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ { runId: 'r-20260101T000000Z-aaaaaa', result: [Object] } ],
|
||||
expected: [ { runId: 'r-20260101T000000Z-aaaaaa', result: null } ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:129:1
|
||||
✖ a document linked out of the data root reads as null (0.958721ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
+ {
|
||||
+ durationMs: 1000,
|
||||
+ exitCode: 0,
|
||||
+ expectedExact: null,
|
||||
+ finishedAt: '2026-01-01T00:00:01.000Z',
|
||||
+ missionId: null,
|
||||
+ model: 'm',
|
||||
+ provider: 'zai',
|
||||
+ reason: null,
|
||||
+ request: 'hi',
|
||||
+ response: 'hi',
|
||||
+ runId: 'r-20260101T000000Z-aaaaaa',
|
||||
+ runVersion: 1,
|
||||
+ session: null,
|
||||
+ sessionForkFrom: null,
|
||||
+ signal: null,
|
||||
+ startedAt: '2026-01-01T00:00:00.000Z',
|
||||
+ status: 'succeeded',
|
||||
+ taskId: 't-one',
|
||||
+ tools: null,
|
||||
+ workspace: null
|
||||
+ }
|
||||
- null
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:137:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { runVersion: 1, runId: 'r-20260101T000000Z-aaaaaa', taskId: 't-one', missionId: null, status: 'succeeded', reason: null, request: 'hi', response: 'hi', expectedExact: null, workspace: null, tools: null, session: null, sessionForkFrom: null, exitCode: 0, signal: null, provider: 'zai', model: 'm', startedAt: '2026-01-01T00:00:00.000Z', finishedAt: '2026-01-01T00:00:01.000Z', durationMs: 1000 },
|
||||
expected: null,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:143:1
|
||||
✖ a runs directory linked out of the data root refuses (0.510659ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:147:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: /runs resolves outside the data root/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:152:1
|
||||
✖ a relative link that climbs out of the data root refuses (0.603903ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:156:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: /resolves outside the data root/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:159:1
|
||||
✖ a sibling whose name starts with the data root's name is outside it (0.702796ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:165:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: /resolves outside the data root/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:201:1
|
||||
✖ a link to the data root's parent is outside it (0.550265ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:205:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: /resolves outside the data root/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:18:1
|
||||
✖ no pointer is null (1.751412ms)
|
||||
Error [RunsError]: cannot read /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-Hvm8Hi/data/state/active.json: ENOENT
|
||||
at readStateFile (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/state.mjs:21:11)
|
||||
at readActivePointer (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/state.mjs:29:17)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:20:16)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.start (node:internal/test_runner/test:1262:17)
|
||||
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:57:1
|
||||
✖ a state file linked out of the data root refuses (1.759557ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:64:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: /resolves outside the data root/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:68:1
|
||||
✖ a state directory linked out of the data root refuses (0.604972ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception.
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:72:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: /state\/active.json resolves outside the data root/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:75:1
|
||||
✖ a state directory linked out to nothing reads as no release and an empty log (0.425196ms)
|
||||
Error [RunsError]: cannot read /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-SAMKL6/data/state/active.json: ENOENT
|
||||
at readStateFile (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/state.mjs:21:11)
|
||||
at readActivePointer (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/state.mjs:29:17)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:78:16)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:82:1
|
||||
✖ a missing log is empty (0.475951ms)
|
||||
Error [RunsError]: cannot read /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-YDcaud/data/state/activation-log.jsonl: ENOENT
|
||||
at readStateFile (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/state.mjs:21:11)
|
||||
at readActivationLog (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/state.mjs:72:17)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:84:20)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:70:1
|
||||
✖ list and show refuse a runs directory linked out of the data root (92.256203ms)
|
||||
AssertionError [ERR_ASSERTION]: list
|
||||
|
||||
0 !== 4
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:76:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 0,
|
||||
expected: 4,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:82:1
|
||||
✖ show refuses a run linked out of the data root; list reports it unknown (80.040594ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
0 !== 4
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:88:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 0,
|
||||
expected: 4,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs
|
||||
index 1dbb5539..2cbffca6 100644
|
||||
--- a/packages/runs/src/paths.mjs
|
||||
+++ b/packages/runs/src/paths.mjs
|
||||
@@ -23,7 +23,7 @@ export function resolveInside(dataRoot, ...parts) {
|
||||
let root;
|
||||
let real;
|
||||
try {
|
||||
- root = fs.realpathSync(dataRoot);
|
||||
+ root = path.resolve(dataRoot);
|
||||
real = fs.realpathSync(target);
|
||||
} catch (error) {
|
||||
if (isMissing(error)) return null;
|
||||
@@ -0,0 +1,67 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (0.997986ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.607466ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.66625ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (2.247012ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.325328ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.518989ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.91467ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.688117ms)
|
||||
✔ readRunDocument reads only the three run documents (0.679207ms)
|
||||
✔ a link inside the data root is followed (1.094892ms)
|
||||
✖ a data root that is itself a link is trusted as configured (0.717025ms)
|
||||
✔ a run directory linked out of the data root is never read (0.971395ms)
|
||||
✔ a document linked out of the data root reads as null (1.253566ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.793626ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.713461ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.825603ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.703219ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.451785ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.578206ms)
|
||||
✔ a link to the data root's parent is outside it (0.386068ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.739358ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.531107ms)
|
||||
✔ the readers write nothing (1.843235ms)
|
||||
✔ no pointer is null (1.972129ms)
|
||||
✔ the pointer release.sh writes reads back (1.24273ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (1.770283ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.565257ms)
|
||||
✔ a state file linked out of the data root refuses (1.498773ms)
|
||||
✔ a state directory linked out of the data root refuses (0.660361ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.59035ms)
|
||||
✔ a missing log is empty (0.482079ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.084198ms)
|
||||
✔ last must be a positive integer (0.634979ms)
|
||||
✔ the state readers write nothing (0.860207ms)
|
||||
✔ list prints each run in the established format (87.530195ms)
|
||||
✔ show prints the run in the established format (78.052145ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (114.872261ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (200.792804ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (194.493903ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (129.049237ms)
|
||||
✔ show refuses an invalid id before reading the config (48.628287ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 914.584975
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:111:1
|
||||
✖ a data root that is itself a link is trusted as configured (0.717025ms)
|
||||
Error [RunsError]: /home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ZbqJkI/alias/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/tmp/mosaic-runs-test-ZbqJkI/alias)
|
||||
at resolveInside (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/paths.mjs:33:11)
|
||||
at listRunIds (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:20:16)
|
||||
at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:44:10)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:116:20)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
exitCode: 4
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs
|
||||
index 03730c33..08a71fab 100644
|
||||
--- a/packages/runs/src/runs.mjs
|
||||
+++ b/packages/runs/src/runs.mjs
|
||||
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
||||
import { RunsError } from "./errors.mjs";
|
||||
import { RUNS_DIRNAME, isMissing, readJsonObject, resolveInside } from "./paths.mjs";
|
||||
|
||||
-export const RUN_ID_PATTERN = /^r-[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
||||
+export const RUN_ID_PATTERN = /^r-[A-Za-z0-9][A-Za-z0-9._-]{0,64}$/;
|
||||
export const RUN_DOCUMENTS = ["result.json", "task.json", "mission.json"];
|
||||
|
||||
export function isRunId(value) {
|
||||
@@ -0,0 +1,70 @@
|
||||
✖ isRunId accepts the run id shape and nothing else (2.210226ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.603108ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.935946ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.163969ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.413922ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.371064ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.118632ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.780695ms)
|
||||
✔ readRunDocument reads only the three run documents (0.621037ms)
|
||||
✔ a link inside the data root is followed (1.177301ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.764799ms)
|
||||
✔ a run directory linked out of the data root is never read (0.722632ms)
|
||||
✔ a document linked out of the data root reads as null (0.995435ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.710336ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.470174ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.553622ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.050635ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.578181ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.593413ms)
|
||||
✔ a link to the data root's parent is outside it (0.486943ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.94863ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.588248ms)
|
||||
✔ the readers write nothing (5.231385ms)
|
||||
✔ no pointer is null (2.354597ms)
|
||||
✔ the pointer release.sh writes reads back (1.773315ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.415432ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.450113ms)
|
||||
✔ a state file linked out of the data root refuses (1.244576ms)
|
||||
✔ a state directory linked out of the data root refuses (0.652045ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.621644ms)
|
||||
✔ a missing log is empty (0.549717ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.224628ms)
|
||||
✔ last must be a positive integer (0.607716ms)
|
||||
✔ the state readers write nothing (1.009192ms)
|
||||
✔ list prints each run in the established format (89.320943ms)
|
||||
✔ show prints the run in the established format (94.517441ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (144.124028ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (170.44307ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (157.310275ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (89.274742ms)
|
||||
✔ show refuses an invalid id before reading the config (45.834389ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 861.630104
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:13:1
|
||||
✖ isRunId accepts the run id shape and nothing else (2.210226ms)
|
||||
AssertionError [ERR_ASSERTION]: r-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
|
||||
true !== false
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:16:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.start (node:internal/test_runner/test:1262:17)
|
||||
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: true,
|
||||
expected: false,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs
|
||||
index 03730c33..db7d57c1 100644
|
||||
--- a/packages/runs/src/runs.mjs
|
||||
+++ b/packages/runs/src/runs.mjs
|
||||
@@ -43,7 +43,7 @@ export function readRunDocument(dataRoot, runId, name) {
|
||||
export function listRunRecords(dataRoot) {
|
||||
return listRunIds(dataRoot).map((runId) => ({
|
||||
runId,
|
||||
- result: readJsonObject(dataRoot, RUNS_DIRNAME, runId, "result.json"),
|
||||
+ result: readRunDocument(dataRoot, runId, "result.json"),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.590741ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.330311ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.907679ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.181581ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.54764ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.169101ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.818664ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.787166ms)
|
||||
✔ readRunDocument reads only the three run documents (0.619749ms)
|
||||
✔ a link inside the data root is followed (1.130548ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.756907ms)
|
||||
✔ a run directory linked out of the data root is never read (1.079323ms)
|
||||
✔ a document linked out of the data root reads as null (1.034215ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.684294ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.532266ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.611387ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.723085ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.536617ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.640848ms)
|
||||
✔ a link to the data root's parent is outside it (0.451118ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.968119ms)
|
||||
✖ listRunRecords lists an r- name that isn't a valid run id, as before (0.6552ms)
|
||||
✔ the readers write nothing (2.352082ms)
|
||||
✔ no pointer is null (3.071243ms)
|
||||
✔ the pointer release.sh writes reads back (2.029825ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (37.796406ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.729401ms)
|
||||
✔ a state file linked out of the data root refuses (1.672903ms)
|
||||
✔ a state directory linked out of the data root refuses (0.622978ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.586589ms)
|
||||
✔ a missing log is empty (0.450358ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.135566ms)
|
||||
✔ last must be a positive integer (0.515257ms)
|
||||
✔ the state readers write nothing (0.965261ms)
|
||||
✔ list prints each run in the established format (100.007368ms)
|
||||
✔ show prints the run in the established format (76.759238ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (165.294787ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (137.384111ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (152.698033ms)
|
||||
✖ list shows an r- name that isn't a valid run id, as before (73.773092ms)
|
||||
✔ show refuses an invalid id before reading the config (39.617828ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 39
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 809.245413
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:220:1
|
||||
✖ listRunRecords lists an r- name that isn't a valid run id, as before (0.6552ms)
|
||||
Error [RunsError]: invalid run id: "r-.bad" (expected r-<id>)
|
||||
at requireRunId (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:13:30)
|
||||
at readRunDocument (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:35:3)
|
||||
at file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:46:13
|
||||
at Array.map (<anonymous>)
|
||||
at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/src/runs.mjs:44:31)
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:225:20)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19) {
|
||||
exitCode: 4
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:96:1
|
||||
✖ list shows an r- name that isn't a valid run id, as before (73.773092ms)
|
||||
AssertionError [ERR_ASSERTION]: mosaic-task: invalid run id: "r-.bad" (expected r-<id>)
|
||||
|
||||
|
||||
4 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:100:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 4,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..9788bfca 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -74,7 +74,7 @@ export function readActivationLog(dataRoot, { last } = {}) {
|
||||
const entries = [];
|
||||
let malformed = 0;
|
||||
for (const line of state.text.split("\n")) {
|
||||
- if (line.trim() === "") continue;
|
||||
+ if (line === "") continue;
|
||||
const entry = logEntry(line);
|
||||
if (entry === null) malformed += 1;
|
||||
else entries.push(entry);
|
||||
@@ -0,0 +1,83 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (2.009126ms)
|
||||
✔ a missing data root or runs directory lists nothing (13.094847ms)
|
||||
✔ runs as a regular file lists nothing, as before (2.278303ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (2.327495ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.905919ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (7.96623ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (3.918579ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (5.602756ms)
|
||||
✔ readRunDocument reads only the three run documents (3.521732ms)
|
||||
✔ a link inside the data root is followed (3.442024ms)
|
||||
✔ a data root that is itself a link is trusted as configured (2.005087ms)
|
||||
✔ a run directory linked out of the data root is never read (2.084232ms)
|
||||
✔ a document linked out of the data root reads as null (7.619635ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.250289ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.818784ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (3.850288ms)
|
||||
✔ a link loop refuses instead of reading as missing (4.675288ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (1.954118ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (1.858696ms)
|
||||
✔ a link to the data root's parent is outside it (1.178473ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.430997ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (3.626875ms)
|
||||
✔ the readers write nothing (3.631659ms)
|
||||
✔ no pointer is null (12.722881ms)
|
||||
✔ the pointer release.sh writes reads back (2.956634ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (23.610773ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (2.467786ms)
|
||||
✔ a state file linked out of the data root refuses (9.154475ms)
|
||||
✔ a state directory linked out of the data root refuses (5.636323ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.989436ms)
|
||||
✔ a missing log is empty (0.893401ms)
|
||||
✖ the log reads oldest first and counts malformed lines (3.734558ms)
|
||||
✔ last must be a positive integer (0.948278ms)
|
||||
✔ the state readers write nothing (2.050762ms)
|
||||
✔ list prints each run in the established format (139.06499ms)
|
||||
✔ show prints the run in the established format (91.810125ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (268.025853ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (205.373671ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (196.491701ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (89.089467ms)
|
||||
✔ show refuses an invalid id before reading the config (49.958959ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1233.510304
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:87:1
|
||||
✖ the log reads oldest first and counts malformed lines (3.734558ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
... Skipped lines
|
||||
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
at: '2026-09-03T20:57:00Z',
|
||||
event: 'package',
|
||||
...
|
||||
],
|
||||
+ malformed: 8
|
||||
- malformed: 7
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:110:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { entries: [ [Object], [Object], [Object], [Object] ], malformed: 8 },
|
||||
expected: { entries: [ [Object], [Object], [Object], [Object] ], malformed: 7 },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs
|
||||
index 03730c33..d8cb0e58 100644
|
||||
--- a/packages/runs/src/runs.mjs
|
||||
+++ b/packages/runs/src/runs.mjs
|
||||
@@ -32,7 +32,6 @@ export function listRunIds(dataRoot) {
|
||||
// One of RUN_DOCUMENTS from a run, or null when it is missing, unreadable,
|
||||
// not a JSON object or outside the data root.
|
||||
export function readRunDocument(dataRoot, runId, name) {
|
||||
- requireRunId(runId);
|
||||
if (!RUN_DOCUMENTS.includes(name)) throw new RunsError(`unknown run document: ${JSON.stringify(name)}`);
|
||||
return readJsonObject(dataRoot, RUNS_DIRNAME, runId, name);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.789031ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.597337ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.16149ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.463129ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.240373ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (2.086403ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.577833ms)
|
||||
✖ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (2.195478ms)
|
||||
✔ readRunDocument reads only the three run documents (1.16193ms)
|
||||
✔ a link inside the data root is followed (2.748711ms)
|
||||
✔ a data root that is itself a link is trusted as configured (2.929924ms)
|
||||
✔ a run directory linked out of the data root is never read (1.362183ms)
|
||||
✔ a document linked out of the data root reads as null (3.606348ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.731427ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.783109ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.924617ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.189822ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.74324ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (1.046894ms)
|
||||
✔ a link to the data root's parent is outside it (0.803458ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.402974ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.820001ms)
|
||||
✔ the readers write nothing (5.081678ms)
|
||||
✔ no pointer is null (3.322821ms)
|
||||
✔ the pointer release.sh writes reads back (2.043259ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (6.549959ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (6.005478ms)
|
||||
✔ a state file linked out of the data root refuses (4.026755ms)
|
||||
✔ a state directory linked out of the data root refuses (1.081501ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (1.876666ms)
|
||||
✔ a missing log is empty (0.648509ms)
|
||||
✔ the log reads oldest first and counts malformed lines (2.286529ms)
|
||||
✔ last must be a positive integer (0.996248ms)
|
||||
✔ the state readers write nothing (1.822738ms)
|
||||
✔ list prints each run in the established format (191.335275ms)
|
||||
✔ show prints the run in the established format (358.090605ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (647.478452ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (725.179038ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (595.356633ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (144.877778ms)
|
||||
✔ show refuses an invalid id before reading the config (138.198732ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2929.86496
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:86:1
|
||||
✖ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (2.195478ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception (RunsError).
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:90:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs
|
||||
index 03730c33..3814b6a5 100644
|
||||
--- a/packages/runs/src/runs.mjs
|
||||
+++ b/packages/runs/src/runs.mjs
|
||||
@@ -26,7 +26,7 @@ export function listRunIds(dataRoot) {
|
||||
if (isMissing(error)) return [];
|
||||
throw new RunsError(`cannot read ${root}: ${error.code ?? error.message}`);
|
||||
}
|
||||
- return names.filter((name) => name.startsWith("r-")).sort();
|
||||
+ return names.filter(isRunId).sort();
|
||||
}
|
||||
|
||||
// One of RUN_DOCUMENTS from a run, or null when it is missing, unreadable,
|
||||
@@ -0,0 +1,99 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (2.349624ms)
|
||||
✔ a missing data root or runs directory lists nothing (3.06341ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.261241ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.52865ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.80885ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.949916ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (3.289521ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.223411ms)
|
||||
✔ readRunDocument reads only the three run documents (0.817925ms)
|
||||
✔ a link inside the data root is followed (1.649226ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.268864ms)
|
||||
✔ a run directory linked out of the data root is never read (1.271219ms)
|
||||
✔ a document linked out of the data root reads as null (4.558659ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.24361ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.769591ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.855321ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.125869ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.92955ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (1.103476ms)
|
||||
✔ a link to the data root's parent is outside it (0.933244ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.548586ms)
|
||||
✖ listRunRecords lists an r- name that isn't a valid run id, as before (3.063895ms)
|
||||
✔ the readers write nothing (5.728488ms)
|
||||
✔ no pointer is null (2.85157ms)
|
||||
✔ the pointer release.sh writes reads back (2.167674ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (28.992167ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.210931ms)
|
||||
✔ a state file linked out of the data root refuses (2.779979ms)
|
||||
✔ a state directory linked out of the data root refuses (1.069934ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.943535ms)
|
||||
✔ a missing log is empty (0.677356ms)
|
||||
✔ the log reads oldest first and counts malformed lines (2.389984ms)
|
||||
✔ last must be a positive integer (4.101041ms)
|
||||
✔ the state readers write nothing (1.756571ms)
|
||||
✔ list prints each run in the established format (213.459424ms)
|
||||
✔ show prints the run in the established format (146.704832ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (380.104067ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (310.571356ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (175.66159ms)
|
||||
✖ list shows an r- name that isn't a valid run id, as before (72.884478ms)
|
||||
✔ show refuses an invalid id before reading the config (55.520564ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 39
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1453.463752
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/runs.test.mjs:220:1
|
||||
✖ listRunRecords lists an r- name that isn't a valid run id, as before (3.063895ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
+ []
|
||||
- [
|
||||
- 'r-.bad'
|
||||
- ]
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/runs.test.mjs:224:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [],
|
||||
expected: [ 'r-.bad' ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:96:1
|
||||
✖ list shows an r- name that isn't a valid run id, as before (72.884478ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
+ ''
|
||||
- 'r-.bad succeeded task=t-one ws=- session=-\n'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/task-cli.test.mjs:101:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: '',
|
||||
expected: 'r-.bad succeeded task=t-one ws=- session=-\n',
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..6b777627 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -39,7 +39,7 @@ export function readActivePointer(dataRoot) {
|
||||
for (const key of Object.keys(pointer)) {
|
||||
if (!POINTER_KEYS.includes(key)) throw invalid(`has an unsupported key: "${key}"`);
|
||||
}
|
||||
- if (pointer.pointerVersion !== 1) throw invalid(`has unsupported pointerVersion ${JSON.stringify(pointer.pointerVersion)}`);
|
||||
+ if (false) throw invalid(`has unsupported pointerVersion ${JSON.stringify(pointer.pointerVersion)}`);
|
||||
for (const key of ["release", "imageTag", "activatedAt"]) {
|
||||
if (!isNonEmptyString(pointer[key])) throw invalid(`needs a non-empty string "${key}"`);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.070238ms)
|
||||
✔ a missing data root or runs directory lists nothing (15.238793ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.630315ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.749971ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (1.868706ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (0.975396ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.713914ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.676303ms)
|
||||
✔ readRunDocument reads only the three run documents (0.521547ms)
|
||||
✔ a link inside the data root is followed (0.939391ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.658101ms)
|
||||
✔ a run directory linked out of the data root is never read (0.61921ms)
|
||||
✔ a document linked out of the data root reads as null (0.876784ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.544007ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.387288ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.479327ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.619689ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.410005ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.46599ms)
|
||||
✔ a link to the data root's parent is outside it (0.377274ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.719835ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.463838ms)
|
||||
✔ the readers write nothing (12.891696ms)
|
||||
✔ no pointer is null (13.84385ms)
|
||||
✔ the pointer release.sh writes reads back (1.126812ms)
|
||||
✖ a pointer that isn't the version 1 shape refuses with exit 2 (78.389391ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.045036ms)
|
||||
✔ a state file linked out of the data root refuses (2.729789ms)
|
||||
✔ a state directory linked out of the data root refuses (0.95196ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.776137ms)
|
||||
✔ a missing log is empty (0.563476ms)
|
||||
✔ the log reads oldest first and counts malformed lines (6.585745ms)
|
||||
✔ last must be a positive integer (0.943606ms)
|
||||
✔ the state readers write nothing (0.995233ms)
|
||||
✔ list prints each run in the established format (95.360894ms)
|
||||
✔ show prints the run in the established format (99.253996ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (122.191371ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (188.490155ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (171.206385ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (96.606326ms)
|
||||
✔ show refuses an invalid id before reading the config (48.391711ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 886.752441
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:32:1
|
||||
✖ a pointer that isn't the version 1 shape refuses with exit 2 (78.389391ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception: /unsupported pointerVersion 2/
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:47:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..2029992d 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -55,7 +55,7 @@ function logEntry(line) {
|
||||
}
|
||||
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return null;
|
||||
if (Object.keys(entry).some((key) => !LOG_KEYS.includes(key))) return null;
|
||||
- if (!["at", "event", "release", "imageTag"].every((key) => typeof entry[key] === "string")) return null;
|
||||
+ if (!["at", "event", "release"].every((key) => typeof entry[key] === "string")) return null;
|
||||
if (entry.note !== undefined && typeof entry.note !== "string") return null;
|
||||
return entry;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.252447ms)
|
||||
✔ a missing data root or runs directory lists nothing (6.093709ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.075597ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.214686ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.148367ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.124565ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.746849ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.009428ms)
|
||||
✔ readRunDocument reads only the three run documents (0.573239ms)
|
||||
✔ a link inside the data root is followed (1.02649ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.812922ms)
|
||||
✔ a run directory linked out of the data root is never read (1.139725ms)
|
||||
✔ a document linked out of the data root reads as null (1.475949ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.79783ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.644081ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.543714ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.716483ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.471177ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.534855ms)
|
||||
✔ a link to the data root's parent is outside it (0.400246ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.78587ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.471629ms)
|
||||
✔ the readers write nothing (2.396636ms)
|
||||
✔ no pointer is null (1.913757ms)
|
||||
✔ the pointer release.sh writes reads back (1.272056ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (125.829499ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.62796ms)
|
||||
✔ a state file linked out of the data root refuses (1.042007ms)
|
||||
✔ a state directory linked out of the data root refuses (0.558456ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.478057ms)
|
||||
✔ a missing log is empty (0.450056ms)
|
||||
✖ the log reads oldest first and counts malformed lines (2.013903ms)
|
||||
✔ last must be a positive integer (0.569281ms)
|
||||
✔ the state readers write nothing (0.848332ms)
|
||||
✔ list prints each run in the established format (82.056594ms)
|
||||
✔ show prints the run in the established format (115.447797ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (143.98818ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (346.242982ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (230.004362ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (128.157444ms)
|
||||
✔ show refuses an invalid id before reading the config (43.502473ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1149.126501
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:87:1
|
||||
✖ the log reads oldest first and counts malformed lines (2.013903ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
... Skipped lines
|
||||
|
||||
{
|
||||
entries: [
|
||||
{
|
||||
at: '2026-09-03T20:57:00Z',
|
||||
event: 'package',
|
||||
...
|
||||
{
|
||||
+ at: '2026-09-03T20:57:47Z',
|
||||
+ event: 'activate',
|
||||
+ release: '0.0.12'
|
||||
+ },
|
||||
+ {
|
||||
at: '2026-09-03T20:57:50Z',
|
||||
event: 'refused',
|
||||
imageTag: 'mosaic-poc-agent:0.84.4-r0.0.11',
|
||||
note: 'health check failed (fault-injected)',
|
||||
release: '0.0.11'
|
||||
...
|
||||
],
|
||||
+ malformed: 6
|
||||
- malformed: 7
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:110:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { entries: [ [Object], [Object], [Object], [Object], [Object] ], malformed: 6 },
|
||||
expected: { entries: [ [Object], [Object], [Object], [Object] ], malformed: 7 },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs
|
||||
index af5cc927..0b58f712 100644
|
||||
--- a/packages/runs/src/state.mjs
|
||||
+++ b/packages/runs/src/state.mjs
|
||||
@@ -66,7 +66,7 @@ function logEntry(line) {
|
||||
// rollback, which skips only lines that aren't JSON. A missing log is empty.
|
||||
// With last, only the newest last well-formed entries are returned.
|
||||
export function readActivationLog(dataRoot, { last } = {}) {
|
||||
- if (last !== undefined && (!Number.isInteger(last) || last < 1)) {
|
||||
+ if (last !== undefined && (!Number.isInteger(last) || last < 0)) {
|
||||
throw new RunsError(`last must be a positive integer (got ${JSON.stringify(last)})`);
|
||||
}
|
||||
const state = readStateFile(dataRoot, ACTIVATION_LOG_FILE);
|
||||
@@ -0,0 +1,69 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.895901ms)
|
||||
✔ a missing data root or runs directory lists nothing (19.117981ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.156194ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (2.786988ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (6.490428ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (3.065151ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.740552ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (2.297296ms)
|
||||
✔ readRunDocument reads only the three run documents (1.292545ms)
|
||||
✔ a link inside the data root is followed (2.752987ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.709382ms)
|
||||
✔ a run directory linked out of the data root is never read (7.227673ms)
|
||||
✔ a document linked out of the data root reads as null (2.243894ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.063142ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.744008ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.882094ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.142281ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (3.150174ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.853351ms)
|
||||
✔ a link to the data root's parent is outside it (0.651315ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.091854ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.60074ms)
|
||||
✔ the readers write nothing (3.036123ms)
|
||||
✔ no pointer is null (14.514676ms)
|
||||
✔ the pointer release.sh writes reads back (3.228549ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (72.542192ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.930314ms)
|
||||
✔ a state file linked out of the data root refuses (1.407715ms)
|
||||
✔ a state directory linked out of the data root refuses (0.738704ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.801635ms)
|
||||
✔ a missing log is empty (0.664066ms)
|
||||
✔ the log reads oldest first and counts malformed lines (2.17924ms)
|
||||
✖ last must be a positive integer (1.668759ms)
|
||||
✔ the state readers write nothing (2.415105ms)
|
||||
✔ list prints each run in the established format (147.726988ms)
|
||||
✔ show prints the run in the established format (108.731864ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (172.540569ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (269.573796ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (185.736528ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (100.838017ms)
|
||||
✔ show refuses an invalid id before reading the config (64.187937ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 40
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1135.081876
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/state.test.mjs:115:1
|
||||
✖ last must be a positive integer (1.668759ms)
|
||||
AssertionError [ERR_ASSERTION]: Missing expected exception: 0
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r56b/mutwt/packages/runs/tests/state.test.mjs:118:12)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: undefined,
|
||||
expected: /last must be a positive integer/,
|
||||
operator: 'throws',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
agents/rocko/work/queue-56/byte-check.sh: OK
|
||||
agents/rocko/work/queue-56/delta-check.sh: OK
|
||||
agents/rocko/work/queue-56/seed.sh: OK
|
||||
packages/runs/package.json: OK
|
||||
packages/runs/README.md: OK
|
||||
packages/runs/src/errors.mjs: OK
|
||||
packages/runs/src/index.mjs: OK
|
||||
packages/runs/src/paths.mjs: OK
|
||||
packages/runs/src/runs.mjs: OK
|
||||
packages/runs/src/state.mjs: OK
|
||||
packages/runs/tests/helpers.mjs: OK
|
||||
packages/runs/tests/runs.test.mjs: OK
|
||||
packages/runs/tests/state.test.mjs: OK
|
||||
packages/runs/tests/task-cli.test.mjs: OK
|
||||
scripts/mosaic-task.mjs: OK
|
||||
@@ -0,0 +1,32 @@
|
||||
# mutate.py <id>: apply one named mutant to the candidate (exact text, must match once). Run from the tree root.
|
||||
import sys
|
||||
P, R, T, X = "packages/runs/src/paths.mjs", "packages/runs/src/runs.mjs", "packages/runs/src/state.mjs", "scripts/mosaic-task.mjs"
|
||||
M = {
|
||||
"D01": [(X, " if (!isRunId(runId)) {\n fail(4, `invalid run id", " if (false) {\n fail(4, `invalid run id")],
|
||||
"D03": [(P, " } catch {\n return null;\n }\n}", " } catch (error) {\n if (error instanceof RunsError) throw error;\n return null;\n }\n}")],
|
||||
"D04": [(R, " if (resolveInside(dataRoot, RUNS_DIRNAME) === null) return null;\n", "")],
|
||||
"D05": [(T, "entries.slice(-last)", "entries.slice(0, last)")],
|
||||
"D06": [(T, ' if (entry.note !== undefined && typeof entry.note !== "string") return null;\n', "")],
|
||||
"D07": [(R, " if (isMissing(error)) return [];\n throw new RunsError(`cannot read ${root}", " return [];\n throw new RunsError(`cannot read ${root}")],
|
||||
"D08": [(T, " } catch (error) {\n throw new RunsError(`cannot read ${file}", " } catch (error) {\n return null;\n throw new RunsError(`cannot read ${file}")],
|
||||
"D09": [(T, "if (!POINTER_KEYS.includes(key))", "if (false)")],
|
||||
"D10": [(P, 'return relative === "" ||', "return false ||")],
|
||||
"D11": [(X, "if (error instanceof RunsError) fail(error.exitCode, error.message);\n throw error;\n }\n}\n\nfunction listRuns", "if (false) fail(error.exitCode, error.message);\n throw error;\n }\n}\n\nfunction listRuns")],
|
||||
"D13": [(R, " if (isMissing(error)) return null;\n throw new RunsError(`cannot read ${dir}", " throw new RunsError(`cannot read ${dir}")],
|
||||
"D14": [(P, "real = fs.realpathSync(target);", "real = path.resolve(target);")],
|
||||
"D15": [(P, "root = fs.realpathSync(dataRoot);", "root = path.resolve(dataRoot);")],
|
||||
"D16": [(R, "{0,63}$/", "{0,64}$/")],
|
||||
"D17": [(R, ' result: readJsonObject(dataRoot, RUNS_DIRNAME, runId, "result.json"),', ' result: readRunDocument(dataRoot, runId, "result.json"),')],
|
||||
"D18": [(T, 'if (line.trim() === "") continue;', 'if (line === "") continue;')],
|
||||
"D19": [(R, " requireRunId(runId);\n if (!RUN_DOCUMENTS", " if (!RUN_DOCUMENTS")],
|
||||
"D20": [(R, 'filter((name) => name.startsWith("r-")).sort()', "filter(isRunId).sort()")],
|
||||
"D21": [(T, "if (pointer.pointerVersion !== 1)", "if (false)")],
|
||||
"D22": [(T, '["at", "event", "release", "imageTag"].every', '["at", "event", "release"].every')],
|
||||
"D23": [(T, "last < 1)", "last < 0)")],
|
||||
}
|
||||
for f, old, new in M[sys.argv[1]]:
|
||||
s = open(f).read()
|
||||
n = s.count(old)
|
||||
if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}")
|
||||
open(f, "w").write(s.replace(old, new))
|
||||
print(sys.argv[1], "applied")
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# Each mutant against the packages/runs suite in a second candidate worktree, then restores from the index.
|
||||
export TMPDIR=~/darkwing-scratch/r56b/tmp
|
||||
S=~/darkwing-scratch/r56b; M=$S/mut; W=$S/mutwt
|
||||
: > $M/summary.txt
|
||||
echo "start $(date -u +%FT%TZ)" >> $M/summary.txt
|
||||
for v in $(python3 -c 'import re;print(" ".join(sorted(set(re.findall(r"\"(D\d\d)\"", open("'$M'/mutate.py").read())))))'); do
|
||||
(cd $W && git checkout -q -- packages scripts && python3 $M/mutate.py $v > /dev/null && git diff > $M/$v.diff) || { echo "$v APPLY-FAILED" >> $M/summary.txt; continue; }
|
||||
(cd $W && env -u NODE_TEST_CONTEXT node --test packages/runs/tests/*.test.mjs > $M/$v.txt 2>&1); e=$?
|
||||
r=killed; [ $e = 0 ] && r=SURVIVED
|
||||
echo "$v $r exit=$e $(grep -E '^ℹ (pass|fail)' $M/$v.txt | tr '\n' ' ')" >> $M/summary.txt
|
||||
done
|
||||
(cd $W && git checkout -q -- packages scripts && sha256sum -c $S/pkt/candidate-manifest.sha256) > $M/manifest-after.txt 2>&1
|
||||
echo "end $(date -u +%FT%TZ)" >> $M/summary.txt
|
||||
echo DONE >> $M/summary.txt
|
||||
@@ -0,0 +1,24 @@
|
||||
start 2026-10-10T17:12:08Z
|
||||
D01 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D03 killed exit=1 ℹ pass 37 ℹ fail 4
|
||||
D04 killed exit=1 ℹ pass 39 ℹ fail 2
|
||||
D05 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D06 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D07 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D08 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D09 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D10 SURVIVED exit=0 ℹ pass 41 ℹ fail 0
|
||||
D11 killed exit=1 ℹ pass 39 ℹ fail 2
|
||||
D13 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D14 killed exit=1 ℹ pass 27 ℹ fail 14
|
||||
D15 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D16 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D17 killed exit=1 ℹ pass 39 ℹ fail 2
|
||||
D18 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D19 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D20 killed exit=1 ℹ pass 39 ℹ fail 2
|
||||
D21 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D22 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
D23 killed exit=1 ℹ pass 40 ℹ fail 1
|
||||
end 2026-10-10T17:12:34Z
|
||||
DONE
|
||||
@@ -0,0 +1,2 @@
|
||||
byte-check: 16 cases, stdout, stderr and exit identical
|
||||
byte-check: data root unchanged
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
== run directory linked out of the data root: list
|
||||
base: exit 0
|
||||
out| r-20260101T000000Z-aaaaaa succeeded task=t-out ws=- session=-
|
||||
cand: exit 0
|
||||
out| r-20260101T000000Z-aaaaaa unknown task=- ws=- session=-
|
||||
|
||||
== run directory linked out of the data root: show
|
||||
base: exit 0
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| status: succeeded
|
||||
out| task: t-out
|
||||
out| adapter: (see config) provider=p model=m
|
||||
out| request: "r"
|
||||
out| response: "s"
|
||||
out| timing: a -> b (1 ms)
|
||||
out| exit: 0
|
||||
out| artifacts: result.json
|
||||
cand: exit 4
|
||||
err| mosaic-task: /home/jwoltje/darkwing-scratch/r56b/dc/run-link/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/dc/run-link/data)
|
||||
|
||||
== result.json linked out of the data root: list
|
||||
base: exit 0
|
||||
out| r-20260101T000000Z-aaaaaa succeeded task=t-out ws=- session=-
|
||||
cand: exit 0
|
||||
out| r-20260101T000000Z-aaaaaa unknown task=- ws=- session=-
|
||||
|
||||
== result.json linked out of the data root: show
|
||||
base: exit 0
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| status: succeeded
|
||||
out| task: t-out
|
||||
out| adapter: (see config) provider=p model=m
|
||||
out| request: "r"
|
||||
out| response: "s"
|
||||
out| timing: a -> b (1 ms)
|
||||
out| exit: 0
|
||||
out| artifacts: result.json
|
||||
cand: exit 0
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| result.json: (missing or unreadable)
|
||||
out| artifacts: result.json
|
||||
|
||||
== runs directory linked out of the data root: list
|
||||
base: exit 0
|
||||
out| r-20260101T000000Z-aaaaaa succeeded task=t-out ws=- session=-
|
||||
cand: exit 4
|
||||
err| mosaic-task: /home/jwoltje/darkwing-scratch/r56b/dc/runs-link/data/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/dc/runs-link/data)
|
||||
|
||||
== runs directory linked out of the data root: show
|
||||
base: exit 0
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| status: succeeded
|
||||
out| task: t-out
|
||||
out| adapter: (see config) provider=p model=m
|
||||
out| request: "r"
|
||||
out| response: "s"
|
||||
out| timing: a -> b (1 ms)
|
||||
out| exit: 0
|
||||
out| artifacts: result.json
|
||||
cand: exit 4
|
||||
err| mosaic-task: /home/jwoltje/darkwing-scratch/r56b/dc/runs-link/data/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/dc/runs-link/data)
|
||||
|
||||
== result.json is 5 and task.json is []: list
|
||||
base: exit 1
|
||||
err| file:///home/jwoltje/darkwing-scratch/r56b/base/scripts/mosaic-task.mjs:483
|
||||
cand: exit 0
|
||||
out| r-20260101T000000Z-aaaaaa unknown task=- ws=- session=-
|
||||
|
||||
== result.json is 5 and task.json is []: show
|
||||
base: exit 0
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| status: undefined
|
||||
out| task: undefined
|
||||
out| adapter: (see config) provider=undefined model=undefined
|
||||
out| request: undefined
|
||||
out| response: undefined
|
||||
out| timing: undefined -> undefined (undefined ms)
|
||||
out| exit: undefined
|
||||
out| task snapshot: task.json present
|
||||
out| artifacts: result.json, task.json
|
||||
cand: exit 0
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| result.json: (missing or unreadable)
|
||||
out| artifacts: result.json, task.json
|
||||
|
||||
== run is a regular file: show
|
||||
base: exit 1
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| result.json: (missing or unreadable)
|
||||
err| node:fs:1954
|
||||
cand: exit 4
|
||||
err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56b/dc/run-file/data/runs)
|
||||
|
||||
== run is a link loop: show
|
||||
base: exit 4
|
||||
err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56b/dc/loop/data/runs)
|
||||
cand: exit 4
|
||||
err| mosaic-task: cannot resolve /home/jwoltje/darkwing-scratch/r56b/dc/loop/data/runs/r-20260101T000000Z-aaaaaa: ELOOP
|
||||
|
||||
== runs directory unreadable: list
|
||||
base: exit 0
|
||||
cand: exit 4
|
||||
err| mosaic-task: cannot read /home/jwoltje/darkwing-scratch/r56b/dc/unreadable/data/runs: EACCES
|
||||
|
||||
== runs directory unreadable: show
|
||||
base: exit 4
|
||||
err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56b/dc/unreadable/data/runs)
|
||||
cand: exit 4
|
||||
err| mosaic-task: cannot resolve /home/jwoltje/darkwing-scratch/r56b/dc/unreadable/data/runs/r-20260101T000000Z-aaaaaa: EACCES
|
||||
|
||||
== run directory unreadable: show
|
||||
base: exit 1
|
||||
out| run: r-20260101T000000Z-aaaaaa
|
||||
out| result.json: (missing or unreadable)
|
||||
err| node:fs:1954
|
||||
cand: exit 4
|
||||
err| mosaic-task: cannot read /home/jwoltje/darkwing-scratch/r56b/dc/run-unreadable/data/runs/r-20260101T000000Z-aaaaaa: EACCES
|
||||
@@ -0,0 +1,49 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (0.845764ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.27599ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.481538ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.620424ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (1.641509ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (0.822114ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.561666ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.531563ms)
|
||||
✔ readRunDocument reads only the three run documents (0.427644ms)
|
||||
✔ a link inside the data root is followed (0.795518ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.549674ms)
|
||||
✔ a run directory linked out of the data root is never read (0.551772ms)
|
||||
✔ a document linked out of the data root reads as null (0.799823ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.528601ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.359757ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.428236ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.558513ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.397344ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.438001ms)
|
||||
✔ a link to the data root's parent is outside it (0.427799ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.733867ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.434006ms)
|
||||
✔ the readers write nothing (1.814734ms)
|
||||
✔ no pointer is null (1.605828ms)
|
||||
✔ the pointer release.sh writes reads back (0.95797ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (357.065646ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.599972ms)
|
||||
✔ a state file linked out of the data root refuses (0.819613ms)
|
||||
✔ a state directory linked out of the data root refuses (0.470093ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.414246ms)
|
||||
✔ a missing log is empty (46.073141ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.021399ms)
|
||||
✔ last must be a positive integer (0.452181ms)
|
||||
✔ the state readers write nothing (0.734058ms)
|
||||
✔ list prints each run in the established format (68.62278ms)
|
||||
✔ show prints the run in the established format (65.989299ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (276.117437ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (185.491853ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (215.611415ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (100.451058ms)
|
||||
✔ show refuses an invalid id before reading the config (51.977553ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1017.118046
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
== Q1 runs/ linked out of the data root to nothing: list
|
||||
base: exit 0
|
||||
cand: exit 0
|
||||
|
||||
== Q1 same: show
|
||||
base: exit 4
|
||||
err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56b/probes/q1/data/runs)
|
||||
cand: exit 4
|
||||
err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56b/probes/q1/data/runs)
|
||||
|
||||
== Q2 runs/ linked out to an empty directory that exists: list
|
||||
base: exit 0
|
||||
cand: exit 4
|
||||
err| mosaic-task: /home/jwoltje/darkwing-scratch/r56b/probes/q2/data/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/probes/q2/data)
|
||||
|
||||
== Q3 state/ linked out to nothing (candidate module)
|
||||
readActivePointer: null
|
||||
readActivationLog: {"entries":[],"malformed":0}
|
||||
|
||||
== Q4 state/ linked out to an empty directory that exists (round 1 P5)
|
||||
readActivePointer: null
|
||||
readActivationLog: {"entries":[],"malformed":0}
|
||||
|
||||
== Q4b same, with active.json there
|
||||
readActivePointer: RunsError 4 /home/jwoltje/darkwing-scratch/r56b/probes/q4/data/state/active.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56b/probes/q4/data)
|
||||
readActivationLog: {"entries":[],"malformed":0}
|
||||
@@ -0,0 +1,7 @@
|
||||
packages/runs/src/errors.mjs: OK
|
||||
packages/runs/src/index.mjs: OK
|
||||
packages/runs/src/paths.mjs: OK
|
||||
packages/runs/src/runs.mjs: OK
|
||||
packages/runs/src/state.mjs: FAILED
|
||||
scripts/mosaic-task.mjs: OK
|
||||
sha256sum: WARNING: 1 computed checksum did NOT match
|
||||
@@ -0,0 +1,12 @@
|
||||
diff -r /home/jwoltje/darkwing-scratch/r56b/r1tree/packages/runs/src/state.mjs /home/jwoltje/darkwing-scratch/r56b/cand/packages/runs/src/state.mjs
|
||||
63,66c63,67
|
||||
< // The activation log as { entries, malformed }, oldest first. Lines that
|
||||
< // aren't a well-formed entry are counted in malformed and skipped, the way
|
||||
< // release.sh rollback skips them. A missing log is empty. With last, only
|
||||
< // the newest last well-formed entries are returned.
|
||||
---
|
||||
> // The activation log as { entries, malformed }, oldest first. A line that
|
||||
> // isn't JSON, or is JSON but not the entry shape release.sh writes, is
|
||||
> // counted in malformed and skipped. This is stricter than release.sh
|
||||
> // rollback, which skips only lines that aren't JSON. A missing log is empty.
|
||||
> // With last, only the newest last well-formed entries are returned.
|
||||
@@ -0,0 +1,13 @@
|
||||
start 2026-10-10T17:12:07Z
|
||||
node-runs exit=0 ℹ pass 41 ℹ fail 0
|
||||
test-auth exit=0 selftest: 15 passed, 0 failed
|
||||
test-conductor exit=0 selftest: 17 passed, 0 failed
|
||||
test-config exit=0 selftest: 24 passed, 0 failed
|
||||
test-discord exit=1 discord suite: 65 passed, 1 failed
|
||||
test-extension-package exit=0 extension package selftest: 18 passed, 0 failed
|
||||
test-foundation exit=0 selftest: 44 passed, 0 failed
|
||||
test-queue exit=0 queue suite: 27 passed, 0 failed
|
||||
test-release exit=0 selftest: 4 passed, 0 failed
|
||||
test-task exit=0 selftest: 26 passed, 0 failed
|
||||
end 2026-10-10T17:14:22Z
|
||||
DONE
|
||||
@@ -0,0 +1,17 @@
|
||||
OK status with missing harness credential exits 3 and still lists accounts
|
||||
OK status reports harness credential (read-only) + mosaic accounts
|
||||
OK api key material never reaches output
|
||||
OK oauth token material never reaches output
|
||||
OK unparseable credential file exits 2
|
||||
OK symlinked credential file exits 4
|
||||
OK env-side credential names reported
|
||||
OK env var values never reach output
|
||||
OK accounts without an accounts dir reports none and creates nothing
|
||||
OK accounts lists files and marks the active one
|
||||
OK loose account perms flagged in listing
|
||||
OK agent --auth with missing account file refuses (exit 4)
|
||||
OK agent --auth with non-0600 account file refuses
|
||||
OK agent --auth with invalid account name refuses
|
||||
OK auth.sh without valid config refuses
|
||||
|
||||
selftest: 15 passed, 0 failed
|
||||
@@ -0,0 +1,55 @@
|
||||
Note: switching to '75ab164698176178f196009f14f994e0192048a7'.
|
||||
|
||||
You are in 'detached HEAD' state. You can look around, make experimental
|
||||
changes and commit them, and you can discard any commits you make in this
|
||||
state without impacting any branches by switching back to a branch.
|
||||
|
||||
If you want to create a new branch to retain commits you create, you may
|
||||
do so (now or later) by using -c with the switch command. Example:
|
||||
|
||||
git switch -c <new-branch-name>
|
||||
|
||||
Or undo this operation with:
|
||||
|
||||
git switch -
|
||||
|
||||
Turn off this advice by setting config variable advice.detachedHead to false
|
||||
|
||||
Not currently on any branch.
|
||||
nothing to commit, working tree clean
|
||||
Note: switching to '75ab164698176178f196009f14f994e0192048a7'.
|
||||
|
||||
You are in 'detached HEAD' state. You can look around, make experimental
|
||||
changes and commit them, and you can discard any commits you make in this
|
||||
state without impacting any branches by switching back to a branch.
|
||||
|
||||
If you want to create a new branch to retain commits you create, you may
|
||||
do so (now or later) by using -c with the switch command. Example:
|
||||
|
||||
git switch -c <new-branch-name>
|
||||
|
||||
Or undo this operation with:
|
||||
|
||||
git switch -
|
||||
|
||||
Turn off this advice by setting config variable advice.detachedHead to false
|
||||
|
||||
OK dry-run: allowed change, exit 0, nothing committed (exit 0)
|
||||
OK dry-run committed nothing
|
||||
OK apply: allowed change exits 0 (exit 0)
|
||||
OK apply: attribution in commit subject
|
||||
OK apply: target tree clean after commit
|
||||
OK disallowed path refused (exit 1)
|
||||
OK disallowed path: target untouched
|
||||
OK syntax gate refused broken .mjs (exit 1)
|
||||
OK syntax gate: target untouched
|
||||
OK suite failure refused (exit 1)
|
||||
OK suite failure: target reverted to clean
|
||||
OK disabled policy refused (exit 2)
|
||||
OK disabled policy: target untouched
|
||||
OK failed run refused (exit 1)
|
||||
OK failed run: target untouched
|
||||
OK missing run exits 4 (exit 4)
|
||||
OK invalid policy exits 2 (exit 2)
|
||||
|
||||
selftest: 17 passed, 0 failed
|
||||
@@ -0,0 +1,26 @@
|
||||
OK absent adapter defaults to pi
|
||||
OK adapter mock validates (exit 0)
|
||||
OK unsupported adapter exits 2 (exit 2)
|
||||
OK env exports adapter
|
||||
OK bootstrap creates default when absent (exit 0)
|
||||
OK bootstrap wrote config file
|
||||
OK bootstrap is idempotent on existing config (exit 0)
|
||||
OK bootstrap did not rewrite existing config
|
||||
OK validate missing config exits 3 (exit 3)
|
||||
OK malformed JSON exits 2 (exit 2)
|
||||
OK unsupported configVersion exits 2 (exit 2)
|
||||
OK unknown top-level key exits 2 (exit 2)
|
||||
OK unknown execution key exits 2 (exit 2)
|
||||
OK unsupported backend exits 2 (exit 2)
|
||||
OK unsupported environment exits 2 (exit 2)
|
||||
OK relative dataRoot exits 2 (exit 2)
|
||||
OK non-canonical dataRoot exits 2 (exit 2)
|
||||
OK filesystem root dataRoot exits 2 (exit 2)
|
||||
OK home directory dataRoot exits 2 (exit 2)
|
||||
OK dataRoot containing config dir exits 2 (exit 2)
|
||||
OK control character in provider exits 2 (exit 2)
|
||||
OK symlinked config file exits 2 (exit 2)
|
||||
OK env exports resolve correctly
|
||||
OK failed validation modified nothing
|
||||
|
||||
selftest: 24 passed, 0 failed
|
||||
@@ -0,0 +1,70 @@
|
||||
toolchain: node v26.8.1
|
||||
|
||||
OK syntax: packages/discord/src/approvals.mjs
|
||||
OK syntax: packages/discord/src/authorize.mjs
|
||||
OK syntax: packages/discord/src/binding.mjs
|
||||
OK syntax: packages/discord/src/cli.mjs
|
||||
OK syntax: packages/discord/src/connector.mjs
|
||||
OK syntax: packages/discord/src/context.mjs
|
||||
OK syntax: packages/discord/src/engine-pi.mjs
|
||||
OK syntax: packages/discord/src/errors.mjs
|
||||
OK syntax: packages/discord/src/gateway.mjs
|
||||
OK syntax: packages/discord/src/git.mjs
|
||||
OK syntax: packages/discord/src/journal.mjs
|
||||
OK syntax: packages/discord/src/notify.mjs
|
||||
OK syntax: packages/discord/src/rest.mjs
|
||||
OK syntax: packages/discord/src/setspark.mjs
|
||||
OK syntax: packages/discord/src/tools.mjs
|
||||
OK syntax: packages/discord/src/web.mjs
|
||||
OK syntax: packages/discord/bin/git-credential.mjs
|
||||
OK syntax: packages/discord/extension/tools.mjs
|
||||
OK syntax: packages/discord/tests/approvals.test.mjs
|
||||
OK syntax: packages/discord/tests/authorize.test.mjs
|
||||
OK syntax: packages/discord/tests/binding.test.mjs
|
||||
OK syntax: packages/discord/tests/connector.test.mjs
|
||||
OK syntax: packages/discord/tests/context.test.mjs
|
||||
OK syntax: packages/discord/tests/engine.test.mjs
|
||||
OK syntax: packages/discord/tests/fake-pi.mjs
|
||||
OK syntax: packages/discord/tests/gateway.test.mjs
|
||||
OK syntax: packages/discord/tests/git.test.mjs
|
||||
OK syntax: packages/discord/tests/helpers.mjs
|
||||
OK syntax: packages/discord/tests/journal.test.mjs
|
||||
OK syntax: packages/discord/tests/notify.test.mjs
|
||||
OK syntax: packages/discord/tests/recover.test.mjs
|
||||
OK syntax: packages/discord/tests/rest.test.mjs
|
||||
OK syntax: packages/discord/tests/setspark.test.mjs
|
||||
OK syntax: packages/discord/tests/tools.test.mjs
|
||||
OK syntax: packages/discord/tests/web.test.mjs
|
||||
OK syntax: packages/discord/fixtures/claim-worker.mjs
|
||||
OK syntax: packages/discord/fixtures/legacy-owner-worker.mjs
|
||||
OK syntax: scripts/discord.sh
|
||||
OK syntax: scripts/discord-service.sh
|
||||
OK packages/discord declares no dependencies
|
||||
OK no bot-token-shaped string in packages/discord
|
||||
OK fixture binding uses placeholder ids only
|
||||
OK fixture binding validates
|
||||
OK real pi with the extension exposes exactly list_dir, read_file, search and no built-in tool
|
||||
OK real pi with a writable root exposes exactly the three reads plus write_file and edit_file, and writes nothing at start
|
||||
OK real pi with a web key exposes the three reads plus web_fetch and web_search, and no write tool without a writable root
|
||||
OK real pi with a git root exposes the reads, writes and the four git verbs, commits nothing at start, and never shows the token
|
||||
OK real pi with protocol vault adds reserve_id to the git verbs
|
||||
OK real pi with a setspark key exposes the reads and the eight record verbs, no counters, and never shows the key
|
||||
OK real pi refuses a git key on a read-only root (fail closed)
|
||||
OK real pi with the pilot flags (--no-tools) exposes no tool at all
|
||||
OK real pi exits non-zero without MOSAIC_DISCORD_TOOLS: no session, no tools (fail closed)
|
||||
OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT
|
||||
OK node --test packages/discord/tests/ (ℹ pass 178)
|
||||
OK scripts/discord.sh --help exits 0
|
||||
OK scripts/discord.sh check without a binding exits 4
|
||||
OK scripts/discord.sh recover without a binding exits 4
|
||||
OK scripts/discord.sh reload without a binding exits 4
|
||||
OK scripts/discord-service.sh without a command exits 4
|
||||
OK service unit renders with the repository path, a supervised run as the main process, exit 3 never retried, and reload as SIGHUP
|
||||
OK service install writes the rendered unit (0644) and leaves no temp file
|
||||
OK service install a second time reports unchanged
|
||||
OK systemd-analyze verify accepts the rendered unit
|
||||
OK service uninstall removes the unit file
|
||||
OK service install with an unknown flag exits 4
|
||||
OK service install with USER unset finishes and names the account for lingering
|
||||
|
||||
discord suite: 66 passed, 0 failed
|
||||
@@ -0,0 +1,74 @@
|
||||
toolchain: node v26.8.1
|
||||
|
||||
OK syntax: packages/discord/src/approvals.mjs
|
||||
OK syntax: packages/discord/src/authorize.mjs
|
||||
OK syntax: packages/discord/src/binding.mjs
|
||||
OK syntax: packages/discord/src/cli.mjs
|
||||
OK syntax: packages/discord/src/connector.mjs
|
||||
OK syntax: packages/discord/src/context.mjs
|
||||
OK syntax: packages/discord/src/engine-pi.mjs
|
||||
OK syntax: packages/discord/src/errors.mjs
|
||||
OK syntax: packages/discord/src/gateway.mjs
|
||||
OK syntax: packages/discord/src/git.mjs
|
||||
OK syntax: packages/discord/src/journal.mjs
|
||||
OK syntax: packages/discord/src/notify.mjs
|
||||
OK syntax: packages/discord/src/rest.mjs
|
||||
OK syntax: packages/discord/src/setspark.mjs
|
||||
OK syntax: packages/discord/src/tools.mjs
|
||||
OK syntax: packages/discord/src/web.mjs
|
||||
OK syntax: packages/discord/bin/git-credential.mjs
|
||||
OK syntax: packages/discord/extension/tools.mjs
|
||||
OK syntax: packages/discord/tests/approvals.test.mjs
|
||||
OK syntax: packages/discord/tests/authorize.test.mjs
|
||||
OK syntax: packages/discord/tests/binding.test.mjs
|
||||
OK syntax: packages/discord/tests/connector.test.mjs
|
||||
OK syntax: packages/discord/tests/context.test.mjs
|
||||
OK syntax: packages/discord/tests/engine.test.mjs
|
||||
OK syntax: packages/discord/tests/fake-pi.mjs
|
||||
OK syntax: packages/discord/tests/gateway.test.mjs
|
||||
OK syntax: packages/discord/tests/git.test.mjs
|
||||
OK syntax: packages/discord/tests/helpers.mjs
|
||||
OK syntax: packages/discord/tests/journal.test.mjs
|
||||
OK syntax: packages/discord/tests/notify.test.mjs
|
||||
OK syntax: packages/discord/tests/recover.test.mjs
|
||||
OK syntax: packages/discord/tests/rest.test.mjs
|
||||
OK syntax: packages/discord/tests/setspark.test.mjs
|
||||
OK syntax: packages/discord/tests/tools.test.mjs
|
||||
OK syntax: packages/discord/tests/web.test.mjs
|
||||
OK syntax: packages/discord/fixtures/claim-worker.mjs
|
||||
OK syntax: packages/discord/fixtures/legacy-owner-worker.mjs
|
||||
OK syntax: scripts/discord.sh
|
||||
OK syntax: scripts/discord-service.sh
|
||||
OK packages/discord declares no dependencies
|
||||
OK no bot-token-shaped string in packages/discord
|
||||
OK fixture binding uses placeholder ids only
|
||||
OK fixture binding validates
|
||||
OK real pi with the extension exposes exactly list_dir, read_file, search and no built-in tool
|
||||
OK real pi with a writable root exposes exactly the three reads plus write_file and edit_file, and writes nothing at start
|
||||
OK real pi with a web key exposes the three reads plus web_fetch and web_search, and no write tool without a writable root
|
||||
OK real pi with a git root exposes the reads, writes and the four git verbs, commits nothing at start, and never shows the token
|
||||
OK real pi with protocol vault adds reserve_id to the git verbs
|
||||
OK real pi with a setspark key exposes the reads and the eight record verbs, no counters, and never shows the key
|
||||
OK real pi refuses a git key on a read-only root (fail closed)
|
||||
OK real pi with the pilot flags (--no-tools) exposes no tool at all
|
||||
OK real pi exits non-zero without MOSAIC_DISCORD_TOOLS: no session, no tools (fail closed)
|
||||
OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT
|
||||
FAIL node --test packages/discord/tests/ (ℹ pass 177)
|
||||
✖ engine: when pi has not started a timed-out turn by the end of the abort grace, the engine stops pi and fails held prompts (309.121655ms)
|
||||
✖ failing tests:
|
||||
✖ engine: when pi has not started a timed-out turn by the end of the abort grace, the engine stops pi and fails held prompts (309.121655ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
OK scripts/discord.sh --help exits 0
|
||||
OK scripts/discord.sh check without a binding exits 4
|
||||
OK scripts/discord.sh recover without a binding exits 4
|
||||
OK scripts/discord.sh reload without a binding exits 4
|
||||
OK scripts/discord-service.sh without a command exits 4
|
||||
OK service unit renders with the repository path, a supervised run as the main process, exit 3 never retried, and reload as SIGHUP
|
||||
OK service install writes the rendered unit (0644) and leaves no temp file
|
||||
OK service install a second time reports unchanged
|
||||
OK systemd-analyze verify accepts the rendered unit
|
||||
OK service uninstall removes the unit file
|
||||
OK service install with an unknown flag exits 4
|
||||
OK service install with USER unset finishes and names the account for lingering
|
||||
|
||||
discord suite: 65 passed, 1 failed
|
||||
@@ -0,0 +1,21 @@
|
||||
OK initial ordinary-file install
|
||||
OK installed tree matches canonical source
|
||||
OK installed tree has no symlinks
|
||||
OK check detects installation drift
|
||||
OK sync refuses to overwrite installation drift
|
||||
OK check detects an extra destination file
|
||||
OK check detects an extra destination directory
|
||||
OK check rejects a destination symlink
|
||||
OK sync accepts a canonical source update
|
||||
OK updated installation matches canonical source
|
||||
scripts/test-extension-package.sh: line 14: 1178504 Killed "$@" > /dev/null 2>&1
|
||||
OK forced interruption kills the replacing process
|
||||
OK next invocation recovers old consistent installation
|
||||
OK interrupted replacement rolled back
|
||||
OK sync succeeds after interruption recovery
|
||||
OK unlocked stale lock file does not block
|
||||
OK active lock refuses a concurrent sync
|
||||
OK source symlink fails closed
|
||||
OK nested second entrypoint fails closed
|
||||
|
||||
extension package selftest: 18 passed, 0 failed
|
||||
@@ -0,0 +1,53 @@
|
||||
toolchain: node v26.8.1, python 3.12.8, jsonschema 4.26.0
|
||||
|
||||
OK syntax: scripts/foundation-inspect.mjs
|
||||
OK syntax: scripts/foundation/strict-json.mjs
|
||||
OK syntax: scripts/foundation/canonical.mjs
|
||||
OK syntax: scripts/foundation/resolve.mjs
|
||||
OK syntax: scripts/foundation/validate-record.mjs
|
||||
OK syntax: scripts/foundation/fixtures/build-fixtures.mjs
|
||||
OK syntax: scripts/foundation/canonical.test.mjs
|
||||
OK syntax: scripts/foundation/cli.test.mjs
|
||||
OK syntax: scripts/foundation/fixtures.test.mjs
|
||||
OK syntax: scripts/foundation/resolve.test.mjs
|
||||
OK syntax: scripts/foundation/strict-json.test.mjs
|
||||
OK syntax: scripts/foundation/verify-schema.py (ast only; no bytecode written)
|
||||
OK fixture generator runs
|
||||
OK checked-in fixtures/bundles equal a fresh generation
|
||||
OK checked-in fixtures/raw equal a fresh generation
|
||||
OK checked-in fixtures/index.json equal a fresh generation
|
||||
OK checked-in demo bundles equal a fresh generation
|
||||
OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT
|
||||
OK node --test scripts/foundation/ (ℹ pass 80)
|
||||
OK differential schema oracle: PASS: differential schema oracle (finite corpus; compatibility evidence, not equivalence proof)
|
||||
platform witness: strftime('%Y') for year 999 -> '999' (pinned checker refuses years 0001..0999)
|
||||
node v26.8.1; corpus 1568 records (38 pinned fixtures, 478 unique bundle records, 1052 typeCase/mutation/lexical cases)
|
||||
schema column: agree-valid 540, agree-invalid 991, DISAGREEMENTS 0; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10
|
||||
profile column (schema-valid records only): profile-valid 510, profile-invalid 30
|
||||
profile refusals asserted: 30 schema-agreed-valid records refused only by the strict typed-string profile (rule profile-pattern-mismatch), 12 declared by name; 73 named probes verified against declared schema/profile columns
|
||||
OK oracle: zero schema-column disagreements with the pinned checker
|
||||
OK oracle: strict-only profile refusals are counted and asserted
|
||||
OK demo: permitted read preview exits 0 (exit 0)
|
||||
OK demo: permitted file.change preview exits 0 (exit 0)
|
||||
OK demo: assignment.change proposal is unresolved (exit 3) (exit 3)
|
||||
OK demo: revoked registration is refused (exit 3) (exit 3)
|
||||
OK demo: message is not authority (exit 3) (exit 3)
|
||||
OK usage: no arguments exits 2 (exit 2)
|
||||
OK io: missing file exits 4 (exit 4)
|
||||
OK io: directory exits 4 (exit 4)
|
||||
OK io: symlink exits 4 (O_NOFOLLOW) (exit 4)
|
||||
OK bound: oversize fixture exits 2 (exit 2)
|
||||
OK profile: one final LF in a typed selection id is refused before admission (exit 2) (exit 2)
|
||||
OK profile: two final LFs fail the schema pattern itself (exit 2) (exit 2)
|
||||
OK profile: escaped newlines in free-form text stay allowed (exit 0) (exit 0)
|
||||
OK profile refusal is invalid-request/profile-pattern-mismatch with selection and operation withheld, value not echoed
|
||||
OK text output starts with the disclaimer
|
||||
OK json output is valid JSON with result allowed and exactly the charter §7 fields
|
||||
OK json golden matches byte-for-byte
|
||||
OK sandboxed bundle run (env -i, PATH=/nonexistent) produced the unresolved proposal
|
||||
OK sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs
|
||||
OK canary never printed (bundle run and credential-file run)
|
||||
OK a non-bundle JSON file is refused at the shape gate, not read into output
|
||||
OK no field of the non-bundle file is echoed
|
||||
|
||||
selftest: 44 passed, 0 failed
|
||||
@@ -0,0 +1,35 @@
|
||||
toolchain: node v26.8.1, git version 2.55.0
|
||||
|
||||
OK syntax: packages/queue/src/cli.mjs
|
||||
OK syntax: packages/queue/src/errors.mjs
|
||||
OK syntax: packages/queue/src/io.mjs
|
||||
OK syntax: packages/queue/src/lock.mjs
|
||||
OK syntax: packages/queue/src/queue.mjs
|
||||
OK syntax: packages/queue/src/review.mjs
|
||||
OK syntax: packages/queue/src/store.mjs
|
||||
OK syntax: packages/queue/tests/commit.test.mjs
|
||||
OK syntax: packages/queue/tests/data.test.mjs
|
||||
OK syntax: packages/queue/tests/dispatch.test.mjs
|
||||
OK syntax: packages/queue/tests/helpers.mjs
|
||||
OK syntax: packages/queue/tests/lock.test.mjs
|
||||
OK syntax: packages/queue/tests/migration.test.mjs
|
||||
OK syntax: packages/queue/tests/review.test.mjs
|
||||
OK syntax: packages/queue/tests/store.test.mjs
|
||||
OK syntax: packages/queue/tests/write.test.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/fake-gitea.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/kill-at.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/lock-child.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/mosaic-pre-a2.sh
|
||||
OK syntax: scripts/queue-commit.sh
|
||||
OK syntax: scripts/git-hooks/pre-commit
|
||||
OK syntax: scripts/mosaic
|
||||
OK queue-commit.sh, the guard and scripts/mosaic are executable
|
||||
OK packages/queue declares no dependencies
|
||||
ℹ tests 148
|
||||
ℹ pass 148
|
||||
ℹ fail 0
|
||||
OK node --test packages/queue/tests/
|
||||
OK scripts/mosaic queue help
|
||||
skip queue verify and render --check: this checkout (/home/jwoltje/darkwing-scratch/r56b/cand) is not the queue's canonical root (/mnt/storage/src/mosaic-stack)
|
||||
|
||||
queue suite: 27 passed, 0 failed
|
||||
@@ -0,0 +1,16 @@
|
||||
OK valid RELEASE resolves (exit 0)
|
||||
OK invalid RELEASE exits 1 (exit 1)
|
||||
OK missing RELEASE exits 1 (exit 1)
|
||||
OK valid RELEASE leaves image tag consistent with version
|
||||
OK status safe on empty state (exit 0)
|
||||
OK status created no pointer
|
||||
OK fault-injected activation refuses (exit 1)
|
||||
OK refused activation wrote no pointer
|
||||
OK refusal logged exactly once with valid fields
|
||||
OK healthy activation succeeds (exit 0)
|
||||
OK pointer written with valid fields
|
||||
OK repeat activation succeeds (log grows) (exit 0)
|
||||
OK log is append-only across activations
|
||||
OK rollback without previous refuses (exit 1)
|
||||
|
||||
selftest: 14 passed, 0 failed
|
||||
@@ -0,0 +1,7 @@
|
||||
OK valid RELEASE resolves (exit 0)
|
||||
OK invalid RELEASE exits 1 (exit 1)
|
||||
OK missing RELEASE exits 1 (exit 1)
|
||||
OK valid RELEASE leaves image tag consistent with version
|
||||
skip state-machine cases (docker daemon unavailable)
|
||||
|
||||
selftest: 4 passed, 0 failed
|
||||
@@ -0,0 +1,32 @@
|
||||
OK valid task validates (exit 0)
|
||||
OK unknown task key exits 2 (exit 2)
|
||||
OK unsupported taskVersion exits 2 (exit 2)
|
||||
OK invalid task id exits 2 (exit 2)
|
||||
OK empty prompt exits 2 (exit 2)
|
||||
OK NUL in expectExact exits 2 (exit 2)
|
||||
OK out-of-range timeout exits 2 (exit 2)
|
||||
OK missing mission file exits 4 (exit 4)
|
||||
OK task with valid mission validates (exit 0)
|
||||
OK invalid mission exits 2 (exit 2)
|
||||
OK validate missing task exits 4 (exit 4)
|
||||
OK validation does not modify the task file
|
||||
OK prune dry-run exits 0 (exit 0)
|
||||
OK dry-run deleted nothing
|
||||
OK prune --keep=2 --yes removes oldest (exit 0)
|
||||
OK kept exactly 2 newest runs
|
||||
OK newest run kept, oldest pruned
|
||||
OK append-only receipt written (3 entries)
|
||||
OK sessions/workspaces untouched by prune
|
||||
OK prune with invalid keep exits 4 (exit 4)
|
||||
skip adapter seam cases (docker daemon unavailable)
|
||||
skip workspace/capability cases (docker daemon unavailable)
|
||||
skip live task cases (docker unavailable)
|
||||
OK onboard without name exits 4 (non-interactive) (exit 4)
|
||||
OK onboard --name renders profile (exit 0)
|
||||
OK profile written
|
||||
OK canon structure: required filled, optional placeholdered
|
||||
OK canon sections present
|
||||
skip live recall pair: user recall run, recalled user name (docker daemon unavailable)
|
||||
OK no agent identity on headless run
|
||||
|
||||
selftest: 26 passed, 0 failed
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# Row 56 round 2 probes: the README's link wording for runs/ and state/, base against candidate.
|
||||
export TMPDIR=~/darkwing-scratch/r56b/tmp
|
||||
S=~/darkwing-scratch/r56b; W=$S/probes; rm -rf $W; mkdir -p $W
|
||||
A=r-20260101T000000Z-aaaaaa
|
||||
root() { mkdir -p "$W/$1/data" "$W/$1/outside"; printf '{"configVersion":1,"environment":"development","dataRoot":"%s","execution":{"backend":"docker","provider":"zai","model":"m"}}\n' "$W/$1/data" > "$W/$1/config.json"; echo "$W/$1/data"; }
|
||||
run_case() { local name="$1" cfg="$2"; shift 2
|
||||
for tree in base cand; do
|
||||
local rc=0 out
|
||||
out="$(cd $S/$tree && env -u NODE_TEST_CONTEXT MOSAIC_CONFIG="$cfg" node scripts/mosaic-task.mjs "$@" 2>"$W/$name.$tree.err")" || rc=$?
|
||||
printf ' %s: exit %s\n' "$tree" "$rc"; [ -z "$out" ] || printf '%s\n' "$out" | sed 's/^/ out| /'
|
||||
[ -s "$W/$name.$tree.err" ] && head -1 "$W/$name.$tree.err" | sed 's/^/ err| /'
|
||||
done; }
|
||||
state_case() {
|
||||
(cd $S/cand && node -e '
|
||||
import("./packages/runs/src/index.mjs").then((m) => {
|
||||
for (const f of ["readActivePointer", "readActivationLog"]) {
|
||||
try { console.log(" " + f + ": " + JSON.stringify(m[f](process.argv[1]))); } catch (e) { console.log(" " + f + ": " + e.name + " " + e.exitCode + " " + e.message); }
|
||||
}
|
||||
});' "$1"); }
|
||||
hdr() { printf '\n== %s\n' "$*"; }
|
||||
|
||||
D="$(root q1)"; ln -s "$W/q1/outside/absent" "$D/runs"
|
||||
hdr "Q1 runs/ linked out of the data root to nothing: list"; run_case q1l "$W/q1/config.json" list
|
||||
hdr "Q1 same: show"; run_case q1s "$W/q1/config.json" show "$A"
|
||||
|
||||
D="$(root q2)"; ln -s "$W/q2/outside" "$D/runs"
|
||||
hdr "Q2 runs/ linked out to an empty directory that exists: list"; run_case q2 "$W/q2/config.json" list
|
||||
|
||||
D="$(root q3)"; ln -s "$W/q3/outside/absent" "$D/state"
|
||||
hdr "Q3 state/ linked out to nothing (candidate module)"; state_case "$D"
|
||||
|
||||
D="$(root q4)"; ln -s "$W/q4/outside" "$D/state"
|
||||
hdr "Q4 state/ linked out to an empty directory that exists (round 1 P5)"; state_case "$D"
|
||||
printf '{"pointerVersion":1,"release":"x","imageTag":"y","activatedAt":"z"}\n' > "$W/q4/outside/active.json"
|
||||
hdr "Q4b same, with active.json there"; state_case "$D"
|
||||
@@ -0,0 +1,154 @@
|
||||
# Row 56, runs and releases reader, round 2 review (Darkwing)
|
||||
|
||||
Issue #1545, request comment 27120, queue revs 350-354. Base `75ab1646`.
|
||||
Candidate manifest sha256
|
||||
`2727198f7e50b935205546a60ea97d8d4f20d87cad2a88e10477148c8d3dc42e`,
|
||||
`build.patch` sha256 `d2fa5fb7…`. Both match comment 27120, and the
|
||||
packet manifest checks clean. This is the delta review Sage asked for,
|
||||
against round 1 (`ed3c5392`, my approval in comment 27115).
|
||||
|
||||
Verdict: **approve**. `src/` and `scripts/mosaic-task.mjs` are the round 1
|
||||
bytes apart from one comment in `state.mjs`. D01 (Rocko's M31), D17, D20
|
||||
and D22 now die on assertions in the new tests. Every suite is green. The
|
||||
README fixes for my notes 4b and 4c are right. The fix for 4a is half
|
||||
right: it covers a `state/` link to nothing, and the sentence above it
|
||||
still says a `state/` link out refuses, which isn't what happens when the
|
||||
link points at a directory that exists. That is wording, nothing outside
|
||||
is read, and I don't think it needs a round 3.
|
||||
|
||||
## Method
|
||||
|
||||
- Detached worktrees at `75ab1646`: `base`, `cand` and `mutwt`, the last
|
||||
two with `git apply --index build.patch`, then `sha256sum -c` on the
|
||||
manifest, 15 OK each. `mutwt` still checks 15 OK after the mutant runs
|
||||
(`r2/mut/manifest-after.txt`).
|
||||
- A fourth worktree at `dc96f87b` with round 1's `build.patch` applied
|
||||
(15 OK against `ed3c5392`). `diff -r` of `packages/runs/src` and `cmp`
|
||||
of `scripts/mosaic-task.mjs` against the round 2 candidate
|
||||
(`r2/out/src-diff.txt`, `r2/out/src-against-r1.txt`).
|
||||
- `diff -u` of the three test files, the README and `delta-check.sh`
|
||||
against round 1. The result matches `out/round2-delta.diff`.
|
||||
- `r2/gate.sh`: the packages/runs suite, then every `scripts/test-*.sh`
|
||||
with `DOCKER_HOST=unix:///nonexistent.sock`, 17:12:07Z to 17:14:22Z.
|
||||
- Round 1's 21 mutants, unchanged (`r2/mut/mutate.py`, `r2/mut/run.sh`),
|
||||
17:12:08Z to 17:12:34Z in `mutwt`, alongside the gate.
|
||||
- Rocko's `byte-check.sh` and `delta-check.sh` from the candidate, base
|
||||
against candidate, work directories in my scratch.
|
||||
- Four probes of the README's new link wording (`r2/probes.sh`, output in
|
||||
`r2/out/probes.txt`).
|
||||
- `test-release` with Docker, 17:14:45Z to 17:15:08Z.
|
||||
|
||||
Node v26.8.1, `TMPDIR=~/darkwing-scratch/r56b/tmp`.
|
||||
|
||||
## src/ against round 1
|
||||
|
||||
Five of the six files are byte-identical. `state.mjs` differs only in the
|
||||
comment above `readActivationLog`:
|
||||
|
||||
```
|
||||
// The activation log as { entries, malformed }, oldest first. A line that
|
||||
// isn't JSON, or is JSON but not the entry shape release.sh writes, is
|
||||
// counted in malformed and skipped. This is stricter than release.sh
|
||||
// rollback, which skips only lines that aren't JSON. A missing log is empty.
|
||||
// With last, only the newest last well-formed entries are returned.
|
||||
```
|
||||
|
||||
That matches `release.sh` lines 91-99: rollback drops empty lines, skips
|
||||
lines `JSON.parse` rejects, and uses the newest `activate` or `rollback`
|
||||
entry whose `imageTag` is truthy and differs from the current one.
|
||||
|
||||
## Suites
|
||||
|
||||
| Suite | Result |
|
||||
|---|---|
|
||||
| packages/runs (node) | 41/0 |
|
||||
| test-auth | 15/0 |
|
||||
| test-conductor | 17/0 |
|
||||
| test-config | 24/0 |
|
||||
| test-discord | 65/1 in the gate, 66/0 alone (below) |
|
||||
| test-extension-package | 18/0 |
|
||||
| test-foundation | 44/0 |
|
||||
| test-queue | 27/0 |
|
||||
| test-release | 4/0 without Docker, 14/0 with it |
|
||||
| test-task, Docker unreachable | 26/0 |
|
||||
| byte-check.sh | 16 cases identical, data root unchanged |
|
||||
| delta-check.sh | 13 cases, same as Rocko's apart from scratch paths |
|
||||
|
||||
The test-discord failure in the gate was "engine: when pi has not started
|
||||
a timed-out turn by the end of the abort grace, the engine stops pi and
|
||||
fails held prompts", a timing test that ran while the mutants and checks
|
||||
were loading the machine. The candidate changes nothing under
|
||||
`packages/discord`. A rerun on its own at 17:14:31Z gave 66/0
|
||||
(`r2/out/test-discord-r2.txt`).
|
||||
|
||||
I didn't run test-task with real Docker, because it makes live model
|
||||
calls. Round 2 doesn't touch `mosaic-task.mjs`, and Rocko's run gave 98/0.
|
||||
|
||||
## Mutants
|
||||
|
||||
20 of 21 killed (`r2/mut/summary.txt`). Only D10 survives, which I said in
|
||||
round 1 needs no test.
|
||||
|
||||
| Mutant | Round 1 | Round 2, killed by |
|
||||
|---|---|---|
|
||||
| D01 (M31) | survived | "show refuses an invalid id before reading the config": exit 3, `configuration problem` |
|
||||
| D17 | survived | "listRunRecords lists an r- name that isn't a valid run id, as before" and the CLI `list` test: exit 4, `invalid run id: "r-.bad"` |
|
||||
| D20 | survived | the same two tests: the list comes back empty |
|
||||
| D22 | survived | "the log reads oldest first and counts malformed lines": the entry with no `imageTag` shows up in `entries` |
|
||||
|
||||
Each is an `AssertionError` from the new assertions, not a load or
|
||||
reference error.
|
||||
|
||||
## Wording
|
||||
|
||||
| Note | Fixed? |
|
||||
|---|---|
|
||||
| 4b, the "like rollback" comparison (Filbert's N1) | yes, in the README and the `state.mjs` comment, and both now match `release.sh` |
|
||||
| 4c, no delta row for an unreadable run directory | yes: a README row and a `delta-check.sh` case. Base prints two lines and crashes, exit 1; the candidate refuses with EACCES, exit 4 |
|
||||
| Filbert's N2, `release` as a string | yes: `{ ...good[1], release: 5 }` is now in the malformed lines |
|
||||
| 4a, `state/` linked out | half: see below |
|
||||
|
||||
The README still says "`runs/` or `state/` resolving outside refuses with a
|
||||
`RunsError`". The new paragraph after the list says a `state/` link out
|
||||
"to a path that doesn't exist" reads as no release and an empty log, and
|
||||
the new test covers that case. My round 1 probe P5 linked `state/` to a
|
||||
directory that exists, and that case still contradicts the bullet:
|
||||
|
||||
| Probe | Candidate |
|
||||
|---|---|
|
||||
| Q1 `runs/` linked out to nothing | `list` prints nothing, exit 0; `show` says `run not found`, exit 4. Base does the same |
|
||||
| Q2 `runs/` linked out to an empty directory that exists | `list` refuses, exit 4 (base: nothing, exit 0) |
|
||||
| Q3 `state/` linked out to nothing | pointer `null`, log empty |
|
||||
| Q4 `state/` linked out to an empty directory that exists | pointer `null`, log empty, no refusal |
|
||||
| Q4b the same, with `active.json` there | `readActivePointer` refuses, exit 4 |
|
||||
|
||||
The module never resolves `state/` itself, only `state/active.json` and
|
||||
`state/activation-log.jsonl`. So a `state/` link out refuses only once one
|
||||
of those files exists behind it. A sentence that says so would fix it,
|
||||
for example: "`runs/` resolving outside refuses. `state/` isn't resolved
|
||||
on its own; `active.json` or `activation-log.jsonl` resolving outside
|
||||
refuses, and while neither exists a `state/` link out reads as no release
|
||||
and an empty log." The invariant holds either way, because nothing outside
|
||||
the data root is read.
|
||||
|
||||
## Notes (not blocking)
|
||||
|
||||
1. The 4a wording above. It can ride with the `padEnd` follow-up or any
|
||||
later change to this README. I don't want a round 3 for it.
|
||||
2. BUILD.md describes rollback as acting on "any parsed `activate` or
|
||||
`rollback` entry with a truthy `imageTag`". It also skips the entry
|
||||
whose `imageTag` equals the current one. The README and the comment
|
||||
don't make that claim, so only the packet is affected.
|
||||
3. Correction to my round 1 review: it said "17 of 22 killed". `mutate.py`
|
||||
defines 21 mutants (there is no D02 or D12), and 16 of them were
|
||||
killed in round 1. The five survivors I listed were right.
|
||||
|
||||
## Files
|
||||
|
||||
- `r2/candidate-manifest.sha256`: copy of Rocko's.
|
||||
- `r2/gate.sh`, `r2/out/`: suite runs, `summary.txt`, the test-discord
|
||||
rerun, byte and delta checks, test-release with Docker, the `src/`
|
||||
comparison with round 1, and the probe output.
|
||||
- `r2/mut/`: round 1's mutant definitions and runner, diffs, outputs,
|
||||
`summary.txt` and the manifest check after the runs.
|
||||
- `r2/probes.sh`: Q1 to Q4b.
|
||||
Reference in New Issue
Block a user