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 { withNetworkSlot } 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 = (project: string, networkName: string) =>
18 compute.getNetworks({ project, network: networkName }).pipe(
19 Effect.as("found" as const),
20 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
21 Effect.repeat({
22 schedule: Schedule.spaced("1 second"),
23 until: (status) => status === "gone",
24 times: 20,
25 }),
26 );
27
28test.provider(
29 "create, update, replace, and delete a network",
30 (stack) =>
31 Effect.gen(function* () {
32 yield* stack.destroy();
33
34 const created = yield* stack.deploy(
35 Effect.gen(function* () {
36 return yield* GCP.Compute.Network("Vpc", {
37 description: "vpc for tests",
38 autoCreateSubnetworks: false,
39 mtu: 1460,
40 routingMode: "REGIONAL",
41 });
42 }),
43 );
44
45 expect(created.networkName).toEqual(expect.any(String));
46 expect(created.networkId).toEqual(expect.any(String));
47 expect(created.autoCreateSubnetworks).toEqual(false);
48 expect(created.description).toEqual("vpc for tests");
49 expect(created.mtu).toEqual(1460);
50 expect(created.routingMode).toEqual("REGIONAL");
51 expect(created.selfLink).toEqual(expect.stringContaining("networks/"));
52
53 const fetched = yield* compute.getNetworks({
54 project: created.project,
55 network: created.networkName,
56 });
57 expect(fetched.name).toEqual(created.networkName);
58 expect(fetched.autoCreateSubnetworks).toEqual(false);
59 expect(fetched.description).toContain("alchemy-id=");
60 expect(fetched.description).toContain("vpc for tests");
61
62 const updated = yield* stack.deploy(
63 Effect.gen(function* () {
64 return yield* GCP.Compute.Network("Vpc", {
65 networkName: created.networkName,
66 description: "vpc for tests",
67 autoCreateSubnetworks: false,
68 mtu: 1500,
69 routingMode: "GLOBAL",
70 });
71 }),
72 );
73
74 expect(updated.networkName).toEqual(created.networkName);
75 expect(updated.networkId).toEqual(created.networkId);
76 expect(updated.description).toEqual("vpc for tests");
77 expect(updated.mtu).toEqual(1500);
78 expect(updated.routingMode).toEqual("GLOBAL");
79
80 const fetchedUpdate = yield* compute.getNetworks({
81 project: created.project,
82 network: created.networkName,
83 });
84 expect(fetchedUpdate.mtu).toEqual(1500);
85 expect(fetchedUpdate.routingConfig?.routingMode).toEqual("GLOBAL");
86 expect(fetchedUpdate.description).toContain("vpc for tests");
87
88 const replaced = yield* stack.deploy(
89 Effect.gen(function* () {
90 return yield* GCP.Compute.Network("Vpc", {
91 networkName: created.networkName,
92 description: "vpc replaced",
93 autoCreateSubnetworks: false,
94 mtu: 1500,
95 routingMode: "GLOBAL",
96 });
97 }),
98 );
99
100 expect(replaced.networkName).toEqual(created.networkName);
101 expect(replaced.description).toEqual("vpc replaced");
102 expect(replaced.networkId).not.toEqual(created.networkId);
103
104 const fetchedReplace = yield* compute.getNetworks({
105 project: created.project,
106 network: created.networkName,
107 });
108 expect(fetchedReplace.description).toContain("vpc replaced");
109 expect(fetchedReplace.mtu).toEqual(1500);
110
111 yield* stack.destroy();
112
113 const gone = yield* waitUntilGone(created.project, created.networkName);
114 expect(gone).toEqual("gone");
115 }).pipe(logLevel, withNetworkSlot),
116 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 180_000 },
117);