1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as essentialcontacts from "@distilled.cloud/gcp/essentialcontacts_v1";
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 essentialcontacts.getFoldersContacts({ name }).pipe(
18 Effect.as("found" as const),
19 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
20 Effect.repeat({
21 schedule: Schedule.spaced("1 second"),
22 until: (status) => status === "gone",
23 times: 10,
24 }),
25 );
26
27// Folder contacts need a folder the test identity can manage contacts on.
28// Set GOOGLE_FOLDER_ID to run these tests.
29const folderId = process.env.GOOGLE_FOLDER_ID;
30const runLifecycle = !!folderId;
31
32const folderOf = () =>
33 Effect.succeed(
34 folderId === undefined
35 ? ""
36 : folderId.startsWith("folders/")
37 ? folderId
38 : `folders/${folderId}`,
39 );
40
41test.provider.skipIf(!runLifecycle)(
42 "getFoldersContacts on a missing contact fails with a typed tag",
43 (stack) =>
44 Effect.gen(function* () {
45 yield* stack.destroy();
46
47 const folder = yield* folderOf();
48 const error = yield* Effect.flip(
49 essentialcontacts.getFoldersContacts({
50 name: `${folder}/contacts/0`,
51 }),
52 );
53 expect(error._tag).toEqual("NotFound");
54
55 yield* stack.destroy();
56 }).pipe(logLevel),
57 {
58 tags: ["provider:gcp", "provider:gcp:essentialcontacts", "live"],
59 timeout: 90_000,
60 },
61);
62
63test.provider.skipIf(!runLifecycle)(
64 "create, update, replace, and delete a folder essential contact",
65 (stack) =>
66 Effect.gen(function* () {
67 yield* stack.destroy();
68
69 const folder = yield* folderOf();
70
71 const created = yield* stack.deploy(
72 Effect.gen(function* () {
73 return yield* GCP.EssentialContacts.FolderContact("Ops", {
74 folderId: folder,
75 email: "folder-ops@example.com",
76 languageTag: "en-US",
77 notificationCategorySubscriptions: ["ALL"],
78 });
79 }),
80 );
81
82 expect(created.contactId.length).toBeGreaterThan(0);
83 expect(created.parent).toEqual(folder);
84 expect(created.email).toEqual("folder-ops@example.com");
85 expect(created.languageTag).toEqual("en-US");
86
87 const fetched = yield* essentialcontacts.getFoldersContacts({
88 name: created.name,
89 });
90 expect(fetched.name).toEqual(created.name);
91 expect(fetched.email).toContain("+alc.");
92
93 const updated = yield* stack.deploy(
94 Effect.gen(function* () {
95 return yield* GCP.EssentialContacts.FolderContact("Ops", {
96 folderId: folder,
97 email: "folder-ops@example.com",
98 languageTag: "en-GB",
99 notificationCategorySubscriptions: ["TECHNICAL"],
100 });
101 }),
102 );
103
104 expect(updated.name).toEqual(created.name);
105 expect(updated.languageTag).toEqual("en-GB");
106 expect(updated.notificationCategorySubscriptions).toEqual(["TECHNICAL"]);
107
108 const replaced = yield* stack.deploy(
109 Effect.gen(function* () {
110 return yield* GCP.EssentialContacts.FolderContact("Ops", {
111 folderId: folder,
112 email: "folder-sec@example.com",
113 languageTag: "en-GB",
114 notificationCategorySubscriptions: ["SECURITY"],
115 });
116 }),
117 );
118
119 expect(replaced.email).toEqual("folder-sec@example.com");
120
121 yield* stack.destroy();
122
123 const gone = yield* waitUntilGone(replaced.name);
124 expect(gone).toEqual("gone");
125 }).pipe(logLevel),
126 {
127 tags: ["provider:gcp", "provider:gcp:essentialcontacts", "live"],
128 timeout: 90_000,
129 },
130);