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 = (project: string, routeName: string) =>
18 compute.getRoutes({ project, route: routeName }).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: 10,
25 }),
26 );
27
28test.provider(
29 "create, replace, and delete a route",
30 (stack) =>
31 Effect.gen(function* () {
32 yield* stack.destroy();
33
34 const created = yield* stack.deploy(
35 Effect.gen(function* () {
36 const route = yield* GCP.Compute.Route("Internet", {
37 destRange: "192.0.2.0/24",
38 network: DEFAULT_NETWORK,
39 nextHopGateway: "default-internet-gateway",
40 description: "test-net egress",
41 tags: ["alchemy-test"],
42 });
43 return { route };
44 }),
45 );
46
47 expect(created.route.routeName).toEqual(expect.any(String));
48 expect(created.route.destRange).toEqual("192.0.2.0/24");
49 expect(created.route.priority).toEqual(1000);
50 expect(created.route.description).toEqual("test-net egress");
51 expect(created.route.tags).toEqual(["alchemy-test"]);
52 expect(created.route.network).toContain(`networks/${DEFAULT_NETWORK}`);
53 expect(created.route.nextHopGateway).toContain(
54 "default-internet-gateway",
55 );
56
57 const fetched = yield* compute.getRoutes({
58 project: created.route.project,
59 route: created.route.routeName,
60 });
61 expect(fetched.name).toEqual(created.route.routeName);
62 expect(fetched.destRange).toEqual("192.0.2.0/24");
63 expect(fetched.description).toContain("[alchemy ");
64 expect(fetched.description).toContain("test-net egress");
65 expect(fetched.tags).toEqual(["alchemy-test"]);
66
67 const updated = yield* stack.deploy(
68 Effect.gen(function* () {
69 const route = yield* GCP.Compute.Route("Internet", {
70 routeName: created.route.routeName,
71 destRange: "198.51.100.0/24",
72 network: DEFAULT_NETWORK,
73 nextHopGateway: "default-internet-gateway",
74 description: "updated test-net",
75 priority: 900,
76 });
77 return { route };
78 }),
79 );
80
81 expect(updated.route.routeName).toEqual(created.route.routeName);
82 expect(updated.route.destRange).toEqual("198.51.100.0/24");
83 expect(updated.route.description).toEqual("updated test-net");
84 expect(updated.route.priority).toEqual(900);
85 expect(updated.route.tags).toEqual([]);
86
87 const refetched = yield* compute.getRoutes({
88 project: updated.route.project,
89 route: updated.route.routeName,
90 });
91 expect(refetched.destRange).toEqual("198.51.100.0/24");
92 expect(refetched.priority).toEqual(900);
93 expect(refetched.description).toContain("updated test-net");
94
95 yield* stack.destroy();
96
97 const gone = yield* waitUntilGone(
98 created.route.project,
99 created.route.routeName,
100 );
101 expect(gone).toEqual("gone");
102 }).pipe(logLevel),
103 { tags: ["provider:gcp", "provider:gcp:compute", "live"], timeout: 120_000 },
104);