Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

1575 lines
62 KiB
Python

"""
Coverage tests for benchmarks/web_api/benchmark_routes.py
Targets the uncovered code paths: route handler bodies, branching on
provider types, evaluation config sources, dataset validation,
error-handling except blocks, search-metric aggregation logic, and
export/delete/cancel/validate/search-quality endpoints.
"""
import enum
from contextlib import contextmanager
from datetime import datetime, UTC
from unittest.mock import MagicMock, patch
from flask import Blueprint, Flask
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _make_app():
"""Create a minimal Flask app with the benchmark blueprint registered."""
# Must import *after* patching decorators is no longer needed because
# the blueprint is registered at import time. Instead we patch the
# auth check at the decorator level so the routes execute normally.
from local_deep_research.benchmarks.web_api.benchmark_routes import (
benchmark_bp,
)
app = Flask(__name__)
app.config["SECRET_KEY"] = "test-secret"
app.config["TESTING"] = True
app.config["WTF_CSRF_ENABLED"] = False
# Stub auth blueprint so url_for("auth.login") resolves
auth_bp = Blueprint("auth", __name__, url_prefix="/auth")
@auth_bp.route("/login")
def login():
return "login"
app.register_blueprint(auth_bp)
# Only register if not already registered (avoid duplicate blueprint error)
if "benchmark" not in app.blueprints:
app.register_blueprint(benchmark_bp)
return app
def _fake_settings(overrides=None):
"""Return a dict of settings and a mock SettingsManager."""
defaults = {
"search.iterations": 8,
"search.questions_per_iteration": 5,
"search.tool": "searxng",
"search.search_strategy": "focused_iteration",
"llm.model": "gpt-4",
"llm.provider": "openai_endpoint",
"llm.temperature": 0.7,
"llm.max_tokens": 30000,
"llm.context_window_unrestricted": True,
"llm.context_window_size": 128000,
"llm.local_context_window_size": 4096,
"llm.openai_endpoint.url": "http://localhost:8080",
"llm.openai_endpoint.api_key": "sk-test",
"llm.openai.api_key": "sk-openai",
"llm.anthropic.api_key": "sk-anthropic",
"benchmark.evaluation.provider": "openai_endpoint",
"benchmark.evaluation.model": "anthropic/claude-3.7-sonnet",
"benchmark.evaluation.temperature": 0,
"benchmark.evaluation.endpoint_url": "https://openrouter.ai/api/v1",
}
if overrides:
defaults.update(overrides)
mgr = MagicMock()
mgr.get_setting.side_effect = lambda key, default=None: defaults.get(
key, default
)
return defaults, mgr
@contextmanager
def _patch_auth_and_db(settings_overrides=None):
"""Context manager that patches login_required, db_manager, limiter,
get_user_db_session, and SettingsManager so route bodies execute."""
_, mgr = _fake_settings(settings_overrides)
mock_db_session = MagicMock()
with (
patch(
"local_deep_research.web.auth.decorators.db_manager"
) as mock_db_mgr,
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.get_user_db_session"
) as mock_get_session,
patch(
"local_deep_research.database.session_context.get_user_db_session"
) as mock_get_session2,
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.SettingsManager",
return_value=mgr,
),
patch(
"local_deep_research.settings.SettingsManager",
return_value=mgr,
),
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.benchmark_service"
) as mock_svc,
):
mock_db_mgr.is_user_connected.return_value = True
@contextmanager
def _session_ctx(username, password=None):
yield mock_db_session
mock_get_session.side_effect = _session_ctx
mock_get_session2.side_effect = _session_ctx
yield mock_svc, mgr, mock_db_session
def _make_routed_query(
*,
runs=None,
avg_processing=None,
results=None,
search_calls=None,
search_calls_exc=None,
):
"""Side-effect for mock_db.query that routes by model class.
After the SearchTracker singleton removal, production code queries
SearchCall directly on the same session. Tests must therefore route
``session.query(Model)`` to the right mock chain depending on the
model class name.
"""
def _route(model, *args):
chain = MagicMock()
chain.filter.return_value = chain
chain.order_by.return_value = chain
chain.limit.return_value = chain
if not isinstance(model, type):
# func.avg(...) — not a class
chain.scalar.return_value = avg_processing
return chain
name = getattr(model, "__name__", "")
if "BenchmarkRun" in name:
chain.all.return_value = runs or []
elif "SearchCall" in name:
if search_calls_exc:
raise search_calls_exc
chain.all.return_value = search_calls or []
else:
# BenchmarkResult or anything else
chain.all.return_value = results or []
return chain
return _route
# Fake enum for BenchmarkStatus
class _FakeStatus(enum.Enum):
IN_PROGRESS = "in_progress"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
class _FakeDatasetType(enum.Enum):
SIMPLEQA = "simpleqa"
BROWSECOMP = "browsecomp"
# ---------------------------------------------------------------------------
# index route
# ---------------------------------------------------------------------------
class TestIndex:
def test_index_renders_template(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.render_template_with_defaults",
return_value="<html>ok</html>",
) as mock_render:
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/")
assert resp.status_code == 200
mock_render.assert_called_once()
call_kwargs = mock_render.call_args
assert (
"eval_settings" in call_kwargs.kwargs
or "eval_settings"
in (call_kwargs[1] if len(call_kwargs) > 1 else {})
)
class TestResults:
def test_results_page(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.render_template_with_defaults",
return_value="<html>results</html>",
):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/results")
assert resp.status_code == 200
# ---------------------------------------------------------------------------
# start_benchmark route
# ---------------------------------------------------------------------------
class TestStartBenchmark:
def _post_start(self, client, json_data):
return client.post(
"/benchmark/api/start",
json=json_data,
content_type="application/json",
)
def test_start_no_json_body(self):
"""No JSON body triggers require_json_body decorator -> 400."""
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.post("/benchmark/api/start", data="not json")
assert resp.status_code == 400
def test_start_empty_datasets(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(client, {"datasets_config": {}})
assert resp.status_code == 400
def test_start_datasets_all_zero_count(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{"datasets_config": {"simpleqa": {"count": 0}}},
)
assert resp.status_code == 400
def test_start_success_openai_endpoint_provider(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = "pw123"
mock_svc.create_benchmark_run.return_value = 42
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
sess["session_id"] = "sid1"
resp = self._post_start(
client,
{
"run_name": "test run",
"datasets_config": {"simpleqa": {"count": 5}},
},
)
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is True
assert data["benchmark_run_id"] == 42
def test_start_success_openai_provider(self):
app = _make_app()
with _patch_auth_and_db({"llm.provider": "openai"}) as (
mock_svc,
mgr,
_,
):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 10
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{"datasets_config": {"simpleqa": {"count": 2}}},
)
assert resp.status_code == 200
def test_start_success_anthropic_provider(self):
app = _make_app()
with _patch_auth_and_db({"llm.provider": "anthropic"}) as (
mock_svc,
mgr,
_,
):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 11
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 200
def test_start_with_evaluation_config_in_data(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 99
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{
"datasets_config": {"simpleqa": {"count": 3}},
"evaluation_config": {
"provider": "openai",
"model_name": "gpt-4",
},
},
)
assert resp.status_code == 200
# Verify evaluation_config was passed through
call_kwargs = mock_svc.create_benchmark_run.call_args
assert (
call_kwargs.kwargs["evaluation_config"]["provider"]
== "openai"
)
def test_start_eval_provider_openai(self):
"""Evaluation provider openai branch."""
app = _make_app()
with _patch_auth_and_db(
{
"benchmark.evaluation.provider": "openai",
}
) as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 50
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 200
def test_start_eval_provider_anthropic(self):
"""Evaluation provider anthropic branch."""
app = _make_app()
with _patch_auth_and_db(
{
"benchmark.evaluation.provider": "anthropic",
}
) as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 51
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 200
def test_start_benchmark_fails(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 77
mock_svc.start_benchmark.return_value = False
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{"datasets_config": {"simpleqa": {"count": 5}}},
)
assert resp.status_code == 500
assert resp.get_json()["success"] is False
def test_start_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.side_effect = RuntimeError("boom")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_start(
client,
{"datasets_config": {"simpleqa": {"count": 5}}},
)
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# get_running_benchmark
# ---------------------------------------------------------------------------
class TestGetRunningBenchmark:
def test_running_found(self):
app = _make_app()
mock_run = MagicMock()
mock_run.id = 1
mock_run.run_name = "Run 1"
mock_run.total_examples = 10
mock_run.completed_examples = 3
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
with (
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.BenchmarkRun",
create=True,
),
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.BenchmarkStatus",
create=True,
) as MockBS,
):
MockBS.IN_PROGRESS = _FakeStatus.IN_PROGRESS
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.filter.return_value = mock_query
mock_query.order_by.return_value = mock_query
mock_query.first.return_value = mock_run
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/running")
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is True
assert data["benchmark_run_id"] == 1
def test_no_running(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
with (
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.BenchmarkRun",
create=True,
),
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.BenchmarkStatus",
create=True,
) as MockBS,
):
MockBS.IN_PROGRESS = _FakeStatus.IN_PROGRESS
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.filter.return_value = mock_query
mock_query.order_by.return_value = mock_query
mock_query.first.return_value = None
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/running")
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is False
def test_running_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
# Force exception in the route
mock_db.query.side_effect = RuntimeError("db error")
with (
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.BenchmarkRun",
create=True,
),
patch(
"local_deep_research.benchmarks.web_api.benchmark_routes.BenchmarkStatus",
create=True,
),
):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/running")
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# get_benchmark_status
# ---------------------------------------------------------------------------
class TestGetBenchmarkStatus:
def test_status_found(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
mock_svc.get_benchmark_status.return_value = {
"completed_examples": 5,
"overall_accuracy": 0.8,
"avg_time_per_example": 12.5,
"estimated_time_remaining": 60,
}
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/status/1")
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is True
assert data["status"]["completed_examples"] == 5
def test_status_not_found(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
mock_svc.get_benchmark_status.return_value = None
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/status/999")
assert resp.status_code == 404
def test_status_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
mock_svc.get_benchmark_status.side_effect = RuntimeError("boom")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/status/1")
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# cancel_benchmark
# ---------------------------------------------------------------------------
class TestCancelBenchmark:
def test_cancel_success(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
mock_svc.cancel_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.post("/benchmark/api/cancel/1")
assert resp.status_code == 200
assert resp.get_json()["success"] is True
def test_cancel_failure(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
mock_svc.cancel_benchmark.return_value = False
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.post("/benchmark/api/cancel/1")
assert resp.status_code == 500
def test_cancel_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
mock_svc.cancel_benchmark.side_effect = RuntimeError("oops")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.post("/benchmark/api/cancel/1")
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# get_benchmark_history
# ---------------------------------------------------------------------------
class TestGetBenchmarkHistory:
def _make_run(self, run_id, status_val="completed", run_name=None):
run = MagicMock()
run.id = run_id
run.run_name = run_name
run.created_at = datetime(2025, 1, 1, tzinfo=UTC)
# Provenance fields added in migration 0014 — None mimics a pre-0014
# row, so the existing history tests cover the back-compat path.
run.start_time = None
run.ldr_version = None
run.total_examples = 10
run.completed_examples = 8
run.overall_accuracy = 0.75
run.status = MagicMock()
run.status.value = status_val
run.search_config = {"tool": "searxng"}
run.evaluation_config = {"provider": "openai"}
run.datasets_config = {"simpleqa": {"count": 10}}
return run
def test_history_empty(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.order_by.return_value = mock_query
mock_query.limit.return_value = mock_query
mock_query.all.return_value = []
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/history")
assert resp.status_code == 200
assert resp.get_json()["runs"] == []
def test_history_with_runs_and_avg_processing_time(self):
app = _make_app()
run = self._make_run(1, run_name=None)
mock_result = MagicMock()
mock_result.research_id = "res-1"
mock_search_call = MagicMock()
mock_search_call.research_id = "res-1"
mock_search_call.results_count = 20
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query(
runs=[run],
avg_processing=15.5,
results=[mock_result],
search_calls=[mock_search_call],
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/history")
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is True
assert len(data["runs"]) == 1
# run_name falls back to "Benchmark #{id}"
assert "Benchmark #1" in data["runs"][0]["run_name"]
def test_history_avg_processing_time_none(self):
"""Branch: avg_result is None."""
app = _make_app()
run = self._make_run(2, run_name="Named Run")
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query(
runs=[run],
avg_processing=None,
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/history")
assert resp.status_code == 200
data = resp.get_json()
assert data["runs"][0]["avg_processing_time"] is None
def test_history_search_metrics_exception(self):
"""Exception in search metrics calculation logged as warning."""
app = _make_app()
run = self._make_run(3)
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query(
runs=[run],
avg_processing=10.0,
search_calls_exc=RuntimeError("no tracker"),
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/history")
assert resp.status_code == 200
def test_history_avg_time_exception(self):
"""Exception in avg processing time calculation."""
app = _make_app()
run = self._make_run(4)
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.order_by.return_value = mock_query
mock_query.limit.return_value = mock_query
mock_query.all.return_value = [run]
mock_query.filter.side_effect = RuntimeError("avg fail")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/history")
# Should still return 200 with avg_processing_time=None
assert resp.status_code == 200
def test_history_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = RuntimeError("db fail")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/history")
assert resp.status_code == 500
def test_history_no_research_ids(self):
"""Branch where research_ids list is empty."""
app = _make_app()
run = self._make_run(5)
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.order_by.return_value = mock_query
mock_query.limit.return_value = mock_query
mock_query.all.side_effect = [[run], []] # runs, then results
mock_query.filter.return_value = mock_query
mock_query.scalar.return_value = 5.0
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/history")
assert resp.status_code == 200
# ---------------------------------------------------------------------------
# get_benchmark_results
# ---------------------------------------------------------------------------
class TestGetBenchmarkResults:
def _make_result(self, example_id="ex1", research_id="r1", completed=True):
r = MagicMock()
r.example_id = example_id
r.dataset_type = _FakeDatasetType.SIMPLEQA
r.question = "What is X?"
r.correct_answer = "42"
r.extracted_answer = "42"
r.response = "The answer is 42"
r.is_correct = True
r.confidence = 0.95
r.grader_response = "Correct"
r.processing_time = 10.5
r.sources = ["source1"]
r.research_id = research_id
r.completed_at = datetime(2025, 1, 1, tzinfo=UTC) if completed else None
return r
def test_results_success(self):
app = _make_app()
result = self._make_result()
mock_search_call = MagicMock()
mock_search_call.research_id = "r1"
mock_search_call.results_count = 15
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query(
results=[result],
search_calls=[mock_search_call],
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1")
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is True
assert len(data["results"]) == 1
assert data["results"][0]["search_result_count"] == 15
def test_results_with_limit_param(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query()
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1?limit=5")
assert resp.status_code == 200
def test_results_no_completed_at(self):
"""Result with completed_at = None."""
app = _make_app()
result = self._make_result(completed=False)
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query(
results=[result],
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1")
assert resp.status_code == 200
assert resp.get_json()["results"][0]["completed_at"] is None
def test_results_no_research_id(self):
"""Result with research_id = None -> search_result_count = 0."""
app = _make_app()
result = self._make_result(research_id=None)
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query(
results=[result],
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1")
assert resp.status_code == 200
assert resp.get_json()["results"][0]["search_result_count"] == 0
def test_results_search_tracker_exception(self):
"""Exception fetching search metrics does not break the route."""
app = _make_app()
result = self._make_result()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_routed_query(
results=[result],
search_calls_exc=RuntimeError("no tracker"),
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1")
assert resp.status_code == 200
def test_results_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_svc.sync_pending_results.side_effect = RuntimeError("fail")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1")
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# export_benchmark_results
# ---------------------------------------------------------------------------
def _make_export_query_router(*, run=None, results=None):
"""Side-effect for mock_db.query that routes by model class for the
/export endpoint.
The endpoint runs two queries:
1. session.query(BenchmarkRun).options(...).filter(...).one_or_none()
2. session.query(BenchmarkResult).options(...).filter(...).order_by(...).all()
"""
def _route(model, *args):
chain = MagicMock()
chain.options.return_value = chain
chain.filter.return_value = chain
chain.order_by.return_value = chain
name = getattr(model, "__name__", "")
if "BenchmarkRun" in name:
chain.one_or_none.return_value = run
else:
chain.all.return_value = results or []
return chain
return _route
def _make_run_mock(
*, ldr_version=None, start_time=None, settings_snapshot=None
):
run = MagicMock()
run.ldr_version = ldr_version
run.start_time = start_time
run.created_at = datetime(2025, 1, 1, tzinfo=UTC)
run.settings_snapshot = settings_snapshot
return run
class TestExportBenchmarkResults:
def test_export_success(self):
app = _make_app()
mock_result = MagicMock()
mock_result.example_id = "ex1"
mock_result.dataset_type = _FakeDatasetType.SIMPLEQA
mock_result.question = "Q?"
mock_result.correct_answer = "A"
mock_result.extracted_answer = "A"
mock_result.is_correct = True
mock_result.confidence = 0.9
mock_result.processing_time = 5.0
mock_result.completed_at = datetime(2025, 1, 1, tzinfo=UTC)
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_export_query_router(
run=_make_run_mock(ldr_version="1.6.10"),
results=[mock_result],
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1/export")
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is True
assert len(data["results"]) == 1
assert "full_response" not in data["results"][0]
def test_export_no_completed_at(self):
app = _make_app()
mock_result = MagicMock()
mock_result.example_id = "ex2"
mock_result.dataset_type = _FakeDatasetType.BROWSECOMP
mock_result.question = "Q2?"
mock_result.correct_answer = "B"
mock_result.extracted_answer = "B"
mock_result.is_correct = False
mock_result.confidence = 0.5
mock_result.processing_time = 3.0
mock_result.completed_at = None
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = _make_export_query_router(
run=_make_run_mock(),
results=[mock_result],
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1/export")
assert resp.status_code == 200
assert resp.get_json()["results"][0]["completed_at"] is None
def test_export_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = RuntimeError("fail")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/results/1/export")
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# get_saved_configs
# ---------------------------------------------------------------------------
class TestGetSavedConfigs:
def test_configs_success(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/configs")
assert resp.status_code == 200
data = resp.get_json()
assert data["success"] is True
assert len(data["configs"]) == 2
assert data["configs"][0]["name"] == "Quick Test"
# ---------------------------------------------------------------------------
# start_benchmark_simple
# ---------------------------------------------------------------------------
class TestStartBenchmarkSimple:
def _post_simple(self, client, json_data):
return client.post(
"/benchmark/api/start-simple",
json=json_data,
content_type="application/json",
)
def test_simple_no_json(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.post("/benchmark/api/start-simple", data="bad")
assert resp.status_code == 400
def test_simple_empty_datasets(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_simple(client, {"datasets_config": {}})
assert resp.status_code == 400
def test_simple_success_openai_endpoint(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = "pw"
mock_svc.create_benchmark_run.return_value = 100
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
sess["session_id"] = "sid"
resp = self._post_simple(
client,
{
"run_name": "simple test",
"datasets_config": {"simpleqa": {"count": 3}},
},
)
assert resp.status_code == 200
assert resp.get_json()["success"] is True
def test_simple_openai_provider(self):
app = _make_app()
with _patch_auth_and_db({"llm.provider": "openai"}) as (
mock_svc,
mgr,
_,
):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 101
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_simple(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 200
def test_simple_anthropic_provider(self):
app = _make_app()
with _patch_auth_and_db({"llm.provider": "anthropic"}) as (
mock_svc,
mgr,
_,
):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 102
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_simple(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 200
def test_simple_eval_openai_provider(self):
app = _make_app()
with _patch_auth_and_db(
{
"benchmark.evaluation.provider": "openai",
}
) as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 103
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_simple(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 200
def test_simple_eval_anthropic_provider(self):
app = _make_app()
with _patch_auth_and_db(
{
"benchmark.evaluation.provider": "anthropic",
}
) as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 104
mock_svc.start_benchmark.return_value = True
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_simple(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 200
def test_simple_start_fails(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.return_value = 200
mock_svc.start_benchmark.return_value = False
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_simple(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 500
def test_simple_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with patch(
"local_deep_research.database.session_passwords.session_password_store"
) as mock_pw:
mock_pw.get_session_password.return_value = None
mock_svc.create_benchmark_run.side_effect = RuntimeError("boom")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_simple(
client,
{"datasets_config": {"simpleqa": {"count": 1}}},
)
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# validate_config
# ---------------------------------------------------------------------------
class TestValidateConfig:
def _post_validate(self, client, json_data):
return client.post(
"/benchmark/api/validate-config",
json=json_data,
content_type="application/json",
)
def test_validate_valid(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_validate(
client,
{
"search_config": {
"search_tool": "searxng",
"search_strategy": "focused_iteration",
},
"datasets_config": {"simpleqa": {"count": 10}},
},
)
assert resp.status_code == 200
data = resp.get_json()
assert data["valid"] is True
assert data["total_examples"] == 10
def test_validate_no_data(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
# Send non-dict JSON (list)
resp = client.post(
"/benchmark/api/validate-config",
data="[]",
content_type="application/json",
)
assert resp.status_code == 200
data = resp.get_json()
assert data["valid"] is False
def test_validate_missing_search_tool(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_validate(
client,
{
"search_config": {
"search_strategy": "focused_iteration"
},
"datasets_config": {"simpleqa": {"count": 10}},
},
)
data = resp.get_json()
assert data["valid"] is False
assert any("Search tool" in e for e in data["errors"])
def test_validate_missing_search_strategy(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_validate(
client,
{
"search_config": {"search_tool": "searxng"},
"datasets_config": {"simpleqa": {"count": 10}},
},
)
data = resp.get_json()
assert data["valid"] is False
def test_validate_no_datasets(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_validate(
client,
{
"search_config": {
"search_tool": "searxng",
"search_strategy": "focused_iteration",
},
"datasets_config": {},
},
)
data = resp.get_json()
assert data["valid"] is False
assert any("dataset" in e.lower() for e in data["errors"])
def test_validate_zero_total_examples(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_validate(
client,
{
"search_config": {
"search_tool": "searxng",
"search_strategy": "focused_iteration",
},
"datasets_config": {"simpleqa": {"count": 0}},
},
)
data = resp.get_json()
assert data["valid"] is False
def test_validate_large_count_accepted(self):
"""Large example counts should pass validation (no artificial cap)."""
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_validate(
client,
{
"search_config": {
"search_tool": "searxng",
"search_strategy": "focused_iteration",
},
"datasets_config": {"simpleqa": {"count": 1001}},
},
)
data = resp.get_json()
assert data["valid"] is True
assert data["total_examples"] == 1001
def test_validate_datasets_config_with_non_dict_values(self):
"""datasets_config with valid structure but non-integer count."""
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, _):
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = self._post_validate(
client,
{
"search_config": {
"search_tool": "searxng",
"search_strategy": "focused_iteration",
},
"datasets_config": {"simpleqa": {}},
},
)
data = resp.get_json()
# count defaults to 0, so total_examples = 0
assert data["valid"] is False
assert data["total_examples"] == 0
# ---------------------------------------------------------------------------
# get_search_quality
# ---------------------------------------------------------------------------
class TestGetSearchQuality:
"""Tests for /benchmark/api/search-quality.
The route reads RateLimitEstimate rows from the user DB and maps each
to {engine_type, total_attempts, success_rate (0-100 scale), status
(EXCELLENT/GOOD/CAUTION/WARNING/CRITICAL)}.
"""
@staticmethod
def _make_estimate(engine_type, success_rate, total_attempts=100):
est = MagicMock()
est.engine_type = engine_type
est.total_attempts = total_attempts
est.success_rate = success_rate
return est
@staticmethod
def _fetch(estimates):
"""Run the route with the given estimates and return (resp, json)."""
app = _make_app()
with _patch_auth_and_db() as (_svc, _mgr, mock_db):
mock_db.query.return_value.all.return_value = estimates
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/search-quality")
return resp, resp.get_json()
def test_requires_authentication(self):
app = _make_app()
with _patch_auth_and_db():
with app.test_client() as client:
resp = client.get("/benchmark/api/search-quality")
assert resp.status_code in (401, 302)
def test_status_tier_excellent(self):
resp, data = self._fetch([self._make_estimate("pubmed", 0.95)])
assert resp.status_code == 200
assert data["success"] is True
assert "timestamp" in data
row = data["search_quality"][0]
assert row["engine_type"] == "pubmed"
assert row["status"] == "EXCELLENT"
assert row["success_rate"] == 95.0
assert row["total_attempts"] == 100
def test_status_tier_good(self):
_resp, data = self._fetch([self._make_estimate("google", 0.90)])
assert data["search_quality"][0]["status"] == "GOOD"
assert data["search_quality"][0]["success_rate"] == 90.0
def test_status_tier_caution(self):
_resp, data = self._fetch([self._make_estimate("google", 0.75)])
assert data["search_quality"][0]["status"] == "CAUTION"
def test_status_tier_warning(self):
_resp, data = self._fetch([self._make_estimate("google", 0.50)])
assert data["search_quality"][0]["status"] == "WARNING"
def test_status_tier_critical(self):
_resp, data = self._fetch([self._make_estimate("google", 0.30)])
assert data["search_quality"][0]["status"] == "CRITICAL"
def test_success_rate_unit_conversion(self):
# success_rate is stored as 0-1 in the DB; route multiplies by 100.
_resp, data = self._fetch([self._make_estimate("google", 0.873)])
assert data["search_quality"][0]["success_rate"] == 87.3
def test_multiple_engines(self):
resp, data = self._fetch(
[
self._make_estimate("bing", 0.6),
self._make_estimate("google", 0.95),
]
)
assert resp.status_code == 200
assert len(data["search_quality"]) == 2
assert {r["engine_type"] for r in data["search_quality"]} == {
"bing",
"google",
}
def test_empty_engines(self):
resp, data = self._fetch([])
assert resp.status_code == 200
assert data["success"] is True
assert data["search_quality"] == []
def test_shape_excludes_legacy_fields(self):
# Regression guard: the old get_search_quality_stats shape included
# recent_avg_results / min_recent_results / max_recent_results /
# sample_size. Those are gone (the underlying data lived only in
# the per-request in-memory tracker). Asserting their absence
# protects the benchmark.html JS from accidentally depending on
# them again.
_resp, data = self._fetch([self._make_estimate("google", 0.95)])
assert set(data["search_quality"][0].keys()) == {
"engine_type",
"total_attempts",
"success_rate",
"status",
}
def test_search_quality_exception(self):
# The route now reads RateLimitEstimate rows from the user DB
# (no get_tracker call), so a DB error is what surfaces a 500.
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = RuntimeError("db error")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.get("/benchmark/api/search-quality")
assert resp.status_code == 500
# ---------------------------------------------------------------------------
# delete_benchmark_run
# ---------------------------------------------------------------------------
class TestDeleteBenchmarkRun:
def test_delete_success(self):
app = _make_app()
mock_run = MagicMock()
mock_run.id = 1
mock_run.status = MagicMock()
mock_run.status.value = "completed"
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.filter.return_value = mock_query
mock_query.first.return_value = mock_run
mock_query.delete.return_value = None
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.delete("/benchmark/api/delete/1")
assert resp.status_code == 200
assert resp.get_json()["success"] is True
def test_delete_not_found(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.filter.return_value = mock_query
mock_query.first.return_value = None
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.delete("/benchmark/api/delete/999")
assert resp.status_code == 404
def test_delete_in_progress(self):
app = _make_app()
mock_run = MagicMock()
mock_run.status = MagicMock()
mock_run.status.value = "in_progress"
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_query = MagicMock()
mock_db.query.return_value = mock_query
mock_query.filter.return_value = mock_query
mock_query.first.return_value = mock_run
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.delete("/benchmark/api/delete/1")
assert resp.status_code == 400
assert (
"running" in resp.get_json()["error"].lower()
or "cancel" in resp.get_json()["error"].lower()
)
def test_delete_exception(self):
app = _make_app()
with _patch_auth_and_db() as (mock_svc, mgr, mock_db):
mock_db.query.side_effect = RuntimeError("db error")
with app.test_client() as client:
with client.session_transaction() as sess:
sess["username"] = "testuser"
resp = client.delete("/benchmark/api/delete/1")
assert resp.status_code == 500