aboutsummaryrefslogtreecommitdiff
path: root/modules/test/test-vfs-checkpoint.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/test/test-vfs-checkpoint.js')
-rw-r--r--modules/test/test-vfs-checkpoint.js55
1 files changed, 55 insertions, 0 deletions
diff --git a/modules/test/test-vfs-checkpoint.js b/modules/test/test-vfs-checkpoint.js
index 03a8c8a..65f32dc 100644
--- a/modules/test/test-vfs-checkpoint.js
+++ b/modules/test/test-vfs-checkpoint.js
@@ -84,6 +84,61 @@ function ok(name, cond, detail) {
'output=' + JSON.stringify(out.join('\n')));
}
+// D. same-millisecond calls must not overwrite each other
+{
+ const fs = mkFs();
+ const names = [];
+ // 4 calls: one more than the cap of 3, so every name is still stored when the next one is
+ // minted (at 6+, prune legitimately frees a name and it may be reused).
+ for (let i = 0; i < 4; i++) names.push(fs.checkpoint(''));
+ ok('D1 four unnamed checkpoints are four distinct names', new Set(names).size === 4,
+ 'names=' + JSON.stringify(names));
+ ok('D2 prune still caps the store at three', fs.listCheckpoints().length === 3,
+ 'stored=' + JSON.stringify(fs.listCheckpoints()));
+}
+
+// E. prune keeps the NEWEST three, not the alphabetically last
+{
+ const fs = mkFs();
+ fs.checkpoint('aaa-oldest');
+ fs.checkpoint('');
+ fs.checkpoint('');
+ fs.checkpoint(''); // 4th -> prune
+ const left = fs.listCheckpoints();
+ ok('E1 oldest custom-named checkpoint was pruned', !left.includes('aaa-oldest'), 'left=' + JSON.stringify(left));
+ ok('E2 three checkpoints remain', left.length === 3, 'left=' + JSON.stringify(left));
+ ok('E3 rollback still works after pruning', fs.rollback(left[0]) === true);
+}
+
+// F. rollback must not destroy scaffolding
+{
+ const fs = mkFs();
+ fs.mkdirRecursive('/_sessions/agent1');
+ fs.writeFile('/_sessions/agent1/log.json', '{"turns":3}');
+ fs.mkdirRecursive('/.trash');
+ fs.writeFile('/.trash/junk.txt', 'x');
+ fs.writeFile('/work.txt', 'before');
+ const name = fs.checkpoint('keep-me');
+ fs.writeFile('/work.txt', 'after');
+ ok('F1 rollback succeeds', fs.rollback(name) === true);
+ ok('F2 file restored', fs.readFile('/work.txt') === 'before', 'got ' + fs.readFile('/work.txt'));
+ ok('F3 checkpoint survived rollback', fs.listCheckpoints().includes('keep-me'),
+ 'list=' + JSON.stringify(fs.listCheckpoints()));
+ ok('F4 sessions survived rollback', !!fs.readDir('/_sessions'));
+ ok('F5 trash survived rollback', !!fs.readDir('/.trash'));
+ ok('F6 rollback is repeatable', fs.rollback('keep-me') === true);
+}
+
+// G. a name with a slash is refused, not silently unlistable
+{
+ const fs = mkFs();
+ let threw = false;
+ try { fs.checkpoint('a/b'); } catch (e) { threw = true; }
+ ok('G1 slash in name throws', threw);
+ ok('G2 nothing was written', fs.listCheckpoints().length === 0,
+ 'list=' + JSON.stringify(fs.listCheckpoints()));
+}
+
if (fails === 0) {
console.log('test-vfs-checkpoint: ' + passes + ' passed, 0 failed');
} else {