1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as cw from "@distilled.cloud/gcp/contentwarehouse_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8import { GcpEnvironment } from "@/GCP/Environment";
9
10const { test } = Test.make({ providers: GCP.providers() });
11
12const logLevel = Effect.provideService(
13 MinimumLogLevel,
14 process.env.DEBUG ? "Debug" : "Info",
15);
16
17// Document AI Warehouse is disabled on the testing project: calls fail with
18// ServiceDisabled "Document AI Warehouse API has not been used in project ...
19// before or it is disabled" (the service also needs per-project
20// provisioning). Set GCP_TEST_CONTENTWAREHOUSE=1 on a provisioned project.
21const runLifecycle =
22 !process.env.FAST && !!process.env.GCP_TEST_CONTENTWAREHOUSE;
23
24const location = "us";
25
26const waitUntilGone = (name: string) =>
27 cw.getProjectsLocationsSynonymSets({ name }).pipe(
28 Effect.as("found" as const),
29 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
30 Effect.repeat({
31 schedule: Schedule.spaced("1 second"),
32 until: (status) => status === "gone",
33 times: 10,
34 }),
35 );
36
37test.provider.skipIf(runLifecycle)(
38 "getProjectsLocationsSynonymSets without Document AI Warehouse enabled fails with ServiceDisabled",
39 (stack) =>
40 Effect.gen(function* () {
41 const { project } = yield* GcpEnvironment.current;
42 const parent = `projects/${project}/locations/${location}`;
43 yield* stack.destroy();
44
45 const error = yield* Effect.flip(
46 cw.getProjectsLocationsSynonymSets({
47 name: `${parent}/synonymSets/alchemy-missing-synonyms`,
48 }),
49 );
50 expect(error._tag).toEqual("ServiceDisabled");
51
52 yield* stack.destroy();
53 }).pipe(logLevel),
54 {
55 tags: ["provider:gcp", "provider:gcp:contentwarehouse", "live"],
56 timeout: 90_000,
57 },
58);
59
60test.provider.skipIf(!runLifecycle)(
61 "create, update, and delete a synonym set",
62 (stack) =>
63 Effect.gen(function* () {
64 const { project } = yield* GcpEnvironment.current;
65 const parent = `projects/${project}/locations/${location}`;
66 yield* stack.destroy();
67
68 const created = yield* stack.deploy(
69 Effect.gen(function* () {
70 return yield* GCP.ContentWarehouse.SynonymSet("Sales", {
71 location,
72 synonyms: [{ words: ["sale", "invoice", "bill"] }],
73 });
74 }),
75 );
76
77 expect(created.context).toEqual(expect.any(String));
78 expect(created.name).toContain("/synonymSets/");
79 expect(
80 (created.synonyms ?? []).some((group) =>
81 (group.words ?? []).includes("invoice"),
82 ),
83 ).toEqual(true);
84
85 const fetched = yield* cw.getProjectsLocationsSynonymSets({
86 name: created.name,
87 });
88 expect(fetched.name).toEqual(created.name);
89 expect(fetched.synonyms).toEqual(created.synonyms);
90
91 const updated = yield* stack.deploy(
92 Effect.gen(function* () {
93 return yield* GCP.ContentWarehouse.SynonymSet("Sales", {
94 context: created.context,
95 location,
96 synonyms: [
97 { words: ["sale", "invoice", "bill", "order"] },
98 { words: ["money", "credit"] },
99 ],
100 });
101 }),
102 );
103
104 expect(updated.name).toEqual(created.name);
105 expect(
106 (updated.synonyms ?? []).some((group) =>
107 (group.words ?? []).includes("order"),
108 ),
109 ).toEqual(true);
110 expect(
111 (updated.synonyms ?? []).some((group) =>
112 (group.words ?? []).includes("credit"),
113 ),
114 ).toEqual(true);
115
116 yield* stack.destroy();
117 const gone = yield* waitUntilGone(created.name);
118 expect(gone).toEqual("gone");
119 }).pipe(logLevel),
120 {
121 tags: ["provider:gcp", "provider:gcp:contentwarehouse", "live"],
122 timeout: 90_000,
123 },
124);