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