1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as apphub from "@distilled.cloud/gcp/apphub_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// App Hub is not enabled in the test project; live calls fail with
18// ServiceDisabled:
19// "App Hub API has not been used in project alchemy-gcp-testing-83661
20// before or it is disabled."
21const runLifecycle = !process.env.FAST && process.env.GCP_TEST_APPHUB === "1";
22const location = "global";
23
24const waitUntilGone = (name: string) =>
25 apphub.getProjectsLocationsServiceProjectAttachments({ name }).pipe(
26 Effect.as("found" as const),
27 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
28 Effect.repeat({
29 schedule: Schedule.spaced("1 second"),
30 until: (status) => status === "gone",
31 times: 10,
32 }),
33 );
34
35test.provider.skipIf(runLifecycle)(
36 "getProjectsLocationsServiceProjectAttachments on a missing attachment 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 apphub.getProjectsLocationsServiceProjectAttachments({
44 name: `projects/${project}/locations/${location}/serviceProjectAttachments/alchemy-missing-spa`,
45 }),
46 );
47 expect(error._tag).toEqual("ServiceDisabled");
48
49 yield* stack.destroy();
50 }).pipe(logLevel),
51 { tags: ["provider:gcp", "provider:gcp:apphub", "live"], timeout: 90_000 },
52);
53
54test.provider.skipIf(!runLifecycle)(
55 "create and delete an App Hub service project attachment",
56 (stack) =>
57 Effect.gen(function* () {
58 const { project } = yield* GcpEnvironment.current;
59 yield* stack.destroy();
60
61 const created = yield* stack.deploy(
62 Effect.gen(function* () {
63 return yield* GCP.AppHub.ServiceProjectAttachment("Host", {
64 serviceProject: `projects/${project}`,
65 });
66 }),
67 );
68
69 expect(created.name).toContain("/serviceProjectAttachments/");
70 expect(created.serviceProjectAttachmentId).toEqual(project);
71 expect(created.location).toEqual(location);
72 expect(created.serviceProject).toBeDefined();
73
74 const fetched =
75 yield* apphub.getProjectsLocationsServiceProjectAttachments({
76 name: created.name,
77 });
78 expect(fetched.name).toEqual(created.name);
79
80 yield* stack.destroy();
81 const gone = yield* waitUntilGone(created.name);
82 expect(gone).toEqual("gone");
83 }).pipe(logLevel),
84 { tags: ["provider:gcp", "provider:gcp:apphub", "live"], timeout: 90_000 },
85);