chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
import { containerTest } from "@internal/testcontainers";
|
||||
import type {
|
||||
Organization,
|
||||
PrismaClient,
|
||||
Project,
|
||||
RuntimeEnvironment,
|
||||
} from "@trigger.dev/database";
|
||||
import { customAlphabet } from "nanoid";
|
||||
import { expect, vi } from "vitest";
|
||||
import { ApiBatchResultsPresenter } from "~/presenters/v3/ApiBatchResultsPresenter.server";
|
||||
import type { AuthenticatedEnvironment } from "~/services/apiAuth.server";
|
||||
import { seedTestEnvironment } from "../helpers/seedTestEnvironment";
|
||||
|
||||
// Neutralize the db.server singleton so importing the presenter (via BasePresenter) does not try
|
||||
// to connect to the env database; the test uses the injected testcontainer prisma for all reads.
|
||||
vi.mock("~/db.server", () => ({ prisma: {}, $replica: {} }));
|
||||
|
||||
vi.setConfig({ testTimeout: 60_000 });
|
||||
|
||||
const idGenerator = customAlphabet("123456789abcdefghijkmnopqrstuvwxyz", 21);
|
||||
|
||||
function authEnv(
|
||||
environment: RuntimeEnvironment,
|
||||
project: Project,
|
||||
organization: Organization
|
||||
): AuthenticatedEnvironment {
|
||||
return { ...environment, project, organization, orgMember: null } as AuthenticatedEnvironment;
|
||||
}
|
||||
|
||||
type SeedContext = {
|
||||
environmentId: string;
|
||||
projectId: string;
|
||||
organizationId: string;
|
||||
backgroundWorkerId: string;
|
||||
backgroundWorkerTaskId: string;
|
||||
queueId: string;
|
||||
};
|
||||
|
||||
async function seedWorker(
|
||||
prisma: PrismaClient,
|
||||
ctx: Omit<SeedContext, "backgroundWorkerId" | "backgroundWorkerTaskId" | "queueId">
|
||||
) {
|
||||
const queue = await prisma.taskQueue.create({
|
||||
data: {
|
||||
friendlyId: `queue_${idGenerator()}`,
|
||||
name: "task/test-task",
|
||||
projectId: ctx.projectId,
|
||||
runtimeEnvironmentId: ctx.environmentId,
|
||||
},
|
||||
});
|
||||
|
||||
const worker = await prisma.backgroundWorker.create({
|
||||
data: {
|
||||
friendlyId: `worker_${idGenerator()}`,
|
||||
contentHash: "hash",
|
||||
projectId: ctx.projectId,
|
||||
runtimeEnvironmentId: ctx.environmentId,
|
||||
version: "20240101.1",
|
||||
metadata: {},
|
||||
},
|
||||
});
|
||||
|
||||
const task = await prisma.backgroundWorkerTask.create({
|
||||
data: {
|
||||
friendlyId: `task_${idGenerator()}`,
|
||||
slug: "test-task",
|
||||
filePath: "src/test.ts",
|
||||
exportName: "testTask",
|
||||
workerId: worker.id,
|
||||
projectId: ctx.projectId,
|
||||
runtimeEnvironmentId: ctx.environmentId,
|
||||
},
|
||||
});
|
||||
|
||||
return { queueId: queue.id, backgroundWorkerId: worker.id, backgroundWorkerTaskId: task.id };
|
||||
}
|
||||
|
||||
async function seedRunWithAttempt(
|
||||
prisma: PrismaClient,
|
||||
ctx: SeedContext,
|
||||
opts: {
|
||||
status: "COMPLETED_SUCCESSFULLY" | "COMPLETED_WITH_ERRORS" | "CANCELED" | "EXECUTING";
|
||||
attempt?: {
|
||||
status: "COMPLETED" | "FAILED";
|
||||
output?: string;
|
||||
outputType?: string;
|
||||
error?: unknown;
|
||||
};
|
||||
}
|
||||
) {
|
||||
const runInternalId = idGenerator();
|
||||
const run = await prisma.taskRun.create({
|
||||
data: {
|
||||
id: runInternalId,
|
||||
friendlyId: `run_${runInternalId}`,
|
||||
taskIdentifier: "test-task",
|
||||
payload: "{}",
|
||||
payloadType: "application/json",
|
||||
traceId: idGenerator(),
|
||||
spanId: idGenerator(),
|
||||
queue: "task/test-task",
|
||||
runtimeEnvironmentId: ctx.environmentId,
|
||||
projectId: ctx.projectId,
|
||||
status: opts.status,
|
||||
},
|
||||
});
|
||||
|
||||
if (opts.attempt) {
|
||||
await prisma.taskRunAttempt.create({
|
||||
data: {
|
||||
friendlyId: `attempt_${idGenerator()}`,
|
||||
taskRunId: run.id,
|
||||
backgroundWorkerId: ctx.backgroundWorkerId,
|
||||
backgroundWorkerTaskId: ctx.backgroundWorkerTaskId,
|
||||
runtimeEnvironmentId: ctx.environmentId,
|
||||
queueId: ctx.queueId,
|
||||
status: opts.attempt.status,
|
||||
output: opts.attempt.output,
|
||||
outputType: opts.attempt.outputType ?? "application/json",
|
||||
error: opts.attempt.error as any,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
containerTest(
|
||||
"ApiBatchResultsPresenter returns ordered results matching pre-decompose behavior",
|
||||
async ({ prisma }) => {
|
||||
const { environment, project, organization } = await seedTestEnvironment(prisma);
|
||||
const worker = await seedWorker(prisma, {
|
||||
environmentId: environment.id,
|
||||
projectId: project.id,
|
||||
organizationId: organization.id,
|
||||
});
|
||||
const ctx: SeedContext = {
|
||||
environmentId: environment.id,
|
||||
projectId: project.id,
|
||||
organizationId: organization.id,
|
||||
...worker,
|
||||
};
|
||||
|
||||
// A successful run, a failed run, and an executing run (no terminal attempt → undefined).
|
||||
const successRun = await seedRunWithAttempt(prisma, ctx, {
|
||||
status: "COMPLETED_SUCCESSFULLY",
|
||||
attempt: { status: "COMPLETED", output: '"hello"', outputType: "application/json" },
|
||||
});
|
||||
const failedRun = await seedRunWithAttempt(prisma, ctx, {
|
||||
status: "COMPLETED_WITH_ERRORS",
|
||||
attempt: {
|
||||
status: "FAILED",
|
||||
error: { type: "BUILT_IN_ERROR", name: "Error", message: "boom", stackTrace: "boom" },
|
||||
},
|
||||
});
|
||||
const executingRun = await seedRunWithAttempt(prisma, ctx, {
|
||||
status: "EXECUTING",
|
||||
});
|
||||
|
||||
const batchInternalId = idGenerator();
|
||||
const batchFriendlyId = `batch_${batchInternalId}`;
|
||||
await prisma.batchTaskRun.create({
|
||||
data: {
|
||||
id: batchInternalId,
|
||||
friendlyId: batchFriendlyId,
|
||||
runtimeEnvironmentId: environment.id,
|
||||
},
|
||||
});
|
||||
|
||||
// Items inserted in a deterministic order: success, failed, executing.
|
||||
for (const run of [successRun, failedRun, executingRun]) {
|
||||
await prisma.batchTaskRunItem.create({
|
||||
data: {
|
||||
batchTaskRunId: batchInternalId,
|
||||
taskRunId: run.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Pass the testcontainer prisma as both the primary and the replica: the passthrough path
|
||||
// reads the batch row off the replica and the member runs off the primary (via the run store).
|
||||
const presenter = new ApiBatchResultsPresenter(prisma, prisma);
|
||||
const result = await presenter.call(
|
||||
batchFriendlyId,
|
||||
authEnv(environment, project, organization)
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result?.id).toBe(batchFriendlyId);
|
||||
|
||||
// executing run yields no execution result → filtered out. Order preserved: success then failed.
|
||||
expect(result?.items).toHaveLength(2);
|
||||
|
||||
const [first, second] = result!.items;
|
||||
expect(first.ok).toBe(true);
|
||||
expect(first.id).toBe(successRun.friendlyId);
|
||||
if (first.ok) {
|
||||
expect(first.output).toBe('"hello"');
|
||||
expect(first.taskIdentifier).toBe("test-task");
|
||||
}
|
||||
|
||||
expect(second.ok).toBe(false);
|
||||
expect(second.id).toBe(failedRun.friendlyId);
|
||||
}
|
||||
);
|
||||
|
||||
containerTest(
|
||||
"ApiBatchResultsPresenter filters runs without an execution result but keeps order",
|
||||
async ({ prisma }) => {
|
||||
const { environment, project, organization } = await seedTestEnvironment(prisma);
|
||||
const worker = await seedWorker(prisma, {
|
||||
environmentId: environment.id,
|
||||
projectId: project.id,
|
||||
organizationId: organization.id,
|
||||
});
|
||||
const ctx: SeedContext = {
|
||||
environmentId: environment.id,
|
||||
projectId: project.id,
|
||||
organizationId: organization.id,
|
||||
...worker,
|
||||
};
|
||||
|
||||
// Pending run → executionResultForTaskRun returns undefined → filtered out, like the
|
||||
// pre-decompose code did via `.filter(Boolean)`.
|
||||
const pendingRun = await seedRunWithAttempt(prisma, ctx, { status: "EXECUTING" });
|
||||
const successRun = await seedRunWithAttempt(prisma, ctx, {
|
||||
status: "COMPLETED_SUCCESSFULLY",
|
||||
attempt: { status: "COMPLETED", output: '"ok"', outputType: "application/json" },
|
||||
});
|
||||
|
||||
const batchInternalId = idGenerator();
|
||||
const batchFriendlyId = `batch_${batchInternalId}`;
|
||||
await prisma.batchTaskRun.create({
|
||||
data: {
|
||||
id: batchInternalId,
|
||||
friendlyId: batchFriendlyId,
|
||||
runtimeEnvironmentId: environment.id,
|
||||
},
|
||||
});
|
||||
|
||||
// pending first, success second — only the success result should survive, in order.
|
||||
for (const run of [pendingRun, successRun]) {
|
||||
await prisma.batchTaskRunItem.create({
|
||||
data: { batchTaskRunId: batchInternalId, taskRunId: run.id },
|
||||
});
|
||||
}
|
||||
|
||||
// Pass the testcontainer prisma as both the primary and the replica: the passthrough path
|
||||
// reads the batch row off the replica and the member runs off the primary (via the run store).
|
||||
const presenter = new ApiBatchResultsPresenter(prisma, prisma);
|
||||
const result = await presenter.call(
|
||||
batchFriendlyId,
|
||||
authEnv(environment, project, organization)
|
||||
);
|
||||
|
||||
expect(result?.items).toHaveLength(1);
|
||||
expect(result?.items[0]?.id).toBe(successRun.friendlyId);
|
||||
}
|
||||
);
|
||||
|
||||
containerTest("ApiBatchResultsPresenter short-circuits an empty batch", async ({ prisma }) => {
|
||||
const { environment, project, organization } = await seedTestEnvironment(prisma);
|
||||
|
||||
const batchInternalId = idGenerator();
|
||||
const batchFriendlyId = `batch_${batchInternalId}`;
|
||||
await prisma.batchTaskRun.create({
|
||||
data: {
|
||||
id: batchInternalId,
|
||||
friendlyId: batchFriendlyId,
|
||||
runtimeEnvironmentId: environment.id,
|
||||
},
|
||||
});
|
||||
|
||||
// Pass the testcontainer prisma as both the primary and the replica: the passthrough path
|
||||
// reads the batch row off the replica and the member runs off the primary (via the run store).
|
||||
const presenter = new ApiBatchResultsPresenter(prisma, prisma);
|
||||
const result = await presenter.call(batchFriendlyId, authEnv(environment, project, organization));
|
||||
|
||||
expect(result).toEqual({ id: batchFriendlyId, items: [] });
|
||||
});
|
||||
Reference in New Issue
Block a user