| 1 | import * as AWS from "@/AWS"; |
| 2 | import { DataCatalog } from "@/AWS/Athena/DataCatalog.ts"; |
| 3 | import * as Provider from "@/Provider"; |
| 4 | import * as Test from "@/Test/Alchemy"; |
| 5 | import * as athena from "@distilled.cloud/aws/athena"; |
| 6 | import { expect } from "alchemy-test"; |
| 7 | import * as Effect from "effect/Effect"; |
| 8 | |
| 9 | const { test } = Test.make({ providers: AWS.providers() }); |
| 10 | |
| 11 | const catalogName = "alchemy_test_catalog"; |
| 12 | const fnA = |
| 13 | "arn:aws:lambda:us-west-2:391965393224:function:alchemy-athena-cat-a"; |
| 14 | const fnB = |
| 15 | "arn:aws:lambda:us-west-2:391965393224:function:alchemy-athena-cat-b"; |
| 16 | |
| 17 | const getCatalog = athena |
| 18 | .getDataCatalog({ Name: catalogName, WorkGroup: "primary" }) |
| 19 | .pipe( |
| 20 | Effect.map((res) => res.DataCatalog), |
| 21 | Effect.catchTag("DataCatalogNotFound", () => Effect.succeed(undefined)), |
| 22 | ); |
| 23 | |
| 24 | test.provider( |
| 25 | "lifecycle: create LAMBDA catalog, update params/description, destroy", |
| 26 | (stack) => |
| 27 | Effect.gen(function* () { |
| 28 | yield* stack.destroy(); |
| 29 | |
| 30 | // Create — a federated LAMBDA connector (a fake function ARN is accepted |
| 31 | // at create time; Athena validates lazily at query time). |
| 32 | const created = yield* stack.deploy( |
| 33 | Effect.gen(function* () { |
| 34 | return yield* DataCatalog("LifecycleCat", { |
| 35 | name: catalogName, |
| 36 | type: "LAMBDA", |
| 37 | description: "initial", |
| 38 | parameters: { "metadata-function": fnA, "record-function": fnA }, |
| 39 | tags: { env: "test" }, |
| 40 | }); |
| 41 | }), |
| 42 | ); |
| 43 | expect(created.dataCatalogArn).toContain(`datacatalog/${catalogName}`); |
| 44 | expect(created.type).toBe("LAMBDA"); |
| 45 | |
| 46 | // Out-of-band verification via distilled. |
| 47 | const observed = yield* getCatalog; |
| 48 | expect(observed?.Type).toBe("LAMBDA"); |
| 49 | expect(observed?.Parameters?.["metadata-function"]).toBe(fnA); |
| 50 | expect(observed?.Description).toBe("initial"); |
| 51 | |
| 52 | // Tags applied. |
| 53 | const tags = yield* athena.listTagsForResource({ |
| 54 | ResourceARN: created.dataCatalogArn, |
| 55 | }); |
| 56 | expect( |
| 57 | tags.Tags?.some((t) => t.Key === "env" && t.Value === "test"), |
| 58 | ).toBe(true); |
| 59 | |
| 60 | // Canonical list() coverage. |
| 61 | const provider = yield* Provider.findProvider(DataCatalog); |
| 62 | const all = yield* provider.list(); |
| 63 | expect(all.some((c) => c.name === catalogName)).toBe(true); |
| 64 | |
| 65 | // Update — change the record-function param + description in place. |
| 66 | yield* stack.deploy( |
| 67 | Effect.gen(function* () { |
| 68 | return yield* DataCatalog("LifecycleCat", { |
| 69 | name: catalogName, |
| 70 | type: "LAMBDA", |
| 71 | description: "updated", |
| 72 | parameters: { "metadata-function": fnA, "record-function": fnB }, |
| 73 | }); |
| 74 | }), |
| 75 | ); |
| 76 | const updated = yield* getCatalog; |
| 77 | expect(updated?.Parameters?.["record-function"]).toBe(fnB); |
| 78 | expect(updated?.Description).toBe("updated"); |
| 79 | |
| 80 | // Destroy — the catalog is removed. |
| 81 | yield* stack.destroy(); |
| 82 | const after = yield* getCatalog; |
| 83 | expect(after).toBeUndefined(); |
| 84 | }), |
| 85 | { tags: ["provider:aws", "provider:aws:athena", "live"], timeout: 180_000 }, |
| 86 | ); |