1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as networksecurity from "@distilled.cloud/gcp/networksecurity_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8import { GcpEnvironment } from "@/GCP/Environment";
9import { withNetworkSlot } from "../networkQuota.ts";
10
11const { test } = Test.make({ providers: GCP.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const waitUntilGone = (name: string) =>
19 networksecurity.getProjectsLocationsMirroringEndpointGroups({ name }).pipe(
20 Effect.as("found" as const),
21 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
22 Effect.repeat({
23 schedule: Schedule.spaced("2 seconds"),
24 until: (status) => status === "gone",
25 times: 10,
26 }),
27 );
28
29test.provider(
30 "getProjectsLocationsMirroringEndpointGroups on a missing group fails with a typed tag",
31 (stack) =>
32 Effect.gen(function* () {
33 yield* stack.destroy();
34
35 const { project } = yield* GcpEnvironment.current;
36 const error = yield* Effect.flip(
37 networksecurity.getProjectsLocationsMirroringEndpointGroups({
38 name: `projects/${project}/locations/global/mirroringEndpointGroups/alchemy-missing`,
39 }),
40 );
41 expect(error._tag).toEqual("NotFound");
42
43 yield* stack.destroy();
44 }).pipe(logLevel),
45 {
46 tags: ["provider:gcp", "provider:gcp:networksecurity", "live"],
47 timeout: 90_000,
48 },
49);
50
51test.provider.skipIf(!!process.env.FAST)(
52 "create, update, and delete a mirroring endpoint group",
53 (stack) =>
54 Effect.gen(function* () {
55 yield* stack.destroy();
56
57 const created = yield* stack.deploy(
58 Effect.gen(function* () {
59 const vpc = yield* GCP.Compute.Network("Vpc", {
60 autoCreateSubnetworks: false,
61 description: "mirroring endpoint vpc",
62 });
63 const collectors =
64 yield* GCP.NetworkSecurity.MirroringDeploymentGroup("Collectors", {
65 network: vpc.selfLink.as<string>(),
66 description: "collectors",
67 });
68 const group = yield* GCP.NetworkSecurity.MirroringEndpointGroup(
69 "Front",
70 {
71 mirroringDeploymentGroup: collectors.name,
72 description: "mirroring eg a",
73 labels: { env: "test" },
74 },
75 );
76 return { vpc, collectors, group };
77 }),
78 );
79
80 expect(created.group.name).toContain("/mirroringEndpointGroups/");
81 expect(created.group.location).toEqual("global");
82 expect(created.group.description).toEqual("mirroring eg a");
83 expect(created.group.labels).toMatchObject({ env: "test" });
84 expect(created.group.mirroringDeploymentGroup).toEqual(
85 created.collectors.name,
86 );
87
88 const fetched =
89 yield* networksecurity.getProjectsLocationsMirroringEndpointGroups({
90 name: created.group.name,
91 });
92 expect(fetched.name).toEqual(created.group.name);
93 expect(fetched.description).toEqual("mirroring eg a");
94 expect(fetched.labels?.env).toEqual("test");
95 expect(
96 Object.keys(fetched.labels ?? {}).some((key) =>
97 key.startsWith("alchemy-"),
98 ),
99 ).toEqual(true);
100
101 const updated = yield* stack.deploy(
102 Effect.gen(function* () {
103 const vpc = yield* GCP.Compute.Network("Vpc", {
104 networkName: created.vpc.networkName,
105 autoCreateSubnetworks: false,
106 description: "mirroring endpoint vpc",
107 });
108 const collectors =
109 yield* GCP.NetworkSecurity.MirroringDeploymentGroup("Collectors", {
110 mirroringDeploymentGroupId:
111 created.collectors.mirroringDeploymentGroupId,
112 network: vpc.selfLink.as<string>(),
113 description: "collectors",
114 });
115 const group = yield* GCP.NetworkSecurity.MirroringEndpointGroup(
116 "Front",
117 {
118 mirroringEndpointGroupId: created.group.mirroringEndpointGroupId,
119 mirroringDeploymentGroup: collectors.name,
120 description: "mirroring eg b",
121 labels: { env: "prod", role: "nsi" },
122 },
123 );
124 return { vpc, collectors, group };
125 }),
126 );
127
128 expect(updated.group.name).toEqual(created.group.name);
129 expect(updated.group.description).toEqual("mirroring eg b");
130 expect(updated.group.labels).toMatchObject({
131 env: "prod",
132 role: "nsi",
133 });
134
135 const refetched =
136 yield* networksecurity.getProjectsLocationsMirroringEndpointGroups({
137 name: created.group.name,
138 });
139 expect(refetched.description).toEqual("mirroring eg b");
140 expect(refetched.labels?.env).toEqual("prod");
141 expect(refetched.labels?.role).toEqual("nsi");
142
143 yield* stack.destroy();
144
145 const gone = yield* waitUntilGone(created.group.name);
146 expect(gone).toEqual("gone");
147 }).pipe(logLevel, withNetworkSlot),
148 {
149 tags: ["provider:gcp", "provider:gcp:networksecurity", "live"],
150 timeout: 600_000,
151 },
152);