返回 CodeWhale
support.ts
根目录 / telemetry-ingest / test / support.ts
1 import { readFileSync } from "node:fs";
2 import { fileURLToPath } from "node:url";
3
4 import type { DataPoint } from "../src/datapoint";
5 import type { Env } from "../src/index";
6 import { INGEST_PATH } from "../src/route";
7
8 /** `docs/TELEMETRY.md` — the published schema, and the thing we must match. */
9 export const DOC = readFileSync(
10 new URL("../../docs/TELEMETRY.md", import.meta.url),
11 "utf8",
12 );
13
14 /**
15 * `crates/telemetry/tests/golden/v1.json` — the client's own pinned v1 wire
16 * form. Reading the real file rather than a hand-written fixture is the point:
17 * the Rust suite already welds this file to the doc and to the serializer, so
18 * an endpoint that accepts it byte for byte is welded to both by transitivity.
19 */
20 export const GOLDEN_PATH = fileURLToPath(
21 new URL("../../crates/telemetry/tests/golden/v1.json", import.meta.url),
22 );
23
24 export const GOLDEN_TEXT = readFileSync(GOLDEN_PATH, "utf8");
25
26 /** A fresh deep copy of the golden batch. */
27 export function goldenBatch(): Record<string, unknown> {
28 return JSON.parse(GOLDEN_TEXT) as Record<string, unknown>;
29 }
30
31 export interface Harness {
32 env: Env;
33 written: DataPoint[];
34 limited: string[];
35 }
36
37 /** An `Env` whose bindings record instead of calling Cloudflare. */
38 export function harness(options: { rateLimit?: boolean } = {}): Harness {
39 const written: DataPoint[] = [];
40 const limited: string[] = [];
41 const env: Env = {
42 TELEMETRY: {
43 writeDataPoint(point) {
44 written.push({
45 indexes: point.indexes ?? [],
46 blobs: point.blobs ?? [],
47 doubles: point.doubles ?? [],
48 });
49 },
50 },
51 };
52 if (options.rateLimit !== undefined) {
53 env.RATE_LIMITER = {
54 async limit({ key }) {
55 limited.push(key);
56 return { success: options.rateLimit === true };
57 },
58 };
59 }
60 return { env, written, limited };
61 }
62
63 const ORIGIN = "https://telemetry.invalid";
64
65 /** A POST shaped the way `crates/telemetry/src/client.rs` shapes it. */
66 export function post(
67 body: BodyInit,
68 init: { path?: string; contentType?: string | null } = {},
69 ): Request {
70 const headers = new Headers();
71 if (init.contentType !== null) {
72 headers.set("content-type", init.contentType ?? "application/json");
73 }
74 return new Request(`${ORIGIN}${init.path ?? INGEST_PATH}`, {
75 method: "POST",
76 headers,
77 body,
78 });
79 }
80
81 /** A POST of a JSON value. */
82 export function postJson(value: unknown): Request {
83 return post(JSON.stringify(value));
84 }
85
85 lines TYPESCRIPT