From 2a6d4e13969c891066740d348a5eaef383d20b3f Mon Sep 17 00:00:00 2001 From: Kai Hudalla Date: Wed, 24 Sep 2025 09:59:59 +0200 Subject: [PATCH 1/3] Simplify configuration of jacoco Maven plugin --- pom.xml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 9c4f38e..57fe133 100644 --- a/pom.xml +++ b/pom.xml @@ -377,23 +377,14 @@ + org/eclipse/uprotocol/Uoptions.* + org/eclipse/uprotocol/UServiceTopic* org/eclipse/uprotocol/core/** org/eclipse/uprotocol/v1/** - - - **/client/** - **/cloudevent/** - **/communication/** - **/transport/** - **/uri/** - **/uuid/** - **/validation/** - - org.sonatype.central From 2e6ed4788877708be2cecc3ba0252f6a7ebe8e04 Mon Sep 17 00:00:00 2001 From: Kai Hudalla Date: Wed, 24 Sep 2025 10:00:51 +0200 Subject: [PATCH 2/3] Increase log level for running tests This makes sure that more lines of code are executed during tests, which increases the code coverage. --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index f26aace..253a798 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -8,5 +8,5 @@ - + From becb8902cdf5af515c78a2e9e3ea950f600b66a0 Mon Sep 17 00:00:00 2001 From: Kai Hudalla Date: Wed, 24 Sep 2025 10:01:46 +0200 Subject: [PATCH 3/3] Fix handling of unsigned integers Some of the UAttributes properties are defined as unsigned integers in the protocol specification. However, Java does not have native support for unsigned types, which can lead to issues when dealing with values that exceed the maximum value of a signed integer. Java 8 has introduced support for handling unsigned integers through methods in the Integer and Long classes. This commit updates the codebase to utilize these methods where appropriate, ensuring that unsigned integer values are handled correctly. --- .../transport/builder/UMessageBuilder.java | 40 ++------ .../validator/UAttributesValidator.java | 94 ++++++------------- .../uprotocol/uuid/factory/UuidUtils.java | 30 +++--- .../communication/InMemoryRpcClientTest.java | 1 + .../builder/UMessageBuilderTest.java | 65 +++++-------- .../validator/UAttributesValidatorTest.java | 42 +++------ .../uprotocol/uuid/factory/UuidUtilsTest.java | 25 ++--- 7 files changed, 92 insertions(+), 205 deletions(-) diff --git a/src/main/java/org/eclipse/uprotocol/transport/builder/UMessageBuilder.java b/src/main/java/org/eclipse/uprotocol/transport/builder/UMessageBuilder.java index 8136be6..d8c038f 100644 --- a/src/main/java/org/eclipse/uprotocol/transport/builder/UMessageBuilder.java +++ b/src/main/java/org/eclipse/uprotocol/transport/builder/UMessageBuilder.java @@ -55,7 +55,7 @@ public final class UMessageBuilder { /** * Gets a builder for a publish message. - * + *

* A publish message is used to notify all interested consumers of an event that has occurred. * Consumers usually indicate their interest by subscribing to a particular topic. * @@ -75,7 +75,7 @@ public static UMessageBuilder publish(UUri source) { /** * Gets a builder for a notification message. - * + *

* A notification is used to inform a specific consumer about an event that has occurred. * * @param source The component that the notification originates from. @@ -135,13 +135,6 @@ public static UMessageBuilder request(UUri source, UUri sink, int ttl) { *

* The builder will be initialized with {@link UPriority#UPRIORITY_CS4}. * - * # Arguments - * - * * `reply_to_address` - The URI that the sender of the request expects to receive the response message at. - * * `request_id` - The identifier of the request that this is the response to. - * * `invoked_method` - The URI identifying the method that has been invoked and which the created message is - * the outcome of. - * * @param source The URI identifying the method that has been invoked and which the created message is * the outcome of. * @param sink The URI that the sender of the request expects to receive the response message at. @@ -169,16 +162,9 @@ public static UMessageBuilder response(UUri source, UUri sink, UUID reqid) { *

* A response message is used to send the outcome of processing a request message * to the original sender of the request message. - *

- * The builder will be initialized with values from the given request attributes. * - * # Arguments - * - * * `request_attributes` - The attributes from the request message. The response message - * builder will be initialized with the corresponding attribute values. - * * @param request The attributes from the request message. The response message - * builder will be initialized with the corresponding attribute values. + * builder will be initialized with the corresponding attribute values. * @return The builder. * @throws NullPointerException if request is {@code null}. * @throws IllegalArgumentException if the request does not contain valid request attributes. @@ -219,7 +205,7 @@ private UMessageBuilder(UUri source, UUID id, UMessageType type) { /** * Sets the message's identifier. - * + *

* Every message must have an identifier. If this method is not used, an identifier will be * generated and set on the message when one of the build methods is invoked. * @@ -241,14 +227,11 @@ public UMessageBuilder withMessageId(UUID id) { /** * Sets the message's time-to-live. * - * @param ttl The time-to-live in milliseconds. + * @param ttl The time-to-live in milliseconds. Note that the value is interpreted as an + * unsigned integer. A value of 0 indicates that the message never expires. * @return The builder with the configured ttl. - * @throws IllegalArgumentException if the ttl is negative. */ public UMessageBuilder withTtl(int ttl) { - if (ttl < 0) { - throw new IllegalArgumentException("TTL must be a non-negative integer."); - } this.ttl = ttl; return this; } @@ -296,16 +279,12 @@ public UMessageBuilder withPriority(UPriority priority) { /** * Sets the message's permission level. * - * @param plevel The level. + * @param plevel The level. Note that the value is interpreted as an unsigned integer. * @return The builder with the configured permission level. - * @throws IllegalArgumentException if the permission level is less than 0. * @throws IllegalStateException if the message is not an RPC request message. */ public UMessageBuilder withPermissionLevel(int plevel) { // [impl->dsn~up-attributes-permission-level~1] - if (plevel < 0) { - throw new IllegalArgumentException("Permission level must be greater than or equal to 0."); - } if (this.type != UMessageType.UMESSAGE_TYPE_REQUEST) { throw new IllegalStateException("Permission level can only be set for RPC request messages."); } @@ -372,11 +351,6 @@ public UMessage build(UPayload payload) { /** * Creates the message based on the builder's state. * - * # Errors - * - * If the properties set on the builder do not represent a consistent set of [`UAttributes`], - * a [`UMessageError::AttributesValidationError`] is returned. - * * @return A message ready to be sent using a transport implementation. * @throws ValidationException if the properties set on the builder do not represent a * consistent set of attributes as determined by {@link UAttributesValidator#validate(UAttributes)}. diff --git a/src/main/java/org/eclipse/uprotocol/transport/validator/UAttributesValidator.java b/src/main/java/org/eclipse/uprotocol/transport/validator/UAttributesValidator.java index 3adecd3..df0e5ef 100644 --- a/src/main/java/org/eclipse/uprotocol/transport/validator/UAttributesValidator.java +++ b/src/main/java/org/eclipse/uprotocol/transport/validator/UAttributesValidator.java @@ -129,19 +129,42 @@ public final void validateRpcPriority(UAttributes attributes) { } } + /** + * Validates the time-to-live configuration of RPC messages. + * + * @param attributes The attributes to check. + * @throws IllegalArgumentException if the attributes do not represent an RPC message. + * @throws ValidationException if the attributes do not contain a TTL or if its value is 0. + */ + public final void validateRpcTtl(UAttributes attributes) { + if (attributes.getType() != UMessageType.UMESSAGE_TYPE_REQUEST + && attributes.getType() != UMessageType.UMESSAGE_TYPE_RESPONSE) { + throw new IllegalArgumentException("Attributes do not represent an RPC message"); + } + if (!attributes.hasTtl()) { + throw new ValidationException("RPC messages must contain a TTL"); + } + int ttl = attributes.getTtl(); + // TTL is interpreted as an unsigned integer, so negative values are not possible + if (ttl == 0) { + throw new ValidationException("RPC message's TTL must not be 0"); + } + } + /** * Checks if a given set of attributes belong to a message that has expired. *

* The message is considered expired if the message's creation time plus the * duration indicated by the ttl attribute is before the current - * instant in time. + * instant in (system) time. * * @param attributes The attributes to check. * @return {@code true} if the given attributes should be considered expired. */ public final boolean isExpired(UAttributes attributes) { final int ttl = attributes.getTtl(); - return ttl > 0 && UuidUtils.isExpired(attributes.getId(), ttl, Instant.now()); + // TTL is interpreted as an unsigned integer, so negative values are not possible + return Integer.compareUnsigned(ttl, 0) > 0 && UuidUtils.isExpired(attributes.getId(), ttl, Instant.now()); } /* @@ -178,43 +201,6 @@ public final boolean isExpired(UAttributes attributes) { */ public abstract void validate(UAttributes attributes); - /** - * Validates the time-to-live configuration. - *

- * If the UAttributes does not contain a time to live then the ValidationResult is ok. - * - * @param attributes The attributes to check. - * @throws ValidationException if the attributes contain a negative TTL. - */ - public void validateTtl(UAttributes attributes) { - if (!attributes.hasTtl()) { - return; - } - int ttl = attributes.getTtl(); - if (ttl < 0) { - throw new ValidationException(String.format("TTL must be a non-negative integer [%s]", ttl)); - } - } - - /** - * Validate the permissionLevel for the default case. If the UAttributes does - * not contain a permission level then - * the ValidationResult is ok. - * - * @param attributes The attributes to check. - * @throws ValidationException if the attributes contain a negative permission level. - */ - public final void validatePermissionLevel(UAttributes attributes) { - if (!attributes.hasPermissionLevel()) { - return; - } - final var level = attributes.getPermissionLevel(); - if (level < 0) { - throw new ValidationException( - String.format("Permission level must be a non-negative integer [%d]", level)); - } - } - /** * Validators for the message types defined by uProtocol. */ @@ -294,7 +280,6 @@ public void validate(UAttributes attributes) { this::validateId, this::validateSource, this::validateSink, - this::validateTtl, this::validatePriority ); if (!errors.isEmpty()) { @@ -366,7 +351,6 @@ public void validate(UAttributes attributes) { this::validateId, this::validateSource, this::validateSink, - this::validateTtl, this::validatePriority ); if (!errors.isEmpty()) { @@ -435,27 +419,6 @@ public void validateSink(UAttributes attributes) { } } - /** - * Verifies that a set of attributes representing an RPC request contain a valid time-to-live. - * - * @param attributes The attributes to check. - * @throws ValidationException if the attributes do not contain a time-to-live, - * or if the time-to-live is <= 0. - */ - @Override - public void validateTtl(UAttributes attributes) { - // [impl->dsn~up-attributes-request-ttl~1] - if (!attributes.hasTtl()) { - throw new ValidationException("RPC request message must contain a TTL"); - } - int ttl = attributes.getTtl(); - if (ttl <= 0) { - throw new ValidationException(String.format( - "RPC request message's TTL must be a positive integer [%d]", - ttl)); - } - } - @Override public void validate(UAttributes attributes) { final var errors = ValidationUtils.collectErrors(attributes, @@ -463,9 +426,8 @@ public void validate(UAttributes attributes) { this::validateId, this::validateSource, this::validateSink, - this::validateTtl, - this::validateRpcPriority, - this::validatePermissionLevel + this::validateRpcTtl, + this::validateRpcPriority ); if (!errors.isEmpty()) { throw new ValidationException(errors); @@ -575,7 +537,7 @@ public void validate(UAttributes attributes) { this::validateSource, this::validateSink, this::validateReqId, - this::validateTtl, + this::validateRpcTtl, this::validateRpcPriority, this::validateCommstatus ); diff --git a/src/main/java/org/eclipse/uprotocol/uuid/factory/UuidUtils.java b/src/main/java/org/eclipse/uprotocol/uuid/factory/UuidUtils.java index 33b40f6..9b7d174 100644 --- a/src/main/java/org/eclipse/uprotocol/uuid/factory/UuidUtils.java +++ b/src/main/java/org/eclipse/uprotocol/uuid/factory/UuidUtils.java @@ -76,7 +76,7 @@ public static boolean isUProtocol(UUID uuid) { * @throws NullPointerException if the UUID is {@code null}. * @throws IllegalArgumentException if the UUID is not a uProtocol UUID. */ - public static long getTime(UUID uuid) { + public static long getTimestamp(UUID uuid) { Objects.requireNonNull(uuid); if (!isUProtocol(uuid)) { throw new IllegalArgumentException("UUID is not a uProtocol UUID"); @@ -101,7 +101,7 @@ public static long getElapsedTime(UUID id, Instant now) { if (!isUProtocol(id)) { throw new IllegalArgumentException("UUID is not a uProtocol UUID"); } - final var creationTime = getTime(id); + final var creationTime = getTimestamp(id); final var referenceTime = now != null ? now.toEpochMilli() : Instant.now().toEpochMilli(); return referenceTime - creationTime; } @@ -118,21 +118,16 @@ public static long getElapsedTime(UUID id, Instant now) { * has already expired. * @throws NullPointerException if the UUID is {@code null}. * @throws IllegalArgumentException if the UUID is not a uProtocol UUID. - * @throws IllegalArgumentException if the TTL is non-positive. + * @throws IllegalArgumentException if the TTL is 0. */ public static long getRemainingTime(UUID id, int ttl, Instant now) { Objects.requireNonNull(id); - if (!isUProtocol(id)) { - throw new IllegalArgumentException("UUID is not a uProtocol UUID"); - } - if (ttl <= 0) { - throw new IllegalArgumentException("TTL must be positive"); + if (ttl == 0) { + throw new IllegalArgumentException("TTL must not be 0"); } - final var creationTime = getTime(id); - final var referenceTime = now != null ? now.toEpochMilli() : Instant.now().toEpochMilli(); - final var elapsedTime = referenceTime - creationTime; - if (elapsedTime >= ttl) { - return 0; + final long elapsedTime = getElapsedTime(id, now); + if (Long.compareUnsigned(elapsedTime, ttl) > 0) { + return 0; // Expired } else { return ttl - elapsedTime; } @@ -142,22 +137,19 @@ public static long getRemainingTime(UUID id, int ttl, Instant now) { * Checks if an object identified by a given UUID should be considered expired. * * @param id The UUID. - * @param ttl The object's time-to-live (TTL) in milliseconds. + * @param ttl The object's time-to-live (TTL) in milliseconds. Note that the TTL is + * interpreted as an unsigned integer. * @param now The reference point in time that the calculation should be based on, given * as the number of milliseconds since the Unix epoch, or {@code null} to use the current point in time. * @return {@code true} if the object's TTL has already expired. * @throws NullPointerException if the UUID is {@code null}. * @throws IllegalArgumentException if the UUID is not a uProtocol UUID. - * @throws IllegalArgumentException if the TTL is negative. */ public static boolean isExpired(UUID id, int ttl, Instant now) { Objects.requireNonNull(id); if (!isUProtocol(id)) { throw new IllegalArgumentException("UUID is not a uProtocol UUID"); } - if (ttl < 0) { - throw new IllegalArgumentException("TTL must be non-negative"); - } - return ttl > 0 && getRemainingTime(id, ttl, now) == 0; + return Integer.compareUnsigned(ttl, 0) > 0 && getRemainingTime(id, ttl, now) == 0; } } diff --git a/src/test/java/org/eclipse/uprotocol/communication/InMemoryRpcClientTest.java b/src/test/java/org/eclipse/uprotocol/communication/InMemoryRpcClientTest.java index bed348e..80fe153 100644 --- a/src/test/java/org/eclipse/uprotocol/communication/InMemoryRpcClientTest.java +++ b/src/test/java/org/eclipse/uprotocol/communication/InMemoryRpcClientTest.java @@ -187,6 +187,7 @@ void testHandleUnexpectedResponse(Consumer unexpectedMessageHandler) { METHOD_URI, TRANSPORT_SOURCE, reqId) + .withTtl(54321) .build(); responseListener.getValue().onReceive(responseMessage); diff --git a/src/test/java/org/eclipse/uprotocol/transport/builder/UMessageBuilderTest.java b/src/test/java/org/eclipse/uprotocol/transport/builder/UMessageBuilderTest.java index b22187d..4c2d390 100644 --- a/src/test/java/org/eclipse/uprotocol/transport/builder/UMessageBuilderTest.java +++ b/src/test/java/org/eclipse/uprotocol/transport/builder/UMessageBuilderTest.java @@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.ValueSource; import com.google.protobuf.ByteString; @@ -130,45 +129,36 @@ void assertBuilderPanics( } } - @ParameterizedTest - @ValueSource(ints = { -1, 0 }) - void testRequestRejectsInvalidTtl(int ttl) { + @Test + void testRequestRejectsInvalidTtl() { assertThrows( IllegalArgumentException.class, - () -> UMessageBuilder.request(UURI_DEFAULT, UURI_METHOD, ttl) + () -> UMessageBuilder.request(UURI_DEFAULT, UURI_METHOD, 0) ); } @ParameterizedTest @CsvSource(useHeadersInDisplayName = true, textBlock = """ - permLevel, commStatus, priority - # // [utest->dsn~up-attributes-permission-level~1] - -1, , - , NOT_FOUND, + commStatus, priority + NOT_FOUND, # // [utest->dsn~up-attributes-request-priority~1] - , , UPRIORITY_UNSPECIFIED + , UPRIORITY_UNSPECIFIED # // [utest->dsn~up-attributes-request-priority~1] - , , UPRIORITY_CS0 + , UPRIORITY_CS0 # // [utest->dsn~up-attributes-request-priority~1] - , , UPRIORITY_CS1 + , UPRIORITY_CS1 # // [utest->dsn~up-attributes-request-priority~1] - , , UPRIORITY_CS2 + , UPRIORITY_CS2 # // [utest->dsn~up-attributes-request-priority~1] - , , UPRIORITY_CS3 + , UPRIORITY_CS3 """) void testRequestMessageBuilderRejectsInvalidAttributes( - Integer permLevel, UCode commStatus, UPriority priority ) { var builder = UMessageBuilder.request(UURI_DEFAULT, UURI_METHOD, 5000); - if (permLevel != null) { - assertThrows( - IllegalArgumentException.class, - () -> builder.withPermissionLevel(permLevel) - ); - } else if (commStatus != null) { + if (commStatus != null) { assertThrows( IllegalStateException.class, () -> builder.withCommStatus(commStatus) @@ -183,25 +173,23 @@ void testRequestMessageBuilderRejectsInvalidAttributes( @ParameterizedTest @CsvSource(useHeadersInDisplayName = true, textBlock = """ - ttl, permLevel, token, priority + permLevel, token, priority # // [utest->dsn~up-attributes-permission-level~1] - -1, , , - , 5, , + 5, , # // [utest->dsn~up-attributes-request-token~1] - , , my-token, + , my-token, # // [utest->dsn~up-attributes-request-priority~1] - , , , UPRIORITY_UNSPECIFIED + , , UPRIORITY_UNSPECIFIED # // [utest->dsn~up-attributes-request-priority~1] - , , , UPRIORITY_CS0 + , , UPRIORITY_CS0 # // [utest->dsn~up-attributes-request-priority~1] - , , , UPRIORITY_CS1 + , , UPRIORITY_CS1 # // [utest->dsn~up-attributes-request-priority~1] - , , , UPRIORITY_CS2 + , , UPRIORITY_CS2 # // [utest->dsn~up-attributes-request-priority~1] - , , , UPRIORITY_CS3 + , , UPRIORITY_CS3 """) void testResponseMessageBuilderRejectsInvalidAttributes( - Integer ttl, Integer permLevel, String token, UPriority priority @@ -211,12 +199,7 @@ void testResponseMessageBuilderRejectsInvalidAttributes( UURI_DEFAULT, UuidFactory.create()); - if (ttl != null) { - assertThrows( - IllegalArgumentException.class, - () -> builder.withTtl(ttl) - ); - } else if (permLevel != null) { + if (permLevel != null) { assertThrows( IllegalStateException.class, () -> builder.withPermissionLevel(permLevel) @@ -312,7 +295,7 @@ void testBuildRetainsAllNotificationAttributes() { UMessage message = UMessageBuilder.notification(origin, destination) .withMessageId(messageId) .withPriority(UPriority.UPRIORITY_CS2) - .withTtl(5000) + .withTtl(0xFF00_FFFF) // test unsigned integer .withTraceparent(traceparent) .build(UPayload.pack(ByteString.copyFromUtf8("locked"), UPayloadFormat.UPAYLOAD_FORMAT_TEXT)); @@ -321,7 +304,7 @@ void testBuildRetainsAllNotificationAttributes() { assertEquals(UPriority.UPRIORITY_CS2, message.getAttributes().getPriority()); assertEquals(origin, message.getAttributes().getSource()); assertEquals(destination, message.getAttributes().getSink()); - assertEquals(5000, message.getAttributes().getTtl()); + assertEquals(0xFF00_FFFF, message.getAttributes().getTtl()); // [utest->dsn~up-attributes-traceparent~1] assertEquals(traceparent, message.getAttributes().getTraceparent()); // [utest->dsn~up-attributes-notification-type~1] @@ -349,7 +332,7 @@ void testBuildRetainsAllRequestAttributes() { var replyToAddress = UURI_DEFAULT; UMessage message = UMessageBuilder.request(replyToAddress, methodToInvoke, 5000) .withMessageId(messageId) - .withPermissionLevel(5) + .withPermissionLevel(0xFF00_FFFF) // test unsigned integer .withPriority(UPriority.UPRIORITY_CS4) .withToken(token) .withTraceparent(traceparent) @@ -358,7 +341,7 @@ void testBuildRetainsAllRequestAttributes() { // [utest->dsn~up-attributes-id~1] assertEquals(messageId, message.getAttributes().getId()); // [utest->dsn~up-attributes-permission-level~1] - assertEquals(5, message.getAttributes().getPermissionLevel()); + assertEquals(0xFF00_FFFF, message.getAttributes().getPermissionLevel()); assertEquals(UPriority.UPRIORITY_CS4, message.getAttributes().getPriority()); assertEquals(replyToAddress, message.getAttributes().getSource()); assertEquals(methodToInvoke, message.getAttributes().getSink()); diff --git a/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributesValidatorTest.java b/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributesValidatorTest.java index 24554e5..c2bbb14 100644 --- a/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributesValidatorTest.java +++ b/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributesValidatorTest.java @@ -563,16 +563,6 @@ static Stream requestMessageArgProvider() { OptionalInt.of(0), OptionalInt.of(UPriority.UPRIORITY_CS4_VALUE), Optional.empty(), - false), - // fails for invalid (negative) permission level - Arguments.of( - Optional.of(UuidFactory.create()), - Optional.of(UURI_METHOD), - Optional.of(UURI_DEFAULT), - OptionalInt.of(-1), - OptionalInt.of(2000), - OptionalInt.of(UPriority.UPRIORITY_CS4_VALUE), - Optional.empty(), false) ); } @@ -629,7 +619,7 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_METHOD), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), true), // succeeds for valid attributes @@ -661,7 +651,7 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_METHOD), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), false), // fails for missing reply-to-address @@ -672,7 +662,7 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_METHOD), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), false), // fails for invalid reply-to-address @@ -683,7 +673,7 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_METHOD), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), false), // fails for reply-to-address with wildcard @@ -694,7 +684,7 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_METHOD), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), false), // fails for missing invoked-method @@ -705,7 +695,7 @@ static Stream responseMessageArgProvider() { Optional.empty(), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), false), // fails for invalid invoked-method @@ -716,7 +706,7 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_TOPIC), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), false), // fails for invoked-method with wildcard @@ -727,7 +717,7 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_WILDCARD_RESOURCE), Optional.of(UuidFactory.create()), OptionalInt.empty(), - OptionalInt.empty(), + OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), false), // fails for invalid commstatus @@ -737,20 +727,10 @@ static Stream responseMessageArgProvider() { Optional.of(UURI_METHOD), Optional.of(UuidFactory.create()), OptionalInt.of(-189), - OptionalInt.empty(), - Optional.of(UPriority.UPRIORITY_CS4), - false), - // succeeds for ttl > 0 - Arguments.of( - Optional.of(UuidFactory.create()), - Optional.of(UURI_DEFAULT), - Optional.of(UURI_METHOD), - Optional.of(UuidFactory.create()), - OptionalInt.empty(), OptionalInt.of(100), Optional.of(UPriority.UPRIORITY_CS4), - true), - // succeeds for ttl = 0 + false), + // fails for ttl = 0 Arguments.of( Optional.of(UuidFactory.create()), Optional.of(UURI_DEFAULT), @@ -759,7 +739,7 @@ static Stream responseMessageArgProvider() { OptionalInt.empty(), OptionalInt.of(0), Optional.of(UPriority.UPRIORITY_CS4), - true), + false), // fails for missing priority Arguments.of( Optional.of(UuidFactory.create()), diff --git a/src/test/java/org/eclipse/uprotocol/uuid/factory/UuidUtilsTest.java b/src/test/java/org/eclipse/uprotocol/uuid/factory/UuidUtilsTest.java index 82c2ce3..cd3f458 100644 --- a/src/test/java/org/eclipse/uprotocol/uuid/factory/UuidUtilsTest.java +++ b/src/test/java/org/eclipse/uprotocol/uuid/factory/UuidUtilsTest.java @@ -75,14 +75,14 @@ private static Stream provideCreationTimestamps() { @MethodSource("provideCreationTimestamps") void testGetTime(Instant timestamp) { final UUID uuid = UuidFactory.create(timestamp); - final var time = UuidUtils.getTime(uuid); + final var time = UuidUtils.getTimestamp(uuid); assertEquals(timestamp.toEpochMilli(), time); } @Test void testGetTimeRejectsInvalidArgs() { - assertThrows(NullPointerException.class, () -> UuidUtils.getTime(null)); - assertThrows(IllegalArgumentException.class, () -> UuidUtils.getTime(invalidUuid())); + assertThrows(NullPointerException.class, () -> UuidUtils.getTimestamp(null)); + assertThrows(IllegalArgumentException.class, () -> UuidUtils.getTimestamp(invalidUuid())); } private static Stream provideElapsedTimeTestCases() { @@ -123,15 +123,16 @@ private static Stream provideRemainingTimeTestCases() { Arguments.of(now.minusSeconds(60), 40_000, now, 0), Arguments.of(now.minusSeconds(60), 60_000, now, 0), Arguments.of(now.minusSeconds(60), 80_000, now, 20_000), - Arguments.of(now.plusSeconds(10), 70_000, now.plusSeconds(79), 1_000) + Arguments.of(now.plusSeconds(10), 70_000, now.plusSeconds(79), 1_000), + Arguments.of(now, 0xFFFF_FFFF, now.plusMillis(0x00FF_FFFF), 0xFF00_0000) ); } @ParameterizedTest(name = "Test getting remaining time for UUID {index} - {arguments}") @MethodSource("provideRemainingTimeTestCases") - void testGetRemainingTime(Instant creationTime, int ttl, Instant referenceTime, long expectedRemaining) { + void testGetRemainingTime(Instant creationTime, int ttl, Instant referenceTime, long expectedRemainingMillis) { final UUID id = UuidFactory.create(creationTime); - assertEquals(expectedRemaining, UuidUtils.getRemainingTime(id, ttl, referenceTime)); + assertEquals(expectedRemainingMillis, UuidUtils.getRemainingTime(id, ttl, referenceTime)); } @Test @@ -154,10 +155,6 @@ void testGetRemainingTimeRejectsInvalidArgs() { IllegalArgumentException.class, () -> UuidUtils.getRemainingTime(UuidFactory.create(), 0, Instant.now().plusSeconds(10)) ); - assertThrows( - IllegalArgumentException.class, - () -> UuidUtils.getRemainingTime(UuidFactory.create(), -1, Instant.now().plusSeconds(10)) - ); } private static Stream provideIsExpiredTestCases() { @@ -167,7 +164,9 @@ private static Stream provideIsExpiredTestCases() { Arguments.of(now.minusSeconds(60), 40_000, now, true), Arguments.of(now.minusSeconds(60), 60_000, now, true), Arguments.of(now.minusSeconds(60), 80_000, now, false), - Arguments.of(now.plusSeconds(10), 70_000, now.plusSeconds(79), false) + Arguments.of(now.plusSeconds(10), 70_000, now.plusSeconds(79), false), + Arguments.of(now, 0xFFFF_FF00, now.plusMillis(0xFFFF_FEFF), false), + Arguments.of(now, 0xFFFF_FF00, now.plusMillis(0xFFFF_FF00), true) ); } @@ -182,9 +181,5 @@ void testIsExpired(Instant creationTime, int ttl, Instant referenceTime, boolean void testIsExpiredRejectsInvalidArgs() { assertThrows(NullPointerException.class, () -> UuidUtils.isExpired(null, TTL, Instant.now())); assertThrows(IllegalArgumentException.class, () -> UuidUtils.isExpired(invalidUuid(), TTL, Instant.now())); - assertThrows( - IllegalArgumentException.class, - () -> UuidUtils.isExpired(UuidFactory.create(), -3, Instant.now()) - ); } }