Skip to content

Commit f506af4

Browse files
test(toolkit-core): Move the pure cache policy tests out of the CLI
The tier, key, and URL normalization property tests now live next to the code in `toolkit-core/src/response-cache/policy.property.test.ts`, with `fast-check` added as a toolkit-core dev dependency. The CLI keeps only the tests for its disk store and for its `buildCacheKey` wrapper's default identity, which comes from the active login. Cases the property tests already cover are dropped from `tiers.test.ts` and `keys.test.ts`.
1 parent 32c29d1 commit f506af4

6 files changed

Lines changed: 34 additions & 96 deletions

File tree

‎packages/cli/test/lib/response-cache.test.ts‎

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import { readdir } from "node:fs/promises";
99
import { join } from "node:path";
10-
import { normalizeUrl } from "@sentry/toolkit-core/response-cache";
1110
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
1211
import { setAuthToken } from "../../src/lib/db/auth.js";
1312
import {
@@ -337,57 +336,11 @@ describe("cache bypass", () => {
337336
});
338337

339338
// ---------------------------------------------------------------------------
340-
// normalizeUrl
341-
// ---------------------------------------------------------------------------
342-
343-
describe("normalizeUrl", () => {
344-
test("sorts query params alphabetically", () => {
345-
const result = normalizeUrl(
346-
"GET",
347-
"https://sentry.io/api/0/issues/?b=2&a=1",
348-
);
349-
expect(result).toBe("GET|https://sentry.io/api/0/issues/?a=1&b=2");
350-
});
351-
352-
test("uppercases the method", () => {
353-
const result = normalizeUrl("get", "https://sentry.io/api/0/issues/");
354-
expect(result).toMatch(/^GET\|/);
355-
});
356-
357-
test("throws on invalid URLs", () => {
358-
expect(() => normalizeUrl("GET", "not-a-valid-url")).toThrow();
359-
});
360-
361-
test("handles self-hosted URLs with unusual schemes", () => {
362-
const result = normalizeUrl(
363-
"GET",
364-
"https://sentry.mycompany.internal/api/0/issues/",
365-
);
366-
expect(result).toBe("GET|https://sentry.mycompany.internal/api/0/issues/");
367-
});
368-
});
369-
370-
// ---------------------------------------------------------------------------
371-
// buildCacheKey
339+
// buildCacheKey — key derivation is tested in toolkit-core; this covers the
340+
// CLI wrapper's default identity, taken from the active login
372341
// ---------------------------------------------------------------------------
373342

374343
describe("buildCacheKey", () => {
375-
test("produces a 64-char hex string", async () => {
376-
expect(await buildCacheKey("GET", TEST_URL)).toMatch(/^[0-9a-f]{64}$/);
377-
});
378-
379-
test("is deterministic", async () => {
380-
expect(await buildCacheKey("GET", TEST_URL)).toBe(
381-
await buildCacheKey("GET", TEST_URL),
382-
);
383-
});
384-
385-
test("different methods produce different keys", async () => {
386-
expect(await buildCacheKey("GET", TEST_URL)).not.toBe(
387-
await buildCacheKey("POST", TEST_URL),
388-
);
389-
});
390-
391344
test("different identities produce different keys for the same URL", async () => {
392345
// Switching accounts must route reads/writes through a different
393346
// namespace so users never see each other's cached data.

‎packages/toolkit-core/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"tsc": "tsc --noEmit"
8383
},
8484
"devDependencies": {
85+
"fast-check": "^4.8.0",
8586
"typescript": "catalog:",
8687
"vitest": "catalog:"
8788
}

‎packages/toolkit-core/src/response-cache/keys.test.ts‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ describe("normalizeUrl", () => {
1111
);
1212
});
1313

14+
it("keeps self-hosted hosts", () => {
15+
expect(
16+
normalizeUrl("GET", "https://sentry.mycompany.internal/api/0/issues/"),
17+
).toBe("GET|https://sentry.mycompany.internal/api/0/issues/");
18+
});
19+
1420
it("throws on a URL it cannot parse", () => {
1521
expect(() => normalizeUrl("GET", "not a url")).toThrow(TypeError);
1622
});
@@ -32,22 +38,6 @@ describe("buildCacheKey", () => {
3238
);
3339
});
3440

35-
it("ignores query param order and method case", async () => {
36-
expect(
37-
await buildCacheKey(
38-
"get",
39-
"https://us.sentry.io/api/0/issues/?a=1&b=2",
40-
"alice",
41-
),
42-
).toBe(
43-
await buildCacheKey(
44-
"GET",
45-
"https://us.sentry.io/api/0/issues/?b=2&a=1",
46-
"alice",
47-
),
48-
);
49-
});
50-
5141
it("matches node:crypto HMAC-SHA256, so existing CLI cache entries still hit", async () => {
5242
const identity = "oauth:3f2a9c";
5343
const expected = createHmac("sha256", identity)

packages/cli/test/lib/response-cache.property.test.ts renamed to packages/toolkit-core/src/response-cache/policy.property.test.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ import {
1414
string,
1515
tuple,
1616
} from "fast-check";
17-
import { classifyUrl, normalizeUrl } from "@sentry/toolkit-core/response-cache";
1817
import { describe, expect, test } from "vitest";
19-
import { buildCacheKey } from "../../src/lib/response-cache.js";
20-
import { DEFAULT_NUM_RUNS } from "../model-based/helpers.js";
18+
import { buildCacheKey, normalizeUrl } from "./keys.js";
19+
import { classifyUrl } from "./tiers.js";
20+
21+
const DEFAULT_NUM_RUNS = 50;
22+
23+
/** Any non-empty identity; scoping across identities is in keys.test.ts. */
24+
const IDENTITY = "test-identity";
2125

2226
// ---------------------------------------------------------------------------
2327
// Arbitraries
@@ -67,7 +71,9 @@ describe("property: buildCacheKey", () => {
6771
test("produces a 64-char hex string (SHA-256)", async () => {
6872
await fcAssert(
6973
asyncProperty(methodArb, sentryUrlArb, async (method, url) => {
70-
expect(await buildCacheKey(method, url)).toMatch(/^[0-9a-f]{64}$/);
74+
expect(await buildCacheKey(method, url, IDENTITY)).toMatch(
75+
/^[0-9a-f]{64}$/,
76+
);
7177
}),
7278
{ numRuns: DEFAULT_NUM_RUNS },
7379
);
@@ -76,8 +82,8 @@ describe("property: buildCacheKey", () => {
7682
test("is deterministic — same inputs produce same key", async () => {
7783
await fcAssert(
7884
asyncProperty(methodArb, sentryUrlArb, async (method, url) => {
79-
expect(await buildCacheKey(method, url)).toBe(
80-
await buildCacheKey(method, url),
85+
expect(await buildCacheKey(method, url, IDENTITY)).toBe(
86+
await buildCacheKey(method, url, IDENTITY),
8187
);
8288
}),
8389
{ numRuns: DEFAULT_NUM_RUNS },
@@ -87,8 +93,8 @@ describe("property: buildCacheKey", () => {
8793
test("different methods produce different keys for same URL", async () => {
8894
await fcAssert(
8995
asyncProperty(sentryUrlArb, async (url) => {
90-
expect(await buildCacheKey("GET", url)).not.toBe(
91-
await buildCacheKey("POST", url),
96+
expect(await buildCacheKey("GET", url, IDENTITY)).not.toBe(
97+
await buildCacheKey("POST", url, IDENTITY),
9298
);
9399
}),
94100
{ numRuns: DEFAULT_NUM_RUNS },
@@ -103,8 +109,8 @@ describe("property: buildCacheKey", () => {
103109
async (base, path) => {
104110
const url1 = `${base}/api/0/${path}?a=1&b=2&c=3`;
105111
const url2 = `${base}/api/0/${path}?c=3&a=1&b=2`;
106-
expect(await buildCacheKey("GET", url1)).toBe(
107-
await buildCacheKey("GET", url2),
112+
expect(await buildCacheKey("GET", url1, IDENTITY)).toBe(
113+
await buildCacheKey("GET", url2, IDENTITY),
108114
);
109115
},
110116
),
@@ -115,8 +121,8 @@ describe("property: buildCacheKey", () => {
115121
test("method comparison is case-insensitive", async () => {
116122
await fcAssert(
117123
asyncProperty(sentryUrlArb, async (url) => {
118-
expect(await buildCacheKey("get", url)).toBe(
119-
await buildCacheKey("GET", url),
124+
expect(await buildCacheKey("get", url, IDENTITY)).toBe(
125+
await buildCacheKey("GET", url, IDENTITY),
120126
);
121127
}),
122128
{ numRuns: DEFAULT_NUM_RUNS },

‎packages/toolkit-core/src/response-cache/tiers.test.ts‎

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,10 @@ describe("classifyUrl", () => {
3232
expect(ttlFor(url)).toBeLessThanOrEqual(60 * 1000);
3333
});
3434

35-
it("treats project event details, log queries, and span queries as volatile", () => {
36-
for (const url of [
37-
`${API}/projects/acme/web/events/deadbeef/`,
38-
`${API}/organizations/acme/events/?dataset=logs&query=foo`,
39-
`${API}/organizations/acme/events/?field=id&dataset=spans`,
40-
`${API}/organizations/acme/trace-logs/?traceId=${TRACE_ID}`,
41-
]) {
42-
expect(classifyUrl(url)).toBe("volatile");
43-
}
35+
it("treats trace log queries as volatile", () => {
36+
expect(
37+
classifyUrl(`${API}/organizations/acme/trace-logs/?traceId=${TRACE_ID}`),
38+
).toBe("volatile");
4439
});
4540

4641
it("never serves polling endpoints from cache", () => {
@@ -52,16 +47,6 @@ describe("classifyUrl", () => {
5247
expect(ttlFor(url)).toBe(0);
5348
}
5449
});
55-
56-
it("defaults everything else to stable", () => {
57-
for (const url of [
58-
`${API}/organizations/`,
59-
`${API}/organizations/acme/projects/`,
60-
`${API}/projects/acme/web/trace-items/abc123/?item_type=spans`,
61-
]) {
62-
expect(classifyUrl(url)).toBe("stable");
63-
}
64-
});
6550
});
6651

6752
describe("FALLBACK_TTL_MS", () => {

‎pnpm-lock.yaml‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)