test(db): release gated transactions in finally so a red assertion holds no lock
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
08946e6d08
commit
8efe99aa20
1 changed files with 37 additions and 25 deletions
|
|
@ -130,11 +130,15 @@ describe("db serialization (database-locked fix)", () => {
|
||||||
await tx.execute("COMMIT");
|
await tx.execute("COMMIT");
|
||||||
await gate;
|
await gate;
|
||||||
});
|
});
|
||||||
|
try {
|
||||||
await vi.waitFor(() => expect(events).toContain("end:COMMIT"));
|
await vi.waitFor(() => expect(events).toContain("end:COMMIT"));
|
||||||
expect(events).not.toContain("start:NESTED");
|
expect(events).not.toContain("start:NESTED");
|
||||||
|
} finally {
|
||||||
|
// Released even on failure, so a red assertion leaves no held lock.
|
||||||
release();
|
release();
|
||||||
await txn;
|
await txn;
|
||||||
await nested;
|
await nested;
|
||||||
|
}
|
||||||
expect(events).toEqual(["start:BEGIN", "end:BEGIN", "start:COMMIT", "end:COMMIT", "start:NESTED", "end:NESTED"]);
|
expect(events).toEqual(["start:BEGIN", "end:BEGIN", "start:COMMIT", "end:COMMIT", "start:NESTED", "end:NESTED"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -358,6 +362,7 @@ describe("blocking alert (#408)", () => {
|
||||||
nested = (await getDb()).execute("NESTED");
|
nested = (await getDb()).execute("NESTED");
|
||||||
await gate;
|
await gate;
|
||||||
});
|
});
|
||||||
|
try {
|
||||||
await vi.advanceTimersByTimeAsync(BLOCKED_ALERT_MS - 1);
|
await vi.advanceTimersByTimeAsync(BLOCKED_ALERT_MS - 1);
|
||||||
expect(logWarn).not.toHaveBeenCalled();
|
expect(logWarn).not.toHaveBeenCalled();
|
||||||
await vi.advanceTimersByTimeAsync(1);
|
await vi.advanceTimersByTimeAsync(1);
|
||||||
|
|
@ -368,10 +373,12 @@ describe("blocking alert (#408)", () => {
|
||||||
// Once per operation: still one warning much later.
|
// Once per operation: still one warning much later.
|
||||||
await vi.advanceTimersByTimeAsync(BLOCKED_ALERT_MS * 3);
|
await vi.advanceTimersByTimeAsync(BLOCKED_ALERT_MS * 3);
|
||||||
expect(logWarn).toHaveBeenCalledTimes(1);
|
expect(logWarn).toHaveBeenCalledTimes(1);
|
||||||
|
} finally {
|
||||||
release();
|
release();
|
||||||
await vi.advanceTimersByTimeAsync(10);
|
await vi.advanceTimersByTimeAsync(10);
|
||||||
await txn;
|
await txn;
|
||||||
await nested;
|
await nested;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("says nothing for an operation that got the lock in time", async () => {
|
it("says nothing for an operation that got the lock in time", async () => {
|
||||||
|
|
@ -393,12 +400,17 @@ describe("blocking alert (#408)", () => {
|
||||||
const switching = connectToProfile("next.db");
|
const switching = connectToProfile("next.db");
|
||||||
// Settled outcome caught at once: the rejection lands while timers advance.
|
// Settled outcome caught at once: the rejection lands while timers advance.
|
||||||
const waiting = withTransaction(async () => "late").catch((e: unknown) => e);
|
const waiting = withTransaction(async () => "late").catch((e: unknown) => e);
|
||||||
|
try {
|
||||||
await vi.advanceTimersByTimeAsync(BLOCKED_ALERT_MS);
|
await vi.advanceTimersByTimeAsync(BLOCKED_ALERT_MS);
|
||||||
expect(logWarn).toHaveBeenCalledTimes(1);
|
expect(logWarn).toHaveBeenCalledTimes(1);
|
||||||
expect(String(vi.mocked(logWarn).mock.calls[0][0])).toContain("a transaction has waited 15 s, the lock is held by a profile opening");
|
expect(String(vi.mocked(logWarn).mock.calls[0][0])).toContain(
|
||||||
|
"a transaction has waited 15 s, the lock is held by a profile opening"
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
finish();
|
finish();
|
||||||
await vi.advanceTimersByTimeAsync(10);
|
await vi.advanceTimersByTimeAsync(10);
|
||||||
await switching;
|
await switching;
|
||||||
|
}
|
||||||
expect(await waiting).toBeInstanceOf(DbConnectionClosedError);
|
expect(await waiting).toBeInstanceOf(DbConnectionClosedError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue