
























@@ -257,6 +257,108 @@ describe("RTT harness", () => {
257257}
258258});
259259260+it("does not start another credential acquire after retry delay exhausts the deadline", async () => {
261+let requests = 0;
262+const server = createServer((_request, response) => {
263+requests += 1;
264+response.writeHead(503, { "content-type": "application/json" });
265+response.end(
266+JSON.stringify({
267+status: "error",
268+code: "POOL_EXHAUSTED",
269+message: "credential pool exhausted",
270+retryAfterMs: 1_000,
271+}),
272+);
273+});
274+const { port } = await listenOnLoopback(server);
275+const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-rtt-credentials-retry-"));
276+tempDirs.push(tempDir);
277+const startedAt = Date.now();
278+279+try {
280+await execFileAsync(
281+process.execPath,
282+[
283+CREDENTIAL_SCRIPT_PATH,
284+"acquire",
285+"--lease-file",
286+path.join(tempDir, "lease.json"),
287+"--credential-env-file",
288+path.join(tempDir, "credentials.env"),
289+],
290+{
291+env: {
292+ ...credentialBrokerEnv(port),
293+OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "75",
294+OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS: "250",
295+},
296+maxBuffer: 128 * 1024,
297+},
298+);
299+throw new Error("Expected credential acquire to fail.");
300+} catch (error) {
301+const execError = error as Error & { stderr?: string };
302+expect(execError.stderr).toContain("credential broker acquire timed out after 75ms");
303+expect(Date.now() - startedAt).toBeLessThan(500);
304+expect(requests).toBe(1);
305+} finally {
306+await closeServer(server);
307+}
308+});
309+310+it("caps credential acquire HTTP retries to the remaining acquire deadline", async () => {
311+let requests = 0;
312+const server = createServer((_request, response) => {
313+requests += 1;
314+if (requests === 1) {
315+response.writeHead(503, { "content-type": "application/json" });
316+response.end(
317+JSON.stringify({
318+status: "error",
319+code: "POOL_EXHAUSTED",
320+message: "credential pool exhausted",
321+retryAfterMs: 1,
322+}),
323+);
324+}
325+});
326+const { port } = await listenOnLoopback(server);
327+const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-rtt-credentials-cap-"));
328+tempDirs.push(tempDir);
329+const startedAt = Date.now();
330+331+try {
332+await execFileAsync(
333+process.execPath,
334+[
335+CREDENTIAL_SCRIPT_PATH,
336+"acquire",
337+"--lease-file",
338+path.join(tempDir, "lease.json"),
339+"--credential-env-file",
340+path.join(tempDir, "credentials.env"),
341+],
342+{
343+env: {
344+ ...credentialBrokerEnv(port),
345+OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "100",
346+OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS: "900",
347+},
348+maxBuffer: 128 * 1024,
349+},
350+);
351+throw new Error("Expected credential acquire to fail.");
352+} catch (error) {
353+const execError = error as Error & { stderr?: string };
354+expect(execError.stderr).toContain("credential broker acquire timed out after");
355+expect(Date.now() - startedAt).toBeLessThan(500);
356+expect(requests).toBe(2);
357+} finally {
358+await closeServer(server);
359+}
360+});
361+260362it("preserves empty broker responses for successful lease release", async () => {
261363const server = createServer((_request, response) => {
262364response.writeHead(204);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。