1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as managedidentities from "@distilled.cloud/gcp/managedidentities_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
17// Domain peering is cross-project only. Same-project create returns
18// `BadRequest` ("DomainPeering should be used when network and domain
19// resource belong to different projects"). Full lifecycle needs a
20// domain in another project via GCP_TEST_MANAGEDIDENTITIES_DOMAIN.
21const runLifecycle =
22 !process.env.FAST &&
23 process.env.GCP_TEST_MANAGEDIDENTITIES === "1" &&
24 !!process.env.GCP_TEST_MANAGEDIDENTITIES_DOMAIN;
25const foreignDomain = process.env.GCP_TEST_MANAGEDIDENTITIES_DOMAIN ?? "";
26
27const waitUntilGone = (name: string) =>
28 managedidentities.getProjectsLocationsGlobalPeerings({ name }).pipe(
29 Effect.as("found" as const),
30 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
31 Effect.repeat({
32 schedule: Schedule.spaced("2 seconds"),
33 until: (status) => status === "gone",
34 times: 10,
35 }),
36 );
37
38test.provider(
39 "getProjectsLocationsGlobalPeerings on a missing peering fails with a typed tag",
40 (stack) =>
41 Effect.gen(function* () {
42 const { project } = yield* GcpEnvironment.current;
43 yield* stack.destroy();
44
45 const error = yield* Effect.flip(
46 managedidentities.getProjectsLocationsGlobalPeerings({
47 name: `projects/${project}/locations/global/peerings/alchemy-peering-missing`,
48 }),
49 );
50 expect(error._tag).toEqual("NotFound");
51
52 yield* stack.destroy();
53 }).pipe(logLevel),
54 {
55 tags: ["provider:gcp", "provider:gcp:managedidentities", "live"],
56 timeout: 90_000,
57 },
58);
59
60test.provider.skipIf(runLifecycle)(
61 "a same-project peering is rejected with BadRequest",
62 (stack) =>
63 Effect.gen(function* () {
64 const { project } = yield* GcpEnvironment.current;
65 const missingDomain = `projects/${project}/locations/global/domains/missing.alch.test`;
66 yield* stack.destroy();
67
68 const error = yield* Effect.flip(
69 stack.deploy(
70 Effect.gen(function* () {
71 return yield* GCP.ManagedIdentities.Peering("Spoke", {
72 domainResource: missingDomain,
73 authorizedNetwork: "default",
74 labels: { env: "test" },
75 });
76 }),
77 ),
78 );
79 expect(error._tag).toEqual("BadRequest");
80
81 yield* stack.destroy();
82 }).pipe(logLevel),
83 {
84 tags: ["provider:gcp", "provider:gcp:managedidentities", "live"],
85 timeout: 90_000,
86 },
87);
88
89test.provider.skipIf(!runLifecycle)(
90 "create, update, and delete a domain peering",
91 (stack) =>
92 Effect.gen(function* () {
93 yield* stack.destroy();
94
95 const created = yield* stack.deploy(
96 Effect.gen(function* () {
97 return yield* GCP.ManagedIdentities.Peering("Spoke", {
98 domainResource: foreignDomain,
99 authorizedNetwork: "default",
100 labels: { env: "test" },
101 });
102 }),
103 );
104
105 expect(created.name).toContain("/peerings/");
106 expect(created.peeringId).toEqual(expect.any(String));
107 expect(created.domainResource).toEqual(foreignDomain);
108 expect(created.labels).toMatchObject({ env: "test" });
109
110 const fetched =
111 yield* managedidentities.getProjectsLocationsGlobalPeerings({
112 name: created.name,
113 });
114 expect(fetched.name).toEqual(created.name);
115 expect(fetched.labels?.env).toEqual("test");
116
117 const updated = yield* stack.deploy(
118 Effect.gen(function* () {
119 return yield* GCP.ManagedIdentities.Peering("Spoke", {
120 peeringId: created.peeringId,
121 domainResource: foreignDomain,
122 authorizedNetwork: "default",
123 labels: { env: "prod", role: "peering" },
124 });
125 }),
126 );
127
128 expect(updated.name).toEqual(created.name);
129 expect(updated.labels).toMatchObject({
130 env: "prod",
131 role: "peering",
132 });
133
134 const refetched =
135 yield* managedidentities.getProjectsLocationsGlobalPeerings({
136 name: created.name,
137 });
138 expect(refetched.labels?.env).toEqual("prod");
139 expect(refetched.labels?.role).toEqual("peering");
140
141 yield* stack.destroy();
142
143 const gone = yield* waitUntilGone(created.name);
144 expect(gone).toEqual("gone");
145 }).pipe(logLevel),
146 {
147 tags: ["provider:gcp", "provider:gcp:managedidentities", "live"],
148 timeout: 240_000,
149 },
150);