This commit is contained in:
Oleg Maslov
2026-09-02 10:14:22 +02:00
parent 0c3e2ead3b
commit b20b138fe4
771 changed files with 161561 additions and 9027 deletions

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import * as fs from 'node:fs';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import {
@@ -20,6 +20,7 @@ beforeEach(() => {
home = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-audit-'));
});
afterEach(() => {
vi.restoreAllMocks();
fs.rmSync(home, { recursive: true, force: true });
});
@@ -27,6 +28,8 @@ const badge = (over: Partial<SkillAuditBadge> = {}): Omit<SkillAuditBadge, 'audi
verified: true, score: 0.88, confidence: 0.88, attempts: 1, rewritten: false, demoted: false, ...over,
});
const tempFiles = (): string[] => fs.readdirSync(home).filter(file => file.endsWith('.tmp'));
describe('loadSkillAudit (fail-safe)', () => {
it('returns {} when the file is missing — and never creates it on read', () => {
expect(loadSkillAudit(home)).toEqual({});
@@ -75,6 +78,66 @@ describe('recordAuditBadge', () => {
});
});
describe('saveSkillAudit (Windows transient locks)', () => {
it.each(['EPERM', 'EACCES', 'EBUSY'] as const)(
'retries %s without leaving a temporary file',
(code) => {
recordAuditBadge(home, 'prior', badge({ feedback: 'replace me' }));
const replacement = {
current: { ...badge({ feedback: 'new index' }), auditedAt: '2026-08-03T00:00:00.000Z' },
};
const actualRename = fs.renameSync.bind(fs);
let attempts = 0;
const rename = vi.spyOn(fs, 'renameSync').mockImplementation((oldPath, newPath) => {
attempts += 1;
if (attempts <= 2) throw Object.assign(new Error('temporarily locked'), { code });
return actualRename(oldPath, newPath);
});
const wait = vi.spyOn(Atomics, 'wait').mockReturnValue('timed-out');
saveSkillAudit(home, replacement);
expect(rename).toHaveBeenCalledTimes(3);
expect(wait).toHaveBeenNthCalledWith(1, expect.any(Int32Array), 0, 0, 25);
expect(wait).toHaveBeenNthCalledWith(2, expect.any(Int32Array), 0, 0, 50);
expect(loadSkillAudit(home)).toEqual(replacement);
expect(tempFiles()).toEqual([]);
},
);
it('preserves the prior index and cleans up after bounded retry exhaustion', () => {
recordAuditBadge(home, 'stable', badge({ feedback: 'keep me' }));
const prior = fs.readFileSync(getSkillAuditPath(home), 'utf-8');
const rename = vi.spyOn(fs, 'renameSync').mockImplementation(() => {
throw Object.assign(new Error('still locked'), { code: 'EPERM' });
});
const wait = vi.spyOn(Atomics, 'wait').mockReturnValue('timed-out');
expect(() => saveSkillAudit(home, {})).toThrow('still locked');
expect(rename).toHaveBeenCalledTimes(10);
expect(wait).toHaveBeenCalledTimes(9);
expect(fs.readFileSync(getSkillAuditPath(home), 'utf-8')).toBe(prior);
expect(tempFiles()).toEqual([]);
});
it('does not retry a non-transient rename error and still cleans up', () => {
recordAuditBadge(home, 'stable', badge({ feedback: 'keep me' }));
const prior = fs.readFileSync(getSkillAuditPath(home), 'utf-8');
const rename = vi.spyOn(fs, 'renameSync').mockImplementation(() => {
throw Object.assign(new Error('invalid destination'), { code: 'ENOENT' });
});
const wait = vi.spyOn(Atomics, 'wait').mockReturnValue('timed-out');
expect(() => saveSkillAudit(home, {})).toThrow('invalid destination');
expect(rename).toHaveBeenCalledTimes(1);
expect(wait).not.toHaveBeenCalled();
expect(fs.readFileSync(getSkillAuditPath(home), 'utf-8')).toBe(prior);
expect(tempFiles()).toEqual([]);
});
});
describe('isSkillVerified / getAuditBadge / clearAuditBadge', () => {
it('isSkillVerified is true only for verified badges', () => {
recordAuditBadge(home, 'ok', badge({ verified: true }));