A new package, packages/server: Hocuspocus 3.4.4 on /sync, a project a document, refused with a reason when the store has not got it; every update stored in Postgres as it comes and compacted after 500 updates, a minute of quiet and when the last person leaves (FOR UPDATE on the row written when the project is made); the janitor runs only here, at loading and 250 ms after a change that is not its own; readers change nothing; /healthz; JSON log. On closing it takes no one new and closes the sockets too (Hocuspocus' close is a message after which a client signs in again on the same socket). The tests use real clients against a throwaway Postgres in Docker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
// A Postgres of its own for the server's tests: FILIUS_TEST_DATABASE_URL
|
|
// when it is set, else a throwaway container of the postgres image (Docker),
|
|
// stopped and gone after the tests. Never a database of the dashboard.
|
|
|
|
import { execFileSync } from 'node:child_process';
|
|
import pg from 'pg';
|
|
|
|
export interface TestDatabase {
|
|
readonly url: string;
|
|
stop(): Promise<void>;
|
|
}
|
|
|
|
export async function testDatabase(): Promise<TestDatabase> {
|
|
const given = process.env.FILIUS_TEST_DATABASE_URL;
|
|
if (given !== undefined) return { url: given, stop: async () => {} };
|
|
const name = `filius-test-pg-${process.pid}-${Date.now()}`;
|
|
execFileSync('docker', ['run', '-d', '--rm', '--name', name, '-e', 'POSTGRES_PASSWORD=filius', '-e', 'POSTGRES_DB=filius', '-p', '127.0.0.1::5432', 'postgres:16-alpine'], { stdio: 'pipe' });
|
|
const stop = async () => {
|
|
execFileSync('docker', ['stop', name], { stdio: 'pipe' });
|
|
};
|
|
try {
|
|
const port = execFileSync('docker', ['port', name, '5432/tcp']).toString().trim().split('\n')[0]!.split(':').pop();
|
|
const url = `postgres://postgres:filius@127.0.0.1:${port}/filius`;
|
|
// The image's first start runs a server on its socket only; the TCP port answers once the real one is up.
|
|
for (let tries = 0; ; tries++) {
|
|
const client = new pg.Client({ connectionString: url });
|
|
try {
|
|
await client.connect();
|
|
await client.query('SELECT 1');
|
|
await client.end();
|
|
return { url, stop };
|
|
} catch (error) {
|
|
await client.end().catch(() => {});
|
|
if (tries > 120) throw error;
|
|
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
}
|
|
}
|
|
} catch (error) {
|
|
await stop();
|
|
throw error;
|
|
}
|
|
}
|