10 lines
3.2 KiB
JavaScript
10 lines
3.2 KiB
JavaScript
import test from 'node:test';import assert from 'node:assert/strict';
|
|||
|
|
import {mkdtempSync,writeFileSync,readFileSync,readdirSync,rmSync,mkdirSync,linkSync} from 'node:fs';import {tmpdir} from 'node:os';import {join,resolve} from 'node:path';
|
||
|
|
import {collectorStorage} from '../scripts/debug-collector-storage.mjs';
|
||
|
|
function fixture(t){const root=mkdtempSync(join(tmpdir(),'safetynet-collector-rotation-'));t.after(()=>{assert.ok(resolve(root).startsWith(resolve(tmpdir())+'\\safetynet-collector-rotation-')||resolve(root).startsWith(resolve(tmpdir())+'/safetynet-collector-rotation-'));rmSync(root,{recursive:true,force:true});});return root;}
|
||
|
|
test('collector exact budget rotates before append and pins original encrypted archive',t=>{const root=fixture(t),old='encrypted-old-record\n';writeFileSync(join(root,'signals.encrypted.ndjson'),old);const store=collectorStorage(root,{segmentBytes:1024,retiredSegments:2});store.append('x'.repeat(1024));assert.equal(readFileSync(join(root,'signals.legacy.encrypted.ndjson'),'utf8'),old);assert.equal(store.summary().storedBytes,1024);assert.equal(store.summary().rotations,1);});
|
||
|
|
test('rolling developer segments are bounded across restart while legacy remains pinned',t=>{const root=fixture(t);let store=collectorStorage(root,{segmentBytes:1024,retiredSegments:2});for(let i=0;i<8;i++)store.append(String(i).repeat(1024));let summary=store.summary();assert.equal(summary.retiredSegments,2);assert.equal(summary.droppedSegments,4);assert.equal(summary.activeBytes+summary.retiredBytes,3072);assert.equal(readFileSync(join(root,'signals.legacy.encrypted.ndjson'),'utf8'),'0'.repeat(1024));store=collectorStorage(root,{segmentBytes:1024,retiredSegments:2});store.append('z');assert.equal(store.summary().retiredSegments,2);assert.equal(readFileSync(join(root,'signals.legacy.encrypted.ndjson'),'utf8'),'0'.repeat(1024));});
|
||
|
|
test('oversized batch is rejected without writing or retiring archive',t=>{const root=fixture(t),store=collectorStorage(root,{segmentBytes:1024});assert.throws(()=>store.append('x'.repeat(1025)));assert.equal(store.summary().rejectedWrites,1);assert.equal(store.summary().rotations,0);assert.equal(readdirSync(root).length,0);});
|
||
|
|
test('unexpected entry and directory substitution fail closed before deletion or append',t=>{const root=fixture(t),store=collectorStorage(root,{segmentBytes:1024});store.append('x'.repeat(1024));writeFileSync(join(root,'unrelated.txt'),'preserve');assert.throws(()=>store.append('z'));assert.equal(readFileSync(join(root,'unrelated.txt'),'utf8'),'preserve');assert.equal(readFileSync(join(root,'signals.encrypted.ndjson'),'utf8').length,1024);});
|
||
|
|
test('retention refuses unexpected directory masquerading as generated segment',t=>{const root=fixture(t);mkdirSync(join(root,'signals.rolling.1234567890123.aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa.encrypted.ndjson'));assert.throws(()=>collectorStorage(root,{segmentBytes:1024}));});
|
||
|
|
test('hardlinked encrypted target is refused without altering its other name',t=>{const root=fixture(t),outside=fixture(t),path=join(outside,'preserved');writeFileSync(path,'external-original');linkSync(path,join(root,'signals.encrypted.ndjson'));assert.throws(()=>collectorStorage(root,{segmentBytes:1024}));assert.equal(readFileSync(path,'utf8'),'external-original');});
|