Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

192 lines
5.6 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
// The hyperdrive runtime adapter imports the bindings from cloudflare:workers,
// builds a node-postgres Pool, and routes per-request queries through the
// instrumentation logger. Mock all three so we can assert which binding's
// connection string the per-request pool is built from, without a real DB.
const { poolCalls, fakeEnv } = vi.hoisted(() => ({
poolCalls: [] as Array<{ connectionString: string }>,
fakeEnv: {
HYPERDRIVE: { connectionString: "postgres://primary/uncached" },
HYPERDRIVE_CACHED: { connectionString: "postgres://replica/cached" },
} as Record<string, { connectionString: string }>,
}));
vi.mock("cloudflare:workers", () => ({
env: fakeEnv,
waitUntil: (_p: Promise<unknown>) => {},
}));
vi.mock("pg", () => ({
Pool: class {
constructor(opts: { connectionString: string }) {
poolCalls.push({ connectionString: opts.connectionString });
}
// Kysely's PostgresDialect only needs these to construct; no query runs.
async end() {}
},
}));
vi.mock("emdash/database/instrumentation", () => ({
kyselyLogOption: () => undefined,
}));
import { createRequestScopedDb, selectBindingName } from "../../src/db/hyperdrive.js";
const cookies = {
get: () => undefined,
set: () => {},
};
const url = new URL("https://example.com/");
const publicUrl = new URL("https://example.com/posts");
const cfg = { binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" };
describe("selectBindingName", () => {
it("uses the cached binding for anonymous reads of public paths", () => {
const name = selectBindingName(cfg, {
isAuthenticated: false,
isWrite: false,
url: publicUrl,
});
expect(name).toBe("HYPERDRIVE_CACHED");
});
it("uses the primary binding for authenticated reads", () => {
const name = selectBindingName(cfg, {
isAuthenticated: true,
isWrite: false,
url: publicUrl,
});
expect(name).toBe("HYPERDRIVE");
});
it("uses the primary binding for anonymous writes", () => {
const name = selectBindingName(cfg, {
isAuthenticated: false,
isWrite: true,
url: publicUrl,
});
expect(name).toBe("HYPERDRIVE");
});
it("uses the primary binding for anonymous GETs under /_emdash (setup/auth/admin APIs)", () => {
for (const path of [
"/_emdash",
"/_emdash/admin",
"/_emdash/admin/setup",
"/_emdash/api/setup/status",
"/_emdash/api/auth/me",
]) {
const name = selectBindingName(cfg, {
isAuthenticated: false,
isWrite: false,
url: new URL(`https://example.com${path}`),
});
expect(name, `path ${path} must use the primary binding`).toBe("HYPERDRIVE");
}
});
it("does not treat a public path that merely contains _emdash as internal", () => {
const name = selectBindingName(cfg, {
isAuthenticated: false,
isWrite: false,
url: new URL("https://example.com/posts/about-_emdash"),
});
expect(name).toBe("HYPERDRIVE_CACHED");
});
it("always uses the primary binding when no cachedBinding is set", () => {
expect(
selectBindingName(
{ binding: "HYPERDRIVE" },
{ isAuthenticated: false, isWrite: false, url: publicUrl },
),
).toBe("HYPERDRIVE");
expect(
selectBindingName(
{ binding: "HYPERDRIVE" },
{ isAuthenticated: true, isWrite: true, url: publicUrl },
),
).toBe("HYPERDRIVE");
});
});
describe("createRequestScopedDb binding routing", () => {
it("builds the pool from the cached binding for anonymous reads", () => {
poolCalls.length = 0;
const scoped = createRequestScopedDb({
config: { binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" },
isAuthenticated: false,
isWrite: false,
cookies,
url,
});
expect(scoped).not.toBeNull();
expect(poolCalls).toHaveLength(1);
expect(poolCalls[0]!.connectionString).toBe("postgres://replica/cached");
});
it("builds the pool from the primary binding for authenticated reads", () => {
poolCalls.length = 0;
createRequestScopedDb({
config: { binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" },
isAuthenticated: true,
isWrite: false,
cookies,
url,
});
expect(poolCalls[0]!.connectionString).toBe("postgres://primary/uncached");
});
it("builds the pool from the primary binding for writes", () => {
poolCalls.length = 0;
createRequestScopedDb({
config: { binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" },
isAuthenticated: false,
isWrite: true,
cookies,
url,
});
expect(poolCalls[0]!.connectionString).toBe("postgres://primary/uncached");
});
it("builds the pool from the primary binding for anonymous /_emdash reads", () => {
poolCalls.length = 0;
createRequestScopedDb({
config: { binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" },
isAuthenticated: false,
isWrite: false,
cookies,
url: new URL("https://example.com/_emdash/api/setup/status"),
});
expect(poolCalls[0]!.connectionString).toBe("postgres://primary/uncached");
});
it("falls back to the primary binding when the cached binding is missing at runtime", () => {
poolCalls.length = 0;
const scoped = createRequestScopedDb({
config: { binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_MISSING" },
isAuthenticated: false,
isWrite: false,
cookies,
url,
});
expect(scoped).not.toBeNull();
expect(poolCalls[0]!.connectionString).toBe("postgres://primary/uncached");
});
it("returns null when the primary binding is absent (singleton fallback)", () => {
poolCalls.length = 0;
const scoped = createRequestScopedDb({
config: { binding: "NOPE" },
isAuthenticated: false,
isWrite: false,
cookies,
url,
});
expect(scoped).toBeNull();
expect(poolCalls).toHaveLength(0);
});
});