Files
computer-playbook/roles/web-app-hermes/files/playwright/test-administrator-persona.js
kevinveenbirkenbachandClaude Opus 5 303c47fe2a fix(test-e2e-playwright): retry transient onion transport errors for every API verb, not only GET
0a52433dcb gave the standalone request fixture a Tor-resilient GET,
because the bundled socks client caps the CONNECT at 30s and a cold
onion circuit fails a request regardless of its timeout. POSTs and calls
made through context.request still went out once, and a circuit Tor
rejected ("Socks5 proxy rejected connection") was not recognised as
transient at all.

apiFetchOnion now takes the verb from opts.method and calls
request.fetch, so it serves both APIRequestContexts; apiGetOnion becomes
its GET shorthand. The rejection joins the transient patterns. Retries
stay onion-only and transport-only: clearnet keeps a single attempt and
HTTP or other errors re-throw at once.

The Mattermost LiteLLM spec routes its login, users/me, users/username
and channels/direct calls through it. The /posts call that sends the
prompt stays a single attempt, because a replayed post would message the
bot twice. The Hermes administrator spec reads /v1/models through
apiGetOnion.

env.test.js pins a POST surviving a rejected circuit, the single
clearnet attempt, no retry of a non-transport error over Tor, and the
GET shorthand.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 12:05:02 +02:00

22 lines
934 B
JavaScript

const { test, expect } = require("@playwright/test");
const { resolveTimeout } = require("./timeouts");
const { apiGetOnion } = require("./personas");
exports.register = function (shared) {
test("administrator: the API server key unlocks the OpenAI-compatible model listing", async ({ request }) => {
test.skip(!shared.env.apiServerKey, "no Hermes API server key provisioned");
const models = await apiGetOnion(request, `${shared.env.baseUrl}/v1/models`, {
headers: { Authorization: `Bearer ${shared.env.apiServerKey}` },
timeout: resolveTimeout(30_000),
});
expect(models.status(), "Expected an authenticated /v1/models listing").toBe(200);
const body = await models.json();
expect(body.object, "Expected an OpenAI-style list envelope").toBe("list");
expect(
Array.isArray(body.data) && body.data.length,
"Expected at least one agent model entry",
).toBeTruthy();
});
};