1import * as Alchemy from "alchemy";
2import * as Fly from "alchemy/Fly";
3import * as Test from "alchemy/Test/Bun";
4import { expect } from "bun:test";
5import * as Effect from "effect/Effect";
6import * as Schedule from "effect/Schedule";
7import * as HttpClient from "effect/http/HttpClient";
8import Stack from "../alchemy.run.ts";
9
10const { test, beforeAll, afterAll, deploy, destroy } = Test.make({
11 providers: Fly.providers(),
12 state: Alchemy.localState(),
13 profile: process.env.ALCHEMY_PROFILE,
14});
15
16const fetchOk = (url: string) =>
17 Effect.gen(function* () {
18 const client = yield* HttpClient.HttpClient;
19 return yield* client.get(url).pipe(
20 Effect.flatMap((res) =>
21 res.status === 200
22 ? Effect.succeed(res)
23 : Effect.fail(new Error(`HTTP ${res.status}`)),
24 ),
25 Effect.retry({
26 schedule: Schedule.exponential("500 millis"),
27 times: 20,
28 }),
29 );
30 });
31
32const stack = beforeAll(deploy(Stack), { timeout: 300_000 });
33
34afterAll.skipIf(!!process.env.NO_DESTROY)(destroy(Stack), {
35 timeout: 180_000,
36});
37
38test(
39 "puts and gets an object on Tigris over HTTP",
40 Effect.gen(function* () {
41 const out = yield* stack;
42 expect(out.addOnId).toBeString();
43 expect(out.bucketName).toBeString();
44 expect(out.apiUrl).toBe(`https://${out.appName}.fly.dev`);
45
46 const health = yield* fetchOk(`${out.apiUrl}/health`);
47 expect(health.status).toBe(200);
48
49 const response = yield* fetchOk(`${out.apiUrl}/`);
50 expect(response.status).toBe(200);
51 const body = (yield* response.json) as { ok: boolean; text: string };
52 expect(body.ok).toBe(true);
53 expect(body.text).toBe("hello-from-tigris");
54 }),
55 { timeout: 180_000 },
56);