test(ci): retry canvas auth reset fetches

This commit is contained in:
Peter Steinberger
2026-04-11 02:45:08 +01:00
parent ecb10c1de9
commit 94a90fcb85

View File

@@ -13,6 +13,33 @@ import { withTempConfig } from "./test-temp-config.js";
const WS_REJECT_TIMEOUT_MS = 2_000;
const WS_CONNECT_TIMEOUT_MS = 2_000;
function isConnectionReset(value: unknown): boolean {
let current: unknown = value;
for (let depth = 0; depth < 4; depth += 1) {
if (!current || typeof current !== "object") {
return false;
}
const record = current as { code?: unknown; cause?: unknown };
if (record.code === "ECONNRESET") {
return true;
}
current = record.cause;
}
return false;
}
async function fetchCanvas(input: string, init?: RequestInit): Promise<Response> {
try {
return await fetch(input, init);
} catch (err) {
if (isConnectionReset(err)) {
return await fetch(input, init);
}
throw err;
}
}
async function listen(
server: ReturnType<typeof createGatewayHttpServer>,
host = "127.0.0.1",
@@ -225,10 +252,12 @@ describe("gateway canvas host auth", () => {
const activeCanvasPath = scopedCanvasPath(activeNodeCapability, `${CANVAS_HOST_PATH}/`);
const activeWsPath = scopedCanvasPath(activeNodeCapability, CANVAS_WS_PATH);
const unauthCanvas = await fetch(`http://${host}:${listener.port}${CANVAS_HOST_PATH}/`);
const unauthCanvas = await fetchCanvas(
`http://${host}:${listener.port}${CANVAS_HOST_PATH}/`,
);
expect(unauthCanvas.status).toBe(401);
const malformedScoped = await fetch(
const malformedScoped = await fetchCanvas(
`http://${host}:${listener.port}${CANVAS_CAPABILITY_PATH_PREFIX}/broken`,
);
expect(malformedScoped.status).toBe(401);
@@ -244,7 +273,7 @@ describe("gateway canvas host auth", () => {
}),
);
const operatorCapabilityBlocked = await fetch(
const operatorCapabilityBlocked = await fetchCanvas(
`http://${host}:${listener.port}${scopedCanvasPath(operatorOnlyCapability, `${CANVAS_HOST_PATH}/`)}`,
);
expect(operatorCapabilityBlocked.status).toBe(401);
@@ -260,7 +289,7 @@ describe("gateway canvas host auth", () => {
}),
);
const expiredCapabilityBlocked = await fetch(
const expiredCapabilityBlocked = await fetchCanvas(
`http://${host}:${listener.port}${scopedCanvasPath(expiredNodeCapability, `${CANVAS_HOST_PATH}/`)}`,
);
expect(expiredCapabilityBlocked.status).toBe(401);
@@ -275,11 +304,13 @@ describe("gateway canvas host auth", () => {
});
clients.add(activeNodeClient);
const scopedCanvas = await fetch(`http://${host}:${listener.port}${activeCanvasPath}`);
const scopedCanvas = await fetchCanvas(
`http://${host}:${listener.port}${activeCanvasPath}`,
);
expect(scopedCanvas.status).toBe(200);
expect(await scopedCanvas.text()).toBe("ok");
const scopedA2ui = await fetch(
const scopedA2ui = await fetchCanvas(
`http://${host}:${listener.port}${scopedCanvasPath(activeNodeCapability, `${A2UI_PATH}/`)}`,
);
expect([200, 503]).toContain(scopedA2ui.status);
@@ -288,7 +319,7 @@ describe("gateway canvas host auth", () => {
clients.delete(activeNodeClient);
const disconnectedNodeBlocked = await fetch(
const disconnectedNodeBlocked = await fetchCanvas(
`http://${host}:${listener.port}${activeCanvasPath}`,
);
expect(disconnectedNodeBlocked.status).toBe(401);
@@ -315,7 +346,7 @@ describe("gateway canvas host auth", () => {
}),
);
const res = await fetch(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`);
const res = await fetchCanvas(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`);
expect(res.status).toBe(401);
await expectWsRejected(`ws://127.0.0.1:${listener.port}${CANVAS_WS_PATH}`, {});
@@ -329,10 +360,10 @@ describe("gateway canvas host auth", () => {
resolvedAuth: tokenResolvedAuth,
handleHttpRequest: allowCanvasHostHttp,
run: async ({ listener }) => {
const res = await fetch(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`);
const res = await fetchCanvas(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`);
expect(res.status).toBe(401);
const a2ui = await fetch(`http://127.0.0.1:${listener.port}${A2UI_PATH}/`);
const a2ui = await fetchCanvas(`http://127.0.0.1:${listener.port}${A2UI_PATH}/`);
expect(a2ui.status).toBe(401);
await expectWsRejected(`ws://127.0.0.1:${listener.port}${CANVAS_WS_PATH}`, {});
@@ -368,7 +399,7 @@ describe("gateway canvas host auth", () => {
const canvasPath = scopedCanvasPath(capability, `${CANVAS_HOST_PATH}/`);
const wsPath = scopedCanvasPath(capability, CANVAS_WS_PATH);
const scopedCanvas = await fetch(`http://[::1]:${listener.port}${canvasPath}`);
const scopedCanvas = await fetchCanvas(`http://[::1]:${listener.port}${canvasPath}`);
expect(scopedCanvas.status).toBe(200);
await expectWsConnected(`ws://[::1]:${listener.port}${wsPath}`);
@@ -402,14 +433,17 @@ describe("gateway canvas host auth", () => {
authorization: "Bearer wrong",
"x-forwarded-for": "203.0.113.99",
};
const first = await fetch(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`, {
const first = await fetchCanvas(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`, {
headers,
});
expect(first.status).toBe(401);
const second = await fetch(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`, {
headers,
});
const second = await fetchCanvas(
`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`,
{
headers,
},
);
expect(second.status).toBe(429);
expect(second.headers.get("retry-after")).toBeTruthy();
@@ -444,14 +478,20 @@ describe("gateway canvas host auth", () => {
host: "localhost",
"x-forwarded-for": "127.0.0.1, 203.0.113.24",
};
const first = await fetch(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`, {
headers,
});
const first = await fetchCanvas(
`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`,
{
headers,
},
);
expect(first.status).toBe(401);
const second = await fetch(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`, {
headers,
});
const second = await fetchCanvas(
`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`,
{
headers,
},
);
expect(second.status).toBe(429);
},
});