1import * as GCP from "@/GCP";
2import { GcpEnvironment } from "@/GCP/Environment";
3import * as Test from "@/Test/Alchemy";
4import * as documentai from "@distilled.cloud/gcp/documentai_v1";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
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);
16const location = "us";
17
18const invoiceSchema: GCP.DocumentAI.DocumentSchemaSpec = {
19 displayName: "invoice",
20 description: "invoice fields",
21 entityTypes: [
22 {
23 name: "invoice",
24 baseTypes: ["document"],
25 properties: [
26 {
27 name: "invoice_id",
28 valueType: "string",
29 occurrenceType: "OPTIONAL_ONCE",
30 },
31 ],
32 },
33 ],
34};
35
36const waitUntilGone = (name: string) =>
37 documentai.getProjectsLocationsSchemasSchemaVersions({ name }).pipe(
38 Effect.as("found" as const),
39 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
40 Effect.repeat({
41 schedule: Schedule.spaced("2 seconds"),
42 until: (status) => status === "gone",
43 times: 10,
44 }),
45 );
46
47test.provider(
48 "getProjectsLocationsSchemasSchemaVersions on a missing version fails with a typed tag",
49 (stack) =>
50 Effect.gen(function* () {
51 const { project } = yield* GcpEnvironment.current;
52 const parent = `projects/${project}/locations/${location}`;
53 yield* stack.destroy();
54
55 const error = yield* Effect.flip(
56 documentai.getProjectsLocationsSchemasSchemaVersions({
57 name: `${parent}/schemas/missing/schemaVersions/alchemy-missing-version`,
58 }),
59 );
60 expect(error._tag).toEqual("NotFound");
61
62 yield* stack.destroy();
63 }).pipe(logLevel),
64 {
65 tags: ["provider:gcp", "provider:gcp:documentai", "live"],
66 timeout: 90_000,
67 },
68);
69
70test.provider.skipIf(!!process.env.FAST)(
71 "create, update, and delete a schema version",
72 (stack) =>
73 Effect.gen(function* () {
74 const { project } = yield* GcpEnvironment.current;
75 const parent = `projects/${project}/locations/${location}`;
76 yield* stack.destroy();
77
78 const created = yield* stack.deploy(
79 Effect.gen(function* () {
80 const schema = yield* GCP.DocumentAI.Schema("Invoice", {
81 location,
82 displayName: "invoice-parent",
83 labels: { env: "test" },
84 });
85 const version = yield* GCP.DocumentAI.SchemasSchemaVersion("V1", {
86 schema: schema.name,
87 location,
88 displayName: "v1",
89 documentSchema: invoiceSchema,
90 labels: { env: "test" },
91 });
92 return { schema, version };
93 }),
94 );
95
96 expect(created.version.schemaVersionId).toEqual(expect.any(String));
97 expect(created.version.name).toContain("/schemaVersions/");
98 expect(created.version.schema).toEqual(created.schema.name);
99 expect(created.version.displayName).toEqual("v1");
100 expect(created.version.labels).toMatchObject({ env: "test" });
101
102 const fetched =
103 yield* documentai.getProjectsLocationsSchemasSchemaVersions({
104 name: created.version.name,
105 });
106 expect(fetched.name).toEqual(created.version.name);
107 expect(fetched.displayName).toEqual("v1");
108 expect(fetched.labels?.env).toEqual("test");
109 expect(fetched.labels?.["alchemy-id"]).toEqual(expect.any(String));
110
111 const updated = yield* stack.deploy(
112 Effect.gen(function* () {
113 const schema = yield* GCP.DocumentAI.Schema("Invoice", {
114 schemaId: created.schema.schemaId,
115 location,
116 displayName: "invoice-parent",
117 labels: { env: "test" },
118 });
119 const version = yield* GCP.DocumentAI.SchemasSchemaVersion("V1", {
120 schema: schema.name,
121 schemaVersionId: created.version.schemaVersionId,
122 location,
123 displayName: "v1-prod",
124 documentSchema: invoiceSchema,
125 labels: { env: "prod", role: "version" },
126 });
127 return { schema, version };
128 }),
129 );
130
131 expect(updated.version.name).toEqual(created.version.name);
132 expect(updated.version.displayName).toEqual("v1-prod");
133 expect(updated.version.labels).toMatchObject({
134 env: "prod",
135 role: "version",
136 });
137
138 yield* stack.destroy();
139 const gone = yield* waitUntilGone(created.version.name);
140 expect(gone).toEqual("gone");
141 }).pipe(logLevel),
142 {
143 tags: ["provider:gcp", "provider:gcp:documentai", "live"],
144 timeout: 120_000,
145 },
146);