feat: F5.1 server F keeps the shared documents
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>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user