t3-code-android-nightly/.repos/alchemy-effect/packages/alchemy/test/Cloudflare/VpcService/VpcService.test.ts
Julius Marminge 6f9cea00ae
chore(refs): sync Effect and Alchemy references to 4.0.1 and beta.80 (#16170)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 13:22:30 -07:00

267 lines
7.9 KiB
TypeScript

import * as Cloudflare from "@/Cloudflare";
import { CloudflareEnvironment } from "@/Cloudflare/CloudflareEnvironment";
import * as Provider from "@/Provider";
import * as Test from "@/Test/Alchemy";
import * as connectivity from "@distilled.cloud/cloudflare/connectivity";
import { expect } from "alchemy-test";
import * as Data from "effect/Data";
import * as Effect from "effect/Effect";
import { MinimumLogLevel } from "effect/References";
import * as Schedule from "effect/Schedule";
const { test } = Test.make({ providers: Cloudflare.providers() });
const logLevel = Effect.provideService(
MinimumLogLevel,
process.env.DEBUG ? "Debug" : "Info",
);
test.provider(
"create, update, delete vpc service",
(stack) =>
Effect.gen(function* () {
const { accountId } = yield* yield* CloudflareEnvironment;
yield* stack.destroy();
const { tunnel, service } = yield* stack.deploy(
Effect.gen(function* () {
const tunnel = yield* Cloudflare.Tunnel.Tunnel("VpcTunnel", {
ingress: [{ service: "http://localhost:8080" }],
adopt: true,
});
const service = yield* Cloudflare.VpcService.VpcService("VpcSvc", {
httpPort: 8080,
host: {
hostname: "localhost",
resolverNetwork: { tunnelId: tunnel.tunnelId },
},
adopt: true,
});
return { tunnel, service };
}),
);
expect(service.serviceId).toBeDefined();
expect(service.serviceType).toEqual("http");
expect(service.httpPort).toEqual(8080);
expect(service.host).toMatchObject({
hostname: "localhost",
resolverNetwork: { tunnelId: tunnel.tunnelId },
});
const fetched = yield* connectivity.getDirectoryService({
accountId,
serviceId: service.serviceId,
});
expect(fetched.serviceId).toEqual(service.serviceId);
expect(fetched.httpPort).toEqual(8080);
const updated = yield* stack.deploy(
Effect.gen(function* () {
const tunnel = yield* Cloudflare.Tunnel.Tunnel("VpcTunnel", {
ingress: [{ service: "http://localhost:8080" }],
adopt: true,
});
return yield* Cloudflare.VpcService.VpcService("VpcSvc", {
httpPort: 3000,
httpsPort: 3001,
host: {
hostname: "localhost",
resolverNetwork: { tunnelId: tunnel.tunnelId },
},
adopt: true,
});
}),
);
expect(updated.serviceId).toEqual(service.serviceId);
expect(updated.httpPort).toEqual(3000);
expect(updated.httpsPort).toEqual(3001);
const fetchedUpdated = yield* connectivity.getDirectoryService({
accountId,
serviceId: service.serviceId,
});
expect(fetchedUpdated.httpPort).toEqual(3000);
expect(fetchedUpdated.httpsPort).toEqual(3001);
yield* stack.destroy();
yield* waitForServiceToBeDeleted(service.serviceId, accountId);
}).pipe(logLevel),
{
tags: [
"provider:cloudflare",
"provider:cloudflare:connectivity",
"provider:cloudflare:tunnel",
"provider:cloudflare:vpcservice",
"live",
],
},
);
test.provider(
"create vpc service with ipv4 host",
(stack) =>
Effect.gen(function* () {
const { accountId } = yield* yield* CloudflareEnvironment;
yield* stack.destroy();
const service = yield* stack.deploy(
Effect.gen(function* () {
const tunnel = yield* Cloudflare.Tunnel.Tunnel("Ipv4Tunnel", {
ingress: [{ service: "http://localhost:8080" }],
adopt: true,
});
return yield* Cloudflare.VpcService.VpcService("Ipv4Svc", {
httpPort: 8080,
host: {
ipv4: "192.168.1.100",
network: { tunnelId: tunnel.tunnelId },
},
adopt: true,
});
}),
);
expect(service.host).toMatchObject({
ipv4: "192.168.1.100",
});
expect("ipv6" in service.host).toBe(false);
const fetched = yield* connectivity.getDirectoryService({
accountId,
serviceId: service.serviceId,
});
expect((fetched.host as { ipv4?: string }).ipv4).toEqual("192.168.1.100");
yield* stack.destroy();
yield* waitForServiceToBeDeleted(service.serviceId, accountId);
}).pipe(logLevel),
{
tags: [
"provider:cloudflare",
"provider:cloudflare:connectivity",
"provider:cloudflare:tunnel",
"provider:cloudflare:vpcservice",
"live",
],
},
);
// TODO: re-enable once distilled ships the union-ordering fix
// (alchemy-run/distilled#232) — on @distilled.cloud/cloudflare@0.16.3 the
// dual-stack host variant comes after the ipv4-only variant in the request
// schema's Schema.Union, so `ipv6` is silently stripped on encode.
test.provider.skip(
"create vpc service with dual-stack host",
(stack) =>
Effect.gen(function* () {
const { accountId } = yield* yield* CloudflareEnvironment;
yield* stack.destroy();
const service = yield* stack.deploy(
Effect.gen(function* () {
const tunnel = yield* Cloudflare.Tunnel.Tunnel("DualStackTunnel", {
ingress: [{ service: "http://localhost:8080" }],
adopt: true,
});
return yield* Cloudflare.VpcService.VpcService("DualStackSvc", {
httpPort: 8080,
host: {
ipv4: "192.168.1.101",
ipv6: "2001:db8::1",
network: { tunnelId: tunnel.tunnelId },
},
adopt: true,
});
}),
);
expect(service.host).toMatchObject({
ipv4: "192.168.1.101",
ipv6: "2001:db8::1",
});
yield* stack.destroy();
yield* waitForServiceToBeDeleted(service.serviceId, accountId);
}).pipe(logLevel),
{
tags: [
"provider:cloudflare",
"provider:cloudflare:connectivity",
"provider:cloudflare:tunnel",
"provider:cloudflare:vpcservice",
"live",
],
},
);
test.provider(
"list enumerates the deployed vpc service",
(stack) =>
Effect.gen(function* () {
const { accountId } = yield* yield* CloudflareEnvironment;
yield* stack.destroy();
const service = yield* stack.deploy(
Effect.gen(function* () {
const tunnel = yield* Cloudflare.Tunnel.Tunnel("ListTunnel", {
ingress: [{ service: "http://localhost:8080" }],
adopt: true,
});
return yield* Cloudflare.VpcService.VpcService("ListSvc", {
httpPort: 8080,
host: {
hostname: "localhost",
resolverNetwork: { tunnelId: tunnel.tunnelId },
},
adopt: true,
});
}),
);
const provider = yield* Provider.findProvider(
Cloudflare.VpcService.VpcService,
);
const all = yield* provider.list();
const found = all.find((s) => s.serviceId === service.serviceId);
expect(found).toBeDefined();
expect(found?.serviceName).toEqual(service.serviceName);
expect(found?.accountId).toEqual(accountId);
yield* stack.destroy();
yield* waitForServiceToBeDeleted(service.serviceId, accountId);
}).pipe(logLevel),
{
tags: [
"provider:cloudflare",
"provider:cloudflare:connectivity",
"provider:cloudflare:tunnel",
"provider:cloudflare:vpcservice",
"live",
],
},
);
const waitForServiceToBeDeleted = Effect.fn(function* (
serviceId: string,
accountId: string,
) {
yield* connectivity.getDirectoryService({ accountId, serviceId }).pipe(
Effect.flatMap(() => Effect.fail(new VpcServiceStillExists())),
Effect.retry({
while: (e): e is VpcServiceStillExists =>
e instanceof VpcServiceStillExists,
schedule: Schedule.exponential(100),
}),
Effect.catch(() => Effect.void),
);
});
class VpcServiceStillExists extends Data.TaggedError("VpcServiceStillExists") {}