From 148f7b69a500601a6707fd87ce1b10e0c0e5c3bb Mon Sep 17 00:00:00 2001 From: "nikita.smirnov" Date: Wed, 12 Jun 2024 11:40:58 +0400 Subject: [PATCH 1/4] Provided ability to set either of raw body of several dody data to `Event` builder --- README.md | 7 ++- build.gradle | 4 +- gradle.properties | 2 +- .../com/exactpro/th2/common/event/Event.java | 55 +++++++++++++++++-- .../exactpro/th2/common/event/TestEvent.kt | 49 ++++++++++++++++- 5 files changed, 108 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c3b35bfb..872070a7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# th2 common library (Java) (5.13.0) +# th2 common library (Java) (5.13.1) ## Usage @@ -511,6 +511,11 @@ dependencies { ## Release notes +### 5.13.1-dev + ++ Provided ability to set either of raw body of several dody data to `Event` builder ++ Updated th2 gradle plugin `0.0.8` + ### 5.13.0-dev + Added functionality for publisher confirmations to mitigate network issues for message producers. diff --git a/build.gradle b/build.gradle index fce8d0e0..0a756250 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id "com.exactpro.th2.gradle.base" version "0.0.6" - id "com.exactpro.th2.gradle.publish" version "0.0.6" + id "com.exactpro.th2.gradle.base" version "0.0.8" + id "com.exactpro.th2.gradle.publish" version "0.0.8" id "org.jetbrains.kotlin.jvm" version "$kotlin_version" id 'org.jetbrains.kotlin.kapt' version "$kotlin_version" id "java-library" diff --git a/gradle.properties b/gradle.properties index bc2d53f5..2c553bc7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -release_version=5.13.0 +release_version=5.13.1 kotlin_version=1.8.22 description='th2 common library (Java)' vcs_url=https://github.com/th2-net/th2-common-j diff --git a/src/main/java/com/exactpro/th2/common/event/Event.java b/src/main/java/com/exactpro/th2/common/event/Event.java index dfa7f930..40fb2e1b 100644 --- a/src/main/java/com/exactpro/th2/common/event/Event.java +++ b/src/main/java/com/exactpro/th2/common/event/Event.java @@ -27,12 +27,14 @@ import com.fasterxml.jackson.module.kotlin.KotlinFeature; import com.fasterxml.jackson.module.kotlin.KotlinModule; import com.google.protobuf.ByteString; +import com.google.protobuf.UnsafeByteOperations; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.ArrayList; import java.util.Collection; @@ -58,6 +60,7 @@ import static org.apache.commons.lang3.StringUtils.defaultIfBlank; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.truncate; //TODO: move to common-utils-j @SuppressWarnings("unused") @@ -80,6 +83,7 @@ public class Event { protected final List subEvents = new ArrayList<>(); protected final List attachedMessageIds = new ArrayList<>(); protected final List body = new ArrayList<>(); + protected byte[] rawBody; protected final Instant startTimestamp; protected Instant endTimestamp; protected String type; @@ -151,13 +155,16 @@ public Event name(String eventName) { * This property value will be appended to the end of event name and added into event body in the {@link #toProto(com.exactpro.th2.common.grpc.EventID)} and {@link #toListProto(com.exactpro.th2.common.grpc.EventID)} methods if this property isn't set * * @return current event - * @throws IllegalStateException if description already set + * @throws IllegalStateException if description already set or raw body is already set */ public Event description(String description) { if (isNotBlank(description)) { if (this.description != null) { throw new IllegalStateException(formatStateException("Description", this.description)); } + if (this.rawBody != null) { + throw new IllegalStateException(formatRawBodyStateException("Description")); + } body.add(0, createMessageBean(description)); this.description = description; } @@ -217,21 +224,53 @@ public Event addSubEvent(Event subEvent) { } /** - * Adds passed body data bodyData + * Set raw body + * Note: you can set either of the whole raw body or several body data + * + * @return current event + * @throws IllegalStateException if raw body is already set or body data list isn't empty + */ + public Event rawBody(byte[] rawBody) { + if (this.rawBody != null) { + throw new IllegalStateException( + formatStateException("Raw body", truncate(new String(this.rawBody, StandardCharsets.UTF_8), 25)) + ); + } + if (!this.body.isEmpty()) { + throw new IllegalStateException( + "Raw body can't be set to event '" + id + "' because body data list isn't empty" + ); + } + this.rawBody = rawBody; + return this; + } + + /** + * Adds passed body data bodyData. + * Note: you can set either of several body data or the whole raw body * * @return current event + * @throws IllegalStateException if raw body is already set */ public Event bodyData(IBodyData bodyData) { + if (this.rawBody != null) { + throw new IllegalStateException(formatRawBodyStateException("Body data")); + } body.add(requireNonNull(bodyData, "Body data can't be null")); return this; } /** * Adds passed collection of body data + * Note: you can set either of several body data or the whole raw body * * @return current event + * @throws IllegalStateException if raw body is already set */ public Event bodyData(Collection bodyDataCollection) { + if (this.rawBody != null) { + throw new IllegalStateException(formatRawBodyStateException("Body data collection")); + } body.addAll(requireNonNull(bodyDataCollection, "Body data collection cannot be null")); return this; } @@ -361,7 +400,7 @@ private com.exactpro.th2.common.grpc.Event toProto( .setType(defaultIfBlank(type, UNKNOWN_EVENT_TYPE)) .setEndTimestamp(toTimestamp(endTimestamp)) .setStatus(getAggregatedStatus().eventStatus) - .setBody(ByteString.copyFrom(buildBody())); + .setBody(UnsafeByteOperations.unsafeWrap(buildBody())); List problems = new ArrayList<>(); if (parentId != null) { if (!Objects.equals(parentId.getBookName(), eventId.getBookName())) { @@ -559,13 +598,21 @@ public Instant getEndTimestamp() { } protected byte[] buildBody() throws IOException { - return OBJECT_MAPPER.get().writeValueAsBytes(body); + if (rawBody == null) { + return OBJECT_MAPPER.get().writeValueAsBytes(body); + } else { + return rawBody; + } } protected String formatStateException(String fieldName, Object value) { return fieldName + " in event '" + id + "' already sed with value '" + value + '\''; } + protected String formatRawBodyStateException(String fieldName) { + return fieldName + " can't be added to body data of event '" + id + "' because raw body is already sed"; + } + @NotNull protected Status getAggregatedStatus() { if (status == Status.PASSED) { diff --git a/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt b/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt index 071f4e07..dfb98653 100644 --- a/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt +++ b/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 Exactpro (Exactpro Systems Limited) + * Copyright 2020-2024 Exactpro (Exactpro Systems Limited) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,6 +52,7 @@ class TestEvent { private val data = EventUtils.createMessageBean("0123456789".repeat(20)) private val dataSize = MAPPER.writeValueAsBytes(listOf(data)).size private val bigData = EventUtils.createMessageBean("0123456789".repeat(30)) + private val rawBody = "Test raw data longer than 25 characters" @Test fun `call the toProto method on a simple event`() { @@ -286,6 +287,7 @@ class TestEvent { } @Test + @Suppress("unused") fun `serializes date time fields`() { class TestBody( val instant: Instant, @@ -313,6 +315,51 @@ class TestEvent { ) } + @Test + fun `add body data when raw body is already set`() { + val event = Event.start() + .rawBody(rawBody.toByteArray()) + assertThrows(IllegalStateException::class.java) { + event.bodyData(data) + }.also { assertEquals("Body data can't be added to body data of event '${event.id}' because raw body is already sed", it.message) } + } + + @Test + fun `set raw body again when raw body is already set`() { + val event = Event.start() + .rawBody(rawBody.toByteArray()) + assertThrows(IllegalStateException::class.java) { + event.rawBody(rawBody.toByteArray()) + }.also { assertEquals("Raw body in event '${event.id}' already sed with value '${rawBody.substring(0, 25)}'", it.message) } + } + + @Test + fun `set description when raw body is already set`() { + val event = Event.start() + .rawBody(rawBody.toByteArray()) + assertThrows(IllegalStateException::class.java) { + event.description("test-description") + }.also { assertEquals("Description can't be added to body data of event '${event.id}' because raw body is already sed", it.message) } + } + + @Test + fun `set raw body when body data is already added`() { + val event = Event.start() + .bodyData(data) + assertThrows(IllegalStateException::class.java) { + event.rawBody(rawBody.toByteArray()) + }.also { assertEquals("Raw body can't be set to event '${event.id}' because body data list isn't empty", it.message) } + } + + @Test + fun `set raw body when description is already set`() { + val event = Event.start() + .description("test-description") + assertThrows(IllegalStateException::class.java) { + event.rawBody(rawBody.toByteArray()) + }.also { assertEquals("Raw body can't be set to event '${event.id}' because body data list isn't empty", it.message) } + } + @TestFactory fun `book mismatch between attached message and event`(): Collection { val event = Event.start() From d3a79c22169585bf7eef00fa088799aa48e920ff Mon Sep 17 00:00:00 2001 From: "nikita.smirnov" Date: Wed, 12 Jun 2024 12:45:11 +0400 Subject: [PATCH 2/4] Added description for rawBody variable --- src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt b/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt index dfb98653..33beac20 100644 --- a/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt +++ b/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt @@ -52,6 +52,7 @@ class TestEvent { private val data = EventUtils.createMessageBean("0123456789".repeat(20)) private val dataSize = MAPPER.writeValueAsBytes(listOf(data)).size private val bigData = EventUtils.createMessageBean("0123456789".repeat(30)) + /** Event build truncates 25 characters of raw body for error message */ private val rawBody = "Test raw data longer than 25 characters" @Test From 994e56f3309d020d0f2dededfdd33a4f8ff81a0a Mon Sep 17 00:00:00 2001 From: Nikita Smirnov <46124551+Nikita-Smirnov-Exactpro@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:21:47 +0400 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Oleg Smirnov --- src/main/java/com/exactpro/th2/common/event/Event.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/exactpro/th2/common/event/Event.java b/src/main/java/com/exactpro/th2/common/event/Event.java index 40fb2e1b..4a43fd33 100644 --- a/src/main/java/com/exactpro/th2/common/event/Event.java +++ b/src/main/java/com/exactpro/th2/common/event/Event.java @@ -606,11 +606,11 @@ protected byte[] buildBody() throws IOException { } protected String formatStateException(String fieldName, Object value) { - return fieldName + " in event '" + id + "' already sed with value '" + value + '\''; + return fieldName + " in event '" + id + "' already set with value '" + value + '\''; } protected String formatRawBodyStateException(String fieldName) { - return fieldName + " can't be added to body data of event '" + id + "' because raw body is already sed"; + return fieldName + " can't be added to body data of event '" + id + "' because raw body is already set"; } @NotNull From 63122d8dd0dddc597fffb493d6cac0fe09a7df0e Mon Sep 17 00:00:00 2001 From: "nikita.smirnov" Date: Wed, 12 Jun 2024 18:15:22 +0400 Subject: [PATCH 4/4] corrected after review --- src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt b/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt index 33beac20..5371e116 100644 --- a/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt +++ b/src/test/kotlin/com/exactpro/th2/common/event/TestEvent.kt @@ -322,7 +322,7 @@ class TestEvent { .rawBody(rawBody.toByteArray()) assertThrows(IllegalStateException::class.java) { event.bodyData(data) - }.also { assertEquals("Body data can't be added to body data of event '${event.id}' because raw body is already sed", it.message) } + }.also { assertEquals("Body data can't be added to body data of event '${event.id}' because raw body is already set", it.message) } } @Test @@ -331,7 +331,7 @@ class TestEvent { .rawBody(rawBody.toByteArray()) assertThrows(IllegalStateException::class.java) { event.rawBody(rawBody.toByteArray()) - }.also { assertEquals("Raw body in event '${event.id}' already sed with value '${rawBody.substring(0, 25)}'", it.message) } + }.also { assertEquals("Raw body in event '${event.id}' already set with value '${rawBody.substring(0, 25)}'", it.message) } } @Test @@ -340,7 +340,7 @@ class TestEvent { .rawBody(rawBody.toByteArray()) assertThrows(IllegalStateException::class.java) { event.description("test-description") - }.also { assertEquals("Description can't be added to body data of event '${event.id}' because raw body is already sed", it.message) } + }.also { assertEquals("Description can't be added to body data of event '${event.id}' because raw body is already set", it.message) } } @Test