iliax před 2 roky
rodič
revize
2bff27244f

+ 25 - 30
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/SchemaReferencesResolver.java

@@ -1,15 +1,10 @@
 package com.provectus.kafka.ui.service.integration.odd;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import com.provectus.kafka.ui.sr.api.KafkaSrClientApi;
 import com.provectus.kafka.ui.sr.model.SchemaReference;
 import java.util.List;
-import java.util.Optional;
 import reactor.core.publisher.Mono;
 
 // logic copied from AbstractSchemaProvider:resolveReferences
@@ -22,41 +17,41 @@ class SchemaReferencesResolver {
     this.client = client;
   }
 
-  Mono<ImmutableMap<String, String>> resolve(List<SchemaReference> references) {
-    return resolveReferences(references, new State(ImmutableMap.of(), ImmutableSet.of()))
-        .map(State::resolved);
+  Mono<ImmutableMap<String, String>> resolve(List<SchemaReference> refs) {
+    return resolveReferences(
+        refs == null ? List.of() : refs,
+        new Resolving(ImmutableMap.of(), ImmutableSet.of())).map(
+        Resolving::resolved
+    );
   }
 
-  private record State(ImmutableMap<String, String> resolved, ImmutableSet<String> visited) {
+  private record Resolving(ImmutableMap<String, String> resolved, ImmutableSet<String> visited) {
 
-    State visit(String name) {
-      return new State(resolved, ImmutableSet.<String>builder().addAll(visited).add(name).build());
+    Resolving visit(String name) {
+      return new Resolving(resolved, ImmutableSet.<String>builder().addAll(visited).add(name).build());
     }
 
-    State resolve(String ref, String schema) {
-      return new State(ImmutableMap.<String, String>builder().putAll(resolved).put(ref, schema).build(), visited);
+    Resolving resolve(String ref, String schema) {
+      return new Resolving(ImmutableMap.<String, String>builder().putAll(resolved).put(ref, schema).build(), visited);
     }
   }
 
-  private Mono<State> resolveReferences(List<SchemaReference> references,
-                                        State initState) {
-    Mono<State> result = Mono.just(initState);
-    for (var reference : Optional.ofNullable(references).orElse(List.of())) {
+  private Mono<Resolving> resolveReferences(List<SchemaReference> references, Resolving initState) {
+    Mono<Resolving> result = Mono.just(initState);
+    for (SchemaReference reference : references) {
       result = result.flatMap(state -> {
-            if (state.visited().contains(reference.getName())) {
-              return Mono.just(state);
-            } else {
-              final var newState = state.visit(reference.getName());
-              return client.getSubjectVersion(reference.getSubject(), String.valueOf(reference.getVersion()), true)
-                  .flatMap(subj ->
-                      resolveReferences(subj.getReferences(), newState)
-                          .map(withNewRefs -> withNewRefs.resolve(reference.getName(), subj.getSchema()))
-                  );
-            }
-          }
-      );
+        if (state.visited().contains(reference.getName())) {
+          return Mono.just(state);
+        } else {
+          final var newState = state.visit(reference.getName());
+          return client.getSubjectVersion(reference.getSubject(), String.valueOf(reference.getVersion()), true)
+              .flatMap(subj ->
+                  resolveReferences(subj.getReferences(), newState)
+                      .map(withNewRefs -> withNewRefs.resolve(reference.getName(), subj.getSchema()))
+              );
+        }
+      });
     }
     return result;
   }
-
 }

+ 54 - 1
kafka-ui-api/src/test/java/com/provectus/kafka/ui/SchemaRegistryServiceTests.java

@@ -2,6 +2,7 @@ package com.provectus.kafka.ui;
 
 import com.provectus.kafka.ui.model.CompatibilityLevelDTO;
 import com.provectus.kafka.ui.model.NewSchemaSubjectDTO;
+import com.provectus.kafka.ui.model.SchemaReferenceDTO;
 import com.provectus.kafka.ui.model.SchemaSubjectDTO;
 import com.provectus.kafka.ui.model.SchemaSubjectsResponseDTO;
 import com.provectus.kafka.ui.model.SchemaTypeDTO;
@@ -190,6 +191,58 @@ class SchemaRegistryServiceTests extends AbstractIntegrationTest {
     Assertions.assertEquals(schema, actual.getSchema());
   }
 
+
+  @Test
+  void shouldCreateNewProtobufSchemaWithRefs() {
+    NewSchemaSubjectDTO requestBody = new NewSchemaSubjectDTO()
+        .schemaType(SchemaTypeDTO.PROTOBUF)
+        .subject(subject + "-ref")
+        .schema("""
+            syntax = "proto3";
+            message MyRecord {
+              int32 id = 1;
+              string name = 2;
+            }
+            """);
+
+    webTestClient
+        .post()
+        .uri("/api/clusters/{clusterName}/schemas", LOCAL)
+        .contentType(MediaType.APPLICATION_JSON)
+        .body(BodyInserters.fromPublisher(Mono.just(requestBody), NewSchemaSubjectDTO.class))
+        .exchange()
+        .expectStatus()
+        .isOk();
+
+    requestBody = new NewSchemaSubjectDTO()
+        .schemaType(SchemaTypeDTO.PROTOBUF)
+        .subject(subject)
+        .schema("""
+            syntax = "proto3";
+            import "MyRecord.proto";
+            message MyRecordWithRef {
+              int32 id = 1;
+              MyRecord my_ref = 2;
+            }
+            """)
+        .references(List.of(new SchemaReferenceDTO().name("MyRecord.proto").subject(subject + "-ref").version(1)));
+
+    SchemaSubjectDTO actual = webTestClient
+        .post()
+        .uri("/api/clusters/{clusterName}/schemas", LOCAL)
+        .contentType(MediaType.APPLICATION_JSON)
+        .body(BodyInserters.fromPublisher(Mono.just(requestBody), NewSchemaSubjectDTO.class))
+        .exchange()
+        .expectStatus()
+        .isOk()
+        .expectBody(SchemaSubjectDTO.class)
+        .returnResult()
+        .getResponseBody();
+
+    Assertions.assertNotNull(actual);
+    Assertions.assertEquals(requestBody.getReferences(), actual.getReferences());
+  }
+
   @Test
   public void shouldReturnBackwardAsGlobalCompatibilityLevelByDefault() {
     webTestClient
@@ -278,7 +331,7 @@ class SchemaRegistryServiceTests extends AbstractIntegrationTest {
   void shouldCreateNewSchemaWhenSubjectIncludesNonAsciiCharacters() {
     String schema =
         "{\"subject\":\"test/test\",\"schemaType\":\"JSON\",\"schema\":"
-        + "\"{\\\"type\\\": \\\"string\\\"}\"}";
+            + "\"{\\\"type\\\": \\\"string\\\"}\"}";
 
     webTestClient
         .post()

+ 1 - 0
kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/integration/odd/SchemaReferencesResolverTest.java

@@ -55,6 +55,7 @@ class SchemaReferencesResolverTest {
 
     assertThat(result.block())
         .containsExactlyEntriesOf(
+            // checking map should be ordered
             ImmutableMap.<String, String>builder()
                 .put("ref1", "schema1")
                 .put("ref2_1_1", "schema2_1_1")