1import * as Cloudflare from "@/Cloudflare";
2import { CloudflareEnvironment } from "@/Cloudflare/CloudflareEnvironment";
3import { findZoneByName } from "@/Cloudflare/Zone/lookup";
4import * as Provider from "@/Provider";
5import * as Test from "@/Test/Alchemy";
6import * as argo from "@distilled.cloud/cloudflare/argo";
7import { describe, expect } from "alchemy-test";
8import * as Effect from "effect/Effect";
9import { MinimumLogLevel } from "effect/References";
10import * as Schedule from "effect/Schedule";
11const { test } = Test.make({ providers: Cloudflare.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const zoneName =
19 process.env.CLOUDFLARE_TEST_DNS_ZONE_NAME ?? "alchemy-test-2.us";
20
21const resolveZoneId = Effect.gen(function* () {
22 const { accountId } = yield* yield* CloudflareEnvironment;
23 const zone = yield* findZoneByName({ accountId, name: zoneName });
24 if (!zone) {
25 return yield* Effect.die(
26 new Error(`zone "${zoneName}" not found in account`),
27 );
28 }
29 return zone.id;
30});
31
32// The scoped API token the test harness mints propagates eventually-
33// consistently across Cloudflare's edge — a fresh token intermittently 403s
34// with "Unable to authenticate request". Ride out the blips on the test's
35// own out-of-band calls by retrying the typed `Forbidden` error (part of
36// the argo operations' error unions via distilled patches).
37const forbiddenRetrySchedule = Schedule.exponential("500 millis");
38
39const getTieredCaching = (zoneId: string) =>
40 argo.getTieredCaching({ zoneId }).pipe(
41 Effect.retry({
42 while: (e) => e._tag === "Forbidden",
43 schedule: forbiddenRetrySchedule,
44 times: 8,
45 }),
46 );
47
48// Normalize the singleton to a known baseline so each run starts from the
49// same cloud state regardless of what a previous (possibly interrupted)
50// run left behind.
51const setBaseline = (zoneId: string, value: "on" | "off") =>
52 argo.patchTieredCaching({ zoneId, value }).pipe(
53 Effect.retry({
54 while: (e) => e._tag === "Forbidden",
55 schedule: forbiddenRetrySchedule,
56 times: 8,
57 }),
58 );
59
60// Both cases mutate the same zone-level Tiered Caching singleton with
61// opposite baselines; run them serially so they don't corrupt each other's
62// captured `initialValue` under the global concurrent test config.
63describe.sequential(
64 "TieredCaching",
65 {
66 tags: [
67 "provider:cloudflare",
68 "provider:cloudflare:argo",
69 "provider:cloudflare:zone",
70 "live",
71 ],
72 },
73 () => {
74 test.provider(
75 "enables Tiered Caching and restores the original value on destroy",
76 (stack) =>
77 Effect.gen(function* () {
78 const zoneId = yield* resolveZoneId;
79
80 yield* stack.destroy();
81 // Known baseline: tiered caching off before we manage it.
82 yield* setBaseline(zoneId, "off");
83
84 const setting = yield* stack.deploy(
85 Effect.gen(function* () {
86 return yield* Cloudflare.Argo.TieredCaching("TieredCaching", {
87 zoneId,
88 });
89 }),
90 );
91
92 expect(setting.zoneId).toEqual(zoneId);
93 expect(setting.value).toEqual("on");
94 // The pre-management value was captured for restore-on-destroy.
95 expect(setting.initialValue).toEqual("off");
96
97 const live = yield* getTieredCaching(zoneId);
98 expect(live.value).toEqual("on");
99
100 yield* stack.destroy();
101
102 // Destroy restored the value the setting had before we managed it.
103 const restored = yield* getTieredCaching(zoneId);
104 expect(restored.value).toEqual("off");
105 }).pipe(logLevel),
106 );
107
108 test.provider(
109 "updates enabled in place and keeps the captured initial value",
110 (stack) =>
111 Effect.gen(function* () {
112 const zoneId = yield* resolveZoneId;
113
114 yield* stack.destroy();
115 // Known baseline: tiered caching on before we manage it.
116 yield* setBaseline(zoneId, "on");
117
118 const initial = yield* stack.deploy(
119 Effect.gen(function* () {
120 return yield* Cloudflare.Argo.TieredCaching("TieredCaching", {
121 zoneId,
122 enabled: false,
123 });
124 }),
125 );
126
127 expect(initial.value).toEqual("off");
128 expect(initial.initialValue).toEqual("on");
129
130 const liveOff = yield* getTieredCaching(zoneId);
131 expect(liveOff.value).toEqual("off");
132
133 const updated = yield* stack.deploy(
134 Effect.gen(function* () {
135 return yield* Cloudflare.Argo.TieredCaching("TieredCaching", {
136 zoneId,
137 enabled: true,
138 });
139 }),
140 );
141
142 // Same singleton patched in place; the original value survives the
143 // update so destroy still restores the pre-management state.
144 expect(updated.value).toEqual("on");
145 expect(updated.initialValue).toEqual("on");
146
147 const liveOn = yield* getTieredCaching(zoneId);
148 expect(liveOn.value).toEqual("on");
149
150 yield* stack.destroy();
151
152 const restored = yield* getTieredCaching(zoneId);
153 expect(restored.value).toEqual("on");
154 }).pipe(logLevel),
155 );
156
157 // Canonical `list()` test (zone-scoped singleton): there is no account-wide
158 // API for this per-zone setting, so `list()` enumerates every zone via
159 // `listAllZones` and reads the singleton in each. Assert the result is
160 // non-empty and contains the standing test zone.
161 test.provider("list enumerates the setting across all zones", (stack) =>
162 Effect.gen(function* () {
163 const zoneId = yield* resolveZoneId;
164
165 const provider = yield* Provider.findProvider(
166 Cloudflare.Argo.TieredCaching,
167 );
168 const all = yield* provider.list();
169
170 expect(all.length).toBeGreaterThan(0);
171 expect(all.some((s) => s.zoneId === zoneId)).toBe(true);
172
173 // `stack` is unused here (the singleton always exists on every zone),
174 // but keep the destroy bookend so the harness state stays clean.
175 yield* stack.destroy();
176 }).pipe(logLevel),
177 );
178 },
179);