From 4e896b7ee81d603cb8964574c6790b7f1492e0a3 Mon Sep 17 00:00:00 2001 From: underwaterresearch Date: Sat, 4 Apr 2026 07:30:02 +0000 Subject: [PATCH] test: lock readiness warning message formatting --- .../__tests__/readinessWarning.test.js | 56 +++++++++++++++++++ workers/provisioner/readinessWarning.js | 19 +++++++ workers/provisioner/worker.js | 10 +--- 3 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 backend-api/__tests__/readinessWarning.test.js create mode 100644 workers/provisioner/readinessWarning.js diff --git a/backend-api/__tests__/readinessWarning.test.js b/backend-api/__tests__/readinessWarning.test.js new file mode 100644 index 0000000..91d9385 --- /dev/null +++ b/backend-api/__tests__/readinessWarning.test.js @@ -0,0 +1,56 @@ +const { buildReadinessWarningDetail } = require("../../workers/provisioner/readinessWarning"); + +describe("buildReadinessWarningDetail", () => { + it("formats a runtime-only readiness warning", () => { + const detail = buildReadinessWarningDetail({ + runtime: { + ok: false, + url: "http://agent.internal:9090/health", + error: "timeout after 5000ms", + }, + gateway: { ok: true }, + }); + + expect(detail).toBe( + "runtime unavailable at http://agent.internal:9090/health (timeout after 5000ms)" + ); + }); + + it("formats a gateway-only readiness warning", () => { + const detail = buildReadinessWarningDetail({ + runtime: { ok: true }, + gateway: { + ok: false, + url: "http://host.docker.internal:18789/", + status: 502, + }, + }); + + expect(detail).toBe( + "gateway unavailable at http://host.docker.internal:18789/ (502)" + ); + }); + + it("formats combined runtime and gateway readiness warnings", () => { + const detail = buildReadinessWarningDetail({ + runtime: { + ok: false, + url: "http://agent.internal:9090/health", + error: "connection refused", + }, + gateway: { + ok: false, + url: "http://host.docker.internal:19123/", + error: "timeout after 5000ms", + }, + }); + + expect(detail).toBe( + "runtime unavailable at http://agent.internal:9090/health (connection refused); gateway unavailable at http://host.docker.internal:19123/ (timeout after 5000ms)" + ); + }); + + it("falls back to a generic message when readiness is malformed", () => { + expect(buildReadinessWarningDetail({})).toBe("readiness checks failed"); + }); +}); diff --git a/workers/provisioner/readinessWarning.js b/workers/provisioner/readinessWarning.js new file mode 100644 index 0000000..3776ae1 --- /dev/null +++ b/workers/provisioner/readinessWarning.js @@ -0,0 +1,19 @@ +function buildReadinessWarningDetail(readiness) { + const problems = []; + + if (readiness?.runtime && !readiness.runtime.ok) { + problems.push( + `runtime unavailable at ${readiness.runtime.url} (${readiness.runtime.error || readiness.runtime.status || 'unreachable'})` + ); + } + + if (readiness?.gateway && !readiness.gateway.ok) { + problems.push( + `gateway unavailable at ${readiness.gateway.url} (${readiness.gateway.error || readiness.gateway.status || 'unreachable'})` + ); + } + + return problems.join('; ') || 'readiness checks failed'; +} + +module.exports = { buildReadinessWarningDetail }; diff --git a/workers/provisioner/worker.js b/workers/provisioner/worker.js index e258a82..e6c3cf3 100644 --- a/workers/provisioner/worker.js +++ b/workers/provisioner/worker.js @@ -3,6 +3,7 @@ const IORedis = require('ioredis'); const { Pool } = require('pg'); const { agentRuntimeUrl } = require('../../agent-runtime/lib/contracts'); const { waitForAgentReadiness } = require('./healthChecks'); +const { buildReadinessWarningDetail } = require('./readinessWarning'); // ── Connections ────────────────────────────────────────── const connection = new IORedis({ @@ -383,14 +384,7 @@ const worker = new Worker('deployments', async (job) => { gatewayPort, }); if (!readiness.ok) { - const problems = []; - if (!readiness.runtime.ok) { - problems.push(`runtime unavailable at ${readiness.runtime.url} (${readiness.runtime.error || readiness.runtime.status || 'unreachable'})`); - } - if (!readiness.gateway.ok) { - problems.push(`gateway unavailable at ${readiness.gateway.url} (${readiness.gateway.error || readiness.gateway.status || 'unreachable'})`); - } - const detail = problems.join('; '); + const detail = buildReadinessWarningDetail(readiness); console.warn(`[provisioner] Readiness check failed for agent ${id}: ${detail}`); await db.query("UPDATE agents SET status = 'warning' WHERE id = $1", [id]); await db.query("UPDATE deployments SET status = 'warning' WHERE agent_id = $1", [id]);