/** * P2 Unit Tests: Staleness Check * * Tests: checkStaleness from staleness.ts * - HEAD matches → not stale * - HEAD differs → stale with commit count * - Git failure → fail open (not stale) */ import { describe, it, expect, vi, afterEach } from 'vitest'; import { execFileSync } from 'child_process'; import { checkStaleness } from '../../src/mcp/staleness.js'; // We test checkStaleness with a real git repo (the project itself) // since mocking execFileSync across ESM modules is complex. describe('checkStaleness', () => { it('returns not stale when HEAD matches lastCommit', () => { // Get the actual HEAD commit of this repo let headCommit: string; try { headCommit = execFileSync( 'git', ['rev-parse', 'HEAD'], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }, ).trim(); } catch { // If we can't get HEAD (e.g., not in a git repo), skip return; } const result = checkStaleness(process.cwd(), headCommit); expect(result.isStale).toBe(false); expect(result.commitsBehind).toBe(0); expect(result.hint).toBeUndefined(); }); it('returns stale when lastCommit is behind HEAD', () => { // Use HEAD~1 — works in shallow clones (GitHub Actions) unlike rev-list --max-parents=0 let previousCommit: string; try { previousCommit = execFileSync( 'git', ['rev-parse', 'HEAD~1'], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }, ).trim(); } catch { return; // Not in a git repo or only 1 commit } if (!previousCommit) return; const result = checkStaleness(process.cwd(), previousCommit); expect(result.isStale).toBe(true); expect(result.commitsBehind).toBeGreaterThan(0); expect(result.hint).toContain('behind HEAD'); }); it('fails open when git command fails (e.g., invalid path)', () => { const result = checkStaleness('/nonexistent/path', 'abc123'); expect(result.isStale).toBe(false); expect(result.commitsBehind).toBe(0); }); it('fails open with invalid commit hash', () => { const result = checkStaleness(process.cwd(), 'not-a-real-commit-hash'); expect(result.isStale).toBe(false); expect(result.commitsBehind).toBe(0); }); });