diff --git a/src/karapace/client.py b/src/karapace/client.py index 22fd563a9..24341a666 100644 --- a/src/karapace/client.py +++ b/src/karapace/client.py @@ -5,10 +5,11 @@ See LICENSE for details """ +from typing import Literal from aiohttp import BasicAuth, ClientSession from collections.abc import Awaitable, Callable, Mapping from karapace.typing import JsonData -from urllib.parse import urljoin +from urllib.parse import urljoin, quote_plus import logging import ssl @@ -115,6 +116,7 @@ async def delete( path: Path, headers: Headers | None = None, auth: BasicAuth | None = None, + params: Mapping[str, str] | None = None, ) -> Result: path = self.path_for(path) if not headers: @@ -125,6 +127,7 @@ async def delete( headers=headers, auth=auth, ssl=self.ssl_mode, + params=params, ) as res: json_result = {} if res.status == 204 else await res.json() return Result(res.status, json_result, headers=res.headers) @@ -135,6 +138,7 @@ async def post( json: JsonData, headers: Headers | None = None, auth: BasicAuth | None = None, + params: Mapping[str, str] | None = None, ) -> Result: path = self.path_for(path) if not headers: @@ -147,6 +151,7 @@ async def post( auth=auth, json=json, ssl=self.ssl_mode, + params=params, ) as res: json_result = {} if res.status == 204 else await res.json() return Result(res.status, json_result, headers=res.headers) @@ -191,3 +196,89 @@ async def put_with_data( ) as res: json_result = await res.json() return Result(res.status, json_result, headers=res.headers) + + # Per resource functions + # COMPATIBILITY + async def post_compatibility_subject_version( + self, *, subject: str, version: int | Literal["latest"], json: JsonData + ) -> Result: + return await self.post( + path=f"compatibility/subjects/{quote_plus(subject)}/versions/{version}", + json=json, + ) + + # CONFIG + async def get_config(self) -> Result: + return await self.get(path="/config") + + async def put_config(self, *, json: JsonData) -> Result: + return await self.put(path="/config", json=json) + + async def get_config_subject(self, *, subject: str, defaultToGlobal: bool | None = None) -> Result: + path = f"/config/{quote_plus(subject)}" + if defaultToGlobal is not None: + path = f"{path}?defaultToGlobal={str(defaultToGlobal).lower()}" + return await self.get(path=path) + + async def put_config_subject(self, *, subject: str, json: JsonData) -> Result: + return await self.put(path=f"config/{quote_plus(subject)}", json=json) + + async def delete_config_subject(self, *, subject: str) -> Result: + return await self.delete(path=f"config/{quote_plus(subject)}") + + # MODE + async def get_mode(self) -> Result: + return await self.get(path="/mode") + + async def get_mode_subject(self, *, subject: str) -> Result: + return await self.get(path=f"/mode/{quote_plus(subject)}") + + # SCHEMAS + async def get_schemas(self) -> Result: + return await self.get("/schemas") + + async def get_types(self) -> Result: + return await self.get(path="/schemas/types") + + async def get_schema_by_id(self, *, schema_id: int, params: Mapping[str, str] | None = None) -> Result: + return await self.get(path=f"/schemas/ids/{schema_id}", params=params) + + async def get_schema_by_id_versions(self, *, schema_id: int, params: Mapping[str, str] | None = None) -> Result: + return await self.get(path=f"/schemas/ids/{schema_id}/versions", params=params) + + # SUBJECTS + async def get_subjects(self, *, params: Mapping[str, str] | None = None) -> Result: + return await self.get("/subjects", params=params) + + async def get_subjects_versions(self, *, subject: str) -> Result: + return await self.get(f"subjects/{quote_plus(subject)}/versions") + + async def post_subjects(self, *, subject: str, json: JsonData, params: Mapping[str, str] | None = None) -> Result: + return await self.post(f"/subjects/{quote_plus(subject)}", json=json, params=params) + + async def post_subjects_versions( + self, *, subject: str, json: JsonData, params: Mapping[str, str] | None = None + ) -> Result: + return await self.post(f"/subjects/{quote_plus(subject)}/versions", json=json, params=params) + + async def get_subjects_subject_version( + self, *, subject: str, version: int | Literal["latest"], params: Mapping[str, str] | None = None + ) -> Result: + return await self.get(f"/subjects/{quote_plus(subject)}/versions/{version}", params=params) + + async def get_subjects_subject_version_schema(self, *, subject: str, version: int | Literal["latest"]) -> Result: + return await self.get(f"subjects/{quote_plus(subject)}/versions/{version}/schema") + + async def get_subjects_subject_version_referenced_by(self, *, subject: str, version: int | Literal["latest"]) -> Result: + return await self.get(f"subjects/{quote_plus(subject)}/versions/{version}/referencedby") + + async def delete_subjects(self, *, subject: str, params: Mapping[str, str] | None = None) -> Result: + return await self.delete(path=f"/subjects/{quote_plus(subject)}", params=params) + + async def delete_subjects_version( + self, *, subject: str, version: int | Literal["latest"], permanent: bool | None = None + ) -> Result: + path = f"subjects/{quote_plus(subject)}/versions/{version}" + if permanent is not None: + path = f"{path}?permanent={str(permanent).lower()}" + return await self.delete(path) diff --git a/src/schema_registry/routers/compatibility.py b/src/schema_registry/routers/compatibility.py index 109df4e95..8b00a2f8a 100644 --- a/src/schema_registry/routers/compatibility.py +++ b/src/schema_registry/routers/compatibility.py @@ -10,14 +10,17 @@ from schema_registry.container import SchemaRegistryContainer from schema_registry.controller import KarapaceSchemaRegistryController from schema_registry.routers.errors import unauthorized +from schema_registry.routers.raw_path_router import RawPathRoute from schema_registry.routers.requests import CompatibilityCheckResponse, SchemaRequest from schema_registry.user import get_current_user from typing import Annotated +from urllib.parse import unquote_plus compatibility_router = APIRouter( prefix="/compatibility", tags=["compatibility"], responses={404: {"description": "Not found"}}, + route_class=RawPathRoute, ) @@ -31,6 +34,7 @@ async def compatibility_post( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> CompatibilityCheckResponse: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() diff --git a/src/schema_registry/routers/config.py b/src/schema_registry/routers/config.py index de151b8da..620f090bc 100644 --- a/src/schema_registry/routers/config.py +++ b/src/schema_registry/routers/config.py @@ -16,6 +16,7 @@ from schema_registry.routers.requests import CompatibilityLevelResponse, CompatibilityRequest, CompatibilityResponse from schema_registry.user import get_current_user from typing import Annotated +from urllib.parse import unquote_plus config_router = APIRouter( @@ -72,6 +73,7 @@ async def config_get_subject( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> CompatibilityLevelResponse: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() @@ -90,6 +92,7 @@ async def config_set_subject( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> CompatibilityResponse: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Write, f"Subject:{subject}"): raise unauthorized() @@ -114,6 +117,7 @@ async def config_delete_subject( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> CompatibilityResponse: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Write, f"Subject:{subject}"): raise unauthorized() diff --git a/src/schema_registry/routers/mode.py b/src/schema_registry/routers/mode.py index 0c3c6d1e7..0970eebb7 100644 --- a/src/schema_registry/routers/mode.py +++ b/src/schema_registry/routers/mode.py @@ -14,6 +14,7 @@ from schema_registry.routers.requests import ModeResponse from schema_registry.user import get_current_user from typing import Annotated +from urllib.parse import unquote_plus mode_router = APIRouter( prefix="/mode", @@ -44,6 +45,11 @@ async def mode_get_subject( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> ModeResponse: + import logging + + logging.error("B SUBJECT: %s", subject) + subject = Subject(unquote_plus(subject)) + logging.error("A SUBJECT: %s", subject) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() diff --git a/src/schema_registry/routers/subjects.py b/src/schema_registry/routers/subjects.py index a3fae0720..adc17181b 100644 --- a/src/schema_registry/routers/subjects.py +++ b/src/schema_registry/routers/subjects.py @@ -6,8 +6,6 @@ from dependency_injector.wiring import inject, Provide from fastapi import APIRouter, Depends, Request from karapace.auth import AuthenticatorAndAuthorizer, Operation, User -from karapace.config import Config -from karapace.container import KarapaceContainer from karapace.forward_client import ForwardClient from karapace.typing import Subject from schema_registry.container import SchemaRegistryContainer @@ -18,6 +16,7 @@ from schema_registry.routers.requests import SchemaIdResponse, SchemaRequest, SchemaResponse, SubjectSchemaVersionResponse from schema_registry.user import get_current_user from typing import Annotated +from urllib.parse import unquote_plus import logging @@ -58,6 +57,7 @@ async def subjects_subject_post( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> SchemaResponse: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() @@ -80,8 +80,8 @@ async def subjects_subject_delete( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), schema_registry: KarapaceSchemaRegistry = Depends(Provide[SchemaRegistryContainer.schema_registry]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), - config: Config = Depends(Provide[KarapaceContainer.config]), ) -> list[int]: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Write, f"Subject:{subject}"): raise unauthorized() @@ -107,6 +107,7 @@ async def subjects_subject_versions_post( normalize: bool = False, controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> SchemaIdResponse: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Write, f"Subject:{subject}"): raise unauthorized() @@ -130,6 +131,7 @@ async def subjects_subject_versions_list( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> list[int]: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() @@ -146,6 +148,7 @@ async def subjects_subject_version_get( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> SubjectSchemaVersionResponse: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() @@ -165,6 +168,7 @@ async def subjects_subject_version_delete( schema_registry: KarapaceSchemaRegistry = Depends(Provide[SchemaRegistryContainer.schema_registry]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> int: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Write, f"Subject:{subject}"): raise unauthorized() @@ -187,6 +191,7 @@ async def subjects_subject_version_schema_get( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> dict: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() @@ -202,6 +207,7 @@ async def subjects_subject_version_referenced_by( authorizer: AuthenticatorAndAuthorizer = Depends(Provide[SchemaRegistryContainer.karapace_container.authorizer]), controller: KarapaceSchemaRegistryController = Depends(Provide[SchemaRegistryContainer.schema_registry_controller]), ) -> list[int]: + subject = Subject(unquote_plus(subject)) if authorizer and not authorizer.check_authorization(user, Operation.Read, f"Subject:{subject}"): raise unauthorized() diff --git a/tests/integration/test_dependencies_compatibility_protobuf.py b/tests/integration/test_dependencies_compatibility_protobuf.py index 87b2dd740..805b9e56e 100644 --- a/tests/integration/test_dependencies_compatibility_protobuf.py +++ b/tests/integration/test_dependencies_compatibility_protobuf.py @@ -12,7 +12,7 @@ async def test_protobuf_schema_compatibility(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_schema_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_dependencies = """ @@ -36,15 +36,17 @@ async def test_protobuf_schema_compatibility(registry_async_client: Client) -> N |""" original_dependencies = trim_margin(original_dependencies) - res = await registry_async_client.post( - "subjects/container1/versions", json={"schemaType": "PROTOBUF", "schema": original_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container1", + json={"schemaType": "PROTOBUF", "schema": original_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() evolved_dependencies = trim_margin(evolved_dependencies) - res = await registry_async_client.post( - "subjects/container2/versions", json={"schemaType": "PROTOBUF", "schema": evolved_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container2", + json={"schemaType": "PROTOBUF", "schema": evolved_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() @@ -66,8 +68,8 @@ async def test_protobuf_schema_compatibility(registry_async_client: Client) -> N original_schema = trim_margin(original_schema) original_references = [{"name": "container1.proto", "subject": "container1", "version": 1}] - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema, "references": original_references}, ) assert res.status_code == 200 @@ -88,8 +90,9 @@ async def test_protobuf_schema_compatibility(registry_async_client: Client) -> N |""" evolved_schema = trim_margin(evolved_schema) evolved_references = [{"name": "container2.proto", "subject": "container2", "version": 1}] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": evolved_schema, "references": evolved_references}, ) assert res.status_code == 200 @@ -99,7 +102,7 @@ async def test_protobuf_schema_compatibility(registry_async_client: Client) -> N async def test_protobuf_schema_compatibility_dependencies(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_schema_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_dependencies = """ @@ -123,15 +126,17 @@ async def test_protobuf_schema_compatibility_dependencies(registry_async_client: |""" original_dependencies = trim_margin(original_dependencies) - res = await registry_async_client.post( - "subjects/container1/versions", json={"schemaType": "PROTOBUF", "schema": original_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container1", + json={"schemaType": "PROTOBUF", "schema": original_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() evolved_dependencies = trim_margin(evolved_dependencies) - res = await registry_async_client.post( - "subjects/container2/versions", json={"schemaType": "PROTOBUF", "schema": evolved_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container2", + json={"schemaType": "PROTOBUF", "schema": evolved_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() @@ -153,8 +158,8 @@ async def test_protobuf_schema_compatibility_dependencies(registry_async_client: original_schema = trim_margin(original_schema) original_references = [{"name": "container1.proto", "subject": "container1", "version": 1}] - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema, "references": original_references}, ) assert res.status_code == 200 @@ -175,8 +180,9 @@ async def test_protobuf_schema_compatibility_dependencies(registry_async_client: |""" evolved_schema = trim_margin(evolved_schema) evolved_references = [{"name": "container2.proto", "subject": "container2", "version": 1}] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": evolved_schema, "references": evolved_references}, ) assert res.status_code == 200 @@ -186,7 +192,7 @@ async def test_protobuf_schema_compatibility_dependencies(registry_async_client: async def test_protobuf_schema_compatibility_dependencies1(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_schema_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_dependencies = """ @@ -210,15 +216,17 @@ async def test_protobuf_schema_compatibility_dependencies1(registry_async_client |""" original_dependencies = trim_margin(original_dependencies) - res = await registry_async_client.post( - "subjects/container1/versions", json={"schemaType": "PROTOBUF", "schema": original_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container1", + json={"schemaType": "PROTOBUF", "schema": original_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() evolved_dependencies = trim_margin(evolved_dependencies) - res = await registry_async_client.post( - "subjects/container2/versions", json={"schemaType": "PROTOBUF", "schema": evolved_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container2", + json={"schemaType": "PROTOBUF", "schema": evolved_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() @@ -240,8 +248,8 @@ async def test_protobuf_schema_compatibility_dependencies1(registry_async_client original_schema = trim_margin(original_schema) original_references = [{"name": "container1.proto", "subject": "container1", "version": 1}] - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema, "references": original_references}, ) assert res.status_code == 200 @@ -262,8 +270,9 @@ async def test_protobuf_schema_compatibility_dependencies1(registry_async_client |""" evolved_schema = trim_margin(evolved_schema) evolved_references = [{"name": "container2.proto", "subject": "container2", "version": 1}] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": evolved_schema, "references": evolved_references}, ) assert res.status_code == 200 @@ -275,7 +284,7 @@ async def test_protobuf_schema_compatibility_dependencies1g(registry_async_clien subject = create_subject_name_factory("test_protobuf_schema_compatibility_dep1g")() subject_container = create_subject_name_factory("test_protobuf_schema_compatibility_dep1g_container")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 container = """ @@ -288,8 +297,9 @@ async def test_protobuf_schema_compatibility_dependencies1g(registry_async_clien } """ - res = await registry_async_client.post( - f"subjects/{subject_container}/versions", json={"schemaType": "PROTOBUF", "schema": container} + res = await registry_async_client.post_subjects_versions( + subject=subject_container, + json={"schemaType": "PROTOBUF", "schema": container}, ) assert res.status_code == 200 assert "id" in res.json() @@ -309,8 +319,8 @@ async def test_protobuf_schema_compatibility_dependencies1g(registry_async_clien """ original_references = [{"name": "container.proto", "subject": subject_container, "version": 1}] - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema, "references": original_references}, ) assert res.status_code == 200 @@ -330,8 +340,9 @@ async def test_protobuf_schema_compatibility_dependencies1g(registry_async_clien } """ - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": evolved_schema}, ) assert res.status_code == 200 @@ -343,7 +354,7 @@ async def test_protobuf_schema_compatibility_dependencies1g_otherway(registry_as subject = create_subject_name_factory("test_protobuf_schema_compatibility_dep1g_back")() subject_container = create_subject_name_factory("test_protobuf_schema_compatibility_dep1g_back_container")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 container = """ @@ -356,8 +367,9 @@ async def test_protobuf_schema_compatibility_dependencies1g_otherway(registry_as } """ - res = await registry_async_client.post( - f"subjects/{subject_container}/versions", json={"schemaType": "PROTOBUF", "schema": container} + res = await registry_async_client.post_subjects_versions( + subject=subject_container, + json={"schemaType": "PROTOBUF", "schema": container}, ) assert res.status_code == 200 assert "id" in res.json() @@ -376,8 +388,8 @@ async def test_protobuf_schema_compatibility_dependencies1g_otherway(registry_as } """ - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema}, ) assert res.status_code == 200 @@ -398,8 +410,9 @@ async def test_protobuf_schema_compatibility_dependencies1g_otherway(registry_as """ container_references = [{"name": "container.proto", "subject": subject_container, "version": 1}] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": evolved_schema, "references": container_references}, ) assert res.status_code == 200 @@ -409,7 +422,7 @@ async def test_protobuf_schema_compatibility_dependencies1g_otherway(registry_as async def test_protobuf_schema_compatibility_dependencies2(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_schema_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_dependencies = """ @@ -431,15 +444,17 @@ async def test_protobuf_schema_compatibility_dependencies2(registry_async_client |""" original_dependencies = trim_margin(original_dependencies) - res = await registry_async_client.post( - "subjects/container1/versions", json={"schemaType": "PROTOBUF", "schema": original_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container1", + json={"schemaType": "PROTOBUF", "schema": original_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() evolved_dependencies = trim_margin(evolved_dependencies) - res = await registry_async_client.post( - "subjects/container2/versions", json={"schemaType": "PROTOBUF", "schema": evolved_dependencies} + res = await registry_async_client.post_subjects_versions( + subject="container2", + json={"schemaType": "PROTOBUF", "schema": evolved_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() @@ -460,8 +475,8 @@ async def test_protobuf_schema_compatibility_dependencies2(registry_async_client original_schema = trim_margin(original_schema) original_references = [{"name": "container1.proto", "subject": "container1", "version": 1}] - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema, "references": original_references}, ) assert res.status_code == 200 @@ -481,8 +496,9 @@ async def test_protobuf_schema_compatibility_dependencies2(registry_async_client |""" evolved_schema = trim_margin(evolved_schema) evolved_references = [{"name": "container2.proto", "subject": "container2", "version": 1}] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": evolved_schema, "references": evolved_references}, ) assert res.status_code == 200 @@ -500,35 +516,38 @@ async def test_protobuf_schema_compatibility_dependencies2(registry_async_client async def test_protobuf_schema_references_rejected_values(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_schema_references_values")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": 1} + res = await registry_async_client.post_subjects_versions( + subject=subject, + json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": 1}, ) assert res.status_code == 422 assert res.json()["message"] == [ {"type": "list_type", "loc": ["body", "references"], "msg": "Input should be a valid list", "input": 1} ] - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": "foo"} + res = await registry_async_client.post_subjects_versions( + subject=subject, + json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": "foo"}, ) assert res.status_code == 422 assert res.json()["message"] == [ {"type": "list_type", "loc": ["body", "references"], "msg": "Input should be a valid list", "input": "foo"} ] - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": False} + res = await registry_async_client.post_subjects_versions( + subject=subject, + json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": False}, ) assert res.status_code == 422 assert res.json()["message"] == [ {"type": "list_type", "loc": ["body", "references"], "msg": "Input should be a valid list", "input": False} ] - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": {"this_is_object": True}}, ) assert res.status_code == 422 @@ -544,24 +563,26 @@ async def test_protobuf_schema_references_rejected_values(registry_async_client: async def test_protobuf_schema_references_valid_values(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_schema_references_values")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 # null value accepted for compatibility, same as empty list - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": None} + res = await registry_async_client.post_subjects_versions( + subject=subject, + json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": None}, ) assert res.status_code == 200 - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": []} + res = await registry_async_client.post_subjects_versions( + subject=subject, + json={"schemaType": "PROTOBUF", "schema": SIMPLE_SCHEMA, "references": []}, ) assert res.status_code == 200 async def test_protobuf_references_latest(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_references_latest")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_dependencies = trim_margin( @@ -576,8 +597,9 @@ async def test_protobuf_references_latest(registry_async_client: Client) -> None |""" ) - res = await registry_async_client.post( - f"subjects/{subject}_base/versions", json={"schemaType": "PROTOBUF", "schema": original_dependencies} + res = await registry_async_client.post_subjects_versions( + subject=f"{subject}_base", + json={"schemaType": "PROTOBUF", "schema": original_dependencies}, ) assert res.status_code == 200 assert "id" in res.json() @@ -599,8 +621,8 @@ async def test_protobuf_references_latest(registry_async_client: Client) -> None ) original_references = [{"name": "container1.proto", "subject": f"{subject}_base", "version": -1}] - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema, "references": original_references}, ) assert res.status_code == 200 @@ -621,7 +643,7 @@ async def test_protobuf_customer_update_when_having_references(registry_async_cl """ body = {"schemaType": "PROTOBUF", "schema": place_proto} - res = await registry_async_client.post(f"subjects/{subject_place}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject_place, json=body) assert res.status_code == 200 @@ -649,7 +671,7 @@ async def test_protobuf_customer_update_when_having_references(registry_async_cl } ], } - res = await registry_async_client.post(f"subjects/{subject_customer}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject_customer, json=body) assert res.status_code == 200 @@ -678,7 +700,7 @@ async def test_protobuf_customer_update_when_having_references(registry_async_cl } ], } - res = await registry_async_client.post(f"subjects/{subject_customer}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject_customer, json=body) assert res.status_code == 200 @@ -699,7 +721,7 @@ async def test_protobuf_schema_lookup_with_other_version_having_references(regis "schemaType": "PROTOBUF", "schema": schema, } - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 old_id = res.json()["id"] @@ -718,7 +740,7 @@ async def test_protobuf_schema_lookup_with_other_version_having_references(regis "schemaType": "PROTOBUF", "schema": dependency, } - res = await registry_async_client.post(f"subjects/{subject_dependency}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject_dependency, json=body) assert res.status_code == 200 new_schema = trim_margin( @@ -743,13 +765,13 @@ async def test_protobuf_schema_lookup_with_other_version_having_references(regis } ], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 body = { "schemaType": "PROTOBUF", "schema": schema, } - res = await registry_async_client.post(f"subjects/{subject}", json=body) + res = await registry_async_client.post_subjects(subject=subject, json=body) assert res.status_code == 200 assert res.json()["id"] == old_id diff --git a/tests/integration/test_request_forwarding.py b/tests/integration/test_request_forwarding.py index 3264fb430..7daf5e4fe 100644 --- a/tests/integration/test_request_forwarding.py +++ b/tests/integration/test_request_forwarding.py @@ -14,6 +14,7 @@ repeat_until_master_is_available, repeat_until_successful_request, ) +from urllib.parse import quote_plus import asyncio import json @@ -58,13 +59,13 @@ async def test_schema_request_forwarding( max_tries, counter = 5, 0 wait_time = 0.5 - subject = create_subject_name_factory(subject)() # subject creation urlencodes + subject = create_subject_name_factory(subject)() schema = {"type": "string"} other_schema = {"type": "int"} # Config updates for subj_path in [None, subject]: if subj_path: - path = f"config/{subject}" + path = f"config/{quote_plus(subject)}" else: path = "config" for compat in ["FULL", "BACKWARD", "FORWARD", "NONE"]: @@ -92,7 +93,7 @@ async def test_schema_request_forwarding( # New schema updates, last compatibility is None for s in [schema, other_schema]: resp = await request_forwarding_retry_client.post( - f"{slave_url}/subjects/{subject}/versions", json={"schema": json.dumps(s)} + f"{slave_url}/subjects/{quote_plus(subject)}/versions", json={"schema": json.dumps(s)} ) assert resp.ok data = resp.json() @@ -100,7 +101,7 @@ async def test_schema_request_forwarding( counter = 0 while True: assert counter < max_tries, "Subject schema data not propagated yet" - resp = await request_forwarding_retry_client.get(f"{master_url}/subjects/{subject}/versions") + resp = await request_forwarding_retry_client.get(f"{master_url}/subjects/{quote_plus(subject)}/versions") if not resp.ok: print(f"Invalid http status code: {resp.status_code}") counter += 1 @@ -116,13 +117,13 @@ async def test_schema_request_forwarding( break # Schema deletions - resp = await request_forwarding_retry_client.delete(f"{slave_url}/subjects/{subject}/versions/1") + resp = await request_forwarding_retry_client.delete(f"{slave_url}/subjects/{quote_plus(subject)}/versions/1") assert resp.ok counter = 0 while True: assert counter < max_tries, "Subject version deletion not propagated yet" resp = await request_forwarding_retry_client.get( - f"{master_url}/subjects/{subject}/versions/1", expected_response_code=404 + f"{master_url}/subjects/{quote_plus(subject)}/versions/1", expected_response_code=404 ) if resp.ok: print(f"Subject {subject} still has version 1 on master") @@ -137,7 +138,7 @@ async def test_schema_request_forwarding( assert resp.ok data = resp.json() assert subject in data - resp = await request_forwarding_retry_client.delete(f"{slave_url}/subjects/{subject}") + resp = await request_forwarding_retry_client.delete(f"{slave_url}/subjects/{quote_plus(subject)}") assert resp.ok counter = 0 while True: diff --git a/tests/integration/test_schema.py b/tests/integration/test_schema.py index 9723d98e9..19b9438b0 100644 --- a/tests/integration/test_schema.py +++ b/tests/integration/test_schema.py @@ -11,6 +11,7 @@ from karapace.kafka.producer import KafkaProducer from karapace.rapu import is_success from karapace.schema_type import SchemaType +from karapace.typing import JsonData from karapace.utils import json_encode from schema_registry.controller import SchemaErrorMessages from tests.base_testcase import BaseTestCase @@ -37,7 +38,7 @@ async def test_union_to_union(registry_async_client: Client) -> None: subject_name_factory = create_subject_name_factory("test_union_to_union") subject_1 = subject_name_factory() - res = await registry_async_client.put(f"config/{subject_1}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject_1, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 init_schema = {"name": "init", "type": "record", "fields": [{"name": "inner", "type": ["string", "int"]}]} evolved = {"name": "init", "type": "record", "fields": [{"name": "inner", "type": ["null", "string"]}]} @@ -55,36 +56,42 @@ async def test_union_to_union(registry_async_client: Client) -> None: } ], } - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(init_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(init_schema)}) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(evolved)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(evolved)}) assert res.status_code == 409 - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(evolved_compatible)}) + res = await registry_async_client.post_subjects_versions( + subject=subject_1, json={"schema": json.dumps(evolved_compatible)} + ) assert res.status_code == 200 # fw compat check subject_2 = subject_name_factory() - res = await registry_async_client.put(f"config/{subject_2}", json={"compatibility": "FORWARD"}) + res = await registry_async_client.put_config_subject(subject=subject_2, json={"compatibility": "FORWARD"}) assert res.status_code == 200 - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(evolved_compatible)}) + res = await registry_async_client.post_subjects_versions( + subject=subject_2, json={"schema": json.dumps(evolved_compatible)} + ) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(evolved)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(evolved)}) assert res.status_code == 409 - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(init_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(init_schema)}) assert res.status_code == 200 async def test_missing_subject_compatibility(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_missing_subject_compatibility")() - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps({"type": "string"})}) + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": json.dumps({"type": "string"})} + ) assert res.status_code == 200, f"{res} {subject}" - res = await registry_async_client.get(f"config/{subject}") + res = await registry_async_client.get_config_subject(subject=subject) assert res.status_code == 404, f"{res} {subject}" - res = await registry_async_client.get(f"config/{subject}?defaultToGlobal=false") + res = await registry_async_client.get_config_subject(subject=subject, defaultToGlobal=False) assert res.status_code == 404, f"subject should have no compatibility when not defaulting to global: {res.json()}" - res = await registry_async_client.get(f"config/{subject}?defaultToGlobal=true") + res = await registry_async_client.get_config_subject(subject=subject, defaultToGlobal=True) assert res.status_code == 200, f"subject should have a compatibility when not defaulting to global: {res.json()}" assert "compatibilityLevel" in res.json(), res.json() @@ -95,8 +102,8 @@ async def test_subject_allowed_chars(registry_async_client: Client) -> None: for suffix in ['"', "{", ":", "}", "'"]: subject = f"{subject_prefix}{suffix}" - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schema": json.dumps({"type": "string"})} + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": json.dumps({"type": "string"})} ) assert res.status_code == 200, f"{res} {subject}" @@ -104,7 +111,7 @@ async def test_subject_allowed_chars(registry_async_client: Client) -> None: async def test_record_union_schema_compatibility(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_record_union_schema_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_schema = { "name": "bar", @@ -123,7 +130,7 @@ async def test_record_union_schema_compatibility(registry_async_client: Client) } ], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(original_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(original_schema)}) assert res.status_code == 200 assert "id" in res.json() @@ -151,22 +158,20 @@ async def test_record_union_schema_compatibility(registry_async_client: Client) } ], } - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", - json={"schema": json.dumps(evolved_schema)}, + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, version="latest", json={"schema": json.dumps(evolved_schema)} ) assert res.status_code == 200 - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(evolved_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(evolved_schema)}) assert res.status_code == 200 assert "id" in res.json() # Check that we can delete the field as well - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", - json={"schema": json.dumps(original_schema)}, + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, version="latest", json={"schema": json.dumps(original_schema)} ) assert res.status_code == 200 - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(original_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(original_schema)}) assert res.status_code == 200 assert "id" in res.json() @@ -174,7 +179,7 @@ async def test_record_union_schema_compatibility(registry_async_client: Client) async def test_record_nested_schema_compatibility(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_record_nested_schema_compatibility")() - res = await registry_async_client.put("config", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config(json={"compatibility": "BACKWARD"}) assert res.status_code == 200 schema = { "type": "record", @@ -199,36 +204,27 @@ async def test_record_nested_schema_compatibility(registry_async_client: Client) }, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() # change string to integer in the nested record, should fail schema["fields"][1]["type"]["fields"][0]["type"] = "int" - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 409 async def test_record_schema_subject_compatibility(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_record_schema_subject_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_schema = { "fields": [{"name": "name", "type": "string"}, {"name": "age", "type": "int"}], "name": "user", "type": "record", } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(original_schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(original_schema)}) assert res.status_code == 200 assert "id" in res.json() @@ -241,22 +237,23 @@ async def test_record_schema_subject_compatibility(registry_async_client: Client "name": "user", "type": "record", } - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schema": json.dumps(evolved_schema)}, ) assert res.status_code == 200 - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(evolved_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(evolved_schema)}) assert res.status_code == 200 assert "id" in res.json() result = {"id": 1, "schema": json_encode(original_schema, compact=True), "subject": subject, "version": 1} - res = await registry_async_client.get(f"subjects/{subject}/versions/1") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=1) assert res.status_code == 200 assert res.json() == result result = {"id": 2, "schema": json_encode(evolved_schema, compact=True), "subject": subject, "version": 2} - res = await registry_async_client.get(f"subjects/{subject}/versions/latest") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version="latest") assert res.status_code == 200 assert res.json() == result @@ -271,10 +268,7 @@ async def test_compatibility_endpoint(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_compatibility_endpoint")() schema_name = create_schema_name_factory("test_compatibility_endpoint")() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json=-1, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json=-1) assert res.status_code == 422 schema = { @@ -288,19 +282,17 @@ async def test_compatibility_endpoint(registry_async_client: Client) -> None: ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 # replace int with long schema["fields"] = [{"type": "long", "name": "age"}] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schema": json.dumps(schema)}, ) assert res.status_code == 200 @@ -308,9 +300,8 @@ async def test_compatibility_endpoint(registry_async_client: Client) -> None: # replace int with string schema["fields"] = [{"type": "string", "name": "age"}] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", - json={"schema": json.dumps(schema)}, + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, version="latest", json={"schema": json.dumps(schema)} ) assert res.status_code == 200 assert res.json().get("is_compatible") is False @@ -335,16 +326,13 @@ async def test_regression_compatibility_should_not_give_internal_server_error_on ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 # replace int with long - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", - json={"schema": json.dumps(schema), "schemaType": "AVROO"}, + # TODO: schema type is invalid, but test is documented to change int with long. + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, version="latest", json={"schema": json.dumps(schema), "schemaType": "AVROO"} ) assert res.status_code == HTTPStatus.UNPROCESSABLE_ENTITY assert res.json()["error_code"] == HTTPStatus.UNPROCESSABLE_ENTITY @@ -371,39 +359,39 @@ async def test_compatibility_to_non_existent_schema_version_returns_404(registry } # Test compatibility returns 404 not found for non-existing subject - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/1", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version=1, json={"schema": json.dumps(schema), "schemaType": "AVRO"}, ) assert res.status_code == 404 assert res.json()["error_code"] == 40402 - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 # Soft delete - res = await registry_async_client.delete(f"subjects/{subject}/versions/1") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1) assert res.status_code == 200 assert res.json() == 1 # Check compatibility after subject has only soft-deleted version schemas - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/1", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version=1, json={"schema": json.dumps(schema), "schemaType": "AVRO"}, ) assert res.status_code == 404 assert res.json()["error_code"] == 40402 # Hard delete - res = await registry_async_client.delete(f"subjects/{subject}/versions/1?permanent=true") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1, permanent=True) assert res.status_code == 200 # Test compatibility returns 404 again - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/1", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version=1, json={"schema": json.dumps(schema), "schemaType": "AVRO"}, ) assert res.status_code == 404 @@ -428,9 +416,8 @@ async def test_regression_invalid_schema_type_should_not_give_internal_server_er ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema), "schemaType": "AVROO"}, + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": json.dumps(schema), "schemaType": "AVROO"} ) assert res.status_code == HTTPStatus.UNPROCESSABLE_ENTITY assert res.json()["error_code"] == HTTPStatus.UNPROCESSABLE_ENTITY @@ -490,7 +477,7 @@ def _test_cases(): subject_name_factory = create_subject_name_factory("test_type_compatibility") for compatibility, source_type, target_type, expected in _test_cases(): subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) schema = { "type": "record", "name": "Objct", @@ -501,15 +488,13 @@ def _test_cases(): }, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 schema["fields"][0]["type"] = target_type - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schema": json.dumps(schema)}, ) assert res.status_code == 200 @@ -531,15 +516,12 @@ async def test_record_schema_compatibility_forward(registry_async_client: Client }, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema_1)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema_1)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] - res = await registry_async_client.put(f"/config/{subject}", json={"compatibility": "FORWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "FORWARD"}) assert res.status_code == 200 schema_2 = { @@ -551,10 +533,7 @@ async def test_record_schema_compatibility_forward(registry_async_client: Client {"name": "age", "type": "int"}, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema_2)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema_2)}) assert res.status_code == 200 assert "id" in res.json() schema_id2 = res.json()["id"] @@ -569,10 +548,7 @@ async def test_record_schema_compatibility_forward(registry_async_client: Client {"name": "age", "type": "int"}, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema_3a)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema_3a)}) # Fails because field removed assert res.status_code == 409 res_json = res.json() @@ -587,10 +563,7 @@ async def test_record_schema_compatibility_forward(registry_async_client: Client {"name": "age", "type": "long"}, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema_3b)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema_3b)}) # Fails because incompatible type change assert res.status_code == 409 res_json = res.json() @@ -606,10 +579,7 @@ async def test_record_schema_compatibility_forward(registry_async_client: Client {"name": "age", "type": "int"}, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema_4)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema_4)}) assert res.status_code == 200 @@ -628,13 +598,10 @@ async def test_record_schema_compatibility_backward(registry_async_client: Clien {"name": "age", "type": "int"}, ], } - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": json.dumps(schema_1)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema_1)}) assert res.status_code == 200 - res = await registry_async_client.put(f"config/{subject_1}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject_1, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 # adds fourth_name w/o default, invalid @@ -649,37 +616,28 @@ async def test_record_schema_compatibility_backward(registry_async_client: Clien {"name": "age", "type": "int"}, ], } - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": json.dumps(schema_2)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema_2)}) assert res.status_code == 409 # Add a default value for the field schema_2["fields"][3] = {"name": "fourth_name", "type": "string", "default": "foof"} - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": json.dumps(schema_2)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema_2)}) assert res.status_code == 200 assert "id" in res.json() # Try to submit schema with a different definition schema_2["fields"][3] = {"name": "fourth_name", "type": "int", "default": 2} - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": json.dumps(schema_2)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema_2)}) assert res.status_code == 409 subject_2 = subject_name_factory() - res = await registry_async_client.put(f"config/{subject_2}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject_2, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 schema_1 = {"type": "record", "name": schema_name, "fields": [{"name": "first_name", "type": "string"}]} - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema_1)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema_1)}) assert res.status_code == 200 schema_1["fields"].append({"name": "last_name", "type": "string"}) - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema_1)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema_1)}) assert res.status_code == 409 @@ -688,15 +646,15 @@ async def test_enum_schema_field_add_compatibility(registry_async_client: Client expected_results = [("BACKWARD", 200), ("FORWARD", 409), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 schema = {"type": "enum", "name": "Suit", "symbols": ["SPADES", "HEARTS", "DIAMONDS"]} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 # Add a field schema["symbols"].append("CLUBS") - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code @@ -705,15 +663,15 @@ async def test_array_schema_field_add_compatibility(registry_async_client: Clien expected_results = [("BACKWARD", 200), ("FORWARD", 409), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 schema = {"type": "array", "items": "int"} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 # Modify the items type schema["items"] = "long" - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code @@ -722,18 +680,18 @@ async def test_array_nested_record_compatibility(registry_async_client: Client) expected_results = [("BACKWARD", 409), ("FORWARD", 200), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 schema = { "type": "array", "items": {"type": "record", "name": "object", "fields": [{"name": "first_name", "type": "string"}]}, } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 # Add a second field to the record schema["items"]["fields"].append({"name": "last_name", "type": "string"}) - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code @@ -742,19 +700,19 @@ async def test_record_nested_array_compatibility(registry_async_client: Client) expected_results = [("BACKWARD", 200), ("FORWARD", 409), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 schema = { "type": "record", "name": "object", "fields": [{"name": "simplearray", "type": {"type": "array", "items": "int"}}], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 # Modify the array items type schema["fields"][0]["type"]["items"] = "long" - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code @@ -765,15 +723,15 @@ async def test_map_schema_field_add_compatibility( expected_results = [("BACKWARD", 200), ("FORWARD", 409), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 schema = {"type": "map", "values": "int"} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 # Modify the items type schema["values"] = "long" - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code @@ -782,54 +740,54 @@ async def test_enum_schema(registry_async_client: Client) -> None: expected_results = [("BACKWARD", 200, 409), ("FORWARD", 409, 200), ("FULL", 409, 409)] for compatibility, status_code_add, status_code_remove in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 schema = {"type": "enum", "name": "testenum", "symbols": ["first", "second"]} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) # Add a symbol. schema["symbols"].append("third") - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_add # Remove a symbol schema["symbols"].pop(1) if res.status_code != 200: schema["symbols"].pop(1) - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_remove # Change the name schema["name"] = "another" - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 409 # Inside record subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 schema = { "type": "record", "name": "object", "fields": [{"name": "enumkey", "type": {"type": "enum", "name": "testenum", "symbols": ["first", "second"]}}], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) # Add a symbol. schema["fields"][0]["type"]["symbols"].append("third") - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_add # Remove a symbol schema["fields"][0]["type"]["symbols"].pop(1) if res.status_code != 200: schema["fields"][0]["type"]["symbols"].pop(1) - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_remove # Change the name schema["fields"][0]["type"]["name"] = "another" - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 409 @@ -839,25 +797,25 @@ async def test_fixed_schema(registry_async_client: Client, compatibility: str) - status_code_allowed = 200 status_code_denied = 409 subject_1 = subject_name_factory() - res = await registry_async_client.put(f"config/{subject_1}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject_1, json={"compatibility": compatibility}) assert res.status_code == 200 schema = {"type": "fixed", "size": 16, "name": "md5", "aliases": ["testalias"]} - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema)}) # Add new alias schema["aliases"].append("anotheralias") - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_allowed # Try to change size schema["size"] = 32 - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_denied # Try to change name schema["size"] = 16 schema["name"] = "denied" - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_denied # In a record @@ -867,22 +825,22 @@ async def test_fixed_schema(registry_async_client: Client, compatibility: str) - "name": "object", "fields": [{"name": "fixedkey", "type": {"type": "fixed", "size": 16, "name": "md5", "aliases": ["testalias"]}}], } - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema)}) # Add new alias schema["fields"][0]["type"]["aliases"].append("anotheralias") - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_allowed # Try to change size schema["fields"][0]["type"]["size"] = 32 - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_denied # Try to change name schema["fields"][0]["type"]["size"] = 16 schema["fields"][0]["type"]["name"] = "denied" - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema)}) assert res.status_code == status_code_denied @@ -891,29 +849,29 @@ async def test_primitive_schema(registry_async_client: Client) -> None: expected_results = [("BACKWARD", 200), ("FORWARD", 200), ("FULL", 200)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 # Transition from string to bytes schema = {"type": "string"} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 schema["type"] = "bytes" - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == status_code expected_results = [("BACKWARD", 409), ("FORWARD", 409), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 # Transition from string to int schema = {"type": "string"} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 schema["type"] = "int" - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) async def test_union_comparing_to_other_types(registry_async_client: Client) -> None: @@ -921,57 +879,57 @@ async def test_union_comparing_to_other_types(registry_async_client: Client) -> expected_results = [("BACKWARD", 409), ("FORWARD", 200), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 # Union vs non-union with the same schema schema = [{"type": "array", "name": "listofstrings", "items": "string"}, "string"] - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 - initial_schema_id = res.json()["id"] + initial_schema_id = int(res.json()["id"]) plain_schema = {"type": "string"} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(plain_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(plain_schema)}) assert res.status_code == status_code - res = await registry_async_client.get(f"/schemas/ids/{initial_schema_id}", params={"includeSubjects": "True"}) + res = await registry_async_client.get_schema_by_id(schema_id=initial_schema_id, params={"includeSubjects": "true"}) assert subject in res.json()["subjects"] expected_results = [("BACKWARD", 200), ("FORWARD", 409), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 # Non-union first schema = {"type": "array", "name": "listofstrings", "items": "string"} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 union_schema = [{"type": "array", "name": "listofstrings", "items": "string"}, "string"] - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(union_schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(union_schema)}) assert res.status_code == status_code expected_results = [("BACKWARD", 409), ("FORWARD", 409), ("FULL", 409)] for compatibility, status_code in expected_results: subject = subject_name_factory() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) assert res.status_code == 200 # Union to a completely different schema schema = [{"type": "array", "name": "listofstrings", "items": "string"}, "string"] - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 plain_wrong_schema = {"type": "int"} - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schema": json.dumps(plain_wrong_schema)} + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": json.dumps(plain_wrong_schema)} ) assert res.status_code == status_code async def test_transitive_compatibility(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_transitive_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD_TRANSITIVE"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD_TRANSITIVE"}) assert res.status_code == 200 schema0 = { @@ -981,10 +939,7 @@ async def test_transitive_compatibility(registry_async_client: Client) -> None: {"name": "age", "type": "int"}, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema0)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema0)}) assert res.status_code == 200 schema1 = { @@ -999,10 +954,7 @@ async def test_transitive_compatibility(registry_async_client: Client) -> None: }, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema1)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema1)}) assert res.status_code == 200 schema2 = { @@ -1021,10 +973,7 @@ async def test_transitive_compatibility(registry_async_client: Client) -> None: }, ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema2)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema2)}) assert res.status_code == 409 res_json = res.json() assert res_json["error_code"] == 409 @@ -1034,7 +983,7 @@ async def assert_schema_versions(client: Client, schema_id: int, expected: list[ """ Calls /schemas/ids/{schema_id}/versions and asserts the expected results were in the response. """ - res = await client.get(f"/schemas/ids/{schema_id}/versions") + res = await client.get_schema_by_id_versions(schema_id=schema_id) assert res.status_code == 200 registered_schemas = res.json() @@ -1048,7 +997,7 @@ async def assert_schema_versions_failed(client: Client, schema_id: int, response """ Calls /schemas/ids/{schema_id}/versions and asserts the response code is the expected. """ - res = await client.get(f"/schemas/ids/{schema_id}/versions") + res = await client.get_schema_by_id(schema_id=schema_id) assert res.status_code == response_code @@ -1056,24 +1005,21 @@ async def register_schema( registry_async_client: Client, subject: str, schema_str: str, schema_type: SchemaType = SchemaType.AVRO ) -> tuple[int, int]: # Register to get the id - payload = {"schema": schema_str} + payload: JsonData = {"schema": schema_str} if schema_type == SchemaType.JSONSCHEMA: payload["schemaType"] = "JSON" elif schema_type == SchemaType.PROTOBUF: payload["schemaType"] = "PROTOBUF" else: pass - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json=payload, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json=payload) assert res.status_code == 200 - schema_id = res.json()["id"] + schema_id = int(res.json()["id"]) # Get version - res = await registry_async_client.post(f"subjects/{subject}", json=payload) + res = await registry_async_client.post_subjects(subject=subject, json=payload) assert res.status_code == 200 - assert res.json()["id"] == schema_id + assert int(res.json()["id"]) == schema_id return schema_id, res.json()["version"] @@ -1202,7 +1148,7 @@ async def test_schema_versions_multiple_subjects_same_schema( await assert_schema_versions(registry_async_client, schema_id_1, schema_1_versions) await assert_schema_versions(registry_async_client, schema_id_4, schema_2_versions) - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert res.status_code == 200 assert res.json() == [subject_1, subject_2, subject_3, subject_4] @@ -1233,7 +1179,7 @@ async def test_schema_versions_deleting(registry_async_client: Client) -> None: schema_1_versions = [(subject, version_1)] await assert_schema_versions(registry_async_client, schema_id_1, schema_1_versions) - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 schema_id_2, version_2 = await register_schema(registry_async_client, subject, schema_str_2) @@ -1241,7 +1187,7 @@ async def test_schema_versions_deleting(registry_async_client: Client) -> None: await assert_schema_versions(registry_async_client, schema_id_2, schema_2_versions) # Deleting one version, the other still found - res = await registry_async_client.delete(f"subjects/{subject}/versions/{version_1}") + res = await registry_async_client.delete_subjects_version(subject=subject, version=version_1) assert res.status_code == 200 assert res.json() == version_1 @@ -1249,7 +1195,7 @@ async def test_schema_versions_deleting(registry_async_client: Client) -> None: await assert_schema_versions(registry_async_client, schema_id_2, schema_2_versions) # Deleting the subject, the schema version 2 cannot be found anymore - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 assert res.json() == [version_2] @@ -1283,7 +1229,7 @@ async def test_schema_delete_latest_version(registry_async_client: Client) -> No schema_1_versions = [(subject, version_1)] await assert_schema_versions(registry_async_client, schema_id_1, schema_1_versions) - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 schema_id_2, version_2 = await register_schema(registry_async_client, subject, schema_str_2) @@ -1291,7 +1237,7 @@ async def test_schema_delete_latest_version(registry_async_client: Client) -> No await assert_schema_versions(registry_async_client, schema_id_2, schema_2_versions) # Deleting latest version, the other still found - res = await registry_async_client.delete(f"subjects/{subject}/versions/latest") + res = await registry_async_client.delete_subjects_version(subject=subject, version="latest") assert res.status_code == 200 assert res.json() == version_2 @@ -1299,7 +1245,7 @@ async def test_schema_delete_latest_version(registry_async_client: Client) -> No await assert_schema_versions(registry_async_client, schema_id_2, []) # Deleting the latest version, no schemas left - res = await registry_async_client.delete(f"subjects/{subject}/versions/latest") + res = await registry_async_client.delete_subjects_version(subject=subject, version="latest") assert res.status_code == 200 assert res.json() == version_1 @@ -1311,7 +1257,7 @@ async def test_schema_types(registry_async_client: Client) -> None: """ Tests for /schemas/types endpoint. """ - res = await registry_async_client.get("/schemas/types") + res = await registry_async_client.get_types() assert res.status_code == 200 json_res = res.json() assert len(json_res) == 3 @@ -1327,15 +1273,12 @@ async def test_schema_list_endpoint(registry_async_client: Client) -> None: unique = unique_field_factory() schema_str = json.dumps({"type": "string", "unique": unique}) - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": schema_str}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] - res = await registry_async_client.get("schemas") + res = await registry_async_client.get_schemas() assert res.status_code == 200 result_json = res.json() assert len(result_json) == 1 @@ -1356,22 +1299,16 @@ async def test_schema_repost(registry_async_client: Client) -> None: unique = unique_field_factory() schema_str = json.dumps({"type": "string", "unique": unique}) - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": schema_str}) assert res.status_code == 200 assert "id" in res.json() - schema_id = res.json()["id"] + schema_id = int(res.json()["id"]) - res = await registry_async_client.get(f"schemas/ids/{schema_id}") + res = await registry_async_client.get_schema_by_id(schema_id=schema_id) assert res.status_code == 200 assert json.loads(res.json()["schema"]) == json.loads(schema_str) - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": schema_str}) assert res.status_code == 200 assert "id" in res.json() assert schema_id == res.json()["id"] @@ -1383,15 +1320,12 @@ async def test_get_schema_with_subjects(registry_async_client: Client) -> None: field_name = create_field_name_factory("field")() schema_str = json.dumps({"type": "string", "unique": field_name}) - res = await registry_async_client.post( - f"subjects/{subject1}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject1, json={"schema": schema_str}) assert res.status_code == 200 assert "id" in res.json() - schema_id = res.json()["id"] + schema_id = int(res.json()["id"]) - res = await registry_async_client.get(f"schemas/ids/{schema_id}") + res = await registry_async_client.get_schema_by_id(schema_id=schema_id) assert res.ok expected_schema = json.loads(schema_str) @@ -1399,20 +1333,17 @@ async def test_get_schema_with_subjects(registry_async_client: Client) -> None: assert "subjects" not in json_reply, "the default reply shouldn't include the subjects field" assert json.loads(json_reply["schema"]) == expected_schema - res = await registry_async_client.get(f"schemas/ids/{schema_id}", params={"includeSubjects": "True"}) + res = await registry_async_client.get_schema_by_id(schema_id=schema_id, params={"includeSubjects": "True"}) assert res.ok json_reply = res.json() assert json.loads(json_reply["schema"]) == expected_schema, "schema should always stays the same" assert json_reply["subjects"] == [subject1], "subjects should be present if specified" - res = await registry_async_client.post( - f"subjects/{subject2}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject2, json={"schema": schema_str}) assert res.status_code == 200 - res = await registry_async_client.get(f"schemas/ids/{schema_id}", params={"includeSubjects": "True"}) + res = await registry_async_client.get_schema_by_id(schema_id=schema_id, params={"includeSubjects": "True"}) assert res.ok json_reply = res.json() @@ -1423,10 +1354,7 @@ async def test_get_schema_with_subjects(registry_async_client: Client) -> None: async def test_schema_missing_body(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_schema_missing_body")() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={}) assert res.status_code == 422 assert res.json()["error_code"] == 422 assert res.json()["message"] == [{"type": "missing", "loc": ["body", "schema"], "msg": "Field required", "input": {}}] @@ -1435,8 +1363,8 @@ async def test_schema_missing_body(registry_async_client: Client) -> None: async def test_schema_missing_schema_body_ok(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_schema_missing_schema_body_ok")() - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={ "schema": "", }, @@ -1450,7 +1378,7 @@ async def test_schema_non_existing_id(registry_async_client: Client) -> None: """ Tests getting a non-existing schema id """ - result = await registry_async_client.get(os.path.join("schemas/ids/123456789")) + result = await registry_async_client.get_schema_by_id(schema_id=123456789) assert result.json()["error_code"] == 40403 @@ -1471,14 +1399,14 @@ async def test_schema_subject_invalid_id(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_schema_subject_invalid_id")() unique_field_factory = create_field_name_factory("unique_") - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": '{"type": "string", "foo": "string", "%s": "string"}' % unique_field_factory()}, ) assert res.status_code == 200 # Find an invalid version 0 - res = await registry_async_client.get(f"subjects/{subject}/versions/0") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=0) assert res.status_code == 422 assert res.json()["error_code"] == 42202 assert ( @@ -1488,7 +1416,7 @@ async def test_schema_subject_invalid_id(registry_async_client: Client) -> None: ) # Find an invalid version (too large) - res = await registry_async_client.get(f"subjects/{subject}/versions/15") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=15) assert res.status_code == 404 assert res.json()["error_code"] == 40402 assert res.json()["message"] == "Version 15 not found." @@ -1504,50 +1432,35 @@ async def test_schema_subject_post_invalid(registry_async_client: Client) -> Non # Create the subject subject_1 = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": schema_str}) assert res.status_code == 200 - res = await registry_async_client.post( - f"subjects/{subject_1}", - json={"schema": json.dumps({"type": "invalid_type"})}, - ) + res = await registry_async_client.post_subjects(subject=subject_1, json={"schema": json.dumps({"type": "invalid_type"})}) assert res.status_code == 422, "Invalid schema for existing subject should return 422" assert res.json()["message"] == f"Error while looking up schema under subject {subject_1}" # Subject is not found subject_2 = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject_2}", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects(subject=subject_2, json={"schema": schema_str}) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject_2}' not found." # Schema not found for subject - res = await registry_async_client.post( - f"subjects/{subject_1}", - json={"schema": '{"type": "int"}'}, - ) + res = await registry_async_client.post_subjects(subject=subject_1, json={"schema": '{"type": "int"}'}) assert res.status_code == 404 assert res.json()["error_code"] == 40403 assert res.json()["message"] == "Schema not found" # Schema not included in the request body - res = await registry_async_client.post(f"subjects/{subject_1}", json={}) + res = await registry_async_client.post_subjects(subject=subject_1, json={}) assert res.status_code == 422 assert res.json()["error_code"] == 422 assert res.json()["message"] == [{"type": "missing", "loc": ["body", "schema"], "msg": "Field required", "input": {}}] # Schema not included in the request body for subject that does not exist subject_3 = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject_3}", - json={}, - ) + res = await registry_async_client.post_subjects(subject=subject_3, json={}) assert res.status_code == 422 assert res.json()["error_code"] == 422 assert res.json()["message"] == [{"type": "missing", "loc": ["body", "schema"], "msg": "Field required", "input": {}}] @@ -1555,20 +1468,19 @@ async def test_schema_subject_post_invalid(registry_async_client: Client) -> Non @pytest.mark.parametrize("subject", ["test_schema_lifecycle", "test_sche/ma_lifecycle"]) async def test_schema_lifecycle(registry_async_client: Client, subject: str) -> None: - subject = create_subject_name_factory(subject)() # subject creation urlencodes unique_field_factory = create_field_name_factory("unique_") unique_1 = unique_field_factory() - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": json.dumps({"type": "string", "foo": "string", unique_1: "string"})}, ) assert res.status_code == 200 schema_id_1 = res.json()["id"] unique_2 = unique_field_factory() - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": json.dumps({"type": "string", "foo": "string", unique_2: "string"})}, ) schema_id_2 = res.json()["id"] @@ -1578,43 +1490,43 @@ async def test_schema_lifecycle(registry_async_client: Client, subject: str) -> await assert_schema_versions(registry_async_client, schema_id_1, [(subject, 1)]) await assert_schema_versions(registry_async_client, schema_id_2, [(subject, 2)]) - result = await registry_async_client.get(os.path.join(f"schemas/ids/{schema_id_1}")) + result = await registry_async_client.get_schema_by_id(schema_id=schema_id_1) schema_json_1 = json.loads(result.json()["schema"]) assert schema_json_1["type"] == "string" assert schema_json_1["foo"] == "string" assert schema_json_1[unique_1] == "string" - result = await registry_async_client.get(os.path.join(f"schemas/ids/{schema_id_2}")) + result = await registry_async_client.get_schema_by_id(schema_id=schema_id_2) schema_json_2 = json.loads(result.json()["schema"]) assert schema_json_2["type"] == "string" assert schema_json_2["foo"] == "string" assert schema_json_2[unique_2] == "string" - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert res.status_code == 200 assert subject in res.json() - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 assert res.json() == [1, 2] - res = await registry_async_client.get(f"subjects/{subject}/versions/1") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=1) assert res.status_code == 200 assert res.json()["subject"] == subject assert json.loads(res.json()["schema"]) == schema_json_1 # Delete an actual version - res = await registry_async_client.delete(f"subjects/{subject}/versions/1") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1) assert res.status_code == 200 assert res.json() == 1 # Get the schema by id, still there, wasn't hard-deleted - res = await registry_async_client.get(f"schemas/ids/{schema_id_1}") + res = await registry_async_client.get_schema_by_id(schema_id=schema_id_1) assert res.status_code == 200 assert json.loads(res.json()["schema"]) == schema_json_1 # Get the schema by id - res = await registry_async_client.get(f"schemas/ids/{schema_id_2}") + res = await registry_async_client.get_schema_by_id(schema_id=schema_id_2) assert res.status_code == 200 # Get the versions, old version not found anymore (even if schema itself is) @@ -1622,48 +1534,48 @@ async def test_schema_lifecycle(registry_async_client: Client, subject: str) -> await assert_schema_versions(registry_async_client, schema_id_2, [(subject, 2)]) # Delete a whole subject - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 assert res.json() == [2] # List all subjects, our subject shouldn't be in the list - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert res.status_code == 200 assert subject not in res.json() # After deleting the last version of a subject, it shouldn't be in the list - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": '{"type": "string", "unique": "%s"}' % unique_field_factory()}, ) assert res.status_code == 200 - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert subject in res.json() - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.json() == [3] - res = await registry_async_client.delete(f"subjects/{subject}/versions/3") + res = await registry_async_client.delete_subjects_version(subject=subject, version=3) assert res.status_code == 200 - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert subject not in res.json() - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 404 print(res.json()) assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." - res = await registry_async_client.get(f"subjects/{subject}/versions/latest") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version="latest") assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." # Creating a new schema works after deleting the only available version unique_3 = unique_field_factory() - res = await registry_async_client.post( - f"subjects/{subject}/versions", + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schema": json.dumps({"type": "string", "foo": "string", unique_3: "string"})}, ) assert res.status_code == 200 - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.json() == [4] @@ -1686,11 +1598,11 @@ async def test_schema_version_numbering(registry_async_client: Client) -> None: } ], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "FORWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "FORWARD"}) assert res.status_code == 200 schema2 = { @@ -1707,19 +1619,19 @@ async def test_schema_version_numbering(registry_async_client: Client) -> None: }, ], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema2)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema2)}) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 assert res.json() == [1, 2] # Recreate subject - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 assert res.json() == [3] # Version number generation should now begin at 3 @@ -1742,13 +1654,10 @@ async def test_schema_version_numbering_complex(registry_async_client: Client) - ], "unique": unique_field_factory(), } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) schema_id = res.json()["id"] - res = await registry_async_client.get(f"subjects/{subject}/versions/1") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=1) assert res.status_code == 200 assert res.json()["subject"] == subject assert sorted(json.loads(res.json()["schema"])) == sorted(schema) @@ -1781,14 +1690,14 @@ async def test_schema_three_subjects_sharing_schema(registry_async_client: Clien }, ], } - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id_1 = res.json()["id"] # New subject with the same schema subject_2 = subject_name_factory() - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id_2 = res.json()["id"] @@ -1796,18 +1705,11 @@ async def test_schema_three_subjects_sharing_schema(registry_async_client: Clien # It also works for multiple versions in a single subject subject_3 = subject_name_factory() - res = await registry_async_client.put( - f"config/{subject_3}", json={"compatibility": "NONE"} - ) # We don't care about the compatibility in this test - res = await registry_async_client.post( - f"subjects/{subject_3}/versions", - json={"schema": '{"type": "string"}'}, - ) + # We don't care about the compatibility in this test + res = await registry_async_client.put_config_subject(subject=subject_3, json={"compatibility": "NONE"}) + res = await registry_async_client.post_subjects_versions(subject=subject_3, json={"schema": '{"type": "string"}'}) assert res.status_code == 200 - res = await registry_async_client.post( - f"subjects/{subject_3}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_3, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert res.json()["id"] == schema_id_1 # Same ID as in the previous test step @@ -1834,27 +1736,24 @@ async def test_schema_subject_version_schema(registry_async_client: Client) -> N } schema_str = json.dumps(schema) - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": schema_str}) assert res.status_code == 200 - res = await registry_async_client.get(f"subjects/{subject_1}/versions/1/schema") + res = await registry_async_client.get_subjects_subject_version_schema(subject=subject_1, version=1) assert res.status_code == 200 assert res.json() == json.loads(schema_str) subject_2 = subject_name_factory() - res = await registry_async_client.get(f"subjects/{subject_2}/versions/1/schema") # Invalid subject + res = await registry_async_client.get_subjects_subject_version_schema(subject=subject_2, version=1) # Invalid subject assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject_2}' not found." - res = await registry_async_client.get(f"subjects/{subject_1}/versions/2/schema") + res = await registry_async_client.get_subjects_subject_version_schema(subject=subject_1, version=2) assert res.status_code == 404 assert res.json()["error_code"] == 40402 assert res.json()["message"] == "Version 2 not found." - res = await registry_async_client.get(f"subjects/{subject_1}/versions/latest/schema") + res = await registry_async_client.get_subjects_subject_version_schema(subject=subject_1, version="latest") assert res.status_code == 200 assert res.json() == json.loads(schema_str) @@ -1879,16 +1778,10 @@ async def test_schema_same_subject(registry_async_client: Client) -> None: } ) subject = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": schema_str}) assert res.status_code == 200 schema_id = res.json()["id"] - res = await registry_async_client.post( - f"subjects/{subject}", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects(subject=subject, json={"schema": schema_str}) assert res.status_code == 200 # Switch the str schema to a dict for comparison @@ -1911,19 +1804,13 @@ async def test_schema_same_subject_unnamed(registry_async_client: Client) -> Non } ) subject = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": schema_str}) assert res.status_code == 200 schema_id = res.json()["id"] unnamed_schema_str = json.dumps({"type": "int"}) - res = await registry_async_client.post( - f"subjects/{subject}", - json={"schema": unnamed_schema_str}, - ) + res = await registry_async_client.post_subjects(subject=subject, json={"schema": unnamed_schema_str}) assert res.status_code == 200 # Switch the str schema to a dict for comparison @@ -1940,26 +1827,17 @@ async def test_schema_json_subject_comparison(registry_async_client: Client) -> schema_1 = {"schemaType": "JSON", "schema": '{"type": "string", "value": "int"}'} subject = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json=schema_1, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json=schema_1) assert res.status_code == 200 schema_id = res.json()["id"] schema_2 = {"schemaType": "JSON", "schema": '{"type": "string", "value": "int"}'} - res = await registry_async_client.post( - f"subjects/{subject}", - json=schema_2, - ) + res = await registry_async_client.post_subjects(subject=subject, json=schema_2) assert res.status_code == 200 schema_3 = {"schemaType": "JSON", "schema": '{"value": "int", "type": "string"}'} - res = await registry_async_client.post( - f"subjects/{subject}", - json=schema_3, - ) + res = await registry_async_client.post_subjects(subject=subject, json=schema_3) assert res.status_code == 200 json_res = res.json() @@ -1990,30 +1868,24 @@ async def test_schema_listing(registry_async_client: Client) -> None: } ) subject_1 = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": schema_str}) assert res.status_code == 200 subject_2 = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject_2}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": schema_str}) assert res.status_code == 200 schema_id_2 = res.json()["id"] # Soft delete schema 2 - res = await registry_async_client.delete(f"subjects/{subject_2}/versions/{schema_id_2}") + res = await registry_async_client.delete_subjects_version(subject=subject_2, version=schema_id_2) assert res.status_code == 200 assert res.json() == 1 - res = await registry_async_client.get("subjects/") + res = await registry_async_client.get_subjects() assert len(res.json()) == 1 assert res.json()[0] == subject_1 - res = await registry_async_client.get("subjects/?deleted=true") + res = await registry_async_client.get_subjects(params={"deleted": "true"}) result = res.json() assert len(result) == 2 assert subject_1 in result @@ -2028,9 +1900,8 @@ async def test_schema_version_number_existing_schema(registry_async_client: Clie unique_field_factory = create_field_name_factory("unique_") subject_1 = subject_name_factory() - res = await registry_async_client.put( - f"config/{subject_1}", json={"compatibility": "NONE"} - ) # We don't care about compatibility + # We don't care about compatibility + res = await registry_async_client.put_config_subject(subject=subject_1, json={"compatibility": "NONE"}) unique = unique_field_factory() schema_1 = { "type": "record", @@ -2074,26 +1945,25 @@ async def test_schema_version_number_existing_schema(registry_async_client: Clie }, ], } - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(schema_1)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema_1)}) assert res.status_code == 200 schema_id_1 = res.json()["id"] - res = await registry_async_client.post(f"subjects/{subject_1}/versions", json={"schema": json.dumps(schema_2)}) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": json.dumps(schema_2)}) assert res.status_code == 200 schema_id_2 = res.json()["id"] assert schema_id_2 > schema_id_1 # Reuse the first schema in another subject subject_2 = subject_name_factory() - res = await registry_async_client.put( - f"config/{subject_2}", json={"compatibility": "NONE"} - ) # We don't care about compatibility - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema_1)}) + # We don't care about compatibility + res = await registry_async_client.put_config_subject(subject=subject_2, json={"compatibility": "NONE"}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema_1)}) assert res.status_code == 200 assert res.json()["id"] == schema_id_1 # Create a new schema - res = await registry_async_client.post(f"subjects/{subject_2}/versions", json={"schema": json.dumps(schema_3)}) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": json.dumps(schema_3)}) assert res.status_code == 200 schema_id_3 = res.json()["id"] assert res.json()["id"] == schema_id_3 @@ -2105,7 +1975,7 @@ async def test_get_config_unknown_subject(registry_async_client: Client) -> None assert res.status_code == 404, f"{res} - Should return 404 for unknown subject" # Set global config, see that unknown subject is still returns correct 404 and does not fallback to global config - res = await registry_async_client.put("config", json={"compatibility": "FULL"}) + res = await registry_async_client.put_config(json={"compatibility": "FULL"}) assert res.status_code == 200 res = await registry_async_client.get("config/unknown-subject") @@ -2116,22 +1986,22 @@ async def test_config(registry_async_client: Client) -> None: subject_name_factory = create_subject_name_factory("test_config") # Tests /config endpoint - res = await registry_async_client.put("config", json={"compatibility": "FULL"}) + res = await registry_async_client.put_config(json={"compatibility": "FULL"}) assert res.status_code == 200 assert res.json()["compatibility"] == "FULL" assert res.headers["Content-Type"] == "application/vnd.schemaregistry.v1+json" - res = await registry_async_client.get("config") + res = await registry_async_client.get_config() assert res.status_code == 200 assert res.json()["compatibilityLevel"] == "FULL" assert res.headers["Content-Type"] == "application/vnd.schemaregistry.v1+json" - res = await registry_async_client.put("config", json={"compatibility": "NONE"}) + res = await registry_async_client.put_config(json={"compatibility": "NONE"}) assert res.status_code == 200 assert res.json()["compatibility"] == "NONE" assert res.headers["Content-Type"] == "application/vnd.schemaregistry.v1+json" - res = await registry_async_client.put("config", json={"compatibility": "nonexistentmode"}) + res = await registry_async_client.put_config(json={"compatibility": "nonexistentmode"}) assert res.status_code == 422 assert res.json()["error_code"] == 42203 assert res.json()["message"] == SchemaErrorMessages.INVALID_COMPATIBILITY_LEVEL.value @@ -2139,66 +2009,60 @@ async def test_config(registry_async_client: Client) -> None: # Create a new subject so we can try setting its config subject_1 = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject_1}/versions", - json={"schema": '{"type": "string"}'}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_1, json={"schema": '{"type": "string"}'}) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.get(f"config/{subject_1}") + res = await registry_async_client.get_config_subject(subject=subject_1) assert res.status_code == 404 assert res.json()["error_code"] == 40408 assert res.json()["message"] == f"Subject '{subject_1}' does not have subject-level compatibility configured" - res = await registry_async_client.put(f"config/{subject_1}", json={"compatibility": "FULL"}) + res = await registry_async_client.put_config_subject(subject=subject_1, json={"compatibility": "FULL"}) assert res.status_code == 200 assert res.json()["compatibility"] == "FULL" assert res.headers["Content-Type"] == "application/vnd.schemaregistry.v1+json" - res = await registry_async_client.get(f"config/{subject_1}") + res = await registry_async_client.get_config_subject(subject=subject_1) assert res.status_code == 200 assert res.json()["compatibilityLevel"] == "FULL" # Delete set compatibility on subject 1 - res = await registry_async_client.delete(f"config/{subject_1}") + res = await registry_async_client.delete_config_subject(subject=subject_1) assert res.status_code == 200 assert res.json()["compatibility"] == "NONE" # Verify compatibility not set on subject after delete - res = await registry_async_client.get(f"config/{subject_1}") + res = await registry_async_client.get_config_subject(subject=subject_1) assert res.status_code == 404 assert res.json()["error_code"] == 40408 assert res.json()["message"] == f"Subject '{subject_1}' does not have subject-level compatibility configured" # It's possible to add a config to a subject that doesn't exist yet subject_2 = subject_name_factory() - res = await registry_async_client.put(f"config/{subject_2}", json={"compatibility": "FULL"}) + res = await registry_async_client.put_config_subject(subject=subject_2, json={"compatibility": "FULL"}) assert res.status_code == 200 assert res.json()["compatibility"] == "FULL" assert res.headers["Content-Type"] == "application/vnd.schemaregistry.v1+json" # The subject doesn't exist from the schema point of view - res = await registry_async_client.get(f"subjects/{subject_2}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject_2) assert res.status_code == 404 - res = await registry_async_client.post( - f"subjects/{subject_2}/versions", - json={"schema": '{"type": "string"}'}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject_2, json={"schema": '{"type": "string"}'}) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.get(f"config/{subject_2}") + res = await registry_async_client.get_config_subject(subject=subject_2) assert res.status_code == 200 assert res.json()["compatibilityLevel"] == "FULL" # Test that config is returned for a subject that does not have an existing schema subject_3 = subject_name_factory() - res = await registry_async_client.put(f"config/{subject_3}", json={"compatibility": "NONE"}) + res = await registry_async_client.put_config_subject(subject=subject_3, json={"compatibility": "NONE"}) assert res.status_code == 200 assert res.json()["compatibility"] == "NONE" - res = await registry_async_client.get(f"config/{subject_3}") + res = await registry_async_client.get_config_subject(subject=subject_3) assert res.status_code == 200 assert res.json()["compatibilityLevel"] == "NONE" @@ -2301,10 +2165,10 @@ async def test_http_headers(registry_async_client: Client) -> None: async def test_schema_body_validation(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_schema_body_validation")() - post_endpoints = {f"subjects/{subject}", f"subjects/{subject}/versions"} - for endpoint in post_endpoints: + post_functions = {registry_async_client.post_subjects, registry_async_client.post_subjects_versions} + for function in post_functions: # Wrong field name - res = await registry_async_client.post(endpoint, json={"invalid_field": "invalid_value"}) + res = await function(subject=subject, json={"invalid_field": "invalid_value"}) assert res.status_code == 422 assert res.json()["error_code"] == 422 assert res.json()["message"] == [ @@ -2322,9 +2186,7 @@ async def test_schema_body_validation(registry_async_client: Client) -> None: }, ] # Additional field - res = await registry_async_client.post( - endpoint, json={"schema": '{"type": "string"}', "invalid_field": "invalid_value"} - ) + res = await function(subject=subject, json={"schema": '{"type": "string"}', "invalid_field": "invalid_value"}) assert res.status_code == 422 assert res.json()["error_code"] == 422 assert res.json()["message"] == [ @@ -2336,7 +2198,7 @@ async def test_schema_body_validation(registry_async_client: Client) -> None: }, ] # Invalid body type - res = await registry_async_client.post(endpoint, json="invalid") + res = await function(subject=subject, json="invalid") assert res.status_code == 422 assert res.json()["error_code"] == 422 assert res.json()["message"] == [ @@ -2357,26 +2219,26 @@ async def test_version_number_validation(registry_async_client: Client) -> None: return correct values both with valid and invalid parameters. """ subject = create_subject_name_factory("test_version_number_validation")() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": '{"type": "string"}'}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": '{"type": "string"}'}) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 schema_version = res.json()[0] invalid_schema_version = schema_version - 1 - version_endpoints = {f"subjects/{subject}/versions/$VERSION", f"subjects/{subject}/versions/$VERSION/schema"} + version_endpoints = { + registry_async_client.get_subjects_subject_version, + registry_async_client.get_subjects_subject_version_schema, + } for endpoint in version_endpoints: # Valid schema id - res = await registry_async_client.get(endpoint.replace("$VERSION", str(schema_version))) + res = await endpoint(subject=subject, version=schema_version) assert res.status_code == 200 # Invalid number - res = await registry_async_client.get(endpoint.replace("$VERSION", str(invalid_schema_version))) + res = await endpoint(subject=subject, version=invalid_schema_version) assert res.status_code == 422 assert res.json()["error_code"] == 42202 assert ( @@ -2384,10 +2246,10 @@ async def test_version_number_validation(registry_async_client: Client) -> None: 'Allowed values are between [1, 2^31-1] and the string "latest"' ) # Valid latest string - res = await registry_async_client.get(endpoint.replace("$VERSION", "latest")) + res = await endpoint(subject=subject, version="latest") assert res.status_code == 200 # Invalid string - res = await registry_async_client.get(endpoint.replace("$VERSION", "invalid")) + res = await endpoint(subject=subject, version="invalid") assert res.status_code == 422 assert res.json()["error_code"] == 42202 assert ( @@ -2402,17 +2264,16 @@ async def test_get_schema_version_by_latest_tags(registry_async_client: Client) `subjects/{subject}/versions/latest` and `subjects/{subject}/versions/-1` return the latest schema. """ subject = create_subject_name_factory("test_subject")() - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": '{"type": "string"}'}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": '{"type": "string"}'}) assert res.status_code == 200 schema_id = res.json()["id"] - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 schema_version = res.json()[0] - version_endpoints = {f"subjects/{subject}/versions/latest", f"subjects/{subject}/versions/-1"} - for endpoint in version_endpoints: - res = await registry_async_client.get(endpoint) + for version in ["latest", -1]: + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=version) res_data = res.json() assert res.status_code == 200 assert res_data["id"] == schema_id @@ -2428,7 +2289,7 @@ async def test_common_endpoints(registry_async_client: Client) -> None: async def test_invalid_namespace(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_invalid_namespace")() schema = {"type": "record", "name": "foo", "namespace": "foo-bar-baz", "fields": []} - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 422, res.json() json_res = res.json() assert json_res["error_code"] == 42201, json_res @@ -2452,7 +2313,7 @@ async def test_schema_remains_constant(registry_async_client: Client) -> None: "fields": [{"type": "string", "name": "bla"}], } schema_str = json.dumps(schema) - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": schema_str}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": schema_str}) assert res.ok, res.json() schema_id = res.json()["id"] res = await registry_async_client.get(f"schemas/ids/{schema_id}") @@ -2521,10 +2382,10 @@ async def test_inner_type_compat_failure(registry_async_client: Client) -> None: } ], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(sc)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(sc)}) assert res.ok sc_id = res.json()["id"] - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(ev)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(ev)}) assert res.ok assert sc_id != res.json()["id"] @@ -2578,10 +2439,10 @@ async def test_anon_type_union_failure(registry_async_client: Client) -> None: ], } - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(schema)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.ok sc_id = res.json()["id"] - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(evolved)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(evolved)}) assert res.ok assert sc_id != res.json()["id"] @@ -2630,10 +2491,10 @@ async def test_full_transitive_failure(registry_async_client: Client, compatibil } ], } - await registry_async_client.put(f"config/{subject}", json={"compatibility": compatibility}) - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(init)}) + await registry_async_client.put_config_subject(subject=subject, json={"compatibility": compatibility}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(init)}) assert res.ok - res = await registry_async_client.post(f"subjects/{subject}/versions", json={"schema": json.dumps(evolved)}) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(evolved)}) assert not res.ok assert res.status_code == 409 @@ -2647,17 +2508,14 @@ async def test_invalid_schemas(registry_async_client: Client) -> None: "fields": [{"type": "string", "name": "name"}, {"type": "string", "name": "name", "default": "test"}], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(repated_field)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(repated_field)}) assert res.status_code != 500, "an invalid schema should not cause a server crash" assert not is_success(HTTPStatus(res.status_code)), "an invalid schema must not be a success" async def test_schema_hard_delete_version(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_schema_hard_delete_version")() - res = await registry_async_client.put("config", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config(json={"compatibility": "BACKWARD"}) assert res.status_code == 200 schemav1 = { "type": "record", @@ -2673,10 +2531,7 @@ async def test_schema_hard_delete_version(registry_async_client: Client) -> None } ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schemav1)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schemav1)}) assert res.status_code == 200 assert "id" in res.json() schemav1_id = res.json()["id"] @@ -2695,57 +2550,54 @@ async def test_schema_hard_delete_version(registry_async_client: Client) -> None } ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schemav2)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schemav2)}) assert res.status_code == 200 assert "id" in res.json() schemav2_id = res.json()["id"] assert schemav1_id != schemav2_id # Cannot directly hard delete schema v1 - res = await registry_async_client.delete(f"subjects/{subject}/versions/1?permanent=true") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1, permanent=True) assert res.status_code == 404 assert res.json()["error_code"] == 40407 assert res.json()["message"] == f"Subject '{subject}' Version 1 was not deleted first before being permanently deleted" # Soft delete schema v1 - res = await registry_async_client.delete(f"subjects/{subject}/versions/1") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1) assert res.status_code == 200 assert res.json() == 1 # Cannot soft delete twice - res = await registry_async_client.delete(f"subjects/{subject}/versions/1") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1) assert res.status_code == 404 assert res.json()["error_code"] == 40406 assert ( res.json()["message"] == f"Subject '{subject}' Version 1 was soft deleted. Set permanent=true to delete permanently" ) - res = await registry_async_client.get(f"subjects/{subject}/versions/1") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=1) assert res.status_code == 404 assert res.json()["error_code"] == 40402 assert res.json()["message"] == "Version 1 not found." # Check that soft deleted is found when asking also for deleted schemas - res = await registry_async_client.get(f"subjects/{subject}/versions/1?deleted=true") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=1, params={"deleted": "true"}) assert res.status_code == 200 assert res.json()["version"] == 1 assert res.json()["subject"] == subject # Hard delete schema v1 - res = await registry_async_client.delete(f"subjects/{subject}/versions/1?permanent=true") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1, permanent=True) assert res.status_code == 200 # Cannot hard delete twice - res = await registry_async_client.delete(f"subjects/{subject}/versions/1?permanent=true") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1, permanent=True) assert res.status_code == 404 assert res.json()["error_code"] == 40402 assert res.json()["message"] == "Version 1 not found." # Check hard deleted is not found at all - res = await registry_async_client.get(f"subjects/{subject}/versions/1?deleted=true") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version=1, params={"deleted": "true"}) assert res.status_code == 404 assert res.json()["error_code"] == 40402 assert res.json()["message"] == "Version 1 not found." @@ -2753,7 +2605,7 @@ async def test_schema_hard_delete_version(registry_async_client: Client) -> None async def test_schema_hard_delete_whole_schema(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_schema_hard_delete_whole_schema")() - res = await registry_async_client.put("config", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config(json={"compatibility": "BACKWARD"}) assert res.status_code == 200 schemav1 = { "type": "record", @@ -2769,10 +2621,7 @@ async def test_schema_hard_delete_whole_schema(registry_async_client: Client) -> } ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schemav1)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schemav1)}) assert res.status_code == 200 assert "id" in res.json() schemav1_id = res.json()["id"] @@ -2791,49 +2640,46 @@ async def test_schema_hard_delete_whole_schema(registry_async_client: Client) -> } ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schemav2)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schemav2)}) assert res.status_code == 200 assert "id" in res.json() schemav2_id = res.json()["id"] assert schemav1_id != schemav2_id # Hard delete whole schema cannot be done before soft delete - res = await registry_async_client.delete(f"subjects/{subject}?permanent=true") + res = await registry_async_client.delete_subjects(subject=subject, params={"permanent": "true"}) assert res.status_code == 404 assert res.json()["error_code"] == 40405 assert res.json()["message"] == f"Subject '{subject}' was not deleted first before being permanently deleted" # Soft delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 assert res.json() == [1, 2] - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." # Check that fetching unescaped schema gives valid error message - res = await registry_async_client.get(f"subjects/{subject}/versions/latest/schema") + res = await registry_async_client.get_subjects_subject_version_schema(subject=subject, version="latest") assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." # Soft delete cannot be done twice - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 404 assert res.json()["error_code"] == 40404 assert res.json()["message"] == f"Subject '{subject}' was soft deleted.Set permanent=true to delete permanently" # Hard delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}?permanent=true") + res = await registry_async_client.delete_subjects(subject=subject, params={"permanent": "true"}) assert res.status_code == 200 assert res.json() == [1, 2] - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." @@ -2844,17 +2690,17 @@ async def test_schema_hard_delete_and_recreate(registry_async_client: Client) -> schema_name = create_schema_name_factory("test_schema_hard_delete_and_recreate")() # Deleting non-existing gives valid error message - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." - res = await registry_async_client.delete(f"subjects/{subject}/versions/1") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." - res = await registry_async_client.put("config", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config(json={"compatibility": "BACKWARD"}) assert res.status_code == 200 schema = { "type": "record", @@ -2870,64 +2716,55 @@ async def test_schema_hard_delete_and_recreate(registry_async_client: Client) -> } ], } - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] # Soft delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 # Recreate with same subject after soft delete - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() assert schema_id == res.json()["id"], "after soft delete the same schema registered, the same identifier" # Soft delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 # Hard delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}?permanent=true") + res = await registry_async_client.delete_subjects(subject=subject, params={"permanent": "true"}) assert res.status_code == 200 # Deleting non-existing gives valid error message - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." - res = await registry_async_client.delete(f"subjects/{subject}/versions/1") + res = await registry_async_client.delete_subjects_version(subject=subject, version=1) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." # Recreate with same subject after hard delete - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() assert schema_id == res.json()["id"], "after permanent deleted the same schema registered, the same identifier" - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 # After recreated, subject again registered - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert res.status_code == 200 assert subject in res.json() @@ -2974,70 +2811,61 @@ async def test_schema_recreate_after_odd_hard_delete( producer.send(registry_cluster.schemas_topic, key=message_key, value=None) producer.flush() - res = await registry_async_client.put("config", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config(json={"compatibility": "BACKWARD"}) assert res.status_code == 200 # Initially no subject registered - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert res.status_code == 200 assert subject not in res.json() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] # Now subject is listed - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert res.status_code == 200 assert subject in res.json() # Also newly registed schema can be fetched - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 # Soft delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 # Recreate with same subject after soft delete - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() assert schema_id == res.json()["id"], "after soft delete the same schema registered, the same identifier" # Soft delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}") + res = await registry_async_client.delete_subjects(subject=subject) assert res.status_code == 200 # Hard delete whole schema - res = await registry_async_client.delete(f"subjects/{subject}?permanent=true") + res = await registry_async_client.delete_subjects(subject=subject, params={"permanent": "true"}) assert res.status_code == 200 - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 404 assert res.json()["error_code"] == 40401 assert res.json()["message"] == f"Subject '{subject}' not found." # Recreate with same subject after hard delete - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() assert schema_id == res.json()["id"], "after permanent deleted the same schema registered, the same identifier" - res = await registry_async_client.get(f"subjects/{subject}/versions") + res = await registry_async_client.get_subjects_versions(subject=subject) assert res.status_code == 200 # After recreated, subject again registered - res = await registry_async_client.get("subjects") + res = await registry_async_client.get_subjects() assert res.status_code == 200 assert subject in res.json() @@ -3048,18 +2876,12 @@ async def test_invalid_schema_should_provide_good_error_messages(registry_async_ test_subject = subject_name_factory() schema_str = json.dumps({"type": "string"}) - res = await registry_async_client.post( - f"subjects/{test_subject}/versions", - json={"schema": schema_str[:-1]}, - ) + res = await registry_async_client.post_subjects_versions(subject=test_subject, json={"schema": schema_str[:-1]}) assert res.json()["message"].startswith("Invalid AVRO schema. Error: ") # Unfortunately the AVRO library doesn't provide a good error message, it just raises an TypeError schema_str = json.dumps({"type": "enum", "name": "error"}) - res = await registry_async_client.post( - f"subjects/{test_subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=test_subject, json={"schema": schema_str}) assert ( res.json()["message"] == "Invalid AVRO schema. Error: Enum symbols must be a sequence of strings, but it is " @@ -3067,10 +2889,7 @@ async def test_invalid_schema_should_provide_good_error_messages(registry_async_ # This is an upstream bug in the python AVRO library, until the bug is fixed we should at least have a nice error message schema_str = json.dumps({"type": "enum", "name": "error", "symbols": {}}) - res = await registry_async_client.post( - f"subjects/{test_subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=test_subject, json={"schema": schema_str}) assert ( res.json()["message"] == "Invalid AVRO schema. Error: Enum symbols must be a sequence of strings, but it is " @@ -3131,43 +2950,33 @@ async def test_schema_non_compliant_namespace_in_existing( # Wait until the schema is available do_until_time = time.monotonic() + 5 while do_until_time > time.monotonic(): - res = await registry_async_client.get(f"subjects/{subject}/versions/latest") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version="latest") if res.status_code == 200: break await asyncio.sleep(0.5) # Compatibility check, is expected to be compatible, namespace is not important. - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", - json={"schema": json.dumps(evolved_schema)}, + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, version="latest", json={"schema": json.dumps(evolved_schema)} ) assert res.status_code == 200 # Post evolved new schema - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(evolved_schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(evolved_schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] assert schema_id == 2 # Check non-compliant schema is registered - res = await registry_async_client.post( - f"subjects/{subject}", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] assert schema_id == 1 # Check evolved schema is registered - res = await registry_async_client.post( - f"subjects/{subject}", - json={"schema": json.dumps(evolved_schema)}, - ) + res = await registry_async_client.post_subjects(subject=subject, json={"schema": json.dumps(evolved_schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] @@ -3228,64 +3037,52 @@ async def test_schema_non_compliant_name_in_existing( # Wait until the schema is available do_until_time = time.monotonic() + 5 while do_until_time > time.monotonic(): - res = await registry_async_client.get(f"subjects/{subject}/versions/latest") + res = await registry_async_client.get_subjects_subject_version(subject=subject, version="latest") if res.status_code == 200: break await asyncio.sleep(0.5) # Compatibility check, should not be compatible, name is important. # Test that no parsing error is given as name in the existing schema is non-compliant. - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schema": json.dumps(evolved_schema)}, ) assert res.status_code == 200 assert res.json().get("is_compatible") is False # Post evolved schema, should not be compatible and rejected. - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(evolved_schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(evolved_schema)}) assert res.status_code == 409 assert res.json() == { "error_code": 409, "message": ( - "Incompatible schema, compatibility_mode=BACKWARD. " - "Incompatibilities: expected: compliant_name_test.test-schema" + "Incompatible schema, compatibility_mode=BACKWARD. Incompatibilities: expected: compliant_name_test.test-schema" ), } # Send compatibility configuration for subject that disabled backwards compatibility. # The name cannot be changed if backward compatibility is required. - res = await registry_async_client.put(f"/config/{subject}", json={"compatibility": "NONE"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "NONE"}) assert res.status_code == 200 # Post evolved schema and expectation is gets registered as no compatiblity is enforced. - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": json.dumps(evolved_schema)}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": json.dumps(evolved_schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] assert schema_id == 2 # Check non-compliant schema is registered - res = await registry_async_client.post( - f"subjects/{subject}", - json={"schema": json.dumps(schema)}, - ) + res = await registry_async_client.post_subjects(subject=subject, json={"schema": json.dumps(schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] assert schema_id == 1 # Check evolved schema is registered - res = await registry_async_client.post( - f"subjects/{subject}", - json={"schema": json.dumps(evolved_schema)}, - ) + res = await registry_async_client.post_subjects(subject=subject, json={"schema": json.dumps(evolved_schema)}) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] diff --git a/tests/integration/test_schema_protobuf.py b/tests/integration/test_schema_protobuf.py index 2c2f9b17b..d8c14a7cb 100644 --- a/tests/integration/test_schema_protobuf.py +++ b/tests/integration/test_schema_protobuf.py @@ -53,7 +53,7 @@ def add_slashes(text: str) -> str: async def test_protobuf_schema_normalization(registry_async_client: Client) -> None: subject = create_subject_name_factory("test_protobuf_schema_compatibility")() - res = await registry_async_client.put(f"config/{subject}", json={"compatibility": "BACKWARD"}) + res = await registry_async_client.put_config_subject(subject=subject, json={"compatibility": "BACKWARD"}) assert res.status_code == 200 original_schema = """ @@ -90,35 +90,37 @@ async def test_protobuf_schema_normalization(registry_async_client: Client) -> N |""" ) - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": original_schema} + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema} ) assert res.status_code == 200 assert "id" in res.json() original_id = res.json()["id"] - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": original_schema} + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema} ) assert res.status_code == 200 assert "id" in res.json() assert original_id == res.json()["id"], "No duplication" - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": original_schema_with_whitespace} + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema_with_whitespace} ) assert res.status_code == 200 assert "id" in res.json() assert original_id == res.json()["id"], "No duplication with whitespace differences" - res = await registry_async_client.post(f"subjects/{subject}", json={"schemaType": "PROTOBUF", "schema": original_schema}) + res = await registry_async_client.post_subjects( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema} + ) assert res.status_code == 200 assert "id" in res.json() assert "schema" in res.json() assert original_id == res.json()["id"], "Check returns original id" - res = await registry_async_client.post( - f"subjects/{subject}", json={"schemaType": "PROTOBUF", "schema": original_schema_with_whitespace} + res = await registry_async_client.post_subjects( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema_with_whitespace} ) assert res.status_code == 200 assert "id" in res.json() @@ -143,35 +145,39 @@ async def test_protobuf_schema_normalization(registry_async_client: Client) -> N |""" evolved_schema = trim_margin(evolved_schema) - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": evolved_schema}, ) assert res.status_code == 200 assert res.json() == {"is_compatible": True} - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": evolved_schema} + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": evolved_schema} ) assert res.status_code == 200 assert "id" in res.json() assert original_id != res.json()["id"], "Evolved is not equal" evolved_id = res.json()["id"] - res = await registry_async_client.post( - f"compatibility/subjects/{subject}/versions/latest", + res = await registry_async_client.post_compatibility_subject_version( + subject=subject, + version="latest", json={"schemaType": "PROTOBUF", "schema": original_schema}, ) assert res.json() == {"is_compatible": True} assert res.status_code == 200 - res = await registry_async_client.post( - f"subjects/{subject}/versions", json={"schemaType": "PROTOBUF", "schema": original_schema} + res = await registry_async_client.post_subjects_versions( + subject=subject, json={"schemaType": "PROTOBUF", "schema": original_schema} ) assert res.status_code == 200 assert "id" in res.json() assert original_id == res.json()["id"], "Original id again" - res = await registry_async_client.post(f"subjects/{subject}", json={"schemaType": "PROTOBUF", "schema": evolved_schema}) + res = await registry_async_client.post_subjects( + subject=subject, json={"schemaType": "PROTOBUF", "schema": evolved_schema} + ) assert res.status_code == 200 assert "id" in res.json() assert "schema" in res.json() @@ -207,16 +213,16 @@ async def test_protobuf_schema_references(registry_async_client: Client) -> None |""" place_schema = trim_margin(place_schema) - res = await registry_async_client.post( - "subjects/place/versions", json={"schemaType": "PROTOBUF", "schema": place_schema} + res = await registry_async_client.post_subjects_versions( + subject="place", json={"schemaType": "PROTOBUF", "schema": place_schema} ) assert res.status_code == 200 assert "id" in res.json() customer_references = [{"name": "Place.proto", "subject": "place", "version": 1}] - res = await registry_async_client.post( - "subjects/customer/versions", + res = await registry_async_client.post_subjects_versions( + subject="customer", json={"schemaType": "PROTOBUF", "schema": customer_schema, "references": customer_references}, ) assert res.status_code == 200 @@ -225,8 +231,8 @@ async def test_protobuf_schema_references(registry_async_client: Client) -> None customer_id = res.json()["id"] # Check if the schema has now been registered under the subject - res = await registry_async_client.post( - "subjects/customer", + res = await registry_async_client.post_subjects( + subject="customer", json={"schemaType": "PROTOBUF", "schema": customer_schema, "references": customer_references}, ) assert res.status_code == 200 @@ -266,22 +272,22 @@ async def test_protobuf_schema_references(registry_async_client: Client) -> None original_schema = trim_margin(original_schema) references = [{"name": "Customer.proto", "subject": "customer", "version": 1}] - res = await registry_async_client.post( - "subjects/test_schema/versions", + res = await registry_async_client.post_subjects_versions( + subject="test_schema", json={"schemaType": "PROTOBUF", "schema": original_schema, "references": references}, ) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.get("subjects/customer/versions/latest/referencedby", json={}) + res = await registry_async_client.get_subjects_subject_version_referenced_by(subject="customer", version="latest") assert res.status_code == 200 myjson = res.json() referents = [3] assert not any(x != y for x, y in zip(myjson, referents)) - res = await registry_async_client.get("subjects/place/versions/latest/referencedby", json={}) + res = await registry_async_client.get_subjects_subject_version_referenced_by(subject="place", version="latest") assert res.status_code == 200 res = await registry_async_client.delete("subjects/customer/versions/1") @@ -291,26 +297,26 @@ async def test_protobuf_schema_references(registry_async_client: Client) -> None myjson = res.json() assert myjson["error_code"] == 42206 and myjson["message"] == match_msg - res = await registry_async_client.delete("subjects/test_schema/versions/1") + res = await registry_async_client.delete_subjects_version(subject="test_schema", version=1) assert res.status_code == 200 - res = await registry_async_client.delete("subjects/test_schema/versions/1") + res = await registry_async_client.delete_subjects_version(subject="test_schema", version=1) myjson = res.json() match_msg = "Subject 'test_schema' Version 1 was soft deleted. Set permanent=true to delete permanently" assert res.status_code == 404 assert myjson["error_code"] == 40406 and myjson["message"] == match_msg - res = await registry_async_client.delete("subjects/customer/versions/1") + res = await registry_async_client.delete_subjects_version(subject="customer", version=1) myjson = res.json() match_msg = "One or more references exist to the schema {magic=1,keytype=SCHEMA,subject=customer,version=1}." assert res.status_code == 422 assert myjson["error_code"] == 42206 and myjson["message"] == match_msg - res = await registry_async_client.delete("subjects/test_schema/versions/1?permanent=true") + res = await registry_async_client.delete_subjects_version(subject="test_schema", version=1, permanent=True) assert res.status_code == 200 - res = await registry_async_client.delete("subjects/customer/versions/1") + res = await registry_async_client.delete_subjects_version(subject="customer", version=1) assert res.status_code == 200 @@ -325,7 +331,9 @@ async def test_protobuf_schema_jjaakola_one(registry_async_client: Client) -> No |""" no_ref = trim_margin(no_ref) - res = await registry_async_client.post("subjects/sub1/versions", json={"schemaType": "PROTOBUF", "schema": no_ref}) + res = await registry_async_client.post_subjects_versions( + subject="sub1", json={"schemaType": "PROTOBUF", "schema": no_ref} + ) assert res.status_code == 200 assert "id" in res.json() @@ -341,8 +349,8 @@ async def test_protobuf_schema_jjaakola_one(registry_async_client: Client) -> No with_first_ref = trim_margin(with_first_ref) references = [{"name": "NoReference.proto", "subject": "sub1", "version": 1}] - res = await registry_async_client.post( - "subjects/sub2/versions", + res = await registry_async_client.post_subjects_versions( + subject="sub2", json={"schemaType": "PROTOBUF", "schema": with_first_ref, "references": references}, ) assert res.status_code == 200 @@ -357,8 +365,8 @@ async def test_protobuf_schema_jjaakola_one(registry_async_client: Client) -> No |""" no_ref_second = trim_margin(no_ref_second) - res = await registry_async_client.post( - "subjects/sub3/versions", json={"schemaType": "PROTOBUF", "schema": no_ref_second} + res = await registry_async_client.post_subjects_versions( + subject="sub3", json={"schemaType": "PROTOBUF", "schema": no_ref_second} ) assert res.status_code == 200 assert "id" in res.json() @@ -381,8 +389,8 @@ async def test_protobuf_schema_jjaakola_one(registry_async_client: Client) -> No {"name": "NoReferenceTwo.proto", "subject": "sub3", "version": 1}, ] - res = await registry_async_client.post( - "subjects/sub2/versions", + res = await registry_async_client.post_subjects_versions( + subject="sub2", json={"schemaType": "PROTOBUF", "schema": add_new_ref_in_sub2, "references": references}, ) assert res.status_code == 200 @@ -401,8 +409,9 @@ async def test_protobuf_schema_verifier(registry_async_client: Client) -> None: |""" customer_schema = trim_margin(customer_schema) - res = await registry_async_client.post( - "subjects/customer/versions", json={"schemaType": "PROTOBUF", "schema": customer_schema} + res = await registry_async_client.post_subjects_versions( + subject="customer", + json={"schemaType": "PROTOBUF", "schema": customer_schema}, ) assert res.status_code == 200 assert "id" in res.json() @@ -438,34 +447,34 @@ async def test_protobuf_schema_verifier(registry_async_client: Client) -> None: original_schema = trim_margin(original_schema) references = [{"name": "Customer.proto", "subject": "customer", "version": 1}] - res = await registry_async_client.post( - "subjects/test_schema/versions", + res = await registry_async_client.post_subjects_versions( + subject="test_schema", json={"schemaType": "PROTOBUF", "schema": original_schema, "references": references}, ) assert res.status_code == 200 assert "id" in res.json() - res = await registry_async_client.get("subjects/customer/versions/latest/referencedby", json={}) + res = await registry_async_client.get_subjects_subject_version_referenced_by(subject="customer", version="latest") assert res.status_code == 200 myjson = res.json() referents = [2] assert not any(x != y for x, y in zip(myjson, referents)) - res = await registry_async_client.delete("subjects/customer/versions/1") + res = await registry_async_client.delete_subjects_version(subject="customer", version=1) assert res.status_code == 422 match_msg = "One or more references exist to the schema {magic=1,keytype=SCHEMA,subject=customer,version=1}." myjson = res.json() assert myjson["error_code"] == 42206 and myjson["message"] == match_msg - res = await registry_async_client.delete("subjects/test_schema/versions/1") + res = await registry_async_client.delete_subjects_version(subject="test_schema", version=1) assert res.status_code == 200 - res = await registry_async_client.delete("subjects/customer/versions/1") + res = await registry_async_client.delete_subjects_version(subject="customer", version=1) assert res.status_code == 422 - res = await registry_async_client.delete("subjects/test_schema/versions/1?permanent=true") + res = await registry_async_client.delete_subjects_version(subject="test_schema", version=1, permanent=True) assert res.status_code == 200 - res = await registry_async_client.delete("subjects/customer/versions/1") + res = await registry_async_client.delete_subjects_version(subject="customer", version=1) assert res.status_code == 200 @@ -986,20 +995,25 @@ async def test_references( } if testdata.references: body["references"] = testdata.references - res = await registry_async_client.post(f"subjects/{testdata.subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=testdata.subject, json=body) elif isinstance(testdata, TestCaseHardDeleteSchema): print( f"Permanently deleting schema, subject: '{testdata.subject}, " f"schema: {testdata.schema_id}, version: {testdata.version}' " ) - res = await registry_async_client.delete( - f"subjects/{testdata.subject}/versions/{testdata.version}?permanent=true" + res = await registry_async_client.delete_subjects_version( + subject=testdata.subject, + version=testdata.version, + permanent=True, ) elif isinstance(testdata, TestCaseDeleteSchema): print( f"Deleting schema, subject: '{testdata.subject}, schema: {testdata.schema_id}, version: {testdata.version}' " ) - res = await registry_async_client.delete(f"subjects/{testdata.subject}/versions/{testdata.version}") + res = await registry_async_client.delete_subjects_version( + subject=testdata.subject, + version=testdata.version, + ) else: raise InvalidTest("Unknown test case.") @@ -1011,7 +1025,7 @@ async def test_references( if isinstance(testdata, TestCaseSchema): if testdata.expected == 200: schema_id = res.json().get("id") - fetch_schema_res = await registry_async_client.get(f"/schemas/ids/{schema_id}") + fetch_schema_res = await registry_async_client.get_schema_by_id(schema_id=schema_id) assert fetch_schema_res.status_code == 200 if testdata.references: assert "references" in fetch_schema_res.json() @@ -1019,10 +1033,13 @@ async def test_references( assert "references" not in fetch_schema_res.json() if isinstance(testdata, TestCaseDeleteSchema): if testdata.expected == 200: - fetch_res = await registry_async_client.get(f"/subjects/{testdata.subject}/versions/{testdata.version}") + fetch_res = await registry_async_client.get_subjects_subject_version( + subject=testdata.subject, + version=testdata.version, + ) assert fetch_res.status_code == 404 else: - fetch_schema_res = await registry_async_client.get(f"/schemas/ids/{testdata.schema_id}") + fetch_schema_res = await registry_async_client.get_schema_by_id(schema_id=testdata.schema_id) assert fetch_schema_res.status_code == 200 @@ -1063,12 +1080,12 @@ async def test_reference_update_creates_new_schema_version(registry_async_client body = {"schemaType": testdata.schema_type, "schema": testdata.schema_str} if testdata.references: body["references"] = testdata.references - res = await registry_async_client.post(f"subjects/{testdata.subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=testdata.subject, json=body) assert res.status_code == testdata.expected schema_ids.append(res.json_result.get("id")) - res = await registry_async_client.get("subjects/wr_s2/versions") + res = await registry_async_client.get_subjects_versions(subject="wr_s2") assert len(res.json_result) == 2, "Expected two versions of schemas as reference was updated." - res = await registry_async_client.get("subjects/wr_s2/versions/2") + res = await registry_async_client.get_subjects_subject_version(subject="wr_s2", version=2) references = res.json_result.get("references") assert len(references) == 1 assert references[0].get("name") == "NoReference.proto" @@ -1083,7 +1100,7 @@ async def test_reference_update_creates_new_schema_version(registry_async_client } if testdata.references: body["references"] = testdata.references - res = await registry_async_client.post(f"subjects/{testdata.subject}", json=body) + res = await registry_async_client.post_subjects(subject=testdata.subject, json=body) assert res.json_result.get("id") == expected_schema_id @@ -1100,7 +1117,7 @@ async def test_protobuf_error(registry_async_client: Client) -> None: body = {"schemaType": testdata.schema_type, "schema": testdata.schema_str} if testdata.references: body["references"] = testdata.references - res = await registry_async_client.post(f"subjects/{testdata.subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=testdata.subject, json=body) assert res.status_code == 200 @@ -1115,7 +1132,7 @@ async def test_protobuf_error(registry_async_client: Client) -> None: body = {"schemaType": testdata.schema_type, "schema": testdata.schema_str} if testdata.references: body["references"] = testdata.references - res = await registry_async_client.post(f"subjects/{testdata.subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=testdata.subject, json=body) assert res.status_code == 200 testdata = TestCaseSchema( schema_type=SchemaType.PROTOBUF, @@ -1133,7 +1150,7 @@ async def test_protobuf_error(registry_async_client: Client) -> None: body = {"schemaType": testdata.schema_type, "schema": testdata.schema_str} if testdata.references: body["references"] = testdata.references - res = await registry_async_client.post(f"subjects/{testdata.subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=testdata.subject, json=body) assert res.status_code == 200 @@ -1151,7 +1168,7 @@ async def test_protobuf_missing_google_import(registry_async_client: Client) -> } """ body = {"schemaType": "PROTOBUF", "schema": unknown_proto} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 422 @@ -1175,7 +1192,7 @@ async def test_protobuf_customer_update(registry_async_client: Client) -> None: """ body = {"schemaType": "PROTOBUF", "schema": customer_proto} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 @@ -1191,7 +1208,7 @@ async def test_protobuf_customer_update(registry_async_client: Client) -> None: """ body = {"schemaType": "PROTOBUF", "schema": customer_proto} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 @@ -1218,31 +1235,31 @@ async def test_protobuf_binary_serialized(registry_async_client: Client) -> None ) body = {"schemaType": "PROTOBUF", "schema": schema_serialized} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 assert "id" in res.json() schema_id = res.json()["id"] body = {"schemaType": "PROTOBUF", "schema": schema_plain} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 assert "id" in res.json() assert schema_id == res.json()["id"] - res = await registry_async_client.get(f"/schemas/ids/{schema_id}") + res = await registry_async_client.get_schema_by_id(schema_id=schema_id) assert res.status_code == 200 assert "schema" in res.json() assert res.json()["schema"] == schema_plain - res = await registry_async_client.get(f"/schemas/ids/{schema_id}?format=serialized") + res = await registry_async_client.get_schema_by_id(schema_id=schema_id, params={"format": "serialized"}) assert res.status_code == 200 assert "schema" in res.json() assert res.json()["schema"] body = {"schemaType": "PROTOBUF", "schema": res.json()["schema"]} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 assert "id" in res.json() assert schema_id == res.json()["id"] @@ -1266,7 +1283,7 @@ async def test_protobuf_update_ordering(registry_async_client: Client) -> None: """ body = {"schemaType": "PROTOBUF", "schema": schema_v1} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 assert "id" in res.json() @@ -1287,7 +1304,7 @@ async def test_protobuf_update_ordering(registry_async_client: Client) -> None: """ body = {"schemaType": "PROTOBUF", "schema": schema_v2} - res = await registry_async_client.post(f"subjects/{subject}/versions", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body) assert res.status_code == 200 assert "id" in res.json() @@ -1352,17 +1369,17 @@ async def test_registering_normalized_schema(session_logdir: Path, kafka_servers await asyncio.sleep(2) body = {"schemaType": "PROTOBUF", "schema": SCHEMA_WITH_OPTION_ORDERED} - res = await client1.post(f"subjects/{subject}/versions?normalize=true", json=body) + res = await client1.post_subjects_versions(subject=subject, json=body, params={"normalize": "true"}) assert res.status_code == 200 assert "id" in res.json() original_schema_id = res.json()["id"] body = {"schemaType": "PROTOBUF", "schema": SCHEMA_WITH_OPTION_UNORDERDERED} - res = await client1.post(f"subjects/{subject}", json=body) + res = await client1.post_subjects(subject=subject, json=body) assert res.status_code == 404 - res = await client2.post(f"subjects/{subject}?normalize=true", json=body) + res = await client2.post_subjects(subject=subject, json=body, params={"normalize": "true"}) assert res.status_code == 200 assert "id" in res.json() @@ -1374,20 +1391,20 @@ async def test_normalized_schema_idempotence_produce_and_fetch(registry_async_cl subject = create_subject_name_factory("test_protobuf_normalization")() body = {"schemaType": "PROTOBUF", "schema": SCHEMA_WITH_OPTION_UNORDERDERED} - res = await registry_async_client.post(f"subjects/{subject}/versions?normalize=true", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body, params={"normalize": "true"}) assert res.status_code == 200 assert "id" in res.json() original_schema_id = res.json()["id"] body = {"schemaType": "PROTOBUF", "schema": SCHEMA_WITH_OPTION_ORDERED} - res = await registry_async_client.post(f"subjects/{subject}/versions?normalize=true", json=body) + res = await registry_async_client.post_subjects_versions(subject=subject, json=body, params={"normalize": "true"}) assert res.status_code == 200 assert "id" in res.json() assert original_schema_id == res.json()["id"] - res = await registry_async_client.get(f"/schemas/ids/{original_schema_id}") + res = await registry_async_client.get_schema_by_id(schema_id=original_schema_id) assert res.status_code == 200 assert "schema" in res.json() assert res.json()["schema"] == SCHEMA_WITH_OPTION_ORDERED diff --git a/tests/integration/test_schema_registry_mode.py b/tests/integration/test_schema_registry_mode.py index cf5a3de87..fa15272bc 100644 --- a/tests/integration/test_schema_registry_mode.py +++ b/tests/integration/test_schema_registry_mode.py @@ -11,7 +11,7 @@ async def test_global_mode(registry_async_client: Client) -> None: - res = await registry_async_client.get("/mode") + res = await registry_async_client.get_mode() assert res.status_code == 200 json_res = res.json() assert json_res == {"mode": str(Mode.readwrite)} @@ -34,18 +34,15 @@ async def test_subject_mode(registry_async_client: Client) -> None: } ) subject = subject_name_factory() - res = await registry_async_client.post( - f"subjects/{subject}/versions", - json={"schema": schema_str}, - ) + res = await registry_async_client.post_subjects_versions(subject=subject, json={"schema": schema_str}) assert res.status_code == 200 - res = await registry_async_client.get(f"/mode/{subject}") + res = await registry_async_client.get_mode_subject(subject=subject) assert res.status_code == 200 json_res = res.json() assert json_res == {"mode": str(Mode.readwrite)} - res = await registry_async_client.get("/mode/unknown_subject") + res = await registry_async_client.get_mode_subject(subject="unknown_subject") assert res.status_code == 404 json_res = res.json() assert json_res == {"error_code": 40401, "message": "Subject 'unknown_subject' not found."} diff --git a/tests/utils.py b/tests/utils.py index e9596f725..dae8d5d9c 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -13,7 +13,6 @@ from pathlib import Path from subprocess import Popen from typing import Any, IO -from urllib.parse import quote_plus import asyncio import copy @@ -228,7 +227,12 @@ def new_random_name(prefix: str) -> str: def create_subject_name_factory(prefix: str) -> Callable[[], str]: - return create_id_factory(f"subject_{prefix}") + """Creates subject from the prefix. + + A slash is added to subject for validating the API behavior for url encoded subject name. + For example subject in the data: `test/subject` is `test%2Fsubject` in the API. + """ + return create_id_factory(f"subj/ect_{prefix}") def create_field_name_factory(prefix: str) -> Callable[[], str]: @@ -246,13 +250,13 @@ def create_group_name_factory(prefix: str) -> Callable[[], str]: def create_id_factory(prefix: str) -> Callable[[], str]: """ Creates unique ids prefixed with prefix.. - The resulting ids are safe to embed in URLs. + The resulting ids are NOT safe to embed in URLs. """ index = 1 def create_name() -> str: nonlocal index - return new_random_name(f"{quote_plus(prefix)}_{index}_") + return new_random_name(f"{prefix}_{index}_") return create_name