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, externalVpnGateway: string) =>
17 compute.getExternalVpnGateways({ project, externalVpnGateway }).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 external VPN gateway",
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.ExternalVpnGateway("Peer", {
36 description: "alchemy test external vpn",
37 redundancyType: "TWO_IPS_REDUNDANCY",
38 interfaces: [
39 { id: 0, ipAddress: "203.0.113.1" },
40 { id: 1, ipAddress: "203.0.113.2" },
41 ],
42 labels: { env: "test" },
43 });
44 }),
45 );
46
47 expect(created.externalVpnGatewayName).toEqual(expect.any(String));
48 expect(created.description).toEqual("alchemy test external vpn");
49 expect(created.redundancyType).toEqual("TWO_IPS_REDUNDANCY");
50 expect(created.labels).toMatchObject({ env: "test" });
51 expect(created.interfaces).toHaveLength(2);
52 expect(created.interfaces[0]?.ipAddress).toEqual("203.0.113.1");
53 expect(created.interfaces[1]?.ipAddress).toEqual("203.0.113.2");
54
55 const fetched = yield* compute.getExternalVpnGateways({
56 project: created.project,
57 externalVpnGateway: created.externalVpnGatewayName,
58 });
59 expect(fetched.name).toEqual(created.externalVpnGatewayName);
60 expect(fetched.description).toEqual("alchemy test external vpn");
61 expect(fetched.redundancyType).toEqual("TWO_IPS_REDUNDANCY");
62 expect(fetched.labels?.env).toEqual("test");
63 expect(fetched.labels?.["alchemy-id"]).toEqual(expect.any(String));
64 expect(fetched.interfaces?.[0]?.ipAddress).toEqual("203.0.113.1");
65 expect(fetched.interfaces?.[1]?.ipAddress).toEqual("203.0.113.2");
66
67 const updated = yield* stack.deploy(
68 Effect.gen(function* () {
69 return yield* GCP.Compute.ExternalVpnGateway("Peer", {
70 externalVpnGatewayName: created.externalVpnGatewayName,
71 description: "alchemy test external vpn",
72 redundancyType: "TWO_IPS_REDUNDANCY",
73 interfaces: [
74 { id: 0, ipAddress: "203.0.113.1" },
75 { id: 1, ipAddress: "203.0.113.2" },
76 ],
77 labels: { env: "prod", role: "vpn" },
78 });
79 }),
80 );
81
82 expect(updated.externalVpnGatewayName).toEqual(
83 created.externalVpnGatewayName,
84 );
85 expect(updated.externalVpnGatewayId).toEqual(
86 created.externalVpnGatewayId,
87 );
88 expect(updated.labels).toMatchObject({
89 env: "prod",
90 role: "vpn",
91 });
92
93 const fetchedUpdated = yield* compute.getExternalVpnGateways({
94 project: updated.project,
95 externalVpnGateway: updated.externalVpnGatewayName,
96 });
97 expect(fetchedUpdated.labels?.env).toEqual("prod");
98 expect(fetchedUpdated.labels?.role).toEqual("vpn");
99
100 yield* stack.destroy();
101
102 const gone = yield* waitUntilGone(
103 created.project,
104 created.externalVpnGatewayName,
105 );
106 expect(gone).toEqual("gone");
107 }).pipe(logLevel),
108 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 90_000 },
109);