chore: resolve merge conflicts for DiffCache test task
Resolves add/add conflict in diff-cache.ts (kept typed PhaseMetaResponse/ FileDiffResponse interfaces from HEAD over unknown-typed singletons from test branch) and content conflict in phase.ts (kept both phaseMetaCache and fileDiffCache imports; removed auto-merged duplicate firstClone/headHash/ cacheKey/cached declarations and unreachable empty-projects guard). Also cleans auto-merged duplicate getHeadCommitHash in orchestrator.test.ts and simple-git-branch-manager.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
76
apps/server/review/diff-cache.test.ts
Normal file
76
apps/server/review/diff-cache.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Unit tests for DiffCache class.
|
||||
*
|
||||
* Tests TTL expiry, prefix invalidation, and env-var TTL configuration.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { DiffCache } from './diff-cache.js';
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('DiffCache', () => {
|
||||
it('returns undefined for a key that was never set', () => {
|
||||
const cache = new DiffCache<string>(5000);
|
||||
expect(cache.get('nonexistent')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns value when entry has not expired', () => {
|
||||
vi.spyOn(Date, 'now').mockReturnValue(1000);
|
||||
const cache = new DiffCache<string>(5000);
|
||||
cache.set('key', 'value');
|
||||
vi.spyOn(Date, 'now').mockReturnValue(5999); // 4999ms elapsed, TTL=5000
|
||||
expect(cache.get('key')).toBe('value');
|
||||
});
|
||||
|
||||
it('returns undefined and deletes the entry when TTL has elapsed', () => {
|
||||
vi.spyOn(Date, 'now').mockReturnValue(1000);
|
||||
const cache = new DiffCache<string>(5000);
|
||||
cache.set('key', 'value');
|
||||
vi.spyOn(Date, 'now').mockReturnValue(6001); // 5001ms elapsed, TTL=5000
|
||||
expect(cache.get('key')).toBeUndefined();
|
||||
// Verify the key is no longer stored (second get also returns undefined)
|
||||
vi.spyOn(Date, 'now').mockReturnValue(6001);
|
||||
expect(cache.get('key')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('overwrites an existing entry and resets its TTL', () => {
|
||||
vi.spyOn(Date, 'now').mockReturnValue(1000);
|
||||
const cache = new DiffCache<string>(5000);
|
||||
cache.set('key', 'first');
|
||||
vi.spyOn(Date, 'now').mockReturnValue(4000); // overwrite before expiry
|
||||
cache.set('key', 'second');
|
||||
vi.spyOn(Date, 'now').mockReturnValue(8999); // 4999ms after overwrite, TTL=5000
|
||||
expect(cache.get('key')).toBe('second');
|
||||
vi.spyOn(Date, 'now').mockReturnValue(9001); // 5001ms after overwrite
|
||||
expect(cache.get('key')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('invalidateByPrefix removes all matching keys and preserves others', () => {
|
||||
const cache = new DiffCache<string>(60_000);
|
||||
cache.set('phase-1:abc', 'a');
|
||||
cache.set('phase-1:abc:file.ts', 'b');
|
||||
cache.set('phase-2:xyz', 'c');
|
||||
cache.invalidateByPrefix('phase-1:');
|
||||
expect(cache.get('phase-1:abc')).toBeUndefined();
|
||||
expect(cache.get('phase-1:abc:file.ts')).toBeUndefined();
|
||||
expect(cache.get('phase-2:xyz')).toBe('c');
|
||||
});
|
||||
|
||||
it('singleton instances use REVIEW_DIFF_CACHE_TTL_MS env var for TTL', async () => {
|
||||
vi.resetModules();
|
||||
vi.stubEnv('REVIEW_DIFF_CACHE_TTL_MS', '1000');
|
||||
const { phaseMetaCache } = await import('./diff-cache.js');
|
||||
|
||||
vi.spyOn(Date, 'now').mockReturnValue(0);
|
||||
phaseMetaCache.set('key', {} as any);
|
||||
vi.spyOn(Date, 'now').mockReturnValue(999);
|
||||
expect(phaseMetaCache.get('key')).toBeDefined();
|
||||
vi.spyOn(Date, 'now').mockReturnValue(1001);
|
||||
expect(phaseMetaCache.get('key')).toBeUndefined();
|
||||
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* DiffCache — in-memory cache with TTL and prefix-based invalidation.
|
||||
* Used to avoid re-running expensive git diff subprocesses on repeated requests.
|
||||
* DiffCache — in-memory TTL cache for git diff results.
|
||||
*
|
||||
* Keyed by `phaseId:headHash` (or `phaseId:headHash:filePath` for per-file diffs).
|
||||
* TTL defaults to 5 minutes, configurable via REVIEW_DIFF_CACHE_TTL_MS env var.
|
||||
* Prefix-based invalidation clears all entries for a phase when a new commit lands.
|
||||
*/
|
||||
|
||||
import type { FileStatEntry } from '../git/types.js';
|
||||
|
||||
Reference in New Issue
Block a user