test: make codex unavailable checks deterministic

This commit is contained in:
Codex
2026-05-25 03:12:19 +08:00
parent 326285c3dd
commit fdafa67ff1
+22 -13
View File
@@ -58,6 +58,14 @@ function assertCodexStdioFeasibilityBlocker(value, label = "codex stdio blocker"
assert.equal(CODEX_STDIO_FEASIBILITY_BLOCKERS.has(value), true, `${label}: ${value}`); assert.equal(CODEX_STDIO_FEASIBILITY_BLOCKERS.has(value), true, `${label}: ${value}`);
} }
function missingCodexCommandEnv(overrides = {}) {
return {
PATH: "",
HWLAB_CODE_AGENT_CODEX_COMMAND: path.join(os.tmpdir(), `hwlab-${process.pid}-missing-codex`),
...overrides
};
}
test("cloud api exposes /health, /health/live, and /live probes", async () => { test("cloud api exposes /health, /health/live, and /live probes", async () => {
const originalUrl = process.env.HWLAB_CLOUD_DB_URL; const originalUrl = process.env.HWLAB_CLOUD_DB_URL;
const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE; const originalSslMode = process.env.HWLAB_CLOUD_DB_SSL_MODE;
@@ -1701,12 +1709,12 @@ test("cloud api /v1 describes Code Agent provider blocker without leaking secret
test("cloud api /v1 describes Code Agent egress blocker without leaking API key", async () => { test("cloud api /v1 describes Code Agent egress blocker without leaking API key", async () => {
const server = createCloudApiServer({ const server = createCloudApiServer({
env: { env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material", OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "codex-stdio", HWLAB_CODE_AGENT_PROVIDER: "codex-stdio",
HWLAB_CODE_AGENT_MODEL: "gpt-test", HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "https://api.openai.com/v1/responses" HWLAB_CODE_AGENT_OPENAI_BASE_URL: "https://api.openai.com/v1/responses"
} })
}); });
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
@@ -1907,6 +1915,7 @@ test("cloud api health blocks full Code Agent readiness when Codex stdio command
test("cloud api /v1/agent/chat refuses provider stub when Codex stdio is unavailable", async () => { test("cloud api /v1/agent/chat refuses provider stub when Codex stdio is unavailable", async () => {
let providerCalled = false; let providerCalled = false;
const server = createCloudApiServer({ const server = createCloudApiServer({
env: missingCodexCommandEnv(),
callCodeAgentProvider: async () => { callCodeAgentProvider: async () => {
providerCalled = true; providerCalled = true;
throw new Error("provider stub must not be used"); throw new Error("provider stub must not be used");
@@ -3621,10 +3630,9 @@ test("cloud api /v1/agent/chat does not use read-only conversation facts as fall
test("cloud api /v1/agent/chat blocks forbidden file paths without leaking values", async () => { test("cloud api /v1/agent/chat blocks forbidden file paths without leaking values", async () => {
const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-file-block-")); const workspace = await mkdtemp(path.join(os.tmpdir(), "hwlab-agent-file-block-"));
const server = createCloudApiServer({ const server = createCloudApiServer({
env: { env: missingCodexCommandEnv({
PATH: process.env.PATH,
HWLAB_CODE_AGENT_WORKSPACE: workspace HWLAB_CODE_AGENT_WORKSPACE: workspace
} })
}); });
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
@@ -4084,13 +4092,13 @@ test("cloud api /v1/agent/chat ignores OpenAI fallback and blocks when Codex std
const providerPort = providerServer.address().port; const providerPort = providerServer.address().port;
const server = createCloudApiServer({ const server = createCloudApiServer({
env: { env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material", OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai", HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true", HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test", HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses` HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses`
} })
}); });
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
@@ -4185,13 +4193,13 @@ test("cloud api /v1/agent/chat does not call delayed provider fallback beyond le
test("cloud api /v1/agent/chat skips delayed provider fallback when Codex stdio is unavailable", async () => { test("cloud api /v1/agent/chat skips delayed provider fallback when Codex stdio is unavailable", async () => {
let providerCalled = false; let providerCalled = false;
const server = createCloudApiServer({ const server = createCloudApiServer({
env: { env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material", OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai", HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true", HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test", HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1/provider-fixture" HWLAB_CODE_AGENT_OPENAI_BASE_URL: "http://127.0.0.1/provider-fixture"
}, }),
callCodeAgentProvider: async ({ providerPlan }) => { callCodeAgentProvider: async ({ providerPlan }) => {
providerCalled = true; providerCalled = true;
await delay(4600); await delay(4600);
@@ -4250,13 +4258,13 @@ test("cloud api /v1/agent/chat reports Codex stdio blocker instead of provider t
const providerPort = providerServer.address().port; const providerPort = providerServer.address().port;
const server = createCloudApiServer({ const server = createCloudApiServer({
env: { env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material", OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai", HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true", HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test", HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses` HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses`
}, }),
codeAgentTimeoutMs: 50 codeAgentTimeoutMs: 50
}); });
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
@@ -4311,13 +4319,13 @@ test("cloud api /v1/agent/chat does not call OpenAI provider 502/503 fallback",
const providerPort = providerServer.address().port; const providerPort = providerServer.address().port;
const server = createCloudApiServer({ const server = createCloudApiServer({
env: { env: missingCodexCommandEnv({
OPENAI_API_KEY: "test-openai-key-material", OPENAI_API_KEY: "test-openai-key-material",
HWLAB_CODE_AGENT_PROVIDER: "openai", HWLAB_CODE_AGENT_PROVIDER: "openai",
HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true", HWLAB_CODE_AGENT_ALLOW_TEXT_FALLBACK: "true",
HWLAB_CODE_AGENT_MODEL: "gpt-test", HWLAB_CODE_AGENT_MODEL: "gpt-test",
HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses` HWLAB_CODE_AGENT_OPENAI_BASE_URL: `http://127.0.0.1:${providerPort}/v1/responses`
} })
}); });
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
@@ -4421,6 +4429,7 @@ function delay(ms) {
test("cloud api /v1/agent/chat does not call empty provider text fallback", async () => { test("cloud api /v1/agent/chat does not call empty provider text fallback", async () => {
let providerCalled = false; let providerCalled = false;
const server = createCloudApiServer({ const server = createCloudApiServer({
env: missingCodexCommandEnv(),
callCodeAgentProvider: async () => { callCodeAgentProvider: async () => {
providerCalled = true; providerCalled = true;
throw new Error("empty provider fallback must not be used"); throw new Error("empty provider fallback must not be used");