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";
8import {
9 CERT_A_PEM,
10 CERT_B_PEM,
11 KEY_A_PEM,
12 KEY_B_PEM,
13} from "./fixtures/https-proxy-cert.ts";
14import { GcpEnvironment } from "@/GCP/Environment";
15
16const { test } = Test.make({ providers: GCP.providers() });
17
18const logLevel = Effect.provideService(
19 MinimumLogLevel,
20 process.env.DEBUG ? "Debug" : "Info",
21);
22
23const region = "us-central1";
24
25const waitUntilGone = (sslCertificateName: string) =>
26 GcpEnvironment.current.pipe(
27 Effect.flatMap(({ project }) =>
28 compute
29 .getRegionSslCertificates({
30 project,
31 region,
32 sslCertificate: sslCertificateName,
33 })
34 .pipe(
35 Effect.as("found" as const),
36 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
37 Effect.repeat({
38 schedule: Schedule.spaced("1 second"),
39 until: (status) => status === "gone",
40 times: 10,
41 }),
42 ),
43 ),
44 );
45
46test.provider(
47 "create, replace, and delete a regional ssl certificate",
48 (stack) =>
49 Effect.gen(function* () {
50 const { project } = yield* GcpEnvironment.current;
51 yield* stack.destroy();
52
53 const created = yield* stack.deploy(
54 Effect.gen(function* () {
55 return yield* GCP.Compute.RegionSslCertificate("FrontendTls", {
56 region,
57 description: "frontend tls a",
58 certificate: CERT_A_PEM,
59 privateKey: KEY_A_PEM,
60 });
61 }),
62 );
63
64 expect(created.sslCertificateName).toEqual(expect.any(String));
65 expect(created.region).toEqual(region);
66 expect(created.type).toEqual("SELF_MANAGED");
67 expect(created.description).toEqual("frontend tls a");
68 expect(created.certificate).toContain(
69 "MIIDIDCCAgigAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWMw",
70 );
71 expect(created.expireTime).toEqual(expect.any(String));
72 expect(created.selfLink).toEqual(expect.any(String));
73
74 const fetched = yield* compute.getRegionSslCertificates({
75 project,
76 region,
77 sslCertificate: created.sslCertificateName,
78 });
79 expect(fetched.name).toEqual(created.sslCertificateName);
80 expect(fetched.type).toEqual("SELF_MANAGED");
81 expect(fetched.description).toContain("[alchemy ");
82 expect(fetched.description).toContain("frontend tls a");
83 expect(fetched.certificate).toContain("BEGIN CERTIFICATE");
84 expect(fetched.certificate).toContain(
85 "MIIDIDCCAgigAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWMw",
86 );
87
88 const listed = yield* compute.listRegionSslCertificates({
89 project,
90 region,
91 maxResults: 500,
92 });
93 expect(
94 (listed.items ?? []).some(
95 (cert) => cert.name === created.sslCertificateName,
96 ),
97 ).toEqual(true);
98
99 const updated = yield* stack.deploy(
100 Effect.gen(function* () {
101 return yield* GCP.Compute.RegionSslCertificate("FrontendTls", {
102 sslCertificateName: created.sslCertificateName,
103 region,
104 description: "frontend tls b",
105 certificate: CERT_B_PEM,
106 privateKey: KEY_B_PEM,
107 });
108 }),
109 );
110
111 expect(updated.sslCertificateName).toEqual(created.sslCertificateName);
112 expect(updated.description).toEqual("frontend tls b");
113 expect(updated.certificate).toContain(
114 "MIIDITCCAgmgAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWQw",
115 );
116 expect(updated.certificate).not.toContain(
117 "MIIDIDCCAgigAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWMw",
118 );
119
120 const refetched = yield* compute.getRegionSslCertificates({
121 project,
122 region,
123 sslCertificate: updated.sslCertificateName,
124 });
125 expect(refetched.description).toContain("frontend tls b");
126 expect(refetched.certificate).toContain(
127 "MIIDITCCAgmgAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWQw",
128 );
129
130 yield* stack.destroy();
131
132 const gone = yield* waitUntilGone(created.sslCertificateName);
133 expect(gone).toEqual("gone");
134 }).pipe(logLevel),
135 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 90_000 },
136);