From 46638e4b8690a4876ebc809b3a785558763eb766 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN Date: Wed, 19 Aug 2026 22:58:53 -0400 Subject: [PATCH] Test relay deletion by index, which had no test at all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DELETE /api/v1/relays/:idx guards the index twice and neither guard was exercised. An off-by-one here does not fail loudly — it removes the WRONG relay, so a user dropping one they distrust keeps it and loses one they wanted. Only asserting the exact resulting list can see that; a length check passes either way. Covers index 0 (a valid index, not a missing one), the last index versus one past it (the `>=` boundary), and a malformed index answering 400 rather than 404 — the request is wrong, not pointing at something absent. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Vtx94nXDmNgXEeThUZP4QN --- js/packages/cli/test/api.test.ts | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/js/packages/cli/test/api.test.ts b/js/packages/cli/test/api.test.ts index 2d2c06af..be94704c 100644 --- a/js/packages/cli/test/api.test.ts +++ b/js/packages/cli/test/api.test.ts @@ -986,6 +986,40 @@ describe("totp, config, relays, stats", () => { expect(reset.json.relays).not.toContain("wss://relay.example"); }); + it("deletes the relay at the index named, and no other", async () => { + // DELETE /relays/:idx had no test at all. An off-by-one here does not + // fail — it removes the WRONG relay, so a user dropping one they distrust + // keeps it and loses one they wanted. Asserting the exact resulting list + // is the only way to see that; a length check would pass either way. + const three = ["wss://a.example", "wss://b.example", "wss://c.example"]; + await call("PUT", "/api/v1/config/relays", { + password: PASSWORD, + body: { value: three }, + }); + + // Index 0 is a valid index, not a missing one. + const first = await call("DELETE", "/api/v1/relays/0"); + expect(first.status).toBe(200); + expect(first.json.relays).toEqual(["wss://b.example", "wss://c.example"]); + + // The LAST index is in range; one past it is not. `>=` versus `>` is + // exactly this boundary. + expect((await call("DELETE", "/api/v1/relays/2")).status).toBe(404); + const last = await call("DELETE", "/api/v1/relays/1"); + expect(last.status).toBe(200); + expect(last.json.relays).toEqual(["wss://b.example"]); + + // And an index that is not a non-negative integer is a 400, not a 404: + // the caller's request is malformed, not pointing at something absent. + for (const idx of ["-1", "1.5", "abc"]) { + const res = await call("DELETE", `/api/v1/relays/${idx}`); + expect(res.status).toBe(400); + expect(res.json.detail).toContain("non-negative integer"); + } + + await call("POST", "/api/v1/relays/reset"); + }); + it("reports profile statistics", async () => { const res = await call("GET", "/api/v1/stats"); expect(res.json.fingerprint).toBe(FINGERPRINT);