1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as networkconnectivity from "@distilled.cloud/gcp/networkconnectivity_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";
9
10const { test } = Test.make({ providers: GCP.providers() });
11
12const logLevel = Effect.provideService(
13 MinimumLogLevel,
14 process.env.DEBUG ? "Debug" : "Info",
15);
16
17const runLifecycle = !process.env.FAST;
18
19const waitUntilGone = (name: string) =>
20 networkconnectivity
21 .getProjectsLocationsMulticloudDataTransferConfigsDestinations({ name })
22 .pipe(
23 Effect.as("found" as const),
24 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
25 Effect.repeat({
26 schedule: Schedule.spaced("2 seconds"),
27 until: (status) => status === "gone",
28 times: 10,
29 }),
30 );
31
32test.provider(
33 "getProjectsLocationsMulticloudDataTransferConfigsDestinations on a missing destination fails with a typed tag",
34 (stack) =>
35 Effect.gen(function* () {
36 const { project } = yield* GcpEnvironment.current;
37 yield* stack.destroy();
38
39 const error = yield* Effect.flip(
40 networkconnectivity.getProjectsLocationsMulticloudDataTransferConfigsDestinations(
41 {
42 name: `projects/${project}/locations/us-central1/multicloudDataTransferConfigs/alchemy-missing/destinations/alchemy-missing`,
43 },
44 ),
45 );
46 expect(error._tag).toEqual("NotFound");
47
48 yield* stack.destroy();
49 }).pipe(logLevel),
50 {
51 tags: ["provider:gcp", "provider:gcp:networkconnectivity", "live"],
52 timeout: 90_000,
53 },
54);
55
56test.provider.skipIf(!runLifecycle)(
57 "create, update, and delete a multicloud data transfer destination",
58 (stack) =>
59 Effect.gen(function* () {
60 yield* stack.destroy();
61
62 const created = yield* stack.deploy(
63 Effect.gen(function* () {
64 const config =
65 yield* GCP.NetworkConnectivity.MulticloudDataTransferConfig("Dte", {
66 location: "europe-west3",
67 description: "dte parent",
68 services: { "cloud-storage": {} },
69 });
70 const destination =
71 yield* GCP.NetworkConnectivity.MulticloudDataTransferConfigsDestination(
72 "OnPrem",
73 {
74 parent: config.name,
75 ipPrefix: "203.0.113.0/24",
76 endpoints: [{ asn: "16509", csp: "AWS" }],
77 description: "dest a",
78 labels: { env: "test" },
79 },
80 );
81 return { config, destination };
82 }),
83 );
84
85 expect(created.destination.name).toContain("/destinations/");
86 expect(created.destination.parent).toEqual(created.config.name);
87 expect(created.destination.ipPrefix).toEqual("203.0.113.0/24");
88 expect(created.destination.labels).toMatchObject({ env: "test" });
89
90 const fetched =
91 yield* networkconnectivity.getProjectsLocationsMulticloudDataTransferConfigsDestinations(
92 { name: created.destination.name },
93 );
94 expect(fetched.name).toEqual(created.destination.name);
95 expect(fetched.ipPrefix).toEqual("203.0.113.0/24");
96 expect(fetched.labels?.env).toEqual("test");
97 expect(
98 Object.keys(fetched.labels ?? {}).some((key) =>
99 key.startsWith("alchemy-"),
100 ),
101 ).toEqual(true);
102
103 const updated = yield* stack.deploy(
104 Effect.gen(function* () {
105 const config =
106 yield* GCP.NetworkConnectivity.MulticloudDataTransferConfig("Dte", {
107 multicloudDataTransferConfigId:
108 created.config.multicloudDataTransferConfigId,
109 location: created.config.location,
110 description: "dte parent",
111 services: { "cloud-storage": {} },
112 });
113 const destination =
114 yield* GCP.NetworkConnectivity.MulticloudDataTransferConfigsDestination(
115 "OnPrem",
116 {
117 parent: config.name,
118 destinationId: created.destination.destinationId,
119 ipPrefix: "203.0.113.0/24",
120 endpoints: [{ asn: "16509", csp: "AWS" }],
121 description: "dest b",
122 labels: { env: "prod", role: "dte" },
123 },
124 );
125 return { config, destination };
126 }),
127 );
128
129 expect(updated.destination.name).toEqual(created.destination.name);
130 expect(updated.destination.description).toEqual("dest b");
131 expect(updated.destination.labels).toMatchObject({
132 env: "prod",
133 role: "dte",
134 });
135
136 yield* stack.destroy();
137
138 const gone = yield* waitUntilGone(created.destination.name);
139 expect(gone).toEqual("gone");
140 }).pipe(logLevel),
141 {
142 tags: ["provider:gcp", "provider:gcp:networkconnectivity", "live"],
143 timeout: 180_000,
144 },
145);