Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

73 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { DeadlineExceeded, LONG_DEADLINE_MS, READ_DEADLINE_MS, SLOW_READ_DEADLINE_MS, WRITE_DEADLINE_MS, deadlineFor, withDeadline } from "./deadline.ts";
5import { STUCK_NAVIGATION_MS } from "./stuck.ts";
6
7test("an answer in time is passed through", async () => {
8 assert.equal(await withDeadline("repos get_repo", 1000, async () => "ok"), "ok");
9});
10
11test("a call that never answers fails at its deadline, and its signal aborts", async () => {
12 let seen: AbortSignal | undefined;
13 const never = withDeadline("repos get_repo", 20, (signal) => {
14 seen = signal;
15 return new Promise<never>(() => {});
16 });
17 await assert.rejects(never, (error: unknown) => error instanceof DeadlineExceeded && /repos get_repo did not answer within 20ms/.test(error.message));
18 assert.equal(seen?.aborted, true);
19});
20
21test("a call that ignores its signal is still let go", async () => {
22 await assert.rejects(
23 withDeadline("chat sidebar", 10, () => new Promise<never>(() => {})),
24 DeadlineExceeded,
25 );
26});
27
28test("a failure in time is the call's own, not a deadline", async () => {
29 await assert.rejects(
30 withDeadline("work get_pull", 1000, async () => {
31 throw new Error("get_pull failed with status 500");
32 }),
33 /status 500/,
34 );
35});
36
37test("the caller's own signal aborts the call", async () => {
38 const outer = new AbortController();
39 let seen: AbortSignal | undefined;
40 const call = withDeadline(
41 "repos get_repo",
42 1000,
43 (signal) =>
44 new Promise<never>((_, reject) => {
45 seen = signal;
46 signal.addEventListener("abort", () => reject(signal.reason));
47 }),
48 outer.signal,
49 );
50 outer.abort(new Error("visitor left"));
51 await assert.rejects(call, /visitor left/);
52 assert.equal(seen?.aborted, true);
53});
54
55test("each call gets the time its work needs", () => {
56 assert.equal(deadlineFor("repos", "get_repo", false), READ_DEADLINE_MS);
57 assert.equal(deadlineFor("work", "merge_pull", true), WRITE_DEADLINE_MS);
58 assert.equal(deadlineFor("security", "overview", false), SLOW_READ_DEADLINE_MS);
59 assert.equal(deadlineFor("repos", "blame", false), SLOW_READ_DEADLINE_MS);
60 assert.equal(deadlineFor("integrations", "github_import", true), LONG_DEADLINE_MS);
61 assert.equal(deadlineFor("security", "rescan", true), LONG_DEADLINE_MS);
62});
63
64test("a long method of one service is not long in another", () => {
65 assert.equal(deadlineFor("security", "rescan", true), LONG_DEADLINE_MS);
66 assert.equal(deadlineFor("work", "rescan", true), WRITE_DEADLINE_MS);
67 assert.equal(deadlineFor("work", "draft", true), WRITE_DEADLINE_MS);
68 assert.equal(deadlineFor("identity", "overview", false), READ_DEADLINE_MS);
69});
70
71test("no read outlasts the browser's patience with a navigation", () => {
72 assert.ok(SLOW_READ_DEADLINE_MS < STUCK_NAVIGATION_MS && READ_DEADLINE_MS < STUCK_NAVIGATION_MS);
73});