mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-10-19 14:17:20 +02:00
fix: cancel token-gate waits and detect complete LFS prefixes
This commit is contained in:
1 parent
705f7c428a
commit
bfcea3e2b7
4 files changed
+113
-12
No files matched your search
+61
@@ -0,0 +1,61 @@
|
||||
const assert = require("node:assert/strict");
|
||||
const { Readable } = require("node:stream");
|
||||
const { setImmediate: nextTurn, setTimeout: delay } = require("node:timers/promises");
|
||||
const { setTimeout, clearTimeout } = require("node:timers");
|
||||
const redis = require("redis");
|
||||
let reads = 0;
|
||||
const resetAt = Date.now() + 10 * 60 * 1000;
|
||||
let readGate = async () => String(resetAt);
|
||||
const client = { isOpen: true, on() { return this; }, async connect() {},
|
||||
async get() { reads++; return readGate(); }, destroy() { this.isOpen = false; } };
|
||||
redis.createClient = () => client;
|
||||
require("ts-node/register/transpile-only");
|
||||
const github = require("../../src/core/GitHubUtils");
|
||||
const GitHubStream = require("../../src/core/source/GitHubStream").default;
|
||||
const got = require("got");
|
||||
|
||||
async function main() {
|
||||
const preAborted = new AbortController(); preAborted.abort();
|
||||
await assert.rejects(github.waitForTokenGate("token", preAborted.signal), { name: "AbortError" });
|
||||
assert.equal(reads, 0);
|
||||
|
||||
const firstController = new AbortController(), secondController = new AbortController();
|
||||
const first = github.waitForTokenGate("token", firstController.signal);
|
||||
let secondSettled = false;
|
||||
const second = github.waitForTokenGate("token", secondController.signal).finally(() => { secondSettled = true; });
|
||||
await nextTurn(); firstController.abort();
|
||||
await assert.rejects(first, { name: "AbortError" });
|
||||
await delay(20); assert.equal(secondSettled, false);
|
||||
secondController.abort(); await assert.rejects(second, { name: "AbortError" });
|
||||
|
||||
// A shared Redis lookup may remain pending. Cancelling one caller must
|
||||
// release that caller without closing the shared client.
|
||||
readGate = () => new Promise(() => {});
|
||||
const lookupController = new AbortController();
|
||||
const lookup = github.waitForTokenGate("token", lookupController.signal);
|
||||
await nextTurn(); lookupController.abort();
|
||||
await assert.rejects(lookup, { name: "AbortError" }); assert.equal(client.isOpen, true);
|
||||
|
||||
let entered;
|
||||
const gateEntered = new Promise(resolve => { entered = resolve; });
|
||||
readGate = async () => { entered(); return String(resetAt); };
|
||||
let metadataCalls = 0;
|
||||
github.octokit = () => ({ repos: { getContent: async () => { metadataCalls++; throw Error("unexpected metadata request"); } } });
|
||||
got.stream = () => new Readable({ read() {
|
||||
this.destroy(Object.assign(Error("private web 404"), { response: { statusCode: 404 } }));
|
||||
} });
|
||||
const source = new GitHubStream({ repoId: "gate-cancel", organization: "owner", repoName: "repo", commit: "pinned", getToken: () => "token" });
|
||||
const input = source.deferredRawDownload("token", "file.bin");
|
||||
const collected = (async () => { for await (const chunk of input) void chunk; })().catch(() => {});
|
||||
await gateEntered; await nextTurn();
|
||||
const closed = new Promise(resolve => input.once("close", resolve)); input.destroy();
|
||||
await closed; await collected;
|
||||
assert.equal(metadataCalls, 0); assert.equal(input.closed, true);
|
||||
}
|
||||
|
||||
const watchdog = setTimeout(() => { console.error("Cancellation did not release the gate wait"); process.exit(1); }, 5000);
|
||||
watchdog.unref();
|
||||
main().then(() => { clearTimeout(watchdog); console.log("gate cancellations released"); },
|
||||
error => { clearTimeout(watchdog); console.error(error); process.exit(1); });
|
||||
// Do not force a successful exit: any retained ten-minute timer must fail
|
||||
// the parent test's process timeout.
|
||||
Reference in new issue
Block a user