1import * as GCP from "@/GCP";
2import { GcpEnvironment } from "@/GCP/Environment";
3import * as Test from "@/Test/Alchemy";
4import * as eventarc from "@distilled.cloud/gcp/eventarc_v1";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8import * as Schedule from "effect/Schedule";
9
10const { test } = Test.make({ providers: GCP.providers() });
11
12const logLevel = Effect.provideService(
13 MinimumLogLevel,
14 process.env.DEBUG ? "Debug" : "Info",
15);
16
17// Enrollment depends on a Pipeline, whose create/update/delete LROs take
18// over 15 minutes end to end.
19const runLifecycle = !!process.env.GCP_TEST_SLOW && !process.env.FAST;
20const LOCATION = "europe-west1";
21
22const waitUntilGone = (name: string) =>
23 eventarc.getProjectsLocationsEnrollments({ name }).pipe(
24 Effect.as("found" as const),
25 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
26 Effect.repeat({
27 schedule: Schedule.spaced("2 seconds"),
28 until: (status) => status === "gone",
29 times: 10,
30 }),
31 );
32
33test.provider(
34 "getProjectsLocationsEnrollments on a missing enrollment fails with a typed tag",
35 (stack) =>
36 Effect.gen(function* () {
37 const { project } = yield* GcpEnvironment.current;
38 yield* stack.destroy();
39
40 const error = yield* Effect.flip(
41 eventarc.getProjectsLocationsEnrollments({
42 name: `projects/${project}/locations/${LOCATION}/enrollments/alchemy-missing-enrollment`,
43 }),
44 );
45 expect(error._tag).toEqual("NotFound");
46
47 yield* stack.destroy();
48 }).pipe(logLevel),
49 { tags: ["provider:gcp", "provider:gcp:eventarc", "live"], timeout: 90_000 },
50);
51
52test.provider.skipIf(!runLifecycle)(
53 "create, update, and delete an Eventarc enrollment",
54 (stack) =>
55 Effect.gen(function* () {
56 yield* stack.destroy();
57
58 const created = yield* stack.deploy(
59 Effect.gen(function* () {
60 const bus = yield* GCP.Eventarc.MessageBus("Events", {
61 location: LOCATION,
62 labels: { env: "test" },
63 });
64 const pipeline = yield* GCP.Eventarc.Pipeline("Forward", {
65 location: LOCATION,
66 destinations: [{ messageBus: bus.name }],
67 labels: { env: "test" },
68 });
69 const enrollment = yield* GCP.Eventarc.Enrollment("All", {
70 location: LOCATION,
71 messageBus: bus.name,
72 destination: pipeline.name,
73 celMatch: "true",
74 displayName: "all events",
75 labels: { env: "test" },
76 });
77 return { bus, pipeline, enrollment };
78 }),
79 );
80
81 expect(created.enrollment.name).toContain("/enrollments/");
82 expect(created.enrollment.enrollmentId).toEqual(expect.any(String));
83 expect(created.enrollment.location).toEqual(LOCATION);
84 expect(created.enrollment.celMatch).toEqual("true");
85 expect(created.enrollment.messageBus).toEqual(created.bus.name);
86 expect(created.enrollment.destination).toEqual(created.pipeline.name);
87 expect(created.enrollment.labels).toMatchObject({ env: "test" });
88
89 const fetched = yield* eventarc.getProjectsLocationsEnrollments({
90 name: created.enrollment.name,
91 });
92 expect(fetched.name).toEqual(created.enrollment.name);
93 expect(fetched.labels?.env).toEqual("test");
94 expect(fetched.celMatch).toEqual("true");
95
96 const updated = yield* stack.deploy(
97 Effect.gen(function* () {
98 const bus = yield* GCP.Eventarc.MessageBus("Events", {
99 messageBusId: created.bus.messageBusId,
100 location: LOCATION,
101 labels: { env: "test" },
102 });
103 const pipeline = yield* GCP.Eventarc.Pipeline("Forward", {
104 pipelineId: created.pipeline.pipelineId,
105 location: LOCATION,
106 destinations: [{ messageBus: bus.name }],
107 labels: { env: "test" },
108 });
109 return yield* GCP.Eventarc.Enrollment("All", {
110 enrollmentId: created.enrollment.enrollmentId,
111 location: LOCATION,
112 messageBus: bus.name,
113 destination: pipeline.name,
114 celMatch:
115 "message.type == 'google.cloud.pubsub.topic.v1.messagePublished'",
116 displayName: "pubsub only",
117 labels: { env: "prod", role: "enrollment" },
118 });
119 }),
120 );
121
122 expect(updated.name).toEqual(created.enrollment.name);
123 expect(updated.enrollmentId).toEqual(created.enrollment.enrollmentId);
124 expect(updated.displayName).toEqual("pubsub only");
125 expect(updated.labels).toMatchObject({
126 env: "prod",
127 role: "enrollment",
128 });
129 expect(updated.celMatch).toContain("messagePublished");
130
131 const refetched = yield* eventarc.getProjectsLocationsEnrollments({
132 name: created.enrollment.name,
133 });
134 expect(refetched.labels?.env).toEqual("prod");
135 expect(refetched.labels?.role).toEqual("enrollment");
136 expect(refetched.displayName).toEqual("pubsub only");
137
138 yield* stack.destroy();
139
140 const gone = yield* waitUntilGone(created.enrollment.name);
141 expect(gone).toEqual("gone");
142 }).pipe(logLevel),
143 {
144 tags: ["provider:gcp", "provider:gcp:eventarc", "live"],
145 timeout: 2_400_000,
146 },
147);