mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 16:01:54 +00:00
- Refactored `test/memory-scheduler.test.mjs` to use `mock.timers` for deterministic execution, replacing flaky `wait` logic. - Strengthened `test/lock-ops.test.mjs` with edge case tests for `parseLockEvent` handling invalid JSON and missing fields. - Fixed a security vulnerability in `src/dashboard.mjs` where sensitive configuration (e.g., rosters, auth) was exposed in `/torch-config.json`. - Updated `src/prompts/daily/test-audit-agent.md` to comply with the canonical prompt contract. - Added `reports/test-audit/test-integrity-note-2025-02-14.yaml` detailing test changes and anti-cheat measures. Co-authored-by: PR0M3TH3AN <[email protected]>
146 lines
4.5 KiB
JavaScript
146 lines
4.5 KiB
JavaScript
import { test, mock } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import {
|
|
createDbAdvisoryLockProvider,
|
|
startMemoryMaintenanceScheduler,
|
|
} from '../src/services/memory/scheduler.js';
|
|
|
|
test('createDbAdvisoryLockProvider acquires and releases postgres advisory locks', async () => {
|
|
const calls = [];
|
|
const db = {
|
|
async query(sql, params) {
|
|
calls.push({ sql, params });
|
|
if (sql.includes('pg_try_advisory_lock')) {
|
|
return { rows: [{ locked: true }] };
|
|
}
|
|
return { rows: [] };
|
|
},
|
|
};
|
|
|
|
const lockProvider = createDbAdvisoryLockProvider(db, { namespace: 'tests' });
|
|
const result = await lockProvider.withLock('job', async () => 42);
|
|
|
|
assert.equal(result.acquired, true);
|
|
assert.equal(result.result, 42);
|
|
assert.equal(calls.length, 2);
|
|
assert.match(calls[0].sql, /pg_try_advisory_lock/);
|
|
assert.match(calls[1].sql, /pg_advisory_unlock/);
|
|
assert.deepEqual(calls[0].params, calls[1].params);
|
|
});
|
|
|
|
test('startMemoryMaintenanceScheduler runs all jobs and emits metrics including retries', async () => {
|
|
mock.timers.enable({ apis: ['Date', 'setTimeout', 'setInterval'] });
|
|
|
|
const metrics = [];
|
|
let ingestAttempts = 0;
|
|
|
|
const scheduler = startMemoryMaintenanceScheduler({
|
|
runImmediately: true,
|
|
maxRetries: 2,
|
|
retryDelayMs: 1,
|
|
random: () => 0,
|
|
emitMetric(name, payload) {
|
|
metrics.push({ name, payload });
|
|
},
|
|
lockProvider: {
|
|
async withLock(key, task) {
|
|
if (key.includes('consolidate-observations')) {
|
|
return { acquired: false, result: null };
|
|
}
|
|
return { acquired: true, result: await task() };
|
|
},
|
|
},
|
|
handlers: {
|
|
async ingestRecentRuntimeEvents() {
|
|
ingestAttempts += 1;
|
|
if (ingestAttempts === 1) {
|
|
throw new Error('transient');
|
|
}
|
|
return { itemCount: 3 };
|
|
},
|
|
async consolidateObservations() {
|
|
return { itemCount: 11 };
|
|
},
|
|
async pruningCycle() {
|
|
return { itemCount: 2 };
|
|
},
|
|
async deepMergeArchivalMaintenance() {
|
|
return { itemCount: 1 };
|
|
},
|
|
},
|
|
});
|
|
|
|
// Advance time to allow async jobs and retries to complete.
|
|
// We tick enough to cover the retryDelayMs (1ms).
|
|
// We also need to allow the promise microtask queue to drain between ticks
|
|
// if necessary, but tick() usually handles the timer callbacks.
|
|
// Since the scheduler logic uses await, we need to ensure those promises resolve.
|
|
|
|
// Tick time forward and yield to event loop to allow promise chains to progress.
|
|
// The job involves multiple async steps (lock, handler, retry wait, lock, handler).
|
|
// We tick multiple times to ensure the retry timer fires and subsequent microtasks run.
|
|
for (let i = 0; i < 10; i++) {
|
|
mock.timers.tick(5);
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
}
|
|
|
|
scheduler.stop();
|
|
mock.timers.reset();
|
|
|
|
const byJob = metrics.reduce((acc, entry) => {
|
|
const key = entry.payload.job;
|
|
acc[key] = acc[key] || [];
|
|
acc[key].push(entry);
|
|
return acc;
|
|
}, {});
|
|
|
|
assert.equal(byJob.ingestRecentRuntimeEvents?.length, 1, 'Expected 1 ingest metric');
|
|
assert.equal(byJob.ingestRecentRuntimeEvents[0].payload.status, 'success');
|
|
assert.equal(byJob.ingestRecentRuntimeEvents[0].payload.itemCount, 3);
|
|
assert.equal(byJob.ingestRecentRuntimeEvents[0].payload.retries, 1);
|
|
|
|
assert.equal(byJob.consolidateObservations[0].payload.status, 'skipped_lock_unavailable');
|
|
assert.equal(byJob.pruningCycle[0].payload.status, 'success');
|
|
assert.equal(byJob.deepMergeArchivalMaintenance[0].payload.status, 'success');
|
|
});
|
|
|
|
|
|
test('startMemoryMaintenanceScheduler skips jobs when feature flags disable memory', async () => {
|
|
mock.timers.enable({ apis: ['Date', 'setTimeout', 'setInterval'] });
|
|
|
|
const metrics = [];
|
|
const called = [];
|
|
|
|
const scheduler = startMemoryMaintenanceScheduler({
|
|
runImmediately: true,
|
|
env: { TORCH_MEMORY_ENABLED: 'false' },
|
|
emitMetric(name, payload) {
|
|
metrics.push({ name, payload });
|
|
},
|
|
handlers: {
|
|
async ingestRecentRuntimeEvents() {
|
|
called.push('ingest');
|
|
},
|
|
async consolidateObservations() {
|
|
called.push('consolidate');
|
|
},
|
|
async pruningCycle() {
|
|
called.push('prune');
|
|
},
|
|
async deepMergeArchivalMaintenance() {
|
|
called.push('merge');
|
|
},
|
|
},
|
|
});
|
|
|
|
mock.timers.tick(10);
|
|
await new Promise(resolve => setImmediate(resolve));
|
|
|
|
scheduler.stop();
|
|
mock.timers.reset();
|
|
|
|
assert.deepEqual(called, []);
|
|
assert.ok(metrics.some((entry) => entry.payload.status === 'skipped_flag_disabled'));
|
|
});
|