"""Published contract and runtime DTOs agree, including generated-client identities.""" import json from pathlib import Path import pytest from django.urls import reverse from organizations.registry_payload_serializers import ( BudgetRegistryRecordDetailPayloadSerializer, BudgetRegistryRecordListPayloadSerializer, SmeSupportRecordDetailPayloadSerializer, SmeSupportRecordListPayloadSerializer, ) from tests.apps.organizations import test_registry_query_contract as query_contract registry_query = query_contract.registry_query @pytest.fixture def contract(): from core import schema return json.loads(Path(schema.__file__).with_name("openapi.json").read_text()) def test_canonical_schema_served_without_authentication(client, contract): response = client.get(reverse("canonical-openapi")) assert response.status_code == 200 assert response["Content-Type"] == "application/json" assert json.loads(b"".join(response.streaming_content)) == contract assert contract["openapi"].startswith("3.") def test_discriminated_records_keep_named_ordering_and_old_operations(contract): schemas = contract["components"]["schemas"] for name in ("OrganizationSourceRecord", "OrganizationSourceRecordList"): record = schemas[name] assert len(record["oneOf"]) == 4 assert record["discriminator"]["propertyName"] == "source_group" for group, record_type in ( ("budget_process_registry", "budget_registry_organization"), ("government_support", "sme_support_measure"), ("sro_membership", "sro_membership"), ): target = record["discriminator"]["mapping"][group].rsplit("/", 1)[1] variant = schemas[target] assert variant["properties"]["record_type"]["enum"] == [record_type] assert { "uid", "organization", "source_group", "record_type", "payload", } <= set(variant["required"]) payload = variant["properties"]["payload"]["$ref"].rsplit("/", 1)[1] assert set(schemas[payload]["properties"]) == set( schemas[payload]["required"] ) assert ( "-payload__united_states" in schemas["V2OrganizationSourceRecordsListOrdering"]["enum"] ) paths = contract["paths"] detail = paths["/api/v2/organization-source-records/{uid}/"]["get"] assert detail["operationId"] == "api_v2_organization_source_records_read" assert detail["tags"] == ["api"] assert ( paths["/api/v1/parsers/dashboard/"]["get"]["operationId"] == "api_v1_parsers_dashboard_list" ) assert ( schemas["PublishedSourceRecordOrganization"]["properties"]["inn"]["nullable"] is True ) @pytest.mark.parametrize( ("source", "list_serializer", "detail_serializer"), [ ( "budget_ubpandnubp", BudgetRegistryRecordListPayloadSerializer, BudgetRegistryRecordDetailPayloadSerializer, ), ( "fns_sme_support_recipients", SmeSupportRecordListPayloadSerializer, SmeSupportRecordDetailPayloadSerializer, ), ], ) def test_list_detail_runtime_payloads_validate_with_named_contract( registry_query, source, list_serializer, detail_serializer, contract ): client, _ = registry_query response = client.get( reverse("api_v2:organizations:organization-source-records-list"), {"source": source}, ) assert response.status_code == 200 assert response.data["errors"] is None assert set(response.data["meta"]["pagination"]) == set( contract["components"]["schemas"]["SourceRecordPagination"]["required"] ) for row in response.data["data"]: serializer = list_serializer(data=row["payload"]) assert serializer.is_valid(), serializer.errors detail = client.get( reverse( "api_v2:organizations:organization-source-records-detail", kwargs={"uid": row["uid"]}, ) ) assert detail.status_code == 200 serializer = detail_serializer(data=detail.data["payload"]) assert serializer.is_valid(), serializer.errors assert detail.data["organization"] == row["organization"] if source == "fns_sme_support_recipients": assert row["payload"] == { key: detail.data["payload"][key] for key in row["payload"] } else: assert ( row["payload"]["registry"]["code"] == detail.data["payload"]["registry"]["code"] ) @pytest.mark.parametrize( "uid,expected", [("broken", 400), ("00000000-0000-0000-0000-000000000099", 404)] ) def test_invalid_or_absent_detail_is_typed_error(registry_query, uid, expected): client, _ = registry_query response = client.get( reverse( "api_v2:organizations:organization-source-records-detail", kwargs={"uid": uid}, ) ) assert response.status_code == expected assert response.data["success"] is False assert response.data["data"] is None assert response.data["errors"][0]["code"] in { "invalid_uid", "source_record_not_found", }