Files
OmniRoute/tests/unit/runtime-timeouts.test.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

160 lines
5.7 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
const runtimeTimeouts = await import("../../src/shared/utils/runtimeTimeouts.ts");
test("upstream timeout config derives hidden fetch timeouts from FETCH_TIMEOUT_MS", () => {
const config = runtimeTimeouts.getUpstreamTimeoutConfig({
FETCH_TIMEOUT_MS: "600000",
STREAM_IDLE_TIMEOUT_MS: "600000",
});
assert.deepEqual(config, {
fetchTimeoutMs: 600000,
streamIdleTimeoutMs: 600000,
sseHeartbeatIntervalMs: 15000,
streamReadinessTimeoutMs: 80000,
streamReadinessMaxTimeoutMs: 180000,
streamDisconnectGracePeriodMs: 10000,
fetchHeadersTimeoutMs: 600000,
fetchBodyTimeoutMs: 600000,
fetchConnectTimeoutMs: 30000,
fetchKeepAliveTimeoutMs: 4000,
});
});
test("REQUEST_TIMEOUT_MS becomes the common timeout baseline when specific overrides are unset", () => {
const upstreamConfig = runtimeTimeouts.getUpstreamTimeoutConfig({
REQUEST_TIMEOUT_MS: "600000",
});
const apiBridgeConfig = runtimeTimeouts.getApiBridgeTimeoutConfig({
REQUEST_TIMEOUT_MS: "600000",
});
assert.equal(upstreamConfig.fetchTimeoutMs, 600000);
assert.equal(upstreamConfig.streamIdleTimeoutMs, 600000);
assert.equal(upstreamConfig.streamReadinessTimeoutMs, 600000);
assert.equal(upstreamConfig.streamReadinessMaxTimeoutMs, 180000);
assert.equal(upstreamConfig.fetchHeadersTimeoutMs, 600000);
assert.equal(upstreamConfig.fetchBodyTimeoutMs, 600000);
assert.equal(apiBridgeConfig.proxyTimeoutMs, 600000);
assert.equal(apiBridgeConfig.serverRequestTimeoutMs, 600000);
});
test("upstream timeout config honors explicit overrides and falls back on invalid values", () => {
const config = runtimeTimeouts.getUpstreamTimeoutConfig({
REQUEST_TIMEOUT_MS: "550000",
FETCH_TIMEOUT_MS: "600000",
STREAM_IDLE_TIMEOUT_MS: "600000",
STREAM_READINESS_TIMEOUT_MS: "90000",
STREAM_READINESS_MAX_TIMEOUT_MS: "240000",
FETCH_HEADERS_TIMEOUT_MS: "610000",
FETCH_BODY_TIMEOUT_MS: "0",
FETCH_CONNECT_TIMEOUT_MS: "45000",
FETCH_KEEPALIVE_TIMEOUT_MS: "-1",
});
assert.equal(config.streamReadinessTimeoutMs, 90000);
assert.equal(config.streamReadinessMaxTimeoutMs, 240000);
assert.equal(config.fetchHeadersTimeoutMs, 610000);
assert.equal(config.fetchBodyTimeoutMs, 0);
assert.equal(config.fetchConnectTimeoutMs, 45000);
assert.equal(config.fetchKeepAliveTimeoutMs, 4000);
});
test("TLS client timeout defaults to FETCH_TIMEOUT_MS and can be overridden", () => {
const defaultConfig = runtimeTimeouts.getTlsClientTimeoutConfig({
FETCH_TIMEOUT_MS: "600000",
});
const overriddenConfig = runtimeTimeouts.getTlsClientTimeoutConfig({
FETCH_TIMEOUT_MS: "600000",
TLS_CLIENT_TIMEOUT_MS: "720000",
});
assert.equal(defaultConfig.timeoutMs, 600000);
assert.equal(overriddenConfig.timeoutMs, 720000);
});
test("stainless timeout derives from fetch timeout and rounds up to whole seconds", () => {
assert.equal(
runtimeTimeouts.getStainlessTimeoutSeconds({
REQUEST_TIMEOUT_MS: "1200000",
}),
1200
);
assert.equal(
runtimeTimeouts.getStainlessTimeoutSeconds({
FETCH_TIMEOUT_MS: "600001",
}),
601
);
});
test("API bridge timeouts align request timeout with long proxy timeout by default", () => {
const config = runtimeTimeouts.getApiBridgeTimeoutConfig({
API_BRIDGE_PROXY_TIMEOUT_MS: "600000",
});
assert.deepEqual(config, {
proxyTimeoutMs: 600000,
serverRequestTimeoutMs: 600000,
serverHeadersTimeoutMs: 60000,
serverKeepAliveTimeoutMs: 5000,
serverSocketTimeoutMs: 0,
});
});
test("idle timeout default stays at 10min (600_000) for slow-thinking model safety", () => {
// NOTE: PR #2233 originally lowered this to 300_000, but the reviewer asked to keep
// the legacy default (slow thinking models, long Anthropic extended-thinking runs).
// The heartbeat-shape change is preserved; only the idle-timeout default revert remains.
assert.equal(runtimeTimeouts.DEFAULT_STREAM_IDLE_TIMEOUT_MS, 600_000);
assert.equal(runtimeTimeouts.getUpstreamTimeoutConfig({}).streamIdleTimeoutMs, 600_000);
});
test("readiness adaptive cap defaults to 180s and is env-overridable", () => {
assert.equal(runtimeTimeouts.DEFAULT_STREAM_READINESS_MAX_TIMEOUT_MS, 180_000);
assert.equal(runtimeTimeouts.getUpstreamTimeoutConfig({}).streamReadinessMaxTimeoutMs, 180_000);
assert.equal(
runtimeTimeouts.getUpstreamTimeoutConfig({ STREAM_READINESS_MAX_TIMEOUT_MS: "300000" })
.streamReadinessMaxTimeoutMs,
300_000
);
assert.equal(
runtimeTimeouts.getUpstreamTimeoutConfig({ STREAM_READINESS_MAX_TIMEOUT_MS: "bad" })
.streamReadinessMaxTimeoutMs,
180_000
);
});
test("heartbeat interval default = 15s, env-overridable", () => {
assert.equal(runtimeTimeouts.DEFAULT_SSE_HEARTBEAT_INTERVAL_MS, 15_000);
assert.equal(runtimeTimeouts.getUpstreamTimeoutConfig({}).sseHeartbeatIntervalMs, 15_000);
assert.equal(
runtimeTimeouts.getUpstreamTimeoutConfig({ SSE_HEARTBEAT_INTERVAL_MS: "8000" })
.sseHeartbeatIntervalMs,
8_000
);
assert.equal(
runtimeTimeouts.getUpstreamTimeoutConfig({ SSE_HEARTBEAT_INTERVAL_MS: "0" })
.sseHeartbeatIntervalMs,
0
);
});
test("API bridge proxy timeout defaults to the long upstream request window", () => {
const config = runtimeTimeouts.getApiBridgeTimeoutConfig({});
assert.equal(config.proxyTimeoutMs, 600000);
assert.equal(config.serverRequestTimeoutMs, 600000);
});
test("REQUEST_TIMEOUT_MS=0 disables API bridge proxy and request timeouts consistently", () => {
const config = runtimeTimeouts.getApiBridgeTimeoutConfig({
REQUEST_TIMEOUT_MS: "0",
});
assert.equal(config.proxyTimeoutMs, 0);
assert.equal(config.serverRequestTimeoutMs, 0);
});