7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
146 lines
4.8 KiB
Python
146 lines
4.8 KiB
Python
"""
|
|
CI Integration tests for OpenAI-Compatible Endpoint.
|
|
|
|
These tests use real API calls to verify the custom endpoint URL handling works.
|
|
They require OPENROUTER_API_KEY to be set in the environment (available in CI).
|
|
|
|
REGRESSION TEST: This test would have caught the v1.3.10+ regression where
|
|
custom endpoint URLs were not being passed correctly to the OpenAI client.
|
|
"""
|
|
|
|
import os
|
|
import pytest
|
|
|
|
from local_deep_research.llm.providers.implementations.custom_openai_endpoint import (
|
|
CustomOpenAIEndpointProvider,
|
|
)
|
|
|
|
|
|
# Mark for tests that require the API key
|
|
requires_openrouter_key = pytest.mark.skipif(
|
|
not os.environ.get("OPENROUTER_API_KEY"),
|
|
reason="OPENROUTER_API_KEY not set - skipping CI integration tests",
|
|
)
|
|
|
|
|
|
@requires_openrouter_key
|
|
class TestCustomEndpointWithOpenRouter:
|
|
"""Integration tests using OpenRouter as a real OpenAI-compatible endpoint.
|
|
|
|
These tests verify that CustomOpenAIEndpointProvider correctly handles
|
|
custom URLs by actually connecting to OpenRouter's API.
|
|
"""
|
|
|
|
OPENROUTER_URL = "https://openrouter.ai/api/v1"
|
|
|
|
def test_fetch_models_from_openrouter(self):
|
|
"""Can fetch models from OpenRouter using custom endpoint.
|
|
|
|
REGRESSION TEST: This is the exact scenario that broke in v1.3.10+.
|
|
The custom URL was not being passed to the OpenAI client.
|
|
"""
|
|
api_key = os.environ.get("OPENROUTER_API_KEY")
|
|
|
|
# Use CustomOpenAIEndpointProvider with OpenRouter URL
|
|
models = CustomOpenAIEndpointProvider.list_models_for_api(
|
|
api_key=api_key,
|
|
base_url=self.OPENROUTER_URL,
|
|
)
|
|
|
|
# OpenRouter should return many models
|
|
assert isinstance(models, list)
|
|
assert len(models) > 0, (
|
|
"Should fetch at least one model from OpenRouter"
|
|
)
|
|
|
|
# Verify model format
|
|
for model in models[:5]: # Check first 5
|
|
assert "value" in model
|
|
assert "label" in model
|
|
assert isinstance(model["value"], str)
|
|
assert len(model["value"]) > 0
|
|
|
|
def test_models_include_known_providers(self):
|
|
"""OpenRouter models include known providers like OpenAI, Anthropic.
|
|
|
|
This verifies we're actually getting real model data.
|
|
"""
|
|
api_key = os.environ.get("OPENROUTER_API_KEY")
|
|
|
|
models = CustomOpenAIEndpointProvider.list_models_for_api(
|
|
api_key=api_key,
|
|
base_url=self.OPENROUTER_URL,
|
|
)
|
|
|
|
model_ids = [m["value"] for m in models]
|
|
|
|
# OpenRouter should have models from major providers
|
|
# Check for at least one of these patterns
|
|
has_known_model = any(
|
|
any(
|
|
provider in model_id
|
|
for provider in ["openai", "anthropic", "google", "meta"]
|
|
)
|
|
for model_id in model_ids
|
|
)
|
|
|
|
assert has_known_model, (
|
|
f"Expected models from known providers, got: {model_ids[:10]}"
|
|
)
|
|
|
|
def test_url_not_modified(self):
|
|
"""The URL we pass is used as-is (no unwanted /v1 suffix added).
|
|
|
|
REGRESSION TEST: Previously the code was adding /v1 to URLs,
|
|
which would break URLs that already have it.
|
|
"""
|
|
api_key = os.environ.get("OPENROUTER_API_KEY")
|
|
|
|
# URL already has /v1 - should work without modification
|
|
url_with_v1 = "https://openrouter.ai/api/v1"
|
|
|
|
models = CustomOpenAIEndpointProvider.list_models_for_api(
|
|
api_key=api_key,
|
|
base_url=url_with_v1,
|
|
)
|
|
|
|
# If URL was modified to /v1/v1, this would fail
|
|
assert len(models) > 0, "URL should work as-is without modification"
|
|
|
|
|
|
class TestCustomEndpointAPIContract:
|
|
"""Tests verifying the API contract is correct for CI usage."""
|
|
|
|
def test_base_url_parameter_exists(self):
|
|
"""list_models_for_api has base_url as second parameter.
|
|
|
|
This ensures the API contract used by settings_routes.py is stable.
|
|
"""
|
|
import inspect
|
|
|
|
sig = inspect.signature(
|
|
CustomOpenAIEndpointProvider.list_models_for_api
|
|
)
|
|
params = list(sig.parameters.keys())
|
|
|
|
assert params == ["api_key", "base_url"], (
|
|
f"Expected ['api_key', 'base_url'], got {params}"
|
|
)
|
|
|
|
@requires_openrouter_key
|
|
def test_works_without_settings_snapshot(self):
|
|
"""Can call list_models_for_api without any settings infrastructure.
|
|
|
|
REGRESSION TEST: The v1.3.10+ code required settings_snapshot which
|
|
added unnecessary complexity and broke the feature.
|
|
"""
|
|
api_key = os.environ.get("OPENROUTER_API_KEY")
|
|
|
|
# Should work with just api_key and base_url - no settings needed
|
|
models = CustomOpenAIEndpointProvider.list_models_for_api(
|
|
api_key=api_key,
|
|
base_url="https://openrouter.ai/api/v1",
|
|
)
|
|
|
|
assert len(models) > 0
|