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 / repository-access.test.ts
repository-access.test.ts 6.2K
1import { describe, expect, it } from "vitest";2import { RepositoryAccess } from "../../src/repository-access.ts";34const latch = () => {5 let release!: () => void;6 const promise = new Promise<void>((resolve) => { release = resolve; });7 return { promise, release };8};9const refused = () => "refused";1011describe("Repository admission", () => {12 it("keeps streamed reads fenced until EOF and restores authority during pulls", async () => {13 const access = new RepositoryAccess();14 let pulls = 0;15 const response = await access.response("git", async () => new Response(new ReadableStream({16 pull(controller) {17 expect(access.owned).toBe(true);18 if (pulls++ === 0) controller.enqueue(new TextEncoder().encode("pack"));19 else controller.close();20 },21 }, { highWaterMark: 0 })), () => new Response("busy", { status: 429 }));22 expect(access.blocked).toBe(true);23 expect(access.sync("event", () => "unexpected", refused)).toBe("refused");24 expect(await response.text()).toBe("pack");25 expect(access.busy).toBe(false);26 });2728 it("releases streaming authority after client cancellation and stream errors", async () => {29 const access = new RepositoryAccess();30 let canceled = false;31 const response = await access.response("git", async () => new Response(new ReadableStream({32 cancel() { expect(access.owned).toBe(true); canceled = true; },33 }, { highWaterMark: 0 })), () => new Response("busy"));34 await response.body!.cancel();35 expect(canceled).toBe(true);36 expect(access.busy).toBe(false);37 const broken = await access.response("git", async () => new Response(new ReadableStream({38 pull() { throw new Error("read failure"); },39 }, { highWaterMark: 0 })), () => new Response("busy"));40 await expect(broken.text()).rejects.toThrow("read failure");41 expect(access.busy).toBe(false);42 });4344 it("keeps unrelated operations out across awaits and permits owned nested work", async () => {45 const access = new RepositoryAccess();46 const entered = latch();47 const finish = latch();48 const active = access.run("git", async () => {49 expect(access.owned).toBe(true);50 expect(access.sync("event", () => "nested", refused)).toBe("nested");51 entered.release();52 await finish.promise;53 expect(await access.run("control", () => "nested async", refused)).toBe("nested async");54 expect(access.kind).toBe("git");55 return "done";56 }, refused);57 await entered.promise;58 expect(access.blocked).toBe(true);59 expect(access.sync("event", () => "unexpected", refused)).toBe("refused");60 expect(await access.run("alarm", () => "unexpected", refused)).toBe("refused");61 finish.release();62 expect(await active).toBe("done");63 expect(access.busy).toBe(false);64 });6566 it("admits provider fuel receipts during Git but fences them during other work", async () => {67 const access = new RepositoryAccess();68 const entered = latch();69 const finish = latch();70 const active = access.run<string>("git", async () => {71 entered.release();72 await finish.promise;73 return "done";74 }, refused);75 await entered.promise;76 expect(await access.runFuel(() => "credited", refused)).toBe("credited");77 finish.release();78 await active;7980 const controlEntered = latch();81 const controlFinish = latch();82 const control = access.run<string>("control", async () => {83 controlEntered.release();84 await controlFinish.promise;85 return "done";86 }, refused);87 await controlEntered.promise;88 expect(await access.runFuel(() => "unexpected", refused)).toBe("refused");89 controlFinish.release();90 await control;91 await access.run<void>("control", async () => {92 expect(await access.runFuel(() => "nested", refused)).toBe("nested");93 }, () => undefined);94 expect(access.busy).toBe(false);95 });9697 it("keeps the Git lease alive until a concurrent fuel receipt finishes", async () => {98 const access = new RepositoryAccess();99 const gitEntered = latch();100 const gitFinish = latch();101 const fuelEntered = latch();102 const fuelFinish = latch();103 const git = access.run<string>("git", async () => {104 gitEntered.release();105 await gitFinish.promise;106 return "done";107 }, refused);108 await gitEntered.promise;109 const fuel = access.runFuel(async () => {110 fuelEntered.release();111 await fuelFinish.promise;112 return "credited";113 }, refused);114 await fuelEntered.promise;115 gitFinish.release();116 await git;117 expect(access.busy).toBe(true);118 expect(await access.run("teardown", () => "unexpected", refused)).toBe("refused");119 fuelFinish.release();120 expect(await fuel).toBe("credited");121 expect(access.busy).toBe(false);122 });123124 it("releases synchronous and asynchronous owners after failures", async () => {125 const access = new RepositoryAccess();126 expect(() => access.sync("event", () => { throw new Error("sync"); }, refused)).toThrow("sync");127 expect(access.busy).toBe(false);128 await expect(access.run("git", async () => { throw new Error("async"); }, refused)).rejects.toThrow("async");129 expect(access.busy).toBe(false);130 });131132 it("retains an entered child until it settles even when the parent returns", async () => {133 const access = new RepositoryAccess();134 const finish = latch();135 let child!: Promise<string>;136 await access.run("control", () => {137 child = access.run("event", async () => { await finish.promise; return "child"; }, refused);138 return "parent";139 }, refused);140 expect(access.blocked).toBe(true);141 finish.release();142 expect(await child).toBe("child");143 expect(access.busy).toBe(false);144 });145146 it("never lets a stale async context borrow a different active owner", async () => {147 const access = new RepositoryAccess();148 const resume = latch();149 let stale!: Promise<string>;150 await access.run("control", () => {151 stale = resume.promise.then(() => access.run("event", () => "unexpected", refused));152 return "original";153 }, refused);154 const finish = latch();155 const active = access.run("git", async () => { await finish.promise; return "current"; }, refused);156 resume.release();157 expect(await stale).toBe("refused");158 finish.release();159 await active;160 expect(access.busy).toBe(false);161 });162});