Files
OmniRoute/tests/unit/executor-cursor-extended.test.mjs
diegosouzapw 592ca9b5c4 fix: remove hardcoded localhost default arg from GET /api/keys, unify coverage to single coverage/ dir, fix test to pass explicit Request
- Remove `new Request('http://localhost/api/keys')` default arg from GET handler in src/app/api/keys/route.ts (line 26)
- Fix api-key-reveal-route.test.mjs to pass explicit Request instead of calling GET() with no args
- Add --output-dir coverage to all c8 scripts in package.json
- Add coverage.reportsDirectory: 'coverage' to vitest.config.ts and vitest.mcp.config.ts
- Fix CHANGELOG.md structure (# Changelog + [Unreleased] to top)
- Remove 30+ stale coverage-* directories from project root
- Coverage: Statements 78.76% | Branches 72.75% | Functions 80.93% | Lines 78.76% (all thresholds passed)
2026-04-05 23:21:08 -03:00

321 lines
9.9 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { CursorExecutor } from "../../open-sse/executors/cursor.ts";
import {
decodeMessage,
encodeField,
parseConnectRPCFrame,
wrapConnectRPCFrame,
} from "../../open-sse/utils/cursorProtobuf.ts";
import {
generateCursorChecksum,
generateHashed64Hex,
generateSessionId,
} from "../../open-sse/utils/cursorChecksum.ts";
const LEN = 2;
const VARINT = 0;
const TOP_LEVEL_TOOL_CALL = 1;
const TOP_LEVEL_RESPONSE = 2;
const RESPONSE_TEXT = 1;
const TOOL_ID = 3;
const TOOL_NAME = 9;
const TOOL_RAW_ARGS = 10;
const TOOL_IS_LAST = 11;
function concatArrays(...arrays) {
const total = arrays.reduce((sum, array) => sum + array.length, 0);
const result = new Uint8Array(total);
let offset = 0;
for (const array of arrays) {
result.set(array, offset);
offset += array.length;
}
return result;
}
function buildTextFrame(text) {
return Buffer.from(
wrapConnectRPCFrame(
encodeField(TOP_LEVEL_RESPONSE, LEN, encodeField(RESPONSE_TEXT, LEN, text)),
false
)
);
}
function buildToolCallFrame({ id, name, args, isLast }) {
return Buffer.from(
wrapConnectRPCFrame(
encodeField(
TOP_LEVEL_TOOL_CALL,
LEN,
concatArrays(
encodeField(TOOL_ID, LEN, id),
encodeField(TOOL_NAME, LEN, name),
encodeField(TOOL_RAW_ARGS, LEN, args),
encodeField(TOOL_IS_LAST, VARINT, isLast ? 1 : 0)
)
),
false
)
);
}
function buildJsonErrorFrame(error) {
return Buffer.from(wrapConnectRPCFrame(new TextEncoder().encode(JSON.stringify(error)), false));
}
test("CursorExecutor.buildUrl uses the configured Cursor endpoint", () => {
const executor = new CursorExecutor();
assert.equal(
executor.buildUrl(),
"https://api2.cursor.sh/aiserver.v1.ChatService/StreamUnifiedChatWithTools"
);
});
test("CursorExecutor.buildHeaders strips token prefixes and derives checksum/session headers", () => {
const executor = new CursorExecutor();
const originalDateNow = Date.now;
Date.now = () => 1_700_000_000_000;
try {
const headers = executor.buildHeaders({
accessToken: "prefix::real-token",
providerSpecificData: { machineId: "machine-1", ghostMode: false },
});
assert.equal(headers.authorization, "Bearer real-token");
assert.equal(headers["x-client-key"], generateHashed64Hex("real-token"));
assert.equal(headers["x-session-id"], generateSessionId("real-token"));
assert.equal(headers["x-cursor-checksum"], generateCursorChecksum("machine-1"));
assert.equal(headers["x-ghost-mode"], "false");
assert.equal(headers["connect-protocol-version"], "1");
assert.match(headers["x-amzn-trace-id"], /^Root=/);
assert.ok(headers["x-request-id"]);
} finally {
Date.now = originalDateNow;
}
});
test("CursorExecutor.buildHeaders requires a machine ID", () => {
const executor = new CursorExecutor();
assert.throws(
() => executor.buildHeaders({ accessToken: "real-token", providerSpecificData: {} }),
/Machine ID is required/
);
});
test("CursorExecutor.transformRequest produces a framed protobuf payload", () => {
const executor = new CursorExecutor();
const transformed = executor.transformRequest(
"claude-3.5-sonnet",
{ messages: [{ role: "user", content: "Hello" }], tools: [] },
true,
{}
);
const frame = parseConnectRPCFrame(transformed);
const fields = decodeMessage(frame.payload);
assert.ok(transformed instanceof Uint8Array);
assert.equal(frame.flags, 0);
assert.equal(frame.consumed, transformed.length);
assert.equal(fields.has(1), true);
});
test("CursorExecutor.transformProtobufToJSON aggregates text and split tool call arguments", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const buffer = Buffer.concat([
buildTextFrame("Hello "),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '{"path":',
isLast: false,
}),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '"/tmp/a"}',
isLast: true,
}),
]);
const response = executor.transformProtobufToJSON(buffer, "cursor-small", body);
const payload = await response.json();
assert.equal(response.status, 200);
assert.equal(payload.object, "chat.completion");
assert.equal(payload.model, "cursor-small");
assert.equal(payload.choices[0].message.content, "Hello ");
assert.equal(payload.choices[0].finish_reason, "tool_calls");
assert.equal(payload.choices[0].message.tool_calls[0].function.name, "read_file");
assert.equal(payload.choices[0].message.tool_calls[0].function.arguments, '{"path":"/tmp/a"}');
assert.equal(payload.usage.estimated, true);
});
test("CursorExecutor.transformProtobufToSSE emits assistant chunks, tool deltas and DONE marker", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const buffer = Buffer.concat([
buildTextFrame("Hello "),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '{"path":',
isLast: false,
}),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '"/tmp/a"}',
isLast: true,
}),
]);
const response = executor.transformProtobufToSSE(buffer, "cursor-small", body);
const text = await response.text();
assert.equal(response.status, 200);
assert.equal(response.headers.get("Content-Type"), "text/event-stream");
assert.match(text, /"role":"assistant","content":"Hello "/);
assert.match(text, /"tool_calls":\[/);
assert.match(text, /"name":"read_file"/);
assert.match(text, /"finish_reason":"tool_calls"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.transformProtobufToSSE converts JSON error frames into rate-limit responses", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(
buildJsonErrorFrame({
error: {
code: "resource_exhausted",
message: "rate limited",
details: [{ debug: { error: "LIMIT", details: { title: "Limit", detail: "Slow down" } } }],
},
}),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const payload = await response.json();
assert.equal(response.status, 429);
assert.equal(payload.error.type, "rate_limit_error");
assert.equal(payload.error.message, "Limit");
assert.equal(payload.error.code, "LIMIT");
});
test("CursorExecutor.execute returns transformed JSON for non-stream responses", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const responseBuffer = Buffer.concat([buildTextFrame("Hello from Cursor")]);
executor.makeHttp2Request = async () => ({
status: 200,
headers: {},
body: responseBuffer,
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = await result.response.json();
assert.equal(
result.url,
"https://api2.cursor.sh/aiserver.v1.ChatService/StreamUnifiedChatWithTools"
);
assert.equal(result.transformedBody, body);
assert.equal(result.headers.authorization, "Bearer token");
assert.equal(payload.object, "chat.completion");
assert.equal(payload.choices[0].message.content, "Hello from Cursor");
assert.equal(payload.choices[0].finish_reason, "stop");
});
test("CursorExecutor.execute returns transformed SSE for stream responses", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const responseBuffer = Buffer.concat([buildTextFrame("Hello stream")]);
executor.makeHttp2Request = async () => ({
status: 200,
headers: {},
body: responseBuffer,
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: true,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const text = await result.response.text();
assert.equal(result.response.status, 200);
assert.match(text, /"content":"Hello stream"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.execute maps non-200 upstream responses to OpenAI-style errors", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
executor.makeHttp2Request = async () => ({
status: 403,
headers: {},
body: Buffer.from("denied"),
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = await result.response.json();
assert.equal(result.response.status, 403);
assert.equal(payload.error.type, "invalid_request_error");
assert.match(payload.error.message, /\[403\]: denied/);
});
test("CursorExecutor.execute maps transport failures to connection_error and refreshCredentials returns null", async () => {
const executor = new CursorExecutor();
executor.makeHttp2Request = async () => {
throw new Error("socket hang up");
};
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = await result.response.json();
assert.equal(result.response.status, 500);
assert.equal(payload.error.type, "connection_error");
assert.equal(payload.error.message, "socket hang up");
assert.equal(await executor.refreshCredentials(), null);
});