import * as net from "node:net";import { it as effectIt } from "@effect/vitest";import { HostProcessPlatform } from "@t3tools/shared/hostProcess";import * as Net from "@t3tools/shared/Net";import { Effect, Layer } from "effect";import { expect } from "vite-plus/test";import { ProcessRunner } from "../processRunner.ts";import * as PortScanner from "./PortScanner.ts";const TestProcessRunner = Layer.succeed(ProcessRunner, { run: () => Effect.die("ProcessRunner should not be used by Windows TCP probe tests"),});const TestPortDiscoveryLive = PortScanner.layer.pipe( Layer.provide( Layer.mergeAll(TestProcessRunner, Net.layer, Layer.succeed(HostProcessPlatform, "win32")), ),);const openServer = (port: number): Effect.Effect<net.Server | null> => Effect.callback((resume) => { const server = net.createServer(); server.once("error", () => { resume(Effect.succeed(null)); }); server.listen(port, "127.0.0.1", () => { resume(Effect.succeed(server)); }); return Effect.sync(() => { server.close(); }); });const closeServer = (server: net.Server): Effect.Effect<void> => Effect.callback((resume) => { server.close(() => resume(Effect.void)); });const openCommonDevServer = Effect.fn("PortScannerTest.openCommonDevServer")(function* ( ports: ReadonlyArray<number>,) { for (const port of ports) { const server = yield* openServer(port); if (server !== null) return { port, server }; } return yield* Effect.die( new Error("No common development port was available for the preview scanner test"), );});const commonDevServer = Effect.acquireRelease( openCommonDevServer(PortScanner.COMMON_DEV_PORTS), ({ server }) => closeServer(server),);/** * Integration tests against a real TCP listener. We provide the Windows host * platform so the tests exercise the TCP-probe fallback without depending on * `lsof` being installed. */effectIt.layer(TestPortDiscoveryLive)("PortDiscovery integration (TCP probe fallback)", (it) => { it.effect( "scan() returns a server we just opened on a curated dev port", Effect.fn("PortScannerTest.scanFindsCommonDevServer")(function* () { const { port } = yield* commonDevServer; const scanner = yield* PortScanner.PortDiscovery; const result = yield* scanner.scan(); const found = result.find((server) => server.port === port); expect(found).toBeDefined(); expect(found?.host).toBe("localhost"); }), ); it.effect( "retain drives an immediate broadcast to subscribers", Effect.fn("PortScannerTest.retainBroadcastsImmediately")(function* () { const { port } = yield* commonDevServer; const received: number[] = []; const scanner = yield* PortScanner.PortDiscovery; yield* scanner.subscribe((servers) => Effect.sync(() => { for (const server of servers) received.push(server.port); }), ); yield* scanner.retain; expect(received).toContain(port); }), );});
import * as net from "node:net";
import { it as effectIt } from "@effect/vitest";
import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
import * as Net from "@t3tools/shared/Net";
import { Effect, Layer } from "effect";
import { expect } from "vite-plus/test";
import { ProcessRunner } from "../processRunner.ts";
import * as PortScanner from "./PortScanner.ts";
const TestProcessRunner = Layer.succeed(ProcessRunner, {
run: () => Effect.die("ProcessRunner should not be used by Windows TCP probe tests"),
});
const TestPortDiscoveryLive = PortScanner.layer.pipe(
Layer.provide(
Layer.mergeAll(TestProcessRunner, Net.layer, Layer.succeed(HostProcessPlatform, "win32")),
),
);
const openServer = (port: number): Effect.Effect<net.Server | null> =>
Effect.callback((resume) => {
const server = net.createServer();
server.once("error", () => {
resume(Effect.succeed(null));
});
server.listen(port, "127.0.0.1", () => {
resume(Effect.succeed(server));
});
return Effect.sync(() => {
server.close();
});
});
const closeServer = (server: net.Server): Effect.Effect<void> =>
Effect.callback((resume) => {
server.close(() => resume(Effect.void));
});
const openCommonDevServer = Effect.fn("PortScannerTest.openCommonDevServer")(function* (
ports: ReadonlyArray<number>,
) {
for (const port of ports) {
const server = yield* openServer(port);
if (server !== null) return { port, server };
}
return yield* Effect.die(
new Error("No common development port was available for the preview scanner test"),
);
});
const commonDevServer = Effect.acquireRelease(
openCommonDevServer(PortScanner.COMMON_DEV_PORTS),
({ server }) => closeServer(server),
);
/**
* Integration tests against a real TCP listener. We provide the Windows host
* platform so the tests exercise the TCP-probe fallback without depending on
* `lsof` being installed.
*/
effectIt.layer(TestPortDiscoveryLive)("PortDiscovery integration (TCP probe fallback)", (it) => {
it.effect(
"scan() returns a server we just opened on a curated dev port",
Effect.fn("PortScannerTest.scanFindsCommonDevServer")(function* () {
const { port } = yield* commonDevServer;
const scanner = yield* PortScanner.PortDiscovery;
const result = yield* scanner.scan();
const found = result.find((server) => server.port === port);
expect(found).toBeDefined();
expect(found?.host).toBe("localhost");
}),
);
it.effect(
"retain drives an immediate broadcast to subscribers",
Effect.fn("PortScannerTest.retainBroadcastsImmediately")(function* () {
const { port } = yield* commonDevServer;
const received: number[] = [];
const scanner = yield* PortScanner.PortDiscovery;
yield* scanner.subscribe((servers) =>
Effect.sync(() => {
for (const server of servers) received.push(server.port);
}),
);
yield* scanner.retain;
expect(received).toContain(port);
}),
);
});