1import * as AWS from "@/AWS";
2import { Discovery, GroupingConfiguration } from "@/AWS/ApplicationSignals";
3import * as Test from "@/Test/Alchemy";
4import * as appsignals from "@distilled.cloud/aws/application-signals";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7
8const { test } = Test.make({ providers: AWS.providers() });
9
10const observedDefinitions = appsignals
11 .listGroupingAttributeDefinitions({})
12 .pipe(Effect.map((r) => r.GroupingAttributeDefinitions));
13
14// The grouping configuration is an ACCOUNT-LEVEL singleton: this test owns
15// it for the duration of the run (create → update → delete restores the
16// account to its unconfigured default).
17test.provider(
18 "create, update, and destroy the account grouping configuration (+ discovery)",
19 (stack) =>
20 Effect.gen(function* () {
21 yield* stack.destroy();
22
23 // CREATE — one custom grouping dimension (plus the idempotent
24 // account-level Discovery enablement in the same stack).
25 const first = yield* stack.deploy(
26 Effect.gen(function* () {
27 const discovery = yield* Discovery("Discovery", {});
28 const grouping = yield* GroupingConfiguration("Grouping", {
29 groupingAttributeDefinitions: [
30 {
31 GroupingName: "AlchemyTestTeam",
32 GroupingSourceKeys: ["Tag.team"],
33 DefaultGroupingValue: "unassigned",
34 },
35 ],
36 });
37 return { discovery, grouping };
38 }),
39 );
40
41 expect(first.discovery.accountId).toMatch(/^\d{12}$/);
42 expect(
43 first.grouping.groupingAttributeDefinitions.map((d) => d.GroupingName),
44 ).toEqual(["AlchemyTestTeam"]);
45
46 // Out-of-band verification via distilled.
47 const observed = yield* observedDefinitions;
48 expect(observed.map((d) => d.GroupingName)).toEqual(["AlchemyTestTeam"]);
49 expect(observed[0].DefaultGroupingValue).toBe("unassigned");
50
51 // UPDATE IN PLACE — PutGroupingConfiguration replaces the whole list.
52 const second = yield* stack.deploy(
53 Effect.gen(function* () {
54 const discovery = yield* Discovery("Discovery", {});
55 const grouping = yield* GroupingConfiguration("Grouping", {
56 groupingAttributeDefinitions: [
57 {
58 GroupingName: "AlchemyTestTeam",
59 GroupingSourceKeys: ["Tag.team"],
60 },
61 {
62 GroupingName: "AlchemyTestCostCenter",
63 GroupingSourceKeys: ["Tag.cost-center"],
64 DefaultGroupingValue: "shared",
65 },
66 ],
67 });
68 return { discovery, grouping };
69 }),
70 );
71
72 expect(
73 second.grouping.groupingAttributeDefinitions.map((d) => d.GroupingName),
74 ).toEqual(["AlchemyTestTeam", "AlchemyTestCostCenter"]);
75 const updated = yield* observedDefinitions;
76 expect(updated).toHaveLength(2);
77
78 // DESTROY — the account reverts to no grouping configuration.
79 // (Discovery deletion is a documented no-op.)
80 yield* stack.destroy();
81 const afterDestroy = yield* observedDefinitions;
82 expect(afterDestroy).toHaveLength(0);
83 }),
84 {
85 tags: ["provider:aws", "provider:aws:applicationsignals", "live"],
86 timeout: 120_000,
87 },
88);