mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 08:17:11 +00:00
fix: stabilize validate pipeline and cliproxy route tests
This commit is contained in:
+2
-2
@@ -71,8 +71,8 @@
|
||||
"verify:bundle": "node scripts/verify-bundle.js",
|
||||
"test": "bun run build && bun run test:all",
|
||||
"test:ci": "bun run test:all",
|
||||
"test:all": "bun test tests/unit tests/integration tests/npm",
|
||||
"test:unit": "bun test tests/unit/",
|
||||
"test:all": "node scripts/run-tests-serial.js tests/unit tests/integration tests/npm",
|
||||
"test:unit": "node scripts/run-tests-serial.js tests/unit",
|
||||
"test:npm": "bun test tests/npm/",
|
||||
"test:native": "bash tests/native/unix/edge-cases.sh",
|
||||
"test:e2e": "bun test tests/e2e/ --bail --timeout 60000",
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
const roots = process.argv.slice(2);
|
||||
const testRoots = roots.length > 0 ? roots : ['tests'];
|
||||
const testFilePattern = /(?:\.test|_test_|\.spec|_spec_)\.(?:[cm]?[jt]s)$/;
|
||||
|
||||
function collectTestFiles(rootDir) {
|
||||
if (!fs.existsSync(rootDir)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const stats = fs.statSync(rootDir);
|
||||
if (stats.isFile()) {
|
||||
return testFilePattern.test(path.basename(rootDir)) ? [rootDir] : [];
|
||||
}
|
||||
|
||||
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
||||
const files = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(rootDir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
files.push(...collectTestFiles(fullPath));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!entry.isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (testFilePattern.test(entry.name)) {
|
||||
files.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
const testFiles = [...new Set(testRoots.flatMap((rootDir) => collectTestFiles(rootDir)))].sort();
|
||||
|
||||
if (testFiles.length === 0) {
|
||||
console.error('No test files found.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (let index = 0; index < testFiles.length; index += 1) {
|
||||
const file = testFiles[index];
|
||||
console.log(`\n[${index + 1}/${testFiles.length}] ${file}`);
|
||||
const bunTestPath = path.isAbsolute(file) ? file : `./${file}`;
|
||||
|
||||
const result = spawnSync('bun', ['test', bunTestPath], {
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
process.exit(result.status ?? 1);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { CLIProxyProvider, ProviderModelMapping } from './types';
|
||||
import type { CLIProxyProvider, ProviderModelMapping } from './types';
|
||||
|
||||
/** Base settings file structure */
|
||||
interface BaseSettings {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
* Used by API routes, service layer, and config loader to avoid contract drift.
|
||||
*/
|
||||
|
||||
import { CLIPROXY_SUPPORTED_PROVIDERS, CompositeTierConfig } from '../config/unified-config-types';
|
||||
import { CLIPROXY_SUPPORTED_PROVIDERS } from '../config/unified-config-types';
|
||||
import type { CompositeTierConfig } from '../config/unified-config-types';
|
||||
import type { CLIProxyProvider } from './types';
|
||||
import { getDeniedModelIdReasonForProvider } from './model-id-normalizer';
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { CLIProxyProvider, ProviderModelMapping } from '../types';
|
||||
import type { CLIProxyProvider, ProviderModelMapping } from '../types';
|
||||
import { getModelMappingFromConfig, getEnvVarsFromConfig } from '../base-config-loader';
|
||||
import { getGlobalEnvConfig } from '../../config/unified-config-loader';
|
||||
import { getEffectiveApiKey } from '../auth-token-manager';
|
||||
import { expandPath } from '../../utils/helpers';
|
||||
import { warn } from '../../utils/ui';
|
||||
import { CompositeTierConfig } from '../../config/unified-config-types';
|
||||
import type { CompositeTierConfig } from '../../config/unified-config-types';
|
||||
import {
|
||||
validatePort,
|
||||
validateRemotePort,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* - Claude (Anthropic): Opt-in via --1m flag
|
||||
*/
|
||||
|
||||
import { CLIProxyProvider } from '../types';
|
||||
import type { CLIProxyProvider } from '../types';
|
||||
import { supportsExtendedContext } from '../model-catalog';
|
||||
import { warn } from '../../utils/ui';
|
||||
import {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { CLIProxyProvider, ProviderConfig } from '../types';
|
||||
import type { CLIProxyProvider, ProviderConfig } from '../types';
|
||||
import { getProviderDisplayName } from '../provider-capabilities';
|
||||
import { getModelMappingFromConfig } from '../base-config-loader';
|
||||
import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as path from 'path';
|
||||
import { getCcsDir } from '../../utils/config-manager';
|
||||
import { CLIProxyProvider } from '../types';
|
||||
import type { CLIProxyProvider } from '../types';
|
||||
import { CLIPROXY_DEFAULT_PORT } from './port-manager';
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
* Manages thinking budget suffixes for CLIProxyAPIPlus
|
||||
*/
|
||||
|
||||
import { CLIProxyProvider } from '../types';
|
||||
import { ThinkingConfig, DEFAULT_THINKING_TIER_DEFAULTS } from '../../config/unified-config-types';
|
||||
import type { CLIProxyProvider } from '../types';
|
||||
import { DEFAULT_THINKING_TIER_DEFAULTS } from '../../config/unified-config-types';
|
||||
import type { ThinkingConfig } from '../../config/unified-config-types';
|
||||
import { getThinkingConfig } from '../../config/unified-config-loader';
|
||||
import { supportsThinking } from '../model-catalog';
|
||||
import { isThinkingOffValue, validateThinking } from '../thinking-validator';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Models are mapped to their internal names used by the proxy backend.
|
||||
*/
|
||||
|
||||
import { CLIProxyProvider } from './types';
|
||||
import type { CLIProxyProvider } from './types';
|
||||
import {
|
||||
isAntigravityProvider,
|
||||
migrateDeniedAntigravityModelAliases,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* model version formats (e.g., 4.6 vs 4-6).
|
||||
*/
|
||||
|
||||
import { CLIProxyProvider } from './types';
|
||||
import type { CLIProxyProvider } from './types';
|
||||
|
||||
/** Env vars that carry model identifiers. */
|
||||
export const MODEL_ENV_VAR_KEYS = [
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
* - Warns when model doesn't support thinking
|
||||
*/
|
||||
|
||||
import { getModelThinkingSupport, ThinkingSupport } from './model-catalog';
|
||||
import { CLIProxyProvider } from './types';
|
||||
import { getModelThinkingSupport } from './model-catalog';
|
||||
import type { ThinkingSupport } from './model-catalog';
|
||||
import type { CLIProxyProvider } from './types';
|
||||
|
||||
/**
|
||||
* Thinking budget bounds (used for validation across API and CLI)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as os from 'os';
|
||||
|
||||
const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);
|
||||
const WILDCARD_HOSTS = new Set(['0.0.0.0', '::', '[::]']);
|
||||
const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1']);
|
||||
const WILDCARD_HOSTS = new Set(['0.0.0.0', '::']);
|
||||
|
||||
interface NetworkInterfaceCandidate {
|
||||
address: string;
|
||||
|
||||
@@ -10,7 +10,6 @@ import * as path from 'path';
|
||||
import * as yaml from 'js-yaml';
|
||||
import { getCcsDir } from '../utils/config-manager';
|
||||
import {
|
||||
UnifiedConfig,
|
||||
isUnifiedConfig,
|
||||
createEmptyUnifiedConfig,
|
||||
UNIFIED_CONFIG_VERSION,
|
||||
@@ -23,6 +22,9 @@ import {
|
||||
DEFAULT_THINKING_CONFIG,
|
||||
DEFAULT_DASHBOARD_AUTH_CONFIG,
|
||||
DEFAULT_IMAGE_ANALYSIS_CONFIG,
|
||||
} from './unified-config-types';
|
||||
import type {
|
||||
UnifiedConfig,
|
||||
CLIProxySafetyConfig,
|
||||
GlobalEnvConfig,
|
||||
ThinkingConfig,
|
||||
|
||||
+11
-9
@@ -1,4 +1,4 @@
|
||||
import { SpawnOptions as NodeSpawnOptions } from 'child_process';
|
||||
import type { SpawnOptions as NodeSpawnOptions } from 'child_process';
|
||||
|
||||
/**
|
||||
* CLI Runtime Types
|
||||
@@ -43,11 +43,13 @@ export interface ClaudeCliInfo {
|
||||
/**
|
||||
* Exit codes
|
||||
*/
|
||||
export enum ExitCode {
|
||||
SUCCESS = 0,
|
||||
GENERIC_ERROR = 1,
|
||||
CLAUDE_NOT_FOUND = 127,
|
||||
CONFIG_ERROR = 2,
|
||||
DELEGATION_ERROR = 3,
|
||||
TIMEOUT = 124,
|
||||
}
|
||||
export const ExitCode = {
|
||||
SUCCESS: 0,
|
||||
GENERIC_ERROR: 1,
|
||||
CLAUDE_NOT_FOUND: 127,
|
||||
CONFIG_ERROR: 2,
|
||||
DELEGATION_ERROR: 3,
|
||||
TIMEOUT: 124,
|
||||
} as const;
|
||||
|
||||
export type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];
|
||||
|
||||
+8
-6
@@ -9,12 +9,14 @@ export type { ErrorCode } from '../utils/error-codes';
|
||||
/**
|
||||
* Log levels
|
||||
*/
|
||||
export enum LogLevel {
|
||||
DEBUG = 'debug',
|
||||
INFO = 'info',
|
||||
WARN = 'warn',
|
||||
ERROR = 'error',
|
||||
}
|
||||
export const LogLevel = {
|
||||
DEBUG: 'debug',
|
||||
INFO: 'info',
|
||||
WARN: 'warn',
|
||||
ERROR: 'error',
|
||||
} as const;
|
||||
|
||||
export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
|
||||
|
||||
/**
|
||||
* Color codes (TTY-aware)
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import {
|
||||
Config,
|
||||
isConfig,
|
||||
Settings,
|
||||
isSettings,
|
||||
CLIProxyVariantsConfig,
|
||||
CLIProxyVariantConfig,
|
||||
} from '../types';
|
||||
import { isConfig, isSettings } from '../types';
|
||||
import type { Config, Settings, CLIProxyVariantsConfig, CLIProxyVariantConfig } from '../types';
|
||||
import { expandPath, error } from './helpers';
|
||||
import { info } from './ui';
|
||||
import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../config/unified-config-loader';
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import ProfileRegistry from '../../auth/profile-registry';
|
||||
import InstanceManager from '../../management/instance-manager';
|
||||
import { isUnifiedMode } from '../../config/unified-config-loader';
|
||||
import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
|
||||
import {
|
||||
getAllAccountsSummary,
|
||||
setDefaultAccount as setCliproxyDefault,
|
||||
@@ -30,12 +30,28 @@ import {
|
||||
parseCliproxyKey,
|
||||
type MergedAccountEntry,
|
||||
} from './account-route-helpers';
|
||||
import type { AccountConfig } from '../../config/unified-config-types';
|
||||
|
||||
const router = Router();
|
||||
const registry = new ProfileRegistry();
|
||||
const instanceMgr = new InstanceManager();
|
||||
|
||||
function createProfileRegistry(): ProfileRegistry {
|
||||
return new ProfileRegistry();
|
||||
}
|
||||
|
||||
function createInstanceManager(): InstanceManager {
|
||||
return new InstanceManager();
|
||||
}
|
||||
|
||||
function getUnifiedAccountsRaw(): Record<string, AccountConfig> {
|
||||
if (!isUnifiedMode()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return loadOrCreateUnifiedConfig().accounts;
|
||||
}
|
||||
|
||||
function hasAuthAccount(name: string): boolean {
|
||||
const registry = createProfileRegistry();
|
||||
return registry.hasAccountUnified(name) || registry.hasProfile(name);
|
||||
}
|
||||
|
||||
@@ -44,8 +60,11 @@ function hasAuthAccount(name: string): boolean {
|
||||
*/
|
||||
router.get('/', (_req: Request, res: Response): void => {
|
||||
try {
|
||||
const registry = createProfileRegistry();
|
||||
|
||||
// Get profiles from both legacy and unified config (same logic as CLI)
|
||||
const legacyProfiles = registry.getAllProfiles();
|
||||
const rawUnifiedAccounts = getUnifiedAccountsRaw();
|
||||
const unifiedAccounts = registry.getAllAccountsUnified();
|
||||
|
||||
// Get CLIProxy OAuth accounts (gemini, codex, agy, etc.)
|
||||
@@ -76,11 +95,12 @@ router.get('/', (_req: Request, res: Response): void => {
|
||||
|
||||
// Override with unified config accounts (takes precedence)
|
||||
for (const [name, account] of Object.entries(unifiedAccounts)) {
|
||||
const rawAccount = rawUnifiedAccounts[name];
|
||||
const contextPolicy = resolveAccountContextPolicy(account);
|
||||
const hasExplicitContextMode =
|
||||
account.context_mode === 'isolated' || account.context_mode === 'shared';
|
||||
rawAccount?.context_mode === 'isolated' || rawAccount?.context_mode === 'shared';
|
||||
const hasExplicitContinuityMode =
|
||||
account.continuity_mode === 'standard' || account.continuity_mode === 'deeper';
|
||||
rawAccount?.continuity_mode === 'standard' || rawAccount?.continuity_mode === 'deeper';
|
||||
merged[name] = {
|
||||
type: 'account',
|
||||
created: account.created,
|
||||
@@ -138,6 +158,7 @@ router.get('/', (_req: Request, res: Response): void => {
|
||||
*/
|
||||
router.post('/default', (req: Request, res: Response): void => {
|
||||
try {
|
||||
const registry = createProfileRegistry();
|
||||
const { name } = req.body;
|
||||
|
||||
if (!name) {
|
||||
@@ -175,6 +196,8 @@ router.post('/default', (req: Request, res: Response): void => {
|
||||
*/
|
||||
router.put('/:name/context', async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const registry = createProfileRegistry();
|
||||
const instanceMgr = createInstanceManager();
|
||||
const { name } = req.params;
|
||||
|
||||
if (!name) {
|
||||
@@ -310,6 +333,7 @@ router.put('/:name/context', async (req: Request, res: Response): Promise<void>
|
||||
*/
|
||||
router.delete('/reset-default', (_req: Request, res: Response): void => {
|
||||
try {
|
||||
const registry = createProfileRegistry();
|
||||
if (isUnifiedMode()) {
|
||||
registry.clearDefaultUnified();
|
||||
} else {
|
||||
@@ -326,6 +350,8 @@ router.delete('/reset-default', (_req: Request, res: Response): void => {
|
||||
*/
|
||||
router.delete('/:name', async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const registry = createProfileRegistry();
|
||||
const instanceMgr = createInstanceManager();
|
||||
const { name } = req.params;
|
||||
|
||||
if (!name) {
|
||||
|
||||
@@ -90,6 +90,6 @@ describe('buildClaudeEnvironment - composite remote routing', () => {
|
||||
expect(env.ANTHROPIC_MODEL).toMatch(/^claude-opus-4-6-thinking(\([^)]+\))?$/);
|
||||
expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toMatch(/^claude-opus-4-6-thinking(\([^)]+\))?$/);
|
||||
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toMatch(/^gemini-2.5-pro(\([^)]+\))?$/);
|
||||
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5.1-codex-mini');
|
||||
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toMatch(/^gpt-5.1-codex-mini(?:-medium)?$/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,18 +14,30 @@ import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import type { Server } from 'http';
|
||||
import claudeExtensionRoutes from '../../../src/web-server/routes/claude-extension-routes';
|
||||
import SharedManager from '../../../src/management/shared-manager';
|
||||
import { createEmptyUnifiedConfig } from '../../../src/config/unified-config-types';
|
||||
import { saveUnifiedConfig } from '../../../src/config/unified-config-loader';
|
||||
|
||||
describe('web-server claude-extension-routes', () => {
|
||||
let server: Server;
|
||||
let baseUrl = '';
|
||||
let tempHome = '';
|
||||
let originalCcsHome: string | undefined;
|
||||
let originalClaudeConfigDir: string | undefined;
|
||||
let setGlobalConfigDir: (dir: string | undefined) => void;
|
||||
let claudeExtensionRoutes: ReturnType<typeof express.Router>;
|
||||
let SharedManager: typeof import('../../../src/management/shared-manager').default;
|
||||
let createEmptyUnifiedConfig: typeof import('../../../src/config/unified-config-types').createEmptyUnifiedConfig;
|
||||
let saveUnifiedConfig: typeof import('../../../src/config/unified-config-loader').saveUnifiedConfig;
|
||||
|
||||
beforeAll(async () => {
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
originalClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
||||
({ setGlobalConfigDir } = await import('../../../src/utils/config-manager'));
|
||||
({ default: SharedManager } = await import('../../../src/management/shared-manager'));
|
||||
({ createEmptyUnifiedConfig } = await import('../../../src/config/unified-config-types'));
|
||||
({ saveUnifiedConfig } = await import('../../../src/config/unified-config-loader'));
|
||||
({ default: claudeExtensionRoutes } = await import(
|
||||
'../../../src/web-server/routes/claude-extension-routes'
|
||||
));
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use('/api/claude-extension', claudeExtensionRoutes);
|
||||
@@ -49,12 +61,20 @@ describe('web-server claude-extension-routes', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
setGlobalConfigDir(undefined);
|
||||
|
||||
if (originalCcsHome !== undefined) process.env.CCS_HOME = originalCcsHome;
|
||||
else delete process.env.CCS_HOME;
|
||||
|
||||
if (originalClaudeConfigDir !== undefined) process.env.CLAUDE_CONFIG_DIR = originalClaudeConfigDir;
|
||||
else delete process.env.CLAUDE_CONFIG_DIR;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-claude-extension-routes-'));
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
process.env.CCS_HOME = tempHome;
|
||||
process.env.CLAUDE_CONFIG_DIR = path.join(tempHome, '.claude');
|
||||
setGlobalConfigDir(path.join(tempHome, '.ccs'));
|
||||
|
||||
const ccsDir = path.join(tempHome, '.ccs');
|
||||
fs.mkdirSync(ccsDir, { recursive: true });
|
||||
@@ -110,9 +130,9 @@ describe('web-server claude-extension-routes', () => {
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
|
||||
if (originalCcsHome !== undefined) process.env.CCS_HOME = originalCcsHome;
|
||||
else delete process.env.CCS_HOME;
|
||||
setGlobalConfigDir(undefined);
|
||||
delete process.env.CCS_HOME;
|
||||
delete process.env.CLAUDE_CONFIG_DIR;
|
||||
|
||||
if (tempHome && fs.existsSync(tempHome)) {
|
||||
fs.rmSync(tempHome, { recursive: true, force: true });
|
||||
|
||||
@@ -7,12 +7,34 @@ const installSpy = {
|
||||
};
|
||||
|
||||
mock.module('../../../src/config/unified-config-loader', () => ({
|
||||
isUnifiedMode: () => true,
|
||||
loadUnifiedConfig: () => ({
|
||||
cliproxy: { backend: 'plus' },
|
||||
}),
|
||||
loadOrCreateUnifiedConfig: () => ({
|
||||
cliproxy: { backend: 'plus' },
|
||||
}),
|
||||
getGlobalEnvConfig: () => ({}),
|
||||
getThinkingConfig: () => ({
|
||||
mode: 'auto',
|
||||
tier_defaults: {
|
||||
opus: 'high',
|
||||
sonnet: 'high',
|
||||
haiku: 'medium',
|
||||
},
|
||||
provider_overrides: {},
|
||||
show_warnings: true,
|
||||
}),
|
||||
getCliproxySafetyConfig: () => ({
|
||||
antigravity_ack_bypass: false,
|
||||
}),
|
||||
saveUnifiedConfig: () => {},
|
||||
}));
|
||||
|
||||
mock.module('../../../src/cliproxy/binary-manager', () => ({
|
||||
ensureCLIProxyBinary: async () => '/tmp/cliproxy',
|
||||
isCLIProxyInstalled: () => true,
|
||||
getCLIProxyPath: () => '/tmp/cliproxy',
|
||||
checkCliproxyUpdate: async () => ({
|
||||
hasUpdate: false,
|
||||
currentVersion: '6.6.80',
|
||||
@@ -26,6 +48,7 @@ mock.module('../../../src/cliproxy/binary-manager', () => ({
|
||||
}),
|
||||
getInstalledCliproxyVersion: () => '6.6.80',
|
||||
installCliproxyVersion: async () => {},
|
||||
fetchLatestCliproxyVersion: async () => '6.6.89',
|
||||
}));
|
||||
|
||||
mock.module('../../../src/cliproxy/binary/version-checker', () => ({
|
||||
@@ -103,7 +126,9 @@ beforeEach(() => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
if (server) {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
}
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import type { Server } from 'http';
|
||||
import cliproxyStatsRoutes from '../../../src/web-server/routes/cliproxy-stats-routes';
|
||||
|
||||
function writeSettings(filePath: string, env: Record<string, string>): void {
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
@@ -16,8 +15,16 @@ describe('cliproxy-stats-routes model update canonicalization', () => {
|
||||
let baseUrl = '';
|
||||
let tempHome = '';
|
||||
let originalCcsHome: string | undefined;
|
||||
let setGlobalConfigDir: (dir: string | undefined) => void;
|
||||
let cliproxyStatsRoutes: ReturnType<typeof express.Router>;
|
||||
|
||||
beforeAll(async () => {
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
({ setGlobalConfigDir } = await import('../../../src/utils/config-manager'));
|
||||
({ default: cliproxyStatsRoutes } = await import(
|
||||
'../../../src/web-server/routes/cliproxy-stats-routes'
|
||||
));
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use('/api/cliproxy', cliproxyStatsRoutes);
|
||||
@@ -41,20 +48,24 @@ describe('cliproxy-stats-routes model update canonicalization', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
});
|
||||
setGlobalConfigDir(undefined);
|
||||
|
||||
beforeEach(() => {
|
||||
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-cliproxy-model-route-'));
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
process.env.CCS_HOME = tempHome;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalCcsHome !== undefined) {
|
||||
process.env.CCS_HOME = originalCcsHome;
|
||||
} else {
|
||||
delete process.env.CCS_HOME;
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-cliproxy-model-route-'));
|
||||
process.env.CCS_HOME = tempHome;
|
||||
setGlobalConfigDir(path.join(tempHome, '.ccs'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
setGlobalConfigDir(undefined);
|
||||
delete process.env.CCS_HOME;
|
||||
|
||||
if (tempHome && fs.existsSync(tempHome)) {
|
||||
fs.rmSync(tempHome, { recursive: true, force: true });
|
||||
|
||||
Reference in New Issue
Block a user