Add Prettier and ESLint tooling (Refs #77)
This commit is contained in:
@@ -5,19 +5,31 @@ import { STATUS_REFRESH_MS } from '../../src/lib/server-freshness.js';
|
||||
vi.mock('../../src/lib/server/pipeline/sweep.js', () => ({ sweep: vi.fn() }));
|
||||
vi.mock('../../src/lib/server/pipeline/beta-runner.js', () => ({ betaTick: vi.fn() }));
|
||||
vi.mock('../../src/lib/server/maintenance/index.js', () => ({ runMaintenance: vi.fn() }));
|
||||
vi.mock('../../src/lib/server/game-files/index.js', () => ({ cleanupControllerLibraries: vi.fn(async () => {}) }));
|
||||
vi.mock('../../src/lib/server/provisioning/worker.js', () => ({ processProvisioning: vi.fn(async () => {}) }));
|
||||
vi.mock('../../src/lib/server/game-files/index.js', () => ({
|
||||
cleanupControllerLibraries: vi.fn(async () => {})
|
||||
}));
|
||||
vi.mock('../../src/lib/server/provisioning/worker.js', () => ({
|
||||
processProvisioning: vi.fn(async () => {})
|
||||
}));
|
||||
vi.mock('../../src/lib/server/retention.js', () => ({ drainRetention: vi.fn(async () => 0) }));
|
||||
vi.mock('../../src/lib/server/fleet/chat.js', () => ({ collectFleetChat: vi.fn(async () => {}) }));
|
||||
|
||||
function deferred() {
|
||||
let resolve!: () => void;
|
||||
const promise = new Promise<void>(done => { resolve = done; });
|
||||
const promise = new Promise<void>((done) => {
|
||||
resolve = done;
|
||||
});
|
||||
return { promise, resolve };
|
||||
}
|
||||
let fixture: Fixture;
|
||||
beforeEach(async () => { vi.resetModules(); vi.clearAllMocks(); fixture = await newFixture([]); });
|
||||
afterEach(async () => { await fixture.cleanup(); });
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
fixture = await newFixture([]);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await fixture.cleanup();
|
||||
});
|
||||
|
||||
async function setup() {
|
||||
const { sweep } = await import('../../src/lib/server/pipeline/sweep.js');
|
||||
@@ -30,40 +42,59 @@ async function setup() {
|
||||
const { processProvisioning } = await import('../../src/lib/server/provisioning/worker.js');
|
||||
const worker = await import('../../src/lib/server/pipeline/worker.js');
|
||||
const { workerActivity } = await import('../../src/lib/server/pipeline/activity.js');
|
||||
return { ...worker, workerActivity, background, process: vi.mocked(processProvisioning), sweep, betaTick, runMaintenance };
|
||||
return {
|
||||
...worker,
|
||||
workerActivity,
|
||||
background,
|
||||
process: vi.mocked(processProvisioning),
|
||||
sweep,
|
||||
betaTick,
|
||||
runMaintenance
|
||||
};
|
||||
}
|
||||
|
||||
describe('independent provisioning scheduling', () => {
|
||||
it.each(['startup', 'scheduled'] as const)('logs a failed %s status snapshot and retries on the next interval', async phase => {
|
||||
const s = await setup();
|
||||
const { MonitoringSnapshot } = await import('../../src/lib/server/fleet/monitoring-snapshot.js');
|
||||
const refresh = vi.spyOn(MonitoringSnapshot.prototype, 'refresh');
|
||||
const log = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const failure = new Error('database or disk is full');
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
if (phase === 'scheduled') {
|
||||
s.startWorker();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
refresh.mockClear();
|
||||
}
|
||||
refresh.mockImplementationOnce(() => { throw failure; });
|
||||
if (phase === 'startup') s.startWorker();
|
||||
await vi.advanceTimersByTimeAsync(phase === 'startup' ? 0 : STATUS_REFRESH_MS);
|
||||
expect(refresh).toHaveBeenCalledTimes(1);
|
||||
expect(log).toHaveBeenCalledExactlyOnceWith('[worker] status fanout error:', failure);
|
||||
it.each(['startup', 'scheduled'] as const)(
|
||||
'logs a failed %s status snapshot and retries on the next interval',
|
||||
async (phase) => {
|
||||
const s = await setup();
|
||||
const { MonitoringSnapshot } =
|
||||
await import('../../src/lib/server/fleet/monitoring-snapshot.js');
|
||||
const refresh = vi.spyOn(MonitoringSnapshot.prototype, 'refresh');
|
||||
const log = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const failure = new Error('database or disk is full');
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
if (phase === 'scheduled') {
|
||||
s.startWorker();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
refresh.mockClear();
|
||||
}
|
||||
refresh.mockImplementationOnce(() => {
|
||||
throw failure;
|
||||
});
|
||||
if (phase === 'startup') s.startWorker();
|
||||
await vi.advanceTimersByTimeAsync(phase === 'startup' ? 0 : STATUS_REFRESH_MS);
|
||||
expect(refresh).toHaveBeenCalledTimes(1);
|
||||
expect(log).toHaveBeenCalledExactlyOnceWith(
|
||||
'[worker] status fanout error:',
|
||||
failure
|
||||
);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(STATUS_REFRESH_MS);
|
||||
expect(refresh).toHaveBeenCalledTimes(2);
|
||||
expect(log).toHaveBeenCalledTimes(1);
|
||||
} finally {
|
||||
s.stopWorker(); s.background.resolve();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
vi.useRealTimers();
|
||||
refresh.mockRestore(); log.mockRestore();
|
||||
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
|
||||
await vi.advanceTimersByTimeAsync(STATUS_REFRESH_MS);
|
||||
expect(refresh).toHaveBeenCalledTimes(2);
|
||||
expect(log).toHaveBeenCalledTimes(1);
|
||||
} finally {
|
||||
s.stopWorker();
|
||||
s.background.resolve();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
vi.useRealTimers();
|
||||
refresh.mockRestore();
|
||||
log.mockRestore();
|
||||
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
it('collects match chat on worker ticks without overlapping a slow collection', async () => {
|
||||
const s = await setup();
|
||||
@@ -81,7 +112,9 @@ describe('independent provisioning scheduling', () => {
|
||||
await vi.advanceTimersByTimeAsync(15_000);
|
||||
expect(collectFleetChat).toHaveBeenCalledTimes(2);
|
||||
} finally {
|
||||
s.stopWorker(); collection.resolve(); s.background.resolve();
|
||||
s.stopWorker();
|
||||
collection.resolve();
|
||||
s.background.resolve();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
vi.useRealTimers();
|
||||
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
|
||||
@@ -102,7 +135,8 @@ describe('independent provisioning scheduling', () => {
|
||||
expect(drainRetention).toHaveBeenCalledTimes(2);
|
||||
expect(s.process.mock.calls.length).toBeGreaterThan(2);
|
||||
} finally {
|
||||
s.stopWorker(); s.background.resolve();
|
||||
s.stopWorker();
|
||||
s.background.resolve();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
vi.useRealTimers();
|
||||
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
|
||||
@@ -113,7 +147,10 @@ describe('independent provisioning scheduling', () => {
|
||||
const s = await setup();
|
||||
const { drainRetention } = await import('../../src/lib/server/retention.js');
|
||||
const cleanup = deferred();
|
||||
vi.mocked(drainRetention).mockImplementationOnce(async () => { await cleanup.promise; return 1501; });
|
||||
vi.mocked(drainRetention).mockImplementationOnce(async () => {
|
||||
await cleanup.promise;
|
||||
return 1501;
|
||||
});
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
s.startWorker();
|
||||
@@ -123,7 +160,9 @@ describe('independent provisioning scheduling', () => {
|
||||
cleanup.resolve();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
} finally {
|
||||
s.stopWorker(); cleanup.resolve(); s.background.resolve();
|
||||
s.stopWorker();
|
||||
cleanup.resolve();
|
||||
s.background.resolve();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
vi.useRealTimers();
|
||||
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
|
||||
@@ -132,7 +171,8 @@ describe('independent provisioning scheduling', () => {
|
||||
|
||||
it('runs controller library cleanup on worker ticks without overlapping a slow cleanup', async () => {
|
||||
const s = await setup();
|
||||
const { cleanupControllerLibraries } = await import('../../src/lib/server/game-files/index.js');
|
||||
const { cleanupControllerLibraries } =
|
||||
await import('../../src/lib/server/game-files/index.js');
|
||||
const cleanup = deferred();
|
||||
vi.mocked(cleanupControllerLibraries).mockImplementationOnce(() => cleanup.promise);
|
||||
vi.useFakeTimers();
|
||||
@@ -147,7 +187,9 @@ describe('independent provisioning scheduling', () => {
|
||||
await vi.advanceTimersByTimeAsync(15_000);
|
||||
expect(cleanupControllerLibraries).toHaveBeenCalledTimes(2);
|
||||
} finally {
|
||||
s.stopWorker(); cleanup.resolve(); s.background.resolve();
|
||||
s.stopWorker();
|
||||
cleanup.resolve();
|
||||
s.background.resolve();
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
vi.useRealTimers();
|
||||
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
|
||||
@@ -159,7 +201,9 @@ describe('independent provisioning scheduling', () => {
|
||||
try {
|
||||
await s.kick();
|
||||
expect(s.process).toHaveBeenCalledTimes(1);
|
||||
expect(s.workerActivity().map(work => work.key)).toEqual(expect.arrayContaining(['campaign', 'beta', 'maintenance']));
|
||||
expect(s.workerActivity().map((work) => work.key)).toEqual(
|
||||
expect.arrayContaining(['campaign', 'beta', 'maintenance'])
|
||||
);
|
||||
await s.kick();
|
||||
expect(s.process).toHaveBeenCalledTimes(2);
|
||||
expect(s.sweep).toHaveBeenCalledTimes(1);
|
||||
@@ -184,7 +228,8 @@ describe('independent provisioning scheduling', () => {
|
||||
await Promise.all([first, second, receipt]);
|
||||
expect(s.process).toHaveBeenCalledTimes(2);
|
||||
} finally {
|
||||
busy.resolve(); s.background.resolve();
|
||||
busy.resolve();
|
||||
s.background.resolve();
|
||||
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user