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
23// Empty `proxies/` directory zip used as archive payload.
24const ARCHIVE_ZIP =
25 "UEsDBAoAAAAAAIdO4kgAAAAAAAAAAAAAAAAJAAAAcHJveGllcy9QSwECFAAKAAAAAACHTuJIAAAAAAAAAAAAAAAACTAAAAAAAAAAABAAAAAAAAAAcHJveGllcy9QSwUGAAAAAAEAAQA3AAAAJwAAAAAA";
26
27const waitUntilGone = (name: string) =>
28 apigee.getOrganizationsEnvironmentsArchiveDeployments({ name }).pipe(
29 Effect.as("found" as const),
30 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
31 Effect.catchTag("ApigeeResourceNotFound", () =>
32 Effect.succeed("gone" as const),
33 ),
34 Effect.repeat({
35 schedule: Schedule.spaced("2 seconds"),
36 until: (status) => status === "gone",
37 times: 10,
38 }),
39 );
40
41test.provider(
42 "getOrganizationsEnvironmentsArchiveDeployments on a missing archive fails with ApigeeResourceNotFound",
43 (stack) =>
44 Effect.gen(function* () {
45 const { project } = yield* GcpEnvironment.current;
46 const org = `organizations/${project}`;
47
48 yield* stack.destroy();
49
50 const error = yield* Effect.flip(
51 apigee.getOrganizationsEnvironmentsArchiveDeployments({
52 name: `${org}/environments/alchemy-missing/archiveDeployments/alchemy-missing`,
53 }),
54 );
55 expect(error._tag).toEqual("ApigeeResourceNotFound");
56
57 yield* stack.destroy();
58 }).pipe(logLevel),
59 { tags: ["provider:gcp", "provider:gcp:apigee", "live"], timeout: 90_000 },
60);
61
62test.provider.skipIf(!runLifecycle)(
63 "create, update, and delete an archive deployment",
64 (stack) =>
65 Effect.gen(function* () {
66 yield* stack.destroy();
67
68 const created = yield* stack.deploy(
69 Effect.gen(function* () {
70 const environment = yield* GCP.Apigee.Environment("Runtime", {
71 displayName: "runtime",
72 });
73 const archive = yield* GCP.Apigee.EnvironmentsArchiveDeployment(
74 "Bundle",
75 {
76 environment: environment.environmentId,
77 archiveZip: ARCHIVE_ZIP,
78 labels: { env: "test" },
79 },
80 );
81 return { environment, archive };
82 }),
83 );
84
85 expect(created.archive.archiveDeploymentId).toEqual(expect.any(String));
86 expect(created.archive.environmentId).toEqual(
87 created.environment.environmentId,
88 );
89 expect(created.archive.labels).toMatchObject({ env: "test" });
90
91 const fetched =
92 yield* apigee.getOrganizationsEnvironmentsArchiveDeployments({
93 name: created.archive.name,
94 });
95 expect(fetched.labels?.["alchemy-id"]).toEqual(expect.any(String));
96
97 const updated = yield* stack.deploy(
98 Effect.gen(function* () {
99 const environment = yield* GCP.Apigee.Environment("Runtime", {
100 environmentId: created.environment.environmentId,
101 displayName: "runtime",
102 });
103 const archive = yield* GCP.Apigee.EnvironmentsArchiveDeployment(
104 "Bundle",
105 {
106 environment: environment.environmentId,
107 archiveDeploymentId: created.archive.archiveDeploymentId,
108 archiveZip: ARCHIVE_ZIP,
109 labels: { env: "prod" },
110 },
111 );
112 return { environment, archive };
113 }),
114 );
115
116 expect(updated.archive.name).toEqual(created.archive.name);
117 expect(updated.archive.labels).toMatchObject({ env: "prod" });
118
119 yield* stack.destroy();
120
121 const gone = yield* waitUntilGone(created.archive.name);
122 expect(gone).toEqual("gone");
123 }).pipe(logLevel),
124 { tags: ["provider:gcp", "provider:gcp:apigee", "live"], timeout: 90_000 },
125);