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, httpHealthCheck: string) =>
17 compute.getHttpHealthChecks({ project, httpHealthCheck }).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(
28 "create, update, replace, and delete an HTTP health check",
29 (stack) =>
30 Effect.gen(function* () {
31 yield* stack.destroy();
32
33 const created = yield* stack.deploy(
34 Effect.gen(function* () {
35 return yield* GCP.Compute.HttpHealthCheck("Api", {
36 description: "frontend probe",
37 port: 80,
38 requestPath: "/health",
39 });
40 }),
41 );
42
43 expect(created.httpHealthCheckName).toEqual(expect.any(String));
44 expect(created.description).toEqual("frontend probe");
45 expect(created.port).toEqual(80);
46 expect(created.requestPath).toEqual("/health");
47 expect(created.checkIntervalSec).toEqual(5);
48 expect(created.healthyThreshold).toEqual(2);
49
50 const fetched = yield* compute.getHttpHealthChecks({
51 project: created.project,
52 httpHealthCheck: created.httpHealthCheckName,
53 });
54 expect(fetched.name).toEqual(created.httpHealthCheckName);
55 expect(fetched.port).toEqual(80);
56 expect(fetched.requestPath).toEqual("/health");
57 expect(fetched.description).toContain("[alchemy ");
58 expect(fetched.description).toContain("frontend probe");
59
60 const updated = yield* stack.deploy(
61 Effect.gen(function* () {
62 return yield* GCP.Compute.HttpHealthCheck("Api", {
63 httpHealthCheckName: created.httpHealthCheckName,
64 description: "ready probe",
65 checkIntervalSec: 10,
66 timeoutSec: 5,
67 healthyThreshold: 3,
68 port: 8080,
69 requestPath: "/ready",
70 host: "ready.example",
71 });
72 }),
73 );
74
75 expect(updated.httpHealthCheckName).toEqual(created.httpHealthCheckName);
76 expect(updated.description).toEqual("ready probe");
77 expect(updated.checkIntervalSec).toEqual(10);
78 expect(updated.healthyThreshold).toEqual(3);
79 expect(updated.port).toEqual(8080);
80 expect(updated.requestPath).toEqual("/ready");
81 expect(updated.host).toEqual("ready.example");
82
83 const refetched = yield* compute.getHttpHealthChecks({
84 project: updated.project,
85 httpHealthCheck: updated.httpHealthCheckName,
86 });
87 expect(refetched.requestPath).toEqual("/ready");
88 expect(refetched.checkIntervalSec).toEqual(10);
89 expect(refetched.port).toEqual(8080);
90 expect(refetched.host).toEqual("ready.example");
91
92 const nextName = `r${created.httpHealthCheckName}`
93 .slice(0, 63)
94 .replace(/-+$/, "x");
95 const replaced = yield* stack.deploy(
96 Effect.gen(function* () {
97 return yield* GCP.Compute.HttpHealthCheck("Api", {
98 httpHealthCheckName: nextName,
99 description: "replaced probe",
100 requestPath: "/live",
101 });
102 }),
103 );
104
105 expect(replaced.httpHealthCheckName).toEqual(nextName);
106 expect(replaced.description).toEqual("replaced probe");
107 expect(replaced.requestPath).toEqual("/live");
108 expect(replaced.port).toEqual(80);
109
110 const afterReplace = yield* compute.getHttpHealthChecks({
111 project: replaced.project,
112 httpHealthCheck: replaced.httpHealthCheckName,
113 });
114 expect(afterReplace.name).toEqual(nextName);
115 expect(afterReplace.requestPath).toEqual("/live");
116
117 const oldGone = yield* waitUntilGone(
118 created.project,
119 created.httpHealthCheckName,
120 );
121 expect(oldGone).toEqual("gone");
122
123 yield* stack.destroy();
124
125 const gone = yield* waitUntilGone(
126 replaced.project,
127 replaced.httpHealthCheckName,
128 );
129 expect(gone).toEqual("gone");
130 }).pipe(logLevel),
131 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 90_000 },
132);