Bladeren bron

Merge branch 'master' into Remove_extra_indents_from_json

# Conflicts:
#	.github/workflows/e2e-automation.yml
#	.github/workflows/e2e-checks.yaml
#	.github/workflows/e2e-weekly.yml
#	kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java
#	kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java
#	kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/QaseSetup.java
#	kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java
VladSenyuta 2 jaren geleden
bovenliggende
commit
f7a90a6a7f

+ 10 - 11
.github/workflows/e2e-automation.yml

@@ -13,11 +13,10 @@ on:
           - regression
           - regression
           - sanity
           - sanity
           - smoke
           - smoke
-      qase_enabled:
-        description: 'Enable Qase integration'
-        default: true
-        required: true
-        type: boolean
+      qase_token:
+        description: 'Set Qase token to enable integration'
+        required: false
+        type: string
 
 
 jobs:
 jobs:
   build-and-test:
   build-and-test:
@@ -25,7 +24,7 @@ jobs:
     steps:
     steps:
       - uses: actions/checkout@v3
       - uses: actions/checkout@v3
         with:
         with:
-          ref: ${{ github.event.pull_request.head.sha }}
+          ref: ${{ github.sha }}
       - name: Set up environment
       - name: Set up environment
         id: set_env_values
         id: set_env_values
         run: |
         run: |
@@ -43,7 +42,7 @@ jobs:
       - name: Build with Maven
       - name: Build with Maven
         id: build_app
         id: build_app
         run: |
         run: |
-          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }}
+          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.sha }}
           ./mvnw -B -V -ntp clean install -Pprod -Dmaven.test.skip=true ${{ github.event.inputs.extraMavenOptions }}
           ./mvnw -B -V -ntp clean install -Pprod -Dmaven.test.skip=true ${{ github.event.inputs.extraMavenOptions }}
       - name: Compose with Docker
       - name: Compose with Docker
         id: compose_app
         id: compose_app
@@ -52,8 +51,8 @@ jobs:
           docker-compose -f ./documentation/compose/e2e-tests.yaml up -d
           docker-compose -f ./documentation/compose/e2e-tests.yaml up -d
       - name: Run test suite
       - name: Run test suite
         run: |
         run: |
-          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }}
-          ./mvnw -B -V -ntp -DQASEIO_API_TOKEN=${{ secrets.QASEIO_API_TOKEN }} -Dsurefire.suiteXmlFiles='src/test/resources/${{ github.event.inputs.test_suite }}.xml' -Dsuite=${{ github.event.inputs.test_suite }} -Dqase=${{ github.event.inputs.qase_enabled }} -f 'kafka-ui-e2e-checks' test -Pprod
+          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.sha }}
+          ./mvnw -B -V -ntp -DQASEIO_API_TOKEN=${{ github.event.inputs.qase_token }} -Dsurefire.suiteXmlFiles='src/test/resources/${{ github.event.inputs.test_suite }}.xml' -Dsuite=${{ github.event.inputs.test_suite }} -f 'kafka-ui-e2e-checks' test -Pprod
       - name: Generate Allure report
       - name: Generate Allure report
         uses: simple-elf/allure-report-action@master
         uses: simple-elf/allure-report-action@master
         if: always()
         if: always()
@@ -77,9 +76,9 @@ jobs:
         uses: Sibz/github-status-action@v1.1.6
         uses: Sibz/github-status-action@v1.1.6
         with:
         with:
           authToken: ${{secrets.GITHUB_TOKEN}}
           authToken: ${{secrets.GITHUB_TOKEN}}
-          context: "Click Details button to open Allure report"
+          context: "Test report"
           state: "success"
           state: "success"
-          sha: ${{ github.event.pull_request.head.sha  || github.sha }}
+          sha: ${{ github.sha }}
           target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }}
           target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }}
       - name: Dump Docker logs on failure
       - name: Dump Docker logs on failure
         if: failure()
         if: failure()

+ 4 - 4
.github/workflows/e2e-checks.yaml

@@ -1,7 +1,7 @@
-name: E2E tests
+name: E2E PR health check
 on:
 on:
   pull_request_target:
   pull_request_target:
-    types: ["opened", "edited", "reopened", "synchronize"]
+    types: [ "opened", "edited", "reopened", "synchronize" ]
     paths:
     paths:
       - "kafka-ui-api/**"
       - "kafka-ui-api/**"
       - "kafka-ui-contract/**"
       - "kafka-ui-contract/**"
@@ -42,7 +42,7 @@ jobs:
       - name: e2e run
       - name: e2e run
         run: |
         run: |
           ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }}
           ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }}
-          ./mvnw -B -V -ntp -DQASEIO_API_TOKEN=${{ secrets.QASEIO_API_TOKEN }} -Dsurefire.suiteXmlFiles='src/test/resources/smoke.xml' -f 'kafka-ui-e2e-checks' test -Pprod
+          ./mvnw -B -V -ntp -Dsurefire.suiteXmlFiles='src/test/resources/smoke.xml' -f 'kafka-ui-e2e-checks' test -Pprod
       - name: Generate allure report
       - name: Generate allure report
         uses: simple-elf/allure-report-action@master
         uses: simple-elf/allure-report-action@master
         if: always()
         if: always()
@@ -66,7 +66,7 @@ jobs:
         uses: Sibz/github-status-action@v1.1.6
         uses: Sibz/github-status-action@v1.1.6
         with:
         with:
           authToken: ${{secrets.GITHUB_TOKEN}}
           authToken: ${{secrets.GITHUB_TOKEN}}
-          context: "Test report"
+          context: "Click Details button to open Allure report"
           state: "success"
           state: "success"
           sha: ${{ github.event.pull_request.head.sha  || github.sha }}
           sha: ${{ github.event.pull_request.head.sha  || github.sha }}
           target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }}
           target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }}

+ 7 - 7
.github/workflows/e2e-weekly.yml

@@ -1,4 +1,4 @@
-name: E2E Automation suite
+name: E2E Weekly suite
 on:
 on:
   schedule:
   schedule:
     - cron: '0 1 * * 1'
     - cron: '0 1 * * 1'
@@ -9,7 +9,7 @@ jobs:
     steps:
     steps:
       - uses: actions/checkout@v3
       - uses: actions/checkout@v3
         with:
         with:
-          ref: ${{ github.event.pull_request.head.sha }}
+          ref: ${{ github.sha }}
       - name: Set up environment
       - name: Set up environment
         id: set_env_values
         id: set_env_values
         run: |
         run: |
@@ -27,7 +27,7 @@ jobs:
       - name: Build with Maven
       - name: Build with Maven
         id: build_app
         id: build_app
         run: |
         run: |
-          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }}
+          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.sha }}
           ./mvnw -B -V -ntp clean install -Pprod -Dmaven.test.skip=true ${{ github.event.inputs.extraMavenOptions }}
           ./mvnw -B -V -ntp clean install -Pprod -Dmaven.test.skip=true ${{ github.event.inputs.extraMavenOptions }}
       - name: Compose with Docker
       - name: Compose with Docker
         id: compose_app
         id: compose_app
@@ -36,8 +36,8 @@ jobs:
           docker-compose -f ./documentation/compose/e2e-tests.yaml up -d
           docker-compose -f ./documentation/compose/e2e-tests.yaml up -d
       - name: Run test suite
       - name: Run test suite
         run: |
         run: |
-          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.event.pull_request.head.sha }}
-          ./mvnw -B -V -ntp -DQASEIO_API_TOKEN=${{ secrets.QASEIO_API_TOKEN }} -Dsurefire.suiteXmlFiles='src/test/resources/sanity.xml' -Dsuite=weekly -Dqase=true -f 'kafka-ui-e2e-checks' test -Pprod
+          ./mvnw -B -ntp versions:set -DnewVersion=${{ github.sha }}
+          ./mvnw -B -V -ntp -DQASEIO_API_TOKEN=${{ secrets.QASEIO_API_TOKEN }} -Dsurefire.suiteXmlFiles='src/test/resources/sanity.xml' -Dsuite=weekly -f 'kafka-ui-e2e-checks' test -Pprod
       - name: Generate Allure report
       - name: Generate Allure report
         uses: simple-elf/allure-report-action@master
         uses: simple-elf/allure-report-action@master
         if: always()
         if: always()
@@ -61,9 +61,9 @@ jobs:
         uses: Sibz/github-status-action@v1.1.6
         uses: Sibz/github-status-action@v1.1.6
         with:
         with:
           authToken: ${{secrets.GITHUB_TOKEN}}
           authToken: ${{secrets.GITHUB_TOKEN}}
-          context: "Click Details button to open Allure report"
+          context: "Test report"
           state: "success"
           state: "success"
-          sha: ${{ github.event.pull_request.head.sha  || github.sha }}
+          sha: ${{ github.sha }}
           target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }}
           target_url: http://kafkaui-allure-reports.s3-website.eu-central-1.amazonaws.com/${{ github.run_number }}
       - name: Dump Docker logs on failure
       - name: Dump Docker logs on failure
         if: failure()
         if: failure()

+ 2 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/serdes/SerdesInitializer.java

@@ -9,6 +9,7 @@ import com.provectus.kafka.ui.config.ClustersProperties.SerdeConfig;
 import com.provectus.kafka.ui.exception.ValidationException;
 import com.provectus.kafka.ui.exception.ValidationException;
 import com.provectus.kafka.ui.serde.api.PropertyResolver;
 import com.provectus.kafka.ui.serde.api.PropertyResolver;
 import com.provectus.kafka.ui.serde.api.Serde;
 import com.provectus.kafka.ui.serde.api.Serde;
+import com.provectus.kafka.ui.serdes.builtin.AvroEmbeddedSerde;
 import com.provectus.kafka.ui.serdes.builtin.Base64Serde;
 import com.provectus.kafka.ui.serdes.builtin.Base64Serde;
 import com.provectus.kafka.ui.serdes.builtin.Int32Serde;
 import com.provectus.kafka.ui.serdes.builtin.Int32Serde;
 import com.provectus.kafka.ui.serdes.builtin.Int64Serde;
 import com.provectus.kafka.ui.serdes.builtin.Int64Serde;
@@ -43,6 +44,7 @@ public class SerdesInitializer {
             .put(Int64Serde.name(), Int64Serde.class)
             .put(Int64Serde.name(), Int64Serde.class)
             .put(UInt32Serde.name(), UInt32Serde.class)
             .put(UInt32Serde.name(), UInt32Serde.class)
             .put(UInt64Serde.name(), UInt64Serde.class)
             .put(UInt64Serde.name(), UInt64Serde.class)
+            .put(AvroEmbeddedSerde.name(), AvroEmbeddedSerde.class)
             .put(Base64Serde.name(), Base64Serde.class)
             .put(Base64Serde.name(), Base64Serde.class)
             .put(UuidBinarySerde.name(), UuidBinarySerde.class)
             .put(UuidBinarySerde.name(), UuidBinarySerde.class)
             .build(),
             .build(),

+ 72 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/serdes/builtin/AvroEmbeddedSerde.java

@@ -0,0 +1,72 @@
+package com.provectus.kafka.ui.serdes.builtin;
+
+import com.provectus.kafka.ui.serde.api.DeserializeResult;
+import com.provectus.kafka.ui.serde.api.PropertyResolver;
+import com.provectus.kafka.ui.serde.api.RecordHeaders;
+import com.provectus.kafka.ui.serde.api.SchemaDescription;
+import com.provectus.kafka.ui.serdes.BuiltInSerde;
+import io.confluent.kafka.schemaregistry.avro.AvroSchemaUtils;
+import java.util.Map;
+import java.util.Optional;
+import lombok.SneakyThrows;
+import org.apache.avro.file.DataFileReader;
+import org.apache.avro.file.SeekableByteArrayInput;
+import org.apache.avro.generic.GenericDatumReader;
+
+public class AvroEmbeddedSerde implements BuiltInSerde {
+
+  public static String name() {
+    return "Avro (Embedded)";
+  }
+
+  @Override
+  public void configure(PropertyResolver serdeProperties,
+                        PropertyResolver kafkaClusterProperties,
+                        PropertyResolver globalProperties) {
+  }
+
+  @Override
+  public Optional<String> getDescription() {
+    return Optional.empty();
+  }
+
+  @Override
+  public Optional<SchemaDescription> getSchema(String topic, Target type) {
+    return Optional.empty();
+  }
+
+  @Override
+  public boolean canDeserialize(String topic, Target type) {
+    return true;
+  }
+
+  @Override
+  public boolean canSerialize(String topic, Target type) {
+    return false;
+  }
+
+  @Override
+  public Serializer serializer(String topic, Target type) {
+    throw new IllegalStateException();
+  }
+
+  @Override
+  public Deserializer deserializer(String topic, Target type) {
+    return new Deserializer() {
+      @SneakyThrows
+      @Override
+      public DeserializeResult deserialize(RecordHeaders headers, byte[] data) {
+        try (var reader = new DataFileReader<>(new SeekableByteArrayInput(data), new GenericDatumReader<>())) {
+          if (!reader.hasNext()) {
+            // this is very strange situation, when only header present in payload
+            // returning null in this case
+            return new DeserializeResult(null, DeserializeResult.Type.JSON, Map.of());
+          }
+          Object avroObj = reader.next();
+          String jsonValue = new String(AvroSchemaUtils.toJson(avroObj));
+          return new DeserializeResult(jsonValue, DeserializeResult.Type.JSON, Map.of());
+        }
+      }
+    };
+  }
+}

+ 92 - 0
kafka-ui-api/src/test/java/com/provectus/kafka/ui/serdes/builtin/AvroEmbeddedSerdeTest.java

@@ -0,0 +1,92 @@
+package com.provectus.kafka.ui.serdes.builtin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.provectus.kafka.ui.serde.api.DeserializeResult;
+import com.provectus.kafka.ui.serde.api.Serde;
+import com.provectus.kafka.ui.serdes.PropertyResolverImpl;
+import io.confluent.kafka.schemaregistry.avro.AvroSchemaUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import org.apache.avro.Schema;
+import org.apache.avro.file.DataFileWriter;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+class AvroEmbeddedSerdeTest {
+
+  private AvroEmbeddedSerde avroEmbeddedSerde;
+
+  @BeforeEach
+  void init() {
+    avroEmbeddedSerde = new AvroEmbeddedSerde();
+    avroEmbeddedSerde.configure(
+        PropertyResolverImpl.empty(),
+        PropertyResolverImpl.empty(),
+        PropertyResolverImpl.empty()
+    );
+  }
+
+  @ParameterizedTest
+  @EnumSource
+  void canDeserializeReturnsTrueForAllTargets(Serde.Target target) {
+    assertThat(avroEmbeddedSerde.canDeserialize("anyTopic", target))
+        .isTrue();
+  }
+
+  @ParameterizedTest
+  @EnumSource
+  void canSerializeReturnsFalseForAllTargets(Serde.Target target) {
+    assertThat(avroEmbeddedSerde.canSerialize("anyTopic", target))
+        .isFalse();
+  }
+
+  @Test
+  void deserializerParsesAvroDataWithEmbeddedSchema() throws Exception {
+    Schema schema = new Schema.Parser().parse("""
+        {
+          "type": "record",
+          "name": "TestAvroRecord",
+          "fields": [
+            { "name": "field1", "type": "string" },
+            { "name": "field2", "type": "int" }
+          ]
+        }
+        """
+    );
+    GenericRecord record = new GenericData.Record(schema);
+    record.put("field1", "this is test msg");
+    record.put("field2", 100500);
+
+    String jsonRecord = new String(AvroSchemaUtils.toJson(record));
+    byte[] serializedRecordBytes = serializeAvroWithEmbeddedSchema(record);
+
+    var deserializer = avroEmbeddedSerde.deserializer("anyTopic", Serde.Target.KEY);
+    DeserializeResult result = deserializer.deserialize(null, serializedRecordBytes);
+    assertThat(result.getType()).isEqualTo(DeserializeResult.Type.JSON);
+    assertThat(result.getAdditionalProperties()).isEmpty();
+    assertJsonEquals(jsonRecord, result.getResult());
+  }
+
+  private void assertJsonEquals(String expected, String actual) throws IOException {
+    var mapper = new JsonMapper();
+    assertThat(mapper.readTree(actual)).isEqualTo(mapper.readTree(expected));
+  }
+
+  private byte[] serializeAvroWithEmbeddedSchema(GenericRecord record) throws IOException {
+    try (DataFileWriter<GenericRecord> writer = new DataFileWriter<>(new GenericDatumWriter<>());
+         ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+      writer.create(record.getSchema(), baos);
+      writer.append(record);
+      writer.flush();
+      return baos.toByteArray();
+    }
+  }
+
+}

+ 0 - 1
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java

@@ -11,7 +11,6 @@ public abstract class BaseSource {
     private static Config config;
     private static Config config;
     public static final String BROWSER = config().browser();
     public static final String BROWSER = config().browser();
     public static final String SUITE_NAME = config().suite();
     public static final String SUITE_NAME = config().suite();
-    public static final String QASE_ENABLED = config().qase();
 
 
     private static Config config() {
     private static Config config() {
         if (config == null) {
         if (config == null) {

+ 0 - 5
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java

@@ -4,7 +4,6 @@ import org.aeonbits.owner.Config;
 
 
 import static com.provectus.kafka.ui.variables.Browser.CONTAINER;
 import static com.provectus.kafka.ui.variables.Browser.CONTAINER;
 import static com.provectus.kafka.ui.variables.Suite.CUSTOM;
 import static com.provectus.kafka.ui.variables.Suite.CUSTOM;
-import static org.apache.commons.lang3.BooleanUtils.FALSE;
 
 
 public interface Profiles extends Config {
 public interface Profiles extends Config {
 
 
@@ -15,8 +14,4 @@ public interface Profiles extends Config {
     @Key("suite")
     @Key("suite")
     @DefaultValue(CUSTOM)
     @DefaultValue(CUSTOM)
     String suite();
     String suite();
-
-    @Key("qase")
-    @DefaultValue(FALSE)
-    String qase();
 }
 }

+ 3 - 3
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/QaseSetup.java

@@ -6,8 +6,8 @@ import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
 
 
-import static com.provectus.kafka.ui.settings.BaseSource.QASE_ENABLED;
 import static com.provectus.kafka.ui.settings.BaseSource.SUITE_NAME;
 import static com.provectus.kafka.ui.settings.BaseSource.SUITE_NAME;
+import static com.provectus.kafka.ui.variables.Suite.MANUAL;
 import static org.apache.commons.lang3.BooleanUtils.FALSE;
 import static org.apache.commons.lang3.BooleanUtils.FALSE;
 import static org.apache.commons.lang3.BooleanUtils.TRUE;
 import static org.apache.commons.lang3.BooleanUtils.TRUE;
 import static org.apache.commons.lang3.StringUtils.isEmpty;
 import static org.apache.commons.lang3.StringUtils.isEmpty;
@@ -17,12 +17,12 @@ public class QaseSetup {
 
 
     public static void testRunSetup() {
     public static void testRunSetup() {
         String qaseApiToken = System.getProperty("QASEIO_API_TOKEN");
         String qaseApiToken = System.getProperty("QASEIO_API_TOKEN");
-        if (isEmpty(qaseApiToken) || !Boolean.parseBoolean(QASE_ENABLED)) {
+        if (isEmpty(qaseApiToken)) {
             log.warn("Integration with Qase is disabled due to run config or token wasn't defined.");
             log.warn("Integration with Qase is disabled due to run config or token wasn't defined.");
             System.setProperty("QASE_ENABLE", FALSE);
             System.setProperty("QASE_ENABLE", FALSE);
         } else {
         } else {
             log.warn("Integration with Qase is enabled. Find this run at https://app.qase.io/run/KAFKAUI.");
             log.warn("Integration with Qase is enabled. Find this run at https://app.qase.io/run/KAFKAUI.");
-            String automation = SUITE_NAME.equalsIgnoreCase("manual") ? "Automation " : "";
+            String automation = SUITE_NAME.equalsIgnoreCase(MANUAL) ? "" : "Automation ";
             System.setProperty("QASE_ENABLE", TRUE);
             System.setProperty("QASE_ENABLE", TRUE);
             System.setProperty("QASE_PROJECT_CODE", "KAFKAUI");
             System.setProperty("QASE_PROJECT_CODE", "KAFKAUI");
             System.setProperty("QASE_API_TOKEN", qaseApiToken);
             System.setProperty("QASE_API_TOKEN", qaseApiToken);

+ 2 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java

@@ -3,6 +3,8 @@ package com.provectus.kafka.ui.variables;
 public interface Suite {
 public interface Suite {
 
 
     String CUSTOM = "custom";
     String CUSTOM = "custom";
+    String MANUAL = "manual";
+    String QASE = "qase";
     String REGRESSION = "regression";
     String REGRESSION = "regression";
     String SANITY = "sanity";
     String SANITY = "sanity";
     String SMOKE = "smoke";
     String SMOKE = "smoke";

+ 4 - 0
kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/sanitySuite/TestClass.java

@@ -0,0 +1,4 @@
+package com.provectus.kafka.ui.sanitySuite;
+
+public class TestClass {
+}