1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as apikeys from "@distilled.cloud/gcp/apikeys_v2";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8
9const { test } = Test.make({ providers: GCP.providers() });
10
11const logLevel = Effect.provideService(
12 MinimumLogLevel,
13 process.env.DEBUG ? "Debug" : "Info",
14);
15
16const waitUntilGone = (name: string) =>
17 apikeys.getProjectsLocationsKeys({ name }).pipe(
18 Effect.map((key) =>
19 (key.deleteTime ?? "") !== "" ? ("gone" as const) : ("found" as const),
20 ),
21 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
22 Effect.repeat({
23 schedule: Schedule.spaced("1 second"),
24 until: (status) => status === "gone",
25 times: 10,
26 }),
27 );
28
29test.provider(
30 "create, update, and delete an API key",
31 (stack) =>
32 Effect.gen(function* () {
33 yield* stack.destroy();
34
35 const created = yield* stack.deploy(
36 Effect.gen(function* () {
37 return yield* GCP.ApiKeys.Key("Maps", {
38 displayName: "alchemy test maps",
39 annotations: { env: "test" },
40 });
41 }),
42 );
43
44 expect(created.name).toContain("/locations/global/keys/");
45 expect(created.keyId).toEqual(expect.any(String));
46 expect(created.location).toEqual("global");
47 expect(created.displayName).toEqual("alchemy test maps");
48 expect(created.annotations).toMatchObject({ env: "test" });
49 expect(created.keyString).toEqual(expect.any(String));
50 expect((created.keyString ?? "").length).toBeGreaterThan(0);
51
52 const fetched = yield* apikeys.getProjectsLocationsKeys({
53 name: created.name,
54 });
55 expect(fetched.name).toEqual(created.name);
56 expect(fetched.displayName).toEqual("alchemy test maps");
57 expect(fetched.annotations?.env).toEqual("test");
58 expect(fetched.annotations?.["alchemy-id"]).toEqual(expect.any(String));
59 expect(fetched.deleteTime).toBeFalsy();
60
61 const keyString = yield* apikeys.getKeyStringProjectsLocationsKeys({
62 name: created.name,
63 });
64 expect(keyString.keyString).toEqual(created.keyString);
65
66 const updated = yield* stack.deploy(
67 Effect.gen(function* () {
68 return yield* GCP.ApiKeys.Key("Maps", {
69 keyId: created.keyId,
70 displayName: "alchemy test maps v2",
71 annotations: { env: "prod", role: "maps" },
72 restrictions: {
73 apiTargets: [{ service: "geocoding-backend.googleapis.com" }],
74 },
75 });
76 }),
77 );
78
79 expect(updated.name).toEqual(created.name);
80 expect(updated.keyId).toEqual(created.keyId);
81 expect(updated.displayName).toEqual("alchemy test maps v2");
82 expect(updated.annotations).toMatchObject({ env: "prod", role: "maps" });
83 expect(updated.restrictions?.apiTargets?.[0]?.service).toEqual(
84 "geocoding-backend.googleapis.com",
85 );
86 expect(updated.keyString).toEqual(created.keyString);
87
88 const fetchedUpdate = yield* apikeys.getProjectsLocationsKeys({
89 name: created.name,
90 });
91 expect(fetchedUpdate.displayName).toEqual("alchemy test maps v2");
92 expect(fetchedUpdate.annotations?.env).toEqual("prod");
93 expect(fetchedUpdate.annotations?.role).toEqual("maps");
94 expect(fetchedUpdate.annotations?.["alchemy-id"]).toEqual(
95 expect.any(String),
96 );
97 expect(fetchedUpdate.restrictions?.apiTargets?.[0]?.service).toEqual(
98 "geocoding-backend.googleapis.com",
99 );
100
101 yield* stack.destroy();
102
103 const gone = yield* waitUntilGone(created.name);
104 expect(gone).toEqual("gone");
105 }).pipe(logLevel),
106 { tags: ["provider:gcp", "provider:gcp:apikeys", "live"], timeout: 90_000 },
107);