mirror of
https://github.com/musistudio/claude-code-router.git
synced 2026-11-05 09:11:29 +08:00
114 lines
3.1 KiB
TypeScript
114 lines
3.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import {
|
|
buildRoutingRuleRows,
|
|
normalizeRouteScriptSampleRequest,
|
|
normalizeRouterRules
|
|
} from "@ccr/ui/pages/home/shared/routing.ts";
|
|
import {
|
|
createRoutingRuleDraft,
|
|
createRoutingRuleDraftFromRule,
|
|
isRoutingRuleDraftSubmittable
|
|
} from "@ccr/ui/pages/home/shared/providers.ts";
|
|
import { appConfigFixture } from "../fixtures/index.ts";
|
|
|
|
test("global routing rows omit Claude Code and Codex built-in profile routes", () => {
|
|
const config = appConfigFixture();
|
|
config.profile.profiles = [
|
|
{
|
|
agent: "claude-code",
|
|
enabled: true,
|
|
id: "claude",
|
|
model: "Provider/claude-sonnet",
|
|
name: "Claude",
|
|
scope: "ccr"
|
|
},
|
|
{
|
|
agent: "codex",
|
|
enabled: true,
|
|
id: "codex",
|
|
model: "uuroute/gpt-5.5",
|
|
name: "Codex",
|
|
scope: "ccr"
|
|
}
|
|
];
|
|
|
|
assert.deepEqual(buildRoutingRuleRows(config), []);
|
|
});
|
|
|
|
test("routing UI preserves the Node.js script file and timeout", () => {
|
|
const rules = normalizeRouterRules([{
|
|
enabled: true,
|
|
id: "node-script",
|
|
name: "Node script",
|
|
script: {
|
|
apiVersion: 1,
|
|
file: "/tmp/route-script.js",
|
|
language: "javascript",
|
|
permissions: {
|
|
environment: ["ROUTER_TOKEN"],
|
|
filesystem: { read: ["~/.config/router"], write: ["~/.cache/router"] },
|
|
network: ["https://api.example.com/v1"]
|
|
},
|
|
readPaths: ["request.body.metadata"],
|
|
timeoutMs: 3500
|
|
},
|
|
type: "script"
|
|
}]);
|
|
|
|
assert.equal(rules?.[0]?.type, "script");
|
|
const draft = createRoutingRuleDraftFromRule(rules![0]);
|
|
assert.equal(draft.type, "script");
|
|
assert.equal(draft.scriptFile, "/tmp/route-script.js");
|
|
assert.equal(draft.scriptTimeoutMs, "3500");
|
|
assert.deepEqual(draft.rewrites, []);
|
|
assert.deepEqual(rules?.[0]?.script, {
|
|
apiVersion: 1,
|
|
file: "/tmp/route-script.js",
|
|
language: "javascript",
|
|
timeoutMs: 3500
|
|
});
|
|
});
|
|
|
|
test("script routing drafts do not depend on request rewrite rows", () => {
|
|
const draft = createRoutingRuleDraft();
|
|
draft.name = "Script";
|
|
draft.type = "script";
|
|
draft.scriptFile = "/tmp/route-script.js";
|
|
draft.rewrites = [];
|
|
assert.equal(isRoutingRuleDraftSubmittable(draft), true);
|
|
|
|
draft.rewrites = [{
|
|
id: "incomplete",
|
|
key: "request.body.temperature",
|
|
match: "",
|
|
operation: "set",
|
|
value: ""
|
|
}];
|
|
assert.equal(isRoutingRuleDraftSubmittable(draft), true);
|
|
});
|
|
|
|
test("route script test JSON accepts request headers and body together", () => {
|
|
assert.deepEqual(normalizeRouteScriptSampleRequest({
|
|
body: { messages: [{ role: "user", content: "hello" }], model: "Provider/alpha" },
|
|
headers: {
|
|
authorization: "Bearer test",
|
|
"x-tags": ["one", "two"]
|
|
},
|
|
method: "POST",
|
|
url: "/v1/messages"
|
|
}), {
|
|
body: { messages: [{ role: "user", content: "hello" }], model: "Provider/alpha" },
|
|
headers: {
|
|
authorization: "Bearer test",
|
|
"x-tags": ["one", "two"]
|
|
},
|
|
method: "POST",
|
|
url: "/v1/messages"
|
|
});
|
|
assert.throws(
|
|
() => normalizeRouteScriptSampleRequest({ body: {}, headers: { invalid: 123 } }),
|
|
/headers/i
|
|
);
|
|
});
|