test: lock training error contract inventory

This commit is contained in:
2026-04-30 23:38:32 -04:00
parent b1e995737b
commit 8ef2cc6cdd
@@ -57,6 +57,20 @@ PUBLIC_PRIVACY_CONTRACT_TEST_SURFACES = (
"route annotation lifecycle",
)
PUBLIC_VALIDATION_ERROR_CONTRACT_TEST_SURFACES = (
"invalid path identifiers",
"invalid and blank limit query values",
"malformed/non-object JSON bodies",
"attempt request field validation",
"annotation request field validation",
"submit request field validation",
"import request field validation",
"not_found behavior",
"internal_server_error masking",
)
VALIDATION_ERROR_CONTRACT_TEST_FILE = ROOT / "tests" / "unit" / "test_training_api_error_contract_m9.py"
PUBLIC_PRIVACY_CONTRACT_TEST_INVENTORY = (
{
"surface": "service public export",
@@ -114,6 +128,70 @@ PUBLIC_PRIVACY_CONTRACT_TEST_INVENTORY = (
},
)
PUBLIC_VALIDATION_ERROR_CONTRACT_TEST_INVENTORY = (
{
"surface": "invalid path identifiers",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": (
"test_invalid_case_path_identifier_returns_public_400",
"test_missing_and_invalid_annotation_fields_return_public_400",
"test_invalid_submit_fields_return_public_400",
),
},
{
"surface": "invalid and blank limit query values",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": (
"test_invalid_limits_are_rejected_before_training_handlers_run",
"test_route_request_helper_rejects_blank_training_limits",
),
},
{
"surface": "malformed/non-object JSON bodies",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": ("test_malformed_or_non_object_bodies_return_public_400",),
},
{
"surface": "attempt request field validation",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": ("test_missing_and_invalid_attempt_fields_return_public_400",),
},
{
"surface": "annotation request field validation",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": ("test_missing_and_invalid_annotation_fields_return_public_400",),
},
{
"surface": "submit request field validation",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": ("test_invalid_submit_fields_return_public_400",),
},
{
"surface": "import request field validation",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": ("test_missing_and_invalid_import_fields_return_public_400",),
},
{
"surface": "not_found behavior",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": ("test_missing_case_returns_public_not_found",),
},
{
"surface": "internal_server_error masking",
"file": VALIDATION_ERROR_CONTRACT_TEST_FILE,
"class_name": "TrainingApiErrorContractM9Tests",
"test_names": ("test_handler_internal_error_does_not_echo_raw_detail",),
},
)
class _TrainingRouteProbe:
def __init__(self) -> None:
@@ -583,6 +661,31 @@ class TrainingPublicApiContractM8Tests(unittest.TestCase):
seen_test_names.add(seen_key)
self.assertIn(test_name, class_methods[class_name])
def test_public_validation_error_contract_inventory_names_exist_by_surface(self) -> None:
surfaces = tuple(entry["surface"] for entry in PUBLIC_VALIDATION_ERROR_CONTRACT_TEST_INVENTORY)
self.assertEqual(surfaces, PUBLIC_VALIDATION_ERROR_CONTRACT_TEST_SURFACES)
parsed_methods_by_path = {}
seen_inventory_entries = set()
for entry in PUBLIC_VALIDATION_ERROR_CONTRACT_TEST_INVENTORY:
path = entry["file"]
class_name = entry["class_name"]
test_names = entry["test_names"]
self.assertGreater(len(test_names), 0, entry["surface"])
if path not in parsed_methods_by_path:
self.assertTrue(path.exists(), path)
parsed_methods_by_path[path] = _test_methods_by_class(path)
class_methods = parsed_methods_by_path[path]
self.assertIn(class_name, class_methods)
for test_name in test_names:
seen_key = (entry["surface"], path, class_name, test_name)
with self.subTest(surface=entry["surface"], test_name=test_name):
self.assertNotIn(seen_key, seen_inventory_entries)
seen_inventory_entries.add(seen_key)
self.assertIn(test_name, class_methods[class_name])
def test_documented_training_routes_resolve_to_expected_handlers(self) -> None:
self.assertEqual(_documented_routes(), DOCUMENTED_TRAINING_ROUTES)