๐Ÿ“ฆ EqualifyEverything / equalify-iris

๐Ÿ“„ stats-route.test.ts ยท 178 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178import { test } from "node:test";
import assert from "node:assert/strict";
import express from "express";
import type { AddressInfo } from "node:net";
import type { PublicQuality, Store } from "../src/store/db.ts";
import { statsRouter, DEFAULT_TTL_MS } from "../src/routes/stats.ts";

// The store side of `GET /v1/stats` is covered in test/stats.test.ts, and e2e step
// 7b covers one real uncached response with no token. This covers the part neither
// of them can see: the route's cache.
//
// That cache is the stated reason it is acceptable for an unauthenticated caller to
// trigger a full scan of the sessions table, which makes it a load-bearing claim
// rather than an optimization. Without these assertions `>= ttlMs` could become
// `<= ttlMs` (recompute every request โ€” the scan-per-request the cache exists to
// prevent), or the `Cache-Control` header could be dropped, and the unit tests, the
// typecheck and the e2e would all still pass.

// A store that records how many times it was actually consulted, and can change its
// answer between reads. Only `publicStats` and `publicQuality` are reachable from this
// router, so nothing else needs to exist. `calls` counts requests that reached the
// store at all, which is the same for both methods โ€” the route recomputes the whole
// body or none of it.
function fakeStore(
  initial: { pages: number; documents: number; since: string | null },
  quality: PublicQuality | null = null,
) {
  const state = { calls: 0, value: initial, quality };
  const store = {
    publicStats() {
      state.calls++;
      return state.value;
    },
    publicQuality() {
      return state.quality;
    },
  } as unknown as Store;
  return { store, state };
}

async function serve(router: express.Router): Promise<{
  get: (query?: string, init?: RequestInit) => Promise<Response>;
  close: () => void;
}> {
  const app = express();
  app.use("/v1/stats", router);
  const server = app.listen(0);
  await new Promise((r) => server.once("listening", r));
  const base = `http://127.0.0.1:${(server.address() as AddressInfo).port}/v1/stats`;
  return { get: (query = "", init) => fetch(base + query, init), close: () => server.close() };
}

const STATS = { pages: 40, documents: 3, since: "2026-01-01T00:00:00.000Z" };
const QUALITY: PublicQuality = { window_days: 30, documents: 212, clean_rate: 0.93, mean_rounds: 1.8 };

test("the tally is served from cache within the TTL, and recomputed after it", async () => {
  const { store, state } = fakeStore(STATS, QUALITY);
  // 200ms rather than the production minute: the branch is the same, and a test
  // that has to wait 60s to assert expiry is a test nobody runs. Long enough that
  // two localhost round-trips inside the window are not a coin flip.
  const srv = await serve(statsRouter(store, { ttlMs: 200 }));
  try {
    const first = await srv.get();
    assert.equal(first.status, 200);
    assert.deepEqual(await first.json(), {
      pages_processed: 40,
      documents_processed: 3,
      since: "2026-01-01T00:00:00.000Z",
      quality: { window_days: 30, documents: 212, clean_rate: 0.93, mean_rounds: 1.8 },
    });
    assert.equal(state.calls, 1, "the first request must actually query the store");

    // Change what the store would say, so a second query is detectable in the
    // body and not only in the counter.
    state.value = { pages: 999, documents: 99, since: "2026-01-01T00:00:00.000Z" };
    state.quality = { ...QUALITY, clean_rate: 0.5 };
    const second = await srv.get();
    assert.equal(state.calls, 1, "a request inside the TTL re-queried the store");
    assert.equal((await second.json()).pages_processed, 40, "the cached body was not served");

    await new Promise((r) => setTimeout(r, 250));
    const third = await srv.get();
    assert.equal(state.calls, 2, "a request after the TTL did not recompute");
    const body = await third.json();
    assert.equal(body.pages_processed, 999, "the recomputed body was not served");
    // The quality half expires with the rest of the body. It comes from a second store
    // query, so a cache that kept only the tally would leave a rate from an hour ago
    // sitting next to a fresh page count and no test would notice.
    assert.equal(body.quality.clean_rate, 0.5, "the quality half was not recomputed");
  } finally {
    srv.close();
  }
});

test("the response carries Cache-Control matching the TTL", async () => {
  const { store } = fakeStore(STATS);
  const srv = await serve(statsRouter(store));
  try {
    const res = await srv.get();
    // Shared caches are asked for the same lifetime the in-process cache uses, so
    // a CDN in front of this deployment does not serve a tally staler than the
    // origin would.
    assert.equal(res.headers.get("cache-control"), `public, max-age=${DEFAULT_TTL_MS / 1000}`);
    assert.match(res.headers.get("content-type") ?? "", /application\/json/);
  } finally {
    srv.close();
  }
});

test("an empty deployment answers 200 with zeros rather than an error", async () => {
  // The demo page hides its line on a zero, but that is the client's decision to
  // make โ€” the endpoint has to give it a well-formed number to decide from, and a
  // fresh deployment is the first thing anyone runs.
  const { store } = fakeStore({ pages: 0, documents: 0, since: null });
  const srv = await serve(statsRouter(store));
  try {
    const res = await srv.get();
    assert.equal(res.status, 200);
    assert.deepEqual(await res.json(), {
      pages_processed: 0,
      documents_processed: 0,
      since: null,
      // Explicitly null rather than absent: the page has to be able to tell "too few
      // documents to say" from "an old deployment serving a body without the field",
      // and null is the answer the store gives below its floor.
      quality: null,
    });
  } finally {
    srv.close();
  }
});

test("the route publishes the quality fields it names, and nothing else the store adds", async () => {
  // The floor that keeps a rate over a handful of identifiable people's uploads off
  // the front page lives in `Store.publicQuality`, and this route must not be able to
  // route around it โ€” hence naming the four fields instead of spreading the return.
  // A store that hands back extra fields stands in for a future `PublicQuality` that
  // grows one; the endpoint is unauthenticated, so inheriting it silently is the
  // failure being prevented.
  const { store } = fakeStore(STATS, {
    ...QUALITY,
    worst_rule: "heading-order",
    session_id: "ses_secret",
  } as unknown as PublicQuality);
  const srv = await serve(statsRouter(store));
  try {
    const body = await (await srv.get()).json();
    assert.deepEqual(Object.keys(body.quality).sort(), [
      "clean_rate",
      "documents",
      "mean_rounds",
      "window_days",
    ]);
    assert.ok(!JSON.stringify(body).includes("ses_secret"), "a store field reached the response");
  } finally {
    srv.close();
  }
});

test("no request-derived value reaches the response", async () => {
  // The endpoint is unauthenticated and takes no parameters. Asserting it ignores
  // query strings and headers keeps a future "?since=" or per-caller variation
  // from quietly turning a cached public aggregate into a per-request answer โ€”
  // which would also make the single shared cache entry wrong for everyone.
  const { store, state } = fakeStore(STATS);
  const srv = await serve(statsRouter(store));
  try {
    const plain = await (await srv.get()).json();
    const withJunk = await srv.get("?limit=1&user=99&session_id=ses_x", {
      headers: { "x-forwarded-for": "1.2.3.4", authorization: "Bearer nope" },
    });
    assert.deepEqual(await withJunk.json(), plain, "a query string or header changed the response");
    assert.equal(state.calls, 1, "the query string bypassed the shared cache entry");
  } finally {
    srv.close();
  }
});