1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as Core from "@/Test/Core";
4import * as crm from "@distilled.cloud/gcp/cloudresourcemanager_v3";
5import type * as memcache from "@distilled.cloud/gcp/memcache_v1";
6import { describe, expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8import { dockerAvailable, expectProbe } from "../bindingHost.ts";
9import MemcacheBindingsHost, {
10 Cache,
11 memcacheEnabled,
12} from "./fixtures/bindings-host.ts";
13
14const testOptions = { providers: GCP.providers() };
15const { test, beforeAll, afterAll } = Test.make(testOptions);
16const sharedStack = Core.scratchStack(testOptions, "MemcacheBindings");
17
18let baseUrl: string;
19let hostAccount: string;
20let project: string;
21let instanceName: string;
22
23describe.skipIf(!dockerAvailable || !memcacheEnabled)(
24 "Memcache Bindings",
25 {
26 tags: ["provider:gcp", "provider:gcp:memcache", "provider:gcp:run", "live"],
27 },
28 () => {
29 beforeAll(
30 Effect.gen(function* () {
31 yield* sharedStack.destroy();
32 const out = yield* sharedStack.deploy(
33 Effect.gen(function* () {
34 const host = yield* MemcacheBindingsHost;
35 const cache = yield* Cache;
36 return {
37 uri: host.uri,
38 serviceAccount: host.serviceAccount,
39 name: cache.name,
40 project: cache.project,
41 };
42 }),
43 );
44 baseUrl = out.uri!;
45 hostAccount = out.serviceAccount!;
46 instanceName = out.name;
47 project = out.project;
48 }),
49 { timeout: 1_800_000 },
50 );
51
52 afterAll(sharedStack.destroy(), { timeout: 1_200_000 });
53
54 describe("GetInstance", () => {
55 test.provider(
56 "reads the instance as the host's service account, granted memcache.viewer on the project",
57 (_stack) =>
58 Effect.gen(function* () {
59 const live = yield* expectProbe<memcache.Instance>(
60 baseUrl,
61 "getInstance",
62 );
63 expect(live.name).toEqual(instanceName);
64 expect(live.state).toEqual("READY");
65
66 // Memcache instances have no IAM policy of their own.
67 const policy = yield* crm.getIamPolicyProjects({
68 resource: `projects/${project}`,
69 body: { options: { requestedPolicyVersion: 3 } },
70 });
71 const roles = (policy.bindings ?? [])
72 .filter((binding) =>
73 (binding.members ?? []).includes(
74 `serviceAccount:${hostAccount}`,
75 ),
76 )
77 .map((binding) => ({
78 role: binding.role,
79 condition: binding.condition,
80 }));
81 expect(roles).toEqual([
82 { role: "roles/memcache.viewer", condition: undefined },
83 ]);
84 }),
85 {
86 tags: ["provider:gcp", "provider:gcp:memcache", "live"],
87 timeout: 600_000,
88 },
89 );
90 });
91 },
92);