1import * as GCP from "@/GCP";
2import { GcpEnvironment } from "@/GCP/Environment";
3import * as Test from "@/Test/Alchemy";
4import * as config from "@distilled.cloud/gcp/config_v1";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8import * as Schedule from "effect/Schedule";
9
10const { test } = Test.make({ providers: GCP.providers() });
11
12const logLevel = Effect.provideService(
13 MinimumLogLevel,
14 process.env.DEBUG ? "Debug" : "Info",
15);
16
17const runLifecycle = !process.env.FAST;
18
19const waitUntilGone = (name: string) =>
20 config.getProjectsLocationsDeploymentGroups({ name }).pipe(
21 Effect.as("found" as const),
22 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
23 Effect.repeat({
24 schedule: Schedule.spaced("2 seconds"),
25 until: (status) => status === "gone",
26 times: 10,
27 }),
28 );
29
30test.provider(
31 "getProjectsLocationsDeploymentGroups on a missing group fails with a typed tag",
32 (stack) =>
33 Effect.gen(function* () {
34 const { project } = yield* GcpEnvironment.current;
35 yield* stack.destroy();
36
37 const error = yield* Effect.flip(
38 config.getProjectsLocationsDeploymentGroups({
39 name: `projects/${project}/locations/us-central1/deploymentGroups/alchemy-missing-group`,
40 }),
41 );
42 expect(error._tag).toEqual("NotFound");
43
44 yield* stack.destroy();
45 }).pipe(logLevel),
46 { tags: ["provider:gcp", "provider:gcp:config", "live"], timeout: 90_000 },
47);
48
49test.provider.skipIf(!runLifecycle)(
50 "create, update, and delete a deployment group",
51 (stack) =>
52 Effect.gen(function* () {
53 yield* stack.destroy();
54
55 const created = yield* stack.deploy(
56 Effect.gen(function* () {
57 return yield* GCP.Config.DeploymentGroup("App", {
58 deploymentUnits: [{ id: "network", dependencies: [] }],
59 labels: { env: "test" },
60 });
61 }),
62 );
63
64 expect(created.name).toContain("/deploymentGroups/");
65 expect(created.deploymentGroupId).toEqual(expect.any(String));
66 expect(created.location).toEqual("us-central1");
67 expect(created.deploymentUnits[0]?.id).toEqual("network");
68 expect(created.labels).toMatchObject({ env: "test" });
69
70 const fetched = yield* config.getProjectsLocationsDeploymentGroups({
71 name: created.name,
72 });
73 expect(fetched.name).toEqual(created.name);
74 expect(fetched.labels?.env).toEqual("test");
75 expect(fetched.deploymentUnits?.[0]?.id).toEqual("network");
76
77 const updated = yield* stack.deploy(
78 Effect.gen(function* () {
79 return yield* GCP.Config.DeploymentGroup("App", {
80 deploymentGroupId: created.deploymentGroupId,
81 deploymentUnits: [
82 { id: "network", dependencies: [] },
83 { id: "cluster", dependencies: ["network"] },
84 ],
85 labels: { env: "prod", role: "config" },
86 });
87 }),
88 );
89
90 expect(updated.name).toEqual(created.name);
91 expect(updated.deploymentUnits.map((unit) => unit.id)).toEqual([
92 "network",
93 "cluster",
94 ]);
95 expect(updated.labels).toMatchObject({ env: "prod", role: "config" });
96
97 yield* stack.destroy();
98
99 const gone = yield* waitUntilGone(created.name);
100 expect(gone).toEqual("gone");
101 }).pipe(logLevel),
102 { tags: ["provider:gcp", "provider:gcp:config", "live"], timeout: 90_000 },
103);