1import * as AWS from "@/AWS";
2import { AlternateContact } from "@/AWS/Account";
3import * as Test from "@/Test/Alchemy";
4import * as account from "@distilled.cloud/aws/account";
5import { describe, expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import * as Redacted from "effect/Redacted";
8
9const { test } = Test.make({ providers: AWS.providers() });
10
11const unwrap = (value: string | Redacted.Redacted<string> | undefined) =>
12 value === undefined
13 ? undefined
14 : typeof value === "string"
15 ? value
16 : Redacted.value(value);
17
18const CONTACT_TYPE = "OPERATIONS" as const;
19
20const captureContact = () =>
21 account.getAlternateContact({ AlternateContactType: CONTACT_TYPE }).pipe(
22 Effect.map((r) => r.AlternateContact),
23 Effect.catchTag("ResourceNotFoundException", () =>
24 Effect.succeed(undefined),
25 ),
26 );
27
28// Account alternate contacts are account-global singletons — one per type. This
29// test captures whatever OPERATIONS contact the account currently has, sets its
30// own, verifies, tears down, and restores the original so the account is left
31// exactly as it was found.
32describe.sequential(
33 "Account AlternateContact",
34 { tags: ["provider:aws", "provider:aws:account", "live"] },
35 () => {
36 test.provider(
37 "set, read, and reset the OPERATIONS alternate contact",
38 (stack) =>
39 Effect.gen(function* () {
40 yield* stack.destroy();
41
42 const original = yield* captureContact();
43
44 const restore = Effect.gen(function* () {
45 if (original) {
46 yield* account.putAlternateContact({
47 AlternateContactType: CONTACT_TYPE,
48 Name: unwrap(original.Name) ?? "",
49 Title: unwrap(original.Title) ?? "",
50 EmailAddress: unwrap(original.EmailAddress) ?? "",
51 PhoneNumber: unwrap(original.PhoneNumber) ?? "",
52 });
53 } else {
54 yield* account
55 .deleteAlternateContact({ AlternateContactType: CONTACT_TYPE })
56 .pipe(
57 Effect.catchTag(
58 "ResourceNotFoundException",
59 () => Effect.void,
60 ),
61 );
62 }
63 });
64
65 yield* Effect.gen(function* () {
66 const contact = yield* stack.deploy(
67 Effect.gen(function* () {
68 return yield* AlternateContact("OpsContact", {
69 alternateContactType: CONTACT_TYPE,
70 name: "Alchemy Test Ops",
71 title: "On-Call",
72 emailAddress: "alchemy-test-ops@example.com",
73 phoneNumber: "+15555550100",
74 });
75 }),
76 );
77
78 expect(contact.alternateContactType).toBe(CONTACT_TYPE);
79 expect(contact.emailAddress).toBe("alchemy-test-ops@example.com");
80
81 // Out-of-band verification.
82 const live = yield* captureContact();
83 expect(unwrap(live?.EmailAddress)).toBe(
84 "alchemy-test-ops@example.com",
85 );
86 expect(unwrap(live?.Name)).toBe("Alchemy Test Ops");
87
88 // Destroy removes the contact.
89 yield* stack.destroy();
90 const gone = yield* captureContact();
91 expect(gone).toBeUndefined();
92 }).pipe(Effect.ensuring(restore.pipe(Effect.orDie)));
93
94 // Confirm restoration matches the captured original.
95 const restored = yield* captureContact();
96 expect(unwrap(restored?.EmailAddress)).toBe(
97 unwrap(original?.EmailAddress),
98 );
99 }),
100 { timeout: 120_000 },
101 );
102 },
103);