1import * as AWS from "@/AWS";
2import { EventSubscription } from "@/AWS/Redshift";
3import * as SNS from "@/AWS/SNS";
4import * as Test from "@/Test/Alchemy";
5import * as redshift from "@distilled.cloud/aws/redshift";
6import { expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8
9const { test } = Test.make({ providers: AWS.providers() });
10
11// Ungated typed-error probe: proves the distilled error union carries the
12// not-found tag this provider's read/delete paths depend on.
13test.provider(
14 "describeEventSubscriptions on a nonexistent subscription fails with SubscriptionNotFoundFault",
15 () =>
16 Effect.gen(function* () {
17 const error = yield* Effect.flip(
18 redshift.describeEventSubscriptions({
19 SubscriptionName: "alchemy-nonexistent-redshift-sub-probe",
20 }),
21 );
22 expect(error._tag).toBe("SubscriptionNotFoundFault");
23 }),
24 { tags: ["provider:aws", "provider:aws:redshift", "live"] },
25);
26
27const readSubscription = (name: string) =>
28 Effect.gen(function* () {
29 const response = yield* redshift.describeEventSubscriptions({
30 SubscriptionName: name,
31 });
32 return response.EventSubscriptionsList?.[0];
33 });
34
35test.provider(
36 "create with filters, update filters in place, destroy",
37 (stack) =>
38 Effect.gen(function* () {
39 yield* stack.destroy();
40
41 // Create — an SNS topic plus a subscription filtered to cluster
42 // monitoring/management events. Subscriptions are free and instant.
43 const created = yield* stack.deploy(
44 Effect.gen(function* () {
45 const topic = yield* SNS.Topic("Alerts", {});
46 return yield* EventSubscription("Events", {
47 snsTopicArn: topic.topicArn,
48 sourceType: "cluster",
49 eventCategories: ["monitoring", "management"],
50 severity: "INFO",
51 tags: { fixture: "redshift-event-subscription" },
52 });
53 }),
54 );
55
56 expect(created.subscriptionName).toBeDefined();
57 expect(created.eventSubscriptionArn).toContain(":eventsubscription:");
58 expect(created.sourceType).toBe("cluster");
59 expect([...created.eventCategories].sort()).toEqual([
60 "management",
61 "monitoring",
62 ]);
63 expect(created.severity).toBe("INFO");
64 expect(created.enabled).toBe(true);
65 expect(created.snsTopicArn).toContain(":sns:");
66
67 // Out-of-band verification via distilled.
68 const observed = yield* readSubscription(created.subscriptionName);
69 expect(observed?.Status).toBe("active");
70 expect(observed?.SourceType).toBe("cluster");
71 expect(
72 observed?.Tags?.some(
73 (t) =>
74 t.Key === "fixture" && t.Value === "redshift-event-subscription",
75 ),
76 ).toBe(true);
77
78 // Update — narrow the categories, flip severity, disable delivery.
79 // Same name, so it must modify in place.
80 const updated = yield* stack.deploy(
81 Effect.gen(function* () {
82 const topic = yield* SNS.Topic("Alerts", {});
83 return yield* EventSubscription("Events", {
84 snsTopicArn: topic.topicArn,
85 sourceType: "cluster",
86 eventCategories: ["monitoring"],
87 severity: "ERROR",
88 enabled: false,
89 tags: { fixture: "redshift-event-subscription" },
90 });
91 }),
92 );
93
94 expect(updated.subscriptionName).toBe(created.subscriptionName);
95 expect(updated.eventCategories).toEqual(["monitoring"]);
96 expect(updated.severity).toBe("ERROR");
97 expect(updated.enabled).toBe(false);
98
99 const reobserved = yield* readSubscription(created.subscriptionName);
100 expect(reobserved?.EventCategoriesList).toEqual(["monitoring"]);
101 expect(reobserved?.Severity).toBe("ERROR");
102 expect(reobserved?.Enabled).toBe(false);
103
104 // Destroy and verify gone with the typed not-found tag.
105 yield* stack.destroy();
106 const error = yield* Effect.flip(
107 redshift.describeEventSubscriptions({
108 SubscriptionName: created.subscriptionName,
109 }),
110 );
111 expect(error._tag).toBe("SubscriptionNotFoundFault");
112 }),
113 {
114 tags: ["provider:aws", "provider:aws:redshift", "provider:aws:sns", "live"],
115 timeout: 180_000,
116 },
117);