chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
// `vi.mock` factories are hoisted above regular top-level `const`s, so
|
||||
// any cross-references between the spy/mock fns and the factories have
|
||||
// to live inside `vi.hoisted`. See `mollifierDrainerHandler.test.ts`
|
||||
// for the same pattern.
|
||||
const { warnSpy, applyMetadataMutationToBufferedRunMock } = vi.hoisted(() => ({
|
||||
warnSpy: vi.fn(),
|
||||
applyMetadataMutationToBufferedRunMock: vi.fn(),
|
||||
}));
|
||||
|
||||
// The route module's import graph (createActionApiRoute, the env, the
|
||||
// services singleton) is heavier than the helper actually needs. Stub
|
||||
// the leaf modules so only the helper under test executes; the route's
|
||||
// top-level `createActionApiRoute(...)` call runs against the stubbed
|
||||
// builder and never touches platform.v3.server / prisma.
|
||||
vi.mock("~/db.server", () => ({ prisma: {}, $replica: {} }));
|
||||
vi.mock("~/env.server", () => ({
|
||||
env: { TASK_RUN_METADATA_MAXIMUM_SIZE: 256 * 1024 },
|
||||
}));
|
||||
vi.mock("~/services/routeBuilders/apiBuilder.server", () => ({
|
||||
createActionApiRoute: () => ({ action: vi.fn() }),
|
||||
}));
|
||||
vi.mock("~/services/apiAuth.server", () => ({
|
||||
authenticateApiRequest: vi.fn(),
|
||||
}));
|
||||
vi.mock("~/v3/services/common.server", () => ({
|
||||
ServiceValidationError: class extends Error {
|
||||
constructor(
|
||||
public override message: string,
|
||||
public status?: number
|
||||
) {
|
||||
super(message);
|
||||
}
|
||||
},
|
||||
}));
|
||||
vi.mock("~/services/metadata/updateMetadataInstance.server", () => ({
|
||||
updateMetadataService: { call: vi.fn(async () => undefined) },
|
||||
}));
|
||||
vi.mock("~/v3/mollifier/applyMetadataMutation.server", () => ({
|
||||
applyMetadataMutationToBufferedRun: applyMetadataMutationToBufferedRunMock,
|
||||
}));
|
||||
vi.mock("~/v3/mollifier/readFallback.server", () => ({
|
||||
findRunByIdWithMollifierFallback: vi.fn(),
|
||||
}));
|
||||
vi.mock("~/services/logger.server", () => ({
|
||||
logger: {
|
||||
warn: warnSpy,
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
import { routeOperationsToRun } from "~/routes/api.v1.runs.$runId.metadata";
|
||||
import type { AuthenticatedEnvironment } from "~/services/apiAuth.server";
|
||||
|
||||
const env = {
|
||||
id: "env_a",
|
||||
organizationId: "org_1",
|
||||
} as unknown as AuthenticatedEnvironment;
|
||||
|
||||
const opsFixture = [{ type: "set", key: "k", value: "v" }] as Parameters<
|
||||
typeof routeOperationsToRun
|
||||
>[1];
|
||||
|
||||
describe("routeOperationsToRun — non-throw buffer outcome logging", () => {
|
||||
// Each non-success outcome `applyMetadataMutationToBufferedRun` can
|
||||
// return (`not_found`, `busy`, `version_exhausted`, `metadata_too_large`)
|
||||
// must produce a warn log so ops can trace silent drops. Without this
|
||||
// branch the parent/root operation would disappear with no record —
|
||||
// `tryCatch` only catches throws, and the outcome object was
|
||||
// previously ignored.
|
||||
for (const kind of ["not_found", "busy", "version_exhausted", "metadata_too_large"] as const) {
|
||||
it(`warn-logs when buffer outcome is { kind: "${kind}" }`, async () => {
|
||||
warnSpy.mockClear();
|
||||
applyMetadataMutationToBufferedRunMock.mockResolvedValueOnce({ kind });
|
||||
|
||||
await routeOperationsToRun("run_buffered_1", opsFixture, env);
|
||||
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
"metadata route: parent/root buffer op did not apply",
|
||||
expect.objectContaining({ targetRunId: "run_buffered_1", kind })
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
it("does NOT warn on the happy path (kind: 'applied')", async () => {
|
||||
warnSpy.mockClear();
|
||||
applyMetadataMutationToBufferedRunMock.mockResolvedValueOnce({
|
||||
kind: "applied",
|
||||
newMetadata: { k: "v" },
|
||||
parentTaskRunFriendlyId: undefined,
|
||||
rootTaskRunFriendlyId: undefined,
|
||||
});
|
||||
|
||||
await routeOperationsToRun("run_buffered_1", opsFixture, env);
|
||||
|
||||
expect(warnSpy).not.toHaveBeenCalledWith(
|
||||
"metadata route: parent/root buffer op did not apply",
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
it("warn-logs once when the helper throws (the pre-existing throw branch keeps working)", async () => {
|
||||
warnSpy.mockClear();
|
||||
applyMetadataMutationToBufferedRunMock.mockRejectedValueOnce(new Error("ECONNRESET"));
|
||||
|
||||
await routeOperationsToRun("run_buffered_1", opsFixture, env);
|
||||
|
||||
// Pre-existing branch — the catch logs `buffer fallback for parent/root
|
||||
// op failed`. The new non-throw branch must NOT also fire (we return
|
||||
// early on bufferError).
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
"metadata route: buffer fallback for parent/root op failed",
|
||||
expect.objectContaining({ targetRunId: "run_buffered_1" })
|
||||
);
|
||||
expect(warnSpy).not.toHaveBeenCalledWith(
|
||||
"metadata route: parent/root buffer op did not apply",
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
it("skips both PG and buffer when targetRunId is missing or operations is empty", async () => {
|
||||
warnSpy.mockClear();
|
||||
applyMetadataMutationToBufferedRunMock.mockClear();
|
||||
|
||||
await routeOperationsToRun(undefined, opsFixture, env);
|
||||
await routeOperationsToRun("run_x", undefined, env);
|
||||
await routeOperationsToRun("run_x", [], env);
|
||||
|
||||
expect(applyMetadataMutationToBufferedRunMock).not.toHaveBeenCalled();
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user