1import * as Cloudflare from "@/Cloudflare";
2import * as Test from "@/Test/Alchemy";
3import { expect } from "alchemy-test";
4import * as Effect from "effect/Effect";
5import { MinimumLogLevel } from "effect/References";
6import * as Schedule from "effect/Schedule";
7import * as HttpClient from "effect/http/HttpClient";
8import Stack from "./fixtures/worker-worker-binding/stack.ts";
9
10const { test, beforeAll, afterAll, deploy, destroy } = Test.make({
11 providers: Cloudflare.providers(),
12});
13
14const logLevel = Effect.provideService(
15 MinimumLogLevel,
16 process.env.DEBUG ? "Debug" : "Info",
17);
18
19const stack = beforeAll(deploy(Stack));
20afterAll.skipIf(!!process.env.NO_DESTROY)(destroy(Stack));
21
22// Cold-start retry — fresh `workers.dev` URLs take a few seconds to start
23// answering 200, so the very first request rides this schedule. Cap the
24// exponential at 3s: uncapped, the doubling sleeps blow through the test
25// timeout in a single wait after ~7 misses, even though the edge would
26// have propagated moments later.
27const coldStartRetry = Effect.retry({
28 schedule: Schedule.min([
29 Schedule.exponential("500 millis"),
30 Schedule.spaced("3 seconds"),
31 ]),
32 times: 30,
33});
34
35test(
36 "target worker's own fetch handler responds",
37 Effect.gen(function* () {
38 const { targetUrl } = yield* stack;
39 const client = HttpClient.filterStatusOk(yield* HttpClient.HttpClient);
40
41 const res = yield* client.get(targetUrl).pipe(coldStartRetry);
42 expect(res.status).toBe(200);
43 expect(yield* res.text).toBe("hello from BindingTargetWorker");
44 }).pipe(logLevel),
45 {
46 tags: ["provider:cloudflare", "provider:cloudflare:worker", "live"],
47 timeout: 180_000,
48 },
49);
50
51test(
52 "async caller can call target's RPC method via service binding",
53 Effect.gen(function* () {
54 const { asyncCallerUrl } = yield* stack;
55 const client = HttpClient.filterStatusOk(yield* HttpClient.HttpClient);
56
57 const res = yield* client
58 .get(`${asyncCallerUrl}/?name=alice`)
59 .pipe(coldStartRetry);
60 expect(res.status).toBe(200);
61 expect(yield* res.text).toBe("hello alice");
62 }).pipe(logLevel),
63 {
64 tags: ["provider:cloudflare", "provider:cloudflare:worker", "live"],
65 timeout: 180_000,
66 },
67);
68
69test(
70 "effect caller can call target's RPC method via bindWorker",
71 Effect.gen(function* () {
72 const { effectCallerUrl } = yield* stack;
73 const client = HttpClient.filterStatusOk(yield* HttpClient.HttpClient);
74
75 const res = yield* client
76 .get(`${effectCallerUrl}/?name=bob`)
77 .pipe(coldStartRetry);
78 expect(res.status).toBe(200);
79 expect(yield* res.text).toBe("hello bob");
80 }).pipe(logLevel),
81 {
82 tags: ["provider:cloudflare", "provider:cloudflare:worker", "live"],
83 timeout: 180_000,
84 },
85);