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 { DEFAULT_NETWORK } from "../networkQuota.ts";
9
10const { test } = Test.make({ providers: GCP.providers() });
11
12const logLevel = Effect.provideService(
13 MinimumLogLevel,
14 process.env.DEBUG ? "Debug" : "Info",
15);
16
17const waitUntilGone = (
18 project: string,
19 region: string,
20 targetVpnGatewayName: string,
21) =>
22 compute
23 .getTargetVpnGateways({
24 project,
25 region,
26 targetVpnGateway: targetVpnGatewayName,
27 })
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
38test.provider.skipIf(!!process.env.FAST)(
39 "create, update, and delete a Classic VPN gateway",
40 (stack) =>
41 Effect.gen(function* () {
42 yield* stack.destroy();
43
44 const created = yield* stack.deploy(
45 Effect.gen(function* () {
46 const gateway = yield* GCP.Compute.TargetVpnGateway("Gateway", {
47 region: "us-central1",
48 network: DEFAULT_NETWORK,
49 description: "classic vpn",
50 labels: { env: "test" },
51 });
52 return { gateway };
53 }),
54 );
55
56 expect(created.gateway.targetVpnGatewayName).toEqual(expect.any(String));
57 expect(created.gateway.region).toEqual("us-central1");
58 expect(created.gateway.network).toEqual(
59 expect.stringContaining(`/networks/${DEFAULT_NETWORK}`),
60 );
61 expect(created.gateway.description).toEqual("classic vpn");
62 expect(created.gateway.labels).toMatchObject({ env: "test" });
63 expect(created.gateway.status).toEqual("READY");
64
65 const fetched = yield* compute.getTargetVpnGateways({
66 project: created.gateway.project,
67 region: created.gateway.region,
68 targetVpnGateway: created.gateway.targetVpnGatewayName,
69 });
70 expect(fetched.name).toEqual(created.gateway.targetVpnGatewayName);
71 expect(fetched.description).toEqual("classic vpn");
72 expect(fetched.labels?.env).toEqual("test");
73 expect(fetched.labels?.["alchemy-id"]).toEqual(expect.any(String));
74 expect(fetched.network).toEqual(
75 expect.stringContaining(`/networks/${DEFAULT_NETWORK}`),
76 );
77
78 const updated = yield* stack.deploy(
79 Effect.gen(function* () {
80 const gateway = yield* GCP.Compute.TargetVpnGateway("Gateway", {
81 targetVpnGatewayName: created.gateway.targetVpnGatewayName,
82 region: "us-central1",
83 network: DEFAULT_NETWORK,
84 description: "classic vpn",
85 labels: { env: "prod", role: "vpn" },
86 });
87 return { gateway };
88 }),
89 );
90
91 expect(updated.gateway.targetVpnGatewayName).toEqual(
92 created.gateway.targetVpnGatewayName,
93 );
94 expect(updated.gateway.targetVpnGatewayId).toEqual(
95 created.gateway.targetVpnGatewayId,
96 );
97 expect(updated.gateway.labels).toMatchObject({
98 env: "prod",
99 role: "vpn",
100 });
101
102 const fetchedUpdated = yield* compute.getTargetVpnGateways({
103 project: updated.gateway.project,
104 region: updated.gateway.region,
105 targetVpnGateway: updated.gateway.targetVpnGatewayName,
106 });
107 expect(fetchedUpdated.labels?.env).toEqual("prod");
108 expect(fetchedUpdated.labels?.role).toEqual("vpn");
109
110 yield* stack.destroy();
111
112 const gone = yield* waitUntilGone(
113 created.gateway.project,
114 created.gateway.region,
115 created.gateway.targetVpnGatewayName,
116 );
117 expect(gone).toEqual("gone");
118 }).pipe(logLevel),
119 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 180_000 },
120);