97 lines
3.8 KiB
Python
97 lines
3.8 KiB
Python
"""Contract tests for runtime-config.schema.json."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import jsonschema
|
|
import pytest
|
|
|
|
from src.runtime.core.config import create_schema_registry, load_runtime_config, load_schema
|
|
|
|
|
|
def test_runtime_config_schema_validation_valid():
|
|
schema = load_schema("runtime-config.schema.json")
|
|
registry = create_schema_registry()
|
|
validator = jsonschema.Draft202012Validator(schema, registry=registry)
|
|
|
|
valid_config = {
|
|
"config_version": "1.0.0",
|
|
"paths": {"output_dir": "out/articles", "sqlite_db": "out/runtime.db"},
|
|
"roles": {
|
|
"runtime_primary": {
|
|
"role_config_version": "1.0.0",
|
|
"provider": "groq",
|
|
"model": "llama-3.1-8b-instant",
|
|
"endpoint_url": "https://api.groq.com/openai/v1",
|
|
"timeout_seconds": 30,
|
|
"max_retries": 3,
|
|
"parameters": {"temperature": 0.0},
|
|
"hygiene_prompt_version": "1.0.0",
|
|
"hygiene_schema_version": "1.0.0",
|
|
"enrichment_prompt_version": "1.0.0",
|
|
"enrichment_schema_version": "1.0.0",
|
|
},
|
|
"runtime_fallback": {
|
|
"role_config_version": "1.0.0",
|
|
"provider": "deepseek",
|
|
"model": "deepseek-chat",
|
|
"endpoint_url": "https://api.deepseek.com/v1",
|
|
"timeout_seconds": 30,
|
|
"max_retries": 3,
|
|
"parameters": {"temperature": 0.0},
|
|
"hygiene_prompt_version": "1.0.0",
|
|
"hygiene_schema_version": "1.0.0",
|
|
"enrichment_prompt_version": "1.0.0",
|
|
"enrichment_schema_version": "1.0.0",
|
|
},
|
|
},
|
|
"prompts": {
|
|
"article_content_hygiene": {
|
|
"path": "prompts/article_content_hygiene.v1.txt",
|
|
"version": "1.0.0",
|
|
"hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
|
},
|
|
"article_sentiment_tags": {
|
|
"path": "prompts/article_sentiment_tags.v1.txt",
|
|
"version": "1.0.0",
|
|
"hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
|
},
|
|
},
|
|
"ecp": {
|
|
"canonical_schema_reference": "specs/006-article-consolidation-runtime/contracts/ecp-snapshot.schema.json",
|
|
"classifier_module": "src.classifier.InherenceClassifier",
|
|
},
|
|
"limits": {"max_input_bytes": 1048576, "context_strategy": "fail_before_provider"},
|
|
"pricing": {
|
|
"primary_input_1k": 0.00005,
|
|
"primary_output_1k": 0.00008,
|
|
"fallback_input_1k": 0.00014,
|
|
"fallback_output_1k": 0.00028,
|
|
},
|
|
"langfuse": {"environment": "local", "trace_content_policy": "metadata_only"},
|
|
"sqlite": {"busy_timeout_ms": 5000},
|
|
}
|
|
|
|
errors = list(validator.iter_errors(valid_config))
|
|
assert len(errors) == 0, f"Schema validation errors: {[e.message for e in errors]}"
|
|
|
|
|
|
def test_runtime_config_fixture_loads_successfully():
|
|
config = load_runtime_config("runtime_config.local.json")
|
|
assert config.config_version == "1.0.0"
|
|
assert "runtime_primary" in config.roles
|
|
assert "runtime_fallback" in config.roles
|
|
assert config.roles["runtime_primary"].model == "llama-3.1-8b-instant"
|
|
|
|
|
|
def test_runtime_config_rejects_powerful_models(tmp_path: Path):
|
|
valid_base = json.loads(Path("runtime_config.local.json").read_text(encoding="utf-8"))
|
|
valid_base["roles"]["runtime_primary"]["model"] = "gpt-4o" # Forbidden powerful model
|
|
cfg_file = tmp_path / "invalid_cfg.json"
|
|
cfg_file.write_text(json.dumps(valid_base), encoding="utf-8")
|
|
|
|
with pytest.raises(ValueError, match="Forbidden powerful model"):
|
|
load_runtime_config(cfg_file)
|