1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as compute from "@distilled.cloud/gcp/compute_v1";
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 = (project: string, snapshot: string) =>
17 compute.getSnapshots({ project, snapshot }).pipe(
18 Effect.as("found" as const),
19 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
20 Effect.repeat({
21 schedule: Schedule.spaced("1 second"),
22 until: (status) => status === "gone",
23 times: 10,
24 }),
25 );
26
27test.provider.skipIf(!!process.env.FAST)(
28 "create, update, and delete a snapshot",
29 (stack) =>
30 Effect.gen(function* () {
31 yield* stack.destroy();
32
33 const created = yield* stack.deploy(
34 Effect.gen(function* () {
35 const disk = yield* GCP.Compute.Disk("Data", {
36 zone: "us-central1-a",
37 type: "pd-standard",
38 sizeGb: 10,
39 });
40 const snapshot = yield* GCP.Compute.Snapshot("Backup", {
41 sourceDisk: disk.selfLink.as<string>(),
42 labels: { env: "test" },
43 });
44 return { disk, snapshot };
45 }),
46 );
47
48 expect(created.snapshot.snapshotName).toEqual(expect.any(String));
49 expect(created.snapshot.status).toEqual("READY");
50 expect(created.snapshot.labels).toMatchObject({ env: "test" });
51 expect(created.snapshot.sourceDisk).toEqual(expect.any(String));
52 expect(created.snapshot.selfLink).toEqual(expect.any(String));
53
54 const fetched = yield* compute.getSnapshots({
55 project: created.snapshot.project,
56 snapshot: created.snapshot.snapshotName,
57 });
58 expect(fetched.name).toEqual(created.snapshot.snapshotName);
59 expect(fetched.labels?.env).toEqual("test");
60 expect(fetched.labels?.["alchemy-id"]).toEqual(expect.any(String));
61 expect(fetched.status).toEqual("READY");
62 expect(fetched.sourceDisk).toEqual(expect.any(String));
63
64 const updated = yield* stack.deploy(
65 Effect.gen(function* () {
66 const disk = yield* GCP.Compute.Disk("Data", {
67 diskName: created.disk.diskName,
68 zone: "us-central1-a",
69 type: "pd-standard",
70 sizeGb: 10,
71 });
72 const snapshot = yield* GCP.Compute.Snapshot("Backup", {
73 snapshotName: created.snapshot.snapshotName,
74 sourceDisk: disk.selfLink.as<string>(),
75 labels: { env: "prod", role: "backup" },
76 });
77 return { disk, snapshot };
78 }),
79 );
80
81 expect(updated.snapshot.snapshotName).toEqual(
82 created.snapshot.snapshotName,
83 );
84 expect(updated.snapshot.labels).toMatchObject({
85 env: "prod",
86 role: "backup",
87 });
88
89 const fetchedUpdated = yield* compute.getSnapshots({
90 project: updated.snapshot.project,
91 snapshot: updated.snapshot.snapshotName,
92 });
93 expect(fetchedUpdated.labels?.env).toEqual("prod");
94 expect(fetchedUpdated.labels?.role).toEqual("backup");
95
96 yield* stack.destroy();
97
98 const gone = yield* waitUntilGone(
99 created.snapshot.project,
100 created.snapshot.snapshotName,
101 );
102 expect(gone).toEqual("gone");
103 }).pipe(logLevel),
104 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 180_000 },
105);