1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as monitoring from "@distilled.cloud/gcp/monitoring_v3";
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 = (name: string) =>
17 monitoring.getProjectsUptimeCheckConfigs({ name }).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, and delete an uptime 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.Monitoring.UptimeCheckConfig("Homepage", {
36 timeout: "10s",
37 period: "600s",
38 httpCheck: {
39 path: "/",
40 port: 443,
41 useSsl: true,
42 validateSsl: true,
43 },
44 monitoredResource: {
45 type: "uptime_url",
46 labels: { host: "example.com" },
47 },
48 labels: { env: "test" },
49 });
50 }),
51 );
52
53 expect(created.name).toContain("/uptimeCheckConfigs/");
54 expect(created.uptimeCheckConfigId).toEqual(expect.any(String));
55 expect(created.timeout).toEqual("10s");
56 expect(created.period).toEqual("600s");
57 expect(created.httpCheck?.useSsl).toEqual(true);
58 expect(created.httpCheck?.path ?? "/").toEqual("/");
59 expect(created.monitoredResource?.type).toEqual("uptime_url");
60 expect(created.monitoredResource?.labels?.host).toEqual("example.com");
61 expect(created.labels).toMatchObject({ env: "test" });
62 expect(created.disabled).toEqual(false);
63
64 const fetched = yield* monitoring.getProjectsUptimeCheckConfigs({
65 name: created.name,
66 });
67 expect(fetched.name).toEqual(created.name);
68 expect(fetched.timeout).toEqual("10s");
69 expect(fetched.period).toEqual("600s");
70 expect(fetched.httpCheck?.useSsl).toEqual(true);
71 expect(fetched.monitoredResource?.labels?.host).toEqual("example.com");
72 expect(fetched.userLabels?.env).toEqual("test");
73 expect(
74 Object.keys(fetched.userLabels ?? {}).some((key) =>
75 key.startsWith("alchemy-"),
76 ),
77 ).toEqual(true);
78
79 const updated = yield* stack.deploy(
80 Effect.gen(function* () {
81 return yield* GCP.Monitoring.UptimeCheckConfig("Homepage", {
82 displayName: created.displayName,
83 timeout: "20s",
84 period: "300s",
85 httpCheck: {
86 path: "/status",
87 port: 443,
88 useSsl: true,
89 validateSsl: true,
90 },
91 monitoredResource: {
92 type: "uptime_url",
93 labels: { host: "example.com" },
94 },
95 labels: { env: "prod", role: "uptime" },
96 });
97 }),
98 );
99
100 expect(updated.name).toEqual(created.name);
101 expect(updated.timeout).toEqual("20s");
102 expect(updated.period).toEqual("300s");
103 expect(updated.httpCheck?.path).toEqual("/status");
104 expect(updated.labels).toMatchObject({ env: "prod", role: "uptime" });
105
106 const fetchedUpdate = yield* monitoring.getProjectsUptimeCheckConfigs({
107 name: updated.name,
108 });
109 expect(fetchedUpdate.timeout).toEqual("20s");
110 expect(fetchedUpdate.period).toEqual("300s");
111 expect(fetchedUpdate.httpCheck?.path).toEqual("/status");
112 expect(fetchedUpdate.userLabels?.env).toEqual("prod");
113
114 yield* stack.destroy();
115
116 const gone = yield* waitUntilGone(created.name);
117 expect(gone).toEqual("gone");
118 }).pipe(logLevel),
119 {
120 tags: ["provider:gcp", "provider:gcp:monitoring", "live"],
121 timeout: 90_000,
122 },
123);