1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as dataplex from "@distilled.cloud/gcp/dataplex_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { MinimumLogLevel } from "effect/References";
7import * as Schedule from "effect/Schedule";
8import { withDataplexSlot } from "./quota.ts";
9
10const { test } = Test.make({ providers: GCP.providers() });
11
12const logLevel = Effect.provideService(
13 MinimumLogLevel,
14 process.env.DEBUG ? "Debug" : "Info",
15);
16
17const waitUntilGone = (name: string) =>
18 dataplex.getProjectsLocationsDataTaxonomiesAttributes({ name }).pipe(
19 Effect.as("found" as const),
20 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
21 Effect.repeat({
22 schedule: Schedule.spaced("1 second"),
23 until: (status) => status === "gone",
24 times: 10,
25 }),
26 );
27
28test.provider.skipIf(!process.env.GCP_TEST_DATATAXONOMY)(
29 "create, update, and delete a data attribute",
30 (stack) =>
31 Effect.gen(function* () {
32 yield* stack.destroy();
33
34 const created = yield* stack.deploy(
35 Effect.gen(function* () {
36 const taxonomy = yield* GCP.Dataplex.DataTaxonomy("Pii", {
37 location: "us-central1",
38 displayName: "pii taxonomy",
39 labels: { env: "test" },
40 });
41 const attribute = yield* GCP.Dataplex.DataTaxonomiesAttribute(
42 "Email",
43 {
44 dataTaxonomy: taxonomy.name,
45 displayName: "email",
46 description: "email addresses",
47 labels: { env: "test" },
48 },
49 );
50 return { taxonomy, attribute };
51 }),
52 );
53
54 expect(created.attribute.name).toContain("/attributes/");
55 expect(created.attribute.dataTaxonomy).toEqual(created.taxonomy.name);
56 expect(created.attribute.displayName).toEqual("email");
57 expect(created.attribute.description).toEqual("email addresses");
58 expect(created.attribute.labels).toMatchObject({ env: "test" });
59
60 const fetched =
61 yield* dataplex.getProjectsLocationsDataTaxonomiesAttributes({
62 name: created.attribute.name,
63 });
64 expect(fetched.name).toEqual(created.attribute.name);
65 expect(fetched.labels?.env).toEqual("test");
66 expect(
67 Object.keys(fetched.labels ?? {}).some((key) =>
68 key.startsWith("alchemy-"),
69 ),
70 ).toEqual(true);
71
72 const updated = yield* stack.deploy(
73 Effect.gen(function* () {
74 const taxonomy = yield* GCP.Dataplex.DataTaxonomy("Pii", {
75 dataTaxonomyId: created.taxonomy.dataTaxonomyId,
76 location: "us-central1",
77 displayName: "pii taxonomy",
78 labels: { env: "test" },
79 });
80 const attribute = yield* GCP.Dataplex.DataTaxonomiesAttribute(
81 "Email",
82 {
83 dataTaxonomy: taxonomy.name,
84 dataAttributeId: created.attribute.dataAttributeId,
85 displayName: "email v2",
86 description: "email addresses v2",
87 labels: { env: "prod", class: "restricted" },
88 },
89 );
90 return { taxonomy, attribute };
91 }),
92 );
93
94 expect(updated.attribute.name).toEqual(created.attribute.name);
95 expect(updated.attribute.displayName).toEqual("email v2");
96 expect(updated.attribute.description).toEqual("email addresses v2");
97 expect(updated.attribute.labels).toMatchObject({
98 env: "prod",
99 class: "restricted",
100 });
101
102 yield* stack.destroy();
103 const gone = yield* waitUntilGone(created.attribute.name);
104 expect(gone).toEqual("gone");
105 }).pipe(logLevel, withDataplexSlot),
106 { tags: ["provider:gcp", "provider:gcp:dataplex", "live"], timeout: 900_000 },
107);