Files
HiveGrid-Wireframes/hivegrid-cloud/server/host-routing-runtime.test.ts
T

207 lines
9.0 KiB
TypeScript

// @vitest-environment node
import { describe, expect, test } from "vitest";
import { getHostRoutingRuntimeDecision } from "./host-routing-runtime";
function expectDispatchDecision(request: Request) {
const decision = getHostRoutingRuntimeDecision(request);
expect(decision.type).toBe("dispatch");
if (decision.type !== "dispatch") {
throw new Error(`Expected dispatch decision, received ${decision.type}`);
}
return decision;
}
describe("getHostRoutingRuntimeDecision", () => {
test("dispatches the canonical app host root to the tenant picker route", () => {
const decision = expectDispatchDecision(new Request("http://app.localhost/?from=login#tenants"));
expect(decision.target).toBe("web");
expect(new URL(decision.request.url).pathname).toBe("/");
expect(new URL(decision.request.url).search).toBe("?from=login");
expect(new URL(decision.request.url).hash).toBe("#tenants");
});
test("keeps app host requests on promoted tenant paths for web dispatch", () => {
const decision = expectDispatchDecision(new Request("http://app.localhost/acme/dashboard?tab=activity#events"));
expect(decision.target).toBe("web");
expect(new URL(decision.request.url).pathname).toBe("/acme/dashboard");
expect(new URL(decision.request.url).search).toBe("?tab=activity");
expect(new URL(decision.request.url).hash).toBe("#events");
});
test("dispatches public auth routes on the app host without tenant rewriting", () => {
const decision = expectDispatchDecision(new Request("http://app.localhost/login?redirectTo=%2Facme%2Fdashboard"));
expect(decision.target).toBe("web");
expect(new URL(decision.request.url).pathname).toBe("/login");
expect(new URL(decision.request.url).search).toBe("?redirectTo=%2Facme%2Fdashboard");
});
test("rejects removed public API paths instead of redirecting compatibility routes", () => {
const decision = getHostRoutingRuntimeDecision(new Request("http://app.localhost/api/workflows/run/workflow_1?tenantId=tenant_1"));
expect(decision).toEqual({
type: "reject",
status: 404,
});
});
test("redirects legacy api v1 paths before removed API path rejection", () => {
expect(getHostRoutingRuntimeDecision(new Request("http://app.localhost/api/v1/health?check=deep#status"))).toEqual({
type: "redirect",
status: 308,
location: "http://api.localhost/v1/health?check=deep#status",
});
});
test("lets internal API proxies reach private web API handlers without public redirects", () => {
const decision = expectDispatchDecision(
new Request("http://app.localhost/internal/api/workflows/run/workflow_1?tenantId=tenant_1", {
method: "POST",
headers: {
"x-toolctrl-internal-web-api-proxy": "1",
"x-toolctrl-internal-web-api-proxy-signature": "signed",
"x-api-key": "tenant-api-key",
},
body: JSON.stringify({ name: "Ada" }),
})
);
expect(decision.target).toBe("web");
expect(new URL(decision.request.url).pathname).toBe("/internal/api/workflows/run/workflow_1");
expect(new URL(decision.request.url).search).toBe("?tenantId=tenant_1");
expect(decision.request.headers.get("x-toolctrl-internal-web-api-proxy")).toBe("1");
expect(decision.request.headers.get("x-toolctrl-internal-web-api-proxy-signature")).toBe("signed");
expect(decision.request.headers.get("x-api-key")).toBe("tenant-api-key");
});
test("dispatches canonical admin host requests for web dispatch", () => {
const decision = expectDispatchDecision(new Request("http://admin.localhost/accounts/users?role=owner#active"));
expect(decision.target).toBe("web");
expect(new URL(decision.request.url).pathname).toBe("/accounts/users");
expect(new URL(decision.request.url).search).toBe("?role=owner");
expect(new URL(decision.request.url).hash).toBe("#active");
});
test("keeps canonical admin host routes stable for web dispatch", () => {
const settingsDecision = expectDispatchDecision(new Request("http://admin.localhost/settings/profile?tab=mfa#codes"));
const metricsDataDecision = expectDispatchDecision(new Request("http://admin.localhost/metrics/summary.data?_routes=routes%2Fadmin%2Fmetrics%2Fsummary.__host"));
expect(settingsDecision.target).toBe("web");
expect(new URL(settingsDecision.request.url).pathname).toBe("/settings/profile");
expect(new URL(settingsDecision.request.url).search).toBe("?tab=mfa");
expect(new URL(settingsDecision.request.url).hash).toBe("#codes");
expect(new URL(metricsDataDecision.request.url).pathname).toBe("/metrics/summary.data");
});
test.each([
["/api?tab=overview", "/api"],
["/api/keys?filter=active#keys", "/api/keys"],
["/api/keys/new", "/api/keys/new"],
["/api/keys/api_key_1", "/api/keys/api_key_1"],
["/api/logs", "/api/logs"],
["/api/docs", "/api/docs"],
["/api/credits", "/api/credits"],
["/api/keys.data?_routes=routes%2Fadmin%2Fapi%2Fkeys.__host", "/api/keys.data"],
])("dispatches canonical admin API section route %s to the web runtime", (route, expectedPathname) => {
const decision = expectDispatchDecision(new Request(`http://admin.localhost${route}`));
expect(decision.target).toBe("web");
expect(new URL(decision.request.url).pathname).toBe(expectedPathname);
});
test("redirects API host unversioned aliases to v1 paths before dispatch", () => {
expect(getHostRoutingRuntimeDecision(new Request("http://api.localhost/health?check=deep#status"))).toEqual({
type: "redirect",
status: 308,
location: "http://api.localhost/v1/health?check=deep#status",
});
expect(getHostRoutingRuntimeDecision(new Request("http://api.localhost/accounts?cursor=next"))).toEqual({
type: "redirect",
status: 308,
location: "http://api.localhost/v1/accounts?cursor=next",
});
});
test("redirects public web paths away from the API host", () => {
const decision = getHostRoutingRuntimeDecision(new Request("http://api.localhost/login?redirectTo=%2Facme%2Fdashboard"));
expect(decision).toEqual({
type: "redirect",
status: 308,
location: "http://app.localhost/login?redirectTo=%2Facme%2Fdashboard",
});
});
test("does not double-prefix API internal paths", () => {
const apiDecision = expectDispatchDecision(new Request("http://api.localhost/v1/health?check=deep#status"));
expect(new URL(apiDecision.request.url).pathname).toBe("/v1/health");
});
test("rejects removed root app paths instead of redirecting compatibility routes", () => {
const decision = getHostRoutingRuntimeDecision(new Request("http://localhost/app/acme/settings?tab=profile#billing"));
expect(decision).toEqual({
type: "reject",
status: 404,
});
});
test("rejects removed admin paths on root and app hosts", () => {
expect(getHostRoutingRuntimeDecision(new Request("http://localhost/admin/settings?tab=users#active"))).toEqual({
type: "reject",
status: 404,
});
expect(getHostRoutingRuntimeDecision(new Request("http://app.localhost/admin/settings?tab=users#active"))).toEqual({
type: "reject",
status: 404,
});
});
test("redirects canonical paths away from the wrong host before dispatch", () => {
expect(getHostRoutingRuntimeDecision(new Request("http://app.localhost/dashboard?tab=activity#events"))).toEqual({
type: "redirect",
status: 308,
location: "http://admin.localhost/dashboard?tab=activity#events",
});
expect(getHostRoutingRuntimeDecision(new Request("http://app.localhost/accounts/users?filter=active"))).toEqual({
type: "redirect",
status: 308,
location: "http://admin.localhost/accounts/users?filter=active",
});
expect(getHostRoutingRuntimeDecision(new Request("http://admin.localhost/acme/dashboard?tab=activity#events"))).toEqual({
type: "redirect",
status: 308,
location: "http://app.localhost/acme/dashboard?tab=activity#events",
});
expect(getHostRoutingRuntimeDecision(new Request("http://admin.localhost/acme"))).toEqual({
type: "redirect",
status: 308,
location: "http://app.localhost/acme",
});
expect(getHostRoutingRuntimeDecision(new Request("http://api.localhost/acme"))).toEqual({
type: "redirect",
status: 308,
location: "http://app.localhost/acme",
});
expect(getHostRoutingRuntimeDecision(new Request("http://app.localhost/v1/health"))).toEqual({
type: "redirect",
status: 308,
location: "http://api.localhost/v1/health",
});
});
test("dispatches API operational routes to the API runtime", () => {
const healthDecision = expectDispatchDecision(new Request("http://api.localhost/healthz"));
const readyDecision = expectDispatchDecision(new Request("http://api.localhost/readyz"));
expect(healthDecision.target).toBe("api");
expect(new URL(healthDecision.request.url).pathname).toBe("/healthz");
expect(readyDecision.target).toBe("api");
expect(new URL(readyDecision.request.url).pathname).toBe("/readyz");
});
});