|
| 1 | +// altimate_change — regression test for the server-side wiring that produces `client_connected`. |
| 2 | +// |
| 3 | +// The telemetry unit tests (test/altimate/telemetry/first-run-health.test.ts) prove the |
| 4 | +// `Telemetry.clientConnected()` latch, but nothing exercised the `.use` middleware in |
| 5 | +// `Server.createApp` that actually calls it. Without this test, deleting the middleware, changing |
| 6 | +// the `/event` / `/global/event` path literals, dropping the `GET` guard, or moving the hook ahead |
| 7 | +// of basicAuth would all leave the suite green while silently killing the IDE-funnel signal. |
| 8 | +// |
| 9 | +// The middleware fires `void import("../altimate/telemetry").then((m) => m.Telemetry.clientConnected())` |
| 10 | +// after next() is set up, so the call lands on a later microtask; each case waits a tick before |
| 11 | +// asserting. We spy on `Telemetry.clientConnected` itself (not `track`) so the assertion is purely |
| 12 | +// about the middleware deciding to call it — the once-per-process latch lives inside that function |
| 13 | +// and is covered elsewhere. |
| 14 | +// |
| 15 | +// These cases catch deleting the middleware, changing the `/event` / `/global/event` path literals, |
| 16 | +// and dropping the `GET` guard. The remaining regression the reviewer named — moving the hook above |
| 17 | +// basicAuth so unauthenticated probes count — is not exercised here: auth is enforced by a separate |
| 18 | +// `basicAuth` middleware gated on `Flag.OPENCODE_SERVER_PASSWORD`, which is a module-level const |
| 19 | +// frozen at load (flag.ts), and CI runs the package in one Bun process, so a password set at test |
| 20 | +// time can't drive basicAuth to 401. The ordering is enforced structurally: this hook is registered |
| 21 | +// immediately after the basicAuth `.use` in `Server.createApp`. |
| 22 | +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test" |
| 23 | +import { Server } from "../../src/server/server" |
| 24 | +import { Telemetry } from "../../src/altimate/telemetry" |
| 25 | +import { resetDatabase } from "./db" |
| 26 | +import { disposeAllInstances } from "../fixture/fixture" |
| 27 | + |
| 28 | +const tick = () => new Promise((r) => setTimeout(r, 15)) |
| 29 | + |
| 30 | +async function cancelBody(response: Response) { |
| 31 | + await response.body?.cancel().catch(() => {}) |
| 32 | +} |
| 33 | + |
| 34 | +let spy: ReturnType<typeof spyOn<typeof Telemetry, "clientConnected">> |
| 35 | + |
| 36 | +beforeEach(() => { |
| 37 | + spy = spyOn(Telemetry, "clientConnected").mockImplementation(() => {}) |
| 38 | +}) |
| 39 | + |
| 40 | +afterEach(async () => { |
| 41 | + spy.mockRestore() |
| 42 | + await disposeAllInstances() |
| 43 | + await resetDatabase() |
| 44 | +}) |
| 45 | + |
| 46 | +describe("client_connected server wiring", () => { |
| 47 | + test("GET /event invokes Telemetry.clientConnected", async () => { |
| 48 | + const response = await Server.Default().request("/event") |
| 49 | + await cancelBody(response) |
| 50 | + await tick() |
| 51 | + expect(spy).toHaveBeenCalled() |
| 52 | + }) |
| 53 | + |
| 54 | + test("GET /global/event invokes Telemetry.clientConnected", async () => { |
| 55 | + const response = await Server.Default().request("/global/event") |
| 56 | + await cancelBody(response) |
| 57 | + await tick() |
| 58 | + expect(spy).toHaveBeenCalled() |
| 59 | + }) |
| 60 | + |
| 61 | + test("a non-event path does not invoke Telemetry.clientConnected", async () => { |
| 62 | + const response = await Server.Default().request("/config") |
| 63 | + await cancelBody(response) |
| 64 | + await tick() |
| 65 | + expect(spy).not.toHaveBeenCalled() |
| 66 | + }) |
| 67 | + |
| 68 | + test("a non-GET request to /event does not invoke Telemetry.clientConnected", async () => { |
| 69 | + const response = await Server.Default().request("/event", { method: "POST" }) |
| 70 | + await cancelBody(response) |
| 71 | + await tick() |
| 72 | + expect(spy).not.toHaveBeenCalled() |
| 73 | + }) |
| 74 | +}) |
0 commit comments