1import { GcpEnvironment } from "@/GCP/Environment";
2import * as GCP from "@/GCP";
3import * as Test from "@/Test/Alchemy";
4import * as apigee from "@distilled.cloud/gcp/apigee_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// Needs a provisioned Apigee organization on the testing project (paid, or
18// ~1h eval provisioning); without one calls fail with ApigeeResourceNotFound (403 "Permission
19// denied on resource \"organizations/{project}\" (or it may not exist)").
20// Set GCP_TEST_APIGEE_ORG=1 when the org exists.
21const runLifecycle = !!process.env.GCP_TEST_APIGEE_ORG;
22
23const waitUntilGone = (parent: string, fileType: string, fileId: string) =>
24 apigee
25 .getOrganizationsEnvironmentsResourcefiles({
26 parent,
27 type: fileType,
28 name: fileId,
29 })
30 .pipe(
31 Effect.as("found" as const),
32 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
33 Effect.catchTag("ApigeeResourceNotFound", () =>
34 Effect.succeed("gone" as const),
35 ),
36 Effect.repeat({
37 schedule: Schedule.spaced("2 seconds"),
38 until: (status) => status === "gone",
39 times: 10,
40 }),
41 );
42
43test.provider(
44 "getOrganizationsEnvironmentsResourcefiles on a missing file fails with ApigeeResourceNotFound",
45 (stack) =>
46 Effect.gen(function* () {
47 const { project } = yield* GcpEnvironment.current;
48 const org = `organizations/${project}`;
49
50 yield* stack.destroy();
51
52 const error = yield* Effect.flip(
53 apigee.getOrganizationsEnvironmentsResourcefiles({
54 parent: `${org}/environments/alchemy-missing`,
55 type: "js",
56 name: "alchemy-missing",
57 }),
58 );
59 expect(error._tag).toEqual("ApigeeResourceNotFound");
60
61 yield* stack.destroy();
62 }).pipe(logLevel),
63 { tags: ["provider:gcp", "provider:gcp:apigee", "live"], timeout: 90_000 },
64);
65
66test.provider.skipIf(!runLifecycle)(
67 "create, update, and delete an environment resource file",
68 (stack) =>
69 Effect.gen(function* () {
70 yield* stack.destroy();
71
72 const created = yield* stack.deploy(
73 Effect.gen(function* () {
74 const environment = yield* GCP.Apigee.Environment("Runtime", {
75 displayName: "runtime",
76 });
77 const file = yield* GCP.Apigee.EnvironmentsResourcefile("Helper", {
78 environment: environment.environmentId,
79 fileType: "js",
80 content: "function helper() { return 1; }",
81 });
82 return { environment, file };
83 }),
84 );
85
86 expect(created.file.fileId).toEqual(expect.any(String));
87 expect(created.file.fileType).toEqual("js");
88 expect(created.file.environmentId).toEqual(
89 created.environment.environmentId,
90 );
91
92 const fetched = yield* apigee.getOrganizationsEnvironmentsResourcefiles({
93 parent: created.file.parent,
94 type: created.file.fileType,
95 name: created.file.fileId,
96 });
97 expect(
98 fetched.data !== undefined || fetched.contentType !== undefined,
99 ).toEqual(true);
100
101 const updated = yield* stack.deploy(
102 Effect.gen(function* () {
103 const environment = yield* GCP.Apigee.Environment("Runtime", {
104 environmentId: created.environment.environmentId,
105 displayName: "runtime",
106 });
107 const file = yield* GCP.Apigee.EnvironmentsResourcefile("Helper", {
108 environment: environment.environmentId,
109 fileType: "js",
110 fileId: created.file.fileId,
111 content: "function helper() { return 2; }",
112 });
113 return { environment, file };
114 }),
115 );
116
117 expect(updated.file.fileId).toEqual(created.file.fileId);
118 expect(updated.file.parent).toEqual(created.file.parent);
119
120 yield* stack.destroy();
121
122 const gone = yield* waitUntilGone(
123 created.file.parent,
124 created.file.fileType,
125 created.file.fileId,
126 );
127 expect(gone).toEqual("gone");
128 }).pipe(logLevel),
129 { tags: ["provider:gcp", "provider:gcp:apigee", "live"], timeout: 90_000 },
130);