| import type { IncomingMessage, ServerResponse } from "node:http"; |
| import { describe, expect, it, vi } from "vitest"; |
|
|
| import { createGatewayPluginRequestHandler } from "./plugins-http.js"; |
| import { createTestRegistry } from "./__tests__/test-utils.js"; |
|
|
| const makeResponse = (): { |
| res: ServerResponse; |
| setHeader: ReturnType<typeof vi.fn>; |
| end: ReturnType<typeof vi.fn>; |
| } => { |
| const setHeader = vi.fn(); |
| const end = vi.fn(); |
| const res = { |
| headersSent: false, |
| statusCode: 200, |
| setHeader, |
| end, |
| } as unknown as ServerResponse; |
| return { res, setHeader, end }; |
| }; |
|
|
| describe("createGatewayPluginRequestHandler", () => { |
| it("returns false when no handlers are registered", async () => { |
| const log = { warn: vi.fn() } as unknown as Parameters< |
| typeof createGatewayPluginRequestHandler |
| >[0]["log"]; |
| const handler = createGatewayPluginRequestHandler({ |
| registry: createTestRegistry(), |
| log, |
| }); |
| const { res } = makeResponse(); |
| const handled = await handler({} as IncomingMessage, res); |
| expect(handled).toBe(false); |
| }); |
|
|
| it("continues until a handler reports it handled the request", async () => { |
| const first = vi.fn(async () => false); |
| const second = vi.fn(async () => true); |
| const handler = createGatewayPluginRequestHandler({ |
| registry: createTestRegistry({ |
| httpHandlers: [ |
| { pluginId: "first", handler: first, source: "first" }, |
| { pluginId: "second", handler: second, source: "second" }, |
| ], |
| }), |
| log: { warn: vi.fn() } as unknown as Parameters< |
| typeof createGatewayPluginRequestHandler |
| >[0]["log"], |
| }); |
|
|
| const { res } = makeResponse(); |
| const handled = await handler({} as IncomingMessage, res); |
| expect(handled).toBe(true); |
| expect(first).toHaveBeenCalledTimes(1); |
| expect(second).toHaveBeenCalledTimes(1); |
| }); |
|
|
| it("handles registered http routes before generic handlers", async () => { |
| const routeHandler = vi.fn(async (_req, res: ServerResponse) => { |
| res.statusCode = 200; |
| }); |
| const fallback = vi.fn(async () => true); |
| const handler = createGatewayPluginRequestHandler({ |
| registry: createTestRegistry({ |
| httpRoutes: [ |
| { |
| pluginId: "route", |
| path: "/demo", |
| handler: routeHandler, |
| source: "route", |
| }, |
| ], |
| httpHandlers: [{ pluginId: "fallback", handler: fallback, source: "fallback" }], |
| }), |
| log: { warn: vi.fn() } as unknown as Parameters< |
| typeof createGatewayPluginRequestHandler |
| >[0]["log"], |
| }); |
|
|
| const { res } = makeResponse(); |
| const handled = await handler({ url: "/demo" } as IncomingMessage, res); |
| expect(handled).toBe(true); |
| expect(routeHandler).toHaveBeenCalledTimes(1); |
| expect(fallback).not.toHaveBeenCalled(); |
| }); |
|
|
| it("logs and responds with 500 when a handler throws", async () => { |
| const log = { warn: vi.fn() } as unknown as Parameters< |
| typeof createGatewayPluginRequestHandler |
| >[0]["log"]; |
| const handler = createGatewayPluginRequestHandler({ |
| registry: createTestRegistry({ |
| httpHandlers: [ |
| { |
| pluginId: "boom", |
| handler: async () => { |
| throw new Error("boom"); |
| }, |
| source: "boom", |
| }, |
| ], |
| }), |
| log, |
| }); |
|
|
| const { res, setHeader, end } = makeResponse(); |
| const handled = await handler({} as IncomingMessage, res); |
| expect(handled).toBe(true); |
| expect(log.warn).toHaveBeenCalledWith(expect.stringContaining("boom")); |
| expect(res.statusCode).toBe(500); |
| expect(setHeader).toHaveBeenCalledWith("Content-Type", "text/plain; charset=utf-8"); |
| expect(end).toHaveBeenCalledWith("Internal Server Error"); |
| }); |
| }); |
|
|