console/packages/libraries/core/tests/persisted-documents.spec.ts
Adam Benhassen 9c5493e441
feat(core): add layer 2 cache support for persisted documents (#7455)
Co-authored-by: Arda TANRIKULU <ardatanrikulu@gmail.com>
2026-01-05 14:50:41 +02:00

1029 lines
31 KiB
TypeScript

import { Logger, MemoryLogWriter } from '@graphql-hive/logger';
import { createPersistedDocuments } from '../src/client/persisted-documents';
import { PERSISTED_DOCUMENT_NOT_FOUND } from '../src/client/types';
test('calls mirror if main source is not working', async () => {
const logger = new Logger({ level: false });
const calls: Array<unknown> = [];
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: [
'https://cdn.localhost/artifacts/v1/target',
'https://cdn-mirror.localhost/artifacts/v1/target',
],
accessToken: 'foobars',
},
logger,
async fetch(args) {
calls.push(args);
if (calls.length === 1) {
throw new Error('Network error or something.');
}
if (calls.length === 2) {
return new Response('{helloWorld}');
}
throw new Error('This should not happen');
},
retry: false,
timeout: false,
});
const result = await persistedDocuments.resolve('graphql-hive~v0.0.0~sha512:123');
expect(result).toEqual('{helloWorld}');
expect(calls).toMatchInlineSnapshot(`
[
https://cdn.localhost/artifacts/v1/target/apps/graphql-hive/v0.0.0/sha512:123,
https://cdn-mirror.localhost/artifacts/v1/target/apps/graphql-hive/v0.0.0/sha512:123,
]
`);
});
test('does not use main source for repeated lookups', async () => {
const logger = new Logger({ level: false });
const calls: Array<unknown> = [];
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: [
'https://cdn.localhost/artifacts/v1/target',
'https://cdn-mirror.localhost/artifacts/v1/target',
],
accessToken: 'foobars',
},
logger,
async fetch(args) {
calls.push(args);
if (calls.length === 1) {
throw new Error('Network error or something.');
}
if (calls.length === 2) {
return new Response('{helloWorld}');
}
if (calls.length === 3) {
return new Response('{foobars}');
}
throw new Error('This should not happen');
},
retry: false,
timeout: false,
circuitBreaker: {
errorThresholdPercentage: 1,
volumeThreshold: 1,
resetTimeout: 30_000,
},
});
const result1 = await persistedDocuments.resolve('graphql-hive~v0.0.0~sha512:123');
expect(result1).toEqual('{helloWorld}');
const result2 = await persistedDocuments.resolve('graphql-hive~v0.0.0~sha512:456');
expect(result2).toEqual('{foobars}');
expect(calls).toMatchInlineSnapshot(`
[
https://cdn.localhost/artifacts/v1/target/apps/graphql-hive/v0.0.0/sha512:123,
https://cdn-mirror.localhost/artifacts/v1/target/apps/graphql-hive/v0.0.0/sha512:123,
https://cdn-mirror.localhost/artifacts/v1/target/apps/graphql-hive/v0.0.0/sha512:456,
]
`);
});
test('fails fast if circuit breaker kicks in', async () => {
const logWriter = new MemoryLogWriter();
const logger = new Logger({ level: 'debug', writers: [logWriter] });
const calls: Array<unknown> = [];
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch(args) {
calls.push(args);
if (calls.length === 1) {
throw new Error('Network error or something.');
}
throw new Error('This should not happen');
},
retry: false,
timeout: false,
circuitBreaker: {
errorThresholdPercentage: 1,
volumeThreshold: 1,
resetTimeout: 30_000,
},
});
await expect(
persistedDocuments.resolve('graphql-hive~v0.0.0~sha512:123'),
).to.rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Failed to look up persisted operation.]`,
);
await expect(
persistedDocuments.resolve('graphql-hive~v0.0.0~sha512:123'),
).to.rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Failed to look up persisted operation.]`,
);
expect((logWriter.logs.pop()?.attrs as any).error?.code).toEqual('EOPENBREAKER');
});
test('validates document ID format - missing hash', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch() {
throw new Error('This should not be called');
},
retry: false,
timeout: false,
});
// Test the malformed document ID from the task description
await expect(
persistedDocuments.resolve('client-name~client-version~'),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[PersistedDocumentValidationError: Invalid document ID "client-name~client-version~": Hash cannot be empty. Expected format: "name~version~hash" (e.g., "client-name~client-version~hash")]`,
);
});
test('validates document ID format - invalid parts count', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch() {
throw new Error('This should not be called');
},
retry: false,
timeout: false,
});
await expect(
persistedDocuments.resolve('client-name~client-version'),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[PersistedDocumentValidationError: Invalid document ID "client-name~client-version": Expected format: "name~version~hash" (e.g., "client-name~client-version~hash")]`,
);
});
test('validates document ID format - empty parts', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch() {
throw new Error('This should not be called');
},
retry: false,
timeout: false,
});
await expect(
persistedDocuments.resolve('~0.1.0~hash'),
).rejects.toThrowErrorMatchingInlineSnapshot(
`[PersistedDocumentValidationError: Invalid document ID "~0.1.0~hash": Name cannot be empty. Expected format: "name~version~hash"]`,
);
});
test('allows valid document IDs to proceed normally', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch(_args) {
return new Response('{helloWorld}');
},
retry: false,
timeout: false,
});
// This should work fine and make the CDN request
const result = await persistedDocuments.resolve('graphql-hive~v0.0.0~sha512:123');
expect(result).toEqual('{helloWorld}');
});
test('validation errors return HTTP 400 status code - missing hash', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch() {
throw new Error('This should not be called');
},
retry: false,
timeout: false,
});
try {
await persistedDocuments.resolve('mytest~0.1.0~');
// Should not reach here - test should fail if no error is thrown
throw new Error('Expected function to throw an error but it did not');
} catch (error: any) {
expect(error.code).toBe('INVALID_DOCUMENT_ID');
expect(error.status).toBe(400);
expect(error.message).toMatch(/Hash cannot be empty/);
}
});
test('validation errors return HTTP 400 status code - invalid format', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch() {
throw new Error('This should not be called');
},
retry: false,
timeout: false,
});
try {
await persistedDocuments.resolve('invalid~format');
// Should not reach here - test should fail if no error is thrown
throw new Error('Expected function to throw an error but it did not');
} catch (error: any) {
expect(error.code).toBe('INVALID_DOCUMENT_ID');
expect(error.status).toBe(400);
expect(error.message).toMatch(/Expected format/);
}
});
test('validation errors return HTTP 400 status code - empty name', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch() {
throw new Error('This should not be called');
},
retry: false,
timeout: false,
});
try {
await persistedDocuments.resolve('~0.1.0~hash123');
// Should not reach here - test should fail if no error is thrown
throw new Error('Expected function to throw an error but it did not');
} catch (error: any) {
expect(error.code).toBe('INVALID_DOCUMENT_ID');
expect(error.status).toBe(400);
expect(error.message).toMatch(/Name cannot be empty/);
}
});
test('validation errors return HTTP 400 status code - empty version', async () => {
const logger = new Logger({ level: false });
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
logger,
async fetch() {
throw new Error('This should not be called');
},
retry: false,
timeout: false,
});
try {
await persistedDocuments.resolve('name~~hash123');
// Should not reach here - test should fail if no error is thrown
throw new Error('Expected function to throw an error but it did not');
} catch (error: any) {
expect(error.code).toBe('INVALID_DOCUMENT_ID');
expect(error.status).toBe(400);
expect(error.message).toMatch(/Version cannot be empty/);
}
});
describe('Layer 2 Cache', () => {
test('L2 cache hit returns cached document without calling CDN', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue('query { cached }'),
set: vi.fn().mockResolvedValue(undefined),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch() {
throw new Error('Should not call CDN when L2 cache hits');
},
});
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { cached }');
expect(l2Cache.get).toHaveBeenCalledWith('app~v1~hash');
// L2 set should not be called because document was already in L2
expect(l2Cache.set).not.toHaveBeenCalled();
});
test('L2 cache miss falls through to CDN and writes back to L2', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null), // cache miss
set: vi.fn().mockResolvedValue(undefined),
};
const cdnCalls: string[] = [];
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch(url) {
cdnCalls.push(String(url));
return new Response('query { fromCdn }');
},
});
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { fromCdn }');
expect(l2Cache.get).toHaveBeenCalledWith('app~v1~hash');
expect(cdnCalls).toHaveLength(1);
// Wait for async L2 write
await new Promise(resolve => setTimeout(resolve, 10));
expect(l2Cache.set).toHaveBeenCalledWith('app~v1~hash', 'query { fromCdn }', undefined);
});
test('L2 cache negative hit returns null without calling CDN', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(PERSISTED_DOCUMENT_NOT_FOUND),
set: vi.fn(),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch() {
throw new Error('Should not call CDN when L2 has negative cache hit');
},
});
const result = await persistedDocuments.resolve('app~v1~missing');
expect(result).toBeNull();
expect(l2Cache.get).toHaveBeenCalledWith('app~v1~missing');
});
test('L2 cache stores not-found with notFoundTtlSeconds', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
notFoundTtlSeconds: 120,
},
logger,
async fetch() {
return new Response('', { status: 404 });
},
});
const result = await persistedDocuments.resolve('app~v1~notfound');
expect(result).toBeNull();
// Wait for async L2 write
await new Promise(resolve => setTimeout(resolve, 10));
expect(l2Cache.set).toHaveBeenCalledWith('app~v1~notfound', PERSISTED_DOCUMENT_NOT_FOUND, {
ttl: 120,
});
});
test('L2 cache stores found documents with ttlSeconds', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
ttlSeconds: 3600,
notFoundTtlSeconds: 60,
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { doc }');
// Wait for async L2 write
await new Promise(resolve => setTimeout(resolve, 10));
expect(l2Cache.set).toHaveBeenCalledWith('app~v1~hash', 'query { doc }', { ttl: 3600 });
});
test('L2 cache failure gracefully falls through to CDN', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockRejectedValue(new Error('Redis connection failed')),
set: vi.fn(),
};
const cdnCalls: string[] = [];
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch(url) {
cdnCalls.push(String(url));
return new Response('query { fallback }');
},
});
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { fallback }');
expect(cdnCalls).toHaveLength(1);
});
test('L2 cache with read-only implementation (no set method)', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
// No set method - read-only cache
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch() {
return new Response('query { doc }');
},
});
// Should not throw when no set method
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { doc }');
});
test('negative caching disabled when notFoundTtlSeconds is 0', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
notFoundTtlSeconds: 0, // Disable negative caching
},
logger,
async fetch() {
return new Response('', { status: 404 });
},
});
await persistedDocuments.resolve('app~v1~notfound');
// Wait for potential async L2 write
await new Promise(resolve => setTimeout(resolve, 10));
// set should not be called for not-found when notFoundTtlSeconds is 0
expect(l2Cache.set).not.toHaveBeenCalled();
});
test('L2 cache set failure does not break the request', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockRejectedValue(new Error('Redis write failed')),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch() {
return new Response('query { doc }');
},
});
// Request should succeed even if L2 set fails
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { doc }');
// Wait for async L2 write attempt
await new Promise(resolve => setTimeout(resolve, 10));
expect(l2Cache.set).toHaveBeenCalled();
});
test('L1 cache is populated from L2 cache hit', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue('query { cached }'),
set: vi.fn(),
};
let fetchCallCount = 0;
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch() {
fetchCallCount++;
throw new Error('Should not call CDN');
},
});
// First call - hits L2, should populate L1
const result1 = await persistedDocuments.resolve('app~v1~hash');
expect(result1).toBe('query { cached }');
expect(l2Cache.get).toHaveBeenCalledTimes(1);
// Second call - should hit L1 directly, not L2
const result2 = await persistedDocuments.resolve('app~v1~hash');
expect(result2).toBe('query { cached }');
// L2 get should still only be called once
expect(l2Cache.get).toHaveBeenCalledTimes(1);
expect(fetchCallCount).toBe(0);
});
test('L1 cache is populated from L2 negative cache hit', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(PERSISTED_DOCUMENT_NOT_FOUND),
set: vi.fn(),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch() {
throw new Error('Should not call CDN');
},
});
// First call - hits L2 negative cache, should populate L1
const result1 = await persistedDocuments.resolve('app~v1~missing');
expect(result1).toBeNull();
expect(l2Cache.get).toHaveBeenCalledTimes(1);
// Second call - should hit L1 directly (with null value), not L2
const result2 = await persistedDocuments.resolve('app~v1~missing');
expect(result2).toBeNull();
// L2 get should still only be called once
expect(l2Cache.get).toHaveBeenCalledTimes(1);
});
test('concurrent requests are deduplicated when hitting L2 cache', async () => {
const logger = new Logger({ level: false });
let l2GetCallCount = 0;
const l2Cache = {
get: vi.fn().mockImplementation(async () => {
l2GetCallCount++;
// Simulate some latency
await new Promise(resolve => setTimeout(resolve, 50));
return 'query { cached }';
}),
set: vi.fn(),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: { cache: l2Cache },
logger,
async fetch() {
throw new Error('Should not call CDN');
},
});
// Fire multiple concurrent requests for the same document
const promises = [
persistedDocuments.resolve('app~v1~hash'),
persistedDocuments.resolve('app~v1~hash'),
persistedDocuments.resolve('app~v1~hash'),
];
const results = await Promise.all(promises);
// All should get the same result
expect(results).toEqual(['query { cached }', 'query { cached }', 'query { cached }']);
// L2 cache should only be called once due to request deduplication
expect(l2GetCallCount).toBe(1);
});
test('without layer2Cache configured, behaves as before', async () => {
const logger = new Logger({ level: false });
const cdnCalls: string[] = [];
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
// No layer2Cache configured
logger,
async fetch(url) {
cdnCalls.push(String(url));
return new Response('query { fromCdn }');
},
});
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { fromCdn }');
expect(cdnCalls).toHaveLength(1);
});
test('waitUntil is called for L2 cache writes', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const waitUntilPromises: Promise<unknown>[] = [];
const waitUntil = vi.fn((promise: void | Promise<void>) => {
if (promise) waitUntilPromises.push(promise);
});
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
waitUntil,
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
await persistedDocuments.resolve('app~v1~hash');
// waitUntil should be called with the cache write promise
expect(waitUntil).toHaveBeenCalledTimes(1);
expect(waitUntilPromises).toHaveLength(1);
// Wait for the promise to resolve
await waitUntilPromises[0];
expect(l2Cache.set).toHaveBeenCalled();
});
test('waitUntil is NOT called when cache has no set method', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
// No set method - read-only cache
};
const waitUntil = vi.fn();
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
waitUntil,
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
await persistedDocuments.resolve('app~v1~hash');
// waitUntil should NOT be called since there's no set method
expect(waitUntil).not.toHaveBeenCalled();
});
test('waitUntil promise resolves (not rejects) when set fails', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockRejectedValue(new Error('Redis write failed')),
};
const waitUntilPromises: Promise<unknown>[] = [];
const waitUntil = vi.fn((promise: void | Promise<void>) => {
if (promise) waitUntilPromises.push(promise);
});
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
waitUntil,
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
await persistedDocuments.resolve('app~v1~hash');
expect(waitUntil).toHaveBeenCalledTimes(1);
// The promise should resolve (not reject) because errors are caught internally
await expect(waitUntilPromises[0]).resolves.toBeUndefined();
});
test('waitUntil is called for negative cache writes (404)', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const waitUntilPromises: Promise<unknown>[] = [];
const waitUntil = vi.fn((promise: void | Promise<void>) => {
if (promise) waitUntilPromises.push(promise);
});
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
notFoundTtlSeconds: 60,
waitUntil,
},
logger,
async fetch() {
return new Response('', { status: 404 });
},
});
await persistedDocuments.resolve('app~v1~notfound');
// waitUntil should be called for negative cache write
expect(waitUntil).toHaveBeenCalledTimes(1);
await waitUntilPromises[0];
expect(l2Cache.set).toHaveBeenCalledWith('app~v1~notfound', PERSISTED_DOCUMENT_NOT_FOUND, {
ttl: 60,
});
});
test('waitUntil is NOT called when notFoundTtlSeconds is 0', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const waitUntil = vi.fn();
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
notFoundTtlSeconds: 0, // Disable negative caching
waitUntil,
},
logger,
async fetch() {
return new Response('', { status: 404 });
},
});
await persistedDocuments.resolve('app~v1~notfound');
// waitUntil should NOT be called since negative caching is disabled
expect(waitUntil).not.toHaveBeenCalled();
expect(l2Cache.set).not.toHaveBeenCalled();
});
test('waitUntil is NOT called on L2 cache hit', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue('query { cached }'),
set: vi.fn().mockResolvedValue(undefined),
};
const waitUntil = vi.fn();
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
waitUntil,
},
logger,
async fetch() {
throw new Error('Should not call CDN');
},
});
const result = await persistedDocuments.resolve('app~v1~hash');
expect(result).toBe('query { cached }');
// waitUntil should NOT be called since we got a cache hit (no write needed)
expect(waitUntil).not.toHaveBeenCalled();
expect(l2Cache.set).not.toHaveBeenCalled();
});
test('waitUntil from context is used when not configured', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const contextWaitUntilPromises: Promise<unknown>[] = [];
const contextWaitUntil = vi.fn((promise: void | Promise<void>) => {
if (promise) contextWaitUntilPromises.push(promise);
});
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
// No waitUntil configured
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
// Pass waitUntil via context
await persistedDocuments.resolve('app~v1~hash', { waitUntil: contextWaitUntil });
expect(contextWaitUntil).toHaveBeenCalledTimes(1);
await contextWaitUntilPromises[0];
expect(l2Cache.set).toHaveBeenCalled();
});
test('config waitUntil takes precedence over context waitUntil', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const configWaitUntil = vi.fn();
const contextWaitUntil = vi.fn();
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
waitUntil: configWaitUntil,
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
await persistedDocuments.resolve('app~v1~hash', { waitUntil: contextWaitUntil });
// Config waitUntil should be used, not context
expect(configWaitUntil).toHaveBeenCalledTimes(1);
expect(contextWaitUntil).not.toHaveBeenCalled();
});
test('waitUntil is NOT called when set returns synchronously (undefined)', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockReturnValue(undefined), // Sync return, not Promise
};
const waitUntil = vi.fn();
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
waitUntil,
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
await persistedDocuments.resolve('app~v1~hash');
// waitUntil should NOT be called because set() returned undefined (falsy)
expect(waitUntil).not.toHaveBeenCalled();
// But set should still have been called
expect(l2Cache.set).toHaveBeenCalled();
});
test('L2 cache write succeeds without any waitUntil configured', async () => {
const logger = new Logger({ level: false });
const l2Cache = {
get: vi.fn().mockResolvedValue(null),
set: vi.fn().mockResolvedValue(undefined),
};
const persistedDocuments = createPersistedDocuments({
cdn: {
endpoint: 'https://cdn.localhost/artifacts/v1/target',
accessToken: 'foobars',
},
layer2Cache: {
cache: l2Cache,
// No waitUntil configured
},
logger,
async fetch() {
return new Response('query { doc }');
},
});
// Pass no context (no waitUntil anywhere)
await persistedDocuments.resolve('app~v1~hash');
// Give the fire-and-forget promise time to resolve
await new Promise(resolve => setTimeout(resolve, 10));
// Cache should still be written, just fire-and-forget
expect(l2Cache.set).toHaveBeenCalledWith('app~v1~hash', 'query { doc }', undefined);
});
});