test(integration): take the clock and the probe budget out of two verdict tests

The grant expiry case gave the grant 400 ms and slept 500: on a loaded
runner accepting, signing in and switching took longer than the grant
lived, and the grant expired before it was accepted. The grant now runs
30 seconds and the case moves the clock the resolver reads to the
instant the grant names, so the row still does not change and nothing
sleeps.

The key check's start-up probe is bounded at ten seconds and two per
query. Under load a probe query ran past two seconds and the check
answered inconclusive where the data says mismatch. The verdict tests
now run the check with time to finish; the cases that test the bounds
pass their own budget or sampler and keep them.
This commit is contained in:
Marc-André Bombeck committed 2026-10-22 10:14:03 +02:00
1 parent 0cefac9d68
commit 703c92c776
2 files changed
+48 -4

No files matched your search

@@ -282,21 +282,30 @@ describe("acting-account resolver — the decision is never cached", () => {
const owner = await makeUser("owner");
const delegate = await makeUser("delegate");
await seedWeight(owner.id, 81);
// Far enough ahead that accepting, signing in and switching cannot
// outrun it on a loaded runner, and well inside the session's minute.
const expiresAt = new Date(Date.now() + 30_000);
const invited = await inviteGrant({
grantorId: owner.id,
granteeId: delegate.id,
access: "READ",
scope: null,
expiresAt: new Date(Date.now() + 400),
expiresAt,
});
await acceptGrant({ grantId: invited.id, granteeId: delegate.id });
const session = await signIn(delegate.id);
await switchTo(session.id, owner.id);
expect((await call()).status).toBe(200);
await new Promise((resolve) => setTimeout(resolve, 500));
// The row did not change. Only the clock the resolver reads moved.
expect((await call()).status).toBe(403);
// The row does not change. Only the clock the resolver reads moves, to
// the instant the grant names: the first one it no longer holds.
vi.useFakeTimers({ toFake: ["Date"] });
try {
vi.setSystemTime(expiresAt);
expect((await call()).status).toBe(403);
} finally {
vi.useRealTimers();
}
});
it("refuses the moment the grant is only pending", async () => {
@@ -44,6 +44,41 @@ vi.mock("@/lib/db-compat", () => ({
ensureDbCompatibility: vi.fn().mockResolvedValue(undefined),
}));
/**
* The start-up probe is bounded in time on purpose: ten seconds in all and
* two per query, so a host with a huge table still starts. Those bounds are
* not what this file asks about. On a loaded runner a probe query can take
* longer than two seconds, and the check then answers "inconclusive"
* (`incomplete`) where the data says "mismatch", which is the right answer
* for a slow host and the wrong one for a test of the verdicts. So the check
* runs here with time to finish, unless a case passes its own budget or
* sampler: the cases that test the bounds themselves do.
*/
vi.mock("@/lib/crypto/canary", async (importOriginal) => {
const actual = await importOriginal<typeof import("@/lib/crypto/canary")>();
return {
...actual,
checkEncryptionKeyCanaries: (
client: Parameters<typeof actual.checkEncryptionKeyCanaries>[0],
options: Parameters<typeof actual.checkEncryptionKeyCanaries>[1] = {},
) => {
let sampler;
try {
sampler = actual.sqlColumnSampler(client, {
statementTimeoutMs: 60_000,
});
} catch {
// A client the sampler cannot use: the check reports that itself.
}
return actual.checkEncryptionKeyCanaries(client, {
probeBudgetMs: 120_000,
...(sampler ? { sampler } : {}),
...options,
});
},
};
});
import {
_resetCryptoCacheForTests,
encrypt,