mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 20:17:45 +00:00
101 lines
2.8 KiB
TypeScript
101 lines
2.8 KiB
TypeScript
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, mock, spyOn } from 'bun:test';
|
|
import * as fs from 'fs';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
import type { CliproxyUsageApiResponse } from '../../../src/cliproxy/stats-fetcher';
|
|
import { runWithScopedConfigDir } from '../../../src/utils/config-manager';
|
|
|
|
let ccsDir = '';
|
|
let rawResponse: CliproxyUsageApiResponse | null = null;
|
|
let fetchCalls = 0;
|
|
|
|
mock.module('../../../src/cliproxy/stats-fetcher', () => ({
|
|
fetchCliproxyUsageRaw: async () => {
|
|
fetchCalls++;
|
|
return rawResponse;
|
|
},
|
|
}));
|
|
|
|
let syncer: typeof import('../../../src/web-server/usage/cliproxy-usage-syncer');
|
|
|
|
beforeAll(async () => {
|
|
syncer = await import('../../../src/web-server/usage/cliproxy-usage-syncer');
|
|
});
|
|
|
|
beforeEach(() => {
|
|
ccsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-cliproxy-syncer-'));
|
|
fetchCalls = 0;
|
|
rawResponse = {
|
|
usage: {
|
|
apis: {
|
|
gemini: {
|
|
models: {
|
|
'gemini-2.5-pro': {
|
|
details: [
|
|
{
|
|
timestamp: '2026-03-02T12:00:00.000Z',
|
|
source: 'account-a',
|
|
auth_index: 0,
|
|
tokens: {
|
|
input_tokens: 100,
|
|
output_tokens: 20,
|
|
reasoning_tokens: 0,
|
|
cached_tokens: 10,
|
|
total_tokens: 130,
|
|
},
|
|
failed: false,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
syncer.stopCliproxySync();
|
|
});
|
|
|
|
afterEach(() => {
|
|
syncer.stopCliproxySync();
|
|
fs.rmSync(ccsDir, { recursive: true, force: true });
|
|
});
|
|
|
|
afterAll(() => {
|
|
mock.restore();
|
|
});
|
|
|
|
describe('cliproxy usage syncer', () => {
|
|
it('writes and loads snapshot data', async () => {
|
|
await runWithScopedConfigDir(ccsDir, async () => {
|
|
await syncer.syncCliproxyUsage();
|
|
});
|
|
|
|
const snapshotPath = path.join(ccsDir, 'cache', 'cliproxy-usage', 'latest.json');
|
|
expect(fs.existsSync(snapshotPath)).toBe(true);
|
|
|
|
const cached = await runWithScopedConfigDir(ccsDir, async () => {
|
|
return await syncer.loadCachedCliproxyData();
|
|
});
|
|
expect(cached.daily).toHaveLength(1);
|
|
expect(cached.daily[0].source).toBe('cliproxy');
|
|
expect(cached.daily[0].inputTokens).toBe(100);
|
|
expect(cached.hourly).toHaveLength(1);
|
|
expect(cached.monthly).toHaveLength(1);
|
|
});
|
|
|
|
it('startCliproxySync is idempotent and starts only one interval', async () => {
|
|
const intervalSpy = spyOn(globalThis, 'setInterval');
|
|
|
|
await runWithScopedConfigDir(ccsDir, async () => {
|
|
syncer.startCliproxySync();
|
|
syncer.startCliproxySync();
|
|
});
|
|
|
|
expect(intervalSpy).toHaveBeenCalledTimes(1);
|
|
expect(fetchCalls).toBeGreaterThan(0);
|
|
|
|
syncer.stopCliproxySync();
|
|
intervalSpy.mockRestore();
|
|
});
|
|
});
|