7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
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
332 lines
12 KiB
Python
332 lines
12 KiB
Python
"""
|
|
Comprehensive API test suite with proper authentication handling.
|
|
"""
|
|
|
|
import json
|
|
import time
|
|
from loguru import logger
|
|
|
|
|
|
class TestComprehensiveAPIs:
|
|
"""Comprehensive API test suite using Flask test client."""
|
|
|
|
def test_auth_apis(self, authenticated_client):
|
|
"""Test authentication APIs."""
|
|
logger.info("Testing Authentication APIs")
|
|
|
|
# Check auth status
|
|
response = authenticated_client.get("/auth/check")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert data["authenticated"] is True
|
|
|
|
# Test integrity check
|
|
response = authenticated_client.get("/auth/integrity-check")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert "integrity" in data
|
|
|
|
logger.info("✅ Auth APIs tested")
|
|
|
|
def test_settings_apis(self, authenticated_client):
|
|
"""Test settings APIs."""
|
|
logger.info("Testing Settings APIs")
|
|
|
|
# Get all settings
|
|
response = authenticated_client.get("/settings/api")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert data["status"] == "success"
|
|
assert "settings" in data
|
|
|
|
# Get categories
|
|
response = authenticated_client.get("/settings/api/categories")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert "categories" in data
|
|
|
|
# Get types
|
|
response = authenticated_client.get("/settings/api/types")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert "types" in data
|
|
|
|
# Get available models
|
|
print("\n[DEBUG] Testing /settings/api/available-models")
|
|
response = authenticated_client.get("/settings/api/available-models")
|
|
print(f"[DEBUG] Response status: {response.status_code}")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
print(f"[DEBUG] Response keys: {list(data.keys())}")
|
|
# The endpoint returns provider_options and providers, not models
|
|
assert "provider_options" in data
|
|
assert "providers" in data
|
|
|
|
# Get available search engines
|
|
response = authenticated_client.get(
|
|
"/settings/api/available-search-engines"
|
|
)
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert "engines" in data or "engine_options" in data
|
|
|
|
# Test setting CRUD (use an allow-listed prefix so the
|
|
# namespace gate permits creation of this throwaway key).
|
|
test_key = "llm.test_setting"
|
|
test_value = {"value": "test_value_123"}
|
|
|
|
# Create/Update setting
|
|
response = authenticated_client.put(
|
|
f"/settings/api/{test_key}",
|
|
json=test_value,
|
|
content_type="application/json",
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
|
|
# Get the setting
|
|
response = authenticated_client.get(f"/settings/api/{test_key}")
|
|
# Setting might have been created or might not exist
|
|
assert response.status_code in [200, 404]
|
|
|
|
# Delete the setting
|
|
response = authenticated_client.delete(f"/settings/api/{test_key}")
|
|
assert response.status_code in [200, 204, 404]
|
|
|
|
logger.info("✅ Settings APIs tested")
|
|
|
|
def test_research_apis(self, authenticated_client):
|
|
"""Test research APIs."""
|
|
# audit: PUNCHLIST reviewed 2026-05 — issue resolved by prior PR (recommendation: REFACTOR_SPLIT).
|
|
logger.info("Testing Research APIs")
|
|
|
|
# Get research history (endpoint is /api/history not /research/api/history)
|
|
response = authenticated_client.get("/api/history")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert "history" in data or "items" in data
|
|
|
|
# Start a test research
|
|
research_data = {
|
|
"query": "Test research from comprehensive API test",
|
|
"mode": "quick",
|
|
"model_provider": "OLLAMA",
|
|
"model": "llama2",
|
|
"search_engine": "searxng",
|
|
"max_results": 5,
|
|
"iterations": 1,
|
|
"questions_per_iteration": 2,
|
|
}
|
|
|
|
response = authenticated_client.post(
|
|
"/api/start_research",
|
|
json=research_data,
|
|
content_type="application/json",
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
data = json.loads(response.data)
|
|
assert "research_id" in data
|
|
research_id = data["research_id"]
|
|
|
|
# Give it a moment to start
|
|
time.sleep(0.5) # allow: unmarked-sleep
|
|
|
|
# Check status
|
|
response = authenticated_client.get(
|
|
f"/api/research/{research_id}/status"
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
# Terminate research
|
|
response = authenticated_client.post(
|
|
f"/api/terminate/{research_id}"
|
|
)
|
|
assert response.status_code in [200, 404]
|
|
|
|
logger.info("✅ Research APIs tested")
|
|
|
|
def test_metrics_apis(self, authenticated_client):
|
|
"""Test metrics APIs."""
|
|
logger.info("Testing Metrics APIs")
|
|
|
|
# Get metrics summary
|
|
response = authenticated_client.get("/metrics/api/metrics")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The endpoint returns 'metrics' not 'summary'
|
|
assert "metrics" in data
|
|
|
|
# Get enhanced metrics
|
|
response = authenticated_client.get("/metrics/api/metrics/enhanced")
|
|
assert response.status_code == 200
|
|
|
|
# Get pricing info
|
|
response = authenticated_client.get("/metrics/api/pricing")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The endpoint returns 'pricing' not 'models'
|
|
assert "pricing" in data
|
|
|
|
# Get cost analytics
|
|
response = authenticated_client.get("/metrics/api/cost-analytics")
|
|
assert response.status_code == 200
|
|
|
|
# Test cost calculation
|
|
cost_data = {
|
|
"model_name": "gpt-3.5-turbo",
|
|
"prompt_tokens": 1000,
|
|
"completion_tokens": 500,
|
|
}
|
|
response = authenticated_client.post(
|
|
"/metrics/api/cost-calculation",
|
|
json=cost_data,
|
|
content_type="application/json",
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
logger.info("✅ Metrics APIs tested")
|
|
|
|
def test_benchmark_apis(self, authenticated_client):
|
|
"""Test benchmark APIs."""
|
|
logger.info("Testing Benchmark APIs")
|
|
|
|
# Get benchmark history
|
|
response = authenticated_client.get("/benchmark/api/history")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The endpoint returns 'runs' not 'history'
|
|
assert "runs" in data
|
|
|
|
# Get saved configs
|
|
response = authenticated_client.get("/benchmark/api/configs")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert "configs" in data
|
|
|
|
# Check running benchmark
|
|
response = authenticated_client.get("/benchmark/api/running")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The endpoint might return either is_running or success key
|
|
assert "is_running" in data or "success" in data
|
|
|
|
# Validate config
|
|
test_config = {
|
|
"name": "Test Config",
|
|
"queries": ["test query"],
|
|
"models": ["gpt-3.5-turbo"],
|
|
"search_engines": ["searxng"],
|
|
}
|
|
response = authenticated_client.post(
|
|
"/benchmark/api/validate-config",
|
|
json=test_config,
|
|
content_type="application/json",
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
logger.info("✅ Benchmark APIs tested")
|
|
|
|
def test_history_apis(self, authenticated_client):
|
|
"""Test history APIs."""
|
|
logger.info("Testing History APIs")
|
|
|
|
response = authenticated_client.get("/history/api")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The endpoint returns 'items' not 'history'
|
|
assert "items" in data
|
|
assert isinstance(data["items"], list)
|
|
|
|
logger.info("✅ History APIs tested")
|
|
|
|
def test_config_apis(self, authenticated_client):
|
|
"""Test configuration APIs."""
|
|
logger.info("Testing Config APIs")
|
|
|
|
# Get current config (correct path is /research/api/settings/current-config)
|
|
response = authenticated_client.get(
|
|
"/research/api/settings/current-config"
|
|
)
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The response has a 'config' key containing the actual config
|
|
assert "config" in data or ("llm" in data and "search" in data)
|
|
if "config" in data:
|
|
config = data["config"]
|
|
assert "provider" in config or "llm" in config
|
|
|
|
logger.info("✅ Config APIs tested")
|
|
|
|
def test_health_check_apis(self, authenticated_client):
|
|
"""Test health check APIs."""
|
|
logger.info("Testing Health Check APIs")
|
|
|
|
# Check Ollama status (correct path is /research/api/check/ollama_status)
|
|
response = authenticated_client.get("/research/api/check/ollama_status")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The endpoint returns 'running' not 'available'
|
|
assert "running" in data or "available" in data
|
|
|
|
# Check Ollama model (might return 400 if no model specified)
|
|
response = authenticated_client.get("/research/api/check/ollama_model")
|
|
assert response.status_code in [200, 400]
|
|
|
|
logger.info("✅ Health Check APIs tested")
|
|
|
|
def test_api_v1_endpoints(self, authenticated_client):
|
|
"""Test API v1 endpoints."""
|
|
logger.info("Testing API v1 endpoints")
|
|
|
|
# Health check
|
|
response = authenticated_client.get("/api/v1/health")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert data["status"] == "ok"
|
|
|
|
# API documentation
|
|
response = authenticated_client.get("/api/v1/")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert data["api_version"] == "v1"
|
|
assert "endpoints" in data
|
|
|
|
logger.info("✅ API v1 endpoints tested")
|
|
|
|
def test_rate_limiting(self, authenticated_client):
|
|
"""Test rate limiting functionality."""
|
|
logger.info("Testing Rate Limiting")
|
|
|
|
# Get rate limiting status
|
|
response = authenticated_client.get(
|
|
"/settings/api/rate-limiting/status"
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
# Get current rate limits
|
|
response = authenticated_client.get(
|
|
"/metrics/api/rate-limiting/current"
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
# Test cleanup
|
|
response = authenticated_client.post(
|
|
"/settings/api/rate-limiting/cleanup"
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
logger.info("✅ Rate limiting tested")
|
|
|
|
def test_data_location_api(self, authenticated_client):
|
|
"""Test data location API."""
|
|
logger.info("Testing Data Location API")
|
|
|
|
response = authenticated_client.get("/settings/api/data-location")
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
# The endpoint returns 'data_directory' not 'data_dir'
|
|
assert "data_directory" in data
|
|
assert "is_custom" in data
|
|
|
|
logger.info("✅ Data location API tested")
|