test/shared/database-key-races.test.ts
Rama main · réplica de lectura del repositorio original.
import { expect } from "@std/expect";
import { it as test } from "@std/testing/bdd";
import { stub } from "@std/testing/mock";
import { FakeTime } from "@std/testing/time";
import type { BuiltSite } from "#db/built-sites/types.ts";
import {
insertBuiltSite,
requireBuiltSiteByIdPrimary,
} from "#db/built-sites.ts";
import { bunnyCdnApi } from "#shared/bunny-cdn.ts";
import { bunnyDbProvider } from "#shared/bunny-db.ts";
import {
completeDatabaseKeyRotation,
startDatabaseKeyRotation,
} from "#shared/database-key-rotation.ts";
import { okResult, requireSuccess } from "#shared/result.ts";
import { describeWithEnv } from "#test-utils/db.ts";
import { withMocks } from "#test-utils/mocks.ts";
const START_MS = 1_700_000_000_000;
type ProviderSteps = Partial<{
invalidate: typeof bunnyDbProvider.invalidateDatabaseTokens;
issue: typeof bunnyDbProvider.issueDatabaseToken;
push: typeof bunnyCdnApi.setEdgeScriptSecret;
}>;
interface RotationObservations {
clock: FakeTime;
issued: { calls: readonly unknown[] };
removed: { calls: readonly unknown[] };
}
/** Each test can hold one provider boundary while it sends another command. */
const rotationFakes = (steps: ProviderSteps) => ({
clock: new FakeTime(START_MS),
issued: stub(
bunnyDbProvider,
"issueDatabaseToken",
steps.issue ?? (() => Promise.resolve(okResult("new-key"))),
),
pushed: stub(
bunnyCdnApi,
"setEdgeScriptSecret",
steps.push ?? (() => Promise.resolve(okResult(undefined))),
),
removed: stub(
bunnyDbProvider,
"invalidateDatabaseTokens",
steps.invalidate ?? (() => Promise.resolve(okResult(undefined))),
),
});
const withRotation = (
steps: ProviderSteps,
run: (site: BuiltSite, fakes: RotationObservations) => Promise<void>,
): Promise<void> =>
withMocks(
() => rotationFakes(steps),
async (fakes) => {
const { id } = await insertBuiltSite(
"Race site",
"https://race.test",
"libsql://race.lite.bunnydb.net",
"old-key",
false,
"9100",
);
await run(await requireBuiltSiteByIdPrimary(id), fakes);
},
);
describeWithEnv(
"database key provider races",
{
db: true,
env: { BUNNY_API_KEY: "host-key" },
},
() => {
test("does not issue while a newer invalidation is in flight", async () => {
const entered = Promise.withResolvers<void>();
const release = Promise.withResolvers<void>();
let removals = 0;
await withRotation(
{
invalidate: async () => {
if (++removals === 2) {
entered.resolve();
await release.promise;
}
return okResult(undefined);
},
},
async (site, { clock, issued }) => {
const first = requireSuccess(await startDatabaseKeyRotation(site));
clock.tick(60_000);
const second = startDatabaseKeyRotation(site);
await entered.promise;
try {
const completed = await completeDatabaseKeyRotation(site, first);
expect([completed.ok, issued.calls.length]).toEqual([false, 0]);
} finally {
release.resolve();
await second;
}
},
);
});
test("keeps the claim until the host receives its key", async () => {
const entered = Promise.withResolvers<void>();
const release = Promise.withResolvers<void>();
await withRotation(
{
push: async () => {
entered.resolve();
await release.promise;
return okResult(undefined);
},
},
async (site, { clock, removed }) => {
const started = requireSuccess(await startDatabaseKeyRotation(site));
clock.tick(60_000);
const completion = completeDatabaseKeyRotation(site, started);
await entered.promise;
try {
const overlapping = await startDatabaseKeyRotation(site);
expect([overlapping.ok, removed.calls.length]).toEqual([false, 1]);
expect((await completeDatabaseKeyRotation(site, started)).ok).toBe(
false,
);
} finally {
release.resolve();
await completion;
}
},
);
});
test("gives same-tick restarts distinct identities and enforces their pause", () =>
withRotation({}, async (site, { clock, issued }) => {
const first = requireSuccess(await startDatabaseKeyRotation(site));
const second = requireSuccess(await startDatabaseKeyRotation(site));
expect([first, second]).toEqual([START_MS, START_MS + 1]);
clock.tick(60_000);
expect((await completeDatabaseKeyRotation(site, first)).ok).toBe(false);
expect((await completeDatabaseKeyRotation(site, second)).ok).toBe(
false,
);
expect(issued.calls.length).toBe(0);
clock.tick(1);
expect(await completeDatabaseKeyRotation(site, second)).toEqual({
ok: true,
});
expect(issued.calls.length).toBe(1);
}));
test("releases the claim when token creation throws", async () => {
const failure = new Error("provider transport stopped");
await withRotation(
{ issue: () => Promise.reject(failure) },
async (site, { clock }) => {
const started = requireSuccess(await startDatabaseKeyRotation(site));
clock.tick(60_000);
await expect(completeDatabaseKeyRotation(site, started)).rejects.toBe(
failure,
);
const current = await requireBuiltSiteByIdPrimary(site.id);
expect([current.databaseKeyRotationStarted, current.dbToken]).toEqual(
[0, "old-key"],
);
},
);
});
},
);