mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 16:15:39 +00:00
70 lines
2.6 KiB
TypeScript
70 lines
2.6 KiB
TypeScript
/**
|
|
* @vitest-environment node
|
|
*/
|
|
import { existsSync, mkdtempSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import path from 'node:path';
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
// Replicas that start in the setup state each print the setup token. With a
|
|
// shared store (#1066) they must print the same one, and the wizard must
|
|
// accept it on whichever replica the load balancer picks.
|
|
|
|
import { setStoreForTests } from '@/lib/shared-store';
|
|
import { resetLocalStoreForTests } from '@/lib/shared-store/local';
|
|
import { separateFakeStore } from '@/lib/admin/__tests__/shared-store-fake';
|
|
|
|
let dir: string;
|
|
|
|
/** One replica's copy of lib/setup/token.ts. */
|
|
async function replica() {
|
|
vi.resetModules();
|
|
return import('@/lib/setup/token');
|
|
}
|
|
|
|
beforeEach(() => {
|
|
dir = mkdtempSync(path.join(tmpdir(), 'bw-setup-token-'));
|
|
vi.stubEnv('ADMIN_STATE_DIR', path.join(dir, 'state'));
|
|
resetLocalStoreForTests();
|
|
setStoreForTests(separateFakeStore(path.join(dir, 'store')));
|
|
});
|
|
|
|
afterEach(() => {
|
|
setStoreForTests(null);
|
|
resetLocalStoreForTests();
|
|
vi.restoreAllMocks();
|
|
vi.unstubAllEnvs();
|
|
rmSync(dir, { recursive: true, force: true });
|
|
});
|
|
|
|
describe('setup token with a shared store', () => {
|
|
it('gives replicas booting together one token that each of them accepts', async () => {
|
|
const replicas = [await replica(), await replica(), await replica()];
|
|
const tokens = await Promise.all(replicas.map((r) => r.ensureSetupToken()));
|
|
expect(new Set(tokens).size).toBe(1);
|
|
for (const r of replicas) expect(await r.verifySetupToken(tokens[0])).toBe(true);
|
|
expect(await replicas[0].verifySetupToken('0'.repeat(64))).toBe(false);
|
|
expect(existsSync(path.join(dir, 'state', '.setup-token'))).toBe(false);
|
|
});
|
|
|
|
it('keeps the token across restarts within the hour, then issues a new one', async () => {
|
|
const first = await (await replica()).ensureSetupToken();
|
|
expect(await (await replica()).ensureSetupToken()).toBe(first);
|
|
|
|
const now = Date.now();
|
|
vi.spyOn(Date, 'now').mockReturnValue(now + 61 * 60 * 1000);
|
|
const later = await replica();
|
|
expect(await later.verifySetupToken(first)).toBe(false);
|
|
const second = await later.ensureSetupToken();
|
|
expect(second).not.toBe(first);
|
|
expect(await (await replica()).verifySetupToken(second)).toBe(true);
|
|
});
|
|
|
|
it('stops the token working on every replica once the wizard finished on one', async () => {
|
|
const [a, b] = [await replica(), await replica()];
|
|
const token = await a.ensureSetupToken();
|
|
await a.clearSetupToken();
|
|
expect(await b.verifySetupToken(token)).toBe(false);
|
|
});
|
|
});
|