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// ChannelConnection is created in a third-party provider project using
18// a subscriber Channel activation token. The testing project is not an
19// Eventarc SaaS partner; live create is gated.
20const runLifecycle =
21 !process.env.FAST && process.env.GCP_TEST_EVENTARC_PARTNER === "1";
22const LOCATION = "us-central1";
23
24const waitUntilGone = (name: string) =>
25 eventarc.getProjectsLocationsChannelConnections({ name }).pipe(
26 Effect.as("found" as const),
27 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
28 Effect.repeat({
29 schedule: Schedule.spaced("2 seconds"),
30 until: (status) => status === "gone",
31 times: 10,
32 }),
33 );
34
35test.provider(
36 "getProjectsLocationsChannelConnections on a missing connection fails with a typed tag",
37 (stack) =>
38 Effect.gen(function* () {
39 const { project } = yield* GcpEnvironment.current;
40 yield* stack.destroy();
41
42 const error = yield* Effect.flip(
43 eventarc.getProjectsLocationsChannelConnections({
44 name: `projects/${project}/locations/${LOCATION}/channelConnections/alchemy-missing-connection`,
45 }),
46 );
47 expect(error._tag).toEqual("NotFound");
48
49 yield* stack.destroy();
50 }).pipe(logLevel),
51 { tags: ["provider:gcp", "provider:gcp:eventarc", "live"], timeout: 90_000 },
52);
53
54test.provider.skipIf(!runLifecycle)(
55 "create, update, and delete an Eventarc channel connection",
56 (stack) =>
57 Effect.gen(function* () {
58 yield* stack.destroy();
59
60 const created = yield* stack.deploy(
61 Effect.gen(function* () {
62 const channel = yield* GCP.Eventarc.Channel("Events", {
63 location: LOCATION,
64 labels: { env: "test" },
65 });
66 const connection = yield* GCP.Eventarc.ChannelConnection("Partner", {
67 location: LOCATION,
68 channel: channel.name,
69 activationToken: channel.activationToken,
70 labels: { env: "test" },
71 });
72 return { channel, connection };
73 }),
74 );
75
76 expect(created.connection.name).toContain("/channelConnections/");
77 expect(created.connection.channelConnectionId).toEqual(
78 expect.any(String),
79 );
80 expect(created.connection.location).toEqual(LOCATION);
81 expect(created.connection.channel).toEqual(created.channel.name);
82 expect(created.connection.labels).toMatchObject({ env: "test" });
83
84 const fetched = yield* eventarc.getProjectsLocationsChannelConnections({
85 name: created.connection.name,
86 });
87 expect(fetched.name).toEqual(created.connection.name);
88 expect(fetched.labels?.env).toEqual("test");
89 expect(fetched.channel).toEqual(created.channel.name);
90
91 const updated = yield* stack.deploy(
92 Effect.gen(function* () {
93 const channel = yield* GCP.Eventarc.Channel("Events", {
94 channelId: created.channel.channelId,
95 location: LOCATION,
96 labels: { env: "test" },
97 });
98 return yield* GCP.Eventarc.ChannelConnection("Partner", {
99 channelConnectionId: created.connection.channelConnectionId,
100 location: LOCATION,
101 channel: channel.name,
102 labels: { env: "prod", role: "connection" },
103 });
104 }),
105 );
106
107 expect(updated.channel).toEqual(created.channel.name);
108 expect(updated.labels).toMatchObject({
109 env: "prod",
110 role: "connection",
111 });
112
113 yield* stack.destroy();
114
115 const gone = yield* waitUntilGone(created.connection.name);
116 expect(gone).toEqual("gone");
117 }).pipe(logLevel),
118 { tags: ["provider:gcp", "provider:gcp:eventarc", "live"], timeout: 180_000 },
119);