mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-03 20:21:54 +00:00
fix(cliproxy): probe routing via management endpoint
This commit is contained in:
@@ -20,6 +20,7 @@ import type { CliproxyRoutingStrategy } from './types';
|
|||||||
|
|
||||||
/** Default timeout for management operations (longer than health check) */
|
/** Default timeout for management operations (longer than health check) */
|
||||||
const DEFAULT_TIMEOUT_MS = 5000;
|
const DEFAULT_TIMEOUT_MS = 5000;
|
||||||
|
const ROUTING_STRATEGY_PATH = '/v0/management/routing/strategy';
|
||||||
|
|
||||||
/** Default port for HTTPS protocol */
|
/** Default port for HTTPS protocol */
|
||||||
const DEFAULT_HTTPS_PORT = 443;
|
const DEFAULT_HTTPS_PORT = 443;
|
||||||
@@ -232,7 +233,7 @@ export class ManagementApiClient {
|
|||||||
* Get the global credential routing strategy from CLIProxy.
|
* Get the global credential routing strategy from CLIProxy.
|
||||||
*/
|
*/
|
||||||
async getRoutingStrategy(): Promise<CliproxyRoutingStrategy> {
|
async getRoutingStrategy(): Promise<CliproxyRoutingStrategy> {
|
||||||
const response = await this.request<{ strategy?: string }>('GET', '/routing/strategy');
|
const response = await this.request<{ strategy?: string }>('GET', ROUTING_STRATEGY_PATH);
|
||||||
return response.data?.strategy === 'fill-first' ? 'fill-first' : 'round-robin';
|
return response.data?.strategy === 'fill-first' ? 'fill-first' : 'round-robin';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ export class ManagementApiClient {
|
|||||||
* Update the global credential routing strategy on CLIProxy.
|
* Update the global credential routing strategy on CLIProxy.
|
||||||
*/
|
*/
|
||||||
async putRoutingStrategy(strategy: CliproxyRoutingStrategy): Promise<CliproxyRoutingStrategy> {
|
async putRoutingStrategy(strategy: CliproxyRoutingStrategy): Promise<CliproxyRoutingStrategy> {
|
||||||
await this.request('PUT', '/routing/strategy', { value: strategy });
|
await this.request('PUT', ROUTING_STRATEGY_PATH, { value: strategy });
|
||||||
return strategy;
|
return strategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import {
|
|||||||
} from './proxy-target-resolver';
|
} from './proxy-target-resolver';
|
||||||
|
|
||||||
const ROUTING_TIMEOUT_MS = 5000;
|
const ROUTING_TIMEOUT_MS = 5000;
|
||||||
|
const CLIPROXY_ROUTING_MANAGEMENT_PATH = '/v0/management/routing/strategy';
|
||||||
|
|
||||||
export async function fetchCliproxyRoutingResponse(
|
export async function fetchCliproxyRoutingResponse(
|
||||||
target: ProxyTarget,
|
target: ProxyTarget,
|
||||||
method: 'GET' | 'PUT',
|
method: 'GET' | 'PUT',
|
||||||
body?: Record<string, string>
|
body?: Record<string, string>
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const url = buildProxyUrl(target, '/routing/strategy');
|
const url = buildProxyUrl(target, CLIPROXY_ROUTING_MANAGEMENT_PATH);
|
||||||
const headers = buildManagementHeaders(
|
const headers = buildManagementHeaders(
|
||||||
target,
|
target,
|
||||||
body ? { 'Content-Type': 'application/json' } : {}
|
body ? { 'Content-Type': 'application/json' } : {}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ describe('management-api-client', () => {
|
|||||||
|
|
||||||
expect(strategy).toBe('round-robin');
|
expect(strategy).toBe('round-robin');
|
||||||
expect(fetchMock).toHaveBeenCalledWith(
|
expect(fetchMock).toHaveBeenCalledWith(
|
||||||
'http://localhost:8317/routing/strategy',
|
'http://localhost:8317/v0/management/routing/strategy',
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify({ value: 'round-robin' }),
|
body: JSON.stringify({ value: 'round-robin' }),
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { afterEach, describe, expect, it, mock } from 'bun:test';
|
||||||
|
import { fetchCliproxyRoutingResponse } from '../../../src/cliproxy/routing-strategy-http';
|
||||||
|
import type { ProxyTarget } from '../../../src/cliproxy/proxy-target-resolver';
|
||||||
|
|
||||||
|
describe('routing-strategy-http', () => {
|
||||||
|
const target: ProxyTarget = {
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 8317,
|
||||||
|
protocol: 'http',
|
||||||
|
isRemote: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mock.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reads the routing strategy from the management endpoint', async () => {
|
||||||
|
const originalFetch = global.fetch;
|
||||||
|
const fetchMock = mock(() =>
|
||||||
|
Promise.resolve(
|
||||||
|
new Response(JSON.stringify({ strategy: 'round-robin' }), {
|
||||||
|
status: 200,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
global.fetch = fetchMock as typeof global.fetch;
|
||||||
|
|
||||||
|
await fetchCliproxyRoutingResponse(target, 'GET');
|
||||||
|
|
||||||
|
expect(fetchMock).toHaveBeenCalledWith(
|
||||||
|
'http://127.0.0.1:8317/v0/management/routing/strategy',
|
||||||
|
expect.objectContaining({
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
global.fetch = originalFetch;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('writes the routing strategy to the management endpoint', async () => {
|
||||||
|
const originalFetch = global.fetch;
|
||||||
|
const fetchMock = mock(() =>
|
||||||
|
Promise.resolve(
|
||||||
|
new Response(JSON.stringify({ ok: true }), {
|
||||||
|
status: 200,
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
global.fetch = fetchMock as typeof global.fetch;
|
||||||
|
|
||||||
|
await fetchCliproxyRoutingResponse(target, 'PUT', { value: 'fill-first' });
|
||||||
|
|
||||||
|
expect(fetchMock).toHaveBeenCalledWith(
|
||||||
|
'http://127.0.0.1:8317/v0/management/routing/strategy',
|
||||||
|
expect.objectContaining({
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({ value: 'fill-first' }),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
global.fetch = originalFetch;
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user