mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-03 09:37:19 +01:00
test: expose transport housekeeping in maintenance receipts
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
1aa064babe
commit
5c0b873f8b
3 files changed
+18
-3
No files matched your search
@@ -160,3 +160,10 @@ quiet including the real 90-second window, startup failure isolation and
|
||||
remaining final-recovery lifecycle races, relevant contracts across the combined tree, current-head
|
||||
Greptile 5/5 and required CI. No aggregate-removal acceptance or deployment claim
|
||||
is made by the preliminary harness checkpoint.
|
||||
|
||||
The assembled routine proof also uses ordinary subtree cancel and restore APIs.
|
||||
It requires the same persisted routine run to return to `issue_created`, clears
|
||||
its terminal projection, and retains zero agent executions while suppression
|
||||
remains active. The passive PostgreSQL observer records connection opens, closes
|
||||
and byte counts separately from SQL frames so final quiet receipts can expose
|
||||
connection housekeeping without hiding it in a zero-query total.
|
||||
@@ -69,8 +69,11 @@ export function createPostgresProtocolObserver(onQuery: (query: ObservedQuery) =
|
||||
export async function startMaintenancePostgresProxy(databaseUrl: string) {
|
||||
const upstream = new URL(databaseUrl), queries: ObservedQuery[] = [], errors: Error[] = [];
|
||||
const frames = { Query: 0, Parse: 0, Bind: 0, Execute: 0, Sync: 0 };
|
||||
const transport = { connectionsOpened: 0, connectionsClosed: 0, frontendBytes: 0, backendBytes: 0 };
|
||||
const sockets = new Set<Socket>(), observers = new Set<ReturnType<typeof createPostgresProtocolObserver>>();
|
||||
const server = createServer(client => {
|
||||
transport.connectionsOpened++;
|
||||
client.once("close", () => { transport.connectionsClosed++; });
|
||||
const target = createConnection({ host: upstream.hostname, port: Number(upstream.port) || 5432 });
|
||||
const observer = createPostgresProtocolObserver(query => queries.push(query), type => {
|
||||
if (type === "Q") frames.Query++; else if (type === "P") frames.Parse++; else if (type === "B") frames.Bind++;
|
||||
@@ -82,8 +85,8 @@ export async function startMaintenancePostgresProxy(databaseUrl: string) {
|
||||
socket.on("error", error => { errors.push(error); client.destroy(); target.destroy(); });
|
||||
socket.on("close", () => { sockets.delete(socket); if (client.destroyed && target.destroyed) observers.delete(observer); });
|
||||
}
|
||||
client.on("data", chunk => { try { observer.frontend(chunk); } catch (error) { errors.push(error as Error); client.destroy(); target.destroy(); } });
|
||||
target.on("data", chunk => { try { observer.backend(chunk); } catch (error) { errors.push(error as Error); client.destroy(); target.destroy(); } });
|
||||
client.on("data", chunk => { transport.frontendBytes += chunk.length; try { observer.frontend(chunk); } catch (error) { errors.push(error as Error); client.destroy(); target.destroy(); } });
|
||||
target.on("data", chunk => { transport.backendBytes += chunk.length; try { observer.backend(chunk); } catch (error) { errors.push(error as Error); client.destroy(); target.destroy(); } });
|
||||
client.pipe(target); target.pipe(client);
|
||||
client.on("end", () => target.end()); target.on("end", () => client.end());
|
||||
});
|
||||
@@ -94,6 +97,7 @@ export async function startMaintenancePostgresProxy(databaseUrl: string) {
|
||||
return {
|
||||
url: url.toString(), queries, errors,
|
||||
get frames() { return { ...frames }; },
|
||||
get transport() { return { ...transport }; },
|
||||
get pending() { return [...observers].reduce((sum, observer) => sum + observer.pending, 0); },
|
||||
async stop() {
|
||||
for (const socket of sockets) socket.destroy();
|
||||
|
||||
@@ -67,9 +67,13 @@ describe("maintenance observer against PostgreSQL", () => {
|
||||
expect(proxy.queries.some(query => /rollback/i.test(query.sql))).toBe(true);
|
||||
expect(proxy.pending).toBe(0);
|
||||
expect(proxy.errors).toEqual([]);
|
||||
const before = proxy.queries.length;
|
||||
expect(proxy.transport).toMatchObject({ connectionsOpened: 1, connectionsClosed: 0 });
|
||||
expect(proxy.transport.frontendBytes).toBeGreaterThan(0);
|
||||
expect(proxy.transport.backendBytes).toBeGreaterThan(0);
|
||||
const before = proxy.queries.length, transport = proxy.transport;
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
expect(proxy.queries.length).toBe(before);
|
||||
expect(proxy.transport).toEqual(transport);
|
||||
} finally { await db.$client.end(); await proxy.stop(); }
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user