Files
ZNJJ-api-server/test/test_eval_catalog.py
T

139 lines
5.3 KiB
Python
Raw Normal View History

"""Selection tests use real case files and make no API/model calls."""
from collections import Counter
from contextlib import nullcontext
import json
import os
from pathlib import Path
import subprocess
import sys
import pytest
import yaml
from evals.catalog import load_suites, select_cases
from evals.run import CaseTranscript, DEFAULT_CASES_DIR, load_cases
ROOT = Path(__file__).resolve().parents[1]
@pytest.fixture
def catalog():
return load_cases(DEFAULT_CASES_DIR, [])
def test_full_keeps_all_cases_and_modes(catalog):
selected = select_cases(catalog, suites=["full"])
assert selected == catalog
assert {c["clientMode"] for c in selected} == {"direct", "browser_addon"}
def test_overlapping_suites_execute_each_case_once(catalog):
selected = select_cases(catalog, suites=["feedback", "collection", "feedback"])
expected = set(c["name"] for c in select_cases(catalog, suites=["collection"]))
assert len(selected) == len(expected)
assert {c["name"] for c in selected} == expected
def test_filter_intersection_and_exclusion(catalog):
selected = select_cases(catalog, suites=["collection"],
groups=["collection_skip_known_info"], mode="direct",
names=["single", "dual"], exclude_names=["single", "unclear"])
assert selected
assert all(c["clientMode"] == "direct" and "dual" in c["name"]
and "unclear" not in c["name"] for c in selected)
assert all(c["_group"] == "collection_skip_known_info" for c in selected)
@pytest.mark.parametrize("kwargs", [
{"groups": ["not-a-group"]},
{"suites": ["not-a-suite"]},
{"names": ["not-a-case"]},
{"groups": ["complex_vehicle"], "suites": ["photo"]},
])
def test_bad_or_empty_selection_fails(catalog, kwargs):
with pytest.raises(ValueError):
select_cases(catalog, **kwargs)
def test_suites_have_live_patterns_and_modes(catalog):
for name, suite in load_suites().items():
assert {c["clientMode"] for c in select_cases(catalog, suites=[name])} == {
"direct", "browser_addon",
}
for pattern in suite["include"]:
assert any(Path(c["_relative_path"]).match(pattern) for c in catalog), (name, pattern)
assert len(select_cases(catalog, suites=["smoke"])) < len(catalog)
def test_directory_group_and_relative_path(catalog):
for case in catalog:
assert case["_group"] == Path(case["_relative_path"]).parent.as_posix()
assert "\\" not in case["_relative_path"]
def test_custom_directory_and_duplicate_names(tmp_path):
case = {"name": "custom", "clientMode": "direct", "steps": [
{"input": "开始", "expect": {"stageCode": "1001"}},
]}
group = tmp_path / "custom_group"
group.mkdir()
(group / "a.yaml").write_text(yaml.safe_dump(case), encoding="utf-8")
selected = select_cases(load_cases(tmp_path, []), groups=["custom_group"])
assert selected[0]["_relative_path"] == "custom_group/a.yaml"
(group / "b.yaml").write_text(yaml.safe_dump(case), encoding="utf-8")
with pytest.raises(ValueError, match="unique"):
load_cases(tmp_path, [])
@pytest.mark.parametrize("command", [
["-m", "evals.run"],
["evals/run.py"],
["-m", "evals.prompt_compare"],
])
def test_cli_preview_has_no_provider_or_output_requirement(command, tmp_path):
env = {**os.environ, "PYTHONIOENCODING": "utf-8", "LLM_PROVIDER": "fake",
"AGENT_BACKEND": "fastgpt"}
result = subprocess.run(
[sys.executable, *command, "--suite", "feedback", "--group", "complex_vehicle",
"--mode", "direct", "--list"], cwd=ROOT, env=env,
capture_output=True, text=True, encoding="utf-8", timeout=30,
)
assert result.returncode == 0, result.stderr
assert "direct_complex_three_immediate" in result.stdout
assert "browser_addon_complex_three_immediate" not in result.stdout
assert "Selected 1 of" in result.stdout
def test_no_identical_inputs_and_assertions_within_a_mode(catalog):
fingerprints = Counter(json.dumps({"mode": case["clientMode"], "steps": case["steps"]},
sort_keys=True, ensure_ascii=False) for case in catalog)
assert all(count == 1 for count in fingerprints.values())
@pytest.mark.parametrize("passed,exit_code", [(True, 0), (False, 1)])
def test_execution_uses_the_preview_selection(monkeypatch, passed, exit_code):
from evals import run
calls = []
monkeypatch.setattr(sys, "argv", ["evals.run", "--suite", "feedback", "--suite", "collection",
"--group", "complex_vehicle", "--mode", "direct", "--no-save"])
monkeypatch.setattr(run.httpx, "Client", lambda **kwargs: nullcontext(None))
def fake_run(client, case):
calls.append(case["name"])
return CaseTranscript(case["name"], case["_path"], case["clientMode"], "test", passed)
monkeypatch.setattr(run, "run_case", fake_run)
assert run.main() == exit_code
assert calls == ["direct_complex_three_immediate"]
def test_cli_unknown_group_is_configuration_error():
result = subprocess.run(
[sys.executable, "-m", "evals.run", "--group", "unknown", "--list"],
cwd=ROOT, capture_output=True, text=True, encoding="utf-8", timeout=30,
)
assert result.returncode == 2
assert "Unknown groups" in result.stderr