diff --git a/karapace/protobuf/dependency.py b/karapace/protobuf/dependency.py index af5121488..55adbf5d0 100644 --- a/karapace/protobuf/dependency.py +++ b/karapace/protobuf/dependency.py @@ -25,7 +25,7 @@ def add_used_type(self, parent: str, element_type: str) -> None: end = element_type.find(">") virgule = element_type.find(",") key = element_type[4:virgule] - value = element_type[virgule + 1 : end] + value = element_type[virgule + 1: end] value = value.strip() self.used_types.append(parent + ";" + key) self.used_types.append(parent + ";" + value) @@ -39,10 +39,14 @@ def verify(self) -> DependencyVerifierResult: declared_index = set(self.declared_types) for used_type in self.used_types: delimiter = used_type.rfind(";") + father_child_type = None used_type_with_scope = "" if delimiter != -1: - used_type_with_scope = used_type[:delimiter] + "." + used_type[delimiter + 1 :] - used_type = used_type[delimiter + 1 :] + used_type_with_scope = used_type[:delimiter] + "." + used_type[delimiter + 1:] + father_delimiter = used_type[:delimiter].find(".") + if father_delimiter != -1: + father_child_type = used_type[:father_delimiter] + "." + used_type[delimiter + 1:] + used_type = used_type[delimiter + 1:] if used_type in DependenciesHardcoded.index: continue @@ -54,6 +58,7 @@ def verify(self) -> DependencyVerifierResult: if ( used_type in declared_index or (delimiter != -1 and used_type_with_scope in declared_index) + or (father_child_type is not None and father_child_type in declared_index) or "." + used_type in declared_index ): continue @@ -63,7 +68,8 @@ def verify(self) -> DependencyVerifierResult: return DependencyVerifierResult(True) -def process_one_of(verifier: ProtobufDependencyVerifier, package_name: str, parent_name: str, one_of: OneOfElement) -> None: +def process_one_of(verifier: ProtobufDependencyVerifier, package_name: str, parent_name: str, + one_of: OneOfElement) -> None: parent = package_name + "." + parent_name for field in one_of.fields: verifier.add_used_type(parent, field.element_type) diff --git a/karapace/protobuf/schema.py b/karapace/protobuf/schema.py index a0d91b1cb..d71f6a29d 100644 --- a/karapace/protobuf/schema.py +++ b/karapace/protobuf/schema.py @@ -169,7 +169,7 @@ def _process_nested_type( one_of_parent_name = parent_name + "." + element_type.name process_one_of(verifier, package_name, one_of_parent_name, one_of) for field in element_type.fields: - verifier.add_used_type(parent_name, field.element_type) + verifier.add_used_type(parent_name, field.element_type) for nested_type in element_type.nested_types: self._process_nested_type(verifier, package_name, parent_name + "." + element_type.name, nested_type) diff --git a/tests/integration/test_schema_protobuf.py b/tests/integration/test_schema_protobuf.py index 9a89a17cd..cfe715796 100644 --- a/tests/integration/test_schema_protobuf.py +++ b/tests/integration/test_schema_protobuf.py @@ -621,6 +621,7 @@ class ReferenceTestCase(BaseTestCase): """ + @pytest.mark.parametrize( "testcase", [ @@ -999,7 +1000,6 @@ async def test_references(testcase: ReferenceTestCase, registry_async_client: Cl fetch_schema_res = await registry_async_client.get(f"/schemas/ids/{testdata.schema_id}") assert fetch_schema_res.status_code == 200 - async def test_protobuf_error(registry_async_client: Client) -> None: testdata = TestCaseSchema( schema_type=SchemaType.PROTOBUF, diff --git a/tests/unit/protobuf/test_protobuf_schema.py b/tests/unit/protobuf/test_protobuf_schema.py index 774ea3279..9f5d96ec2 100644 --- a/tests/unit/protobuf/test_protobuf_schema.py +++ b/tests/unit/protobuf/test_protobuf_schema.py @@ -293,3 +293,44 @@ def test_protobuf_field_compatible_alter_to_oneof(): protobuf_schema1.compare(protobuf_schema2, result) assert result.is_compatible() + +def test_protobuf_self_referencing_schema(): + proto1 = """\ + syntax = "proto3"; + + package fancy.company.in.party.v1; + message MyFirstMessage { + string my_fancy_string = 1; + } + message AnotherMessage { + message WowANestedMessage { + enum BamFancyEnum { + // Hei! This is a comment! + MY_AWESOME_FIELD = 0; + } + BamFancyEnum im_tricky_im_referring_to_the_previous_enum = 1; + } + } + """ + + assert type(ValidatedTypedSchema.parse(SchemaType.PROTOBUF, proto1).schema) == ProtobufSchema + + + proto2 ="""\ + syntax = "proto3"; + + package fancy.company.in.party.v1; + message AnotherMessage { + enum BamFancyEnum { + // Hei! This is a comment! + MY_AWESOME_FIELD = 0; + } + message WowANestedMessage { + message DeeplyNestedMsg { + BamFancyEnum im_tricky_im_referring_to_the_previous_enum = 1; + } + } + } + """ + + assert type(ValidatedTypedSchema.parse(SchemaType.PROTOBUF, proto2).schema) == ProtobufSchema