1import { GcpEnvironment } from "@/GCP/Environment";
2import * as GCP from "@/GCP";
3import * as Test from "@/Test/Alchemy";
4import * as discoveryengine from "@distilled.cloud/gcp/discoveryengine_v1";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8import * as Schedule from "effect/Schedule";
9import { ensureDataStore, quotaTolerant } from "./parent.ts";
10
11const { test } = Test.make({ providers: GCP.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const runLifecycle = !process.env.FAST;
19const parentId = "alchds3doc";
20
21const waitUntilGone = (name: string) =>
22 discoveryengine
23 .getProjectsLocationsDataStoresBranchesDocuments({ name })
24 .pipe(
25 Effect.as("found" as const),
26 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
27 Effect.repeat({
28 schedule: Schedule.spaced("2 seconds"),
29 until: (status) => status === "gone",
30 times: 10,
31 }),
32 );
33
34test.provider(
35 "getProjectsLocationsDataStoresBranchesDocuments on a missing document fails with a typed tag",
36 (stack) =>
37 Effect.gen(function* () {
38 const { project } = yield* GcpEnvironment.current;
39
40 yield* stack.destroy();
41
42 const error = yield* Effect.flip(
43 discoveryengine.getProjectsLocationsDataStoresBranchesDocuments({
44 name: `projects/${project}/locations/global/dataStores/alchemy-missing/branches/default_branch/documents/alchemy-missing`,
45 }),
46 );
47 expect(error._tag).toEqual("NotFound");
48
49 yield* stack.destroy();
50 }).pipe(logLevel, quotaTolerant),
51 {
52 tags: ["provider:gcp", "provider:gcp:discoveryengine", "live"],
53 timeout: 90_000,
54 },
55);
56
57test.provider.skipIf(!runLifecycle)(
58 "create, update, and delete a data store document",
59 (stack) =>
60 Effect.gen(function* () {
61 const { project } = yield* GcpEnvironment.current;
62
63 yield* stack.destroy();
64
65 const parent = yield* ensureDataStore(project, parentId, {
66 contentConfig: "NO_CONTENT",
67 });
68
69 const created = yield* stack.deploy(
70 Effect.gen(function* () {
71 return yield* GCP.DiscoveryEngine.DataStoresBranchesDocument(
72 "About",
73 {
74 dataStore: parent.name ?? "",
75 jsonData: JSON.stringify({
76 title: "About us",
77 uri: "https://example.com/about",
78 }),
79 },
80 );
81 }),
82 );
83
84 expect(created.name).toContain("/documents/");
85 expect(created.jsonData).toContain("About us");
86
87 const fetched =
88 yield* discoveryengine.getProjectsLocationsDataStoresBranchesDocuments({
89 name: created.name,
90 });
91 expect(fetched.name).toEqual(created.name);
92
93 const updated = yield* stack.deploy(
94 Effect.gen(function* () {
95 return yield* GCP.DiscoveryEngine.DataStoresBranchesDocument(
96 "About",
97 {
98 dataStore: parent.name ?? "",
99 documentId: created.documentId,
100 jsonData: JSON.stringify({
101 title: "About the team",
102 uri: "https://example.com/about",
103 }),
104 },
105 );
106 }),
107 );
108
109 expect(updated.name).toEqual(created.name);
110 expect(updated.jsonData).toContain("About the team");
111
112 yield* stack.destroy();
113
114 const gone = yield* waitUntilGone(created.name);
115 expect(gone).toEqual("gone");
116 }).pipe(logLevel, quotaTolerant),
117 {
118 tags: ["provider:gcp", "provider:gcp:discoveryengine", "live"],
119 timeout: 120_000,
120 },
121);