1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as bigquery from "@distilled.cloud/gcp/bigquery_v2";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8
9const { test } = Test.make({ providers: GCP.providers() });
10
11const logLevel = Effect.provideService(
12 MinimumLogLevel,
13 process.env.DEBUG ? "Debug" : "Info",
14);
15
16const waitUntilGone = (projectId: string, jobId: string, location: string) =>
17 bigquery
18 .getJobs({
19 projectId,
20 jobId,
21 location,
22 })
23 .pipe(
24 Effect.as("found" as const),
25 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
26 Effect.repeat({
27 schedule: Schedule.spaced("1 second"),
28 until: (status) => status === "gone",
29 times: 10,
30 }),
31 );
32
33test.provider(
34 "create, replace, and delete a query job",
35 (stack) =>
36 Effect.gen(function* () {
37 yield* stack.destroy();
38
39 const created = yield* stack.deploy(
40 Effect.gen(function* () {
41 return yield* GCP.BigQuery.Job("Count", {
42 location: "US-CENTRAL1",
43 labels: { env: "test" },
44 query: { query: "SELECT 1 AS n", useLegacySql: false },
45 });
46 }),
47 );
48
49 expect(created.jobId).toEqual(expect.any(String));
50 expect(created.project).toEqual(expect.any(String));
51 expect(created.location.toUpperCase()).toEqual("US-CENTRAL1");
52 expect(created.labels).toMatchObject({ env: "test" });
53 expect(created.jobType).toEqual("QUERY");
54 expect(created.state).toEqual("DONE");
55 expect(created.errorResult).toBeUndefined();
56 expect(created.query).toEqual("SELECT 1 AS n");
57
58 const fetched = yield* bigquery.getJobs({
59 projectId: created.project,
60 jobId: created.jobId,
61 location: created.location,
62 });
63 expect(fetched.jobReference?.jobId).toEqual(created.jobId);
64 expect(fetched.configuration?.labels?.env).toEqual("test");
65 expect(fetched.configuration?.labels?.["alchemy-id"]).toEqual(
66 expect.any(String),
67 );
68 expect(fetched.configuration?.query?.query).toEqual("SELECT 1 AS n");
69 expect(fetched.status?.state).toEqual("DONE");
70
71 const updated = yield* stack.deploy(
72 Effect.gen(function* () {
73 return yield* GCP.BigQuery.Job("Count", {
74 location: "US-CENTRAL1",
75 labels: { env: "prod", role: "query" },
76 query: { query: "SELECT 2 AS n", useLegacySql: false },
77 });
78 }),
79 );
80
81 expect(updated.jobId).toEqual(expect.any(String));
82 expect(updated.jobId).not.toEqual(created.jobId);
83 expect(updated.labels).toMatchObject({ env: "prod", role: "query" });
84 expect(updated.query).toEqual("SELECT 2 AS n");
85 expect(updated.state).toEqual("DONE");
86 expect(updated.errorResult).toBeUndefined();
87
88 const fetchedUpdate = yield* bigquery.getJobs({
89 projectId: updated.project,
90 jobId: updated.jobId,
91 location: updated.location,
92 });
93 expect(fetchedUpdate.configuration?.labels?.env).toEqual("prod");
94 expect(fetchedUpdate.configuration?.labels?.role).toEqual("query");
95 expect(fetchedUpdate.configuration?.query?.query).toEqual(
96 "SELECT 2 AS n",
97 );
98
99 const oldGone = yield* waitUntilGone(
100 created.project,
101 created.jobId,
102 created.location,
103 );
104 expect(oldGone).toEqual("gone");
105
106 yield* stack.destroy();
107
108 const gone = yield* waitUntilGone(
109 updated.project,
110 updated.jobId,
111 updated.location,
112 );
113 expect(gone).toEqual("gone");
114 }).pipe(logLevel),
115 { tags: ["provider:gcp", "provider:gcp:bigquery", "live"], timeout: 90_000 },
116);