1import * as AWS from "@/AWS";
2import { Nodegroup } from "@/AWS/EKS";
3import * as Provider from "@/Provider";
4import * as Test from "@/Test/Alchemy";
5import * as eks from "@distilled.cloud/aws/eks";
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: `describeNodegroup` against a cluster that does not
12// exist must surface the `ResourceNotFoundException` tag that the provider's
13// read/reconcile/delete paths catch. This proves the distilled error union is
14// correct without needing a ~10-minute EKS cluster.
15test.provider(
16 "describeNodegroup on a nonexistent cluster fails with ResourceNotFoundException",
17 () =>
18 Effect.gen(function* () {
19 const error = yield* Effect.flip(
20 eks.describeNodegroup({
21 clusterName: "alchemy-nonexistent-cluster-probe",
22 nodegroupName: "alchemy-nonexistent-nodegroup-probe",
23 }),
24 );
25 expect(error._tag).toBe("ResourceNotFoundException");
26 }),
27 { tags: ["provider:aws", "provider:aws:eks", "live"] },
28);
29
30// Ungated `list()` probe: enumerates every cluster, lists each cluster's node
31// groups, then hydrates each via `describeNodegroup`. Requires no deployed
32// resource — returns `[]` in a clean account/region, otherwise a well-formed
33// array of full Nodegroup Attributes. Proves the enumeration wiring compiles
34// and runs live.
35test.provider(
36 "list returns a well-formed array of node groups",
37 (stack) =>
38 Effect.gen(function* () {
39 yield* stack.destroy();
40
41 const provider = yield* Provider.findProvider(Nodegroup);
42 const all = yield* provider.list();
43
44 expect(Array.isArray(all)).toBe(true);
45 for (const nodegroup of all) {
46 expect(typeof nodegroup.nodegroupArn).toBe("string");
47 expect(typeof nodegroup.nodegroupName).toBe("string");
48 expect(typeof nodegroup.clusterName).toBe("string");
49 expect(typeof nodegroup.nodeRole).toBe("string");
50 expect(Array.isArray(nodegroup.subnets)).toBe(true);
51 expect(Array.isArray(nodegroup.instanceTypes)).toBe(true);
52 }
53 }),
54 { tags: ["provider:aws", "provider:aws:eks", "live"] },
55);
56
57// Full deploy lifecycle. An EKS cluster + managed node group takes 5+ minutes to
58// provision, far beyond the routine test budget. Gate behind a pre-existing
59// cluster supplied via AWS_TEST_EKS_CLUSTER (+ the node IAM role ARN and two
60// private subnet IDs); an entitled account with a standing cluster runs this
61// unchanged. Deploys a node group, waits for ACTIVE, updates its scaling
62// config, then tears down and asserts it is gone.
63test.provider.skipIf(!process.env.AWS_TEST_EKS_CLUSTER)(
64 "creates, scales, and deletes a managed node group",
65 (stack) =>
66 Effect.gen(function* () {
67 yield* stack.destroy();
68
69 const clusterName = process.env.AWS_TEST_EKS_CLUSTER!;
70 const nodeRole = process.env.AWS_TEST_EKS_NODE_ROLE_ARN!;
71 const subnets = (process.env.AWS_TEST_EKS_PRIVATE_SUBNETS ?? "")
72 .split(",")
73 .map((s) => s.trim())
74 .filter(Boolean);
75
76 const created = yield* stack.deploy(
77 Effect.gen(function* () {
78 return yield* Nodegroup("TestNodegroup", {
79 clusterName,
80 nodeRole,
81 subnets,
82 instanceTypes: ["t3.medium"],
83 scalingConfig: { minSize: 1, maxSize: 2, desiredSize: 1 },
84 });
85 }),
86 );
87 expect(created.status).toBe("ACTIVE");
88 expect(created.scalingConfig?.desiredSize).toBe(1);
89
90 const scaled = yield* stack.deploy(
91 Effect.gen(function* () {
92 return yield* Nodegroup("TestNodegroup", {
93 clusterName,
94 nodeRole,
95 subnets,
96 instanceTypes: ["t3.medium"],
97 scalingConfig: { minSize: 1, maxSize: 3, desiredSize: 2 },
98 });
99 }),
100 );
101 expect(scaled.status).toBe("ACTIVE");
102 expect(scaled.scalingConfig?.desiredSize).toBe(2);
103
104 yield* stack.destroy();
105
106 const gone = yield* eks
107 .describeNodegroup({
108 clusterName,
109 nodegroupName: created.nodegroupName,
110 })
111 .pipe(
112 Effect.map(() => false),
113 Effect.catchTag("ResourceNotFoundException", () =>
114 Effect.succeed(true),
115 ),
116 );
117 expect(gone).toBe(true);
118 }),
119 { tags: ["provider:aws", "provider:aws:eks", "live"], timeout: 900_000 },
120);