test: fix broken unit tests, add missing fixtures, and stabilize CI pipeline
- Fix os module mock pattern for Vitest v4 in proxy-ide-config tests - Fix enterprise oauth_client_key expectations in cloudHandler-sync and token-manager-parity tests - Fix proxy-controller integration test argument expectations - Add missing proxy-parity JSON fixtures (OpenAI tools, Anthropic tool-use, Gemini SSE) - Add reasoning_content mapping to convertClaudeToOpenAIResponse - Fix google-api service test env var cache leak with resetModules + dynamic imports - Fix proxy-metrics timer tests by calling onModuleInit in beforeEach - Fix locale-sensitive number formatting in StatCard tests - Add missing test files to version control (components, hooks, ipc, mocks, server, utils) - Fix CI workflows: testing.yaml (use vitest run, add type-check job, npm cache), lint.yaml and format.yaml (add npm cache, concurrency, fix job names)
This commit is contained in:
1 parent
bf4bcf4f96
commit
afe8859f16
47 files changed
+4341
-73
No files matched your search
@@ -0,0 +1,154 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { ProxyMetricsRepo } from '../../../ipc/database/proxyMetricsHandler';
|
||||
|
||||
const mockRun = vi.fn();
|
||||
const mockAll = vi.fn();
|
||||
const mockGet = vi.fn();
|
||||
const mockClose = vi.fn();
|
||||
const mockPrepare = vi.fn(() => ({ run: mockRun, all: mockAll, get: mockGet }));
|
||||
|
||||
const mockOrm = {
|
||||
insert: vi.fn(() => ({
|
||||
values: vi.fn(() => ({ run: mockRun })),
|
||||
})),
|
||||
};
|
||||
|
||||
vi.mock('../../../ipc/database/dbConnection', () => ({
|
||||
openDrizzleConnection: vi.fn(() => ({
|
||||
raw: { prepare: mockPrepare, close: mockClose, exec: vi.fn() },
|
||||
orm: mockOrm,
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock('../../../ipc/database/cloudHandler', () => ({
|
||||
ensureDatabaseInitialized: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../../utils/paths', () => ({
|
||||
getCloudAccountsDbPath: vi.fn(() => '/mock/db/path.sqlite'),
|
||||
}));
|
||||
|
||||
vi.mock('../../../utils/logger', () => ({
|
||||
logger: {
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ProxyMetricsRepo', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('recordRequest (record)', () => {
|
||||
it('should insert proxy request metrics into the database', () => {
|
||||
const params = {
|
||||
endpoint: '/v1/chat',
|
||||
statusCode: 200,
|
||||
durationMs: 150,
|
||||
timestamp: Date.now(),
|
||||
accountId: 'acc-1',
|
||||
tokensPrompt: 10,
|
||||
tokensCompletion: 20,
|
||||
errorMessage: null,
|
||||
};
|
||||
|
||||
const result = ProxyMetricsRepo.recordRequest(params);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(mockOrm.insert).toHaveBeenCalled();
|
||||
expect(mockRun).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return false when recording fails', () => {
|
||||
mockRun.mockImplementationOnce(() => {
|
||||
throw new Error('DB error');
|
||||
});
|
||||
|
||||
const result = ProxyMetricsRepo.recordRequest({
|
||||
endpoint: '/v1/chat',
|
||||
statusCode: 500,
|
||||
durationMs: 100,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRecentAggregates (getRecent)', () => {
|
||||
it('should return time-filtered aggregate metrics', () => {
|
||||
mockGet
|
||||
.mockReturnValueOnce({ count: 5 })
|
||||
.mockReturnValueOnce({ total: 10, avgLatency: 120, errorRate: 10 });
|
||||
|
||||
const result = ProxyMetricsRepo.getRecentAggregates();
|
||||
|
||||
expect(mockPrepare).toHaveBeenCalledTimes(2);
|
||||
expect(result.requestsPerMinute).toBe(5);
|
||||
expect(result.avgLatencyMs).toBe(120);
|
||||
expect(result.errorRatePercent).toBe(10);
|
||||
});
|
||||
|
||||
it('should return zeros when no recent data exists', () => {
|
||||
mockGet.mockReturnValueOnce(undefined).mockReturnValueOnce(undefined);
|
||||
|
||||
const result = ProxyMetricsRepo.getRecentAggregates();
|
||||
|
||||
expect(result.requestsPerMinute).toBe(0);
|
||||
expect(result.avgLatencyMs).toBe(0);
|
||||
expect(result.errorRatePercent).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getHistoricalAggregates (getAggregate)', () => {
|
||||
it('should return summary aggregates for the given window', () => {
|
||||
mockGet
|
||||
.mockReturnValueOnce({ total: 100, avgLatency: 200, errorRate: 5 })
|
||||
.mockReturnValueOnce({ avg: 12 });
|
||||
|
||||
const result = ProxyMetricsRepo.getHistoricalAggregates();
|
||||
|
||||
expect(mockPrepare).toHaveBeenCalledTimes(2);
|
||||
expect(result.totalRequests).toBe(100);
|
||||
expect(result.avgLatencyMs).toBe(200);
|
||||
expect(result.errorRatePercent).toBe(5);
|
||||
expect(result.avgActiveConnections).toBe(12);
|
||||
});
|
||||
|
||||
it('should return zeros when an error occurs', () => {
|
||||
mockPrepare.mockImplementationOnce(() => {
|
||||
throw new Error('DB error');
|
||||
});
|
||||
|
||||
const result = ProxyMetricsRepo.getHistoricalAggregates();
|
||||
|
||||
expect(result.totalRequests).toBe(0);
|
||||
expect(result.avgLatencyMs).toBe(0);
|
||||
expect(result.errorRatePercent).toBe(0);
|
||||
expect(result.avgActiveConnections).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteOldRecords (cleanup)', () => {
|
||||
it('should remove old records from metrics and snapshots tables', () => {
|
||||
const result = ProxyMetricsRepo.deleteOldRecords(Date.now() - 86400000);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(mockPrepare).toHaveBeenCalledTimes(2);
|
||||
expect(mockRun).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should return false when cleanup fails', () => {
|
||||
mockRun.mockImplementationOnce(() => {
|
||||
throw new Error('DB error');
|
||||
});
|
||||
|
||||
const result = ProxyMetricsRepo.deleteOldRecords(0);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user