diff --git a/scripts/e2e/npm-telegram-rtt-driver.mjs b/scripts/e2e/npm-telegram-rtt-driver.mjs index 09af3ad4a1f..bfad135d0c7 100755 --- a/scripts/e2e/npm-telegram-rtt-driver.mjs +++ b/scripts/e2e/npm-telegram-rtt-driver.mjs @@ -10,23 +10,16 @@ const outputDir = process.env.OPENCLAW_NPM_TELEGRAM_OUTPUT_DIR ?? ".artifacts/rt const telegramApiBaseUrl = ( process.env.OPENCLAW_QA_TELEGRAM_API_BASE_URL ?? "https://api.telegram.org" ).replace(/\/+$/u, ""); -const timeoutMs = Number(process.env.OPENCLAW_QA_TELEGRAM_SCENARIO_TIMEOUT_MS ?? "180000"); -const canaryTimeoutMs = Number( - process.env.OPENCLAW_QA_TELEGRAM_CANARY_TIMEOUT_MS ?? String(timeoutMs), -); -const warmSampleCount = Number(process.env.OPENCLAW_NPM_TELEGRAM_WARM_SAMPLES ?? "20"); -const sampleTimeoutMs = Number(process.env.OPENCLAW_NPM_TELEGRAM_SAMPLE_TIMEOUT_MS ?? "30000"); -const botApiTimeoutMs = readPositiveInt( - process.env.OPENCLAW_NPM_TELEGRAM_BOT_API_TIMEOUT_MS, - 30000, -); -const botApiBodyMaxBytes = readPositiveInt( - process.env.OPENCLAW_NPM_TELEGRAM_BOT_API_BODY_MAX_BYTES, +const timeoutMs = readPositiveIntEnv("OPENCLAW_QA_TELEGRAM_SCENARIO_TIMEOUT_MS", 180000); +const canaryTimeoutMs = readPositiveIntEnv("OPENCLAW_QA_TELEGRAM_CANARY_TIMEOUT_MS", timeoutMs); +const warmSampleCount = readPositiveIntEnv("OPENCLAW_NPM_TELEGRAM_WARM_SAMPLES", 20); +const sampleTimeoutMs = readPositiveIntEnv("OPENCLAW_NPM_TELEGRAM_SAMPLE_TIMEOUT_MS", 30000); +const botApiTimeoutMs = readPositiveIntEnv("OPENCLAW_NPM_TELEGRAM_BOT_API_TIMEOUT_MS", 30000); +const botApiBodyMaxBytes = readPositiveIntEnv( + "OPENCLAW_NPM_TELEGRAM_BOT_API_BODY_MAX_BYTES", 1024 * 1024, ); -const maxWarmFailures = Number( - process.env.OPENCLAW_NPM_TELEGRAM_MAX_FAILURES ?? String(warmSampleCount), -); +const maxWarmFailures = readPositiveIntEnv("OPENCLAW_NPM_TELEGRAM_MAX_FAILURES", warmSampleCount); const successMarker = process.env.OPENCLAW_NPM_TELEGRAM_SUCCESS_MARKER ?? "OPENCLAW_E2E_OK"; const scenarioIds = new Set( (process.env.OPENCLAW_NPM_TELEGRAM_SCENARIOS ?? "telegram-mentioned-message-reply") @@ -40,25 +33,16 @@ if (!groupId || !driverToken || !sutToken) { "missing Telegram env: OPENCLAW_QA_TELEGRAM_GROUP_ID, OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN, OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN", ); } -if (!Number.isInteger(warmSampleCount) || warmSampleCount < 1) { - throw new Error( - `OPENCLAW_NPM_TELEGRAM_WARM_SAMPLES must be a positive integer; got: ${warmSampleCount}`, - ); -} -if (!Number.isInteger(sampleTimeoutMs) || sampleTimeoutMs < 1) { - throw new Error( - `OPENCLAW_NPM_TELEGRAM_SAMPLE_TIMEOUT_MS must be a positive integer; got: ${sampleTimeoutMs}`, - ); -} -if (!Number.isInteger(maxWarmFailures) || maxWarmFailures < 1) { - throw new Error( - `OPENCLAW_NPM_TELEGRAM_MAX_FAILURES must be a positive integer; got: ${maxWarmFailures}`, - ); -} - -function readPositiveInt(raw, fallback) { - const parsed = Number.parseInt(String(raw || ""), 10); - return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback; +function readPositiveIntEnv(name, fallback) { + const text = String(process.env[name] ?? fallback).trim(); + if (!/^\d+$/u.test(text)) { + throw new Error(`invalid ${name}: ${text}`); + } + const value = Number(text); + if (!Number.isSafeInteger(value) || value <= 0) { + throw new Error(`invalid ${name}: ${text}`); + } + return value; } function taggedError(message, code) { diff --git a/test/scripts/npm-telegram-rtt-driver.test.ts b/test/scripts/npm-telegram-rtt-driver.test.ts index f173508c7a6..9d695bbdf3b 100644 --- a/test/scripts/npm-telegram-rtt-driver.test.ts +++ b/test/scripts/npm-telegram-rtt-driver.test.ts @@ -7,6 +7,20 @@ import { describe, expect, it } from "vitest"; const DRIVER_SCRIPT = "scripts/e2e/npm-telegram-rtt-driver.mjs"; +function runDriver(env: Record) { + return spawnSync(process.execPath, [DRIVER_SCRIPT], { + encoding: "utf8", + env: { + ...process.env, + OPENCLAW_QA_TELEGRAM_API_BASE_URL: "http://127.0.0.1:9", + OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN: "driver-token", + OPENCLAW_QA_TELEGRAM_GROUP_ID: "-100123", + OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN: "sut-token", + ...env, + }, + }); +} + async function waitForFile(filePath: string, timeoutMs = 3000): Promise { const startedAt = Date.now(); while (Date.now() - startedAt < timeoutMs) { @@ -84,6 +98,30 @@ function startOversizedJsonServer(portPath: string) { } describe("npm Telegram RTT driver", () => { + it("rejects loose numeric env values instead of parsing prefixes", () => { + for (const [name, value] of [ + ["OPENCLAW_QA_TELEGRAM_SCENARIO_TIMEOUT_MS", "180000ms"], + ["OPENCLAW_QA_TELEGRAM_CANARY_TIMEOUT_MS", "1e3"], + ["OPENCLAW_NPM_TELEGRAM_WARM_SAMPLES", "20samples"], + ["OPENCLAW_NPM_TELEGRAM_SAMPLE_TIMEOUT_MS", "30000ms"], + ["OPENCLAW_NPM_TELEGRAM_BOT_API_TIMEOUT_MS", "100ms"], + ["OPENCLAW_NPM_TELEGRAM_BOT_API_BODY_MAX_BYTES", "1mb"], + ["OPENCLAW_NPM_TELEGRAM_MAX_FAILURES", "2failures"], + ]) { + const result = runDriver({ [name]: value }); + + expect(result.status).not.toBe(0); + expect(result.stderr).toContain(`invalid ${name}: ${value}`); + } + }); + + it("rejects zero where positive numeric env values are required", () => { + const result = runDriver({ OPENCLAW_NPM_TELEGRAM_WARM_SAMPLES: "0" }); + + expect(result.status).not.toBe(0); + expect(result.stderr).toContain("invalid OPENCLAW_NPM_TELEGRAM_WARM_SAMPLES: 0"); + }); + it("bounds stalled Telegram Bot API response bodies", async () => { const root = mkdtempSync(path.join(tmpdir(), "openclaw-telegram-rtt-driver-")); const portPath = path.join(root, "port.txt");