Files
OmniRoute/tests/unit/bailian-coding-plan-provider.test.ts
backryun 00677044be [Part 3/3] feat(qwen): add regional Alibaba and Qwen Cloud providers (#7882)
* feat(qwen): add Qwen3.8 Max Preview catalogs [Part 2/3]

Rebuilt clean on release/v3.8.49 after Part 1 (#7866) squash-merged — applies
only the Part-2 delta (Qwen Web / Qoder qwen3.8-max-preview registration +
required-thinking allowlist + Qoder client rework) onto the current tip. No
migration in this part (that was Part 1).

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* feat(qwen): add regional Alibaba and Qwen Cloud providers [Part 3/3]

Rebuilt clean on top of Part 2 (#7874) over the current release tip — applies
only the Part-3 delta (alibaba Model Studio, Alibaba Token Plan, qwen-cloud,
qwen-cloud-token-plan with region selector). No migration in this part.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-20 18:48:24 -03:00

687 lines
23 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
// Regular ESM imports — top-level await with dynamic import() races with
// --test-force-exit and emits "Promise resolution is still pending" failures
// in CI even though the module evaluation is well-formed.
import { APIKEY_PROVIDERS, OAUTH_PROVIDERS } from "../../src/shared/constants/providers.ts";
import { validateProviderApiKey } from "../../src/lib/providers/validation.ts";
import { BAILIAN_CODING_PLAN_MODELS } from "../../open-sse/config/providers/registry/bailian-coding-plan/index.ts";
import {
validateBody,
createProviderSchema,
updateProviderConnectionSchema,
} from "../../src/shared/validation/schemas.ts";
test("APIKEY_PROVIDERS includes bailian-coding-plan", () => {
assert.ok(
APIKEY_PROVIDERS["bailian-coding-plan"],
"bailian-coding-plan should be present in APIKEY_PROVIDERS"
);
const provider = APIKEY_PROVIDERS["bailian-coding-plan"];
assert.equal(provider.id, "bailian-coding-plan", "Provider id should be 'bailian-coding-plan'");
assert.equal(provider.alias, "bcp", "Provider alias should be 'bcp'");
assert.equal(provider.name, "Alibaba Token Plan");
});
test("bailian-coding-plan not in OAUTH_PROVIDERS", () => {
assert.equal(
OAUTH_PROVIDERS["bailian-coding-plan"],
undefined,
"bailian-coding-plan should NOT be present in OAUTH_PROVIDERS"
);
});
// Schema validation tests for providerSpecificData.baseUrl
const VALID_BAILIAN_URL = "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1";
test("createProviderSchema accepts valid baseUrl in providerSpecificData", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-test-key",
name: "Test Bailian",
providerSpecificData: {
baseUrl: VALID_BAILIAN_URL,
},
});
assert.equal(validation.success, true, "Should accept valid URL");
if (validation.success) {
assert.equal(
validation.data.providerSpecificData?.baseUrl,
VALID_BAILIAN_URL,
"Should preserve valid baseUrl"
);
}
});
test("createProviderSchema accepts missing providerSpecificData", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-test-key",
name: "Test Bailian",
});
assert.equal(validation.success, true, "Should accept without providerSpecificData");
});
test("createProviderSchema accepts empty providerSpecificData", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-test-key",
name: "Test Bailian",
providerSpecificData: {},
});
assert.equal(validation.success, true, "Should accept empty providerSpecificData");
});
test("createProviderSchema rejects invalid baseUrl in providerSpecificData", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-test-key",
name: "Test Bailian",
providerSpecificData: {
baseUrl: "not-a-valid-url",
},
});
assert.equal(validation.success, false, "Should reject invalid URL");
if (!validation.success && typeof validation.error === "object" && validation.error !== null) {
const errorObj = validation.error;
const details = Array.isArray(errorObj.details) ? errorObj.details : [];
const errorStr = details.map((d) => d.message || "").join(", ");
assert.ok(
errorStr.includes("baseUrl") && errorStr.includes("URL"),
`Error should mention baseUrl and URL. Got: ${errorStr}`
);
}
});
test("createProviderSchema rejects malformed baseUrl (no protocol)", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-test-key",
name: "Test Bailian",
providerSpecificData: {
baseUrl: "example.com/path",
},
});
assert.equal(validation.success, false, "Should reject URL without protocol");
});
test("createProviderSchema rejects baseUrl with non-string value", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-test-key",
name: "Test Bailian",
providerSpecificData: {
baseUrl: 12345,
},
});
assert.equal(validation.success, false, "Should reject non-string baseUrl");
});
test("createProviderSchema rejects non-boolean Codex context1m request default", () => {
const validation = validateBody(createProviderSchema, {
provider: "codex",
apiKey: "sk-test-key",
name: "Test Codex",
providerSpecificData: {
requestDefaults: {
context1m: "yes",
},
},
});
assert.equal(validation.success, false, "Should reject non-boolean context1m");
if (!validation.success && typeof validation.error === "object" && validation.error !== null) {
const details = Array.isArray(validation.error.details) ? validation.error.details : [];
assert.ok(
details.some((detail) => String(detail.message || "").includes("context1m")),
"Error should mention context1m"
);
}
});
test("updateProviderConnectionSchema accepts valid baseUrl in providerSpecificData", () => {
const validation = validateBody(updateProviderConnectionSchema, {
providerSpecificData: {
baseUrl: VALID_BAILIAN_URL,
},
});
assert.equal(validation.success, true, "Should accept valid URL");
if (validation.success) {
assert.equal(
validation.data.providerSpecificData?.baseUrl,
VALID_BAILIAN_URL,
"Should preserve valid baseUrl"
);
}
});
test("updateProviderConnectionSchema rejects invalid baseUrl in providerSpecificData", () => {
const validation = validateBody(updateProviderConnectionSchema, {
providerSpecificData: {
baseUrl: "invalid-url-abc",
},
});
assert.equal(validation.success, false, "Should reject invalid URL");
if (!validation.success && typeof validation.error === "object" && validation.error !== null) {
const errorObj = validation.error;
const details = Array.isArray(errorObj.details) ? errorObj.details : [];
const errorStr = details.map((d) => d.message || "").join(", ");
assert.ok(
errorStr.includes("baseUrl") && errorStr.includes("URL"),
`Error should mention baseUrl and URL. Got: ${errorStr}`
);
}
});
test("updateProviderConnectionSchema accepts partial update without baseUrl", () => {
const validation = validateBody(updateProviderConnectionSchema, {
name: "Updated Name",
priority: 5,
});
assert.equal(validation.success, true, "Should accept update without baseUrl");
});
test("updateProviderConnectionSchema rejects baseUrl with trailing garbage", () => {
const validation = validateBody(updateProviderConnectionSchema, {
providerSpecificData: {
baseUrl: "https://example.com not-a-url",
},
});
assert.equal(validation.success, false, "Should reject URL with trailing garbage");
});
test("updateProviderConnectionSchema accepts https protocol", () => {
const validation = validateBody(updateProviderConnectionSchema, {
providerSpecificData: {
baseUrl: "https://secure.example.com/v1",
},
});
assert.equal(validation.success, true, "Should accept https URL");
});
test("updateProviderConnectionSchema accepts http protocol", () => {
const validation = validateBody(updateProviderConnectionSchema, {
providerSpecificData: {
baseUrl: "http://localhost:3000/v1",
},
});
assert.equal(validation.success, true, "Should accept http URL");
});
// ============================================================================
// ROUTE-LEVEL TESTS: Static model listing behavior for bailian-coding-plan
// ============================================================================
// Import the exported helper function from the route
const { getStaticModelsForProvider } = await import("../../src/lib/providers/staticModels.ts");
test("getStaticModelsForProvider returns 6 models for bailian-coding-plan", () => {
const models = getStaticModelsForProvider("bailian-coding-plan");
assert.ok(models, "Should return models for bailian-coding-plan");
assert.ok(Array.isArray(models), "Should return an array");
assert.equal(models.length, 6, "Should return exactly 6 models");
});
test("getStaticModelsForProvider returns correct model IDs for bailian-coding-plan", () => {
const models = getStaticModelsForProvider("bailian-coding-plan");
if (!models) {
assert.fail("Models should not be undefined");
return;
}
const expectedIds = [
"qwen3.8-max-preview",
"qwen3.7-max",
"qwen3.7-plus",
"qwen3.6-flash",
"glm-5.2",
"deepseek-v4-pro",
];
const actualIds = models.map((m) => m.id);
assert.deepEqual(actualIds, expectedIds);
});
test("bailian-coding-plan models match the documented reasoning and vision capabilities", () => {
assert.deepEqual(
BAILIAN_CODING_PLAN_MODELS.map(({ id, supportsReasoning, supportsVision }) => ({
id,
supportsReasoning,
supportsVision: supportsVision === true,
})),
[
{ id: "qwen3.8-max-preview", supportsReasoning: true, supportsVision: true },
{ id: "qwen3.7-max", supportsReasoning: true, supportsVision: false },
{ id: "qwen3.7-plus", supportsReasoning: true, supportsVision: true },
{ id: "qwen3.6-flash", supportsReasoning: true, supportsVision: true },
{ id: "glm-5.2", supportsReasoning: true, supportsVision: false },
{ id: "deepseek-v4-pro", supportsReasoning: true, supportsVision: false },
]
);
});
test("getStaticModelsForProvider returns models with correct structure", () => {
const models = getStaticModelsForProvider("bailian-coding-plan");
if (!models) {
assert.fail("Models should not be undefined");
return;
}
for (const model of models) {
assert.ok(model.id, `Model should have id: ${JSON.stringify(model)}`);
assert.ok(model.name, `Model should have name: ${JSON.stringify(model)}`);
assert.equal(typeof model.id, "string", "Model id should be string");
assert.equal(typeof model.name, "string", "Model name should be string");
}
});
test("getStaticModelsForProvider returns undefined for non-static providers", () => {
const nonStaticProviders = ["anthropic", "deepseek", "unknown-provider"];
for (const provider of nonStaticProviders) {
const models = getStaticModelsForProvider(provider);
assert.equal(models, undefined, `Should return undefined for non-static provider: ${provider}`);
}
});
test("getStaticModelsForProvider returns local image catalogs for image-only providers", () => {
// nanobanana has IMAGE_PROVIDERS rows but no chat registry models — specialty
// must still surface them. Chat+image providers (xai/lmarena/openai) keep
// image models exclusively in IMAGE_PROVIDERS (not the chat specialty list).
const models = getStaticModelsForProvider("nanobanana");
assert.ok(models, "nanobanana should expose local image models");
assert.ok(models.length >= 1);
assert.ok(models.every((m) => m.supportedEndpoints?.includes("images")));
});
test("getStaticModelsForProvider does not dump IMAGE_PROVIDERS into chat specialty", () => {
for (const provider of ["lmarena", "openai", "xai"]) {
const models = getStaticModelsForProvider(provider) || [];
assert.ok(
!models.some((m) => m.supportedEndpoints?.includes("images")),
`${provider} chat specialty must not include image-only models`
);
}
const lmarena = getStaticModelsForProvider("lmarena") || [];
assert.ok(!lmarena.some((m) => String(m.id).includes("flux")));
});
test("getStaticModelsForProvider returns models for other static providers", () => {
// Verify other static providers still work
const staticProviders = ["deepgram", "assemblyai", "nanobanana", "perplexity"];
for (const provider of staticProviders) {
const models = getStaticModelsForProvider(provider);
assert.ok(models, `Should return models for static provider: ${provider}`);
assert.ok(models.length > 0, `Should return non-empty models for: ${provider}`);
}
});
test("getStaticModelsForProvider returns models matching registry for bailian-coding-plan", async () => {
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const models = getStaticModelsForProvider("bailian-coding-plan");
const registryEntry = REGISTRY["bailian-coding-plan"];
assert.ok(models, "Static models should be defined");
assert.ok(registryEntry, "Registry entry should exist");
const registryModels = registryEntry.models;
// Verify counts match
assert.equal(
models.length,
registryModels.length,
`Static model count (${models.length}) should match registry (${registryModels.length})`
);
// Verify all model IDs match
const staticIds = new Set(models.map((m) => m.id));
const registryIds = new Set(registryModels.map((m) => m.id));
assert.equal(staticIds.size, registryIds.size, "Should have same number of unique model IDs");
// Verify each model ID exists in both
for (const model of models) {
assert.ok(registryIds.has(model.id), `Registry should have model: ${model.id}`);
}
});
test("bailian-coding-plan static models have no duplicates", () => {
const models = getStaticModelsForProvider("bailian-coding-plan");
if (!models) {
assert.fail("Models should not be undefined");
return;
}
const ids = models.map((m) => m.id);
const uniqueIds = new Set(ids);
assert.equal(ids.length, uniqueIds.size, "All model IDs should be unique (no duplicates)");
});
test("bailian-coding-plan static models are complete and valid", () => {
const models = getStaticModelsForProvider("bailian-coding-plan");
if (!models) {
assert.fail("Models should not be undefined");
return;
}
// Verify array is not empty
assert.ok(models.length > 0, "Models array should not be empty");
// Verify no null/undefined entries
for (let i = 0; i < models.length; i++) {
assert.ok(models[i], `Model at index ${i} should not be null/undefined`);
}
// Verify no empty model IDs or names
for (const model of models) {
assert.ok(
model.id && model.id.trim().length > 0,
`Model ID should be non-empty: ${JSON.stringify(model)}`
);
assert.ok(
model.name && model.name.trim().length > 0,
`Model name should be non-empty: ${JSON.stringify(model)}`
);
}
});
// ============================================================================
// SCENARIO C TESTS: validateProviderApiKey for bailian-coding-plan
// These test the key validation outcomes with mocked fetch
// ============================================================================
test("validateProviderApiKey returns invalid for 401 response (bailian-coding-plan)", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 401,
headers: { "content-type": "application/json" },
});
try {
const result = await validateProviderApiKey({
provider: "bailian-coding-plan",
apiKey: "invalid-key",
providerSpecificData: {
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1",
},
});
assert.equal(result.valid, false, "Should return invalid for 401");
assert.equal(result.error, "Invalid API key", "Error should be 'Invalid API key'");
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateProviderApiKey returns invalid for 403 response (bailian-coding-plan)", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(JSON.stringify({ error: "Forbidden" }), {
status: 403,
headers: { "content-type": "application/json" },
});
try {
const result = await validateProviderApiKey({
provider: "bailian-coding-plan",
apiKey: "forbidden-key",
providerSpecificData: {
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1",
},
});
assert.equal(result.valid, false, "Should return invalid for 403");
assert.equal(result.error, "Invalid API key", "Error should be 'Invalid API key'");
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateProviderApiKey returns valid for 400 response (bailian-coding-plan)", async () => {
const originalFetch = globalThis.fetch;
// 400 means auth passed but request was malformed
// This is a valid auth path for bailian-coding-plan
globalThis.fetch = async () =>
new Response(JSON.stringify({ error: "invalid request" }), {
status: 400,
headers: { "content-type": "application/json" },
});
try {
const result = await validateProviderApiKey({
provider: "bailian-coding-plan",
apiKey: "valid-key",
providerSpecificData: {
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1",
},
});
assert.equal(
result.valid,
true,
"Should return valid for 400 (auth passed, request malformed)"
);
assert.equal(result.error, null, "Error should be null for valid auth");
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateProviderApiKey returns valid for 200 response (bailian-coding-plan)", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(JSON.stringify({ model: "qwen3-coder-plus" }), {
status: 200,
headers: { "content-type": "application/json" },
});
try {
const result = await validateProviderApiKey({
provider: "bailian-coding-plan",
apiKey: "valid-key",
providerSpecificData: {
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1",
},
});
assert.equal(result.valid, true, "Should return valid for 200");
assert.equal(result.error, null, "Error should be null for valid auth");
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateProviderApiKey returns invalid for 500 response (bailian-coding-plan)", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(JSON.stringify({ error: "upstream unavailable" }), {
status: 500,
headers: { "content-type": "application/json" },
});
try {
const result = await validateProviderApiKey({
provider: "bailian-coding-plan",
apiKey: "bad-key",
providerSpecificData: {
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1",
},
});
assert.equal(result.valid, false, "Should return invalid for 500");
assert.equal(result.error, "Validation failed: 500");
} finally {
globalThis.fetch = originalFetch;
}
});
test("validateProviderApiKey avoids double /messages suffix for bailian-coding-plan", async () => {
const originalFetch = globalThis.fetch;
const urls = [];
globalThis.fetch = async (url) => {
urls.push(String(url));
return new Response(JSON.stringify({ error: "invalid request" }), {
status: 400,
headers: { "content-type": "application/json" },
});
};
try {
const result = await validateProviderApiKey({
provider: "bailian-coding-plan",
apiKey: "valid-key",
providerSpecificData: {
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1/messages",
},
});
assert.equal(result.valid, true);
assert.equal(urls.length, 1);
assert.equal(
urls[0],
"https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1/messages",
"Should probe exactly one /messages suffix"
);
} finally {
globalThis.fetch = originalFetch;
}
});
// ============================================================================
// SCENARIO A TESTS: POST /api/providers create flow validation
// These test that the schema (used by POST route) accepts valid bailian data
// ============================================================================
test("POST /api/providers validation: bailian-coding-plan with baseUrl passes schema", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-placeholder-key",
name: "Test Bailian Provider",
providerSpecificData: {
baseUrl: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1",
},
});
assert.equal(validation.success, true, "Schema should accept valid bailian-coding-plan payload");
if (validation.success) {
assert.equal(validation.data.provider, "bailian-coding-plan");
assert.equal(
validation.data.providerSpecificData?.baseUrl,
"https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1"
);
}
});
test("POST /api/providers validation: bailian-coding-plan with custom baseUrl passes schema", () => {
const customUrl = "https://custom.dashscope.aliyuncs.com/apps/anthropic/v1";
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-another-placeholder",
name: "Custom Bailian",
providerSpecificData: {
baseUrl: customUrl,
},
});
assert.equal(validation.success, true, "Schema should accept custom baseUrl");
if (validation.success) {
assert.equal(validation.data.providerSpecificData?.baseUrl, customUrl);
}
});
test("POST /api/providers validation rejects non-http(s) baseUrl", () => {
const validation = validateBody(createProviderSchema, {
provider: "bailian-coding-plan",
apiKey: "sk-placeholder-key",
name: "Bad URL Scheme",
providerSpecificData: {
baseUrl: "ftp://example.com/v1",
},
});
assert.equal(validation.success, false, "Schema should reject non-http(s) URL schemes");
});
// ============================================================================
// SCENARIO B TESTS: PUT /api/providers/{id} update flow validation
// These test that the schema (used by PUT route) accepts valid baseUrl updates
// ============================================================================
test("PUT /api/providers/{id} validation: updating baseUrl passes schema", () => {
const validation = validateBody(updateProviderConnectionSchema, {
providerSpecificData: {
baseUrl: "https://updated.dashscope.aliyuncs.com/apps/anthropic/v1",
},
});
assert.equal(validation.success, true, "Schema should accept baseUrl update");
if (validation.success) {
assert.equal(
validation.data.providerSpecificData?.baseUrl,
"https://updated.dashscope.aliyuncs.com/apps/anthropic/v1"
);
}
});
test("PUT /api/providers/{id} validation: baseUrl update with other fields passes schema", () => {
const validation = validateBody(updateProviderConnectionSchema, {
name: "Updated Bailian Name",
priority: 5,
providerSpecificData: {
baseUrl: "https://new-url.example.com/v1",
},
});
assert.equal(
validation.success,
true,
"Schema should accept update with baseUrl and other fields"
);
if (validation.success) {
assert.equal(validation.data.name, "Updated Bailian Name");
assert.equal(validation.data.priority, 5);
assert.equal(validation.data.providerSpecificData?.baseUrl, "https://new-url.example.com/v1");
}
});
test("PUT /api/providers/{id} validation rejects non-http(s) baseUrl", () => {
const validation = validateBody(updateProviderConnectionSchema, {
providerSpecificData: {
baseUrl: "file:///etc/passwd",
},
});
assert.equal(validation.success, false, "Schema should reject non-http(s) URL schemes");
});