import { describe, expect, vi } from "vitest"; // Store-routed engine create/get seam + the residency-keyed id contract behind // the create route (not its HTTP action). A standalone MANUAL token is cuid → // LEGACY; NEW residency is reached only by co-locating the token with a run-ops run. import { RunEngine } from "@internal/run-engine"; import { setupAuthenticatedEnvironment } from "@internal/run-engine/tests"; import { containerTest, heteroRunOpsPostgresTest, network, redisContainer, redisOptions, } from "@internal/testcontainers"; import { PostgresRunStore, RoutingRunStore, type CreateRunInput } from "@internal/run-store"; import type { RunOpsPrismaClient } from "@internal/run-ops-database"; import { WaitpointId, RunId, generateRunOpsId, ownerEngine, CUID_LENGTH, } from "@trigger.dev/core/v3/isomorphic"; import type { Prisma, PrismaClient } from "@trigger.dev/database"; import { trace } from "@opentelemetry/api"; vi.setConfig({ testTimeout: 60_000 }); function buildEngine(opts: { prisma: any; redisOptions: any; store?: ConstructorParameters[0]["store"]; }) { return new RunEngine({ prisma: opts.prisma, ...(opts.store ? { store: opts.store } : {}), worker: { redis: opts.redisOptions, workers: 1, tasksPerWorker: 10, pollIntervalMs: 100, }, queue: { redis: opts.redisOptions, }, runLock: { redis: opts.redisOptions, }, machines: { defaultMachine: "small-1x", machines: { "small-1x": { name: "small-1x" as const, cpu: 0.5, memory: 0.5, centsPerMs: 0.0001, }, }, baseCostInCents: 0.0005, }, tracer: trace.getTracer("test", "0.0.0"), }); } describe("waitpoint-token create engine seam — residency-keyed id contract", () => { // A standalone token (no owning run) mints a cuid WaitpointId and stays LEGACY. containerTest( "create mints a cuid WaitpointId for a standalone token (LEGACY)", async ({ prisma, redisOptions }) => { const engine = buildEngine({ prisma, redisOptions }); try { const env = await setupAuthenticatedEnvironment(prisma, "PRODUCTION"); const result = await engine.createManualWaitpoint({ environmentId: env.id, projectId: env.project.id, timeout: new Date(Date.now() + 60_000), }); expect(result.waitpoint.id.length).toBe(CUID_LENGTH); expect(result.waitpoint.type).toBe("MANUAL"); const row = await prisma.waitpoint.findUnique({ where: { id: result.waitpoint.id } }); expect(row).not.toBeNull(); expect(row?.environmentId).toBe(env.id); // The exact response body id, computed as the route computes it. const responseId = WaitpointId.toFriendlyId(result.waitpoint.id); expect(responseId.startsWith("waitpoint_")).toBe(true); expect(responseId).toBe("waitpoint_" + result.waitpoint.id); expect(WaitpointId.fromFriendlyId(responseId)).toBe(result.waitpoint.id); expect(ownerEngine(WaitpointId.fromFriendlyId(responseId))).toBe("LEGACY"); } finally { await engine.quit(); } } ); // The standalone token id classifies LEGACY and resolves back. containerTest( "token id classifies to the legacy store and resolves back", async ({ prisma, redisOptions }) => { const engine = buildEngine({ prisma, redisOptions }); try { const env = await setupAuthenticatedEnvironment(prisma, "PRODUCTION"); const result = await engine.createManualWaitpoint({ environmentId: env.id, projectId: env.project.id, timeout: new Date(Date.now() + 60_000), }); expect(ownerEngine(result.waitpoint.id)).toBe("LEGACY"); const resolved = await engine.getWaitpoint({ waitpointId: result.waitpoint.id, environmentId: env.id, projectId: env.project.id, }); expect(resolved).not.toBeNull(); expect(resolved?.id).toBe(result.waitpoint.id); } finally { await engine.quit(); } } ); // The control-plane WaitpointTag write stays control-plane — it cannot // route through the run-ops store, which exposes no tag-write surface at all. containerTest( "control-plane WaitpointTag write stays control-plane, not on the run-ops store", async ({ prisma, redisOptions }) => { // A run-ops store that counts every waitpoint write that passes through it. // Overrides mirror the base PostgresRunStore generics so a base-signature // change can't silently detach the counter. let waitpointWrites = 0; class CountingPostgresRunStore extends PostgresRunStore { async upsertWaitpoint( args: Prisma.SelectSubset, tx?: Parameters[1] ): Promise> { waitpointWrites++; return super.upsertWaitpoint(args, tx); } async createWaitpoint( args: Prisma.SelectSubset, tx?: Parameters[1] ): Promise> { waitpointWrites++; return super.createWaitpoint(args, tx); } } const countingStore = new CountingPostgresRunStore({ prisma, readOnlyPrisma: prisma, }); const engine = buildEngine({ prisma, redisOptions, store: countingStore }); try { const env = await setupAuthenticatedEnvironment(prisma, "PRODUCTION"); // Issue the control-plane tag write directly (the same upsert the // createWaitpointTag model performs), against the container prisma — // control-plane, never the run-ops store. await prisma.waitpointTag.upsert({ where: { environmentId_name: { environmentId: env.id, name: "t1" } }, create: { name: "t1", environmentId: env.id, projectId: env.project.id }, update: {}, }); const result = await engine.createManualWaitpoint({ environmentId: env.id, projectId: env.project.id, tags: ["t1"], timeout: new Date(Date.now() + 60_000), }); expect(result.waitpoint.id.length).toBe(CUID_LENGTH); // The tag landed on the control-plane client. const tagRow = await prisma.waitpointTag.findFirst({ where: { environmentId: env.id, name: "t1" }, }); expect(tagRow).not.toBeNull(); // The waitpoint went through the run-ops store (counting store fired). expect(waitpointWrites).toBeGreaterThanOrEqual(1); // The run-ops store has no tag-write surface, so the partition rests on the // two assertions above: the tag landed on control-plane and the waitpoint went through the store. } finally { await engine.quit(); } } ); }); const twoDbEngineTest = heteroRunOpsPostgresTest.extend<{ redisContainer: any; redisOptions: any; }>({ network, redisContainer, redisOptions, }); async function seedControlPlaneEnv(prisma: PrismaClient, suffix: string) { const organization = await prisma.organization.create({ data: { title: `Org ${suffix}`, slug: `org-${suffix}` }, }); const project = await prisma.project.create({ data: { name: `Project ${suffix}`, slug: `project-${suffix}`, externalRef: `proj_${suffix}`, organizationId: organization.id, }, }); const environment = await prisma.runtimeEnvironment.create({ data: { type: "PRODUCTION", slug: `prod-${suffix}`, projectId: project.id, organizationId: organization.id, apiKey: `tr_prod_${suffix}`, pkApiKey: `pk_prod_${suffix}`, shortcode: `short_${suffix}`, maximumConcurrencyLimit: 10, }, }); return { organization, project, environment }; } function buildCreateRunInput(params: { runId: string; friendlyId: string; organizationId: string; projectId: string; runtimeEnvironmentId: string; }): CreateRunInput { return { data: { id: params.runId, engine: "V2", status: "EXECUTING", friendlyId: params.friendlyId, runtimeEnvironmentId: params.runtimeEnvironmentId, environmentType: "PRODUCTION", organizationId: params.organizationId, projectId: params.projectId, taskIdentifier: "parent-task", payload: "{}", payloadType: "application/json", context: {}, traceContext: {}, traceId: `trace_${params.runId}`, spanId: `span_${params.runId}`, runTags: [], queue: "task/parent-task", isTest: false, taskEventStore: "taskEvent", depth: 0, createdAt: new Date("2024-01-01T00:00:00.000Z"), }, snapshot: { engine: "V2", executionStatus: "RUN_CREATED", description: "Run was created", runStatus: "PENDING", environmentId: params.runtimeEnvironmentId, environmentType: "PRODUCTION", projectId: params.projectId, organizationId: params.organizationId, }, }; } async function seedExecutingRunOpsRun( prisma14: PrismaClient, router: RoutingRunStore, runId: string, suffix: string ) { const env = await seedControlPlaneEnv(prisma14, suffix); await router.createRun( buildCreateRunInput({ runId, friendlyId: `run_${suffix}`, organizationId: env.organization.id, projectId: env.project.id, runtimeEnvironmentId: env.environment.id, }) ); const created = await router.findLatestExecutionSnapshot(runId); await router.createExecutionSnapshot( { run: { id: runId, status: "EXECUTING", attemptNumber: 1 }, snapshot: { executionStatus: "EXECUTING", description: "run executing" }, previousSnapshotId: created!.id, environmentId: env.environment.id, environmentType: "PRODUCTION", projectId: env.project.id, organizationId: env.organization.id, }, prisma14 ); return env; } function makeRouter(prisma14: PrismaClient, prisma17: RunOpsPrismaClient) { const newStore = new PostgresRunStore({ prisma: prisma17 as never, readOnlyPrisma: prisma17 as never, schemaVariant: "dedicated", }); const legacyStore = new PostgresRunStore({ prisma: prisma14, readOnlyPrisma: prisma14, schemaVariant: "legacy", }); return new RoutingRunStore({ new: newStore, legacy: legacyStore }); } describe("waitpoint-token create engine seam — NEW residency via a run-ops run across the version boundary", () => { // NEW residency comes from co-locating the token with a run-ops run; the token // resolves only on its owning (#new) store across the PG14<->PG17 boundary, never #legacy. twoDbEngineTest( "a run-ops run's token co-locates on #new and resolves only there, not on #legacy", async ({ prisma14, prisma17, redisOptions }) => { const p14 = prisma14 as unknown as PrismaClient; const router = makeRouter(p14, prisma17); const engine = buildEngine({ prisma: prisma14, redisOptions, store: router }); try { // A NEW-classified run id (explicit run-ops id), mirroring the trigger-routing helper. const runId = RunId.toFriendlyId(generateRunOpsId()); expect(ownerEngine(runId)).toBe("NEW"); const env = await seedExecutingRunOpsRun(p14, router, runId, "wpnew"); const { waitpoint } = await engine.createManualWaitpoint({ runId, environmentId: env.environment.id, projectId: env.project.id, }); // The token is always cuid (Option B); its NEW residency comes from the run. expect(waitpoint.id.length).toBe(CUID_LENGTH); expect(ownerEngine(waitpoint.id)).toBe("LEGACY"); // Co-location: the token lives on #new next to its run, not on #legacy. const onNew = await prisma17.waitpoint.findUnique({ where: { id: waitpoint.id } }); const onLegacy = await p14.waitpoint.findUnique({ where: { id: waitpoint.id } }); expect(onNew).not.toBeNull(); expect(onLegacy).toBeNull(); const resolved = await engine.getWaitpoint({ waitpointId: waitpoint.id, environmentId: env.environment.id, projectId: env.project.id, }); expect(resolved?.id).toBe(waitpoint.id); expect(await p14.waitpoint.findUnique({ where: { id: waitpoint.id } })).toBeNull(); } finally { await engine.quit(); } } ); });