From d41590ac0e111e9730e2a44e021df2a1ac8052fe Mon Sep 17 00:00:00 2001 From: Dotta Date: Sat, 24 Oct 2026 09:47:38 -0700 Subject: [PATCH] test: verify secret expiry settlement and concurrent producer writes Co-Authored-By: Paperclip --- .../__tests__/secret-proposals-routes.test.ts | 26 +++++++++++++++++-- .../server-startup-feedback-export.test.ts | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/server/src/__tests__/secret-proposals-routes.test.ts b/server/src/__tests__/secret-proposals-routes.test.ts index 0ae0403106b..5d24de6dbb2 100644 --- a/server/src/__tests__/secret-proposals-routes.test.ts +++ b/server/src/__tests__/secret-proposals-routes.test.ts @@ -1,3 +1,4 @@ +import { resolveExternalTestDatabaseUrl } from "./helpers/external-test-database.js"; import { registerSecretProposalExpiryWork } from "../services/secret-proposal-expiry-work.js"; import { createDeliveryWorkCoordinator } from "../services/delivery-work-coordinator.js"; import { idleWorkSnapshot } from "../services/task-admission.js"; @@ -41,7 +42,7 @@ import { startEmbeddedPostgresTestDatabase, } from "./helpers/embedded-postgres.js"; -const externalTestDatabase = process.env.PAPERCLIP_SECRET_PROPOSAL_TEST_DATABASE_URL; +const externalTestDatabase = resolveExternalTestDatabaseUrl("PAPERCLIP_SECRET_PROPOSAL_TEST_DATABASE_URL"); const embeddedPostgresSupport = externalTestDatabase ? { supported: true } : await getEmbeddedPostgresTestSupport(); const describeEmbeddedPostgres = embeddedPostgresSupport.supported ? describe : describe.skip; @@ -312,7 +313,28 @@ describeEmbeddedPostgres("secret proposal routes", () => { } finally { release(); } await writing; await settle(); expect(await proposals.nextExpiryAt()).toEqual(rollback ? null : expect.any(Number)); - expect(coordinator!.nextWakeAt()).toBe(await proposals.nextExpiryAt()); + if (rollback) await quiet(); + else expect(coordinator!.nextWakeAt()).toBe(await proposals.nextExpiryAt()); + }); + + it("retains a proposal committed while an empty deadline read is finishing", async () => { + let release!: () => void, reading!: () => void; + const gate = new Promise(resolve => { release = resolve; }); + const entered = new Promise(resolve => { reading = resolve; }); + const readDeadline = proposals.nextExpiryAt; + vi.spyOn(proposals, "nextExpiryAt").mockImplementationOnce(async () => { + const stale = await readDeadline(); + reading(); await gate; + return stale; + }); + const starting = start(); + await entered; + let secret!: Awaited>; + try { secret = await create(); } finally { release(); } + await starting; await settle(); + expect(coordinator!.nextWakeAt()).toBe(secret.expiresAt.getTime()); + await proposals.transition(fixture.companyId, secret.id, "withdrawn", { proposerAgentId: fixture.agentId }); + await quiet(); }); it("reconstructs a deadline after restart and disarms when the proposer withdraws", async () => { diff --git a/server/src/__tests__/server-startup-feedback-export.test.ts b/server/src/__tests__/server-startup-feedback-export.test.ts index 81c689366c3..e3d29b1435f 100644 --- a/server/src/__tests__/server-startup-feedback-export.test.ts +++ b/server/src/__tests__/server-startup-feedback-export.test.ts @@ -442,6 +442,7 @@ vi.mock("../services/native-runtime/native-question-bridge.js", () => ({ vi.mock("../services/secret-proposals.js", () => ({ createSecretProposalsService: vi.fn(() => ({ + nextExpiryAt: vi.fn(async () => null), sweepExpired: vi.fn(async () => 0), })), }));