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 waitUntilGone = (sslCertificateName: string) =>
24 GcpEnvironment.current.pipe(
25 Effect.flatMap(({ project }) =>
26 compute
27 .getSslCertificates({ project, sslCertificate: sslCertificateName })
28 .pipe(
29 Effect.as("found" as const),
30 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
31 Effect.repeat({
32 schedule: Schedule.spaced("1 second"),
33 until: (status) => status === "gone",
34 times: 10,
35 }),
36 ),
37 ),
38 );
39
40test.provider(
41 "create, replace, and delete an ssl certificate",
42 (stack) =>
43 Effect.gen(function* () {
44 const { project } = yield* GcpEnvironment.current;
45 yield* stack.destroy();
46
47 const created = yield* stack.deploy(
48 Effect.gen(function* () {
49 return yield* GCP.Compute.SslCertificate("FrontendTls", {
50 description: "frontend tls a",
51 certificate: CERT_A_PEM,
52 privateKey: KEY_A_PEM,
53 });
54 }),
55 );
56
57 expect(created.sslCertificateName).toEqual(expect.any(String));
58 expect(created.type).toEqual("SELF_MANAGED");
59 expect(created.description).toEqual("frontend tls a");
60 expect(created.certificate).toContain(
61 "MIIDIDCCAgigAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWMw",
62 );
63 expect(created.expireTime).toEqual(expect.any(String));
64 expect(created.selfLink).toEqual(expect.any(String));
65
66 const fetched = yield* compute.getSslCertificates({
67 project,
68 sslCertificate: created.sslCertificateName,
69 });
70 expect(fetched.name).toEqual(created.sslCertificateName);
71 expect(fetched.type).toEqual("SELF_MANAGED");
72 expect(fetched.description).toContain("[alchemy ");
73 expect(fetched.description).toContain("frontend tls a");
74 expect(fetched.certificate).toContain("BEGIN CERTIFICATE");
75 expect(fetched.certificate).toContain(
76 "MIIDIDCCAgigAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWMw",
77 );
78
79 const listed = yield* compute.listSslCertificates({
80 project,
81 maxResults: 500,
82 });
83 expect(
84 (listed.items ?? []).some(
85 (cert) => cert.name === created.sslCertificateName,
86 ),
87 ).toEqual(true);
88
89 const updated = yield* stack.deploy(
90 Effect.gen(function* () {
91 return yield* GCP.Compute.SslCertificate("FrontendTls", {
92 sslCertificateName: created.sslCertificateName,
93 description: "frontend tls b",
94 certificate: CERT_B_PEM,
95 privateKey: KEY_B_PEM,
96 });
97 }),
98 );
99
100 expect(updated.sslCertificateName).toEqual(created.sslCertificateName);
101 expect(updated.description).toEqual("frontend tls b");
102 expect(updated.certificate).toContain(
103 "MIIDITCCAgmgAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWQw",
104 );
105 expect(updated.certificate).not.toContain(
106 "MIIDIDCCAgigAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWMw",
107 );
108
109 const refetched = yield* compute.getSslCertificates({
110 project,
111 sslCertificate: updated.sslCertificateName,
112 });
113 expect(refetched.description).toContain("frontend tls b");
114 expect(refetched.certificate).toContain(
115 "MIIDITCCAgmgAwIBAgIUD2oKsfjRQWSWaAiVXJCmak8GeWQw",
116 );
117
118 yield* stack.destroy();
119
120 const gone = yield* waitUntilGone(created.sslCertificateName);
121 expect(gone).toEqual("gone");
122 }).pipe(logLevel),
123 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 90_000 },
124);