1import * as AWS from "@/AWS";
2import * as Test from "@/Test/Alchemy";
3import * as lf from "@distilled.cloud/aws/lakeformation";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6
7const { test } = Test.make({ providers: AWS.providers() });
8
9const describeResource = (resourceArn: string) =>
10 lf.describeResource({ ResourceArn: resourceArn }).pipe(
11 Effect.map((r) => r.ResourceInfo),
12 Effect.catchTag("EntityNotFoundException", () => Effect.succeed(undefined)),
13 );
14
15test.provider(
16 "register, update, deregister an S3 location",
17 (stack) =>
18 Effect.gen(function* () {
19 yield* stack.destroy();
20
21 // create — register a bucket with the service-linked role
22 const created = yield* stack.deploy(
23 Effect.gen(function* () {
24 const bucket = yield* AWS.S3.Bucket("LfData", {});
25 const location = yield* AWS.LakeFormation.Resource("LfLocation", {
26 resourceArn: bucket.bucketArn,
27 });
28 return { bucket, location };
29 }),
30 );
31
32 expect(created.location.resourceArn).toEqual(created.bucket.bucketArn);
33 expect(created.location.roleArn).toContain(
34 "AWSServiceRoleForLakeFormationDataAccess",
35 );
36
37 // out-of-band verification
38 const observed = yield* describeResource(created.location.resourceArn);
39 expect(observed).toBeDefined();
40 expect(observed?.RoleArn).toEqual(created.location.roleArn);
41 expect(observed?.HybridAccessEnabled).toEqual(false);
42
43 // update — enable hybrid access mode
44 const updated = yield* stack.deploy(
45 Effect.gen(function* () {
46 const bucket = yield* AWS.S3.Bucket("LfData", {});
47 const location = yield* AWS.LakeFormation.Resource("LfLocation", {
48 resourceArn: bucket.bucketArn,
49 hybridAccessEnabled: true,
50 });
51 return { bucket, location };
52 }),
53 );
54
55 expect(updated.location.resourceArn).toEqual(
56 created.location.resourceArn,
57 );
58 expect(updated.location.hybridAccessEnabled).toEqual(true);
59 const reobserved = yield* describeResource(created.location.resourceArn);
60 expect(reobserved?.HybridAccessEnabled).toEqual(true);
61
62 // delete
63 yield* stack.destroy();
64 const gone = yield* describeResource(created.location.resourceArn);
65 expect(gone).toBeUndefined();
66 }),
67 {
68 tags: [
69 "provider:aws",
70 "provider:aws:lakeformation",
71 "provider:aws:s3",
72 "live",
73 ],
74 timeout: 180_000,
75 },
76);