fix(test): restructure DirectoryTailer re-activation test
The test 'resumes from saved position when a file is re-activated after eviction' was incorrectly creating both files before starting the tailer. With maxActiveFiles: 1, only the newer file (fileB) was being activated initially, so fileA never emitted its 'initial' event. Restructured to: 1. Create fileA with content 2. Start tailer (fileA gets activated) 3. Wait for fileA to emit 'initial' 4. Create fileB (triggers eviction of fileA via dirWatcher) 5. Continue with re-activation test This properly tests the LRU eviction and position checkpointing behavior.
This commit is contained in:
parent
10533b0b4f
commit
7fa822d3ea
1 changed files with 41 additions and 20 deletions
|
|
@ -273,38 +273,59 @@ describe('DirectoryTailer', () => {
|
|||
const fileA = path.join(tempDir, 'a.jsonl');
|
||||
const fileB = path.join(tempDir, 'b.jsonl');
|
||||
|
||||
fs.writeFileSync(fileA, makeEvent('w-a', 'before-eviction', 1) + '\n');
|
||||
fs.writeFileSync(fileB, '');
|
||||
// Create fileA with initial content - this will be activated first.
|
||||
fs.writeFileSync(fileA, makeEvent('w-a', 'initial', 1) + '\n');
|
||||
|
||||
// maxActiveFiles=1 so opening fileB will evict fileA.
|
||||
const tailer = new DirectoryTailer({
|
||||
directory: tempDir,
|
||||
maxActiveFiles: 1,
|
||||
recentMtimeMs: 86_400_000,
|
||||
inactiveCheckIntervalMs: 200,
|
||||
inactiveCheckIntervalMs: 100,
|
||||
});
|
||||
|
||||
const received: string[] = [];
|
||||
tailer.on('event', (event) => received.push(event.msg));
|
||||
const received: Array<{ msg: string; filePath: string }> = [];
|
||||
tailer.on('event', (event, filePath) => {
|
||||
received.push({ msg: event.msg, filePath });
|
||||
});
|
||||
|
||||
// Start with only fileA present - it will be activated.
|
||||
tailer.start();
|
||||
|
||||
// Wait for fileA to be read and emit 'initial'.
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
// Verify fileA is active and emitted 'initial'.
|
||||
expect(tailer.activeFiles.length).toBe(1);
|
||||
expect(tailer.activeFiles[0]).toBe(fileA);
|
||||
expect(received.filter((r) => r.msg === 'initial').length).toBe(1);
|
||||
|
||||
// Create fileB empty - when detected, it will evict fileA via activateWithEviction.
|
||||
fs.writeFileSync(fileB, '');
|
||||
|
||||
// Wait for dirWatcher to detect fileB and evict fileA.
|
||||
await new Promise((r) => setTimeout(r, 200));
|
||||
|
||||
// Exactly one file should be active (fileB, the newer one).
|
||||
expect(tailer.activeFiles.length).toBe(1);
|
||||
expect(tailer.activeFiles[0]).toBe(fileB);
|
||||
|
||||
// fileA should have been read and emitted 'initial' before being evicted.
|
||||
const initialCount = received.filter((r) => r.msg === 'initial').length;
|
||||
expect(initialCount).toBe(1);
|
||||
|
||||
// Write to fileA (the inactive/evicted file) to trigger re-activation.
|
||||
// This new content should be read from the checkpointed position.
|
||||
fs.appendFileSync(fileA, makeEvent('w-a', 'after-eviction', 2) + '\n');
|
||||
|
||||
// Wait for the poll cycle to detect mtime change and re-activate fileA.
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
|
||||
// Exactly one file is active; the other is inactive.
|
||||
expect(tailer.activeFiles.length).toBe(1);
|
||||
|
||||
// Write to the inactive file to trigger re-activation.
|
||||
const inactive = tailer.activeFiles[0] === fileA ? fileB : fileA;
|
||||
fs.appendFileSync(inactive, makeEvent('w-inactive', 'after-reactivation', 2) + '\n');
|
||||
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
tailer.stop();
|
||||
|
||||
// The event written after re-activation must have been received.
|
||||
expect(received).toContain('after-reactivation');
|
||||
// The event written before eviction (to fileA at start time) should NOT
|
||||
// have been re-emitted when fileA was re-activated (position is checkpointed).
|
||||
const beforeCount = received.filter((m) => m === 'before-eviction').length;
|
||||
expect(beforeCount).toBe(0);
|
||||
// The new event should be received.
|
||||
expect(received.some((r) => r.msg === 'after-eviction')).toBe(true);
|
||||
// 'initial' should only have been emitted once (during initial activation),
|
||||
// not again when fileA was re-activated.
|
||||
expect(received.filter((r) => r.msg === 'initial').length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue