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 3d50c0b5..5f73da0d 100644 --- a/src/main/java/org/eclipse/uprotocol/transport/builder/UMessageBuilder.java +++ b/src/main/java/org/eclipse/uprotocol/transport/builder/UMessageBuilder.java @@ -13,6 +13,7 @@ package org.eclipse.uprotocol.transport.builder; import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.validation.ValidationException; import org.eclipse.uprotocol.v1.UMessage; import org.eclipse.uprotocol.v1.UAttributes; import org.eclipse.uprotocol.v1.UCode; @@ -139,8 +140,10 @@ public static UMessageBuilder response(UUri source, UUri sink, UUID reqid) { throw new IllegalArgumentException("sink must be a response and source must be an rpc method."); } - if (UuidValidator.Validators.UPROTOCOL.validator().validate(reqid).getCode() != UCode.OK) { - throw new IllegalArgumentException("reqid is not a valid UUID."); + try { + UuidValidator.Validators.UPROTOCOL.validator().validate(reqid); + } catch (ValidationException e) { + throw new IllegalArgumentException("reqid is not a valid UUID.", e); } return new UMessageBuilder(source, UuidFactory.Factories.UPROTOCOL.factory().create(), @@ -159,8 +162,10 @@ public static UMessageBuilder response(UAttributes request) { Objects.requireNonNull(request, "request cannot be null."); // Validate the request - if (UAttributesValidator.Validators.REQUEST.validator().validate(request).isFailure()) { - throw new IllegalArgumentException("request must contain valid request attributes."); + try { + UAttributesValidator.Validators.REQUEST.validator().validate(request); + } catch (ValidationException e) { + throw new IllegalArgumentException("request is not a valid request attributes.", e); } return new UMessageBuilder( diff --git a/src/main/java/org/eclipse/uprotocol/transport/validate/UAttributesValidator.java b/src/main/java/org/eclipse/uprotocol/transport/validate/UAttributesValidator.java index d6350924..7e0d6462 100644 --- a/src/main/java/org/eclipse/uprotocol/transport/validate/UAttributesValidator.java +++ b/src/main/java/org/eclipse/uprotocol/transport/validate/UAttributesValidator.java @@ -19,12 +19,11 @@ import org.eclipse.uprotocol.v1.UPriority; import org.eclipse.uprotocol.v1.UUri; import org.eclipse.uprotocol.v1.UUID; -import org.eclipse.uprotocol.validation.ValidationResult; +import org.eclipse.uprotocol.validation.ValidationException; +import org.eclipse.uprotocol.validation.ValidationUtils; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * {@link UAttributes} is the class that defines the Payload. It is the place @@ -65,20 +64,25 @@ public static UAttributesValidator getValidator(UAttributes attribute) { } /** - * Take a {@link UAttributes} object and run validations. + * Checks if a given set of attributes complies with the rules specified for + * the type of message they describe. * - * @param attributes The UAttriubes to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * message containing all validation - * errors for - * invalid configurations. + * @param attributes The attributes to validate. + * @throws ValidationException if the attributes are not consistent with the rules specified for the message type. */ - public ValidationResult validate(UAttributes attributes) { - final String errorMessage = Stream.of(validateType(attributes), - validateTtl(attributes), validateSink(attributes), validatePriority(attributes), - validatePermissionLevel(attributes), validateReqId(attributes), validateId(attributes)) - .filter(ValidationResult::isFailure).map(ValidationResult::getMessage).collect(Collectors.joining(",")); - return errorMessage.isBlank() ? ValidationResult.success() : ValidationResult.failure(errorMessage); + public void validate(UAttributes attributes) { + final var errors = ValidationUtils.collectErrors(attributes, + this::validateType, + this::validateTtl, + this::validateSink, + this::validatePriority, + this::validatePermissionLevel, + this::validateReqId, + this::validateId + ); + if (!errors.isEmpty()) { + throw new ValidationException(errors); + } } /** @@ -113,15 +117,12 @@ public boolean isExpired(UAttributes uAttributes) { * * @param attributes UAttributes object containing the message time to live * configuration to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. + * @throws ValidationException if TTL <= 0. */ - public ValidationResult validateTtl(UAttributes attributes) { + public void validateTtl(UAttributes attributes) { int ttl = attributes.getTtl(); if (attributes.hasTtl() && ttl <= 0) { - return ValidationResult.failure(String.format("Invalid TTL [%s]", ttl)); - } else { - return ValidationResult.success(); + throw new ValidationException(String.format("Invalid TTL [%s]", ttl)); } } @@ -130,10 +131,9 @@ public ValidationResult validateTtl(UAttributes attributes) { * Validate the sink UriPart. * * @param attributes UAttributes object containing the sink to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. + * @throws ValidationException if sink is invalid. */ - public abstract ValidationResult validateSink(UAttributes attributes); + public abstract void validateSink(UAttributes attributes); /** * Validate the permissionLevel for the default case. If the UAttributes does @@ -142,14 +142,11 @@ public ValidationResult validateTtl(UAttributes attributes) { * * @param attributes UAttributes object containing the permission level to * validate. - * @return Returns a ValidationResult indicating if the permissionLevel is valid - * or not. + * @throws ValidationException if the permission level is invalid. */ - public ValidationResult validatePermissionLevel(UAttributes attributes) { - if (!attributes.hasPermissionLevel() || attributes.getPermissionLevel() > 0) { - return ValidationResult.success(); - } else { - return ValidationResult.failure("Invalid Permission Level"); + public void validatePermissionLevel(UAttributes attributes) { + if (attributes.hasPermissionLevel() && attributes.getPermissionLevel() <= 0) { + throw new ValidationException("Invalid Permission Level"); } } @@ -158,25 +155,24 @@ public ValidationResult validatePermissionLevel(UAttributes attributes) { * should have a reqid. * * @param attributes Attributes object containing the request id to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. + * @throws ValidationException if the request id is invalid. */ - public ValidationResult validateReqId(UAttributes attributes) { - return attributes.hasReqid() ? ValidationResult.failure("Message should not have a reqid") - : ValidationResult.success(); + public void validateReqId(UAttributes attributes) { + if (attributes.hasReqid()) { + throw new ValidationException("Message should not have a reqid"); + } } /** * Validate the priority value to ensure it is one of the known CS values. * * @param attributes Attributes object containing the Priority to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. + * @throws ValidationException if the priority is invalid. */ - public ValidationResult validatePriority(UAttributes attributes) { - return attributes.getPriority().getNumber() >= UPriority.UPRIORITY_CS1_VALUE ? ValidationResult.success() - : ValidationResult.failure( - String.format("Invalid UPriority [%s]", attributes.getPriority().name())); + public void validatePriority(UAttributes attributes) { + if (attributes.getPriority().getNumber() < UPriority.UPRIORITY_CS1_VALUE) { + throw new ValidationException(String.format("Invalid UPriority [%s]", attributes.getPriority().name())); + } } /** @@ -185,17 +181,14 @@ public ValidationResult validatePriority(UAttributes attributes) { * the ValidationResult is failed. * * @param attributes Attributes object containing the id to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. + * @throws ValidationException if the message ID is invalid. */ - public ValidationResult validateId(UAttributes attributes) { + public void validateId(UAttributes attributes) { if (!attributes.hasId()) { - return ValidationResult.failure("Missing id"); + throw new ValidationException("Missing id"); } if (!UuidUtils.isUuid(attributes.getId())) { - return ValidationResult.failure("Attributes must contain valid uProtocol UUID in id property"); - } else { - return ValidationResult.success(); + throw new ValidationException("Attributes must contain valid uProtocol UUID in id property"); } } @@ -203,10 +196,9 @@ public ValidationResult validateId(UAttributes attributes) { * Validate the {@link UMessageType} attribute, it is required. * * @param attributes UAttributes object containing the message type to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. + * @throws ValidationException if this validator is inappropriate for the message's type. */ - public abstract ValidationResult validateType(UAttributes attributes); + public abstract void validateType(UAttributes attributes); /** * Validators Factory. Example: @@ -241,29 +233,31 @@ private static class Publish extends UAttributesValidator { * the correct type. * * @param attributes UAttributes object containing the message type to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a + * @return Returns a {@link ValidationException} that is success or failed with a * failure message. */ @Override - public ValidationResult validateType(UAttributes attributes) { - return UMessageType.UMESSAGE_TYPE_PUBLISH == attributes.getType() ? ValidationResult.success() - : ValidationResult.failure( - String.format("Wrong Attribute Type [%s]", attributes.getType())); + public void validateType(UAttributes attributes) { + if (UMessageType.UMESSAGE_TYPE_PUBLISH != attributes.getType()) { + throw new ValidationException( + String.format("Wrong Attribute Type [%s]", attributes.getType())); + } } /** * Validate the sink UriPart for Publish events. Publish should not have a sink. * * @param attributes UAttributes object containing the sink to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a + * @return Returns a {@link ValidationException} that is success or failed with a * failure message. */ @Override - public ValidationResult validateSink(UAttributes attributes) { - return attributes.hasSink() ? ValidationResult.failure("Sink should not be present") - : ValidationResult.success(); + public void validateSink(UAttributes attributes) { + if (attributes.hasSink()) { + throw new ValidationException("Sink should not be present"); + } } - + @Override public String toString() { return "UAttributesValidator.Publish"; @@ -277,71 +271,64 @@ public String toString() { private static class Request extends UAttributesValidator { /** + * {@inheritDoc} + * * Validates that attributes for a message meant for an RPC request has the * correct type. - * - * @param attributes UAttributes object containing the message type to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateType(UAttributes attributes) { - return UMessageType.UMESSAGE_TYPE_REQUEST == attributes.getType() ? ValidationResult.success() - : ValidationResult.failure( - String.format("Wrong Attribute Type [%s]", attributes.getType())); + public void validateType(UAttributes attributes) { + if (UMessageType.UMESSAGE_TYPE_REQUEST != attributes.getType()) { + throw new ValidationException( + String.format("Wrong Attribute Type [%s]", attributes.getType())); + } } /** + * {@inheritDoc} + * * Validates that attributes for a message meant for an RPC request has a * destination sink. * In the case of an RPC request, the sink is required. - * - * @param attributes UAttributes object containing the sink to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateSink(UAttributes attributes) { + public void validateSink(UAttributes attributes) { if (!attributes.hasSink()) { - return ValidationResult.failure("Missing Sink"); + throw new ValidationException("Missing Sink"); + } + if (!UriValidator.isRpcMethod(attributes.getSink())) { + throw new ValidationException("Invalid Sink Uri"); } - return UriValidator.isRpcMethod(attributes.getSink()) ? ValidationResult.success() - : ValidationResult.failure("Invalid Sink Uri"); } /** + * {@inheritDoc} + * * Validate the time to live configuration. * In the case of an RPC request, the time to live is required. - * - * @param attributes UAttributes object containing the time to live to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateTtl(UAttributes attributes) { + public void validateTtl(UAttributes attributes) { if (!attributes.hasTtl()) { - return ValidationResult.failure("Missing TTL"); + throw new ValidationException("Missing TTL"); } int ttl = attributes.getTtl(); if (ttl <= 0) { - return ValidationResult.failure(String.format("Invalid TTL [%s]", ttl)); - } else { - return ValidationResult.success(); + throw new ValidationException(String.format("Invalid TTL [%s]", ttl)); } } /** + * {@inheritDoc} + * * Validate the priority value to ensure it is one of the known CS values - * - * @param attributes Attributes object containing the Priority to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validatePriority(UAttributes attributes) { - return attributes.getPriority().getNumber() >= UPriority.UPRIORITY_CS4_VALUE ? ValidationResult.success() - : ValidationResult.failure( - String.format("Invalid UPriority [%s]", attributes.getPriority().name())); + public void validatePriority(UAttributes attributes) { + if (attributes.getPriority().getNumber() < UPriority.UPRIORITY_CS4_VALUE) { + throw new ValidationException( + String.format("Invalid UPriority [%s]", attributes.getPriority().name())); + } } @Override @@ -357,73 +344,64 @@ public String toString() { private static class Response extends UAttributesValidator { /** + * {@inheritDoc} + * * Validates that attributes for a message meant for an RPC response has the * correct type. - * - * @param attributes UAttributes object containing the message type to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateType(UAttributes attributes) { - return UMessageType.UMESSAGE_TYPE_RESPONSE == attributes.getType() ? ValidationResult.success() - : ValidationResult.failure( - String.format("Wrong Attribute Type [%s]", attributes.getType())); + public void validateType(UAttributes attributes) { + if (UMessageType.UMESSAGE_TYPE_RESPONSE != attributes.getType()) { + throw new ValidationException( + String.format("Wrong Attribute Type [%s]", attributes.getType())); + } } /** + * {@inheritDoc} + * * Validates that attributes for a message meant for an RPC response has a * destination sink. * In the case of an RPC response, the sink is required. - * - * @param attributes UAttributes object containing the sink to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateSink(UAttributes attributes) { + public void validateSink(UAttributes attributes) { Objects.requireNonNull(attributes, "UAttributes cannot be null."); if (!attributes.hasSink() || attributes.getSink() == UUri.getDefaultInstance()) { - return ValidationResult.failure("Missing Sink"); + throw new ValidationException("Missing Sink"); + } + if (!UriValidator.isRpcResponse(attributes.getSink())) { + throw new ValidationException("Invalid Sink Uri"); } - return UriValidator.isRpcResponse(attributes.getSink()) ? ValidationResult.success() - : ValidationResult.failure("Invalid Sink Uri"); } /** + * {@inheritDoc} + * * Validate the correlationId. n the case of an RPC response, the correlation id * is required. - * - * @param attributes UAttributes object containing the correlation id to - * validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateReqId(UAttributes attributes) { + public void validateReqId(UAttributes attributes) { if (!attributes.hasReqid() || attributes.getReqid() == UUID.getDefaultInstance()) { - return ValidationResult.failure("Missing correlationId"); + throw new ValidationException("Missing correlationId"); } if (!UuidUtils.isUuid(attributes.getReqid())) { - return ValidationResult.failure("Invalid correlation UUID"); - } else { - return ValidationResult.success(); + throw new ValidationException("Invalid correlation UUID"); } - } /** + * {@inheritDoc} + * * Validate the priority value to ensure it is one of the known CS values - * - * @param attributes Attributes object containing the Priority to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validatePriority(UAttributes attributes) { - return attributes.getPriority().getNumber() >= UPriority.UPRIORITY_CS4_VALUE ? ValidationResult.success() - : ValidationResult.failure( - String.format("Invalid UPriority [%s]", attributes.getPriority().name())); + public void validatePriority(UAttributes attributes) { + if (attributes.getPriority().getNumber() < UPriority.UPRIORITY_CS4_VALUE) { + throw new ValidationException( + String.format("Invalid UPriority [%s]", attributes.getPriority().name())); + } } @Override @@ -439,37 +417,35 @@ public String toString() { private static class Notification extends UAttributesValidator { /** + * {@inheritDoc} + * * Validates that attributes for a message meant to Notification state changes * has the correct type. - * - * @param attributes UAttributes object containing the message type to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateType(UAttributes attributes) { - return UMessageType.UMESSAGE_TYPE_NOTIFICATION == attributes.getType() ? ValidationResult.success() - : ValidationResult.failure( - String.format("Wrong Attribute Type [%s]", attributes.getType())); + public void validateType(UAttributes attributes) { + if (UMessageType.UMESSAGE_TYPE_NOTIFICATION != attributes.getType()) { + throw new ValidationException( + String.format("Wrong Attribute Type [%s]", attributes.getType())); + } } /** + * {@inheritDoc} + * * Validates that attributes for a message meant for notifications has a * destination sink. * In the case of a notification, the sink is required. - * - * @param attributes UAttributes object containing the sink to validate. - * @return Returns a {@link ValidationResult} that is success or failed with a - * failure message. */ @Override - public ValidationResult validateSink(UAttributes attributes) { + public void validateSink(UAttributes attributes) { Objects.requireNonNull(attributes, "UAttributes cannot be null."); if (!attributes.hasSink() || attributes.getSink() == UUri.getDefaultInstance()) { - return ValidationResult.failure("Missing Sink"); + throw new ValidationException("Missing Sink"); + } + if (!UriValidator.isDefaultResourceId(attributes.getSink())) { + throw new ValidationException("Invalid Sink Uri"); } - return UriValidator.isDefaultResourceId(attributes.getSink()) ? ValidationResult.success() - : ValidationResult.failure("Invalid Sink Uri"); } @Override @@ -477,5 +453,4 @@ public String toString() { return "UAttributesValidator.Notification"; } } - } diff --git a/src/main/java/org/eclipse/uprotocol/uuid/validate/UuidValidator.java b/src/main/java/org/eclipse/uprotocol/uuid/validate/UuidValidator.java index c851f362..6dcf05b3 100644 --- a/src/main/java/org/eclipse/uprotocol/uuid/validate/UuidValidator.java +++ b/src/main/java/org/eclipse/uprotocol/uuid/validate/UuidValidator.java @@ -14,13 +14,11 @@ import org.eclipse.uprotocol.uuid.factory.UuidUtils; import org.eclipse.uprotocol.v1.UUID; -import org.eclipse.uprotocol.v1.UStatus; -import org.eclipse.uprotocol.v1.UCode; -import org.eclipse.uprotocol.validation.ValidationResult; +import org.eclipse.uprotocol.validation.ValidationException; +import org.eclipse.uprotocol.validation.ValidationUtils; +import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * A Validator for uProtocol UUIDs. @@ -53,48 +51,63 @@ public UuidValidator validator() { } } - public UStatus validate(UUID uuid) { - final String errorMessage = Stream.of( - validateVersion(uuid), - validateTime(uuid)) - .filter(ValidationResult::isFailure) - .map(ValidationResult::getMessage) - .collect(Collectors.joining(",")); - return errorMessage.isBlank() ? ValidationResult.success().toStatus() - : UStatus.newBuilder().setCode(UCode.INVALID_ARGUMENT).setMessage(errorMessage).build(); + /** + * Checks if a UUID is valid according to the specific variant/version of the UUID. + * + * @param uuid The UUID to validate. + * @throws NullPointerException if the UUID is null. + * @throws ValidationException if the UUID is invalid. + */ + public void validate(UUID uuid) { + Objects.requireNonNull(uuid); + final var errors = ValidationUtils.collectErrors(uuid, + this::validateVersion, + this::validateTime + ); + if (!errors.isEmpty()) { + throw new ValidationException(errors); + } } - public abstract ValidationResult validateVersion(UUID uuid); + /** + * Validates the version of the UUID. + * + * @param uuid The UUID to check. + * @throws ValidationException if the UUID is invalid. + */ + public abstract void validateVersion(UUID uuid); - public ValidationResult validateTime(UUID uuid) { + public void validateTime(UUID uuid) { final Optional time = UuidUtils.getTime(uuid); - return time.isPresent() && (time.get() > 0) ? ValidationResult.success() - : ValidationResult.failure(String.format("Invalid UUID Time")); + if (time.isPresent() && (time.get() > 0)) { + return; + } + throw new ValidationException("Invalid UUID Time"); } private static class InvalidValidator extends UuidValidator { @Override - public ValidationResult validateVersion(UUID uuid) { - return ValidationResult.failure(String.format("Invalid UUID Version")); + public void validateVersion(UUID uuid) { + throw new ValidationException("Invalid UUID Version"); } } private static class UUIDv6Validator extends UuidValidator { @Override - public ValidationResult validateVersion(UUID uuid) { - return UuidUtils.isUuidv6(uuid) - ? ValidationResult.success() - : ValidationResult.failure(String.format("Not a UUIDv6 Version")); + public void validateVersion(UUID uuid) { + if (!UuidUtils.isUuidv6(uuid)) { + throw new ValidationException("Not a UUIDv6 Version"); + } } } private static class UUIDv7Validator extends UuidValidator { @Override - public ValidationResult validateVersion(UUID uuid) { - return UuidUtils.isUProtocol(uuid) - ? ValidationResult.success() - : ValidationResult.failure(String.format("Invalid UUIDv7 Version")); + public void validateVersion(UUID uuid) { + if (!UuidUtils.isUProtocol(uuid)) { + throw new ValidationException("Invalid UUIDv7 Version"); + } } } } diff --git a/src/main/java/org/eclipse/uprotocol/validation/ValidationException.java b/src/main/java/org/eclipse/uprotocol/validation/ValidationException.java new file mode 100644 index 00000000..79cc11f6 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/validation/ValidationException.java @@ -0,0 +1,64 @@ +/** + * SPDX-FileCopyrightText: 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.uprotocol.validation; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Indicates an error that has occurred during validation of a uProtocol type. + */ +public class ValidationException extends RuntimeException { + + private static final long serialVersionUID = 1L; + private final List causes; + + /** + * Creates a new exception for an error message. + * + * @param message The message. + */ + public ValidationException(String message) { + super(message); + this.causes = List.of(); + } + + /** + * Creates a new exception for multiple causes. + * + * @param causes The causes for the validation failure. + */ + public ValidationException(List causes) { + super("Multiple validation errors"); + this.causes = List.copyOf(causes); + } + + @Override + public String getMessage() { + if (causes.isEmpty()) { + return super.getMessage(); + } + return causes.stream() + .map(Exception::getMessage) + .collect(Collectors.joining(",")); + } + + /** + * Gets the causes of this exception. + * + * @return An unmodifiable view of the causes. + */ + public final List getCauses() { + return causes; + } +} diff --git a/src/main/java/org/eclipse/uprotocol/validation/ValidationResult.java b/src/main/java/org/eclipse/uprotocol/validation/ValidationResult.java deleted file mode 100644 index b34c1ea4..00000000 --- a/src/main/java/org/eclipse/uprotocol/validation/ValidationResult.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.eclipse.uprotocol.validation; - -import org.eclipse.uprotocol.v1.UStatus; -import org.eclipse.uprotocol.v1.UCode; - -import java.util.Objects; - -/** - * Class wrapping a ValidationResult of success or failure wrapping the value of - * a google.rpc.Status. - */ -public abstract class ValidationResult { - - public static final UStatus STATUS_SUCCESS = UStatus.newBuilder().setCode(UCode.OK).setMessage("OK").build(); - - private static final ValidationResult SUCCESS = new Success(); - - private ValidationResult() { - } - - public abstract UStatus toStatus(); - - public abstract boolean isSuccess(); - - public boolean isFailure() { - return !isSuccess(); - } - - public abstract String getMessage(); - - /** - * Implementation for failure, wrapping the message. - */ - private static class Failure extends ValidationResult { - private final String message; - - private Failure(String message) { - this.message = Objects.requireNonNullElse(message, "Validation Failed."); - } - - @Override - public UStatus toStatus() { - return UStatus.newBuilder().setCode(UCode.INVALID_ARGUMENT).setMessage(message).build(); - } - - @Override - public boolean isSuccess() { - return false; - } - - @Override - public String getMessage() { - return message; - } - - @Override - public String toString() { - return "ValidationResult.Failure(" + "message='" + message + '\'' + ')'; - } - } - - /** - * Implementation for success, wrapping a UStatus with Code 0 for success. - */ - private static class Success extends ValidationResult { - - @Override - public UStatus toStatus() { - return STATUS_SUCCESS; - } - - @Override - public boolean isSuccess() { - return true; - } - - @Override - public String getMessage() { - return ""; - } - - @Override - public String toString() { - return "ValidationResult.Success()"; - } - } - - public static ValidationResult success() { - return SUCCESS; - } - - public static ValidationResult failure(String message) { - return new Failure(message); - } - -} diff --git a/src/main/java/org/eclipse/uprotocol/validation/ValidationUtils.java b/src/main/java/org/eclipse/uprotocol/validation/ValidationUtils.java new file mode 100644 index 00000000..0c84bb57 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/validation/ValidationUtils.java @@ -0,0 +1,52 @@ +/** + * SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.uprotocol.validation; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public final class ValidationUtils { + + private ValidationUtils() { + // Utility class + } + + /** + * Collects all exception thrown by checks performed on a given subject. + * + * @param The type of the subject. + * @param subject The subject to perform checks on. + * @param checks The validation checks to perform. + * @return A list of exceptions thrown during validation. + */ + @SafeVarargs + public static List collectErrors(T subject, Consumer... checks) { + Objects.requireNonNull(subject); + Objects.requireNonNull(checks); + + return Arrays.stream(checks) + .map(check -> { + try { + check.accept(subject); + return null; // No exception = valid + } catch (Exception e) { + return e; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } +} diff --git a/src/test/java/org/eclipse/uprotocol/communication/TestUTransport.java b/src/test/java/org/eclipse/uprotocol/communication/TestUTransport.java index ba2031df..410c8c90 100644 --- a/src/test/java/org/eclipse/uprotocol/communication/TestUTransport.java +++ b/src/test/java/org/eclipse/uprotocol/communication/TestUTransport.java @@ -32,7 +32,7 @@ import org.eclipse.uprotocol.v1.UMessageType; import org.eclipse.uprotocol.v1.UStatus; import org.eclipse.uprotocol.v1.UUri; -import org.eclipse.uprotocol.validation.ValidationResult; +import org.eclipse.uprotocol.validation.ValidationException; import com.google.protobuf.InvalidProtocolBufferException; @@ -85,9 +85,16 @@ public TestUTransport(UUri source) { @Override public CompletionStage send(UMessage message) { + if (message == null) { + return CompletableFuture.completedFuture(UStatus.newBuilder() + .setCode(UCode.INVALID_ARGUMENT) + .setMessage("Message cannot be null") + .build()); + } UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes()); - - if ( (message == null) || validator.validate(message.getAttributes()) != ValidationResult.success()) { + try { + validator.validate(message.getAttributes()); + } catch (ValidationException e) { return CompletableFuture.completedFuture(UStatus.newBuilder() .setCode(UCode.INVALID_ARGUMENT) .setMessage("Invalid message attributes") diff --git a/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributeValidatorTest.java b/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributeValidatorTest.java index 2c98da10..c35fb49c 100644 --- a/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributeValidatorTest.java +++ b/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributeValidatorTest.java @@ -1,5 +1,18 @@ +/** + * SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + */ package org.eclipse.uprotocol.transport.validator; +import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -13,7 +26,7 @@ import org.eclipse.uprotocol.transport.validate.UAttributesValidator; import org.eclipse.uprotocol.uuid.factory.UuidFactory; import org.eclipse.uprotocol.v1.UUri; -import org.eclipse.uprotocol.validation.ValidationResult; +import org.eclipse.uprotocol.validation.ValidationException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -40,8 +53,7 @@ public void testUAttributeValidatorHappyPath() { UMessage message = UMessageBuilder.publish(buildTopicUUri()).build(); UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes()); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isSuccess()); + validator.validate(message.getAttributes()); assertEquals(validator.toString(), "UAttributesValidator.Publish"); } @@ -51,8 +63,7 @@ public void testUAttributeValidatorNotification() { UMessage message = UMessageBuilder.notification(buildTopicUUri(), buildDefaultUUri()).build(); UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes()); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isSuccess()); + validator.validate(message.getAttributes()); assertEquals(validator.toString(), "UAttributesValidator.Notification"); } @@ -62,8 +73,7 @@ public void testUAttributeValidatorRequest() { UMessage message = UMessageBuilder.request(buildDefaultUUri(), buildMethodUUri(), 1000).build(); UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes()); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isSuccess()); + validator.validate(message.getAttributes()); assertEquals(validator.toString(), "UAttributesValidator.Request"); } @@ -78,10 +88,8 @@ public void testUAttributeValidatorResponse() { .build(); UAttributesValidator validator = UAttributesValidator.getValidator(response.getAttributes()); - ValidationResult result = validator.validate(response.getAttributes()); - assertTrue(result.isSuccess()); + validator.validate(response.getAttributes()); assertEquals(validator.toString(), "UAttributesValidator.Response"); - assertEquals(result.getMessage(), ""); } @Test @@ -91,8 +99,7 @@ public void testUAttributeValidatorResponseWithRequestAttributes() { UMessage response = UMessageBuilder.response(request.getAttributes()).build(); UAttributesValidator validator = UAttributesValidator.getValidator(response.getAttributes()); - ValidationResult result = validator.validate(response.getAttributes()); - assertTrue(result.isSuccess()); + validator.validate(response.getAttributes()); assertEquals(validator.toString(), "UAttributesValidator.Response"); } @@ -102,10 +109,13 @@ public void testUAttributeValidatorRequestWithPublishValidator() { UMessage message = UMessageBuilder.request(buildDefaultUUri(), buildMethodUUri(), 1000).build(); UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(message.getAttributes())); assertEquals(validator.toString(), "UAttributesValidator.Publish"); - assertEquals(result.getMessage(), "Wrong Attribute Type [UMESSAGE_TYPE_REQUEST],Sink should not be present"); + assertEquals( + result.getMessage(), + "Wrong Attribute Type [UMESSAGE_TYPE_REQUEST],Sink should not be present"); } @Test @@ -114,8 +124,9 @@ public void testUAttributeValidatorPublishWithNotificationValidator() { UMessage message = UMessageBuilder.publish(buildTopicUUri()).build(); UAttributesValidator validator = UAttributesValidator.Validators.NOTIFICATION.validator(); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(message.getAttributes())); assertEquals(validator.toString(), "UAttributesValidator.Notification"); assertEquals(result.getMessage(), "Wrong Attribute Type [UMESSAGE_TYPE_PUBLISH],Missing Sink"); } @@ -127,8 +138,9 @@ public void testUAttributeValidatorResponseWithRequestValidator() { UMessage response = UMessageBuilder.response(request.getAttributes()).build(); UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); - ValidationResult result = validator.validate(response.getAttributes()); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(response.getAttributes())); assertEquals(validator.toString(), "UAttributesValidator.Request"); assertEquals( result.getMessage(), @@ -143,8 +155,9 @@ public void testUAttributeValidatorNotificationWithResponseValidator() { UMessage message = UMessageBuilder.notification(buildTopicUUri(), buildDefaultUUri()).build(); UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(message.getAttributes())); assertEquals(validator.toString(), "UAttributesValidator.Response"); assertEquals( result.getMessage(), @@ -166,8 +179,9 @@ public void testUAttributeValidatorRequestMissingSink() { .build(); UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - ValidationResult result = validator.validate(attributes); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); assertEquals(validator.toString(), "UAttributesValidator.Request"); assertEquals(result.getMessage(), "Invalid Sink Uri"); } @@ -183,8 +197,9 @@ public void testUAttributeValidatorRequestInvalidPermissionLevel() { .build(); UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes()); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(message.getAttributes())); assertEquals(validator.toString(), "UAttributesValidator.Request"); assertEquals(result.getMessage(), "Invalid Permission Level"); } @@ -200,8 +215,7 @@ public void testUAttributeValidatorRequestValidPermissionLevel() { .build(); UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes()); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isSuccess()); + validator.validate(message.getAttributes()); assertFalse(validator.isExpired(message.getAttributes())); assertEquals(validator.toString(), "UAttributesValidator.Request"); } @@ -212,8 +226,9 @@ public void testUAttributeValidatorRequestInvalidTTL() { UMessage message = UMessageBuilder.publish(buildTopicUUri()).withTtl(-1).build(); UAttributesValidator validator = UAttributesValidator.getValidator(message.getAttributes()); - ValidationResult result = validator.validate(message.getAttributes()); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(message.getAttributes())); assertFalse(validator.isExpired(message.getAttributes())); assertEquals(validator.toString(), "UAttributesValidator.Publish"); assertEquals(result.getMessage(), "Invalid TTL [-1]"); @@ -249,8 +264,9 @@ public void testUAttributeValidatorPublishWithReqId() { .build(); UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - ValidationResult result = validator.validate(attributes); - assertTrue(result.isFailure()); + ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); assertEquals(validator.toString(), "UAttributesValidator.Publish"); assertEquals(result.getMessage(), "Message should not have a reqid"); } @@ -261,9 +277,10 @@ public void testUAttributeValidatorNotificationMissingSink() { final UMessage message = UMessageBuilder.notification(buildTopicUUri(), buildDefaultUUri()).build(); final UAttributes attributes = UAttributes.newBuilder().mergeFrom(message.getAttributes()).clearSink().build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Notification"); assertEquals(result.getMessage(), "Missing Sink"); } @@ -277,9 +294,10 @@ public void testUAttributeValidatorNotificationDefaultSink() { .setSink(UUri.getDefaultInstance()) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Notification"); assertEquals(result.getMessage(), "Missing Sink"); } @@ -295,9 +313,10 @@ public void testUAttributeValidatorNotificationDefaultResourceId() { .setPriority(UPriority.UPRIORITY_CS1) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Notification"); assertEquals(result.getMessage(), "Invalid Sink Uri"); } @@ -311,9 +330,10 @@ public void testUAttributeValidatorValidatePriorityLessThanCS0() { .setPriority(UPriority.UPRIORITY_UNSPECIFIED) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Publish"); assertEquals(result.getMessage(), "Invalid UPriority [UPRIORITY_UNSPECIFIED]"); } @@ -325,9 +345,10 @@ public void testUAttributeValidatorValidatePriorityIsCS0() { final UAttributes attributes = UAttributes.newBuilder(). mergeFrom(message.getAttributes()).setPriority(UPriority.UPRIORITY_CS0).build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Publish"); assertEquals(result.getMessage(), "Invalid UPriority [UPRIORITY_CS0]"); } @@ -338,9 +359,10 @@ public void testUAttributeValidatorValidateIdMissing() { final UMessage message = UMessageBuilder.publish(buildTopicUUri()).build(); final UAttributes attributes = UAttributes.newBuilder().mergeFrom(message.getAttributes()).clearId().build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Publish"); assertEquals(result.getMessage(), "Missing id"); } @@ -354,9 +376,10 @@ public void testUAttributeValidatorValidateIdDefault() { .setId(UUID.getDefaultInstance()) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Publish"); assertEquals(result.getMessage(), "Attributes must contain valid uProtocol UUID in id property"); } @@ -370,9 +393,10 @@ public void testUAttributeValidatorValidateSinkNotEmpty() { .setSink(buildDefaultUUri()) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Publish"); assertEquals(result.getMessage(), "Sink should not be present"); } @@ -383,9 +407,10 @@ public void testUAttributeValidatorValidateSinkMissing() { final UMessage message = UMessageBuilder.request(buildDefaultUUri(), buildMethodUUri(), 1000).build(); final UAttributes attributes = UAttributes.newBuilder().mergeFrom(message.getAttributes()).clearSink().build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Request"); assertEquals(result.getMessage(), "Missing Sink"); } @@ -401,9 +426,10 @@ public void testUAttributeValidatorValidateTtlLessThanZero() { .setType(UMessageType.UMESSAGE_TYPE_REQUEST) .setPriority(UPriority.UPRIORITY_CS4).build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Request"); assertEquals(result.getMessage(), "Invalid TTL [-1]"); } @@ -417,9 +443,10 @@ public void testUAttributeValidatorValidatePriorityLessThanCS4() { .setPriority(UPriority.UPRIORITY_CS3) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Request"); assertEquals(result.getMessage(), "Invalid UPriority [UPRIORITY_CS3]"); } @@ -431,9 +458,10 @@ public void testUAttributeValidatorValidateSinkResponseMissing() { final UMessage response = UMessageBuilder.response(request.getAttributes()).build(); final UAttributes attributes = UAttributes.newBuilder().mergeFrom(response.getAttributes()).clearSink().build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Response"); assertEquals(result.getMessage(), "Missing Sink"); } @@ -448,9 +476,10 @@ public void testUAttributeValidatorValidateSinkResponseDefault() { .setSink(UUri.getDefaultInstance()) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Response"); assertEquals(result.getMessage(), "Missing Sink"); } @@ -469,9 +498,10 @@ public void testUAttributeValidatorValidateSinkResponseDefaultResourceId() { .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Response"); assertEquals(result.getMessage(), "Invalid Sink Uri"); } @@ -486,9 +516,10 @@ public void testUAttributeValidatorValidateReqIdMissing() { .clearReqid() .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Response"); assertEquals(result.getMessage(), "Missing correlationId"); } @@ -503,9 +534,10 @@ public void testUAttributeValidatorValidateReqIdDefault() { .setReqid(UUID.getDefaultInstance()) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Response"); assertEquals(result.getMessage(), "Missing correlationId"); } @@ -520,9 +552,10 @@ public void testUAttributeValidatorValidateReqIdInvalid() { .setReqid(UUID.newBuilder().setLsb(0xbeadbeef).setMsb(0xdeadbeef)) .build(); final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); - final ValidationResult result = validator.validate(attributes); + final ValidationException result = assertThrows( + ValidationException.class, + () -> validator.validate(attributes)); - assertTrue(result.isFailure()); assertEquals(validator.toString(), "UAttributesValidator.Response"); assertEquals(result.getMessage(), "Invalid correlation UUID"); } diff --git a/src/test/java/org/eclipse/uprotocol/uuid/factory/UUIDFactoryTest.java b/src/test/java/org/eclipse/uprotocol/uuid/factory/UUIDFactoryTest.java index 9077e890..2e7ca849 100644 --- a/src/test/java/org/eclipse/uprotocol/uuid/factory/UUIDFactoryTest.java +++ b/src/test/java/org/eclipse/uprotocol/uuid/factory/UUIDFactoryTest.java @@ -253,7 +253,4 @@ void testCreateUuidv7WithTheSameTimeToConfirmTheUuidsAreNotTheSame() { assertNotEquals(uuid, uuid1); assertEquals(UuidUtils.getTime(uuid1).get(), UuidUtils.getTime(uuid).get()); } - - } - diff --git a/src/test/java/org/eclipse/uprotocol/uuid/validator/UuidValidatorTest.java b/src/test/java/org/eclipse/uprotocol/uuid/validator/UuidValidatorTest.java index c9c79433..c84d92a3 100644 --- a/src/test/java/org/eclipse/uprotocol/uuid/validator/UuidValidatorTest.java +++ b/src/test/java/org/eclipse/uprotocol/uuid/validator/UuidValidatorTest.java @@ -17,9 +17,7 @@ import org.eclipse.uprotocol.uuid.serializer.UuidSerializer; import org.eclipse.uprotocol.uuid.validate.UuidValidator; import org.eclipse.uprotocol.v1.UUID; -import org.eclipse.uprotocol.v1.UCode; -import org.eclipse.uprotocol.v1.UStatus; -import org.eclipse.uprotocol.validation.ValidationResult; +import org.eclipse.uprotocol.validation.ValidationException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -32,34 +30,35 @@ public class UuidValidatorTest { void testValidatorWithGoodUuid() { //final UuidValidator validator = new UuidValidator(); final UUID uuid = UuidFactory.Factories.UPROTOCOL.factory().create(); - final UStatus status = UuidValidator.getValidator(uuid).validate(uuid); - assertEquals(ValidationResult.STATUS_SUCCESS, status); + UuidValidator.getValidator(uuid).validate(uuid); } @Test @DisplayName("Test Good uuid Check") void testGoodUuidString() { - final UStatus status = UuidValidator.Validators.UPROTOCOL.validator() - .validate(UuidFactory.Factories.UPROTOCOL.factory().create()); - assertEquals(status, ValidationResult.STATUS_SUCCESS); + final var uuid = UuidFactory.Factories.UPROTOCOL.factory().create(); + UuidValidator.Validators.UPROTOCOL.validator().validate(uuid); } @Test @DisplayName("Test fetching the invalid Validator for when UUID passed is garbage") void testInvalidUuid() { final UUID uuid = UUID.newBuilder().setMsb(0L).setLsb(0L).build(); - final UStatus status = UuidValidator.getValidator(uuid).validate(uuid); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); - assertEquals("Invalid UUID Version,Invalid UUID Time", status.getMessage()); + final UuidValidator validator = UuidValidator.getValidator(uuid); + final var validationException = assertThrows(ValidationException.class, () -> validator.validate(uuid)); + assertEquals( + "Invalid UUID Version,Invalid UUID Time", + validationException.getMessage()); } @Test @DisplayName("Test invalid time uuid") void testInvalidTimeUuid() { final UUID uuid = UuidFactory.Factories.UPROTOCOL.factory().create(Instant.ofEpochSecond(0)); - final UStatus status = UuidValidator.Validators.UPROTOCOL.validator().validate(uuid); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); - assertEquals("Invalid UUID Time", status.getMessage()); + final var validationException = assertThrows( + ValidationException.class, + () -> UuidValidator.Validators.UPROTOCOL.validator().validate(uuid)); + assertEquals("Invalid UUID Time", validationException.getMessage()); } @Test @@ -67,9 +66,7 @@ void testInvalidTimeUuid() { void testUuidv7WithInvalidUuids() { final UuidValidator validator = UuidValidator.Validators.UPROTOCOL.validator(); assertNotNull(validator); - final UStatus status = validator.validate(null); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); - assertEquals("Invalid UUIDv7 Version,Invalid UUID Time", status.getMessage()); + assertThrows(NullPointerException.class, () -> validator.validate(null)); } @Test @@ -77,6 +74,7 @@ void testUuidv7WithInvalidUuids() { void testUuidv7WithInvalidTypes() { final UUID uuidv6 = UuidFactory.Factories.UUIDV6.factory().create(); final UUID uuid = UUID.newBuilder().setMsb(0L).setLsb(0L).build(); + final java.util.UUID uuid_java = java.util.UUID.randomUUID(); final UUID uuidv4 = UUID.newBuilder().setMsb(uuid_java.getMostSignificantBits()) .setLsb(uuid_java.getLeastSignificantBits()).build(); @@ -84,17 +82,16 @@ void testUuidv7WithInvalidTypes() { final UuidValidator validator = UuidValidator.Validators.UPROTOCOL.validator(); assertNotNull(validator); - final UStatus status = validator.validate(uuidv6); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); - assertEquals("Invalid UUIDv7 Version", status.getMessage()); + var validationException = assertThrows(ValidationException.class, () -> validator.validate(uuidv6)); + assertEquals("Invalid UUIDv7 Version", validationException.getMessage()); - final UStatus status1 = validator.validate(uuid); - assertEquals(UCode.INVALID_ARGUMENT, status1.getCode()); - assertEquals("Invalid UUIDv7 Version,Invalid UUID Time", status1.getMessage()); + validationException = assertThrows(ValidationException.class, () -> validator.validate(uuid)); + assertEquals( + "Invalid UUIDv7 Version,Invalid UUID Time", + validationException.getMessage()); - final UStatus status2 = validator.validate(uuidv4); - assertEquals(UCode.INVALID_ARGUMENT, status2.getCode()); - assertEquals("Invalid UUIDv7 Version,Invalid UUID Time", status2.getMessage()); + validationException = assertThrows(ValidationException.class, () -> validator.validate(uuidv4)); + assertEquals("Invalid UUIDv7 Version,Invalid UUID Time", validationException.getMessage()); } @Test @@ -105,10 +102,9 @@ void testGoodUuidv6() { UuidValidator validator = UuidValidator.getValidator(uuid); assertNotNull(validator); assertTrue(UuidUtils.isUuidv6(uuid)); - assertEquals(UCode.OK, validator.validate(uuid).getCode()); + validator.validate(uuid); } - @Test @DisplayName("Test UUIDv6 with bad variant") void testUuidv6WithBadVariant() { @@ -116,9 +112,10 @@ void testUuidv6WithBadVariant() { assertFalse(uuid.equals(UUID.getDefaultInstance())); final UuidValidator validator = UuidValidator.getValidator(uuid); assertNotNull(validator); - final UStatus status = validator.validate(uuid); - assertEquals("Invalid UUID Version,Invalid UUID Time", status.getMessage()); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); + final var validationException = assertThrows(ValidationException.class, () -> validator.validate(uuid)); + assertEquals( + "Invalid UUID Version,Invalid UUID Time", + validationException.getMessage()); } @Test @@ -128,9 +125,10 @@ void testUuidv6WithInvalidUuid() { final UUID uuid = UUID.newBuilder().setMsb(9 << 12).setLsb(0L).build(); final UuidValidator validator = UuidValidator.Validators.UUIDV6.validator(); assertNotNull(validator); - final UStatus status = validator.validate(uuid); - assertEquals("Not a UUIDv6 Version,Invalid UUID Time", status.getMessage()); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); + final var validationException = assertThrows(ValidationException.class, () -> validator.validate(uuid)); + assertEquals( + "Not a UUIDv6 Version,Invalid UUID Time", + validationException.getMessage()); } @@ -139,9 +137,7 @@ void testUuidv6WithInvalidUuid() { void testUuidv6WithNullUuid() { final UuidValidator validator = UuidValidator.Validators.UUIDV6.validator(); assertNotNull(validator); - final UStatus status = validator.validate(null); - assertEquals("Not a UUIDv6 Version,Invalid UUID Time", status.getMessage()); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); + assertThrows(NullPointerException.class, () -> validator.validate(null)); } @Test @@ -150,9 +146,7 @@ void testUuidv6WithUuidv7() { final UUID uuid = UuidFactory.Factories.UPROTOCOL.factory().create(); final UuidValidator validator = UuidValidator.Validators.UUIDV6.validator(); assertNotNull(validator); - final UStatus status = validator.validate(uuid); - assertEquals("Not a UUIDv6 Version", status.getMessage()); - assertEquals(UCode.INVALID_ARGUMENT, status.getCode()); + final var validationException = assertThrows(ValidationException.class, () -> validator.validate(uuid)); + assertEquals("Not a UUIDv6 Version", validationException.getMessage()); } - } diff --git a/src/test/java/org/eclipse/uprotocol/validation/ValidationExceptionTest.java b/src/test/java/org/eclipse/uprotocol/validation/ValidationExceptionTest.java new file mode 100644 index 00000000..b6356b10 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/validation/ValidationExceptionTest.java @@ -0,0 +1,45 @@ +/** + * SPDX-FileCopyrightText: 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.eclipse.uprotocol.validation; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.common.truth.Truth; + +class ValidationExceptionTest { + + @Test + void testGetCauses() { + final List causes = List.of( + new ValidationException("First cause"), + new IllegalArgumentException("Second cause") + ); + ValidationException exception = new ValidationException(causes); + Truth.assertThat(exception.getCauses()).containsExactlyElementsIn(causes); + } + + @Test + void testGetMessage() { + final List causes = List.of( + new ValidationException("First cause"), + new IllegalArgumentException("Second cause") + ); + ValidationException exception = new ValidationException(causes); + String errorMessages = exception.getMessage(); + assertEquals("First cause,Second cause", errorMessages); + } +}