This is an automated email from the ASF dual-hosted git repository. cdeppisch pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-kamelets.git
The following commit(s) were added to refs/heads/main by this push: new b06399e8 Improve Protobuf serialization/deserialization Kamelets b06399e8 is described below commit b06399e85eb540834f4c55f196068d5dfc3174c6 Author: Christoph Deppisch <cdeppi...@redhat.com> AuthorDate: Fri May 3 09:56:04 2024 +0200 Improve Protobuf serialization/deserialization Kamelets - Use Protobuf schema resolver from Camel core - Add YAKS tests for Protobuf serdes --- kamelets/protobuf-deserialize-action.kamelet.yaml | 2 +- kamelets/protobuf-serialize-action.kamelet.yaml | 2 +- .../camel/kamelets/utils/format/MimeType.java | 2 + .../camel/kamelets/utils/format/SchemaType.java | 49 ------- .../format/schema/DelegatingSchemaResolver.java | 4 +- .../utils/format/schema/protobuf/Protobuf.java | 29 ---- .../schema/protobuf/ProtobufSchemaResolver.java | 159 --------------------- .../protobuf-deserialize-action.kamelet.yaml | 2 +- .../protobuf-serialize-action.kamelet.yaml | 2 +- .../src/test/java/KameletsYaksIT.java | 1 + .../src/test/resources/avro/README.md | 10 +- .../test/resources/aws/s3/aws-s3-http-pipe.feature | 2 + .../resources/earthquake/earthquake-source.feature | 2 + .../src/test/resources/kafka/kafka-source.feature | 1 + .../src/test/resources/mail/mail-sink.feature | 1 + .../resources/openapi/rest-openapi-sink.feature | 2 + .../src/test/resources/protobuf/README.md | 42 ++++++ .../src/test/resources/protobuf/User.proto | 10 ++ .../protobuf/protobuf-binary-source-pipe.yaml | 63 ++++++++ .../resources/protobuf/protobuf-data-type.feature | 22 +++ .../protobuf-deserialize-pipe.yaml} | 58 ++++---- .../protobuf/protobuf-serdes-action.feature | 22 +++ .../protobuf/protobuf-serialize-pipe.yaml | 59 ++++++++ .../protobuf/protobuf-x-struct-sink-pipe.yaml | 67 +++++++++ .../yaks-config.yaml} | 52 +++---- .../src/test/resources/timer/timer-source.feature | 2 + .../src/test/resources/timer/timer-to-http.feature | 2 + .../transformation/data-type-action.feature | 2 + .../transformation/extract-field-action.feature | 2 + .../transformation/insert-field-action.feature | 2 + 30 files changed, 380 insertions(+), 295 deletions(-) diff --git a/kamelets/protobuf-deserialize-action.kamelet.yaml b/kamelets/protobuf-deserialize-action.kamelet.yaml index 830d0d8c..1501811b 100644 --- a/kamelets/protobuf-deserialize-action.kamelet.yaml +++ b/kamelets/protobuf-deserialize-action.kamelet.yaml @@ -46,7 +46,7 @@ spec: template: beans: - name: schemaResolver - type: "#class:org.apache.camel.kamelets.utils.format.schema.protobuf.ProtobufSchemaResolver" + type: "#class:org.apache.camel.component.jackson.protobuf.transform.ProtobufSchemaResolver" property: - key: schema value: '{{schema:}}' diff --git a/kamelets/protobuf-serialize-action.kamelet.yaml b/kamelets/protobuf-serialize-action.kamelet.yaml index 9e4bbb23..61755b84 100644 --- a/kamelets/protobuf-serialize-action.kamelet.yaml +++ b/kamelets/protobuf-serialize-action.kamelet.yaml @@ -46,7 +46,7 @@ spec: template: beans: - name: schemaResolver - type: "#class:org.apache.camel.kamelets.utils.format.schema.protobuf.ProtobufSchemaResolver" + type: "#class:org.apache.camel.component.jackson.protobuf.transform.ProtobufSchemaResolver" property: - key: schema value: '{{schema:}}' diff --git a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/MimeType.java b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/MimeType.java index 7c205439..4c819bb8 100644 --- a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/MimeType.java +++ b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/MimeType.java @@ -22,6 +22,8 @@ import java.util.Objects; public enum MimeType { JSON("application/json"), PROTOBUF("application/protobuf"), + PROTOBUF_BINARY("protobuf/binary"), + PROTOBUF_STRUCT("protobuf/x-struct"), AVRO("application/avro"), AVRO_BINARY("avro/binary"), AVRO_STRUCT("avro/x-struct"), diff --git a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/SchemaType.java b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/SchemaType.java deleted file mode 100644 index 10fa2c58..00000000 --- a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/SchemaType.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.camel.kamelets.utils.format; - -import java.util.Arrays; -import java.util.Objects; - -/** - * Supported schema type for Java object serialization/deserialization - */ -public enum SchemaType { - PROTOBUF("protobuf"), - AVRO("avsc"), - JSON("json"); - - private static final SchemaType[] VALUES = values(); - - private final String schemaType; - - SchemaType(String type) { - this.schemaType = type; - } - - public String type() { - return schemaType; - } - - public static SchemaType of(String type) { - return Arrays.stream(VALUES) - .filter(s -> Objects.equals(s.schemaType, type)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException(String.format("Unsupported schema type '%s'", type))); - } -} diff --git a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/DelegatingSchemaResolver.java b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/DelegatingSchemaResolver.java index dba0fae2..0c05a37b 100644 --- a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/DelegatingSchemaResolver.java +++ b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/DelegatingSchemaResolver.java @@ -20,9 +20,9 @@ package org.apache.camel.kamelets.utils.format.schema; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.component.jackson.avro.transform.AvroSchemaResolver; +import org.apache.camel.component.jackson.protobuf.transform.ProtobufSchemaResolver; import org.apache.camel.component.jackson.transform.JsonSchemaResolver; import org.apache.camel.kamelets.utils.format.MimeType; -import org.apache.camel.kamelets.utils.format.schema.protobuf.ProtobufSchemaResolver; import org.apache.camel.util.ObjectHelper; /** @@ -63,6 +63,8 @@ public class DelegatingSchemaResolver implements Processor { private Processor fromMimeType(MimeType mimeType) { switch (mimeType) { case PROTOBUF: + case PROTOBUF_BINARY: + case PROTOBUF_STRUCT: ProtobufSchemaResolver protobufSchemaResolver = new ProtobufSchemaResolver(); protobufSchemaResolver.setSchema(this.schema); protobufSchemaResolver.setContentClass(this.contentClass); diff --git a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/protobuf/Protobuf.java b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/protobuf/Protobuf.java deleted file mode 100644 index 2cb44689..00000000 --- a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/protobuf/Protobuf.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.camel.kamelets.utils.format.schema.protobuf; - -import com.fasterxml.jackson.dataformat.protobuf.ProtobufMapper; - -public final class Protobuf { - - public static final ProtobufMapper MAPPER = new ProtobufMapper(); - - private Protobuf() { - // prevent instantiation of utility class - } -} diff --git a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/protobuf/ProtobufSchemaResolver.java b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/protobuf/ProtobufSchemaResolver.java deleted file mode 100644 index dfa37609..00000000 --- a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/format/schema/protobuf/ProtobufSchemaResolver.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.camel.kamelets.utils.format.schema.protobuf; - -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import com.fasterxml.jackson.core.FormatSchema; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchema; -import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchemaLoader; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.apache.camel.RuntimeCamelException; -import org.apache.camel.component.jackson.SchemaHelper; -import org.apache.camel.component.jackson.SchemaResolver; -import org.apache.camel.kamelets.utils.format.SchemaType; -import org.apache.camel.spi.Resource; -import org.apache.camel.support.PluginHelper; -import org.apache.camel.util.ObjectHelper; - -public class ProtobufSchemaResolver implements SchemaResolver, Processor { - private final ConcurrentMap<String, ProtobufSchema> schemes; - - private ProtobufSchema schema; - private String contentClass; - - public ProtobufSchemaResolver() { - this.schemes = new ConcurrentHashMap<>(); - } - - public String getSchema() { - if (this.schema != null) { - return this.schema.getSource().toString(); - } - - return null; - } - - public void setSchema(String schema) { - if (ObjectHelper.isNotEmpty(schema)) { - try { - this.schema = ProtobufSchemaLoader.std.parse(schema); - } catch (IOException e) { - throw new RuntimeCamelException("Cannot parse protobuf schema", e); - } - } else { - this.schema = null; - } - } - - public String getContentClass() { - return contentClass; - } - - public void setContentClass(String contentClass) { - if (ObjectHelper.isNotEmpty(contentClass)) { - this.contentClass = contentClass; - } else { - this.contentClass = null; - } - } - - @Override - public void process(Exchange exchange) throws Exception { - Object payload = exchange.getMessage().getBody(); - if (payload == null) { - return; - } - - ProtobufSchema answer = computeIfAbsent(exchange); - - if (answer != null) { - exchange.setProperty(SchemaHelper.CONTENT_SCHEMA, answer); - exchange.setProperty(SchemaHelper.CONTENT_SCHEMA_TYPE, SchemaType.PROTOBUF.type()); - exchange.setProperty(SchemaHelper.CONTENT_CLASS, SchemaHelper.resolveContentClass(exchange, this.contentClass)); - } - } - - @Override - public FormatSchema resolve(Exchange exchange) { - ProtobufSchema answer = exchange.getProperty(SchemaHelper.CONTENT_SCHEMA, ProtobufSchema.class); - if (answer == null) { - answer = computeIfAbsent(exchange); - } - - return answer; - } - - private ProtobufSchema computeIfAbsent(Exchange exchange) { - if (this.schema != null) { - return this.schema; - } - - ProtobufSchema answer = exchange.getProperty(SchemaHelper.CONTENT_SCHEMA, ProtobufSchema.class); - - if (answer == null && exchange.getProperties().containsKey(SchemaHelper.SCHEMA)) { - String schemaJson = exchange.getProperty(SchemaHelper.SCHEMA, String.class); - try { - answer = ProtobufSchemaLoader.std.parse(schemaJson); - } catch (IOException e) { - throw new RuntimeException("Unable to parse Protobuf schema", e); - } - } - - if (answer == null) { - String contentClass = SchemaHelper.resolveContentClass(exchange, this.contentClass); - if (contentClass != null) { - answer = this.schemes.computeIfAbsent(contentClass, t -> { - Resource res = PluginHelper.getResourceLoader(exchange.getContext()) - .resolveResource("classpath:schemas/" + SchemaType.AVRO.type() + "/" + t + "." + SchemaType.AVRO.type()); - - try { - if (res.exists()) { - try (InputStream is = res.getInputStream()) { - if (is != null) { - return Protobuf.MAPPER.schemaLoader().load(is); - } - } - } - } catch (Exception e) { - throw new RuntimeException( - "Unable to load Protobuf schema for type: " + t + ", resource: " + res.getLocation(), e); - } - - try { - return Protobuf.MAPPER.generateSchemaFor(Class.forName(contentClass)); - } catch (JsonMappingException | ClassNotFoundException e) { - throw new RuntimeException( - "Unable to compute Protobuf schema for type: " + t, e); - } - }); - } - } - - if (answer != null) { - this.schema = answer; - } - - return answer; - } -} diff --git a/library/camel-kamelets/src/main/resources/kamelets/protobuf-deserialize-action.kamelet.yaml b/library/camel-kamelets/src/main/resources/kamelets/protobuf-deserialize-action.kamelet.yaml index 830d0d8c..1501811b 100644 --- a/library/camel-kamelets/src/main/resources/kamelets/protobuf-deserialize-action.kamelet.yaml +++ b/library/camel-kamelets/src/main/resources/kamelets/protobuf-deserialize-action.kamelet.yaml @@ -46,7 +46,7 @@ spec: template: beans: - name: schemaResolver - type: "#class:org.apache.camel.kamelets.utils.format.schema.protobuf.ProtobufSchemaResolver" + type: "#class:org.apache.camel.component.jackson.protobuf.transform.ProtobufSchemaResolver" property: - key: schema value: '{{schema:}}' diff --git a/library/camel-kamelets/src/main/resources/kamelets/protobuf-serialize-action.kamelet.yaml b/library/camel-kamelets/src/main/resources/kamelets/protobuf-serialize-action.kamelet.yaml index 9e4bbb23..61755b84 100644 --- a/library/camel-kamelets/src/main/resources/kamelets/protobuf-serialize-action.kamelet.yaml +++ b/library/camel-kamelets/src/main/resources/kamelets/protobuf-serialize-action.kamelet.yaml @@ -46,7 +46,7 @@ spec: template: beans: - name: schemaResolver - type: "#class:org.apache.camel.kamelets.utils.format.schema.protobuf.ProtobufSchemaResolver" + type: "#class:org.apache.camel.component.jackson.protobuf.transform.ProtobufSchemaResolver" property: - key: schema value: '{{schema:}}' diff --git a/tests/camel-kamelets-itest/src/test/java/KameletsYaksIT.java b/tests/camel-kamelets-itest/src/test/java/KameletsYaksIT.java index 50b80bb0..1558f9e5 100644 --- a/tests/camel-kamelets-itest/src/test/java/KameletsYaksIT.java +++ b/tests/camel-kamelets-itest/src/test/java/KameletsYaksIT.java @@ -21,6 +21,7 @@ import org.junit.runner.RunWith; @RunWith(Cucumber.class) @CucumberOptions( + //features = "src/test/resources/openapi", extraGlue = "org.citrusframework.yaks", plugin = { "pretty", "org.citrusframework.yaks.report.TestReporter" } ) diff --git a/tests/camel-kamelets-itest/src/test/resources/avro/README.md b/tests/camel-kamelets-itest/src/test/resources/avro/README.md index c642975b..6825c4de 100644 --- a/tests/camel-kamelets-itest/src/test/resources/avro/README.md +++ b/tests/camel-kamelets-itest/src/test/resources/avro/README.md @@ -6,9 +6,9 @@ This test verifies the Avro serialization/deserialization actions The test verifies the proper Avro serialization and deserialization of Avro. -The test uses two Pipes that interact with each other. The first binding `json-to-avro` periodically creates a test data event as Json and applies the `avro/binary` data type using the schema in [User.avsc](User.avsc). +The test uses two Pipes that interact with each other. The first binding `avro-binary-source-pipe` periodically creates a test data event as Json and applies the `avro/binary` data type using the schema in [User.avsc](User.avsc). -The binary Avro data is then sent to a Http webhook sink that references an Http endpoint that is provided by the 2nd binding `avro-to-log`. The `avro-to-log` binding provides the Http service and deserializes the binary Avro data using the same User schema. The deserialized data is printed to the log output. +The binary Avro data is then sent to a Http webhook sink that references a Http endpoint that is provided by the 2nd binding `avro-deserialize-pipe`. The `avro-deserialize-pipe` binding provides the Http service and deserializes the binary Avro data using the same User schema. The deserialized data is printed to the log output. The test starts both Pipes and is able to verify the proper log output as an expected outcome. @@ -18,8 +18,8 @@ The test performs the following high level steps: *Avro data type feature* - Create test data based on the User.avsc Avro schema -- Load and run the `avro-to-log` Pipe -- Load and run the `json-to-avro` Pipe +- Load and run the `avro-deserialize-pipe` Pipe +- Load and run the `avro-binary-source-pipe` Pipe - Verify that the bindings do interact with each other and the proper test data is logged in the binding output ## Installation @@ -36,7 +36,7 @@ You can review the installation steps for the tooling in the documentation: To run tests with URI based configuration: ```shell script -$ yaks run --local test/avro-serdes-action/avro-serdes-action.feature +$ yaks run --local test/avro/avro-serdes-action.feature ``` You will be provided with the test log output and the test results. diff --git a/tests/camel-kamelets-itest/src/test/resources/aws/s3/aws-s3-http-pipe.feature b/tests/camel-kamelets-itest/src/test/resources/aws/s3/aws-s3-http-pipe.feature index c938cb37..e0e12afd 100644 --- a/tests/camel-kamelets-itest/src/test/resources/aws/s3/aws-s3-http-pipe.feature +++ b/tests/camel-kamelets-itest/src/test/resources/aws/s3/aws-s3-http-pipe.feature @@ -4,6 +4,7 @@ Feature: AWS S3 Source - Http sink Given Kubernetes timeout is 60000 ms Given HTTP server timeout is 60000 ms Given HTTP server "test-service" + Given start HTTP server Given variables | aws.s3.bucketNameOrArn | mybucket | | aws.s3.message | Hello from S3 Kamelet | @@ -48,3 +49,4 @@ Feature: AWS S3 Source - Http sink Given delete Kubernetes service test-service # Stop LocalStack container Given stop LocalStack container + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature b/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature index 70350aea..18cadf3d 100644 --- a/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature +++ b/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature @@ -20,6 +20,7 @@ Feature: Earthquake source Background: Given HTTP server timeout is 150000 ms Given HTTP server "test-service" + Given start HTTP server Scenario: Create Http server Given create Kubernetes service test-service with target port 8080 @@ -39,3 +40,4 @@ Feature: Earthquake source Scenario: Remove Camel K resources Given delete Pipe earthquake-to-http And delete Kubernetes service test-service + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/kafka/kafka-source.feature b/tests/camel-kamelets-itest/src/test/resources/kafka/kafka-source.feature index 2c1cca68..aa40beed 100644 --- a/tests/camel-kamelets-itest/src/test/resources/kafka/kafka-source.feature +++ b/tests/camel-kamelets-itest/src/test/resources/kafka/kafka-source.feature @@ -62,3 +62,4 @@ Feature: Kafka Kamelet source Given delete Pipe kafka-source-pipe And delete Kubernetes service test-service And stop Redpanda container + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/mail/mail-sink.feature b/tests/camel-kamelets-itest/src/test/resources/mail/mail-sink.feature index 02a0dbff..5ef88fef 100644 --- a/tests/camel-kamelets-itest/src/test/resources/mail/mail-sink.feature +++ b/tests/camel-kamelets-itest/src/test/resources/mail/mail-sink.feature @@ -61,3 +61,4 @@ Feature: Mail Sink Scenario: Remove Camel K resources Given delete Pipe timer-to-mail And delete Kubernetes service mail-server + And stop server component mail-server diff --git a/tests/camel-kamelets-itest/src/test/resources/openapi/rest-openapi-sink.feature b/tests/camel-kamelets-itest/src/test/resources/openapi/rest-openapi-sink.feature index 64269d2f..f1bb9596 100644 --- a/tests/camel-kamelets-itest/src/test/resources/openapi/rest-openapi-sink.feature +++ b/tests/camel-kamelets-itest/src/test/resources/openapi/rest-openapi-sink.feature @@ -20,6 +20,7 @@ Feature: REST OpenAPI Kamelet sink Background: Given HTTP server timeout is 60000 ms Given HTTP server "test-service" + Given start HTTP server Given variable petId is "1000" Given load variable pet.json @@ -64,3 +65,4 @@ Feature: REST OpenAPI Kamelet sink Scenario: Remove resources Given delete Pipe rest-openapi-sink-pipe And delete Kubernetes service test-service + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/protobuf/README.md b/tests/camel-kamelets-itest/src/test/resources/protobuf/README.md new file mode 100644 index 00000000..852f5ad8 --- /dev/null +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/README.md @@ -0,0 +1,42 @@ +# Protobuf serialization/deserialization + +This test verifies the Protobuf serialization/deserialization actions + +## Objectives + +The test verifies the proper Protobuf serialization and deserialization of Protobuf. + +The test uses two Pipes that interact with each other. The first binding `protobuf-binary-source-pipe` periodically creates a test data event as Json and applies the `protobuf/binary` data type using the schema in [User.proto](User.proto). + +The binary Protobuf data is then sent to a Http webhook sink that references a Http endpoint that is provided by the 2nd binding `protobuf-deserialize-pipe`. The `protobuf-deserialize-pipe` binding provides the Http service and deserializes the binary Protobuf data using the same User schema. The deserialized data is printed to the log output. + +The test starts both Pipes and is able to verify the proper log output as an expected outcome. + +### YAKS Test + +The test performs the following high level steps: + +*Protobuf data type feature* +- Create test data based on the User.proto Protobuf schema +- Load and run the `protobuf-deserialize-pipe` Pipe +- Load and run the `protobuf-binary-source-pipe` Pipe +- Verify that the bindings do interact with each other and the proper test data is logged in the binding output + +## Installation + +The test assumes that you have [JBang](https://www.jbang.dev/) installed and the YAKS CLI setup locally. + +You can review the installation steps for the tooling in the documentation: + +- [JBang](https://www.jbang.dev/documentation/guide/latest/installation.html) +- [Install YAKS CLI](https://github.com/citrusframework/yaks#installation) + +## Run the tests with JBang + +To run tests with URI based configuration: + +```shell script +$ yaks run --local test/protobuf/protobuf-serdes-action.feature +``` + +You will be provided with the test log output and the test results. diff --git a/tests/camel-kamelets-itest/src/test/resources/protobuf/User.proto b/tests/camel-kamelets-itest/src/test/resources/protobuf/User.proto new file mode 100644 index 00000000..e520bfe9 --- /dev/null +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/User.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package demo.kamelets; + +message User { + optional string id = 1; + optional string firstname = 2; + optional string lastname = 3; + optional int32 age = 4; +} diff --git a/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-binary-source-pipe.yaml b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-binary-source-pipe.yaml new file mode 100644 index 00000000..36a3896e --- /dev/null +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-binary-source-pipe.yaml @@ -0,0 +1,63 @@ +# --------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --------------------------------------------------------------------------- + +apiVersion: camel.apache.org/v1 +kind: Pipe +metadata: + name: protobuf-binary-source-pipe +spec: + integration: + dependencies: + - "camel:jackson-protobuf" + source: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: timer-source + properties: + period: 10000 + contentType: application/json + message: > + ${user} + steps: + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: json-deserialize-action + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: resolve-pojo-schema-action + properties: + mimeType: "protobuf/binary" + schema: > + syntax = "proto3"; + package demo.kamelets; + message User { + optional string id=1; + optional string firstname=2; + optional string lastname=3; + optional int32 age=4; + } + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: data-type-action + properties: + format: "protobuf-binary" + sink: + uri: http://localhost:8080/user diff --git a/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-data-type.feature b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-data-type.feature new file mode 100644 index 00000000..b8f408bc --- /dev/null +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-data-type.feature @@ -0,0 +1,22 @@ +Feature: Protobuf data type + + Scenario: Create Kamelet Pipes + Given variable uuid is "citrus:randomUUID()" + Given variable user is + """ + { "id": "${uuid}", "firstname": "Sheldon", "lastname": "Cooper", "age": 28 } + """ + # Create protobuf-to-log binding + When load Pipe protobuf-x-struct-sink-pipe.yaml + Then Camel K integration protobuf-x-struct-sink-pipe should be running + + # Create json-to-protobuf binding + When load Pipe protobuf-binary-source-pipe.yaml + Then Camel K integration protobuf-binary-source-pipe should be running + + # Verify output message sent + Then Camel K integration protobuf-x-struct-sink-pipe should print Body: { "id" : "${uuid}", "firstname" : "Sheldon", "lastname" : "Cooper", "age" : 28} + + Scenario: Remove resources + Given delete Pipe protobuf-x-struct-sink-pipe + Given delete Pipe protobuf-binary-source-pipe diff --git a/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-deserialize-pipe.yaml similarity index 53% copy from tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature copy to tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-deserialize-pipe.yaml index 70350aea..436cbc8f 100644 --- a/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-deserialize-pipe.yaml @@ -15,27 +15,37 @@ # limitations under the License. # --------------------------------------------------------------------------- -Feature: Earthquake source - - Background: - Given HTTP server timeout is 150000 ms - Given HTTP server "test-service" - - Scenario: Create Http server - Given create Kubernetes service test-service with target port 8080 - Given purge endpoint test-service - - Scenario: Create Kamelet binding - Given load Pipe earthquake-to-http.yaml - Then Pipe earthquake-to-http should be available - Then Camel K integration earthquake-to-http should be running - And Camel K integration earthquake-to-http should print Routes startup - - Scenario: Verify binding - Given expect HTTP request header: Content-Type="application/json;charset=UTF-8" - When receive POST /test - Then send HTTP 200 OK - - Scenario: Remove Camel K resources - Given delete Pipe earthquake-to-http - And delete Kubernetes service test-service +apiVersion: camel.apache.org/v1 +kind: Pipe +metadata: + name: protobuf-deserialize-pipe +spec: + source: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: webhook-source + properties: + subpath: user + steps: + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: protobuf-deserialize-action + properties: + schema: > + syntax = "proto3"; + package demo.kamelets; + message User { + optional string id=1; + optional string firstname=2; + optional string lastname=3; + optional int32 age=4; + } + sink: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: log-action + properties: + showHeaders: true diff --git a/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-serdes-action.feature b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-serdes-action.feature new file mode 100644 index 00000000..594a84da --- /dev/null +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-serdes-action.feature @@ -0,0 +1,22 @@ +Feature: Protobuf serialize/deserialize action + + Scenario: Create Kamelet Pipes + Given variable uuid is "citrus:randomUUID()" + Given variable user is + """ + { "id": "${uuid}", "firstname": "Sheldon", "lastname": "Cooper", "age": 28 } + """ + # Create protobuf-to-log binding + When load Pipe protobuf-deserialize-pipe.yaml + Then Camel K integration protobuf-deserialize-pipe should be running + + # Create json-to-protobuf binding + When load Pipe protobuf-serialize-pipe.yaml + Then Camel K integration protobuf-serialize-pipe should be running + + # Verify output message sent + Then Camel K integration protobuf-deserialize-pipe should print Body: { "id" : "${uuid}", "firstname" : "Sheldon", "lastname" : "Cooper", "age" : 28} + + Scenario: Remove resources + Given delete Pipe protobuf-deserialize-pipe + Given delete Pipe protobuf-serialize-pipe diff --git a/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-serialize-pipe.yaml b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-serialize-pipe.yaml new file mode 100644 index 00000000..e59ac3c8 --- /dev/null +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-serialize-pipe.yaml @@ -0,0 +1,59 @@ +# --------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --------------------------------------------------------------------------- + +apiVersion: camel.apache.org/v1 +kind: Pipe +metadata: + name: protobuf-serialize-pipe +spec: + source: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: timer-source + properties: + period: 10000 + contentType: application/json + message: > + ${user} + steps: + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: json-deserialize-action + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: protobuf-serialize-action + properties: + schema: > + syntax = "proto3"; + package demo.kamelets; + message User { + optional string id=1; + optional string firstname=2; + optional string lastname=3; + optional int32 age=4; + } + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: log-action + properties: + showHeaders: true + sink: + uri: http://localhost:8080/user diff --git a/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-x-struct-sink-pipe.yaml b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-x-struct-sink-pipe.yaml new file mode 100644 index 00000000..5fb05bd9 --- /dev/null +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/protobuf-x-struct-sink-pipe.yaml @@ -0,0 +1,67 @@ +# --------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --------------------------------------------------------------------------- + +apiVersion: camel.apache.org/v1 +kind: Pipe +metadata: + name: protobuf-x-struct-sink-pipe +spec: + integration: + dependencies: + - "camel:jackson-protobuf" + source: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: webhook-source + properties: + subpath: user + steps: + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: data-type-action + properties: + format: "application-octet-stream" + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: resolve-pojo-schema-action + properties: + mimeType: "protobuf/binary" + schema: > + syntax = "proto3"; + package demo.kamelets; + message User { + optional string id=1; + optional string firstname=2; + optional string lastname=3; + optional int32 age=4; + } + - ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: data-type-action + properties: + format: "protobuf-x-struct" + sink: + ref: + kind: Kamelet + apiVersion: camel.apache.org/v1 + name: log-action + properties: + showHeaders: true diff --git a/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature b/tests/camel-kamelets-itest/src/test/resources/protobuf/yaks-config.yaml similarity index 53% copy from tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature copy to tests/camel-kamelets-itest/src/test/resources/protobuf/yaks-config.yaml index 70350aea..186bb32a 100644 --- a/tests/camel-kamelets-itest/src/test/resources/earthquake/earthquake-source.feature +++ b/tests/camel-kamelets-itest/src/test/resources/protobuf/yaks-config.yaml @@ -15,27 +15,31 @@ # limitations under the License. # --------------------------------------------------------------------------- -Feature: Earthquake source - - Background: - Given HTTP server timeout is 150000 ms - Given HTTP server "test-service" - - Scenario: Create Http server - Given create Kubernetes service test-service with target port 8080 - Given purge endpoint test-service - - Scenario: Create Kamelet binding - Given load Pipe earthquake-to-http.yaml - Then Pipe earthquake-to-http should be available - Then Camel K integration earthquake-to-http should be running - And Camel K integration earthquake-to-http should print Routes startup - - Scenario: Verify binding - Given expect HTTP request header: Content-Type="application/json;charset=UTF-8" - When receive POST /test - Then send HTTP 200 OK - - Scenario: Remove Camel K resources - Given delete Pipe earthquake-to-http - And delete Kubernetes service test-service +config: + namespace: + temporary: false + runtime: + env: + - name: YAKS_CAMELK_AUTO_REMOVE_RESOURCES + value: false + - name: YAKS_KUBERNETES_AUTO_REMOVE_RESOURCES + value: false + - name: YAKS_JBANG_CAMEL_DUMP_INTEGRATION_OUTPUT + value: true + settings: + loggers: + - name: INTEGRATION_STATUS + level: INFO + - name: INTEGRATION_LOGS + level: INFO + resources: + - protobuf-serialize-pipe.yaml + - protobuf-deserialize-pipe.yaml + - protobuf-binary-source-pipe.yaml + - protobuf-x-struct-sink-pipe.yaml + - User.proto + dump: + enabled: true + failedOnly: true + includes: + - app=camel-k diff --git a/tests/camel-kamelets-itest/src/test/resources/timer/timer-source.feature b/tests/camel-kamelets-itest/src/test/resources/timer/timer-source.feature index ae38394a..397e014b 100644 --- a/tests/camel-kamelets-itest/src/test/resources/timer/timer-source.feature +++ b/tests/camel-kamelets-itest/src/test/resources/timer/timer-source.feature @@ -20,6 +20,7 @@ Feature: Timer Source Kamelet Background: Given HTTP server timeout is 5000 ms Given HTTP server "test-service" + Given start HTTP server Scenario: Create Http server Given create Kubernetes service test-service with target port 8080 @@ -41,3 +42,4 @@ Feature: Timer Source Kamelet Scenario: Remove Camel K resources Given delete Pipe timer-to-http-pipe And delete Kubernetes service test-service + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/timer/timer-to-http.feature b/tests/camel-kamelets-itest/src/test/resources/timer/timer-to-http.feature index ccfeb09a..ffb1b745 100644 --- a/tests/camel-kamelets-itest/src/test/resources/timer/timer-to-http.feature +++ b/tests/camel-kamelets-itest/src/test/resources/timer/timer-to-http.feature @@ -4,6 +4,7 @@ Feature: Verify Camel K integrations Given HTTP server "test-service" Given HTTP server listening on port 8080 Given HTTP request timeout is 6000 ms + Given start HTTP server Given Kubernetes timeout is 60000 ms Scenario: Verify timer-to-http integration @@ -28,3 +29,4 @@ Feature: Verify Camel K integrations Scenario: Remove Camel K resources Given delete Camel K integration timer-to-http And delete Kubernetes service test-service + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/transformation/data-type-action.feature b/tests/camel-kamelets-itest/src/test/resources/transformation/data-type-action.feature index 2bc1f8c7..038afcb0 100644 --- a/tests/camel-kamelets-itest/src/test/resources/transformation/data-type-action.feature +++ b/tests/camel-kamelets-itest/src/test/resources/transformation/data-type-action.feature @@ -3,6 +3,7 @@ Feature: Data type action Background: Given HTTP server timeout is 15000 ms Given HTTP server "test-service" + Given start HTTP server Scenario: Create Http server Given create Kubernetes service test-service with target port 8080 @@ -32,3 +33,4 @@ Feature: Data type action Scenario: Remove resources Given delete Pipe data-type-action-pipe And delete Kubernetes service test-service + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/transformation/extract-field-action.feature b/tests/camel-kamelets-itest/src/test/resources/transformation/extract-field-action.feature index 34b5585f..731f3e68 100644 --- a/tests/camel-kamelets-itest/src/test/resources/transformation/extract-field-action.feature +++ b/tests/camel-kamelets-itest/src/test/resources/transformation/extract-field-action.feature @@ -20,6 +20,7 @@ Feature: Extract field Kamelet action Background: Given HTTP server timeout is 15000 ms Given HTTP server "test-service" + Given start HTTP server Given variable field = "subject" Scenario: Create Http server @@ -43,3 +44,4 @@ Feature: Extract field Kamelet action Scenario: Remove resources Given delete Pipe extract-field-action-pipe And delete Kubernetes service test-service + And stop HTTP server diff --git a/tests/camel-kamelets-itest/src/test/resources/transformation/insert-field-action.feature b/tests/camel-kamelets-itest/src/test/resources/transformation/insert-field-action.feature index a9412cb0..7a0ce64b 100644 --- a/tests/camel-kamelets-itest/src/test/resources/transformation/insert-field-action.feature +++ b/tests/camel-kamelets-itest/src/test/resources/transformation/insert-field-action.feature @@ -20,6 +20,7 @@ Feature: Insert field Kamelet action Background: Given HTTP server timeout is 5000 ms Given HTTP server "test-service" + Given start HTTP server Given variables | field | subject | | value | Camel K rocks! | @@ -49,3 +50,4 @@ Feature: Insert field Kamelet action Scenario: Remove resources Given delete Pipe insert-field-action-pipe And delete Kubernetes service test-service + And stop HTTP server