112 lines
3.9 KiB
TypeScript
112 lines
3.9 KiB
TypeScript
/**
|
|
* Tests for analytics CLI command logic — metrics review and purge.
|
|
*
|
|
* Tests the command action logic by calling the underlying functions
|
|
* with appropriate parameters, verifying the integration between
|
|
* config loading, eventsDir resolution, and the analytics functions.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { tmpdir } from 'node:os';
|
|
import {
|
|
computeReviewMetrics,
|
|
formatReviewMetrics,
|
|
parseSinceDuration,
|
|
purgeOldEvents,
|
|
} from '../features/analytics/index.js';
|
|
import type { ReviewFindingEvent } from '../features/analytics/index.js';
|
|
|
|
describe('metrics review command logic', () => {
|
|
let eventsDir: string;
|
|
|
|
beforeEach(() => {
|
|
eventsDir = join(tmpdir(), `takt-test-cli-metrics-${Date.now()}`);
|
|
mkdirSync(eventsDir, { recursive: true });
|
|
});
|
|
|
|
afterEach(() => {
|
|
rmSync(eventsDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('should compute and format metrics from resolved eventsDir', () => {
|
|
const events: ReviewFindingEvent[] = [
|
|
{
|
|
type: 'review_finding', findingId: 'f-001', status: 'new', ruleId: 'r-1',
|
|
severity: 'error', decision: 'reject', file: 'a.ts', line: 1, iteration: 1,
|
|
runId: 'r', timestamp: '2026-02-18T10:00:00.000Z',
|
|
},
|
|
];
|
|
writeFileSync(
|
|
join(eventsDir, '2026-02-18.jsonl'),
|
|
events.map((e) => JSON.stringify(e)).join('\n') + '\n',
|
|
'utf-8',
|
|
);
|
|
|
|
const durationMs = parseSinceDuration('30d');
|
|
const sinceMs = new Date('2026-02-18T00:00:00Z').getTime();
|
|
const result = computeReviewMetrics(eventsDir, sinceMs);
|
|
const output = formatReviewMetrics(result);
|
|
|
|
expect(output).toContain('Review Metrics');
|
|
expect(result.rejectCountsByRule.get('r-1')).toBe(1);
|
|
});
|
|
|
|
it('should parse since duration and compute correct time window', () => {
|
|
const durationMs = parseSinceDuration('7d');
|
|
const now = new Date('2026-02-18T12:00:00Z').getTime();
|
|
const sinceMs = now - durationMs;
|
|
|
|
expect(sinceMs).toBe(new Date('2026-02-11T12:00:00Z').getTime());
|
|
});
|
|
});
|
|
|
|
describe('purge command logic', () => {
|
|
let eventsDir: string;
|
|
|
|
beforeEach(() => {
|
|
eventsDir = join(tmpdir(), `takt-test-cli-purge-${Date.now()}`);
|
|
mkdirSync(eventsDir, { recursive: true });
|
|
});
|
|
|
|
afterEach(() => {
|
|
rmSync(eventsDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('should purge files using eventsDir from config and retentionDays from config', () => {
|
|
writeFileSync(join(eventsDir, '2025-12-01.jsonl'), '{}', 'utf-8');
|
|
writeFileSync(join(eventsDir, '2026-02-18.jsonl'), '{}', 'utf-8');
|
|
|
|
const retentionDays = 30;
|
|
const deleted = purgeOldEvents(eventsDir, retentionDays, new Date('2026-02-18T12:00:00Z'));
|
|
|
|
expect(deleted).toContain('2025-12-01.jsonl');
|
|
expect(deleted).not.toContain('2026-02-18.jsonl');
|
|
});
|
|
|
|
it('should fallback to CLI retentionDays when config has no retentionDays', () => {
|
|
writeFileSync(join(eventsDir, '2025-01-01.jsonl'), '{}', 'utf-8');
|
|
|
|
const cliRetentionDays = parseInt('30', 10);
|
|
const configRetentionDays = undefined;
|
|
const retentionDays = configRetentionDays ?? cliRetentionDays;
|
|
const deleted = purgeOldEvents(eventsDir, retentionDays, new Date('2026-02-18T12:00:00Z'));
|
|
|
|
expect(deleted).toContain('2025-01-01.jsonl');
|
|
});
|
|
|
|
it('should use config retentionDays when specified', () => {
|
|
writeFileSync(join(eventsDir, '2026-02-10.jsonl'), '{}', 'utf-8');
|
|
writeFileSync(join(eventsDir, '2026-02-18.jsonl'), '{}', 'utf-8');
|
|
|
|
const cliRetentionDays = parseInt('30', 10);
|
|
const configRetentionDays = 5;
|
|
const retentionDays = configRetentionDays ?? cliRetentionDays;
|
|
const deleted = purgeOldEvents(eventsDir, retentionDays, new Date('2026-02-18T12:00:00Z'));
|
|
|
|
expect(deleted).toContain('2026-02-10.jsonl');
|
|
expect(deleted).not.toContain('2026-02-18.jsonl');
|
|
});
|
|
});
|