Files
RedditBot/tests/control-auth.test.ts
T

107 lines
3.8 KiB
TypeScript

import express from 'express';
import type { AddressInfo } from 'node:net';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { createControlRouter } from '../src/web/routes/control.js';
const servers: Array<ReturnType<express.Express['listen']>> = [];
afterEach(async () => {
await Promise.all(servers.splice(0).map(
(server) => new Promise<void>((resolve) => server.close(() => resolve())),
));
});
describe('bot control account authentication gate', () => {
it('refuses to start the bot until full account authentication', async () => {
const setBotRunning = vi.fn();
const app = express();
app.use(createControlRouter({
services: {
accountAuth: {
isFullyAuthenticated: () => false,
ensureFullyAuthenticated: vi.fn(async () => false),
},
},
setBotRunning,
activity: { push: vi.fn() },
logger: { warn: vi.fn(), info: vi.fn() },
} as never));
const server = app.listen(0);
servers.push(server);
await new Promise<void>((resolve) => server.once('listening', resolve));
const { port } = server.address() as AddressInfo;
const response = await fetch(`http://127.0.0.1:${port}/start`, { method: 'POST' });
expect(response.status).toBe(409);
expect(await response.json()).toMatchObject({ success: false, authenticated: false });
expect(setBotRunning).not.toHaveBeenCalled();
});
it('renews an expired authentication lease before starting the bot', async () => {
let running = false;
const ensureFullyAuthenticated = vi.fn(async () => true);
const app = express();
app.use(createControlRouter({
config: { browser: { dryRun: false } },
services: {
accountAuth: {
isFullyAuthenticated: () => false,
ensureFullyAuthenticated,
},
},
getBotRunning: () => running,
setBotRunning: (next: boolean) => { running = next; },
activity: { push: vi.fn() },
logger: { warn: vi.fn(), info: vi.fn() },
broadcaster: { dashboardEvents: { bot: vi.fn() } },
} as never));
const server = app.listen(0);
servers.push(server);
await new Promise<void>((resolve) => server.once('listening', resolve));
const { port } = server.address() as AddressInfo;
const response = await fetch(`http://127.0.0.1:${port}/start`, { method: 'POST' });
expect(response.status).toBe(200);
expect(await response.json()).toMatchObject({ success: true, running: true });
expect(ensureFullyAuthenticated).toHaveBeenCalledOnce();
expect(running).toBe(true);
});
it('renews a running account runtime when the legacy auth context is unavailable', async () => {
let running = false;
const ensureFullyAuthenticated = vi.fn(async () => true);
const runtime = {
resources: {
accountAuth: { isFullyAuthenticated: () => false, ensureFullyAuthenticated },
},
};
const app = express();
app.use(createControlRouter({
config: { browser: { dryRun: false } },
services: {
accountRuntimes: {
list: () => [{ accountId: '@t2_account:reddit.com', state: 'running' }],
get: () => runtime,
},
},
getBotRunning: () => running,
setBotRunning: (next: boolean) => { running = next; },
activity: { push: vi.fn() },
logger: { warn: vi.fn(), info: vi.fn() },
broadcaster: { dashboardEvents: { bot: vi.fn() } },
} as never));
const server = app.listen(0);
servers.push(server);
await new Promise<void>((resolve) => server.once('listening', resolve));
const { port } = server.address() as AddressInfo;
const response = await fetch(`http://127.0.0.1:${port}/start`, { method: 'POST' });
expect(response.status).toBe(200);
expect(ensureFullyAuthenticated).toHaveBeenCalledOnce();
expect(running).toBe(true);
});
});