Files
OmniRoute/tests/unit/search-route.test.ts
diegosouzapw dc6d9e2e4b feat(core): add payload rules, tag routing, and scheduled budgets
Introduce runtime-configurable payload mutation/filter rules with file
reload support and a settings API so upstream request bodies can be
customized per model and protocol without restarts.

Expand search support with Google PSE, Linkup, SearchAPI, and SearXNG,
including validation, routing, analytics costing, MCP schema updates,
and search-type-aware provider selection. Update Pollinations to support
anonymous access, endpoint failover, and the latest public model lineup.

Add OmniRoute response metadata headers/SSE comments, per-connection
model exclusion rules, combo tag-based routing, buffered spend writes,
and scheduled daily/weekly/monthly budget resets. Update model catalog
and dashboard UIs to surface source labels and hide models excluded by
all active connections.
2026-04-17 09:00:32 -03:00

179 lines
5.2 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-search-route-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const searchRoute = await import("../../src/app/api/v1/search/route.ts");
async function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
async function seedConnection(
provider: string,
overrides: {
apiKey?: string | null;
authType?: string;
providerSpecificData?: Record<string, unknown>;
} = {}
) {
return providersDb.createProviderConnection({
provider,
authType: overrides.authType || "apikey",
name: `${provider}-${Math.random().toString(16).slice(2, 8)}`,
apiKey: overrides.apiKey ?? "test-key",
isActive: true,
testStatus: "active",
providerSpecificData: overrides.providerSpecificData || {},
});
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("v1 search GET lists all 9 search providers", async () => {
const response = await searchRoute.GET();
const body = await response.json();
const ids = body.data.map((item: { id: string }) => item.id);
assert.equal(response.status, 200);
assert.equal(body.object, "list");
assert.equal(body.data.length, 9);
assert.deepEqual(ids, [
"serper-search",
"brave-search",
"perplexity-search",
"exa-search",
"tavily-search",
"google-pse-search",
"linkup-search",
"searchapi-search",
"searxng-search",
]);
});
test("v1 search POST uses stored Linkup credentials and returns normalized results", async () => {
await seedConnection("linkup-search", { apiKey: "linkup-key" });
const originalFetch = globalThis.fetch;
let capturedUrl = "";
let capturedInit: RequestInit | undefined;
globalThis.fetch = async (url, init = {}) => {
capturedUrl = String(url);
capturedInit = init;
return new Response(
JSON.stringify({
results: [
{
name: "Linkup result",
url: "https://example.com/article",
content: "Linkup snippet",
type: "web",
},
],
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
};
try {
const response = await searchRoute.POST(
new Request("http://localhost/api/v1/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: "omniroute linkup",
provider: "linkup-search",
max_results: 1,
search_type: "web",
}),
})
);
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(capturedUrl, "https://api.linkup.so/v1/search");
assert.equal(
(capturedInit?.headers as Record<string, string>).Authorization,
"Bearer linkup-key"
);
assert.equal(body.provider, "linkup-search");
assert.equal(body.query, "omniroute linkup");
assert.equal(body.results.length, 1);
assert.equal(body.results[0].title, "Linkup result");
assert.equal(body.results[0].snippet, "Linkup snippet");
assert.equal(body.results[0].citation.provider, "linkup-search");
assert.equal(body.cached, false);
assert.equal(body.usage.queries_used, 1);
} finally {
globalThis.fetch = originalFetch;
}
});
test("v1 search POST accepts authless SearXNG with provider_options baseUrl", async () => {
const originalFetch = globalThis.fetch;
let capturedUrl = "";
globalThis.fetch = async (url) => {
capturedUrl = String(url);
return new Response(
JSON.stringify({
results: [
{
title: "SearXNG result",
url: "https://searx.example/result",
content: "Self-hosted response",
engines: ["duckduckgo"],
},
],
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
};
try {
const response = await searchRoute.POST(
new Request("http://localhost/api/v1/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: "self hosted meta search",
provider: "searxng-search",
search_type: "news",
provider_options: {
baseUrl: "http://127.0.0.1:9090/custom-search",
},
}),
})
);
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(
capturedUrl,
"http://127.0.0.1:9090/custom-search/search?q=self+hosted+meta+search&format=json&categories=news"
);
assert.equal(body.provider, "searxng-search");
assert.equal(body.results[0].title, "SearXNG result");
assert.equal(body.results[0].citation.provider, "searxng-search");
} finally {
globalThis.fetch = originalFetch;
}
});