mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-28 16:31:56 +00:00
Refactor `cmdCheck` in `src/cmd-check.mjs` to support dependency injection for better testability. Add `test/cmd-check.test.mjs` with comprehensive unit tests for `cmdCheck`, covering happy paths and edge cases. Verify tests pass with `node --test test/cmd-check.test.mjs`. Co-authored-by: PR0M3TH3AN <[email protected]>
188 lines
6.4 KiB
JavaScript
188 lines
6.4 KiB
JavaScript
import { describe, it, mock, afterEach, after } from 'node:test';
|
|
import assert from 'node:assert';
|
|
import { cmdCheck } from '../src/cmd-check.mjs';
|
|
|
|
// Mocks
|
|
const mockLoadTorchConfig = mock.fn(() => ({
|
|
scheduler: {
|
|
paused: {
|
|
daily: [],
|
|
weekly: [],
|
|
},
|
|
},
|
|
}));
|
|
const mockGetRelays = mock.fn(() => ['wss://mock-relay']);
|
|
const mockGetNamespace = mock.fn(() => 'mock-namespace');
|
|
const mockGetRoster = mock.fn(() => []);
|
|
const mockQueryLocks = mock.fn(async () => []);
|
|
const mockTodayDateStr = mock.fn(() => '2023-10-27');
|
|
|
|
const deps = {
|
|
loadTorchConfigFn: mockLoadTorchConfig,
|
|
getRelaysFn: mockGetRelays,
|
|
getNamespaceFn: mockGetNamespace,
|
|
getRosterFn: mockGetRoster,
|
|
queryLocksFn: mockQueryLocks,
|
|
todayDateStrFn: mockTodayDateStr,
|
|
};
|
|
|
|
describe('cmdCheck', () => {
|
|
// Capture console output
|
|
const originalConsoleLog = console.log;
|
|
const originalConsoleError = console.error;
|
|
let consoleLogOutput = [];
|
|
let consoleErrorOutput = [];
|
|
|
|
const mockConsoleLog = mock.fn((msg) => {
|
|
consoleLogOutput.push(msg);
|
|
});
|
|
const mockConsoleError = mock.fn((msg) => {
|
|
consoleErrorOutput.push(msg);
|
|
});
|
|
|
|
// Setup console mocks
|
|
console.log = mockConsoleLog;
|
|
console.error = mockConsoleError;
|
|
|
|
afterEach(() => {
|
|
// Reset mocks
|
|
mockLoadTorchConfig.mock.resetCalls();
|
|
mockGetRelays.mock.resetCalls();
|
|
mockGetNamespace.mock.resetCalls();
|
|
mockGetRoster.mock.resetCalls();
|
|
mockQueryLocks.mock.resetCalls();
|
|
mockTodayDateStr.mock.resetCalls();
|
|
|
|
// Clear captured output
|
|
consoleLogOutput = [];
|
|
consoleErrorOutput = [];
|
|
});
|
|
|
|
// Restore console after all tests
|
|
after(() => {
|
|
console.log = originalConsoleLog;
|
|
console.error = originalConsoleError;
|
|
});
|
|
|
|
it('correctly reports available agents when no locks exist', async () => {
|
|
mockGetRoster.mock.mockImplementation(() => ['agent1', 'agent2']);
|
|
mockQueryLocks.mock.mockImplementation(async () => []);
|
|
mockLoadTorchConfig.mock.mockImplementation(() => ({
|
|
scheduler: { paused: { daily: [] } }
|
|
}));
|
|
|
|
const result = await cmdCheck('daily', deps);
|
|
|
|
assert.strictEqual(result.cadence, 'daily');
|
|
assert.strictEqual(result.namespace, 'mock-namespace');
|
|
assert.strictEqual(result.date, '2023-10-27');
|
|
assert.deepStrictEqual(result.available, ['agent1', 'agent2']);
|
|
assert.deepStrictEqual(result.locked, []);
|
|
assert.deepStrictEqual(result.paused, []);
|
|
assert.deepStrictEqual(result.excluded, []);
|
|
assert.strictEqual(result.lockCount, 0);
|
|
|
|
// Verify console output was JSON
|
|
assert.strictEqual(consoleLogOutput.length, 1);
|
|
const logOutput = JSON.parse(consoleLogOutput[0]);
|
|
assert.deepStrictEqual(logOutput.available, ['agent1', 'agent2']);
|
|
});
|
|
|
|
it('correctly identifies locked agents', async () => {
|
|
mockGetRoster.mock.mockImplementation(() => ['agent1', 'agent2', 'agent3']);
|
|
mockQueryLocks.mock.mockImplementation(async () => [
|
|
{ agent: 'agent1', eventId: 'evt1', createdAtIso: '2023-10-27T00:00:00Z', expiresAtIso: '2023-10-27T01:00:00Z', platform: 'linux' }
|
|
]);
|
|
mockLoadTorchConfig.mock.mockImplementation(() => ({
|
|
scheduler: { paused: { daily: [] } }
|
|
}));
|
|
|
|
const result = await cmdCheck('daily', deps);
|
|
|
|
assert.deepStrictEqual(result.available, ['agent2', 'agent3']);
|
|
assert.deepStrictEqual(result.locked, ['agent1']);
|
|
assert.deepStrictEqual(result.excluded, ['agent1']);
|
|
assert.strictEqual(result.lockCount, 1);
|
|
assert.strictEqual(result.locks[0].agent, 'agent1');
|
|
});
|
|
|
|
it('correctly identifies paused agents', async () => {
|
|
mockGetRoster.mock.mockImplementation(() => ['agent1', 'agent2', 'agent3']);
|
|
mockQueryLocks.mock.mockImplementation(async () => []);
|
|
mockLoadTorchConfig.mock.mockImplementation(() => ({
|
|
scheduler: { paused: { daily: ['agent2'] } }
|
|
}));
|
|
|
|
const result = await cmdCheck('daily', deps);
|
|
|
|
assert.deepStrictEqual(result.available, ['agent1', 'agent3']);
|
|
assert.deepStrictEqual(result.locked, []);
|
|
assert.deepStrictEqual(result.paused, ['agent2']);
|
|
assert.deepStrictEqual(result.excluded, ['agent2']);
|
|
});
|
|
|
|
it('handles agents that are both locked and paused', async () => {
|
|
mockGetRoster.mock.mockImplementation(() => ['agent1', 'agent2']);
|
|
mockQueryLocks.mock.mockImplementation(async () => [
|
|
{ agent: 'agent1', eventId: 'evt1' }
|
|
]);
|
|
mockLoadTorchConfig.mock.mockImplementation(() => ({
|
|
scheduler: { paused: { daily: ['agent1'] } }
|
|
}));
|
|
|
|
const result = await cmdCheck('daily', deps);
|
|
|
|
assert.deepStrictEqual(result.available, ['agent2']);
|
|
assert.deepStrictEqual(result.locked, ['agent1']);
|
|
assert.deepStrictEqual(result.paused, ['agent1']);
|
|
// excluded should contain unique agents
|
|
assert.deepStrictEqual(result.excluded, ['agent1']);
|
|
});
|
|
|
|
it('identifies unknown locked agents (not in roster)', async () => {
|
|
mockGetRoster.mock.mockImplementation(() => ['agent1']);
|
|
mockQueryLocks.mock.mockImplementation(async () => [
|
|
{ agent: 'agent1', eventId: 'evt1' },
|
|
{ agent: 'unknown-agent', eventId: 'evt2' }
|
|
]);
|
|
mockLoadTorchConfig.mock.mockImplementation(() => ({
|
|
scheduler: { paused: { daily: [] } }
|
|
}));
|
|
|
|
const result = await cmdCheck('daily', deps);
|
|
|
|
assert.deepStrictEqual(result.available, []);
|
|
assert.deepStrictEqual(result.locked, ['agent1', 'unknown-agent']);
|
|
assert.deepStrictEqual(result.unknownLockedAgents, ['unknown-agent']);
|
|
assert.deepStrictEqual(result.excluded, ['agent1', 'unknown-agent']);
|
|
});
|
|
|
|
it('handles weekly cadence', async () => {
|
|
mockGetRoster.mock.mockImplementation(() => ['weekly1', 'weekly2']);
|
|
mockQueryLocks.mock.mockImplementation(async () => []);
|
|
mockLoadTorchConfig.mock.mockImplementation(() => ({
|
|
scheduler: { paused: { weekly: ['weekly2'] } }
|
|
}));
|
|
|
|
const result = await cmdCheck('weekly', deps);
|
|
|
|
assert.strictEqual(result.cadence, 'weekly');
|
|
assert.deepStrictEqual(result.available, ['weekly1']);
|
|
assert.deepStrictEqual(result.paused, ['weekly2']);
|
|
});
|
|
|
|
it('handles empty roster', async () => {
|
|
mockGetRoster.mock.mockImplementation(() => []);
|
|
mockQueryLocks.mock.mockImplementation(async () => []);
|
|
mockLoadTorchConfig.mock.mockImplementation(() => ({
|
|
scheduler: { paused: { daily: [] } }
|
|
}));
|
|
|
|
const result = await cmdCheck('daily', deps);
|
|
|
|
assert.deepStrictEqual(result.available, []);
|
|
assert.deepStrictEqual(result.locked, []);
|
|
assert.deepStrictEqual(result.paused, []);
|
|
});
|
|
});
|