alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
148 lines (117 loc) • 4.37 kB
text/typescript
import { Alepha } from "alepha";
import { afterEach, describe, expect, test } from "vitest";
import { NodeHttpServerProvider } from "../providers/NodeHttpServerProvider.ts";
describe("NodeHttpServerProvider", () => {
describe("graceful shutdown", () => {
let alepha: Alepha;
let server: NodeHttpServerProvider;
afterEach(async () => {
await alepha?.stop().catch(() => {});
});
test("dev mode: destroys connections immediately on close", async () => {
alepha = Alepha.create({
env: { NODE_ENV: "development", SERVER_PORT: 0 },
});
alepha.with(NodeHttpServerProvider);
await alepha.start();
server = alepha.inject(NodeHttpServerProvider);
// Make a request to establish connection
await fetch(`${server.hostname}/`);
const startTime = Date.now();
await alepha.stop();
const elapsed = Date.now() - startTime;
// Should close instantly (under 100ms)
expect(elapsed).toBeLessThan(100);
expect(server.getConnectionsCount()).toBe(0);
});
test("production mode: waits for connections then closes", async () => {
alepha = Alepha.create({
env: {
NODE_ENV: "production",
SERVER_PORT: 0,
APP_SECRET: "test-secret",
},
});
alepha.with(NodeHttpServerProvider);
await alepha.start();
server = alepha.inject(NodeHttpServerProvider);
server.options.shutdownTimeout = 500;
// Make a request to establish keep-alive connection
await fetch(`${server.hostname}/`);
const startTime = Date.now();
await alepha.stop();
const elapsed = Date.now() - startTime;
// In production, should not be instant (waits for graceful close or timeout)
// But should complete within timeout
expect(elapsed).toBeLessThan(server.options.shutdownTimeout + 100);
expect(server.getConnectionsCount()).toBe(0);
});
test("production mode: forces close after timeout", async () => {
alepha = Alepha.create({
env: {
NODE_ENV: "production",
SERVER_PORT: 0,
APP_SECRET: "test-secret",
},
});
alepha.with(NodeHttpServerProvider);
await alepha.start();
server = alepha.inject(NodeHttpServerProvider);
server.options.shutdownTimeout = 50;
// Make a request to establish connection
await fetch(`${server.hostname}/`);
const startTime = Date.now();
await alepha.stop();
const elapsed = Date.now() - startTime;
// Should close around timeout
expect(elapsed).toBeLessThan(200);
expect(server.getConnectionsCount()).toBe(0);
});
test("connections are tracked and cleared", async () => {
alepha = Alepha.create({
env: { NODE_ENV: "development", SERVER_PORT: 0 },
});
alepha.with(NodeHttpServerProvider);
await alepha.start();
server = alepha.inject(NodeHttpServerProvider);
// Make multiple requests
await fetch(`${server.hostname}/`);
await fetch(`${server.hostname}/`);
await alepha.stop();
// All connections cleared after stop
expect(server.getConnectionsCount()).toBe(0);
});
test("rejects new requests during shutdown", async () => {
alepha = Alepha.create({
env: {
NODE_ENV: "production",
SERVER_PORT: 0,
APP_SECRET: "test-secret",
},
});
alepha.with(NodeHttpServerProvider);
await alepha.start();
server = alepha.inject(NodeHttpServerProvider);
server.options.shutdownTimeout = 500;
// Establish a connection to keep server busy
await fetch(`${server.hostname}/`);
// Start shutdown (don't await yet)
const stopPromise = alepha.stop();
// Give server.close() time to be called
await new Promise((r) => setTimeout(r, 10));
// New request should fail (server no longer accepting connections)
let error: Error | null = null;
try {
await fetch(`${server.hostname}/`, {
signal: AbortSignal.timeout(100),
});
} catch (e) {
error = e as Error;
}
// Should get a connection error (ECONNREFUSED or similar)
expect(error).not.toBeNull();
// Wait for shutdown to complete
await stopPromise;
});
});
});