clone

nostr relays on demand at <name>.bind.ws: claim one with your key, pay in zaps past the free allowance

main
bindws / test / unit / network.test.ts
network.test.ts 4.0K
1import { describe, it, expect, vi } from "vitest";2const { manifest, validateManifest, cleanup, usageDelta } = await import(new URL("../../scripts/ops/network.mjs", import.meta.url).href);34describe("network cleanup", () => {5 it("rejects a recovery manifest that points outside its run before making a request", async () => {6 const m = manifest();7 m.nodes[0].state = "claimed";8 m.nodes[0].url = "https://someone-else.bind.ws/";9 const call = vi.fn();10 await expect(cleanup(m, vi.fn(), call)).rejects.toThrow("manifest target");11 expect(call).not.toHaveBeenCalled();12 });1314 it("recovers a lost claim reply and persists each deletion independently", async () => {15 const m = manifest();16 m.nodes[0].state = "claiming";17 m.nodes[1].state = "claimed";18 const saved: string[][] = [];19 const call = vi.fn(async (n: { owner: string; slug: string }, _key: unknown, method: string, slug?: string) => {20 if (method === "getpolicy") return { owner: m.actors[n.owner].pubkey };21 expect(method).toBe("deleterelay");22 expect(slug).toBe(n.slug);23 return { deleted: true, name: slug };24 });25 const results = await cleanup(m, async () => saved.push(m.nodes.map((n: { state: string }) => n.state)), call);26 expect(results).toHaveLength(2);27 expect(results.every((r: { deleted: boolean }) => r.deleted)).toBe(true);28 expect(saved).toHaveLength(2);29 expect(saved[0][0]).toBe("claiming");30 expect(saved[1][0]).toBe("deleted");31 expect(call).toHaveBeenCalledTimes(4);32 });3334 it("continues after a failed deletion and never deletes a mismatched owner", async () => {35 const m = manifest();36 m.nodes[0].state = "claimed";37 m.nodes[1].state = "claimed";38 const call = vi.fn(async (n: { role: string; owner: string; slug: string }, _key: unknown, method: string) => {39 if (method === "getpolicy") return { owner: n.role === "peer-b" ? "ff".repeat(32) : m.actors[n.owner].pubkey };40 return { deleted: true, name: n.slug };41 });42 const r = await cleanup(m, vi.fn(), call);43 expect(r[0].deleted).toBe(false);44 expect(r[1].deleted).toBe(true);45 expect(call.mock.calls.filter((c) => c[2] === "deleterelay")).toHaveLength(1);46 expect(m.nodes[1].state).toBe("claimed");47 });4849 it("treats only the authenticated unclaimed response as an already completed deletion", async () => {50 const m = manifest();51 m.nodes[0].state = "claiming";52 const call = vi.fn(async () => { throw Object.assign(new Error("restricted: this relay is unclaimed"), { status: 403 }); });53 expect((await cleanup(m, vi.fn(), call))[0].deleted).toBe(true);54 expect(call).toHaveBeenCalledTimes(1);55 m.nodes[0].state = "claiming";56 call.mockImplementation(async () => { throw Object.assign(new Error("restricted: not the relay owner"), { status: 403 }); });57 expect((await cleanup(m, vi.fn(), call))[0].deleted).toBe(false);58 expect(m.nodes[0].state).toBe("claiming");59 });6061 it("keeps malformed successful ownership responses pending for recovery", async () => {62 for (const policy of [null, undefined, false, {}, { owner: "" }]) {63 const m = manifest();64 m.nodes[0].state = "claimed";65 const call = vi.fn(async () => policy);66 const results = await cleanup(m, vi.fn(), call);67 expect(results[0].deleted).toBe(false);68 expect(m.nodes[0].state).toBe("claimed");69 expect(call).toHaveBeenCalledTimes(1);70 }71 });7273 it("rejects duplicate nodes and a secret that does not match the recorded owner", () => {74 const m = manifest();75 m.nodes[1] = { ...m.nodes[0] };76 expect(() => validateManifest(m)).toThrow("manifest target");77 const second = manifest();78 second.actors.alice.pubkey = second.actors.bob.pubkey;79 expect(() => validateManifest(second)).toThrow("manifest owner");80 });81});8283it("reports counter deltas without confusing flags or absent samples with zero usage", () => {84 expect(usageDelta({ activeMs: 2, outOfFuel: false }, { activeMs: 9, outOfFuel: true, rowsRead: 10 })).toEqual({ activeMs: 7 });85});