diff --git a/.github/workflows/branch.yaml b/.github/workflows/branch.yaml index 4c5f60743..06c75437b 100644 --- a/.github/workflows/branch.yaml +++ b/.github/workflows/branch.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ 8, 11 ] + java: [ 8, 11, 17 ] steps: - uses: actions/checkout@v2 - name: Setup java @@ -20,8 +20,9 @@ jobs: with: java-version: ${{ matrix.java }} - run: | - mvn clean install -DskipTests -B - mvn verify -B + ./mvnw clean install -DskipTests -B + ./mvnw verify -B + deploy: runs-on: ubuntu-latest name: Deploy @@ -38,7 +39,7 @@ jobs: gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase - name: Publish to Apache Maven Central - run: mvn clean deploy -Drelease -DskipTests -B + run: ./mvnw clean deploy -Drelease -DskipTests -B env: MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} diff --git a/.github/workflows/bump.yaml b/.github/workflows/bump.yaml index 3636cb5b2..86ca4215b 100644 --- a/.github/workflows/bump.yaml +++ b/.github/workflows/bump.yaml @@ -19,7 +19,7 @@ jobs: with: java-version: 8 - name: Bump version using Maven - run: 'mvn versions:set -DnewVersion=$NEW_VERSION -DgenerateBackupPoms=false -B' + run: './mvnw versions:set -DnewVersion=$NEW_VERSION -DgenerateBackupPoms=false -B' - name: Bump version in docs if: ${{ !endsWith(github.event.inputs.version, 'SNAPSHOT') }} run: 'find . -type f -name "*.md" -exec sed -i -e "s+[a-zA-Z0-9.-]*<\/version>+$NEW_VERSION+g" {} +' diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 57780b56f..2f808c92b 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -22,5 +22,6 @@ jobs: java-version: ${{ matrix.java }} distribution: 'temurin' - run: | - mvn clean install -DskipTests -B - mvn verify -B + ./mvnw clean install -DskipTests -B + ./mvnw verify -B + ./mvnw javadoc:javadoc diff --git a/amqp/pom.xml b/amqp/pom.xml index cff9ac2d9..ce8248b51 100644 --- a/amqp/pom.xml +++ b/amqp/pom.xml @@ -6,7 +6,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT cloudevents-amqp-proton diff --git a/api/pom.xml b/api/pom.xml index 885668ba0..0c54d7b32 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -24,7 +24,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT cloudevents-api diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 5439585d5..4661dcfd3 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -21,7 +21,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT cloudevents-benchmarks diff --git a/bom/pom.xml b/bom/pom.xml index c7b6eaaff..fb7326dcf 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT cloudevents-bom diff --git a/core/pom.xml b/core/pom.xml index e037daa15..35f9c2643 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT cloudevents-core diff --git a/docs/amqp-proton.md b/docs/amqp-proton.md index f6a456c04..c2bc150cc 100644 --- a/docs/amqp-proton.md +++ b/docs/amqp-proton.md @@ -18,7 +18,7 @@ binding for CloudEvents: io.cloudevents cloudevents-amqp-proton - 2.3.0 + 2.4.2 ``` diff --git a/docs/api.md b/docs/api.md index 1de08596f..66dbf2ba7 100644 --- a/docs/api.md +++ b/docs/api.md @@ -17,7 +17,7 @@ For Maven based projects, use the following dependency: io.cloudevents cloudevents-api - 2.3.0 + 2.4.2 ``` diff --git a/docs/core.md b/docs/core.md index fcafac13d..36be5efb8 100644 --- a/docs/core.md +++ b/docs/core.md @@ -16,7 +16,7 @@ For Maven based projects, use the following dependency: io.cloudevents cloudevents-core - 2.3.0 + 2.4.2 ``` diff --git a/docs/http-basic.md b/docs/http-basic.md index f2cb67aa2..2b58934a6 100644 --- a/docs/http-basic.md +++ b/docs/http-basic.md @@ -27,7 +27,7 @@ HTTP Transport: io.cloudevents cloudevents-http-basic - 2.3.0 + 2.4.2 ``` diff --git a/docs/http-jakarta-restful-ws.md b/docs/http-jakarta-restful-ws.md index a7f08fefb..1fa123e3a 100644 --- a/docs/http-jakarta-restful-ws.md +++ b/docs/http-jakarta-restful-ws.md @@ -14,7 +14,7 @@ RESTful Web Services Binding: io.cloudevents cloudevents-http-restful-ws - 2.3.0 + 2.4.2 ``` diff --git a/docs/http-vertx.md b/docs/http-vertx.md index bdecc9a79..494b88840 100644 --- a/docs/http-vertx.md +++ b/docs/http-vertx.md @@ -14,7 +14,7 @@ HTTP Transport: io.cloudevents cloudevents-http-vertx - 2.3.0 + 2.4.2 ``` diff --git a/docs/json-jackson.md b/docs/json-jackson.md index 6bb2a7c6a..1aac7c33a 100644 --- a/docs/json-jackson.md +++ b/docs/json-jackson.md @@ -17,7 +17,7 @@ For Maven based projects, use the following dependency: io.cloudevents cloudevents-json-jackson - 2.3.0 + 2.4.2 ``` diff --git a/docs/kafka.md b/docs/kafka.md index bcdeb80ae..48fe54d8c 100644 --- a/docs/kafka.md +++ b/docs/kafka.md @@ -17,7 +17,7 @@ For Maven based projects, use the following to configure the io.cloudevents cloudevents-kafka - 2.3.0 + 2.4.2 ``` diff --git a/docs/protobuf.md b/docs/protobuf.md index 64d7c4318..902c68a93 100644 --- a/docs/protobuf.md +++ b/docs/protobuf.md @@ -17,7 +17,7 @@ For Maven based projects, use the following dependency: io.cloudevents cloudevents-protobuf - 2.3.0 + 2.4.2 ``` diff --git a/docs/spring.md b/docs/spring.md index b9dab8ed4..89381b607 100644 --- a/docs/spring.md +++ b/docs/spring.md @@ -17,7 +17,7 @@ For Maven based projects, use the following dependency: io.cloudevents cloudevents-spring - 2.3.0 + 2.4.2 ``` diff --git a/examples/amqp-proton/pom.xml b/examples/amqp-proton/pom.xml index 5b888ae31..0a0177f6f 100644 --- a/examples/amqp-proton/pom.xml +++ b/examples/amqp-proton/pom.xml @@ -3,7 +3,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/basic-http/pom.xml b/examples/basic-http/pom.xml index 27b162cda..7fbb38045 100644 --- a/examples/basic-http/pom.xml +++ b/examples/basic-http/pom.xml @@ -21,7 +21,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/kafka/pom.xml b/examples/kafka/pom.xml index f20ca8320..4098bfeae 100644 --- a/examples/kafka/pom.xml +++ b/examples/kafka/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/pom.xml b/examples/pom.xml index 9a7ee82be..3534c038a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ cloudevents-parent io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/restful-ws-quarkus/pom.xml b/examples/restful-ws-quarkus/pom.xml index c5c2e691c..d9f77ab3f 100644 --- a/examples/restful-ws-quarkus/pom.xml +++ b/examples/restful-ws-quarkus/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 cloudevents-restful-ws-quarkus-example diff --git a/examples/restful-ws-spring-boot/pom.xml b/examples/restful-ws-spring-boot/pom.xml index 9b5a25bd8..b26966e35 100644 --- a/examples/restful-ws-spring-boot/pom.xml +++ b/examples/restful-ws-spring-boot/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/spring-function/pom.xml b/examples/spring-function/pom.xml index bd9c0ecb8..3608ca042 100644 --- a/examples/spring-function/pom.xml +++ b/examples/spring-function/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/spring-reactive/pom.xml b/examples/spring-reactive/pom.xml index 06313d9ea..5da76d433 100644 --- a/examples/spring-reactive/pom.xml +++ b/examples/spring-reactive/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/spring-rsocket/pom.xml b/examples/spring-rsocket/pom.xml index 348b4ab64..1660bfa39 100644 --- a/examples/spring-rsocket/pom.xml +++ b/examples/spring-rsocket/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/examples/vertx/pom.xml b/examples/vertx/pom.xml index 31d56c4a5..132b2fa28 100644 --- a/examples/vertx/pom.xml +++ b/examples/vertx/pom.xml @@ -5,7 +5,7 @@ cloudevents-examples io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0 diff --git a/formats/json-jackson/pom.xml b/formats/json-jackson/pom.xml index a1a8146e1..9262d30ca 100644 --- a/formats/json-jackson/pom.xml +++ b/formats/json-jackson/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../../pom.xml diff --git a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java index 8454a5a22..542405894 100644 --- a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java +++ b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java @@ -47,7 +47,7 @@ public final class JsonFormat implements EventFormat { /** * JSON Data Content Type Discriminator */ - private static final Pattern JSON_CONTENT_TYPE_PATTERN = Pattern.compile("^(application|text)\\/([a-zA-Z]+\\+)?json$"); + private static final Pattern JSON_CONTENT_TYPE_PATTERN = Pattern.compile("^(application|text)\\/([a-zA-Z]+\\+)?json(;.*)*$"); private final ObjectMapper mapper; private final JsonFormatOptions options; diff --git a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java index 7e40fe98e..253e2fc89 100644 --- a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java +++ b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java @@ -47,6 +47,22 @@ class JsonFormatTest { private final ObjectMapper mapper = new ObjectMapper(); + @ParameterizedTest + @MethodSource("jsonContentTypes") + void isJsonContentType(String contentType) { + boolean json = JsonFormat.dataIsJsonContentType(contentType); + + assertThat(json).isTrue(); + } + + @ParameterizedTest + @MethodSource("wrongJsonContentTypes") + void isNotJsonContentType(String contentType) { + boolean json = JsonFormat.dataIsJsonContentType(contentType); + + assertThat(json).isFalse(); + } + @ParameterizedTest @MethodSource("serializeTestArgumentsDefault") void serialize(CloudEvent input, String outputFile) throws IOException { @@ -151,6 +167,39 @@ void verifyDeserializeError(String inputFile){ } + static Stream jsonContentTypes() { + return Stream.of( + Arguments.of("application/json"), + Arguments.of("application/json;charset=utf-8"), + Arguments.of("application/json;\tcharset = \"utf-8\""), + Arguments.of("application/cloudevents+json;charset=UTF-8"), + Arguments.of("text/json"), + Arguments.of("text/json;charset=utf-8"), + Arguments.of("text/cloudevents+json;charset=UTF-8"), + Arguments.of("text/json;\twhatever"), + Arguments.of("text/json; boundary=something"), + Arguments.of("text/json;foo=\"bar\""), + Arguments.of("text/json; charset = \"us-ascii\""), + Arguments.of("text/json; \t"), + Arguments.of("text/json;"), + //https://www.rfc-editor.org/rfc/rfc2045#section-5.1 + // any us-ascii char can be part of parameters (except CTRLs and tspecials) + Arguments.of("text/json; char-set = $!#$%&'*+.^_`|"), + Arguments.of((Object) null) + ); + } + + static Stream wrongJsonContentTypes() { + return Stream.of( + Arguments.of("applications/json"), + Arguments.of("application/jsom"), + Arguments.of("application/jsonwrong"), + Arguments.of("text/json "), + Arguments.of("text/json ;"), + Arguments.of("test/json") + ); + } + public static Stream serializeTestArgumentsDefault() { return Stream.of( Arguments.of(V03_MIN, "v03/min.json"), diff --git a/formats/protobuf/pom.xml b/formats/protobuf/pom.xml index 0a8a2f7f8..a7b223087 100644 --- a/formats/protobuf/pom.xml +++ b/formats/protobuf/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../../pom.xml diff --git a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDataWrapper.java b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDataWrapper.java index f4b87f5ea..3316787fc 100644 --- a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDataWrapper.java +++ b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDataWrapper.java @@ -16,8 +16,11 @@ */ package io.cloudevents.protobuf; +import com.google.protobuf.Any; import com.google.protobuf.Message; +import java.util.Arrays; + class ProtoDataWrapper implements ProtoCloudEventData { private final Message protoMessage; @@ -35,4 +38,49 @@ public Message getMessage() { public byte[] toBytes() { return protoMessage.toByteArray(); } + + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return (true); + } + + if (!(obj instanceof ProtoDataWrapper)) { + return (false); + } + + // Now compare the actual data + ProtoDataWrapper rhs = (ProtoDataWrapper) obj; + + if (this.getMessage() == rhs.getMessage()){ + return true; + } + + // This is split out for readability. + // Compare the content in terms onf an 'Any'. + // - Verify the types match + // - Verify the values match. + + final Any lhsAny = getAsAny(this.getMessage()); + final Any rhsAny = getAsAny(rhs.getMessage()); + + final boolean typesMatch = (ProtoSupport.extractMessageType(lhsAny).equals(ProtoSupport.extractMessageType(rhsAny))); + + if (typesMatch) { + return lhsAny.getValue().equals(rhsAny.getValue()); + } else { + return false; + } + } + + private Any getAsAny(Message m) { + + if (m instanceof Any) { + return (Any) m; + } + + return Any.pack(m); + + } } diff --git a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDeserializer.java b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDeserializer.java index dd55973d5..dc1f54c27 100644 --- a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDeserializer.java +++ b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoDeserializer.java @@ -105,7 +105,7 @@ public , R> R read( data = BytesCloudEventData.wrap(raw); break; case PROTO_DATA: - data = new ProtoAccessor(this.protoCe); + data = new ProtoDataWrapper(this.protoCe.getProtoData()); break; case DATA_NOT_SET: break; @@ -130,22 +130,4 @@ private OffsetDateTime covertProtoTimestamp(com.google.protobuf.Timestamp timest return instant.atOffset(ZoneOffset.UTC); } - private static class ProtoAccessor implements ProtoCloudEventData { - - private final Message message; - - ProtoAccessor(CloudEvent proto){ - this.message = proto.getProtoData(); - } - - @Override - public Message getMessage() { - return message; - } - - @Override - public byte[] toBytes() { - return message.toByteArray(); - } - } } diff --git a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSerializer.java b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSerializer.java index bc240d84d..2f76d81b8 100644 --- a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSerializer.java +++ b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSerializer.java @@ -16,11 +16,8 @@ */ package io.cloudevents.protobuf; -import com.google.protobuf.Any; -import com.google.protobuf.ByteString; +import com.google.protobuf.*; import com.google.protobuf.Descriptors.FieldDescriptor; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Timestamp; import io.cloudevents.CloudEventData; import io.cloudevents.SpecVersion; import io.cloudevents.core.CloudEventUtils; @@ -248,8 +245,14 @@ public CloudEvent end(CloudEventData data) throws CloudEventRWException { // If it's a proto message we can handle that directly. if (data instanceof ProtoCloudEventData) { final ProtoCloudEventData protoData = (ProtoCloudEventData) data; - if (protoData.getMessage() != null) { - protoBuilder.setProtoData(Any.pack(protoData.getMessage())); + final Message m = protoData.getMessage(); + if (m != null) { + // If it's already an 'Any' don't re-pack it. + if (m instanceof Any) { + protoBuilder.setProtoData((Any) m); + }else { + protoBuilder.setProtoData(Any.pack(m)); + } } } else { if (Objects.equals(dataContentType, PROTO_DATA_CONTENT_TYPE)) { diff --git a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSupport.java b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSupport.java index a2c079359..a4cf0ec1d 100644 --- a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSupport.java +++ b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtoSupport.java @@ -17,6 +17,8 @@ package io.cloudevents.protobuf; +import com.google.protobuf.Any; + /** * General support functions. */ @@ -44,4 +46,16 @@ static boolean isTextContent(String contentType) { || contentType.endsWith("+xml") ; } + + /** + * Extract the Protobuf message type from an 'Any' + * @param anyMessage + * @return + */ + static String extractMessageType(final Any anyMessage) { + final String typeUrl = anyMessage.getTypeUrl(); + final String[] parts = typeUrl.split("/"); + + return parts[parts.length -1]; + } } diff --git a/formats/protobuf/src/test/java/io/cloudevents/protobuf/ProtoDataWrapperTest.java b/formats/protobuf/src/test/java/io/cloudevents/protobuf/ProtoDataWrapperTest.java new file mode 100644 index 000000000..232af3209 --- /dev/null +++ b/formats/protobuf/src/test/java/io/cloudevents/protobuf/ProtoDataWrapperTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018-Present The CloudEvents Authors + *

+ * Licensed 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 io.cloudevents.protobuf; + +import com.google.protobuf.Any; +import com.google.protobuf.Message; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class ProtoDataWrapperTest { + + // == Closing Quotes for 2023/02/23 + private final Message quote1 = io.cloudevents.test.v1.proto.Test.Quote.newBuilder() + .setPrice(io.cloudevents.test.v1.proto.Test.Decimal.newBuilder().setScale(2).setUnscaled(7519).build()) + .setHigh(io.cloudevents.test.v1.proto.Test.Decimal.newBuilder().setScale(2).setUnscaled(7628).build()) + .setSymbol("PYPL") + .build(); + + private final Message quote2 = io.cloudevents.test.v1.proto.Test.Quote.newBuilder() + .setPrice(io.cloudevents.test.v1.proto.Test.Decimal.newBuilder().setScale(2).setUnscaled(13097).build()) + .setHigh(io.cloudevents.test.v1.proto.Test.Decimal.newBuilder().setScale(2).setUnscaled(13170).build()) + .setSymbol("IBM") + .build(); + + @Test + public void testBasic() { + + ProtoDataWrapper pdw = new ProtoDataWrapper(quote1); + + assertThat(pdw).isNotNull(); + assertThat(pdw.getMessage()).isNotNull(); + assertThat(pdw.toBytes()).withFailMessage("toBytes was NULL").isNotNull(); + assertThat(pdw.toBytes()).withFailMessage("toBytes[] returned empty array").hasSizeGreaterThan(0); + + // This is current behavior and will probably change in the next version. + assertThat(pdw.getMessage()).isInstanceOf(io.cloudevents.test.v1.proto.Test.Quote.class); + } + + @Test + public void testEquality() { + + ProtoDataWrapper pdw1 = new ProtoDataWrapper(quote1); + ProtoDataWrapper pdw2 = new ProtoDataWrapper(quote1); + + ProtoDataWrapper pdw3 = new ProtoDataWrapper(quote2); + + assertThat(pdw1).withFailMessage("Self Equality Failed - 1").isEqualTo(pdw1); + assertThat(pdw2).withFailMessage("Self Equality Failed - 2").isEqualTo(pdw2); + assertThat(pdw1).withFailMessage("Self Equality Failed - 3").isEqualTo(pdw2); + assertThat(pdw2).withFailMessage("Self Equality Failed - 4").isEqualTo(pdw1); + + assertThat(pdw1).withFailMessage("Non-Equality Failed - 1").isNotEqualTo(null); + assertThat(pdw1).withFailMessage("Non-Equality Failed - 2").isNotEqualTo(pdw3); + assertThat(pdw3).withFailMessage("Non-Equality Failed - 3").isNotEqualTo(pdw2); + + } + + /** + * Verify the generated bytes[] is correct + */ + @Test + public void testBytes() { + + // Our expected 'Any' + final Any expAny = Any.pack(quote1); + + // Our expected 'data' + final byte[] expData = expAny.toByteArray(); + + // Build the wrapper + final ProtoDataWrapper pdw = new ProtoDataWrapper(quote1); + + // Get the actual data + final byte[] actData = pdw.toBytes(); + + // Verify + Arrays.equals(expData, actData); + + } + +} diff --git a/formats/protobuf/src/test/java/io/cloudevents/protobuf/ProtobufFormatTest.java b/formats/protobuf/src/test/java/io/cloudevents/protobuf/ProtobufFormatTest.java index 539811e51..c611ce2bb 100644 --- a/formats/protobuf/src/test/java/io/cloudevents/protobuf/ProtobufFormatTest.java +++ b/formats/protobuf/src/test/java/io/cloudevents/protobuf/ProtobufFormatTest.java @@ -22,19 +22,20 @@ import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.v1.proto.CloudEvent; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.net.URI; +import java.net.URL; import java.time.OffsetDateTime; import java.time.ZoneId; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.net.URL; +import java.util.UUID; import java.util.stream.Stream; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; @@ -45,6 +46,46 @@ class ProtobufFormatTest { EventFormat format = new ProtobufFormat(); + public static Stream serializeTestArgumentsDefault() { + return Stream.of( + Arguments.of(V1_MIN, "v1/min.proto.json"), + Arguments.of(V1_WITH_JSON_DATA, "v1/json_data.proto.json"), + Arguments.of(V1_WITH_TEXT_DATA, "v1/text_data.proto.json"), + Arguments.of(V1_WITH_JSON_DATA_WITH_EXT, "v1/json_data_with_ext.proto.json"), + Arguments.of(V1_WITH_XML_DATA, "v1/xml_data.proto.json"), + Arguments.of(V1_WITH_BINARY_EXT, "v1/binary_ext.proto.json"), + + Arguments.of(V03_MIN, "v03/min.proto.json") + + ); + } + + public static Stream roundTripTestArguments() { + return Stream.of( + "v1/min.proto.json", + "v1/json_data.proto.json", + "v1/text_data.proto.json", + "v1/json_data_with_ext.proto.json", + "v1/xml_data.proto.json", + "v1/binary_ext.proto.json", + + "v03/min.proto.json" + ); + } + + private static Message loadProto(String filename) throws IOException { + CloudEvent.Builder b = CloudEvent.newBuilder(); + JsonFormat.parser().ignoringUnknownFields().merge(getReader(filename), b); + return b.build(); + } + + private static Reader getReader(String filename) throws IOException { + URL file = Thread.currentThread().getContextClassLoader().getResource(filename); + assertThat(file).isNotNull(); + File dataFile = new File(file.getFile()); + return new FileReader(dataFile); + } + @Test public void testRegistration() { EventFormat act = EventFormatProvider.getInstance().resolveFormat("application/cloudevents+protobuf"); @@ -90,6 +131,8 @@ public void serialize(io.cloudevents.CloudEvent input, String jsonFile) throws I } + // ---------------------------------------------------------------- + /** * RoundTrip Test *

@@ -131,46 +174,40 @@ public void roundTripTest(String filename) throws IOException { } - public static Stream serializeTestArgumentsDefault() { - return Stream.of( - Arguments.of(V1_MIN, "v1/min.proto.json"), - Arguments.of(V1_WITH_JSON_DATA, "v1/json_data.proto.json"), - Arguments.of(V1_WITH_TEXT_DATA, "v1/text_data.proto.json"), - Arguments.of(V1_WITH_JSON_DATA_WITH_EXT, "v1/json_data_with_ext.proto.json"), - Arguments.of(V1_WITH_XML_DATA, "v1/xml_data.proto.json"), - Arguments.of(V1_WITH_BINARY_EXT, "v1/binary_ext.proto.json"), - - Arguments.of(V03_MIN, "v03/min.proto.json") - - ); - } - - public static Stream roundTripTestArguments() { - return Stream.of( - "v1/min.proto.json", - "v1/json_data.proto.json", - "v1/text_data.proto.json", - "v1/json_data_with_ext.proto.json", - "v1/xml_data.proto.json", - "v1/binary_ext.proto.json", + /** + * This test verifies the fix for Issue #523 that reported the Data + * portion was being corrupted during multi-step round trips if the + * data was a Protobuf Message. + */ + @Test + public void verifyMultiRoundTrip() { + + io.cloudevents.CloudEvent event = CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(SOURCE) + .withType(TYPE) + .withData(ProtoCloudEventData.wrap(io.cloudevents.test.v1.proto.Test.Quote.newBuilder() + .setHigh(io.cloudevents.test.v1.proto.Test.Decimal.newBuilder().setScale(2).setUnscaled(4200).build()) + .setPrice(io.cloudevents.test.v1.proto.Test.Decimal.newBuilder().setScale(2).setUnscaled(1000).build()) + .setSymbol("PYPL") + .build())) + .build(); - "v03/min.proto.json" - ); - } + // 1st Round Trip + byte[] raw1 = format.serialize(event); + io.cloudevents.CloudEvent act1 = format.deserialize(raw1); + assertThat(event).withFailMessage("Mismatch on 1st round trip").isEqualTo(act1); - // ---------------------------------------------------------------- + // 2nd Round Trip + byte[] raw2 = format.serialize(act1); + io.cloudevents.CloudEvent act2 = format.deserialize(raw2); + assertThat(event).withFailMessage("Mismatch on 2nd round trip").isEqualTo(act2); - private static Message loadProto(String filename) throws IOException { - CloudEvent.Builder b = CloudEvent.newBuilder(); - JsonFormat.parser().ignoringUnknownFields().merge(getReader(filename), b); - return b.build(); - } + // 3rd Time's a charm + byte[] raw3 = format.serialize(act2); + io.cloudevents.CloudEvent act3 = format.deserialize(raw3); + assertThat(event).withFailMessage("Mismatch on 3rd round trip").isEqualTo(act3); - private static Reader getReader(String filename) throws IOException { - URL file = Thread.currentThread().getContextClassLoader().getResource(filename); - assertThat(file).isNotNull(); - File dataFile = new File(file.getFile()); - return new FileReader(dataFile); } private byte[] getProtoData(String filename) throws IOException { diff --git a/http/basic/pom.xml b/http/basic/pom.xml index 63cd764a9..975bc0da1 100644 --- a/http/basic/pom.xml +++ b/http/basic/pom.xml @@ -21,7 +21,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../../pom.xml diff --git a/http/restful-ws-integration-tests/pom.xml b/http/restful-ws-integration-tests/pom.xml index 8018ba56e..ce0ecba1f 100644 --- a/http/restful-ws-integration-tests/pom.xml +++ b/http/restful-ws-integration-tests/pom.xml @@ -22,7 +22,7 @@ cloudevents-parent io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/http/restful-ws-integration-tests/restful-ws-common/pom.xml b/http/restful-ws-integration-tests/restful-ws-common/pom.xml index 63a17aae0..8329eb7e0 100644 --- a/http/restful-ws-integration-tests/restful-ws-common/pom.xml +++ b/http/restful-ws-integration-tests/restful-ws-common/pom.xml @@ -22,7 +22,7 @@ cloudevents-http-restful-ws-integration-tests io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../ 4.0.0 diff --git a/http/restful-ws-integration-tests/restful-ws-jersey/pom.xml b/http/restful-ws-integration-tests/restful-ws-jersey/pom.xml index cb5f2b84e..76cb0cfb4 100644 --- a/http/restful-ws-integration-tests/restful-ws-jersey/pom.xml +++ b/http/restful-ws-integration-tests/restful-ws-jersey/pom.xml @@ -22,7 +22,7 @@ cloudevents-http-restful-ws-integration-tests io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../ 4.0.0 diff --git a/http/restful-ws-integration-tests/restful-ws-resteasy/pom.xml b/http/restful-ws-integration-tests/restful-ws-resteasy/pom.xml index f778f7fa2..e7dabc1d0 100644 --- a/http/restful-ws-integration-tests/restful-ws-resteasy/pom.xml +++ b/http/restful-ws-integration-tests/restful-ws-resteasy/pom.xml @@ -22,7 +22,7 @@ cloudevents-http-restful-ws-integration-tests io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../ 4.0.0 diff --git a/http/restful-ws-integration-tests/restful-ws-spring/pom.xml b/http/restful-ws-integration-tests/restful-ws-spring/pom.xml index c9e329775..10686acff 100644 --- a/http/restful-ws-integration-tests/restful-ws-spring/pom.xml +++ b/http/restful-ws-integration-tests/restful-ws-spring/pom.xml @@ -22,7 +22,7 @@ cloudevents-http-restful-ws-integration-tests io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../ 4.0.0 diff --git a/http/restful-ws/pom.xml b/http/restful-ws/pom.xml index ce58fe5dc..ad960cf87 100644 --- a/http/restful-ws/pom.xml +++ b/http/restful-ws/pom.xml @@ -21,7 +21,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../../pom.xml diff --git a/http/vertx/pom.xml b/http/vertx/pom.xml index be808981a..246d2ac4d 100644 --- a/http/vertx/pom.xml +++ b/http/vertx/pom.xml @@ -22,7 +22,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT ../../pom.xml diff --git a/kafka/pom.xml b/kafka/pom.xml index a7caae6e5..cc17f7641 100644 --- a/kafka/pom.xml +++ b/kafka/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT cloudevents-kafka diff --git a/pom.xml b/pom.xml index f63d8a47a..32e3f3cdf 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT pom CloudEvents @@ -168,6 +168,7 @@ https://qpid.apache.org/releases/qpid-proton-j-0.33.7/api/ https://fasterxml.github.io/jackson-databind/javadoc/2.10/ + 8 diff --git a/spring/pom.xml b/spring/pom.xml index 945554a87..ec31b0c63 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -23,7 +23,7 @@ io.cloudevents cloudevents-parent - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT cloudevents-spring diff --git a/sql/pom.xml b/sql/pom.xml index 746f8a569..92c153cd5 100644 --- a/sql/pom.xml +++ b/sql/pom.xml @@ -5,7 +5,7 @@ cloudevents-parent io.cloudevents - 2.4.0-SNAPSHOT + 2.4.3-SNAPSHOT 4.0.0