1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as storage from "@distilled.cloud/gcp/storage_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import * as Redacted from "effect/Redacted";
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
17const SERVICE_ACCOUNT_EMAIL =
18 "alchemy-testing@alchemy-gcp-testing-83661.iam.gserviceaccount.com";
19
20const waitUntilGone = (projectId: string, accessId: string) =>
21 storage.getProjectsHmacKeys({ projectId, accessId }).pipe(
22 Effect.map((metadata) =>
23 metadata.state?.toUpperCase() === "DELETED"
24 ? ("gone" as const)
25 : ("found" as const),
26 ),
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(
36 "create, update, and delete an HMAC key",
37 (stack) =>
38 Effect.gen(function* () {
39 yield* stack.destroy();
40
41 const created = yield* stack.deploy(
42 Effect.gen(function* () {
43 return yield* GCP.Storage.HmacKey("Interop", {
44 serviceAccountEmail: SERVICE_ACCOUNT_EMAIL,
45 });
46 }),
47 );
48
49 expect(created.accessId).toEqual(expect.any(String));
50 expect(created.accessId.length).toBeGreaterThan(0);
51 expect(created.serviceAccountEmail).toEqual(SERVICE_ACCOUNT_EMAIL);
52 expect(created.state).toEqual("ACTIVE");
53 expect(created.projectId).toEqual(expect.any(String));
54 expect(Redacted.isRedacted(created.secret)).toEqual(true);
55
56 const fetched = yield* storage.getProjectsHmacKeys({
57 projectId: created.projectId,
58 accessId: created.accessId,
59 });
60 expect(fetched.accessId).toEqual(created.accessId);
61 expect(fetched.state).toEqual("ACTIVE");
62 expect(fetched.serviceAccountEmail).toEqual(SERVICE_ACCOUNT_EMAIL);
63
64 const updated = yield* stack.deploy(
65 Effect.gen(function* () {
66 return yield* GCP.Storage.HmacKey("Interop", {
67 serviceAccountEmail: SERVICE_ACCOUNT_EMAIL,
68 state: "INACTIVE",
69 });
70 }),
71 );
72
73 expect(updated.accessId).toEqual(created.accessId);
74 expect(updated.state).toEqual("INACTIVE");
75 expect(Redacted.isRedacted(updated.secret)).toEqual(true);
76
77 const refetched = yield* storage.getProjectsHmacKeys({
78 projectId: updated.projectId,
79 accessId: updated.accessId,
80 });
81 expect(refetched.accessId).toEqual(created.accessId);
82 expect(refetched.state).toEqual("INACTIVE");
83
84 yield* stack.destroy();
85
86 const gone = yield* waitUntilGone(created.projectId, created.accessId);
87 expect(gone).toEqual("gone");
88 }).pipe(logLevel),
89 { tags: ["provider:gcp", "provider:gcp:storage", "live"], timeout: 90_000 },
90);