from __future__ import annotations import io import pytest class DynamicService: def generate(self, ontology_uid, payload, actor_uid): return { "change_set_uid": "change-1", "suggestions": [ { "uid": "suggestion-1", "kind": "class", "confidence": 0.95, "evidence_uids": ["domain-1"], } ], } def decide(self, ontology_uid, change_set_uid, decisions, actor_uid): return {"uid": change_set_uid, "ontology_uid": ontology_uid, "decisions": decisions, "actor_uid": actor_uid} class ExchangeService: def export(self, ontology_uid, format_name): assert (ontology_uid, format_name) == ("ontology-1", "json") return b'{"ontology_uid":"ontology-1"}', "application/json", "ontology-1.json" def import_document(self, content, format_name, actor_uid): return { "ontology_uid": "ontology-2", "version": 1, "format": format_name, "actor_uid": actor_uid, "content": content.decode("utf-8"), } class SemanticService: def trace_property(self, uid, *, allowed_domains, limit, after_uid): return {"items": [{"property_uid": uid, "business_domain_uid": next(iter(allowed_domains))}], "count": 1, "truncated": False, "next_cursor": None} @pytest.fixture() def client(monkeypatch): from flask import request from app import create_app from app.api.data_development import routes from app.core.system import permissions def identity(): role = request.headers.get("Authorization", "").removeprefix("Bearer ") return {"id": f"{role}-1", "roles": [role]} if role in {"viewer", "editor", "admin"} else None monkeypatch.setattr(permissions, "authenticate_request", identity) monkeypatch.setattr(routes, "get_ontology_dynamic_service", lambda: DynamicService()) monkeypatch.setattr(routes, "get_ontology_exchange_service", lambda: ExchangeService()) monkeypatch.setattr(routes, "get_semantic_query_service", lambda: SemanticService()) app = create_app() app.config.update(TESTING=True) return app.test_client() def test_dynamic_suggestion_and_audited_decision_endpoints(client): headers = {"Authorization": "Bearer editor"} generated = client.post( "/api/development/v1/ontologies/ontology-1/suggestions", headers=headers, json={"domains": [], "data_elements": [], "foreign_keys": []}, ) decided = client.post( "/api/development/v1/ontologies/ontology-1/change-sets/change-1/decisions", headers=headers, json={"decisions": [{"suggestion_uid": "suggestion-1", "decision": "accept"}]}, ) assert generated.get_json()["data"]["change_set_uid"] == "change-1" assert generated.get_json()["data"]["suggestions"][0]["evidence_uids"] == [ "domain-1" ] assert decided.get_json()["data"]["actor_uid"] == "editor-1" def test_exchange_and_read_only_semantic_query_endpoints(client): exported = client.get( "/api/development/v1/ontologies/ontology-1/export?format=json", headers={"Authorization": "Bearer viewer"}, ) imported = client.post( "/api/development/v1/ontologies/import?format=json", headers={"Authorization": "Bearer editor"}, data=b'{"ontology_uid":"ontology-2"}', content_type="application/json", ) queried = client.get( "/api/development/v1/semantic/properties/property-1?business_domain_uid=sales&limit=20", headers={"Authorization": "Bearer viewer"}, ) assert exported.status_code == 200 and exported.mimetype == "application/json" assert imported.status_code == 201 assert queried.get_json()["data"]["items"][0]["business_domain_uid"] == "sales" def test_ontology_import_accepts_browser_multipart_upload(client): imported = client.post( "/api/development/v1/ontologies/import?format=json", headers={"Authorization": "Bearer editor"}, data={ "file": ( io.BytesIO(b'{"ontology_uid":"ontology-2"}'), "ontology.json", ) }, content_type="multipart/form-data", ) assert imported.status_code == 201 assert imported.get_json()["data"]["content"] == ( '{"ontology_uid":"ontology-2"}' )