diff --git a/README.adoc b/README.adoc index 53c10e78..f3781eb8 100644 --- a/README.adoc +++ b/README.adoc @@ -1,17 +1,11 @@ -image:https://github.com/eclipse-uprotocol/.github/raw/main/logo/uprotocol_logo.png[alt=uProtocol,640] - -image:https://img.shields.io/badge/License-Apache%202.0-blue.svg[License,link=https://opensource.org/licenses/Apache-2.0] - = Eclipse uProtocol Java SDK :toc: == Overview -The main object of this module is to enable constructing and deconstructing uProtocol CloudEvents. - -The core module contains functional factory methods for creating CloudEvents as well as functional factory methods that make it more intuitive to create URIs that are used to configure source and sink (destination) elements in the uProtocol CloudEvents. +The purpose of this module is to provide language specific code that builds the various data types defined in . The SDK also defines https://github.com/eclipse-uprotocol/uprotocol-spec/tree/main[uProtocol Specifications]. -This module contains the data model structures as well as core functionality for building uProtocol CloudEvents and URIs for sink and source attributes. +The module contains factory methods and validators for all data types used in uProtocol. The SDKs are then used by the code generators to auto-populate service stubs with generated code that builds CloudEvents. For more information on auto-generating service stubs, please refer to http://github.com/eclipse-uprotocol/uprotocol[uProtocol Main Project] @@ -28,57 +22,29 @@ The SDKs are then used by the code generators to auto-populate service stubs wit ---- +=== Using the sdk -=== UriFactory - -Matches the uProtocol URI Format. and is used to define source and sink (destination) attributes of uProtocol CloudEvents. -The factory builds URIs. - -URI is used as a method to uniquely identify devices, services, and resources on the network. - -*An Uri is built from the following elements:* - -* *UAuthority* - represents the device and domain of the software, the deployment. You can specify local or remote options. -* *UEntity* - The Software Entity defines the software name and version. -* *UResource* - The resource of the software can be a service name, and instance in the service and the name of the protobuf IDL message. - -==== UAuthority - -An Authority consists of a device and a domain per uProtocol URI format. - -An Authority represents the deployment location of a specific Software Entity. - -==== UEntity - uE - -An Software Entity is a piece of software deployed somewhere on a device. The uE is used in the source and sink parts of communicating software. - -A uE that *publishes* events is a *Service* role. - -A uE that *consumes* events is an *Application* role. - -A uE may combine bother Service and Application roles. - - -==== UResource - -A service API - defined in the uE - has Resources and Methods. Both of these are represented by the UResource class. - -An UResource is something that can be manipulated/controlled/exposed by a service. - -Resources are unique when prepended with UAuthority that represents the device and Software Entity that represents the service. - -An Resource represents a resource from a Service such as "door" and an optional specific instance such as "front_left". -In addition, it can optionally contain the name of the resource Message type, such as "Door". +The SDK is composed of 4 main packages as shown in <> below: -The Message type matches the protobuf service IDL that defines structured data types. A message is a data structure type used to define data that is passed in events and rpc methods. +.SDK Packages +[#sdk-packages,width=100%,cols="15%,25%,60%"] +|=== +| Package | https://github.com/eclipse-uprotocol/uprotocol-spec[uprotocol-spec] | Purpose -=== CloudEventFactory -Factory class that builds the various types of CloudEvents for uProtocol (publish, notification, request, response) +| link:src/main/java/org/eclipse/uprotocol/uri/README.adoc[`uuri`] +| https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/basics/uri.adoc[URI, UAthority, UEntity, UResource] +| Uniform Resource Identifier (RFC3986) used to address things (devices, software, methods, topics, etc...) on the network -== Examples +| link:src/main/java/org/eclipse/uprotocol/cloudevent/README.adoc[`cloudevent`] +| https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l1/cloudevents.adoc[uProtocol CloudEvents] +| Common way to represent uProtocol messages using CloudEvent data model -The SDK contains comprehensive tests, the best place to look at how all the APIs are used are at: +| link:src/main/java/org/eclipse/uprotocol/uuid/README.adoc[`uuid`] +| https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/basics/uuid.adoc[uProtocol UUIDs] +| Identifier used to uniquely identify messages that are sent between devices. also includes timestamp for the message -* link:src/test/java/org/eclipse/uprotocol/uri/factory/UriFactoryTest.java[UriFactoryTest.java] +| link:src/main/java/org/eclipse/uprotocol/utransport/README.adoc[`utransport`] +| https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l1/README.adoc[uP-L1 Specifications] +| Interface (and data model) used for bidirectional point-2-point communication between uEs. Interface is to be implemented by the different communication technologies (ex. Binder, MQTT, Zenoh, SOME/IP, DDS, HTTP, etc…​) -* link:src/test/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactoryTest.java[CloudEventFactoryTest.java] +|=== \ No newline at end of file diff --git a/pom.xml b/pom.xml index e0152045..e4119d0f 100644 --- a/pom.xml +++ b/pom.xml @@ -132,6 +132,27 @@ + + + io.cloudevents + cloudevents-protobuf + 2.4.2 + + + + + com.google.errorprone + error_prone_annotations + 2.11.0 + + + + + org.checkerframework + checker-qual + 3.12.0 + + com.google.protobuf protobuf-bom @@ -153,7 +174,7 @@ nl.jqno.equalsverifier equalsverifier - 3.10.1 + 3.14.1 test @@ -173,6 +194,7 @@ nl.jqno.equalsverifier equalsverifier + 3.14.1 test @@ -188,7 +210,7 @@ io.cloudevents cloudevents-protobuf - 2.2.0 + @@ -223,14 +245,6 @@ - - com.google.truth.extensions - truth-proto-extension - 1.1 - test - - - com.github.f4b6a3 @@ -238,6 +252,19 @@ 5.1.2 + + commons-validator + commons-validator + 1.7 + + + org.eclipse.uprotocol + uprotocol-core-api + 1.4.9-SNAPSHOT + system + ${project.basedir}/uprotocol-core-api-1.4.9-SNAPSHOT.jar + + \ No newline at end of file diff --git a/src/main/java/org/eclipse/uprotocol/cloudevent/README.adoc b/src/main/java/org/eclipse/uprotocol/cloudevent/README.adoc new file mode 100644 index 00000000..cf1a4aea --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/cloudevent/README.adoc @@ -0,0 +1,21 @@ += uProtocol CloudEvents +:toc: +:sectnums: + + +== Overview + +https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l1/cloudevents.adoc[uProtocol CloudEvents] is a common message envelope that could be used to carry way to represent uProtocol transport layer information `UUri` (source), `UPayload`, and `UAttributes`. `CloudEvents` are used by a number of Device-2-Cloud and Cloud-2-Device based transports such as MQTT and HTTP, however it could also be used by any transport (ex. Binder). + +NOTE: CloudEvent is not, nor was not, meant to be _the_ only message format used below or above the transport layer. + +=== CloudEventFactory +Factory class that builds the various types of CloudEvents for uProtocol (publish, notification, request, response) + +== Examples + +The SDK contains comprehensive tests, the best place to look at how all the APIs are used are at: + +* link:src/test/java/org/eclipse/uprotocol/uri/factory/UriFactoryTest.java[UriFactoryTest.java] + +* link:src/test/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactoryTest.java[CloudEventFactoryTest.java] diff --git a/src/main/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventType.java b/src/main/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventType.java index eaebd295..9ca06f43 100644 --- a/src/main/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventType.java +++ b/src/main/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventType.java @@ -29,7 +29,6 @@ */ public enum UCloudEventType { PUBLISH ("pub.v1"), - FILE ("file.v1"), REQUEST ("req.v1"), RESPONSE ("res.v1"); diff --git a/src/main/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactory.java b/src/main/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactory.java index 1a93b297..b7c6e545 100644 --- a/src/main/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactory.java +++ b/src/main/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactory.java @@ -23,8 +23,7 @@ import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.eclipse.uprotocol.uri.factory.UriFactory; + import com.google.protobuf.Any; import com.google.protobuf.Empty; import com.google.rpc.Code; @@ -159,8 +158,7 @@ static String generateCloudEventId() { * * @param id Event unique identifier. * @param source Identifies who is sending this event in the format of a uProtocol URI that - * can be built from a {@link UUri} object using - * the {@link UriFactory} + * can be built from a {@link UUri} object. * @param protoPayloadBytes The serialized Event data with the content type of "application/x-protobuf". * @param protoPayloadSchema The schema of the proto payload bytes, for example you can use protoPayload.getTypeUrl() on your service/app object. * @param attributes Additional cloud event attributes that can be passed in. All attributes are optional and will be added only if they diff --git a/src/main/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidator.java b/src/main/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidator.java index a883e9a8..95cd593d 100644 --- a/src/main/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidator.java +++ b/src/main/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidator.java @@ -21,15 +21,16 @@ package org.eclipse.uprotocol.cloudevent.validate; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; -import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.eclipse.uprotocol.uri.factory.UriFactory; import com.google.rpc.Code; import com.google.rpc.Status; import io.cloudevents.CloudEvent; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; +import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.validation.ValidationResult; +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.uri.validator.UriValidator; import java.util.Optional; import java.util.stream.Collectors; @@ -53,15 +54,20 @@ public static CloudEventValidator getValidator(CloudEvent cloudEvent){ if (maybeType.isEmpty()) { return Validators.PUBLISH.validator(); } + + CloudEventValidator validator; switch (maybeType.get()){ - case FILE: - return Validators.FILE.validator(); case RESPONSE: - return Validators.RESPONSE.validator(); + validator = Validators.RESPONSE.validator(); + break; case REQUEST: - return Validators.REQUEST.validator(); + validator = Validators.REQUEST.validator(); + break; + default: + validator = Validators.PUBLISH.validator(); + break; } - return Validators.PUBLISH.validator(); + return validator; } /** @@ -70,7 +76,6 @@ public static CloudEventValidator getValidator(CloudEvent cloudEvent){ public enum Validators { PUBLISH (new Publish()), NOTIFICATION (new Notification()), - FILE (new File()), REQUEST (new Request()), RESPONSE (new Response()); @@ -141,42 +146,33 @@ public ValidationResult validateSink(CloudEvent cloudEvent) { } /** - * Validate an Uri for an Software Entity must have an authority in the case of a remote uri, and must contain + * Validate an UriPart for an Software Entity must have an authority in the case of a microRemote uri, and must contain * the name of the USE. * @param uri uri string to validate. * @return Returns the ValidationResult containing a success or a failure with the error message. */ public static ValidationResult validateUEntityUri(String uri) { - UUri Uri = UriFactory.parseFromUri(uri); + UUri Uri = LongUriSerializer.instance().deserialize(uri); return validateUEntityUri(Uri); } public static ValidationResult validateUEntityUri(UUri Uri) { - final UAuthority uAuthority = Uri.uAuthority(); - if (uAuthority.isMarkedRemote()) { - if (uAuthority.device().isEmpty()) { - return ValidationResult.failure("Uri is configured to be remote and is missing uAuthority device name."); - } - } - if (Uri.uEntity().name().isBlank()) { - return ValidationResult.failure("Uri is missing uSoftware Entity name."); - } - return ValidationResult.success(); + return UriValidator.validate(Uri); } - /** - * Validate a Uri that is to be used as a topic in publish scenarios for events such as publish, file and notification. - * @param uri String Uri to validate. +/** + * Validate a UriPart that is to be used as a topic in publish scenarios for events such as publish, file and notification. + * @param uri String UriPart to validate. * @return Returns the ValidationResult containing a success or a failure with the error message. */ public static ValidationResult validateTopicUri(String uri) { - UUri Uri = UriFactory.parseFromUri(uri); + UUri Uri = LongUriSerializer.instance().deserialize(uri); return validateTopicUri(Uri); } /** - * Validate a Uri that is to be used as a topic in publish scenarios for events such as publish, file and notification. - * @param Uri Uri to validate. + * Validate a UriPart that is to be used as a topic in publish scenarios for events such as publish, file and notification. + * @param Uri UriPart to validate. * @return Returns the ValidationResult containing a success or a failure with the error message. */ public static ValidationResult validateTopicUri(UUri Uri) { @@ -184,30 +180,30 @@ public static ValidationResult validateTopicUri(UUri Uri) { if (validationResult.isFailure()) { return validationResult; } - final UResource uResource = Uri.uResource(); - if (uResource.name().isBlank()) { - return ValidationResult.failure("Uri is missing uResource name."); + final UResource uResource = Uri.getResource(); + if (uResource.getName().isBlank()) { + return ValidationResult.failure("UriPart is missing uResource name."); } - if (uResource.message().isEmpty()) { - return ValidationResult.failure("Uri is missing Message information."); + if (uResource.getMessage().isEmpty()) { + return ValidationResult.failure("UriPart is missing Message information."); } return ValidationResult.success(); } /** - * Validate a Uri that is meant to be used as the application response topic for rpc calls.
+ * Validate a UriPart that is meant to be used as the application response topic for rpc calls.
* Used in Request source values and Response sink values. - * @param uri String Uri to validate. + * @param uri String UriPart to validate. * @return Returns the ValidationResult containing a success or a failure with the error message. */ public static ValidationResult validateRpcTopicUri(String uri) { - UUri Uri = UriFactory.parseFromUri(uri); + UUri Uri = LongUriSerializer.instance().deserialize(uri); return validateRpcTopicUri(Uri); } /** - * Validate an Uri that is meant to be used as the application response topic for rpc calls.
- * @param Uri Uri to validate. + * Validate an UriPart that is meant to be used as the application response topic for rpc calls.
+ * @param Uri UriPart to validate. * @return Returns the ValidationResult containing a success or a failure with the error message. */ public static ValidationResult validateRpcTopicUri(UUri Uri) { @@ -215,28 +211,28 @@ public static ValidationResult validateRpcTopicUri(UUri Uri) { if (validationResult.isFailure()){ return ValidationResult.failure(String.format("Invalid RPC uri application response topic. %s", validationResult.getMessage())); } - final UResource uResource = Uri.uResource(); - String topic = String.format("%s.%s", uResource.name(), uResource.instance().isPresent() ? uResource.instance().get() : "" ); + final UResource uResource = Uri.getResource(); + String topic = String.format("%s.%s", uResource.getName(), uResource.getInstance()); if (!"rpc.response".equals(topic)) { - return ValidationResult.failure("Invalid RPC uri application response topic. Uri is missing rpc.response."); + return ValidationResult.failure("Invalid RPC uri application response topic. UriPart is missing rpc.response."); } return ValidationResult.success(); } /** - * Validate a Uri that is meant to be used as an RPC method URI. Used in Request sink values and Response source values. - * @param uri String Uri to validate. + * Validate a UriPart that is meant to be used as an RPC method URI. Used in Request sink values and Response source values. + * @param uri String UriPart to validate. * @return Returns the ValidationResult containing a success or a failure with the error message. */ public static ValidationResult validateRpcMethod(String uri) { - UUri Uri = UriFactory.parseFromUri(uri); + UUri Uri = LongUriSerializer.instance().deserialize(uri); ValidationResult validationResult = validateUEntityUri(Uri); if (validationResult.isFailure()){ return ValidationResult.failure(String.format("Invalid RPC method uri. %s", validationResult.getMessage())); } - final UResource uResource = Uri.uResource(); - if (!uResource.isRPCMethod()) { - return ValidationResult.failure("Invalid RPC method uri. Uri should be the method to be called, or method from response."); + + if (!UriValidator.isRpcMethod(Uri)) { + return ValidationResult.failure("Invalid RPC method uri. UriPart should be the method to be called, or method from response."); } return ValidationResult.success(); } @@ -295,22 +291,6 @@ public String toString() { } } - /** - * Implements Validations for a CloudEvent of type File. - */ - private static class File extends Publish { - - @Override - public ValidationResult validateType(CloudEvent cloudEvent) { - return "file.v1".equals(cloudEvent.getType()) ? ValidationResult.success() : - ValidationResult.failure(String.format("Invalid CloudEvent type [%s]. CloudEvent of type File must have a type of 'file.v1'", cloudEvent.getType())); - } - - @Override - public String toString() { - return "CloudEventValidator.File"; - } - } /** * Implements Validations for a CloudEvent for RPC Request. diff --git a/src/main/java/org/eclipse/uprotocol/rpc/README.adoc b/src/main/java/org/eclipse/uprotocol/rpc/README.adoc new file mode 100644 index 00000000..5282d2e6 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/rpc/README.adoc @@ -0,0 +1,7 @@ += uProtocol Rpc Interfaces +:toc: +:sectnums: + +== Overview + +_comming soon_ diff --git a/src/main/java/org/eclipse/uprotocol/rpc/Rpc.java b/src/main/java/org/eclipse/uprotocol/rpc/RpcClient.java similarity index 50% rename from src/main/java/org/eclipse/uprotocol/rpc/Rpc.java rename to src/main/java/org/eclipse/uprotocol/rpc/RpcClient.java index 0a371dc1..78a6c592 100644 --- a/src/main/java/org/eclipse/uprotocol/rpc/Rpc.java +++ b/src/main/java/org/eclipse/uprotocol/rpc/RpcClient.java @@ -21,27 +21,27 @@ package org.eclipse.uprotocol.rpc; -import com.google.protobuf.Any; -import io.cloudevents.CloudEvent; - import java.util.concurrent.CompletableFuture; +import org.eclipse.uprotocol.transport.datamodel.UAttributes; +import org.eclipse.uprotocol.transport.datamodel.UPayload; +import org.eclipse.uprotocol.v1.UUri; + /** - * Interface for transport layers that want to implement RPC over for Layer 2. + * RpcClient is an interface used by code generators for uProtocol services defined in proto files such as + * the core uProtocol services found in https://github.com/eclipse-uprotocol/uprotocol-core-api. the interface + * provides a clean contract for all transports to implement to be able to support RPC on their platform. Each + * platform MUST implement this interface. For more details please refer to + * https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l2/README.adoc[RpcClient Specifications] */ -public interface Rpc { +public interface RpcClient { /** * Support for RPC method invocation. - * @param requestEvent req.v1 CloudEvent. - * @return Returns the CompletableFuture with the result or exception. Tamara would rather have a CompletionStage since she likes it better - * when you program to an interface and not an implementation. - */ - CompletableFuture invokeMethod(CloudEvent requestEvent); - - /** - * This is the URI of the calling client, used for routing the response back to the caller. - * @return Returns the uri of the uE invoking the rpc. + * @param topic topic of the method to be invoked (i.e. the name of the API we are calling). + * @param payload The request message to be sent to the server. + * @param attributes Metadata for the method invocation (i.e. priority, timeout, etc.) + * @return Returns the CompletableFuture with the result or exception. */ - String getResponseUri(); + CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes); } diff --git a/src/main/java/org/eclipse/uprotocol/rpc/RpcMapper.java b/src/main/java/org/eclipse/uprotocol/rpc/RpcMapper.java index 09460565..94cdf1ac 100644 --- a/src/main/java/org/eclipse/uprotocol/rpc/RpcMapper.java +++ b/src/main/java/org/eclipse/uprotocol/rpc/RpcMapper.java @@ -30,19 +30,23 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import org.eclipse.uprotocol.transport.datamodel.UPayload; + /** - * An interface that maps the returned value from uProtocol Layer 2 to the response in Layer3. + * RPC Wrapper is an interface that provides static methods to be able to wrap an RPC request with + * an RPC Response (uP-L2). APIs that return Message assumes that the payload is protobuf serialized + * com.google.protobuf.Any (USerializationHint.PROTOBUF) and will barf if anything else is passed */ public interface RpcMapper { /** - * Map a response of CompletableFuture<Any> from Link into a CompletableFuture containing the declared expected return type of the RPC method or an exception. - * @param responseFuture CompletableFuture<Any> response from Link. + * Map a response of CompletableFuture<UPayload> from Link into a CompletableFuture containing the declared expected return type of the RPC method or an exception. + * @param responseFuture CompletableFuture<UPayload> response from uTransport. * @param expectedClazz The class name of the declared expected return type of the RPC method. * @return Returns a CompletableFuture containing the declared expected return type of the RPC method or an exception. * @param The declared expected return type of the RPC method. */ - static CompletableFuture mapResponse(CompletableFuture responseFuture, Class expectedClazz) { + static CompletableFuture mapResponse(CompletableFuture responseFuture, Class expectedClazz) { return responseFuture.handle((payload, exception) -> { // Unexpected exception if (exception != null) { @@ -51,12 +55,19 @@ static CompletableFuture mapResponse(CompletableFuture CompletableFuture mapResponse(CompletableFuture The declared expected return type of the RPC method. */ - static CompletableFuture> mapResponseToResult(CompletableFuture responseFuture, Class expectedClazz) { + static CompletableFuture> mapResponseToResult(CompletableFuture responseFuture, Class expectedClazz) { return responseFuture.handle((payload, exception) -> { // Unexpected exception if (exception != null) { throw new RuntimeException(exception.getMessage(), exception); } + if (payload == null) { throw new RuntimeException("Server returned a null payload. Expected " + expectedClazz.getName()); } - // Expected type - if (payload.is(expectedClazz)) { - if (Status.class.equals(expectedClazz)) { - return calculateStatusResult(payload); - } else { - return RpcResult.success(unpackPayload(payload, expectedClazz)); + Any any; + try { + any = Any.parseFrom(payload.data()); + + // Expected type + if (any.is(expectedClazz)) { + if (Status.class.equals(expectedClazz)) { + return calculateStatusResult(any); + } else { + return RpcResult.success(unpackPayload(any, expectedClazz)); + } } + // Status instead of the expected one + if (any.is(Status.class)) { + return calculateStatusResult(any); + } + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(String.format("%s [%s]", e.getMessage(), Status.class.getName()), e); } - // Status instead of the expected one - if (payload.is(Status.class)) { - return calculateStatusResult(payload); - } + // Some other type instead of the expected one throw new RuntimeException(String.format("Unknown payload type [%s]. Expected [%s]", - payload.getTypeUrl(), expectedClazz.getName())); + any.getTypeUrl(), expectedClazz.getName())); }); } diff --git a/src/main/java/org/eclipse/uprotocol/transport/README.adoc b/src/main/java/org/eclipse/uprotocol/transport/README.adoc new file mode 100644 index 00000000..e154d5d9 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/README.adoc @@ -0,0 +1,7 @@ += uProtocol Transport Interface & Data Model +:toc: +:sectnums: +:source-highlighter: prettify + +== Overview +The purpose of this moduel is to provide the Java implementation of https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l1/README.adoc[uTransport API & Data Model]. The transport API is used by all uE developers to send and receive messages across any transport. The interface is to be implemented by communication transport developers (i.e. developing a uTransport for SOME/IP, DDS, Zenoh, MQTT, etc...). diff --git a/src/main/java/org/eclipse/uprotocol/transport/UTransport.java b/src/main/java/org/eclipse/uprotocol/transport/UTransport.java new file mode 100644 index 00000000..675dc27d --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/UTransport.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.transport; + +import org.eclipse.uprotocol.transport.datamodel.UAttributes; +import org.eclipse.uprotocol.transport.datamodel.UListener; +import org.eclipse.uprotocol.transport.datamodel.UPayload; +import org.eclipse.uprotocol.transport.datamodel.UStatus; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UUri; + +/** + * UTransport is the uP-L1 interface that provides a common API for uE developers to send and receive messages. + * UTransport implementations contain the details for connecting to the underlying transport technology and + * sending UMessage using the configured technology. For more information please refer to + * https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/up-l1/README.adoc. + */ + +public interface UTransport { + + /** + * API used to authenticate with the underlining transport layer that the uEntity passed + * matches the transport specific identity. MUST pass a resolved UUri. + * @param uEntity Resolved UEntity + * @return Returns OKSTATUS if authenticate was successful, FAILSTATUS if the calling uE + * is not authenticated. + */ + UStatus authenticate (UEntity uEntity) ; + + + /** + * Transmit UPayload to the topic using the attributes defined in UTransportAttributes. + * @param topic Resolved UUri topic to send the payload to. + * @param payload Actual payload. + * @param attributes Additional transport attributes. + * @return Returns OKSTATUS if the payload has been successfully sent (ACK'ed), otherwise it + * returns FAILSTATUS with the appropriate failure. + */ + UStatus send(UUri topic, UPayload payload, UAttributes attributes); + + /** + * Register listener to be called when UPayload is received for the specific topic. + * @param topic Resolved UUri for where the message arrived via the underlying transport technology. + * @param listener The method to execute to process the date for the topic. + * @return Returns OKSTATUS if the listener is unregistered correctly, otherwise it returns FAILSTATUS + * with the appropriate failure. + */ + UStatus registerListener(UUri topic, UListener listener); + + /** + * Unregister a listener for a given topic. Messages arriving on this topic will no longer be processed + * by this listener. + * @param topic Resolved UUri for where the listener was registered to receive messages from. + * @param listener The method to execute to process the date for the topic. + * @return Returns OKSTATUS if the listener is unregistered correctly, otherwise it returns FAILSTATUS + * with the appropriate failure. + * + */ + UStatus unregisterListener(UUri topic, UListener listener); +} \ No newline at end of file diff --git a/src/main/java/org/eclipse/uprotocol/transport/datamodel/UAttributes.java b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UAttributes.java new file mode 100644 index 00000000..143d267a --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UAttributes.java @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.transport.datamodel; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +import org.eclipse.uprotocol.v1.UUri; + +/** + * When sending data over uTransport the basic API for send uses a source topic and the UPayload as the data. + * Any other information about the message is placed in the UAttributes class. + * The UAttributes class holds the additional information along with business methods for understanding more about the actual message sent. + * {@link UAttributes} is the class that defines the Payload. It is the place for configuring time to live, priority, security tokens and more. + * Each UAttributes class defines a different type of message payload. The payload can represent a simple published payload with some state change, + * Payload representing an RPC request or Payload representing an RPC response. + */ +public class UAttributes { + + private static final UAttributes EMPTY = new UAttributes(null, null, null, null, null, null, null, null, null); + + // Required Attributes + private final UUID id; // Unique identifier for the message + private final UMessageType type; // Message type + private final UPriority priority; // Message priority + + // Optional Attributes + private final Integer ttl; // Time to live in milliseconds + private final String token; // Authorization token used for TAP + private final UUri sink; // Explicit destination URI + private final Integer plevel; // Permission Level + private final Integer commstatus; // Communication Status + private final UUID reqid; // Request ID + + + /** + * Construct the transport UAttributes object. + * + * @param id Unique identifier for the message. Required. + * @param type Message type such as Publish a state change, RPC request or RPC response. Required. + * @param priority Message priority. Required. + * @param ttl Time to live in milliseconds. + * @param token Authorization token used for TAP. + * @param sink Explicit destination URI, used in notifications and RPC messages. + * @param plevel Permission Level. + * @param commstatus Communication Status, used to indicate platform communication errors that occurred during delivery. + * @param reqid Request ID, used to indicate the id of the RPC request that matches this RPC response. + */ + private UAttributes(UUID id, UMessageType type, UPriority priority, Integer ttl, String token, + UUri sink, Integer plevel, Integer commstatus, UUID reqid) { + this.id = id; + this.type = type; + this.priority = priority; + this.ttl = ttl; + this.token = token; + this.sink = sink; + this.plevel = plevel; + this.commstatus = commstatus; + this.reqid = reqid; + } + + private UAttributes(UAttributesBuilder builder) { + this(builder.id, builder.type, builder.priority, builder.ttl, builder.token, builder.sink, + builder.plevel, builder.commstatus, builder.reqid); + } + + + /** + * Static factory method for creating an empty attributes object, to avoid working with null. + * @return Returns an empty attributes that indicates that there are no added additional attributes to configure. + * An empty UAttributes is not valid, in the same way null is not valid, this is because UAttributes has 3 required values - id, type and priority. + */ + public static UAttributes empty() { + return EMPTY; + } + + /** + * Static factory method for creating a base UAttributes for an RPC request. + * @param id id Unique identifier for the RPC request message. + * @param sink UUri describing the exact RPC command. + * @return Returns a base UAttributes that can be used to build an RPC request. + */ + public static UAttributesBuilder forRpcRequest(UUID id, UUri sink) { + return new UAttributesBuilder(id, UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(sink); + } + + + /** + * Static factory method for creating a base UAttributes for an RPC response. + * @param id Unique identifier for the RPC response message. + * @param sink UUri describing where the response needs to go. + * @param requestId The UUID of the message that this response is responding to. + * @return Returns a base UAttributes that can be used to build an RPC response. + */ + public static UAttributesBuilder forRpcResponse(UUID id, UUri sink, UUID requestId) { + return new UAttributesBuilder(id, UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(sink) + .withReqId(requestId); + } + + + /** + * Unique identifier for the message. + * @return Returns the unique identifier for the message. + */ + public UUID id() { + return id; + } + + /** + * Message type such as Publish a state change, RPC request or RPC response. + * @return Returns the message type such as Publish a state change, RPC request or RPC response. + */ + public UMessageType type() { + return type; + } + + /** + * uProtocol Prioritization classifications. + * @return Returns the configured uProtocol Prioritization classifications. + */ + public UPriority priority() { + return priority; + } + + /** + * A time to live which is how long this event should live for after it was generated (in milliseconds). + * Events without this attribute (or value is 0) MUST NOT timeout. + * @return An Optional time to live which is how long this event should live for after it was generated (in milliseconds). + */ + public Optional ttl() { + return ttl == null ? Optional.empty() : Optional.of(this.ttl); + } + + /** + * Oauth2 access token to perform the access request defined in the request message. + * @return Returns an Optional token attribute. + */ + public Optional token() { + return token == null || token.isBlank() ? Optional.empty() : Optional.of(token); + } + + + /** + * An explicit destination URI, used in notifications and RPC messages. + * @return Returns an Optional destination URI attribute, used in notifications and RPC messages. + */ + public Optional sink() { + return sink == null ? Optional.empty() : Optional.of(sink); + } + + /** + * The reqid is used to indicate a response for a specific request. + * @return Returns an Optional requestId that indicates that this is a response for a specific request. + */ + public Optional reqid() { + return reqid == null ? Optional.empty() : Optional.of(reqid); + } + + /** + * The permission level of the message. + * @return Returns an Optional permission level attribute. + */ + public Optional plevel() { + return plevel == null ? Optional.empty() : Optional.of(plevel); + } + + /** + * The communication status of the message. + * @return Returns an Optional communication status attribute that indicates an error from the platform. + */ + public Optional commstatus() { + return commstatus == null ? Optional.empty() : Optional.of(commstatus); + } + + /** + * Look at the configured UAttributes and determine if the payload could be an RPC Request. + * @return Returns true if the attributes configured indicate that the payload is an RPC Request. + */ + public boolean isRpcRequest() { + return UMessageType.REQUEST.equals(type()) && sink().isPresent(); + } + + /** + * Look at the configured UAttributes and determine if the payload could be an RPC Response. + * @return Returns true if the attributes configured indicate that the payload is an RPC Response. + */ + public boolean isRpcResponse() { + return UMessageType.RESPONSE.equals(type()) && sink().isPresent() && reqid().isPresent(); + } + + /** + * Look at the configured UAttributes and determine of the platform indicated problems. + * @return Returns true if there were platform errors during the operation of uTransport. + */ + public boolean isPlatformTransportSuccess() { + return commstatus().orElse(0) == 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UAttributes that = (UAttributes) o; + return Objects.equals(id, that.id) && type == that.type + && priority == that.priority && Objects.equals(ttl, that.ttl) + && Objects.equals(token, that.token) && Objects.equals(sink, that.sink) + && Objects.equals(plevel, that.plevel) && Objects.equals(commstatus, that.commstatus) + && Objects.equals(reqid, that.reqid); + } + + @Override + public int hashCode() { + return Objects.hash(id, type, priority, ttl, token, sink, plevel, commstatus, reqid); + } + + @Override + public String toString() { + return "UAttributes{" + + "id=" + id + + ", type=" + type + + ", priority=" + priority + + ", ttl=" + ttl + + ", token='" + token + '\'' + + ", sink=" + sink + + ", plevel=" + plevel + + ", commstatus=" + commstatus + + ", reqid=" + reqid + + '}'; + } + + /** + * Builder for easy construction of the UAttributes object. + */ + public static class UAttributesBuilder { + + private final UUID id; + private final UMessageType type; + private final UPriority priority; + private Integer ttl; + private String token; + private UUri sink; + private Integer plevel; + private Integer commstatus; + private UUID reqid; + + /** + * Construct the UAttributesBuilder with the configurations that are required for every payload transport. + * @param id Unique identifier for the message. + * @param type Message type such as Publish a state change, RPC request or RPC response. + * @param priority uProtocol Prioritization classifications. + */ + public UAttributesBuilder(UUID id, UMessageType type, UPriority priority) { + this.id = id; + this. type = type; + this.priority = priority; + } + + /** + * Add the time to live in milliseconds. + * @param ttl the time to live in milliseconds. + * @return Returns the UAttributesBuilder with the configured ttl. + */ + public UAttributesBuilder withTtl(Integer ttl) { + this.ttl = ttl; + return this; + } + + /** + * Add the authorization token used for TAP. + * @param token the authorization token used for TAP. + * @return Returns the UAttributesBuilder with the configured token. + */ + public UAttributesBuilder withToken(String token) { + this.token = token; + return this; + } + + /** + * Add the explicit destination URI. + * @param sink the explicit destination URI. + * @return Returns the UAttributesBuilder with the configured sink. + */ + public UAttributesBuilder withSink(UUri sink) { + this.sink = sink; + return this; + } + + /** + * Add the permission level of the message. + * @param plevel the permission level of the message. + * @return Returns the UAttributesBuilder with the configured plevel. + */ + public UAttributesBuilder withPermissionLevel(Integer plevel) { + this.plevel = plevel; + return this; + } + + /** + * Add the communication status of the message. + * @param commstatus the communication status of the message. + * @return Returns the UAttributesBuilder with the configured commstatus. + */ + public UAttributesBuilder withCommStatus(Integer commstatus) { + this.commstatus = commstatus; + return this; + } + + /** + * Add the request ID. + * @param reqid the request ID. + * @return Returns the UAttributesBuilder with the configured reqid. + */ + public UAttributesBuilder withReqId(UUID reqid) { + this.reqid = reqid; + return this; + } + + /** + * Construct the UAttributes from the builder. + * @return Returns a constructed UAttributes. + */ + public UAttributes build() { + return new UAttributes(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/eclipse/uprotocol/transport/datamodel/UListener.java b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UListener.java new file mode 100644 index 00000000..33f80bdb --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UListener.java @@ -0,0 +1,19 @@ +package org.eclipse.uprotocol.transport.datamodel; + +import org.eclipse.uprotocol.v1.UUri; + +/** + * For any implementation that defines some kind of callback or function that will be called to handle incoming messages. + */ +public interface UListener { + + /** + * Method called to handle/process events. + * @param topic Topic the underlying source of the message. + * @param payload Payload of the message. + * @param attributes Transportation attributes + * @return Returns an Ack every time a message is received and processed. + */ + UStatus onReceive(UUri topic, UPayload payload, UAttributes attributes); + +} diff --git a/src/main/java/org/eclipse/uprotocol/transport/datamodel/UMessageType.java b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UMessageType.java new file mode 100644 index 00000000..83471cae --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UMessageType.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + package org.eclipse.uprotocol.transport.datamodel; + +import java.util.Arrays; +import java.util.Optional; + +/** + * uProtocol defines message types. Using the message type, validation can be performed to ensure transport validity of the data in the {@link UAttributes}. + */ +public enum UMessageType { + PUBLISH(0, "pub.v1"), // Publish or notification event + REQUEST(1, "req.v1"), // Request + RESPONSE(2, "res.v1"); // Response + + private final int intValue; + private final String stringValue; + + public int intValue() { + return intValue; + } + + public String stringValue() { + return stringValue; + } + + UMessageType(int value, String name) { + this.intValue = value; + this.stringValue = name; + } + + /** + * Find the Message type from a numeric value. Mind you, it might not exist. + * @param value numeric message type. + * @return Returns the UMessageType matching the numeric value. + */ + public static Optional from(int value) { + return Arrays.stream(UMessageType.values()) + .filter(p -> p.intValue() == value) + .findAny(); + } + + /** + * Find the Message type from a string value. Mind you, it might not exist. + * @param value string message type. + * @return Returns the UMessageType matching the string value. + */ + public static Optional from(String value) { + return Arrays.stream(UMessageType.values()) + .filter(p -> p.stringValue().equals(value)) + .findAny(); + } +} diff --git a/src/main/java/org/eclipse/uprotocol/transport/datamodel/UPayload.java b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UPayload.java new file mode 100644 index 00000000..c73342d7 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UPayload.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + package org.eclipse.uprotocol.transport.datamodel; + +import java.util.Arrays; +import java.util.Objects; + +/** + * The UPayload contains the clean Payload information along with its raw serialized structure of a byte[]. + */ +public class UPayload { + + private static final UPayload EMPTY = new UPayload(new byte[0], USerializationHint.UNKNOWN); + + private final byte[] data; + + private final USerializationHint hint; // Hint regarding the bytes contained within the UPayload + + + /** + * Create a UPayload. + * @param data A byte array of the actual data. + */ + public UPayload(byte[] data, USerializationHint hint) { + this.data = Objects.requireNonNullElse(data, new byte[0]); + this.hint = Objects.requireNonNullElse(hint, USerializationHint.UNKNOWN); + } + + + /** + * The actual serialized or raw data, which can be deserialized or simply used as is. + * @return Returns the actual serialized or raw data, which can be deserialized or simply used as is. + */ + public byte[] data() { + return this.data; + } + + /** + * The hint regarding the bytes contained within the UPayload. + * @return Returns the hint regarding the bytes contained within the UPayload. + */ + public USerializationHint hint() { + return this.hint; + } + + /** + * @return Returns an empty representation of UPayload. + */ + public static UPayload empty() { + return EMPTY; + } + + + /** + * @return Returns true if the data in the UPayload is empty. + */ + public boolean isEmpty() { + return this.data.length == 0; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UPayload uPayload = (UPayload) o; + return Arrays.equals(data, uPayload.data) && this.hint == uPayload.hint; + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(data),hint); + } + + @Override + public String toString() { + return "UPayload{" + + "data=" + Arrays.toString(data()) + + ", hint=" + hint +'}'; + } +} diff --git a/src/main/java/org/eclipse/uprotocol/transport/datamodel/UPriority.java b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UPriority.java new file mode 100644 index 00000000..f636bd8f --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UPriority.java @@ -0,0 +1,58 @@ +package org.eclipse.uprotocol.transport.datamodel; + +import java.util.Arrays; +import java.util.Optional; + +public enum UPriority { + // Low Priority. No bandwidth assurance such as File Transfer. + LOW ("CS0", 0), + // Standard, undifferentiated application such as General (unclassified). + STANDARD ("CS1", 1), + // Operations, Administration, and Management such as Streamer messages (sub, connect, etc…) + OPERATIONS ("CS2", 2), + // Multimedia streaming such as Video Streaming + MULTIMEDIA_STREAMING ("CS3", 3), + // Real-time interactive such as High priority (rpc events) + REALTIME_INTERACTIVE ("CS4", 4), + // Signaling such as Important + SIGNALING("CS5", 5), + // Network control such as Safety Critical + NETWORK_CONTROL ("CS6", 6); + + private final String qosString; + private final int value; + public String qosString() { + return qosString; + } + + public int intValue() { + return value; + } + + UPriority(String qosString, int value) { + this.qosString = qosString; + this.value = value; + } + + /** + * Find the Priority matching the numeric value. Mind you, it might not exist. + * @param value numeric priority value. + * @return Returns the Priority matching the numeric value. Mind you, it might not exist. + */ + public static Optional from(int value) { + return Arrays.stream(UPriority.values()) + .filter(p -> p.intValue() == value) + .findAny(); + } + + /** + * Find the Priority matching the QOS String value. Mind you, it might not exist. + * @param qosString QOS String priority value. + * @return Returns the Priority matching the QOS String value. Mind you, it might not exist. + */ + public static Optional from(String qosString) { + return Arrays.stream(UPriority.values()) + .filter(p -> p.qosString().equals(qosString)) + .findAny(); + } +} diff --git a/src/main/java/org/eclipse/uprotocol/transport/datamodel/USerializationHint.java b/src/main/java/org/eclipse/uprotocol/transport/datamodel/USerializationHint.java new file mode 100644 index 00000000..d95c894a --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/datamodel/USerializationHint.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.transport.datamodel; + +import java.util.Arrays; +import java.util.Optional; + +public enum USerializationHint { + // Serialization hint is unknown + UNKNOWN(0, ""), + + // serialized com.google.protobuf.Any type + PROTOBUF (1, "application/x-protobuf"), + + // data is a UTF-8 string containing a JSON structure + JSON(2, "application/json"), + + // data is a UTF-8 string containing a JSON structure + SOMEIP(3, "application/x-someip"), + + // Raw binary data that has not been serialized + RAW(4, "application/octet-stream"), + + // Text Format + TEXT(5, "text/plain"); + + private final int hintNumber; + private final String mimeType; + + public int hintNumber() { + return hintNumber; + } + + public String mimeType() { + return mimeType; + } + + USerializationHint(int hintNumber, String mimeType) { + this.hintNumber = hintNumber; + this.mimeType = mimeType; + } + + /** + * Find the serialization hint matching the mimeType value. Mind you, it might not exist. + * @param value numeric hint value. + * @return Returns the USerializationHint matching the numeric value. + */ + public static Optional from(int value) { + return Arrays.stream(USerializationHint.values()) + .filter(p -> p.hintNumber() == value) + .findAny(); + } + + /** + * Find the serialization hint matching the String value. Mind you, it might not exist. + * @param value String hint value. + * @return Returns the USerializationHint matching the String value. + */ + public static Optional from(String value) { + return Arrays.stream(USerializationHint.values()) + .filter(p -> p.mimeType().equals(value)) + .findAny(); + } +} + diff --git a/src/main/java/org/eclipse/uprotocol/transport/datamodel/UStatus.java b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UStatus.java new file mode 100644 index 00000000..f3373838 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/datamodel/UStatus.java @@ -0,0 +1,217 @@ +package org.eclipse.uprotocol.transport.datamodel; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; + +/** + * UProtocol general status for all operations. + * A UStatus is generated using the static factory methods, making is easy to quickly create UStatus objects. + * Example: UStatus ok = UStatus.ok(); + */ +public abstract class UStatus { + + private static final String OK = "ok"; + private static final String FAILED = "failed"; + + public abstract boolean isSuccess(); + public abstract String msg(); + public abstract int getCode(); + + /** + * Enum to contain the status code that we map to google.rpc.Code. + * Please refer to code.proto + * for documentation on the codes listed below + * + */ + public enum Code { + + OK (com.google.rpc.Code.OK_VALUE), + CANCELLED (com.google.rpc.Code.CANCELLED_VALUE), + UNKNOWN (com.google.rpc.Code.UNKNOWN_VALUE), + INVALID_ARGUMENT (com.google.rpc.Code.INVALID_ARGUMENT_VALUE), + DEADLINE_EXCEEDED (com.google.rpc.Code.DEADLINE_EXCEEDED_VALUE), + NOT_FOUND (com.google.rpc.Code.NOT_FOUND_VALUE), + ALREADY_EXISTS (com.google.rpc.Code.ALREADY_EXISTS_VALUE), + PERMISSION_DENIED (com.google.rpc.Code.PERMISSION_DENIED_VALUE), + UNAUTHENTICATED (com.google.rpc.Code.UNAUTHENTICATED_VALUE), + RESOURCE_EXHAUSTED (com.google.rpc.Code.RESOURCE_EXHAUSTED_VALUE), + FAILED_PRECONDITION (com.google.rpc.Code.FAILED_PRECONDITION_VALUE), + ABORTED (com.google.rpc.Code.ABORTED_VALUE), + OUT_OF_RANGE (com.google.rpc.Code.OUT_OF_RANGE_VALUE), + UNIMPLEMENTED (com.google.rpc.Code.UNIMPLEMENTED_VALUE), + INTERNAL (com.google.rpc.Code.INTERNAL_VALUE), + UNAVAILABLE (com.google.rpc.Code.UNAVAILABLE_VALUE), + DATA_LOSS (com.google.rpc.Code.DATA_LOSS_VALUE), + UNSPECIFIED (-1); + + private final int value; + Code (int value) { + this.value = value; + } + + public int value() { + return value; + } + + /** + * Get the Code from an integer value. + * @param value The integer value of the Code. + * @return Returns the Code if found, otherwise returns Optional.empty(). + */ + public static Optional from(int value) { + return Arrays.stream(Code.values()) + .filter(p -> p.value() == value) + .findAny(); + } + + + /** + * Get the Code from a google.rpc.Code. + * @param code The google.rpc.Code. + * @return Returns the Code if found, otherwise returns Optional.empty(). + */ + public static Optional from(com.google.rpc.Code code) { + if (code == null || code == com.google.rpc.Code.UNRECOGNIZED) { + return Optional.empty(); + } + return Arrays.stream(Code.values()) + .filter(p -> p.value() == code.getNumber()) + .findAny(); + } + } + + /** + * Return true if UStatus is a failure + * @return Returns true if the UStatus is successful. + */ + public boolean isFailed() { + return !isSuccess(); + } + + @Override + public String toString() { + return String.format("UStatus %s %s%s code=%s", isSuccess() ? "ok" : "failed", + isSuccess() ? "id=" : "msg=", msg(), + getCode()); + } + + /** + * A successful UStatus. + */ + private static class OKSTATUS extends UStatus { + + /** + * A successful status could contain an id for tracking purposes. + */ + private final String id; + + private OKSTATUS(String id) { + this.id = id; + } + + @Override + public boolean isSuccess() { + return true; + } + + public int getCode() { + return Code.OK.value(); + } + + @Override + public String msg() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OKSTATUS okstatus = (OKSTATUS) o; + return Objects.equals(id, okstatus.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + } + + + /** + * A failed UStatus. + */ + private static class FAILSTATUS extends UStatus { + + private final String failMsg; + + private final Code code; + + private FAILSTATUS(String failMsg, Code code) { + this.failMsg = failMsg; + this.code = code; + } + + private FAILSTATUS(String failMsg, int value) { + Optional code = Code.from(value); + this.failMsg = failMsg; + this.code = code.orElse(Code.UNSPECIFIED); + } + + @Override + public boolean isSuccess() { + return false; + } + + @Override + public String msg() { + return this.failMsg; + } + + @Override + public int getCode() { + return code.value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FAILSTATUS that = (FAILSTATUS) o; + return Objects.equals(failMsg, that.failMsg) && code == that.code; + } + + @Override + public int hashCode() { + return Objects.hash(failMsg, code); + } + } + + + public static UStatus ok() { + return new OKSTATUS(UStatus.OK); + } + + public static UStatus ok(String ackId) { + return new OKSTATUS(ackId); + } + + public static UStatus failed() { + return new FAILSTATUS(FAILED, Code.UNKNOWN.value()); + } + + public static UStatus failed(String msg) { + return new FAILSTATUS(msg, Code.UNKNOWN.value()); + } + + public static UStatus failed(String msg, int failureReason) { + return new FAILSTATUS(msg, failureReason); + } + + public static UStatus failed(String msg, Code code) { + return new FAILSTATUS(msg, code); + } + +} diff --git a/src/main/java/org/eclipse/uprotocol/transport/validate/UAttributesValidator.java b/src/main/java/org/eclipse/uprotocol/transport/validate/UAttributesValidator.java new file mode 100644 index 00000000..4aab1ae4 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/transport/validate/UAttributesValidator.java @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.transport.validate; + +import org.eclipse.uprotocol.transport.datamodel.UAttributes; +import org.eclipse.uprotocol.transport.datamodel.UMessageType; +import org.eclipse.uprotocol.transport.datamodel.UPriority; +import org.eclipse.uprotocol.transport.datamodel.UStatus; +import org.eclipse.uprotocol.transport.datamodel.UStatus.Code; +import org.eclipse.uprotocol.uri.validator.UriValidator; +import org.eclipse.uprotocol.uuid.factory.UUIDUtils; +import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.validation.ValidationResult; + +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * {@link UAttributes} is the class that defines the Payload. It is the place for configuring time to live, priority, security tokens and more. + * Each UAttributes class defines a different type of message payload. The payload can represent a simple published payload with some state change, + * Payload representing an RPC request or Payload representing an RPC response. + * UAttributesValidator is a base class for all UAttribute validators, that can help validate that the {@link UAttributes} object is correctly defined + * to define the Payload correctly. + */ +public abstract class UAttributesValidator { + + /** + * Static factory method for getting a validator according to the {@link UMessageType} defined in the {@link UAttributes}. + * @param attribute UAttributes containing the UMessageType. + * @return returns a UAttributesValidator according to the {@link UMessageType} defined in the {@link UAttributes}. + */ + public static UAttributesValidator getValidator(UAttributes attribute) { + if (attribute.type() == null) { + return Validators.PUBLISH.validator(); + } + switch (attribute.type()){ + case RESPONSE: + return Validators.RESPONSE.validator(); + case REQUEST: + return Validators.REQUEST.validator(); + default: + return Validators.PUBLISH.validator(); + } + } + + + /** + * Validators Factory. Example: + * UAttributesValidator validateForPublishMessageType = UAttributesValidator.Validators.PUBLISH.validator() + */ + public enum Validators { + PUBLISH (new Publish()), + REQUEST (new Request()), + RESPONSE (new Response()); + + private final UAttributesValidator uattributesValidator; + + public UAttributesValidator validator() { + return uattributesValidator; + } + + Validators(UAttributesValidator uattributesValidator) { + this.uattributesValidator = uattributesValidator; + } + } + + + /** + * Take a {@link UAttributes} object and run validations. + * @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. + */ + public ValidationResult validate(UAttributes attributes) { + final String errorMessage = Stream.of( + validateId(attributes), + validateType(attributes), + validatePriority(attributes), + validateTtl(attributes), + validateSink(attributes), + validateCommStatus(attributes), + validatePermissionLevel(attributes), + validateReqId(attributes)) + .filter(ValidationResult::isFailure) + .map(ValidationResult::getMessage) + .collect(Collectors.joining(",")); + return errorMessage.isBlank() ? ValidationResult.success() : + ValidationResult.failure(errorMessage); + } + + /** + * Indication if the Payload with these UAttributes is expired. + * @param uAttributes UAttributes with time to live value. + * @return Returns a {@link ValidationResult} that is success meaning not expired or failed with a validation message or expiration. + */ + public ValidationResult isExpired(UAttributes uAttributes) { + final Optional maybeTtl = uAttributes.ttl(); + final Optional maybeTime = UUIDUtils.getTime(uAttributes.id()); + if (maybeTime.isEmpty()) { + return ValidationResult.failure("Invalid Time"); + } + if (maybeTtl.isEmpty()) { + return ValidationResult.success(); + } + int ttl = maybeTtl.get(); + if (ttl <= 0) { + return ValidationResult.success(); + } + + long delta = System.currentTimeMillis() - maybeTime.get(); + + return delta >= ttl ? ValidationResult.failure("Payload is expired") : ValidationResult.success(); + } + + /** + * Validate the id attribute, it is required. + * @param attributes UAttributes object containing the id to validate. + * @return Returns a {@link ValidationResult} that is success or failed with a failure message. + */ + public ValidationResult validateId(UAttributes attributes) { + final UUID id = attributes.id(); + return UUIDUtils.isUuid(id) ? ValidationResult.success() : + ValidationResult.failure(String.format("Invalid UUID [%s]", id)); + } + + /** + * Validate the {@link UPriority} since it is required. + * @param attributes UAttributes object containing the message priority to validate. + * @return Returns a {@link ValidationResult} that is success or failed with a failure message. + */ + public ValidationResult validatePriority(UAttributes attributes) { + return attributes.priority() == null ? + ValidationResult.failure("Priority is missing") : ValidationResult.success(); + } + + /** + * Validate the time to live configuration. If the UAttributes does not contain a time to live then the ValidationResult is ok. + * @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. + */ + public ValidationResult validateTtl(UAttributes attributes) { + return attributes.ttl() + .filter(ttl -> ttl <= 0) + .map(ttl -> ValidationResult.failure(String.format("Invalid TTL [%s]", ttl))) + .orElse(ValidationResult.success()); + } + + /** + * Validate the sink UriPart for the default case. If the UAttributes does not contain a sink then the ValidationResult is ok. + * @param attributes UAttributes object containing the sink to validate. + * @return Returns a {@link ValidationResult} that is success or failed with a failure message. + */ + public ValidationResult validateSink(UAttributes attributes) { + return attributes.sink() + .map(UriValidator::validate) + .orElse(ValidationResult.success()); + } + + /** + * Validate the permissionLevel for the default case. If the UAttributes does not contain a permission level then the ValidationResult is ok. + * @param attributes UAttributes object containing the permission level to validate. + * @return Returns a ValidationResult indicating if the permissionLevel is valid or not. + */ + public ValidationResult validatePermissionLevel(UAttributes attributes) { + return attributes.plevel() + .map(permissionLevel -> permissionLevel > 0 ? ValidationResult.success() : ValidationResult.failure("Invalid Permission Level")) + .orElse(ValidationResult.success()); + } + + /** + * Validate the commStatus for the default case. If the UAttributes does not contain a comm status then the ValidationResult is ok. + * @param attributes UAttributes object containing the comm status to validate. + * @return Returns a {@link ValidationResult} that is success or failed with a failure message. + */ + public ValidationResult validateCommStatus(UAttributes attributes) { + return attributes.commstatus().or(() -> Optional.of(Code.OK.value())) + .flatMap(Code::from) + .map(code -> ValidationResult.success()) + .orElse(ValidationResult.failure("Invalid Communication Status Code")); + } + + /** + * Validate the correlationId for the default case. If the UAttributes does not contain a request id then the ValidationResult is ok. + * @param attributes Attributes object containing the request id to validate. + * @return Returns a {@link ValidationResult} that is success or failed with a failure message. + */ + public ValidationResult validateReqId(UAttributes attributes) { + return attributes.reqid() + .filter(correlationId -> !UUIDUtils.isUuid(correlationId)) + .map(correlationId -> ValidationResult.failure("Invalid UUID")) + .orElse(ValidationResult.success()); + } + + /** + * 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. + */ + public abstract ValidationResult validateType(UAttributes attributes); + + /** + * Implements validations for UAttributes that define a message that is meant for publishing state changes. + */ + private static class Publish extends UAttributesValidator { + + /** + * Validates that attributes for a message meant to publish 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.PUBLISH == attributes.type() ? ValidationResult.success() : + ValidationResult.failure(String.format("Wrong Attribute Type [%s]", attributes.type())); + } + + @Override + public String toString() { + return "UAttributesValidator.Publish"; + } + } + + /** + * Implements validations for UAttributes that define a message that is meant for an RPC request. + */ + private static class Request extends UAttributesValidator { + + /** + * 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.REQUEST == attributes.type() ? ValidationResult.success() : + ValidationResult.failure(String.format("Wrong Attribute Type [%s]", attributes.type())); + } + + /** + * 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) { + return attributes.sink() + .map(UriValidator::validateRpcResponse) + .orElse(ValidationResult.failure("Missing Sink")); + } + + /** + * 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) { + return attributes.ttl() + .map(ttl -> ttl > 0 ? ValidationResult.success() : ValidationResult.failure(String.format("Invalid TTL [%s]", ttl))) + .orElse(ValidationResult.failure("Missing TTL")); + } + + @Override + public String toString() { + return "UAttributesValidator.Request"; + } + } + + /** + * Implements validations for UAttributes that define a message that is meant for an RPC response. + */ + private static class Response extends UAttributesValidator { + + /** + * 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.RESPONSE == attributes.type() ? ValidationResult.success() : + ValidationResult.failure(String.format("Wrong Attribute Type [%s]", attributes.type())); + } + + /** + * 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) { + return attributes.sink() + .map(UriValidator::validateRpcMethod) + .orElse(ValidationResult.failure("Missing Sink")); + } + + + /** + * 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) { + return attributes.reqid() + .map(correlationId -> UUIDUtils.isUuid(correlationId) ? + ValidationResult.success() : ValidationResult.failure(String.format("Invalid correlationId [%s]", correlationId))) + .orElse(ValidationResult.failure("Missing correlationId")); + } + + @Override + public String toString() { + return "UAttributesValidator.Response"; + } + } + +} diff --git a/src/main/java/org/eclipse/uprotocol/uri/README.adoc b/src/main/java/org/eclipse/uprotocol/uri/README.adoc new file mode 100644 index 00000000..fc205b9d --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/uri/README.adoc @@ -0,0 +1,51 @@ += uProtocol URI +:toc: +:sectnums: + + +== Overview + +The following folder contains the data model, factory, and validators to implement https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/basics/uri.adoc[uProtocol URI Specifications] + +Matches the uProtocol URI Format. and is used to define source and sink (destination) attributes of uProtocol. +The factory builds URIs. + +URI is used as a method to uniquely identify devices, services, and resources on the network. + +== UUri + +*An Uri is built from the following elements:* + +* *UAuthority* - represents the device and domain of the software, the deployment. You can specify local or remote options. +* *UEntity* - The Software Entity defines the software name and version. +* *UResource* - The resource of the software can be a service name, and instance in the service and the name of the protobuf IDL message. + +=== UAuthority + +An Authority consists of a device and a domain per uProtocol URI format. + +An Authority represents the deployment location of a specific Software Entity. + +=== UEntity - uE + +An Software Entity is a piece of software deployed somewhere on a device. The uE is used in the source and sink parts of communicating software. + +A uE that *publishes* events is a *Service* role. + +A uE that *consumes* events is an *Application* role. + +A uE may combine bother Service and Application roles. + + +=== UResource + +A service API - defined in the uE - has Resources and Methods. Both of these are represented by the UResource class. + +An UResource is something that can be manipulated/controlled/exposed by a service. + +Resources are unique when prepended with UAuthority that represents the device and Software Entity that represents the service. + +An Resource represents a resource from a Service such as "door" and an optional specific instance such as "front_left". +In addition, it can optionally contain the name of the resource Message type, such as "Door". + +The Message type matches the protobuf service IDL that defines structured data types. A message is a data structure type used to define data that is passed in events and rpc methods. \ No newline at end of file diff --git a/src/main/java/org/eclipse/uprotocol/uri/builder/UResourceBuilder.java b/src/main/java/org/eclipse/uprotocol/uri/builder/UResourceBuilder.java new file mode 100644 index 00000000..22395d79 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/uri/builder/UResourceBuilder.java @@ -0,0 +1,32 @@ +package org.eclipse.uprotocol.uri.builder; + +import org.eclipse.uprotocol.v1.UResource; + +public interface UResourceBuilder { + + /** + * Builds a UResource for an RPC response. + * @return Returns a UResource for an RPC response. + */ + static UResource forRpcResponse() { + return UResource.newBuilder() + .setName("rpc") + .setInstance("response") + .setId(0) + .build(); + } + + + /** + * Builds a UResource for an RPC request. + * @param method The method to be invoked. + * @return Returns a UResource for an RPC request. + */ + static UResource forRpcRequest(String method) { + return UResource.newBuilder() + .setName("rpc") + .setInstance(method) + .build(); + } + +} diff --git a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UAuthority.java b/src/main/java/org/eclipse/uprotocol/uri/datamodel/UAuthority.java deleted file mode 100644 index 98be22e6..00000000 --- a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UAuthority.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import java.util.Objects; -import java.util.Optional; - -/** - * Data representation of an Authority.
An Authority consists of a device and a domain.
- * Device and domain names are used as part of the URI for device and service discovery.
- * Devices will be grouped together into realms of Zone of Authority.
- * An Authority represents the deployment location of a specific Software Entity in the Ultiverse. - */ -public class UAuthority { - private final static UAuthority EMPTY = new UAuthority(null, null, false); - - /** - * A device is a logical independent representation of a service bus in different execution environments.
- * Devices will be grouped together into realms of Zone of Authority. - */ - private final String device; - - /** - * The domain an software entity is deployed on, such as vehicle or backoffice.
- * Vehicle Domain name MUST be that of the vehicle VIN.
- * A domain name is an identification string that defines a realm of administrative autonomy, authority or control within the Internet. - */ - private final String domain; - - /** - * An Uri starting with // is a remote configuration of a URI, and we mark the uAuthority implicitly as remote. - */ - private final boolean markedRemote; - - // TODO add user information - what is this used for? make sure it is part of the domain. - - /** - * Constructor. - * - * @param device The device an software entity is deployed on, such as the VCU, CCU or Cloud (PaaS). - * @param domain The domain an software entity is deployed on, such as vehicle or backoffice. - * @param markedRemote Indicates if this UAuthority was implicitly marked as remote. Used for validation. - */ - private UAuthority(String device, String domain, boolean markedRemote) { - this.device = device == null ? null : device.toLowerCase(); - this.domain = domain == null ? null : domain.toLowerCase(); - this.markedRemote = markedRemote; - } - - /** - * Static factory method for creating a local authority.
- * A local uri does not contain an authority and looks like this: - *
 :<service>/<version>/<resource>#<Message> 
- * @return Returns a local altifi authority that has no domain or device information. - */ - public static UAuthority local() { - return EMPTY; - } - - /** - * Static factory method for creating a remote authority.
- * A remote uri contains an authority and looks like this: - *
 //<device>.<domain>/<service>/<version>/<resource>#<Message> 
- * @param device The device an software entity is deployed on, such as the VCU, CCU or Cloud (PaaS). - * @param domain The domain an software entity is deployed on, such as vehicle or backoffice. Vehicle Domain name MUST be that of the vehicle VIN. - * @return returns a remote authority that contains the device and the domain. - */ - public static UAuthority remote(String device, String domain) { - return new UAuthority(device, domain, true); - } - - /** - * Static factory method for creating an empty authority, to avoid working with null
- * @return Returns an empty altifi authority that has no domain or device information. - */ - public static UAuthority empty() { - return EMPTY; - } - - /** - * @return returns true if this authority is remote, meaning it contains a device or a domain. - */ - public boolean isRemote() { - return domain().isPresent() || device().isPresent(); - } - - /** - * @return returns true if this authority is local, meaning does not contain a device or a domain. - */ - public boolean isLocal() { - return domain().isEmpty() && device().isEmpty(); - } - - /** - * @return Returns the device an software entity is deployed on, such as the VCU, CCU or Cloud (PaaS). - */ - public Optional device() { - return device == null || device.isBlank() ? Optional.empty() : Optional.of(device); - } - - /** - * @return Returns the domain an software entity is deployed on, such as vehicle or backoffice. - */ - public Optional domain() { - return domain == null || domain.isBlank() ? Optional.empty() : Optional.of(domain); - } - - /** - * @return Returns the explicitly configured remote deployment. - */ - public boolean isMarkedRemote() { - return markedRemote; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - UAuthority that = (UAuthority) o; - return markedRemote == that.markedRemote && Objects.equals(device, that.device) - && Objects.equals(domain, that.domain); - } - - @Override - public int hashCode() { - return Objects.hash(device, domain, markedRemote); - } - - @Override - public String toString() { - return "UAuthority{" + - "device='" + device + '\'' + - ", domain='" + domain + '\'' + - ", markedRemote=" + markedRemote + - '}'; - } -} diff --git a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UEntity.java b/src/main/java/org/eclipse/uprotocol/uri/datamodel/UEntity.java deleted file mode 100644 index 4ff8ab7a..00000000 --- a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UEntity.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import java.util.Objects; -import java.util.Optional; - -/** - * Data representation of an Software Entity - USE
- * Matches the first part of the path part <app|service>/<version> in SDV-202 uProtocol Format
- * An Software Entity is a piece of software deployed somewhere on a uDevice in the Ultiverse.
- * The Software Entity is used in the source and sink parts of communicating software in the Ultiverse.
- * A USE that publishes events is a Service role.
- * A USE that consumes events is an Application role. - */ -public class UEntity { - private static final UEntity EMPTY = new UEntity("", null); - - private final String name; - private final String version; - - /** - * Build an Software Entity that represents a communicating piece of software in the Ultiverse. - * @param name The name of the software such as petpp or body.access. - * @param version The software version. If not supplied, the latest version of the service will be used. - */ - public UEntity(String name, String version) { - Objects.requireNonNull(name, " Software Entity must have a name"); - this.name = name; - this.version = version; - } - - /** - * Static factory method for creating a USE using the application or service name. - * @param name The application or service name, such as petapp or body.access. - * @return Returns an UEntity with the name where the version is the latest version of the service. - */ - public static UEntity fromName(String name) { - return new UEntity(name, null); - } - - /** - * Static factory method for creating an empty software entity, to avoid working with null
- * @return Returns an empty software entity that has a blank name and no version information. - */ - public static UEntity empty() { - return EMPTY; - } - - /** - * Indicates that this USE is an empty container and has no valuable information in building uProtocol sinks or sources. - * @return Returns true if this USE is an empty container and has no valuable information in building uProtocol sinks or sources. - */ - public boolean isEmpty() { - return name.isBlank() && version().isEmpty(); - } - - /** - * @return Returns the name of the software such as petpp or body.access. - */ - public String name() { - return name; - } - - /** - * @return Returns the software version if it exists. - * If the version does not exist, the latest version of the service will be used. - */ - public Optional version() { - return version == null || version.isBlank() ? Optional.empty() : Optional.of(version); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - UEntity that = (UEntity) o; - return Objects.equals(name, that.name) && Objects.equals(version, that.version); - } - - @Override - public int hashCode() { - return Objects.hash(name, version); - } - - @Override - public String toString() { - return "UEntity{" + "name='" + name + '\'' - + ", version='" + (version == null ? "latest" : version) + '\'' + '}'; - } -} diff --git a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UResource.java b/src/main/java/org/eclipse/uprotocol/uri/datamodel/UResource.java deleted file mode 100644 index 5d70bf12..00000000 --- a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UResource.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import java.util.Objects; -import java.util.Optional; - -/** - * An service API - defined in the {@link UEntity} - has Resources and Methods. Both of these are represented by the UResource class.
- * An Resource represents a resource from a Service such as "door" and an optional specific instance such as "front_left". In addition, it can optionally contain - * the name of the resource Message type, such as "Door". The Message type matches the protobuf service IDL that defines structured data types.
- * An UResource is something that can be manipulated/controlled/exposed by a service. Resources are unique when prepended with UAuthority that represents the device and - * UEntity that represents the service. - */ -public class UResource { - - private static final UResource EMPTY = new UResource("", null,null); - - private static final UResource RESPONSE = new UResource("rpc", "response",null); - - private final String name; - - private final String instance; - - private final String message; - - //TODO when message is empty - try and infer it from the name "door" -> "Door" - - /** - * Create an Resource. The resource is something that is manipulated by a service such as a door. - * @param name The name of the resource as a noun such as door or window, or in the case a method that manipulates the resource, a verb. - * @param instance An instance of a resource such as front_left. - * @param message The Message type matches the protobuf service IDL message name that defines structured data types. - * A message is a data structure type used to define data that is passed in events and rpc methods. - */ - public UResource(String name, String instance, String message) { - Objects.requireNonNull(name, " Resource must have a name."); - this.name = name; - this.instance = instance; - this.message = message; - } - - /** - * Static factory method for creating an Resource using the resource name. - * @param name The name of the resource as a noun such as door or window, or in the case a method that manipulates the resource, a verb. - * @return Returns an UResource with the resource name where the instance and message are empty. - * If the instance does not exist, it is assumed that all the instances of the resource are wanted. - */ - public static UResource fromName(String name) { - return new UResource(name, null, null); - } - - /** - * Static factory method for creating an Resource using the resource name and some resource instance. - * @param name The name of the resource as a noun such as door or window, or in the case a method that manipulates the resource, a verb. - * @param instance An instance of a resource such as front_left. - * @return Returns an UResource with the resource name and a specific instance where the message is left empty. - */ - public static UResource fromNameWithInstance(String name, String instance) { - return new UResource(name, instance, null); - } - - /** - * Static factory method for creating an Resource using a resource command name such as UpdateDoor. - * @param commandName The RPC command name such as UpdateDoor. - * @return returns an Ulitfi resource used for sending RPC commands. - */ - public static UResource forRpc(String commandName) { - Objects.requireNonNull(commandName, " Resource must have a command name."); - return new UResource("rpc", commandName, null); - } - - /** - * @return Returns true if this resource specifies an RPC method call. - */ - public boolean isRPCMethod() { - return name.equals("rpc"); - } - - /** - * Static factory method for creating an empty resource, to avoid working with null
- * @return Returns an empty resource that has a blank name and no message instance information. - */ - public static UResource empty() { - return EMPTY; - } - - /** - * Static factory method for creating a response resource that is returned from RPC calls
- * @return Returns a response resource used for response RPC calls. - */ - public static UResource response() { - return RESPONSE; - } - - /** - * Indicates that this resource is an empty container and has no valuable information in building uProtocol URI. - * @return Returns true if this resource is an empty container and has no valuable information in building uProtocol URI. - */ - public boolean isEmpty() { - return name.isBlank() && instance().isEmpty() && message().isEmpty(); - } - - /** - * @return Returns the name of the resource as a noun such as door or window, or in the case a method that manipulates the resource, a verb. - */ - public String name() { - return name; - } - - /** - * Support for building the name attribute in many protobuf Message objects. - * Will build a string with the name and instance with a dot delimiter, only if the instance exists. - * @return Returns a string used for building the name attribute in many protobuf Message objects. - * Will build a string with the name and instance with a dot delimiter, only if the instance exists. - */ - public String nameWithInstance() { - return instance().isPresent() ? String.format("%s.%s", name(), instance().get()) : name(); - } - - /** - * An instance of a resource such as front_left - * or in the case of RPC a method name that manipulates the resource such as UpdateDoor. - * @return Returns the resource instance of the resource if it exists. - * If the instance does not exist, it is assumed that all the instances of the resource are wanted. - */ - public Optional instance() { - return instance == null || instance.isBlank() ? Optional.empty() : Optional.of(instance); - } - - - /** - * The Message type matches the protobuf service IDL that defines structured data types. - * A message is a data structure type used to define data that is passed in events and rpc methods. - * @return Returns the Message type matches the protobuf service IDL that defines structured data types. - */ - public Optional message() { - return message == null || message.isBlank() ? Optional.empty() : Optional.of(message); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - UResource that = (UResource) o; - return Objects.equals(name, that.name) && Objects.equals(instance, that.instance) && Objects.equals(message, that.message); - } - - @Override - public int hashCode() { - return Objects.hash(name, instance, message); - } - - @Override - public String toString() { - return "UResource{" + - "name='" + name + '\'' + - ", instance='" + instance + '\'' + - ", message='" + message + '\'' + - '}'; - } -} diff --git a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UUri.java b/src/main/java/org/eclipse/uprotocol/uri/datamodel/UUri.java deleted file mode 100644 index f354ed2d..00000000 --- a/src/main/java/org/eclipse/uprotocol/uri/datamodel/UUri.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import org.eclipse.uprotocol.uri.factory.UriFactory; - -import java.util.Objects; - -/** - * Data representation of an URI. - * This class will be used to represent the source and sink (destination) parts of the Packet CloudEvent.
- * URI is used as a method to uniquely identify devices, services, and resources on the network.
- * Defining a common URI for the system allows applications and/or services to publish and discover each other - * as well as maintain a database/repository of microservices in the various vehicles.
- * Example: - *
- *     //<device>.<domain>/<service>/<version>/<resource>#<message>
- * 
- * - */ -public class UUri { - private static final UUri EMPTY = new UUri(UAuthority.empty(), UEntity.empty(), UResource.empty()); - - private final UAuthority uAuthority; - private final UEntity uEntity; - private final UResource uResource; - - private transient String uProtocolUri; - - /** - * Create a full URI. - * @param uAuthority The Authority represents the deployment location of a specific Software Entity in the Ultiverse. - * @param uEntity The USE in the role of a service or in the role of an application. - * @param uResource The resource is something that is manipulated by a service such as a Door. - */ - public UUri(UAuthority uAuthority, UEntity uEntity, UResource uResource) { - this.uAuthority = Objects.requireNonNullElse(uAuthority, UAuthority.empty()); - this.uEntity = Objects.requireNonNullElse(uEntity, UEntity.empty()); - this.uResource = Objects.requireNonNullElse(uResource, UResource.empty()); - } - - /** - * Create an URI for a resource. This will match all the specific instances of the resource, - * for example all the instances of the vehicle doors. - * @param uAuthority The Authority represents the deployment location of a specific Software Entity in the Ultiverse. - * @param uEntity The USE in the role of a service or in the role of an application. - * @param uResource The resource is something that is manipulated by a service such as a Door. - */ - public UUri(UAuthority uAuthority, UEntity uEntity, String uResource) { - this(uAuthority, uEntity, UResource.fromName(uResource)); - } - - /** - * Static factory method for creating an empty uri, to avoid working with null
- * @return Returns an empty altifi uri to avoid working with null. - */ - public static UUri empty() { - return EMPTY; - } - - /** - * Indicates that this URI is an empty container and has no valuable information in building uProtocol sinks or sources. - * @return Returns true if this URI is an empty container and has no valuable information in building uProtocol sinks or sources. - */ - public boolean isEmpty() { - return uAuthority.isLocal() && uEntity().isEmpty() - && uResource.isEmpty(); - } - - /** - * @return Returns the Authority represents the deployment location of a specific Software Entity in the Ultiverse. - */ - public UAuthority uAuthority() { - return uAuthority; - } - - /** - * @return Returns the USE in the role of a service or in the role of an application. - */ - public UEntity uEntity() { - return uEntity; - } - - /** - * @return Returns the resource, something that is manipulated by a service such as a Door. - */ - public UResource uResource() { - return this.uResource; - } - - /** - * Support for a lazy generation of the uProtocol Uri string that is used in CloudEvent routing for - * sources and sinks. - * The function used to generate the string is the buildUProtocolUri method in the {@link UriFactory}. - * @return Returns the String that can be used as Source and Sink values of CloudEvents. The value is cached and only calculated on the first call. - */ - public String uProtocolUri() { - if (this.uProtocolUri == null) { - uProtocolUri = UriFactory.buildUProtocolUri(uAuthority(), uEntity(), uResource()); - } - return uProtocolUri; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - UUri uri = (UUri) o; - return Objects.equals(uAuthority, uri.uAuthority) && Objects.equals(uEntity, uri.uEntity) - && Objects.equals(uResource, uri.uResource); - } - - @Override - public int hashCode() { - return Objects.hash(uAuthority, uEntity, uResource); - } - - @Override - public String toString() { - return "Uri{" + - "uAuthority=" + uAuthority + - ", uEntity=" + uEntity + - ", uResource=" + uResource + - '}'; - } -} diff --git a/src/main/java/org/eclipse/uprotocol/uri/factory/UriFactory.java b/src/main/java/org/eclipse/uprotocol/uri/factory/UriFactory.java deleted file mode 100644 index 1d0f3530..00000000 --- a/src/main/java/org/eclipse/uprotocol/uri/factory/UriFactory.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.factory; - -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UEntity; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UUri; - -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * A factory is a part of the software has methods to generate concrete objects, usually of the same type or interface.
- * The URI Factory generates an URI. - */ -public interface UriFactory { - - /** - * Create the uProtocol URI string for source sink and topics from an URI. - * - * @param Uri The URI data object. - * @return Returns the uProtocol URI string from an URI data object - * that can be used as a sink or a source in a uProtocol publish communication. - */ - static String buildUProtocolUri(UUri Uri) { - if (Uri == null || Uri.isEmpty()) { - return new String(); - } - - StringBuilder sb = new StringBuilder(); - - sb.append(buildAuthorityPartOfUri(Uri.uAuthority())); - - if (Uri.uAuthority().isMarkedRemote()) { - sb.append("/"); - } - - if (Uri.uEntity().isEmpty()) { - return sb.toString(); - } - - sb.append(buildSoftwareEntityPartOfUri(Uri.uEntity())); - - sb.append(buildResourcePartOfUri(Uri.uResource())); - - return sb.toString().replaceAll("/+$", ""); - } - - /** - * Create the uProtocol URI string for source sink and topics from the separate parts - * of an URI. - * - * @param uAuthority The Authority represents the deployment location of a specific Software Entity in the Ultiverse. - * @param uEntity The Software Entity in the role of a service or in the role of an application. - * @param uResource The resource is something that is manipulated by a service such as a Door. - * - * @return Returns the uProtocol URI string from an URI data object - * that can be used as a sink or a source in a uProtocol publish communication. - */ - static String buildUProtocolUri(UAuthority uAuthority, UEntity uEntity, UResource uResource) { - return buildUProtocolUri(new UUri(uAuthority, uEntity, uResource)); - } - - - /** - * Create the uProtocol URI string for the source or sink of the CloudEvent that represents an RPC request. - * Use this to generate the URI for the software entity who originated the RPC call. - * As specified in SDV-202 Request for the source and SDV-202 Response for the sink. - * - * @param uAuthority The uAuthority of the software entity requesting the RPC. - * @param uEntitySource The software entity requesting the RPC. - * @return Returns the uProtocol URI string that can be used in a CloudEvent representing the application making an RPC call to a service. - */ - static String buildUriForRpc(UAuthority uAuthority, - UEntity uEntitySource) { - StringBuilder sb = new StringBuilder(); - - sb.append(buildAuthorityPartOfUri(uAuthority)); - if (uAuthority.isMarkedRemote()) { - sb.append("/"); - } - sb.append(buildSoftwareEntityPartOfUri(uEntitySource)); - sb.append("/rpc.response"); - - return sb.toString(); - } - - /** - * Create the uProtocol URI string for the sink of the CloudEvent that represents an RPC request - * or the source of the CloudEvent that represents an RPC response. - * @param uAuthority The uAuthority of the software entity service accepting the RPC. - * @param uEntity The software entity service accepting the RPC. - * @param methodName The name of the RPC method on the service such as UpdateDoor. - * @return Returns Returns the uProtocol URI string for the sink of the CloudEvent that represents - * an RPC request or the source of the CloudEvent that represents an RPC response for RPC scenarios. - */ - static String buildMethodUri(UAuthority uAuthority, UEntity uEntity, String methodName) { - StringBuilder sb = new StringBuilder(); - - sb.append(buildAuthorityPartOfUri(uAuthority)); - if (uAuthority.isMarkedRemote()) { - sb.append("/"); - } - sb.append(buildSoftwareEntityPartOfUri(uEntity)); - - sb.append(buildResourcePartOfUri(UResource.forRpc(methodName))); - - return sb.toString(); - } - - private static String buildResourcePartOfUri(UResource uResource) { - if (uResource.isEmpty()) { - return ""; - } - StringBuilder sb = new StringBuilder("/").append(uResource.name()); - uResource.instance().ifPresent(instance -> sb.append(".").append(instance)); - uResource.message().ifPresent(message -> sb.append("#").append(message)); - - return sb.toString(); - } - - /** - * Create the service part of the uProtocol URI from an software entity object. - * @param use Software Entity representing a service or an application. - */ - private static String buildSoftwareEntityPartOfUri(UEntity use) { - StringBuilder sb = new StringBuilder(use.name().trim()); - sb.append("/"); - use.version().ifPresent(sb::append); - - return sb.toString(); - } - - - /** - * Create the authority part of the uProtocol URI from an authority object. - * @param Authority represents the deployment location of a specific Software Entity in the Ultiverse. - * @return Returns the String representation of the Authority in the uProtocol URI. - */ - private static String buildAuthorityPartOfUri(UAuthority Authority) { - if (Authority.isLocal()) { - return "/"; - } - StringBuilder partialURI = new StringBuilder("//"); - final Optional maybeDevice = Authority.device(); - final Optional maybeDomain = Authority.domain(); - - if (maybeDevice.isPresent()) { - partialURI.append(maybeDevice.get()); - maybeDomain.ifPresent(domain -> partialURI.append(".")); - } - maybeDomain.ifPresent(partialURI::append); - - return partialURI.toString(); - } - - /** - * Create an URI data object from a uProtocol string. - * @param uProtocolUri A String uProtocol URI. - * @return Returns an URI data object. - */ - static UUri parseFromUri(String uProtocolUri) { - if (uProtocolUri == null || uProtocolUri.isBlank()) { - return UUri.empty(); - } - - String uri = uProtocolUri.contains(":") ? uProtocolUri.substring(uProtocolUri.indexOf(":")+1) : uProtocolUri - .replace('\\', '/'); - - boolean isLocal = !uri.startsWith("//"); - - final String[] uriParts = uri.split("/"); - final int numberOfPartsInUri = uriParts.length; - - if(numberOfPartsInUri == 0 || numberOfPartsInUri == 1) { - return isLocal ? UUri.empty() : - new UUri(UAuthority.remote("", ""), UEntity.empty(), UResource.empty()); - } - - String useName; - String useVersion = ""; - - UResource uResource; - - UAuthority uAuthority; - if(isLocal) { - uAuthority = UAuthority.local(); - useName = uriParts[1]; - if (numberOfPartsInUri > 2) { - useVersion = uriParts[2]; - - uResource = numberOfPartsInUri > 3 ? buildResource(uriParts[3]) : UResource.empty(); - - } else { - uResource = UResource.empty(); - } - } else { - String[] authorityParts = uriParts[2].split("\\."); - String device = authorityParts[0]; - String domain = ""; - if (authorityParts.length > 1) { - domain = Arrays.stream(authorityParts) - .skip(1) - .collect(Collectors.joining(".")); - } - uAuthority = UAuthority.remote(device, domain); - - if (uriParts.length > 3) { - useName = uriParts[3]; - if (numberOfPartsInUri > 4) { - useVersion = uriParts[4]; - - uResource = numberOfPartsInUri > 5 ? buildResource(uriParts[5]) : UResource.empty(); - - } else { - uResource = UResource.empty(); - } - } else { - return new UUri(uAuthority, UEntity.empty(), UResource.empty()); - } - - } - - return new UUri(uAuthority, new UEntity(useName, useVersion), uResource); - } - - private static UResource buildResource(String resourceString) { - String[] parts = resourceString.split("#"); - String nameAndInstance = parts[0]; - String[] nameAndInstanceParts = nameAndInstance.split("\\."); - String resourceName = nameAndInstanceParts[0]; - String resourceInstance = nameAndInstanceParts.length > 1 ? nameAndInstanceParts[1] : null; - String resourceMessage = parts.length > 1 ? parts[1] : null; - return new UResource(resourceName, resourceInstance, resourceMessage); - } - -} diff --git a/src/main/java/org/eclipse/uprotocol/uri/serializer/LongUriSerializer.java b/src/main/java/org/eclipse/uprotocol/uri/serializer/LongUriSerializer.java new file mode 100644 index 00000000..57a98027 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/uri/serializer/LongUriSerializer.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.uri.serializer; + + +import java.util.Objects; +import java.util.Optional; +import org.eclipse.uprotocol.uri.validator.UriValidator; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; + +/** + * UUri Serializer that serializes a UUri to a long format string per + * https://github.com/eclipse-uprotocol/uprotocol-spec/blob/main/basics/uri.adoc + */ +public class LongUriSerializer implements UriSerializer { + + private static final LongUriSerializer INSTANCE = new LongUriSerializer(); + + private LongUriSerializer(){} + + public static LongUriSerializer instance() { + return INSTANCE; + } + + /** + * Support for serializing {@link UUri} objects into their String format. + * @param Uri {@link UUri} object to be serialized to the String format. + * @return Returns the String format of the supplied {@link UUri} that can be used as a sink or a source in a uProtocol publish communication. + */ + @Override + public String serialize(UUri Uri) { + if (Uri == null || UriValidator.isEmpty(Uri)) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + + if (Uri.hasAuthority()) { + sb.append(buildAuthorityPartOfUri(Uri.getAuthority())); + } + sb.append("/"); + + sb.append(buildSoftwareEntityPartOfUri(Uri.getEntity())); + + sb.append(buildResourcePartOfUri(Uri)); + + return sb.toString().replaceAll("/+$", ""); + } + + private static String buildResourcePartOfUri(UUri uri) { + if (!uri.hasResource()) { + return ""; + } + final UResource uResource = uri.getResource(); + + StringBuilder sb = new StringBuilder("/"); + sb.append(uResource.getName()); + + if (uResource.hasInstance()) { + sb.append(".").append(uResource.getInstance()); + } + if (uResource.hasMessage()) { + sb.append("#").append(uResource.getMessage()); + } + + return sb.toString(); + } + + /** + * Create the service part of the uProtocol URI from an software entity object. + * @param use Software Entity representing a service or an application. + */ + private static String buildSoftwareEntityPartOfUri(UEntity use) { + StringBuilder sb = new StringBuilder(use.getName().trim()); + sb.append("/"); + if (use.getVersionMajor() > 0) { + sb.append(use.getVersionMajor()); + } + + return sb.toString(); + } + + + /** + * Create the authority part of the uProtocol URI from an authority object. + * @param Authority represents the deployment location of a specific Software Entity. + * @return Returns the String representation of the Authority in the uProtocol URI. + */ + private static String buildAuthorityPartOfUri(UAuthority Authority) { + + StringBuilder partialURI = new StringBuilder("//"); + final Optional maybeName = Optional.ofNullable(Authority.getName()); + + if (maybeName.isPresent()) { + partialURI.append(maybeName.get()); + } + + return partialURI.toString(); + } + + /** + * Deserialize a String into a UUri object. + * @param uProtocolUri A long format uProtocol URI. + * @return Returns an UUri data object. + */ + @Override + public UUri deserialize(String uProtocolUri) { + if (uProtocolUri == null || uProtocolUri.isBlank()) { + return UUri.getDefaultInstance(); + } + + String uri = uProtocolUri.contains(":") ? uProtocolUri.substring(uProtocolUri.indexOf(":")+1) : uProtocolUri + .replace('\\', '/'); + + boolean isLocal = !uri.startsWith("//"); + + final String[] uriParts = uri.split("/"); + final int numberOfPartsInUri = uriParts.length; + + if(numberOfPartsInUri == 0 || numberOfPartsInUri == 1) { + return UUri.getDefaultInstance(); + } + + String useName; + String useVersion = ""; + + UResource uResource = null; + + UAuthority uAuthority = null; + + if(isLocal) { + useName = uriParts[1]; + if (numberOfPartsInUri > 2) { + useVersion = uriParts[2]; + + if (numberOfPartsInUri > 3) { + uResource = parseFromString(uriParts[3]); + } + } + } else { + // If authority is blank, it is an error + if (uriParts[2].isBlank()) { + return UUri.getDefaultInstance(); + } + uAuthority = UAuthority.newBuilder().setName(uriParts[2]).build(); + + if (uriParts.length > 3) { + useName = uriParts[3]; + if (numberOfPartsInUri > 4) { + useVersion = uriParts[4]; + + if (numberOfPartsInUri > 5) { + uResource = parseFromString(uriParts[5]); + } + + } + } else { + return UUri.newBuilder() + .setAuthority(uAuthority) + .build(); + } + } + + Integer useVersionInt = null; + try { + if (!useVersion.isBlank()) { + useVersionInt = Integer.valueOf(useVersion); + } + } catch (NumberFormatException ignored) { + return UUri.getDefaultInstance(); + } + + UEntity.Builder uEntityBuilder = UEntity.newBuilder().setName(useName); + + if (useVersionInt != null) { + uEntityBuilder.setVersionMajor(useVersionInt); + } + + UUri.Builder uriBuilder = UUri.newBuilder().setEntity(uEntityBuilder); + if (uAuthority != null) { + uriBuilder.setAuthority(uAuthority); + } + if (uResource != null) { + uriBuilder.setResource(uResource); + } + return uriBuilder.build(); + } + + /** + * Static factory method for creating a UResource using a string that contains + * name + instance + message. + * @param resourceString String that contains the UResource information. + * @return Returns a UResource object. + */ + private static UResource parseFromString(String resourceString) { + Objects.requireNonNull(resourceString, " Resource must have a command name."); + String[] parts = resourceString.split("#"); + String nameAndInstance = parts[0]; + + String[] nameAndInstanceParts = nameAndInstance.split("\\."); + String resourceName = nameAndInstanceParts[0]; + String resourceInstance = nameAndInstanceParts.length > 1 ? nameAndInstanceParts[1] : null; + String resourceMessage = parts.length > 1 ? parts[1] : null; + + UResource.Builder uResourceBuilder = UResource.newBuilder().setName(resourceName); + if (resourceInstance != null) { + uResourceBuilder.setInstance(resourceInstance); + } + if (resourceMessage != null) { + uResourceBuilder.setMessage(resourceMessage); + } + + return uResourceBuilder.build(); + } + +} diff --git a/src/main/java/org/eclipse/uprotocol/uri/serializer/MicroUriSerializer.java b/src/main/java/org/eclipse/uprotocol/uri/serializer/MicroUriSerializer.java new file mode 100644 index 00000000..3a048001 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/uri/serializer/MicroUriSerializer.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.uri.serializer; + + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Optional; + +import org.eclipse.uprotocol.uri.validator.UriValidator; +import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; + +import com.google.protobuf.ByteString; + +/** + * UUri Serializer that serializes a UUri to a byte[] (micro format) per + * ... + */ +public class MicroUriSerializer implements UriSerializer { + + static final int LOCAL_MICRO_URI_LENGTH = 8; // local micro URI length + + static final int IPV4_MICRO_URI_LENGTH = 12; // IPv4 micro URI length + + static final int IPV6_MICRO_URI_LENGTH = 24; // IPv6 micro UriPart length + + static final byte UP_VERSION = 0x1; // UP version + + private static final MicroUriSerializer INSTANCE = new MicroUriSerializer(); + + private MicroUriSerializer(){} + + public static MicroUriSerializer instance() { + return INSTANCE; + } + + /** + * The type of address used for Micro URI. + */ + private enum AddressType { + LOCAL(0), + IPv4(1), + IPv6(2), + ID(3); + + private final int value; + + AddressType(int value) { + this.value = value; + } + + public byte getValue() { + return (byte)value; + } + + public static Optional from(int value) { + return Arrays.stream(AddressType.values()) + .filter(p -> p.getValue() == value) + .findAny(); + } + } + + /** + * Serialize a UUri into a byte[] following the Micro-URI specifications. + * @param Uri The {@link UUri} data object. + * @return Returns a byte[] representing the serialized {@link UUri}. + */ + @Override + public byte[] serialize(UUri Uri) { + AddressType type = AddressType.LOCAL; + + if (Uri == null || UriValidator.isEmpty(Uri) || !UriValidator.isMicroForm(Uri)) { + return new byte[0]; + } + + Optional maybeUeId = Optional.ofNullable(Uri.getEntity().getId()); + Optional maybeUResourceId = Optional.ofNullable(Uri.getResource().getId()); + + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + // UP_VERSION + os.write(UP_VERSION); + + // Determine the uAuthority type to be written + switch (Uri.getAuthority().getRemoteCase()) { + case REMOTE_NOT_SET: + type = AddressType.LOCAL; + break; + case IP: + final Integer length = Uri.getAuthority().getIp().size(); + if (length == 4) { + type = AddressType.IPv4; + } else if (length == 16) { + type = AddressType.IPv6; + } else { + return new byte[0]; + } + break; + + case ID: + type = AddressType.ID; + break; + + default: + return new byte[0]; + } + + + + os.write(type.getValue()); + + // URESOURCE_ID + os.write(maybeUResourceId.get()>>8); + os.write(maybeUResourceId.get()); + + // UENTITY_ID + os.write(maybeUeId.get()>>8); + os.write(maybeUeId.get()); + + // UE_VERSION + os.write(Uri.getEntity().getVersionMajor() == 0 ? (byte)0 : Uri.getEntity().getVersionMajor()); + + // UNUSED + os.write((byte)0); + + // UAUTHORITY_ADDRESS + final Optional maybeUAuthorityAddressBytes; + switch(Uri.getAuthority().getRemoteCase()) { + case IP: + maybeUAuthorityAddressBytes = Optional.ofNullable(Uri.getAuthority().getIp().toByteArray()); + break; + case ID: + maybeUAuthorityAddressBytes = Optional.ofNullable(Uri.getAuthority().getId().toByteArray()); + break; + default: + maybeUAuthorityAddressBytes = Optional.empty(); + } + + // Write the ID length if the type is ID + if (maybeUAuthorityAddressBytes.isPresent()) { + if (Uri.getAuthority().getRemoteCase() == UAuthority.RemoteCase.IP) { + os.write(Uri.getAuthority().getId().size()); + } + + try { + os.write(maybeUAuthorityAddressBytes.get()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + return os.toByteArray(); + + } + + + /** + * Deserialize a byte[] into a {@link UUri} object. + * @param microUri A byte[] uProtocol micro URI. + * @return Returns an {@link UUri} data object from the serialized format of a microUri. + */ + @Override + public UUri deserialize(byte[] microUri) { + if (microUri == null || microUri.length < LOCAL_MICRO_URI_LENGTH ) { + return UUri.getDefaultInstance(); + } + + // Need to be version 1 + if (microUri[0] != 0x1) { + return UUri.getDefaultInstance(); + } + + int uResourceId = ((microUri[2] & 0xFF) << 8) | (microUri[3] & 0xFF); + + Optional type = AddressType.from(microUri[1]); + + // Validate Type is found + if (type.isEmpty()) { + return UUri.getDefaultInstance(); + } + + // Validate that the microUri is the correct length for the type + final AddressType addressType = type.get(); + if (addressType == AddressType.LOCAL && microUri.length != LOCAL_MICRO_URI_LENGTH) { + return UUri.getDefaultInstance(); + } + else if (addressType == AddressType.IPv4 && microUri.length != IPV4_MICRO_URI_LENGTH) { + return UUri.getDefaultInstance(); + } + else if (addressType == AddressType.IPv6 && microUri.length != IPV6_MICRO_URI_LENGTH) { + return UUri.getDefaultInstance(); + } + + // UENTITY_ID + int ueId = ((microUri[4] & 0xFF) << 8) | (microUri[5] & 0xFF); + + // UE_VERSION + int uiVersion = Byte.toUnsignedInt(microUri[6]); + + // Calculate uAuthority + UAuthority uAuthority = null; + switch (addressType) { + case IPv4: + case IPv6: + uAuthority = UAuthority.newBuilder().setIp(ByteString.copyFrom(microUri, 8, + addressType == AddressType.IPv4 ? 4 : 16)).build(); + break; + case ID: + int length = microUri[8]; + uAuthority = UAuthority.newBuilder().setId(ByteString.copyFrom(microUri, 9, + length)).build(); + break; + default: + break; + } + + UUri.Builder uriBuilder = UUri.newBuilder() + .setEntity(UEntity.newBuilder() + .setId(ueId) + .setVersionMajor(uiVersion)) + .setResource(UResource.newBuilder() + .setId(uResourceId)); + if (uAuthority != null) { + uriBuilder.setAuthority(uAuthority); + } + + return uriBuilder.build(); + } + +} diff --git a/src/main/java/org/eclipse/uprotocol/uri/serializer/UriSerializer.java b/src/main/java/org/eclipse/uprotocol/uri/serializer/UriSerializer.java new file mode 100644 index 00000000..0350de46 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/uri/serializer/UriSerializer.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.uri.serializer; + + +import java.util.Optional; + +import org.eclipse.uprotocol.uri.validator.UriValidator; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; + +/** + * UUris are used in transport layers and hence need to be serialized. + * Each transport supports different serialization formats. + * For more information, please refer to ... + * @param The data structure that the UUri will be serialized into. For example String or byte[]. + */ +public interface UriSerializer { + + /** + * Deserialize from the format to a {@link UUri}. + * @param uri serialized UUri. + * @return Returns a {@link UUri} object from the serialized format from the wire. + */ + UUri deserialize(T uri); + + /** + * Serialize from a {@link UUri} to a specific serialization format. + * @param uri UUri object to be serialized to the format T. + * @return Returns the {@link UUri} in the transport serialized format. + */ + T serialize(UUri uri); + + /** + * Build a fully resolved {@link UUri} from the serialized long format and the serializes micro format. + * @param longUri {@link UUri} serialized as a Sting. + * @param microUri {@link UUri} serialized as a byte[]. + * @return Returns a {@link UUri} object serialized from one of the forms. + */ + default Optional buildResolved(String longUri, byte[] microUri) { + + if ((longUri == null || longUri.isEmpty()) && (microUri == null || microUri.length == 0)) { + return Optional.of(UUri.getDefaultInstance()); + } + + UUri longUUri = LongUriSerializer.instance().deserialize(longUri); + UUri microUUri = MicroUriSerializer.instance().deserialize(microUri); + + final UAuthority.Builder uAuthorityBuilder = + UAuthority.newBuilder(microUUri.getAuthority()) + .setName(longUUri.getAuthority().getName()); + + + final UEntity.Builder uEntityBuilder = UEntity.newBuilder(microUUri.getEntity()) + .setName(longUUri.getEntity().getName()); + + + final UResource.Builder uResourceBuilder = UResource.newBuilder(longUUri.getResource()) + .setId(microUUri.getResource().getId()); + + UUri uUri = UUri.newBuilder() + .setAuthority(uAuthorityBuilder) + .setEntity(uEntityBuilder) + .setResource(uResourceBuilder) + .build(); + return UriValidator.isResolved(uUri) ? Optional.of(uUri) : Optional.empty(); + } + +} diff --git a/src/main/java/org/eclipse/uprotocol/uri/validator/UriValidator.java b/src/main/java/org/eclipse/uprotocol/uri/validator/UriValidator.java new file mode 100644 index 00000000..16223542 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/uri/validator/UriValidator.java @@ -0,0 +1,153 @@ +package org.eclipse.uprotocol.uri.validator; + +import java.util.Objects; + +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.validation.ValidationResult; + +/** + * class for validating Uris. + */ +public interface UriValidator { + + /** + * Validate a {@link UUri} to ensure that it has at least a name for the uEntity. + * @param uri {@link UUri} to validate. + * @return Returns UStatus containing a success or a failure with the error message. + */ + static ValidationResult validate(UUri uri) { + if (isEmpty(uri)) { + return ValidationResult.failure("Uri is empty."); + } + if (uri.hasAuthority() && !isRemote(uri.getAuthority())) { + return ValidationResult.failure("Uri is remote missing uAuthority."); + } + + if (uri.getEntity().getName().isBlank()) { + return ValidationResult.failure("Uri is missing uSoftware Entity name."); + } + + return ValidationResult.success(); + } + + /** + * Validate a {@link UUri} that is meant to be used as an RPC method URI. Used in Request sink values and Response source values. + * @param uri {@link UUri} to validate. + * @return Returns UStatus containing a success or a failure with the error message. + */ + static ValidationResult validateRpcMethod(UUri uri) { + ValidationResult status = validate(uri); + if (status.isFailure()){ + return status; + } + + if (!isRpcMethod(uri)) { + return ValidationResult.failure("Invalid RPC method uri. Uri should be the method to be called, or method from response."); + } + return ValidationResult.success(); + } + + /** + * Validate a {@link UUri} that is meant to be used as an RPC response URI. Used in Request source values and Response sink values. + * @param uri {@link UUri} to validate. + * @return Returns UStatus containing a success or a failure with the error message. + */ + static ValidationResult validateRpcResponse(UUri uri) { + ValidationResult status = validate(uri); + if (status.isFailure()){ + return status; + } + + if (!isRpcResponse(uri)) { + return ValidationResult.failure("Invalid RPC response type."); + } + + return ValidationResult.success(); + } + + + /** + * Indicates that this URI is an empty as it does not contain authority, entity, and resource. + * @param uri {@link UUri} to check if it is empty + * @return Returns true if this URI is an empty container and has no valuable information in building uProtocol sinks or sources. + */ + static boolean isEmpty(UUri uri) { + Objects.requireNonNull(uri, "Uri cannot be null."); + return !uri.hasAuthority() && !uri.hasEntity() && !uri.hasResource(); + } + + + /** + * Returns true if URI is of type RPC. + * @param uri {@link UUri} to check if it is of type RPC method + * @return Returns true if URI is of type RPC. + */ + static boolean isRpcMethod(UUri uri) { + Objects.requireNonNull(uri, "Uri cannot be null."); + return !isEmpty(uri) && uri.getResource().getName().contains("rpc"); + } + + /** + * Returns true if URI contains both names and numeric representations of the names inside its belly. + * Meaning that this UUri can be serialized to long or micro formats. + * @param uri {@link UUri} to check if resolved. + * @return Returns true if URI contains both names and numeric representations of the names inside its belly. + * Meaning that this UUri can buree serialized to long or micro formats. + */ + static boolean isResolved(UUri uri) { + Objects.requireNonNull(uri, "Uri cannot be null."); + return !isEmpty(uri); + // TODO: Finish this + } + + + /** + * Returns true if URI is of type RPC response. + * @param uri {@link UUri} to check response + * @return Returns true if URI is of type RPC response. + */ + static boolean isRpcResponse(UUri uri) { + Objects.requireNonNull(uri, "Uri cannot be null."); + final UResource resource = uri.getResource(); + return isRpcMethod(uri) && + ((resource.hasInstance() && resource.getInstance().contains("response")) || + (resource.hasId() && resource.getId() == 0)); + } + + + + /** + * Returns true if URI contains numbers so that it can be serialized into micro format. + * @param uri {@link UUri} to check + * @return Returns true if URI contains numbers so that it can be serialized into micro format. + */ + static boolean isMicroForm(UUri uri) { + Objects.requireNonNull(uri, "Uri cannot be null."); + + return !isEmpty(uri) && + uri.getEntity().hasId() && + uri.getResource().hasId() && + (!uri.hasAuthority() || uri.getAuthority().hasIp() || uri.getAuthority().hasId()); + } + + /** + * Returns true if URI contains names so that it can be serialized into long format. + * @param uri {@link UUri} to check + * @return Returns true if URI contains names so that it can be serialized into long format. + */ + static boolean isLongForm(UUri uri) { + Objects.requireNonNull(uri, "Uri cannot be null."); + return !isEmpty(uri) && + !(uri.hasAuthority() && !uri.getAuthority().hasName()) && + !uri.getEntity().getName().isBlank() && + !uri.getResource().getName().isBlank(); + } + + + static boolean isRemote(UAuthority authority) { + Objects.requireNonNull(authority, "Uri cannot be null."); + return authority.getRemoteCase() != UAuthority.RemoteCase.REMOTE_NOT_SET; + } +} diff --git a/src/main/java/org/eclipse/uprotocol/uuid/README.adoc b/src/main/java/org/eclipse/uprotocol/uuid/README.adoc new file mode 100644 index 00000000..e61f7ae2 --- /dev/null +++ b/src/main/java/org/eclipse/uprotocol/uuid/README.adoc @@ -0,0 +1,8 @@ += uProtocol UUID +:toc: +:sectnums: + +== Overview + +_comming soon_ + 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 dae9a971..d4bfcbdd 100644 --- a/src/main/java/org/eclipse/uprotocol/uuid/validate/UuidValidator.java +++ b/src/main/java/org/eclipse/uprotocol/uuid/validate/UuidValidator.java @@ -21,8 +21,8 @@ package org.eclipse.uprotocol.uuid.validate; -import org.eclipse.uprotocol.cloudevent.validate.ValidationResult; import org.eclipse.uprotocol.uuid.factory.UUIDUtils; +import org.eclipse.uprotocol.validation.ValidationResult; import com.github.f4b6a3.uuid.enums.UuidVariant; import com.google.rpc.Code; diff --git a/src/main/java/org/eclipse/uprotocol/cloudevent/validate/ValidationResult.java b/src/main/java/org/eclipse/uprotocol/validation/ValidationResult.java similarity index 98% rename from src/main/java/org/eclipse/uprotocol/cloudevent/validate/ValidationResult.java rename to src/main/java/org/eclipse/uprotocol/validation/ValidationResult.java index e38ca889..81378c03 100644 --- a/src/main/java/org/eclipse/uprotocol/cloudevent/validate/ValidationResult.java +++ b/src/main/java/org/eclipse/uprotocol/validation/ValidationResult.java @@ -19,7 +19,7 @@ * under the License. */ -package org.eclipse.uprotocol.cloudevent.validate; +package org.eclipse.uprotocol.validation; import com.google.rpc.Code; import com.google.rpc.Status; diff --git a/src/test/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventTypeTest.java b/src/test/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventTypeTest.java index 09bc6422..b8f257ef 100644 --- a/src/test/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventTypeTest.java +++ b/src/test/java/org/eclipse/uprotocol/cloudevent/datamodel/UCloudEventTypeTest.java @@ -36,12 +36,6 @@ public void test_type_for_publish() { assertEquals("pub.v1", uCloudEventType.type()); } - @Test - @DisplayName("Test the type for a file event type") - public void test_type_for_file() { - UCloudEventType uCloudEventType = UCloudEventType.FILE; - assertEquals("file.v1", uCloudEventType.type()); - } @Test @DisplayName("Test the type for a request RPC event type") @@ -65,14 +59,6 @@ public void test_parse_publish_event_type_from_string() { assertEquals(UCloudEventType.PUBLISH, UCloudEventType.valueOfType(type).get()); } - @Test - @DisplayName("Test parsing the file event type from a string") - public void test_parse_file_event_type_from_string() { - String type = "file.v1"; - assertTrue(UCloudEventType.valueOfType(type).isPresent()); - assertEquals(UCloudEventType.FILE, UCloudEventType.valueOfType(type).get()); - } - @Test @DisplayName("Test parsing the request event type from a string") public void test_parse_request_event_type_from_string() { diff --git a/src/test/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactoryTest.java b/src/test/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactoryTest.java index 3cec0d5d..d8532f12 100644 --- a/src/test/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactoryTest.java +++ b/src/test/java/org/eclipse/uprotocol/cloudevent/factory/CloudEventFactoryTest.java @@ -21,17 +21,17 @@ package org.eclipse.uprotocol.cloudevent.factory; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UEntity; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.eclipse.uprotocol.uri.factory.UriFactory; import com.google.protobuf.Any; import com.google.rpc.Code; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -41,17 +41,14 @@ class CloudEventFactoryTest { + private static final String DATA_CONTENT_TYPE = CloudEventFactory.PROTOBUF_CONTENT_TYPE; @Test @DisplayName("Test create base CloudEvent") public void test_create_base_cloud_event() { - // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -89,11 +86,7 @@ public void test_create_base_cloud_event() { @DisplayName("Test create base CloudEvent with datacontenttype and dataschema") public void test_create_base_cloud_event_with_datacontenttype_and_schema() { - // source - UEntity use = UEntity.fromName("body.access"); - UUri ultifiUri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(ultifiUri); + String source = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -137,11 +130,7 @@ public void test_create_base_cloud_event_with_datacontenttype_and_schema() { @DisplayName("Test create base CloudEvent without attributes") public void test_create_base_cloud_event_without_attributes() { - // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -175,10 +164,7 @@ public void test_create_base_cloud_event_without_attributes() { public void test_create_publish_cloud_event() { // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -209,15 +195,10 @@ public void test_create_publish_cloud_event() { public void test_create_notification_cloud_event() { // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildUriForTest(); // sink - UEntity sinkUse = UEntity.fromName("petapp"); - UUri sinkUri = new UUri(UAuthority.remote("com.gm.bo", "bo"), sinkUse, "OK"); - String sink = UriFactory.buildUProtocolUri(sinkUri); + String sink = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -252,15 +233,11 @@ public void test_create_notification_cloud_event() { @DisplayName("Test create request RPC CloudEvent coming from a local USE") public void test_create_request_cloud_event_from_local_use() { - // Uri for the application requesting the RPC - UEntity sourceUse = UEntity.fromName("petapp"); - String applicationUriForRPC = UriFactory.buildUriForRpc(UAuthority.local(), sourceUse); + // UriPart for the application requesting the RPC + String applicationUriForRPC = buildUriForTest(); - // service Method Uri - UEntity methodSoftwareEntityService = new UEntity("body.access", "1"); - UUri methodUri = new UUri(UAuthority.local(), methodSoftwareEntityService, - UResource.forRpc("UpdateDoor")); - String serviceMethodUri = UriFactory.buildUProtocolUri(methodUri); + // service Method UriPart + String serviceMethodUri = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -278,10 +255,10 @@ public void test_create_request_cloud_event_from_local_use() { assertEquals("1.0", cloudEvent.getSpecVersion().toString()); assertNotNull(cloudEvent.getId()); - assertEquals("/petapp//rpc.response", cloudEvent.getSource().toString()); + assertEquals(applicationUriForRPC, cloudEvent.getSource().toString()); assertTrue(cloudEvent.getExtensionNames().contains("sink")); - assertEquals("/body.access/1/rpc.UpdateDoor", Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); + assertEquals(serviceMethodUri, Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); assertEquals("req.v1", cloudEvent.getType()); assertEquals("somehash", cloudEvent.getExtension("hash")); @@ -293,66 +270,16 @@ public void test_create_request_cloud_event_from_local_use() { } - @Test - @DisplayName("Test create request RPC CloudEvent coming from a remote USE") - public void test_create_request_cloud_event_from_remote_use() { - - // Uri for the application requesting the RPC - UAuthority sourceUseAuthority = UAuthority.remote("bo", "cloud"); - UEntity sourceUse = new UEntity("petapp", "1"); - String applicationUriForRPC = UriFactory.buildUriForRpc(sourceUseAuthority, sourceUse); - - // service Method Uri - UEntity methodSoftwareEntityService = new UEntity("body.access", "1"); - UUri methodUri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), - methodSoftwareEntityService, - UResource.forRpc("UpdateDoor")); - String serviceMethodUri = UriFactory.buildUProtocolUri(methodUri); - - // fake payload - final Any protoPayload = buildProtoPayloadForTest(); - - // additional attributes - final UCloudEventAttributes uCloudEventAttributes = new UCloudEventAttributes.UCloudEventAttributesBuilder() - .withHash("somehash") - .withPriority(UCloudEventAttributes.Priority.OPERATIONS) - .withTtl(3) - .withToken("someOAuthToken") - .build(); - - final CloudEvent cloudEvent = CloudEventFactory.request(applicationUriForRPC, serviceMethodUri, - protoPayload, uCloudEventAttributes); - - assertEquals("1.0", cloudEvent.getSpecVersion().toString()); - assertNotNull(cloudEvent.getId()); - assertEquals("//bo.cloud/petapp/1/rpc.response", cloudEvent.getSource().toString()); - - assertTrue(cloudEvent.getExtensionNames().contains("sink")); - assertEquals("//vcu.my_car_vin/body.access/1/rpc.UpdateDoor", Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); - - assertEquals("req.v1", cloudEvent.getType()); - assertEquals("somehash", cloudEvent.getExtension("hash")); - assertEquals(UCloudEventAttributes.Priority.OPERATIONS.qosString(), cloudEvent.getExtension("priority")); - assertEquals(3, cloudEvent.getExtension("ttl")); - assertEquals("someOAuthToken", cloudEvent.getExtension("token")); - - assertArrayEquals(protoPayload.toByteArray(), Objects.requireNonNull(cloudEvent.getData()).toBytes()); - - } @Test @DisplayName("Test create response RPC CloudEvent originating from a local USE") public void test_create_response_cloud_event_originating_from_local_use() { - // Uri for the application requesting the RPC - UEntity sourceUse = new UEntity("petapp", "1"); - String applicationUriForRPC = UriFactory.buildUriForRpc(UAuthority.local(), sourceUse); + // UriPart for the application requesting the RPC + String applicationUriForRPC = buildUriForTest(); - // service Method Uri - UEntity methodSoftwareEntityService = new UEntity("body.access", "1"); - UUri methodUri = new UUri(UAuthority.local(), methodSoftwareEntityService, - UResource.forRpc("UpdateDoor")); - String serviceMethodUri = UriFactory.buildUProtocolUri(methodUri); + // service Method UriPart + String serviceMethodUri = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -369,10 +296,10 @@ public void test_create_response_cloud_event_originating_from_local_use() { assertEquals("1.0", cloudEvent.getSpecVersion().toString()); assertNotNull(cloudEvent.getId()); - assertEquals("/body.access/1/rpc.UpdateDoor", cloudEvent.getSource().toString()); + assertEquals(serviceMethodUri, cloudEvent.getSource().toString()); assertTrue(cloudEvent.getExtensionNames().contains("sink")); - assertEquals("/petapp/1/rpc.response", Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); + assertEquals(applicationUriForRPC, Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); assertEquals("res.v1", cloudEvent.getType()); assertEquals("somehash", cloudEvent.getExtension("hash")); @@ -385,70 +312,16 @@ public void test_create_response_cloud_event_originating_from_local_use() { } - @Test - @DisplayName("Test create response RPC CloudEvent originating from a remote USE") - public void test_create_response_cloud_event_originating_from_remote_use() { - - // Uri for the application requesting the RPC - UAuthority sourceUseAuthority = UAuthority.remote("bo", "cloud"); - UEntity sourceUse = UEntity.fromName("petapp"); - String applicationUriForRPC = UriFactory.buildUriForRpc(sourceUseAuthority, sourceUse); - - // service Method Uri - UEntity methodSoftwareEntityService = new UEntity("body.access", "1"); - UUri methodUri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), - methodSoftwareEntityService, - UResource.forRpc("UpdateDoor")); - String serviceMethodUri = UriFactory.buildUProtocolUri(methodUri); - - // fake payload - final Any protoPayload = buildProtoPayloadForTest(); - - // additional attributes - final UCloudEventAttributes uCloudEventAttributes = new UCloudEventAttributes.UCloudEventAttributesBuilder() - .withHash("somehash") - .withPriority(UCloudEventAttributes.Priority.OPERATIONS) - .withTtl(3) - .build(); - - final CloudEvent cloudEvent = CloudEventFactory.response(applicationUriForRPC, serviceMethodUri, - "requestIdFromRequestCloudEvent", protoPayload, uCloudEventAttributes); - - - assertEquals("1.0", cloudEvent.getSpecVersion().toString()); - assertNotNull(cloudEvent.getId()); - assertEquals("//vcu.my_car_vin/body.access/1/rpc.UpdateDoor", cloudEvent.getSource().toString()); - - assertTrue(cloudEvent.getExtensionNames().contains("sink")); - assertEquals("//bo.cloud/petapp//rpc.response", Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); - - assertEquals("res.v1", cloudEvent.getType()); - assertEquals("somehash", cloudEvent.getExtension("hash")); - assertEquals(UCloudEventAttributes.Priority.OPERATIONS.qosString(), cloudEvent.getExtension("priority")); - assertEquals(3, cloudEvent.getExtension("ttl")); - - assertEquals("requestIdFromRequestCloudEvent", cloudEvent.getExtension("reqid")); - - assertArrayEquals(protoPayload.toByteArray(), Objects.requireNonNull(cloudEvent.getData()).toBytes()); - - } @Test @DisplayName("Test create a failed response RPC CloudEvent originating from a local USE") public void test_create_a_failed_response_cloud_event_originating_from_local_use() { - // Uri for the application requesting the RPC - UEntity sourceUse = new UEntity("petapp", "1"); - String applicationUriForRPC = UriFactory.buildUriForRpc(UAuthority.local(), sourceUse); + // UriPart for the application requesting the RPC + String applicationUriForRPC = buildUriForTest(); - // service Method Uri - UEntity methodSoftwareEntityService = new UEntity("body.access", "1"); - UUri methodUri = new UUri(UAuthority.local(), methodSoftwareEntityService, - UResource.forRpc("UpdateDoor")); - String serviceMethodUri = UriFactory.buildUProtocolUri(methodUri); - - // fake payload - final Any protoPayload = buildProtoPayloadForTest(); + // service Method UriPart + String serviceMethodUri = buildUriForTest(); // additional attributes final UCloudEventAttributes uCloudEventAttributes = new UCloudEventAttributes.UCloudEventAttributesBuilder() @@ -464,10 +337,10 @@ public void test_create_a_failed_response_cloud_event_originating_from_local_use assertEquals("1.0", cloudEvent.getSpecVersion().toString()); assertNotNull(cloudEvent.getId()); - assertEquals("/body.access/1/rpc.UpdateDoor", cloudEvent.getSource().toString()); + assertEquals(serviceMethodUri, cloudEvent.getSource().toString()); assertTrue(cloudEvent.getExtensionNames().contains("sink")); - assertEquals("/petapp/1/rpc.response", Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); + assertEquals(applicationUriForRPC, Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); assertEquals("res.v1", cloudEvent.getType()); assertEquals("somehash", cloudEvent.getExtension("hash")); @@ -480,23 +353,15 @@ public void test_create_a_failed_response_cloud_event_originating_from_local_use } @Test - @DisplayName("Test create a failed response RPC CloudEvent originating from a remote USE") + @DisplayName("Test create a failed response RPC CloudEvent originating from a microRemote USE") public void test_create_a_failed_response_cloud_event_originating_from_remote_use() { - // Uri for the application requesting the RPC - UAuthority sourceUseAuthority = UAuthority.remote("bo", "cloud"); - UEntity sourceUse = UEntity.fromName("petapp"); - String applicationUriForRPC = UriFactory.buildUriForRpc(sourceUseAuthority, sourceUse); + // UriPart for the application requesting the RPC + String applicationUriForRPC = buildUriForTest(); - // service Method Uri - UEntity methodSoftwareEntityService = new UEntity("body.access", "1"); - UUri methodUri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), - methodSoftwareEntityService, - UResource.forRpc("UpdateDoor")); - String serviceMethodUri = UriFactory.buildUProtocolUri(methodUri); + // service Method UriPart + String serviceMethodUri = buildUriForTest(); - // fake payload - final Any protoPayload = buildProtoPayloadForTest(); // additional attributes final UCloudEventAttributes uCloudEventAttributes = new UCloudEventAttributes.UCloudEventAttributesBuilder() @@ -512,10 +377,10 @@ public void test_create_a_failed_response_cloud_event_originating_from_remote_us assertEquals("1.0", cloudEvent.getSpecVersion().toString()); assertNotNull(cloudEvent.getId()); - assertEquals("//vcu.my_car_vin/body.access/1/rpc.UpdateDoor", cloudEvent.getSource().toString()); + assertEquals(serviceMethodUri, cloudEvent.getSource().toString()); assertTrue(cloudEvent.getExtensionNames().contains("sink")); - assertEquals("//bo.cloud/petapp//rpc.response", Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); + assertEquals(applicationUriForRPC, Objects.requireNonNull(cloudEvent.getExtension("sink")).toString()); assertEquals("res.v1", cloudEvent.getType()); assertEquals("somehash", cloudEvent.getExtension("hash")); @@ -527,6 +392,18 @@ public void test_create_a_failed_response_cloud_event_originating_from_remote_us } + private String buildUriForTest() { + + UUri Uri = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")) + .setResource(UResource.newBuilder() + .setName("door") + .setInstance("front_left") + .setMessage("Door")) + .build(); + + return LongUriSerializer.instance().serialize(Uri); + } private Any buildProtoPayloadForTest() { io.cloudevents.v1.proto.CloudEvent cloudEventProto = io.cloudevents.v1.proto.CloudEvent.newBuilder() @@ -539,4 +416,5 @@ private Any buildProtoPayloadForTest() { return Any.pack(cloudEventProto); } + } \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/cloudevent/factory/UCloudEventTest.java b/src/test/java/org/eclipse/uprotocol/cloudevent/factory/UCloudEventTest.java index 0ca88b46..ab99a36d 100644 --- a/src/test/java/org/eclipse/uprotocol/cloudevent/factory/UCloudEventTest.java +++ b/src/test/java/org/eclipse/uprotocol/cloudevent/factory/UCloudEventTest.java @@ -21,20 +21,20 @@ package org.eclipse.uprotocol.cloudevent.factory; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UEntity; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.eclipse.uprotocol.uri.factory.UriFactory; -import org.eclipse.uprotocol.uuid.factory.UUIDFactory; import com.google.protobuf.Any; import com.google.protobuf.InvalidProtocolBufferException; import com.google.rpc.Code; import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; import io.cloudevents.core.builder.CloudEventBuilder; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; + +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.uuid.factory.UUIDFactory; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -43,7 +43,8 @@ import java.time.Instant; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; -import java.util.*; +import java.util.Optional; +import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; @@ -633,7 +634,7 @@ public void test_unpack_payload_by_class_from_cloud_event_proto_message_object() @Test @DisplayName("Test unpack payload by class from cloud event when protobuf Message is not unpack-able") - public void test_unpack_payload_by_class_from_cloud_event_proto_message_object_when_not_valid_message() { + public void test_unpack_payload_by_class_from_cloud_event_proto_message_object_when_not_valid_getMessage() { final CloudEventBuilder cloudEventBuilder = CloudEventBuilder.v1() .withId("someId") .withType("pub.v1") @@ -690,10 +691,15 @@ public void test_pretty_printing_a_cloudevent_without_a_sink() { private CloudEventBuilder buildBaseCloudEventBuilderForTest() { // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + UUri Uri = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")) + .setResource(UResource.newBuilder() + .setName("door") + .setInstance("front_left") + .setMessage("Door")) + .build(); + + String source = LongUriSerializer.instance().serialize(Uri); // fake payload final Any protoPayload = buildProtoPayloadForTest(); diff --git a/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToJsonSerializerTest.java b/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToJsonSerializerTest.java index 3e6f4b91..04587624 100644 --- a/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToJsonSerializerTest.java +++ b/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToJsonSerializerTest.java @@ -21,20 +21,16 @@ package org.eclipse.uprotocol.cloudevent.serialize; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; -import org.eclipse.uprotocol.cloudevent.factory.CloudEventFactory; -import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UEntity; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.eclipse.uprotocol.uri.factory.UriFactory; import com.google.protobuf.Any; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; +import org.eclipse.uprotocol.cloudevent.factory.CloudEventFactory; +import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -163,11 +159,7 @@ public void test_double_serialization_protobuf_when_creating_cloud_event_with_fa final CloudEventSerializer serializer = CloudEventSerializers.JSON.serializer(); - // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = "/body.access//door.front_left#Door"; // fake payload final Any protoPayload = buildProtoPayloadForTest1(); diff --git a/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToProtobufSerializerTest.java b/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToProtobufSerializerTest.java index 5a06c53b..26dd9817 100644 --- a/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToProtobufSerializerTest.java +++ b/src/test/java/org/eclipse/uprotocol/cloudevent/serialize/CloudEventToProtobufSerializerTest.java @@ -21,20 +21,20 @@ package org.eclipse.uprotocol.cloudevent.serialize; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; -import org.eclipse.uprotocol.cloudevent.factory.CloudEventFactory; -import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UEntity; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.eclipse.uprotocol.uri.factory.UriFactory; import com.google.protobuf.Any; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; +import org.eclipse.uprotocol.cloudevent.factory.CloudEventFactory; +import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -55,9 +55,7 @@ class CloudEventToProtobufSerializerTest { public void test_serialize_and_desirialize_cloud_event_to_protobuf() { // build the source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, UResource.fromNameWithInstance("Door", "front_left")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -144,10 +142,7 @@ public void test_double_serialization_protobuf_when_creating_cloud_event_with_fa final CloudEventSerializer serializer = CloudEventSerializers.PROTOBUF.serializer(); // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest1(); @@ -330,6 +325,18 @@ private Any buildProtoPayloadForTest1() { return Any.pack(cloudEventProto); } + private String buildUriForTest() { + UUri Uri = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")) + .setResource(UResource.newBuilder() + .setName("door") + .setInstance("front_left") + .setMessage("Door")) + .build(); + + return LongUriSerializer.instance().serialize(Uri); + } + private Any buildProtoPayloadForTest() { io.cloudevents.v1.proto.CloudEvent cloudEventProto = io.cloudevents.v1.proto.CloudEvent.newBuilder() .setSpecVersion("1.0") diff --git a/src/test/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidatorTest.java b/src/test/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidatorTest.java index 7597c310..81113b37 100644 --- a/src/test/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidatorTest.java +++ b/src/test/java/org/eclipse/uprotocol/cloudevent/validate/CloudEventValidatorTest.java @@ -21,21 +21,22 @@ package org.eclipse.uprotocol.cloudevent.validate; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; -import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; -import org.eclipse.uprotocol.cloudevent.factory.CloudEventFactory; -import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UEntity; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.eclipse.uprotocol.uri.factory.UriFactory; -import org.eclipse.uprotocol.uuid.factory.UUIDFactory; import com.google.protobuf.Any; import com.google.rpc.Code; import com.google.rpc.Status; import io.cloudevents.CloudEvent; import io.cloudevents.core.builder.CloudEventBuilder; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventAttributes; +import org.eclipse.uprotocol.cloudevent.datamodel.UCloudEventType; +import org.eclipse.uprotocol.cloudevent.factory.CloudEventFactory; +import org.eclipse.uprotocol.cloudevent.factory.UCloudEvent; +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.uuid.factory.UUIDFactory; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.validation.ValidationResult; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -43,7 +44,9 @@ import java.time.Instant; import java.util.UUID; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class CloudEventValidatorTest { @@ -96,29 +99,6 @@ void test_notification_cloud_event_type() { assertEquals("Invalid CloudEvent type [res.v1]. CloudEvent of type Publish must have a type of 'pub.v1'", status.getMessage()); } - @Test - @DisplayName("Test get a file cloud event validator") - void test_get_a_file_cloud_event_validator() { - CloudEventBuilder builder = buildBaseCloudEventBuilderForTest() - .withType("file.v1"); - CloudEvent cloudEvent = builder.build(); - final CloudEventValidator validator = CloudEventValidator.getValidator(cloudEvent); - final Status status = validator.validateType(cloudEvent).toStatus(); - assertEquals(status, ValidationResult.STATUS_SUCCESS); - assertEquals("CloudEventValidator.File", validator.toString()); - } - - @Test - @DisplayName("Test file cloud event type") - void test_file_cloud_event_type() { - CloudEventBuilder builder = buildBaseCloudEventBuilderForTest() - .withType("res.v1"); - CloudEvent cloudEvent = builder.build(); - final CloudEventValidator validator = CloudEventValidator.Validators.FILE.validator(); - final Status status = validator.validateType(cloudEvent).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid CloudEvent type [res.v1]. CloudEvent of type File must have a type of 'file.v1'", status.getMessage()); - } @Test @DisplayName("Test get a request cloud event validator") @@ -247,534 +227,6 @@ void validate_cloud_event_id_when_not_valid() { assertEquals("Invalid CloudEvent Id [testme]. CloudEvent Id must be of type UUIDv8.", status.getMessage()); } - @Test - @DisplayName("Test validate software entity uri with version, when it is valid remote") - void test_usoftware_entity_uri_with_version_when_it_is_valid_remote() { - - final String uri = "//VCU.MY_CAR_VIN/body.access/1"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate software entity uri no version, when it is valid remote") - void test_usoftware_entity_uri_no_version_when_it_is_valid_remote() { - - final String uri = "//VCU.MY_CAR_VIN/body.access"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate software entity uri with version, when it is valid local") - void test_usoftware_entity_uri_with_version_when_it_is_valid_local() { - - final String uri = "/body.access/1"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate software entity uri no version, when it is valid local") - void test_usoftware_entity_uri_no_version_when_it_is_valid_local() { - - final String uri = "/body.access/"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate software entity uri is invalid when uri contains nothing but schema") - void test_usoftware_entity_uri_invalid_when_uri_has_schema_only() { - - final String uri = ":"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate software entity uri is invalid when uri is remote but missing authority") - void test_usoftware_entity_uri_invalid_when_uri_is_remote_no_authority() { - - final String uri = "//"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate software entity uri is invalid when uri is remote with use but missing authority") - void test_usoftware_entity_uri_invalid_when_uri_is_remote_no_authority_with_use() { - - final String uri = "///body.access/1"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate software entity uri is invalid when uri has no use information") - void test_usoftware_entity_uri_invalid_when_uri_is_missing_use() { - - final String uri = "//VCU.myvin"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate local software entity uri is invalid when uri is missing use name") - void test_usoftware_entity_uri_invalid_when_uri_is_missing_use_name_local() { - - final String uri = "//VCU.myvin//1"; - - final Status status = CloudEventValidator.validateUEntityUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate topic uri with version, when it is valid remote") - void test_topic_uri_with_version_when_it_is_valid_remote() { - - final String uri = "//VCU.MY_CAR_VIN/body.access/1/door.front_left#Door"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate topic uri no version, when it is valid remote") - void test_topic_uri_no_version_when_it_is_valid_remote() { - - final String uri = "//VCU.MY_CAR_VIN/body.access//door.front_left#Door"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate topic uri with version, when it is valid local") - void test_topic_uri_with_version_when_it_is_valid_local() { - - final String uri = "/body.access/1/door.front_left#Door"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate topic uri no version, when it is valid local") - void test_topic_uri_no_version_when_it_is_valid_local() { - - final String uri = "/body.access//door.front_left#Door"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate topic uri is invalid when uri contains nothing but schema") - void test_topic_uri_invalid_when_uri_has_schema_only() { - - final String uri = ":"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate topic uri is invalid when uri contains empty use name local") - void test_topic_uri_invalid_when_uri_has_empty_use_name_local() { - - final String uri = "/"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate topic uri is invalid when uri is remote but missing authority") - void test_topic_uri_invalid_when_uri_is_remote_no_authority() { - - final String uri = "//"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate topic uri is invalid when uri is remote with use but missing authority") - void test_topic_uri_invalid_when_uri_is_remote_no_authority_with_use() { - - final String uri = "///body.access/1/door.front_left#Door"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate topic uri is invalid when uri has no use information") - void test_topic_uri_invalid_when_uri_is_missing_use_remote() { - - final String uri = "//VCU.myvin///door.front_left#Door"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate remote topic uri is invalid when uri is missing use name") - void test_topic_uri_invalid_when_uri_is_missing_use_name_remote() { - - final String uri = "/1/door.front_left#Door"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uResource name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate local topic uri is invalid when uri is missing use name") - void test_topic_uri_invalid_when_uri_is_missing_use_name_local() { - - final String uri = "//VCU.myvin//1"; - - final Status status = CloudEventValidator.validateTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate remote topic uri, when uri has authority and use no version missing resource") - void test_topic_uri_when_uri_is_with_authority_with_use_no_version_missing_resource_remote() { - - final String source = "//VCU.myvin/body.access"; - - final Status status = CloudEventValidator.validateTopicUri(source).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uResource name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate remote topic uri, when uri has authority and use with version missing resource") - void test_topic_uri_when_uri_is_with_authority_with_use_with_version_missing_resource_remote() { - - final String source = "//VCU.myvin/body.access/"; - - final Status status = CloudEventValidator.validateTopicUri(source).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing uResource name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate remote topic uri, when uri has authority and use and resource missing Message") - void test_topic_uri_when_uri_is_with_authority_with_use_with_resource_missing_message_remote() { - - final String source = "//VCU.myvin/body.access/1/door.front_left"; - - final Status status = CloudEventValidator.validateTopicUri(source).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Uri is missing Message information.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc topic uri with version, when it is valid remote") - void test_rpc_topic_uri_with_version_when_it_is_valid_remote() { - - final String uri = "//bo.cloud/petapp/1/rpc.response"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc topic uri no version, when it is valid remote") - void test_rpc_topic_uri_no_version_when_it_is_valid_remote() { - - final String uri = "//bo.cloud/petapp//rpc.response"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc topic uri with version, when it is valid local") - void test_rpc_topic_uri_with_version_when_it_is_valid_local() { - - final String uri = "/petapp/1/rpc.response"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc topic uri no version, when it is valid local") - void test_rpc_topic_uri_no_version_when_it_is_valid_local() { - - final String uri = "/petapp//rpc.response"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc topic uri is invalid when uri contains nothing but schema") - void test_rpc_topic_uri_invalid_when_uri_has_schema_only() { - - final String uri = ":"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc topic uri with version, when it is local but missing rpc.respons") - void test_rpc_topic_uri_with_version_when_it_is_not_valid_missing_rpc_response_local() { - - final String uri = "/petapp/1/dog"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is missing rpc.response.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc topic uri with version, when it is remote but missing rpc.respons") - void test_rpc_topic_uri_with_version_when_it_is_not_valid_missing_rpc_response_remote() { - - final String uri = "//petapp/1/dog"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is missing rpc.response.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc topic uri is invalid when uri is remote but missing authority") - void test_rpc_topic_uri_invalid_when_uri_is_remote_no_authority() { - - final String uri = "//"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc topic uri is invalid when uri is remote with use but missing authority") - void test_rpc_topic_uri_invalid_when_uri_is_remote_no_authority_with_use() { - - final String uri = "///body.access/1"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc topic uri is invalid when uri has no use information") - void test_rpc_topic_uri_invalid_when_uri_is_missing_use() { - - final String uri = "//VCU.myvin"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate remote rpc topic uri is invalid when uri is missing use name") - void test_rpc_topic_uri_invalid_when_uri_is_missing_use_name_remote() { - - final String uri = "/1"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is missing rpc.response.", status.getMessage()); - } - - @Test - @DisplayName("Test validate local rpc topic uri is invalid when uri is missing use name") - void test_rpc_topic_uri_invalid_when_uri_is_missing_use_name_local() { - - final String uri = "//VCU.myvin//1"; - - final Status status = CloudEventValidator.validateRpcTopicUri(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc topic uri with version, when it is valid") - void test_rpc_topic__uri_with_version_when_it_is_valid() { - - UEntity use = new UEntity("petapp", "1"); - UAuthority uAuthority = UAuthority.remote("bo", "cloud"); - UResource uResource = UResource.fromNameWithInstance("rpc", "response"); - UUri Uri = new UUri(uAuthority, use, uResource); - - final Status status = CloudEventValidator.validateRpcTopicUri(Uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc topic uri with version, when it is not valid") - void test_rpc_topic__uri_with_version_when_it_is_not_valid() { - - UEntity use = new UEntity("petapp", "1"); - UAuthority uAuthority = UAuthority.remote("bo", "cloud"); - UResource uResource = UResource.fromNameWithInstance("body.access", "front_left"); - UUri Uri = new UUri(uAuthority, use, uResource); - - final Status status = CloudEventValidator.validateRpcTopicUri(Uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC uri application response topic. Uri is missing rpc.response.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc method uri with version, when it is valid remote") - void test_rpc_method_uri_with_version_when_it_is_valid_remote() { - - final String uri = "//VCU.myvin/body.access/1/rpc.UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc method uri no version, when it is valid remote") - void test_rpc_method_uri_no_version_when_it_is_valid_remote() { - - final String uri = "//VCU.myvin/body.access//rpc.UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc method uri with version, when it is valid local") - void test_rpc_method_uri_with_version_when_it_is_valid_local() { - - final String uri = "/body.access/1/rpc.UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc method uri no version, when it is valid local") - void test_rpc_method_uri_no_version_when_it_is_valid_local() { - - final String uri = "/body.access//rpc.UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test validate rpc method uri is invalid when uri contains nothing but schema") - void test_rpc_method_uri_invalid_when_uri_has_schema_only() { - - final String uri = ":"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc method uri with version, when it is local but not an rpc method") - void test_rpc_method_uri_with_version_when_it_is_not_valid_not_rpc_method_local() { - - final String uri = "/body.access//UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri should be the method to be called, or method from response.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc method uri with version, when it is remote but not an rpc method") - void test_rpc_method_uri_with_version_when_it_is_not_valid_not_rpc_method_remote() { - - final String uri = "//body.access/1/UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri should be the method to be called, or method from response.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc method uri is invalid when uri is remote but missing authority") - void test_rpc_method_uri_invalid_when_uri_is_remote_no_authority() { - - final String uri = "//"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc method uri is invalid when uri is remote with use but missing authority") - void test_rpc_method_uri_invalid_when_uri_is_remote_no_authority_with_use() { - - final String uri = "///body.access/1/rpc.UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri is configured to be remote and is missing uAuthority device name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate rpc method uri is invalid when uri has no use information") - void test_rpc_method_uri_invalid_when_uri_is_missing_use() { - - final String uri = "//VCU.myvin"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri is missing uSoftware Entity name.", status.getMessage()); - } - - @Test - @DisplayName("Test validate local rpc method uri is invalid when uri is missing use name") - void test_rpc_method_uri_invalid_when_uri_is_missing_use_name_local() { - - final String uri = "/1/rpc.UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri should be the method to be called, or method from response.", status.getMessage()); - } - - @Test - @DisplayName("Test validate remote rpc method uri is invalid when uri is missing use name") - void test_rpc_method_uri_invalid_when_uri_is_missing_use_name_remote() { - - final String uri = "//VCU.myvin//1/rpc.UpdateDoor"; - - final Status status = CloudEventValidator.validateRpcMethod(uri).toStatus(); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC method uri. Uri is missing uSoftware Entity name.", status.getMessage()); - } - @Test @DisplayName("Test local Publish type CloudEvent is valid everything is valid") void test_publish_type_cloudevent_is_valid_when_everything_is_valid_local() { @@ -790,7 +242,7 @@ void test_publish_type_cloudevent_is_valid_when_everything_is_valid_local() { } @Test - @DisplayName("Test remote Publish type CloudEvent is valid everything is valid") + @DisplayName("Test microRemote Publish type CloudEvent is valid everything is valid") void test_publish_type_cloudevent_is_valid_when_everything_is_valid_remote() { UUID uuid = UUIDFactory.Factories.UPROTOCOL.factory().create(); CloudEventBuilder builder = buildBaseCloudEventBuilderForTest() @@ -804,7 +256,7 @@ void test_publish_type_cloudevent_is_valid_when_everything_is_valid_remote() { } @Test - @DisplayName("Test remote Publish type CloudEvent is valid everything is valid with a sink") + @DisplayName("Test microRemote Publish type CloudEvent is valid everything is valid with a sink") void test_publish_type_cloudevent_is_valid_when_everything_is_valid_remote_with_a_sink() { UUID uuid = UUIDFactory.Factories.UPROTOCOL.factory().create(); CloudEventBuilder builder = buildBaseCloudEventBuilderForTest() @@ -819,7 +271,7 @@ void test_publish_type_cloudevent_is_valid_when_everything_is_valid_remote_with_ } @Test - @DisplayName("Test remote Publish type CloudEvent is not valid everything is valid with invalid sink") + @DisplayName("Test microRemote Publish type CloudEvent is not valid everything is valid with invalid sink") void test_publish_type_cloudevent_is_not_valid_when_remote_with_invalid_sink() { UUID uuid = UUIDFactory.Factories.UPROTOCOL.factory().create(); CloudEventBuilder builder = buildBaseCloudEventBuilderForTest() @@ -846,7 +298,7 @@ void test_publish_type_cloudevent_is_not_valid_when_source_is_empty() { final CloudEventValidator validator = CloudEventValidator.Validators.PUBLISH.validator(); final Status status = validator.validate(cloudEvent); assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid Publish type CloudEvent source [/]. Uri is missing uSoftware Entity name.", status.getMessage()); + assertEquals("Invalid Publish type CloudEvent source [/]. Uri is empty.", status.getMessage()); } @Test @@ -861,7 +313,7 @@ void test_publish_type_cloudevent_is_not_valid_when_source_is_missing_authority( final Status status = validator.validate(cloudEvent); assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); assertEquals("Invalid CloudEvent Id [testme]. CloudEvent Id must be of type UUIDv8.," + - "Invalid Publish type CloudEvent source [/body.access]. Uri is missing uResource name.", status.getMessage()); + "Invalid Publish type CloudEvent source [/body.access]. UriPart is missing uResource name.", status.getMessage()); } @Test @@ -910,34 +362,6 @@ void test_notification_type_cloudevent_is_not_valid_invalid_sink() { assertEquals("Invalid Notification type CloudEvent sink [//bo.cloud]. Uri is missing uSoftware Entity name.", status.getMessage()); } - @Test - @DisplayName("Test File type CloudEvent is valid everything is valid") - void test_file_type_cloudevent_is_valid_when_everything_is_valid() { - UUID uuid = UUIDFactory.Factories.UPROTOCOL.factory().create(); - CloudEventBuilder builder = buildBaseCloudEventBuilderForTest() - .withId(uuid.toString()) - .withSource(URI.create("/body.access/1/door.front_left#Door")) - .withType(UCloudEventType.FILE.type()); - CloudEvent cloudEvent = builder.build(); - final CloudEventValidator validator = CloudEventValidator.Validators.FILE.validator(); - final Status status = validator.validate(cloudEvent); - assertEquals(ValidationResult.STATUS_SUCCESS, status); - } - - @Test - @DisplayName("Test File type CloudEvent is not valid when source is empty") - void test_file_type_cloudevent_is_not_valid_when_source_is_empty() { - UUID uuid = UUIDFactory.Factories.UPROTOCOL.factory().create(); - CloudEventBuilder builder = buildBaseCloudEventBuilderForTest() - .withId(uuid.toString()) - .withSource(URI.create("/")) - .withType(UCloudEventType.FILE.type()); - CloudEvent cloudEvent = builder.build(); - final CloudEventValidator validator = CloudEventValidator.Validators.FILE.validator(); - final Status status = validator.validate(cloudEvent); - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid Publish type CloudEvent source [/]. Uri is missing uSoftware Entity name.", status.getMessage()); - } @Test @DisplayName("Test Request type CloudEvent is valid everything is valid") @@ -968,7 +392,7 @@ void test_request_type_cloudevent_is_not_valid_invalid_source() { final Status status = validator.validate(cloudEvent); assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); assertEquals("Invalid RPC Request CloudEvent source [//bo.cloud/petapp//dog]. " + - "Invalid RPC uri application response topic. Uri is missing rpc.response.", status.getMessage()); + "Invalid RPC uri application response topic. UriPart is missing rpc.response.", status.getMessage()); } @Test @@ -1000,7 +424,7 @@ void test_request_type_cloudevent_is_not_valid_invalid_sink_not_rpc_command() { final Status status = validator.validate(cloudEvent); assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); assertEquals("Invalid RPC Request CloudEvent sink [//VCU.myvin/body.access/1/UpdateDoor]. " + - "Invalid RPC method uri. Uri should be the method to be called, or method from response.", status.getMessage()); + "Invalid RPC method uri. UriPart should be the method to be called, or method from response.", status.getMessage()); } @Test @@ -1032,7 +456,7 @@ void test_response_type_cloudevent_is_not_valid_invalid_source() { final Status status = validator.validate(cloudEvent); assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); assertEquals("Invalid RPC Response CloudEvent source [//VCU.myvin/body.access/1/UpdateDoor]. " + - "Invalid RPC method uri. Uri should be the method to be called, or method from response.", status.getMessage()); + "Invalid RPC method uri. UriPart should be the method to be called, or method from response.", status.getMessage()); } @Test @@ -1048,7 +472,7 @@ void test_response_type_cloudevent_is_not_valid_missing_sink_and_invalid_source( final Status status = validator.validate(cloudEvent); assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); assertEquals("Invalid RPC Response CloudEvent source [//VCU.myvin/body.access/1/UpdateDoor]. " + - "Invalid RPC method uri. Uri should be the method to be called, or method from response.," + + "Invalid RPC method uri. UriPart should be the method to be called, or method from response.," + "Invalid CloudEvent sink. Response CloudEvent sink must be uri the destination of the response.", status.getMessage()); } @@ -1065,17 +489,14 @@ void test_response_type_cloudevent_is_not_valid_invalid_source_not_rpc_command() final CloudEventValidator validator = CloudEventValidator.Validators.RESPONSE.validator(); final Status status = validator.validate(cloudEvent); assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("Invalid RPC Response CloudEvent source [//bo.cloud/petapp/1/dog]. Invalid RPC method uri. Uri should be the method to be called, or method from response.," + + assertEquals("Invalid RPC Response CloudEvent source [//bo.cloud/petapp/1/dog]. Invalid RPC method uri. UriPart should be the method to be called, or method from response.," + "Invalid RPC Response CloudEvent sink [//VCU.myvin/body.access/1/UpdateDoor]. " + - "Invalid RPC uri application response topic. Uri is missing rpc.response.", status.getMessage()); + "Invalid RPC uri application response topic. UriPart is missing rpc.response.", status.getMessage()); } private CloudEventBuilder buildBaseCloudEventBuilderForTest() { // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildLongUriForTest(); // fake payload final Any protoPayload = buildProtoPayloadForTest(); @@ -1113,10 +534,7 @@ private Any buildProtoPayloadForTest() { public void test_create_a_v6_cloudevent_and_validate_it_against_sdk() { // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildLongUriForTest(); UUID uuid = UUIDFactory.Factories.UUIDV6.factory().create(); String id = uuid.toString(); @@ -1144,10 +562,7 @@ public void test_create_a_v6_cloudevent_and_validate_it_against_sdk() { public void test_create_an_expired_v6_cloudevent() { // source - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, - new UResource("door", "front_left", "Door")); - String source = UriFactory.buildUProtocolUri(Uri); + String source = buildLongUriForTest(); UUID uuid = UUIDFactory.Factories.UUIDV6.factory().create(Instant.now().minusSeconds(100)); String id = uuid.toString(); @@ -1169,4 +584,19 @@ public void test_create_an_expired_v6_cloudevent() { assertEquals(Code.OK_VALUE, status.getCode()); assertTrue(UCloudEvent.isExpired(cloudEvent)); } + + + private String buildLongUriForTest() { + return LongUriSerializer.instance().serialize(buildUUriForTest()); + } + + private UUri buildUUriForTest() { + return UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")) + .setResource(UResource.newBuilder() + .setName("door") + .setInstance("front_left") + .setMessage("Door")) + .build(); + } } \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/cloudevent/validate/ValidationResultTest.java b/src/test/java/org/eclipse/uprotocol/cloudevent/validate/ValidationResultTest.java index ac2cb27c..60edeb93 100644 --- a/src/test/java/org/eclipse/uprotocol/cloudevent/validate/ValidationResultTest.java +++ b/src/test/java/org/eclipse/uprotocol/cloudevent/validate/ValidationResultTest.java @@ -28,6 +28,8 @@ import static org.junit.jupiter.api.Assertions.*; +import org.eclipse.uprotocol.validation.ValidationResult; + class ValidationResultTest { @Test @@ -60,14 +62,14 @@ void test_failure_validation_result_isSuccess() { @Test @DisplayName("Test success message") - void test_success_validation_result_message() { + void test_success_validation_result_getMessage() { ValidationResult success = ValidationResult.success(); assertTrue(success.getMessage().isBlank()); } @Test @DisplayName("Test failure message") - void test_failure_validation_result_message() { + void test_failure_validation_result_getMessage() { ValidationResult failure = ValidationResult.failure("boom"); assertEquals("boom", failure.getMessage()); } diff --git a/src/test/java/org/eclipse/uprotocol/rpc/RpcMapperTest.java b/src/test/java/org/eclipse/uprotocol/rpc/RpcMapperTest.java deleted file mode 100644 index 5fc8ffe2..00000000 --- a/src/test/java/org/eclipse/uprotocol/rpc/RpcMapperTest.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.rpc; - -import com.google.protobuf.Any; -import com.google.protobuf.Int32Value; -import com.google.rpc.Code; -import com.google.rpc.Status; -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.net.URI; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import static org.junit.jupiter.api.Assertions.*; - -class RpcMapperTest { - - Rpc uLinkReturnsNumber3 = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Int32Value.of(3)); - return CompletableFuture.completedFuture(payload); - } - @Override - public String getResponseUri() { - return ""; - } - }; - - Rpc uLinkHappyPath = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(buildProtoPayloadForTest()); - return CompletableFuture.completedFuture(payload); - } - - @Override - public String getResponseUri() { - return ""; - } - }; - - Rpc uLinkWithStatusCodeInsteadOfHappyPath = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Status.newBuilder() - .setCode(Code.INVALID_ARGUMENT_VALUE) - .setMessage("boom") - .build()); - return CompletableFuture.completedFuture(payload); - } - - @Override - public String getResponseUri() { - return ""; - } - }; - - Rpc uLinkWithStatusCodeHappyPath = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Status.newBuilder() - .setCode(Code.OK_VALUE) - .setMessage("all good") - .build()); - return CompletableFuture.completedFuture(payload); - } - - @Override - public String getResponseUri() { - return ""; - } - }; - - Rpc uLinkWithStatusCodeThatFailedHappyPath = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Status.newBuilder() - .setCode(Code.INVALID_ARGUMENT_VALUE) - .setMessage("boom") - .build()); - return CompletableFuture.completedFuture(payload); - } - - @Override - public String getResponseUri() { - return ""; - } - }; - - Rpc uLinkWithNullInPayload = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - return CompletableFuture.completedFuture(null); - } - - @Override - public String getResponseUri() { - return ""; - } - }; - - Rpc uLinkThatCompletesWithAnException = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - return CompletableFuture.failedFuture(new RuntimeException("Boom")); - } - - @Override - public String getResponseUri() { - return ""; - } - }; - - Rpc uLinkThatReturnsTheWrongProto = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Int32Value.of(42)); - return CompletableFuture.completedFuture(payload); - } - - @Override - public String getResponseUri() { - return ""; - } - }; - - @Test - void test_compose_happy_path() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkReturnsNumber3.invokeMethod(request), Int32Value.class) - .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))) - .exceptionally(exception -> { - System.out.println("in exceptionally"); - return RpcResult.failure("boom", exception); - }); - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { - assertTrue(RpcResult.isSuccess()); - assertEquals(Int32Value.of(8), RpcResult.successValue()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - void test_compose_that_returns_status() throws ExecutionException, InterruptedException { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkWithStatusCodeInsteadOfHappyPath.invokeMethod(request), Int32Value.class) - .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))) - .exceptionally(exception -> { - System.out.println("in exceptionally"); - return RpcResult.failure("boom", exception); - }); - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { - assertTrue(RpcResult.isFailure()); - assertEquals(Code.INVALID_ARGUMENT_VALUE, RpcResult.failureValue().getCode()); - assertEquals("boom", RpcResult.failureValue().getMessage()); - }); - assertEquals(rpcResponse.get().failureValue().getCode(), Code.INVALID_ARGUMENT_VALUE); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - void test_compose_with_failure() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkThatCompletesWithAnException.invokeMethod(request), Int32Value.class) - .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))); - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), "java.lang.RuntimeException: Boom"); - } - - @Test - void test_compose_with_failure_transform_Exception() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkThatCompletesWithAnException.invokeMethod(request), Int32Value.class) - .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))) - .exceptionally(exception -> { - System.out.println("in exceptionally"); - return RpcResult.failure("boom", exception); - }); - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { - assertTrue(RpcResult.isFailure()); - assertEquals(Code.UNKNOWN_VALUE, RpcResult.failureValue().getCode()); - assertEquals("boom", RpcResult.failureValue().getMessage()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that returns the expected class successfully") - void test_success_invoke_method_happy_flow_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = - RpcMapper.mapResponse(uLinkHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(cloudEvent -> assertEquals(buildProtoPayloadForTest(), cloudEvent)); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that returns successfully with null in the payload") - void test_success_invoke_method_that_has_null_payload_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = - RpcMapper.mapResponse(uLinkWithNullInPayload.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), "java.lang.RuntimeException: Server returned a null payload. Expected io.cloudevents.v1.proto.CloudEvent"); - - } - - @Test - @DisplayName("Invoke method that expects a Status payload and returns successfully with OK Status in the payload") - void test_success_invoke_method_happy_flow_that_returns_status_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = - RpcMapper.mapResponse(uLinkWithStatusCodeHappyPath.invokeMethod(request), Status.class); - - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(status -> { - assertEquals(Code.OK.getNumber(), status.getCode()); - assertEquals("all good", status.getMessage()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that expects a Status payload and returns successfully with a not OK Status in the payload") - void test_success_invoke_method_happy_flow_that_returns_failed_status_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = - RpcMapper.mapResponse(uLinkWithStatusCodeThatFailedHappyPath.invokeMethod(request), Status.class); - - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(status -> { - assertEquals(Code.INVALID_ARGUMENT_VALUE, status.getCode()); - assertEquals("boom", status.getMessage()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that expects a CloudEvent payload and returns successfully with a Status in the payload") - void test_fail_invoke_method_when_invoke_method_returns_a_status_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = - RpcMapper.mapResponse(uLinkWithStatusCodeInsteadOfHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), "java.lang.RuntimeException: Unknown payload type [type.googleapis.com/google.rpc.Status]. " + - "Expected [io.cloudevents.v1.proto.CloudEvent]"); - } - - @Test - @DisplayName("Invoke method that throws an exception") - void test_fail_invoke_method_when_invoke_method_threw_an_exception_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = - RpcMapper.mapResponse(uLinkThatCompletesWithAnException.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), "java.lang.RuntimeException: Boom"); - } - - @Test - @DisplayName("Invoke method that expects a CloudEvent in the payload but gets an Int32Value") - void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = - RpcMapper.mapResponse(uLinkThatReturnsTheWrongProto.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), - "java.lang.RuntimeException: Unknown payload type [type.googleapis.com/google.protobuf.Int32Value]. Expected [io.cloudevents.v1.proto.CloudEvent]"); - } - - @Test - @DisplayName("Invoke method that returns the expected class successfully, mapResponseToResult") - void test_success_invoke_method_happy_flow_using_mapResponseToResultToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { - assertTrue(RpcResult.isSuccess()); - assertEquals(buildProtoPayloadForTest(), RpcResult.successValue()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that returns successfully with null in the payload, mapResponseToResult") - void test_success_invoke_method_that_has_null_payload_mapResponseToResultToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkWithNullInPayload.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), "java.lang.RuntimeException: Server returned a null payload. Expected io.cloudevents.v1.proto.CloudEvent"); - - } - - @Test - @DisplayName("Invoke method that expects a Status payload and returns successfully with OK Status in the payload, mapResponseToResult") - void test_success_invoke_method_happy_flow_that_returns_status_using_mapResponseToResultToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkWithStatusCodeHappyPath.invokeMethod(request), Status.class); - - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { - assertTrue(RpcResult.isSuccess()); - assertEquals(Code.OK.getNumber(), RpcResult.successValue().getCode()); - assertEquals("all good", RpcResult.successValue().getMessage()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that expects a Status payload and returns successfully with a not OK Status in the payload, mapResponseToResult") - void test_success_invoke_method_happy_flow_that_returns_failed_status_using_mapResponseToResultToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkWithStatusCodeThatFailedHappyPath.invokeMethod(request), Status.class); - - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { - assertTrue(RpcResult.isFailure()); - assertEquals(Code.INVALID_ARGUMENT_VALUE, RpcResult.failureValue().getCode()); - assertEquals("boom", RpcResult.failureValue().getMessage()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that expects a CloudEvent payload and returns successfully with a Status in the payload, mapResponseToResult") - void test_fail_invoke_method_when_invoke_method_returns_a_status_using_mapResponseToResultToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkWithStatusCodeInsteadOfHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { - assertTrue(RpcResult.isFailure()); - assertEquals(Code.INVALID_ARGUMENT.getNumber(), RpcResult.failureValue().getCode()); - assertEquals("boom", RpcResult.failureValue().getMessage()); - }); - assertFalse(test.isCompletedExceptionally()); - } - - @Test - @DisplayName("Invoke method that throws an exception, mapResponseToResult") - void test_fail_invoke_method_when_invoke_method_threw_an_exception_using_mapResponseToResultToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkThatCompletesWithAnException.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), "java.lang.RuntimeException: Boom"); - } - - @Test - @DisplayName("Invoke method that expects a CloudEvent in the payload but gets an Int32Value, mapResponseToResult") - void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto_using_mapResponseToResultToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - RpcMapper.mapResponseToResult(uLinkThatReturnsTheWrongProto.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); - - assertTrue(rpcResponse.isCompletedExceptionally()); - Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), - "java.lang.RuntimeException: Unknown payload type [type.googleapis.com/google.protobuf.Int32Value]. Expected [io.cloudevents.v1.proto.CloudEvent]"); - } - - @Test - void test_unpack_payload_failed() { - Any payload = Any.pack(Int32Value.of(3)); - Exception exception = assertThrows(RuntimeException.class, () -> RpcMapper.unpackPayload(payload, Status.class)); - assertEquals(exception.getMessage(), - "Type of the Any message does not match the given class. [com.google.rpc.Status]"); - } - - private io.cloudevents.v1.proto.CloudEvent buildProtoPayloadForTest() { - return io.cloudevents.v1.proto.CloudEvent.newBuilder() - .setSpecVersion("1.0") - .setId("hello") - .setSource("http://example.com") - .setType("example.demo") - .setProtoData(Any.newBuilder().build()) - .putAttributes("ttl", io.cloudevents.v1.proto.CloudEvent.CloudEventAttributeValue.newBuilder() - .setCeString("3").build()) - .build(); - } - - private CloudEventBuilder buildCloudEventForTest() { - return CloudEventBuilder.v1() - .withId("hello") - .withType("req.v1") - .withSource(URI.create("//VCU.VIN/body.access")); - } - -} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/rpc/RpcTest.java b/src/test/java/org/eclipse/uprotocol/rpc/RpcTest.java index 1ae1b3bf..a7f153b3 100644 --- a/src/test/java/org/eclipse/uprotocol/rpc/RpcTest.java +++ b/src/test/java/org/eclipse/uprotocol/rpc/RpcTest.java @@ -24,14 +24,19 @@ import com.google.protobuf.Any; import com.google.protobuf.Int32Value; import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Message; import com.google.rpc.Code; import com.google.rpc.Status; -import io.cloudevents.CloudEvent; -import io.cloudevents.core.builder.CloudEventBuilder; + +import org.eclipse.uprotocol.transport.datamodel.UAttributes; +import org.eclipse.uprotocol.transport.datamodel.UPayload; +import org.eclipse.uprotocol.transport.datamodel.USerializationHint; +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.uuid.factory.UUIDFactory; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UUri; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.net.URI; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -39,143 +44,90 @@ class RpcTest { - Rpc uLinkReturnsNumber3 = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Int32Value.of(3)); - return CompletableFuture.completedFuture(payload); - } + RpcClient ReturnsNumber3 = new RpcClient() { @Override - public String getResponseUri() { - return ""; + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + UPayload data = new UPayload(Any.pack(Int32Value.of(3)).toByteArray(), USerializationHint.PROTOBUF); + return CompletableFuture.completedFuture(data); } }; - Rpc uLinkHappyPath = new Rpc() { + RpcClient HappyPath = new RpcClient() { @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(buildProtoPayloadForTest()); - return CompletableFuture.completedFuture(payload); - } - - @Override - public String getResponseUri() { - return ""; + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + UPayload data = buildUPayload(); + return CompletableFuture.completedFuture(data); } }; - Rpc uLinkWithStatusCodeInsteadOfHappyPath = new Rpc() { + RpcClient WithStatusCodeInsteadOfHappyPath = new RpcClient() { @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Status.newBuilder() + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + Status status = Status.newBuilder() .setCode(Code.INVALID_ARGUMENT_VALUE) .setMessage("boom") - .build()); - return CompletableFuture.completedFuture(payload); - } + .build(); + Any any = Any.pack(status); + UPayload data = new UPayload(any.toByteArray(), USerializationHint.PROTOBUF); + + return CompletableFuture.completedFuture(data); + } + }; + RpcClient WithStatusCodeHappyPath = new RpcClient() { @Override - public String getResponseUri() { - return ""; - } + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + Status status = Status.newBuilder() + .setCode(Code.OK_VALUE) + .setMessage("all good") + .build(); + Any any = Any.pack(status); + UPayload data = new UPayload(any.toByteArray(), USerializationHint.PROTOBUF); + + return CompletableFuture.completedFuture(data); + } }; - Rpc uLinkThatCompletesWithAnException = new Rpc() { + RpcClient ThatBarfsCrapyPayload = new RpcClient() { @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - return CompletableFuture.failedFuture(new RuntimeException("Boom")); + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + UPayload response = new UPayload(new byte[] {0}, USerializationHint.RAW); + return CompletableFuture.completedFuture(response); } + }; + + RpcClient ThatCompletesWithAnException = new RpcClient() { @Override - public String getResponseUri() { - return ""; + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + return CompletableFuture.failedFuture(new RuntimeException("Boom")); } + }; - Rpc uLinkThatReturnsTheWrongProto = new Rpc() { + RpcClient ThatReturnsTheWrongProto = new RpcClient() { @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Int32Value.of(42)); - return CompletableFuture.completedFuture(payload); + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + Any any = Any.pack(Int32Value.of(42)); + return CompletableFuture.completedFuture(new UPayload(any.toByteArray(), USerializationHint.PROTOBUF)); } + }; + + + RpcClient WithNullInPayload = new RpcClient() { @Override - public String getResponseUri() { - return ""; + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + return CompletableFuture.completedFuture(null); } }; - private static CompletableFuture mapResponse(CompletableFuture responseFuture, - Class expectedClazz) { - return responseFuture.handle((payload, exception) -> { - // Unexpected exception - if (exception != null) { - throw new RuntimeException(exception.getMessage(), exception); - } - if (payload == null) { - throw new RuntimeException("Server returned a null payload. Expected " + expectedClazz.getName()); - } - // Expected type - if (payload.is(expectedClazz)) { - try { - return payload.unpack(expectedClazz); - } catch (InvalidProtocolBufferException e) { - throw new RuntimeException(String.format("%s [%s]", e.getMessage(), expectedClazz.getName()), e); - } - } - // Status instead of the expected one - if (payload.is(Status.class)) { - try { - Status status = payload.unpack(Status.class); - throw new RuntimeException(String.format("Error returned, status code: [%s], message: [%s]", - Code.forNumber(status.getCode()), status.getMessage())); - } catch (InvalidProtocolBufferException e) { - throw new RuntimeException(String.format("%s [%s]", e.getMessage(), Status.class.getName()), e); - } - } - // Some other type instead of the expected one - throw new RuntimeException(String.format("Unknown payload type [%s]. Expected [%s]", - payload.getTypeUrl(), expectedClazz.getName())); - }); - } - - private static CompletableFuture> mapResponseToRpcResponse(CompletableFuture responseFuture, - Class expectedClazz) { - return responseFuture.handle((payload, exception) -> { - // Unexpected exception - if (exception != null) { - throw new RuntimeException(exception.getMessage(), exception); - } - if (payload == null) { - throw new RuntimeException("Server returned a null payload. Expected " + expectedClazz.getName()); - } - // Expected type - if (payload.is(expectedClazz)) { - try { - return RpcResult.success(payload.unpack(expectedClazz)); - } catch (InvalidProtocolBufferException e) { - throw new RuntimeException(String.format("%s [%s]", e.getMessage(), expectedClazz.getName()), e); - } - } - // Status instead of the expected one - if (payload.is(Status.class)) { - try { - return RpcResult.failure(payload.unpack(Status.class)); - } catch (InvalidProtocolBufferException e) { - throw new RuntimeException(String.format("%s [%s]", e.getMessage(), Status.class.getName()), e); - } - } - // Some other type instead of the expected one - throw new RuntimeException(String.format("Unknown payload type [%s]. Expected [%s]", - payload.getTypeUrl(), expectedClazz.getName())); - }); - } @Test void test_compose_happy_path() { - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkReturnsNumber3.invokeMethod(request), Int32Value.class) + UPayload payload = buildUPayload(); + final CompletableFuture> rpcResponse = + RpcMapper.mapResponseToResult(ReturnsNumber3.invokeMethod(buildTopic(), payload, buildUAttributes()), Int32Value.class) .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))) .exceptionally(exception -> { System.out.println("in exceptionally"); @@ -191,9 +143,9 @@ void test_compose_happy_path() { @Test void test_compose_that_returns_status() throws ExecutionException, InterruptedException { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkWithStatusCodeInsteadOfHappyPath.invokeMethod(request), Int32Value.class) + RpcMapper.mapResponseToResult(WithStatusCodeInsteadOfHappyPath.invokeMethod(buildTopic(), payload, buildUAttributes()), Int32Value.class) .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))) .exceptionally(exception -> { System.out.println("in exceptionally"); @@ -212,9 +164,9 @@ void test_compose_that_returns_status() throws ExecutionException, InterruptedEx @Test void test_compose_with_failure() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkThatCompletesWithAnException.invokeMethod(request), Int32Value.class) + RpcMapper.mapResponseToResult(ThatCompletesWithAnException.invokeMethod(buildTopic(), payload, buildUAttributes()), Int32Value.class) .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))); assertTrue(rpcResponse.isCompletedExceptionally()); Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); @@ -223,9 +175,9 @@ void test_compose_with_failure() { @Test void test_compose_with_failure_transform_Exception() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkThatCompletesWithAnException.invokeMethod(request), Int32Value.class) + RpcMapper.mapResponseToResult(ThatCompletesWithAnException.invokeMethod(buildTopic(), payload, buildUAttributes()), Int32Value.class) .thenApply(ur -> ur.map(i -> Int32Value.of(i.getValue()+5))) .exceptionally(exception -> { System.out.println("in exceptionally"); @@ -240,38 +192,27 @@ void test_compose_with_failure_transform_Exception() { assertFalse(test.isCompletedExceptionally()); } - @Test - void test_compose_with_failure_2() { - CloudEvent request = buildCloudEventForTest().build(); -// final CompletableFuture> rpcResponse = -// mapResponseToRpcResponse(uLinkReturnsNumber3.invokeMethod(request), Int32Value.class) -// .thenApply(this::xxx) -// .thenApply(ur -> ); -// rpcResponse.thenAccept(RpcResult -> { -// assertTrue(RpcResult.isSuccess()); -// assertEquals(Int32Value.of(8), RpcResult.successValue()); -// }); - } @Test void test_success_invoke_method_happy_flow_using_mapResponseToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); + final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponseToResult(HappyPath.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertFalse(rpcResponse.isCompletedExceptionally()); final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { assertTrue(RpcResult.isSuccess()); - assertEquals(buildProtoPayloadForTest(), RpcResult.successValue()); + assertEquals(buildCloudEvent(), RpcResult.successValue()); }); assertFalse(test.isCompletedExceptionally()); } @Test void test_fail_invoke_method_when_invoke_method_returns_a_status_using_mapResponseToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkWithStatusCodeInsteadOfHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponseToResult(WithStatusCodeInsteadOfHappyPath.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertFalse(rpcResponse.isCompletedExceptionally()); final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { @@ -284,9 +225,9 @@ void test_fail_invoke_method_when_invoke_method_returns_a_status_using_mapRespon @Test void test_fail_invoke_method_when_invoke_method_threw_an_exception_using_mapResponseToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkThatCompletesWithAnException.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponseToResult(ThatCompletesWithAnException.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertTrue(rpcResponse.isCompletedExceptionally()); Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); @@ -295,9 +236,9 @@ void test_fail_invoke_method_when_invoke_method_threw_an_exception_using_mapResp @Test void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto_using_mapResponseToRpcResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture> rpcResponse = - mapResponseToRpcResponse(uLinkThatReturnsTheWrongProto.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponseToResult(ThatReturnsTheWrongProto.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertTrue(rpcResponse.isCompletedExceptionally()); Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); @@ -305,36 +246,35 @@ void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto_using_mapRes "java.lang.RuntimeException: Unknown payload type [type.googleapis.com/google.protobuf.Int32Value]. Expected [io.cloudevents.v1.proto.CloudEvent]"); } - // --- @Test void test_success_invoke_method_happy_flow_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture rpcResponse = - mapResponse(uLinkHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponse(HappyPath.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertFalse(rpcResponse.isCompletedExceptionally()); - final CompletableFuture test = rpcResponse.thenAccept(cloudEvent -> assertEquals(buildProtoPayloadForTest(), cloudEvent)); + final CompletableFuture test = rpcResponse.thenAccept(cloudEvent -> assertEquals(buildCloudEvent(), cloudEvent)); assertFalse(test.isCompletedExceptionally()); } @Test void test_fail_invoke_method_when_invoke_method_returns_a_status_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture rpcResponse = - mapResponse(uLinkWithStatusCodeInsteadOfHappyPath.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponse(WithStatusCodeInsteadOfHappyPath.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertTrue(rpcResponse.isCompletedExceptionally()); Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); - assertEquals(exception.getMessage(), "java.lang.RuntimeException: Error returned, status code: [INVALID_ARGUMENT], message: [boom]"); + assertEquals(exception.getMessage(), "java.lang.RuntimeException: Unknown payload type [type.googleapis.com/google.rpc.Status]. Expected [io.cloudevents.v1.proto.CloudEvent]"); } @Test void test_fail_invoke_method_when_invoke_method_threw_an_exception_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture rpcResponse = - mapResponse(uLinkThatCompletesWithAnException.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponse(ThatCompletesWithAnException.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertTrue(rpcResponse.isCompletedExceptionally()); Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); @@ -343,9 +283,9 @@ void test_fail_invoke_method_when_invoke_method_threw_an_exception_using_mapResp @Test void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto_using_mapResponse() { - CloudEvent request = buildCloudEventForTest().build(); + UPayload payload = buildUPayload(); final CompletableFuture rpcResponse = - mapResponse(uLinkThatReturnsTheWrongProto.invokeMethod(request), io.cloudevents.v1.proto.CloudEvent.class); + RpcMapper.mapResponse(ThatReturnsTheWrongProto.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); assertTrue(rpcResponse.isCompletedExceptionally()); Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); @@ -353,60 +293,65 @@ void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto_using_mapRes "java.lang.RuntimeException: Unknown payload type [type.googleapis.com/google.protobuf.Int32Value]. Expected [io.cloudevents.v1.proto.CloudEvent]"); } - // --- - + @Test void test_success_invoke_method_happy_flow() { //Stub code - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = uLinkHappyPath.invokeMethod(request); + UPayload data = buildUPayload(); + final CompletableFuture rpcResponse = HappyPath.invokeMethod(buildTopic(), data, buildUAttributes()); final CompletableFuture stubReturnValue = rpcResponse.handle((payload, exception) -> { - // happy flow, no exception - assertNull(exception); + Any any; + assertTrue(true); + assertFalse(true); + + try { + any = Any.parseFrom(payload.data()); + // happy flow, no exception + assertNull(exception); - // check the payload is not google.rpc.Status - assertFalse(payload.is(Status.class)); + // check the payload is not google.rpc.Status + assertFalse(any.is(Status.class)); - // check the payload is the cloud event we build - assertTrue(payload.is(io.cloudevents.v1.proto.CloudEvent.class)); + // check the payload is the cloud event we build + assertTrue(any.is(io.cloudevents.v1.proto.CloudEvent.class)); - try { - return payload.unpack(io.cloudevents.v1.proto.CloudEvent.class); + return any.unpack(io.cloudevents.v1.proto.CloudEvent.class); } catch (InvalidProtocolBufferException e) { throw new RuntimeException(e); } }); - stubReturnValue.thenAccept(cloudEvent -> assertEquals(buildProtoPayloadForTest(), cloudEvent)); + stubReturnValue.thenAccept(cloudEvent -> assertEquals(buildUPayload(), cloudEvent)); } @Test void test_fail_invoke_method_when_invoke_method_returns_a_status() { //Stub code - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = uLinkWithStatusCodeInsteadOfHappyPath.invokeMethod(request); + UPayload data = buildUPayload(); + final CompletableFuture rpcResponse = WithStatusCodeInsteadOfHappyPath.invokeMethod(buildTopic(), data, buildUAttributes()); final CompletableFuture stubReturnValue = rpcResponse.handle((payload, exception) -> { - // happy flow, no exception - assertNull(exception); + try { + Any any = Any.parseFrom(payload.data()); + // happy flow, no exception + assertNull(exception); - // check the payload not google.rpc.Status - assertTrue(payload.is(Status.class)); + // check the payload not google.rpc.Status + assertTrue(any.is(Status.class)); - // check the payload is not the type we expected - assertFalse(payload.is(io.cloudevents.v1.proto.CloudEvent.class)); + // check the payload is not the type we expected + assertFalse(any.is(io.cloudevents.v1.proto.CloudEvent.class)); - // we know it is a Status - so let's unpack it - try { - Status status = payload.unpack(Status.class); + // we know it is a Status - so let's unpack it + + Status status = any.unpack(Status.class); throw new RuntimeException(String.format("Error returned, status code: [%s], message: [%s]", Code.forNumber(status.getCode()), status.getMessage())); } catch (InvalidProtocolBufferException e) { throw new RuntimeException(e); } - }); assertTrue(stubReturnValue.isCompletedExceptionally()); @@ -419,8 +364,8 @@ void test_fail_invoke_method_when_invoke_method_returns_a_status() { @Test void test_fail_invoke_method_when_invoke_method_threw_an_exception() { //Stub code - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = uLinkThatCompletesWithAnException.invokeMethod(request); + UPayload data = buildUPayload(); + final CompletableFuture rpcResponse = ThatCompletesWithAnException.invokeMethod(buildTopic(), data, buildUAttributes()); final CompletableFuture stubReturnValue = rpcResponse.handle((payload, exception) -> { // exception was thrown @@ -442,21 +387,22 @@ void test_fail_invoke_method_when_invoke_method_threw_an_exception() { @Test void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto() { //Stub code - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture rpcResponse = uLinkThatReturnsTheWrongProto.invokeMethod(request); + UPayload data = buildUPayload(); + final CompletableFuture rpcResponse = ThatReturnsTheWrongProto.invokeMethod(buildTopic(), data, buildUAttributes()); final CompletableFuture stubReturnValue = rpcResponse.handle((payload, exception) -> { - // happy flow, no exception - assertNull(exception); + try { + Any any = Any.parseFrom(payload.data()); + // happy flow, no exception + assertNull(exception); - // check the payload is not google.rpc.Status - assertFalse(payload.is(Status.class)); + // check the payload is not google.rpc.Status + assertFalse(any.is(Status.class)); - // check the payload is the cloud event we build - assertFalse(payload.is(io.cloudevents.v1.proto.CloudEvent.class)); + // check the payload is the cloud event we build + assertFalse(any.is(io.cloudevents.v1.proto.CloudEvent.class)); - try { - return payload.unpack(io.cloudevents.v1.proto.CloudEvent.class); + return any.unpack(io.cloudevents.v1.proto.CloudEvent.class); } catch (InvalidProtocolBufferException e) { throw new RuntimeException(String.format("%s [%s]", e.getMessage(), "io.cloudevents.v1.proto.CloudEvent.class"), e); } @@ -470,57 +416,170 @@ void test_fail_invoke_method_when_invoke_method_returns_a_bad_proto() { } @Test - void what_the_stub_looks_like() { + @DisplayName("Invoke method that returns successfully with null in the payload") + void test_success_invoke_method_that_has_null_payload_mapResponse() { + UPayload payload = buildUPayload(); + final CompletableFuture rpcResponse = + RpcMapper.mapResponse(WithNullInPayload.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); - Rpc uLink = new Rpc() { - @Override - public CompletableFuture invokeMethod(CloudEvent requestEvent) { - Any payload = Any.pack(Status.newBuilder() - .setCode(Code.INVALID_ARGUMENT_VALUE) - .setMessage("boom") - .build()); - return CompletableFuture.completedFuture(payload); - } + assertTrue(rpcResponse.isCompletedExceptionally()); + Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); + assertEquals(exception.getMessage(), "java.lang.RuntimeException: Server returned a null payload. Expected io.cloudevents.v1.proto.CloudEvent"); + + } + + + @Test + @DisplayName("Invoke method that returns successfully with null in the payload, mapResponseToResult") + void test_success_invoke_method_that_has_null_payload_mapResponseToResultToRpcResponse() { + UPayload payload = buildUPayload(); + final CompletableFuture> rpcResponse = + RpcMapper.mapResponseToResult(WithNullInPayload.invokeMethod(buildTopic(), payload, buildUAttributes()), io.cloudevents.v1.proto.CloudEvent.class); + + assertTrue(rpcResponse.isCompletedExceptionally()); + Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); + assertEquals(exception.getMessage(), "java.lang.RuntimeException: Server returned a null payload. Expected io.cloudevents.v1.proto.CloudEvent"); + + } + + + @Test + @DisplayName("Invoke method that expects a Status payload and returns successfully with OK Status in the payload") + void test_success_invoke_method_happy_flow_that_returns_status_using_mapResponse() { + UPayload payload = buildUPayload(); + final CompletableFuture rpcResponse = + RpcMapper.mapResponse(WithStatusCodeHappyPath.invokeMethod(buildTopic(), payload, buildUAttributes()), Status.class); + + assertFalse(rpcResponse.isCompletedExceptionally()); + final CompletableFuture test = rpcResponse.thenAccept(status -> { + assertEquals(Code.OK.getNumber(), status.getCode()); + assertEquals("all good", status.getMessage()); + }); + assertFalse(test.isCompletedExceptionally()); + } + + @Test + @DisplayName("Invoke method that expects a Status payload and returns successfully with OK Status in the payload, mapResponseToResult") + void test_success_invoke_method_happy_flow_that_returns_status_using_mapResponseToResultToRpcResponse() { + UPayload payload = buildUPayload(); + final CompletableFuture> rpcResponse = + RpcMapper.mapResponseToResult(WithStatusCodeHappyPath.invokeMethod(buildTopic(), payload, buildUAttributes()), Status.class); + + assertFalse(rpcResponse.isCompletedExceptionally()); + final CompletableFuture test = rpcResponse.thenAccept(RpcResult -> { + assertTrue(RpcResult.isSuccess()); + assertEquals(Code.OK.getNumber(), RpcResult.successValue().getCode()); + assertEquals("all good", RpcResult.successValue().getMessage()); + }); + assertFalse(test.isCompletedExceptionally()); + } + + @Test + void test_unpack_payload_failed() { + Any payload = Any.pack(Int32Value.of(3)); + Exception exception = assertThrows(RuntimeException.class, () -> RpcMapper.unpackPayload(payload, Status.class)); + assertEquals(exception.getMessage(), + "Type of the Any message does not match the given class. [com.google.rpc.Status]"); + } + + @Test + @DisplayName("test invalid payload that is not of type any") + void test_invalid_payload_that_is_not_type_any() { + UPayload payload = buildUPayload(); + final CompletableFuture rpcResponse = + RpcMapper.mapResponse(ThatBarfsCrapyPayload.invokeMethod(buildTopic(), payload, buildUAttributes()), Status.class); + assertTrue(rpcResponse.isCompletedExceptionally()); + Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); + assertEquals(exception.getMessage(), + "java.lang.RuntimeException: Protocol message contained an invalid tag (zero). [com.google.rpc.Status]");; + } + + @Test + @DisplayName("test invalid payload that is not of type any") + void test_invalid_payload_that_is_not_type_any_map_to_result() { + UPayload payload = buildUPayload(); + final CompletableFuture> rpcResponse = + RpcMapper.mapResponseToResult(ThatBarfsCrapyPayload.invokeMethod(buildTopic(), payload, buildUAttributes()), Status.class); + + assertTrue(rpcResponse.isCompletedExceptionally()); + Exception exception = assertThrows(java.util.concurrent.ExecutionException.class, rpcResponse::get); + assertEquals(exception.getMessage(), + "java.lang.RuntimeException: Protocol message contained an invalid tag (zero). [com.google.rpc.Status]");; + } + + @Test + void what_the_stub_looks_like() throws InterruptedException { + + RpcClient client = new RpcClient() { @Override - public String getResponseUri() { - return ""; + public CompletableFuture invokeMethod(UUri topic, UPayload payload, UAttributes attributes) { + return CompletableFuture.completedFuture(UPayload.empty()); } }; //Stub code - CloudEvent request = buildCloudEventForTest().build(); - final CompletableFuture invokeMethodResponse = uLink.invokeMethod(request); + UPayload payload = buildUPayload(); + final CompletableFuture invokeMethodResponse = client.invokeMethod(buildTopic(), payload, buildUAttributes()); CompletableFuture stubReturnValue = rpcResponse(invokeMethodResponse); + assertFalse(stubReturnValue.isCancelled()); + + } + + private static io.cloudevents.v1.proto.CloudEvent buildCloudEvent() { + return io.cloudevents.v1.proto.CloudEvent.newBuilder() + .setSpecVersion("1.0") + .setId("HARTLEY IS THE BEST") + .setSource("http://example.com") + .build(); + } + private static UPayload buildUPayload() { + Any any = Any.pack(buildCloudEvent()); + return new UPayload(any.toByteArray(), USerializationHint.PROTOBUF); + } + + private static UUri buildTopic() { + return LongUriSerializer.instance().deserialize("//vcu.vin/hartley/1/rpc.Raise"); + } + private static UAttributes buildUAttributes() { + return UAttributes.forRpcRequest( + UUIDFactory.Factories.UPROTOCOL.factory().create(), + UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("hartley")) + .build()).build(); } - private static CompletableFuture rpcResponse(CompletableFuture invokeMethodResponse) { + private static CompletableFuture rpcResponse(CompletableFuture invokeMethodResponse) { final CompletableFuture stubReturnValue = invokeMethodResponse.handle((payload, exception) -> { + Any any; + try { + any = Any.parseFrom(payload.data()); + } catch (InvalidProtocolBufferException e) { + throw new RuntimeException(e.getMessage(), e); + } + // invoke method had some unexpected problem. if (exception != null) { throw new RuntimeException(exception.getMessage(), exception); } - if (payload == null) { - throw new RuntimeException("Server returned a null payload. Expected a io.cloudevents.v1.proto.CloudEvent"); - } - + // test to see if we have expected type - if (payload.is(io.cloudevents.v1.proto.CloudEvent.class)) { + if (any.is(io.cloudevents.v1.proto.CloudEvent.class)) { try { - return payload.unpack(io.cloudevents.v1.proto.CloudEvent.class); + return any.unpack(io.cloudevents.v1.proto.CloudEvent.class); } catch (InvalidProtocolBufferException e) { throw new RuntimeException(e.getMessage(), e); } } // this will be called only if expected return type is not status, but status was returned to indicate a problem. - if (payload.is(Status.class)) { + if (any.is(Status.class)) { try { - Status status = payload.unpack(Status.class); + Status status = any.unpack(Status.class); throw new RuntimeException(String.format("Error returned, status code: [%s], message: [%s]", Code.forNumber(status.getCode()), status.getMessage())); } catch (InvalidProtocolBufferException e) { @@ -528,39 +587,11 @@ private static CompletableFuture rpcResponse } } - throw new RuntimeException(String.format("Unknown payload type [%s]", payload.getTypeUrl())); + throw new RuntimeException(String.format("Unknown payload type [%s]", any.getTypeUrl())); }); return stubReturnValue; } - private Status crateErrorStatus(Exception e, Code exceptionCode) { - return Status.newBuilder() - .setCode(exceptionCode.getNumber()) - .setMessage(e.getMessage() == null ? "" : e.getMessage()) - .build(); - } - - - private io.cloudevents.v1.proto.CloudEvent buildProtoPayloadForTest() { - io.cloudevents.v1.proto.CloudEvent cloudEventProto = io.cloudevents.v1.proto.CloudEvent.newBuilder() - .setSpecVersion("1.0") - .setId("hello") - .setSource("http://example.com") - .setType("example.demo") - .setProtoData(Any.newBuilder().build()) - .putAttributes("ttl", io.cloudevents.v1.proto.CloudEvent.CloudEventAttributeValue.newBuilder() - .setCeString("3").build()) - .build(); - return cloudEventProto; - } - - private CloudEventBuilder buildCloudEventForTest() { - return CloudEventBuilder.v1() - .withId("hello") - .withType("req.v1") - .withSource(URI.create("//VCU.VIN/body.access")); - } - } \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/transport/datamodel/UAttributeTest.java b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UAttributeTest.java new file mode 100644 index 00000000..556cb085 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UAttributeTest.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.transport.datamodel; + +import org.eclipse.uprotocol.uri.builder.UResourceBuilder; +import org.eclipse.uprotocol.uuid.factory.UUIDFactory; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UUri; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + + +public class UAttributeTest { + + @Test + @DisplayName("Make sure the equals and hash code works") + public void testHashCodeEquals() { + // EqualsVerifier.forClass(UAttributes.class).usingGetClass().verify(); + } + + @Test + @DisplayName("Make sure the toString works on empty") + public void testToString_with_empty() { + UAttributes uAttributes = UAttributes.empty(); + assertEquals("UAttributes{id=null, type=null, priority=null, ttl=null, token='null', sink=null, plevel=null, commstatus=null, reqid=null}", + uAttributes.toString()); + } + + @Test + @DisplayName("Make sure the toString works") + public void testToString() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UUID requestId = UUID.randomUUID(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.LOW) + .withSink(UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")).build()) + .withTtl(1000) + .withToken("someToken") + .withPermissionLevel(1) + .withReqId(requestId) + .withCommStatus(5) + .build(); + assertEquals(String.format("UAttributes{id=%s, type=RESPONSE, priority=LOW, ttl=1000, token='someToken', " + + "sink=entity {\n name: \"body.access\"\n}\n" + + ", plevel=1, commstatus=5, " + + "reqid=%s}",id, requestId),uAttributes.toString()); + + } + + @Test + @DisplayName("Test creating a complete UAttributes") + public void testCreatingUattributes() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UUID requestId = UUID.randomUUID(); + final UUri sink = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")).build(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(sink) + .withTtl(1000) + .withToken("someToken") + .withPermissionLevel(1) + .withReqId(requestId) + .withCommStatus(5) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertTrue(uAttributes.ttl().isPresent()); + assertTrue(uAttributes.token().isPresent()); + assertTrue(uAttributes.sink().isPresent()); + assertTrue(uAttributes.plevel().isPresent()); + assertTrue(uAttributes.commstatus().isPresent()); + assertTrue(uAttributes.reqid().isPresent()); + assertEquals(sink, uAttributes.sink().orElse(UUri.getDefaultInstance())); + assertEquals(1000, uAttributes.ttl().orElse(0)); + assertEquals(1, uAttributes.plevel().orElse(3)); + assertEquals("someToken", uAttributes.token().orElse("")); + assertEquals(5, uAttributes.commstatus().orElse(0)); + assertEquals(requestId, uAttributes.reqid().orElse(UUID.randomUUID())); + } + + @Test + @DisplayName("Test creating a basic UAttributes, only required values") + public void test_basic_uattribues_only_required_values() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.PUBLISH, UPriority.LOW) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.PUBLISH, uAttributes.type()); + assertEquals(UPriority.LOW, uAttributes.priority()); + assertTrue(uAttributes.ttl().isEmpty()); + assertTrue(uAttributes.token().isEmpty()); + assertTrue(uAttributes.sink().isEmpty()); + assertTrue(uAttributes.plevel().isEmpty()); + assertTrue(uAttributes.commstatus().isEmpty()); + assertTrue(uAttributes.reqid().isEmpty()); + + } + + @Test + @DisplayName("Test creating UAttributes builder with static factory method for a basic RPC request") + public void test_create_uattributes_builder_for_basic_rpc_request() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + + // source + final UUri sink = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")) + .setResource(UResourceBuilder.forRpcRequest("ExecuteWindowCommand")) + .build(); + + final UAttributes uAttributes = UAttributes.forRpcRequest(id, sink) + .withToken("someToken") + .withTtl(10000) + .build(); + assertTrue(uAttributes.isRpcRequest()); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.REQUEST, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertEquals(sink, uAttributes.sink().orElse(UUri.getDefaultInstance())); + assertEquals("someToken", uAttributes.token().orElse("")); + assertEquals(10000, uAttributes.ttl().orElse(0)); + } + + + @Test + @DisplayName("Test creating UAttributes builder with static factory method for a basic RPC response") + public void test_create_uattributes_builder_for_basic_rpc_response() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + + final UUri sink = UUri.newBuilder() + .setAuthority( + UAuthority.newBuilder() + .setName("vcu.veh.ultifi.gm.com")) + .setEntity(UEntity.newBuilder(). + setName("petapp.ultifi.gm.com") + .setVersionMajor(1)) + .setResource(UResourceBuilder.forRpcResponse()) + .build(); + + final UUID requestId = UUID.randomUUID(); + final UAttributes uAttributes = UAttributes.forRpcResponse(id, sink, requestId) + .withToken("someToken") + .withTtl(10000) + .build(); + assertTrue(uAttributes.isRpcResponse()); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertEquals("petapp.ultifi.gm.com", uAttributes.sink().orElse(UUri.getDefaultInstance()).getEntity().getName()); + assertEquals("someToken", uAttributes.token().orElse("")); + assertEquals(10000, uAttributes.ttl().orElse(0)); + } + + @Test + @DisplayName("Test creating UAttributes with null required attribute id") + public void test_create_uattributes_missing_required_attribute_id() { + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(null, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .build(); + assertNull(uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + } + + @Test + @DisplayName("Test creating UAttributes with null required attribute type") + public void test_create_uattributes_missing_required_attribute_type() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + null, UPriority.REALTIME_INTERACTIVE) + .build(); + assertEquals(id, uAttributes.id()); + assertNull(uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + } + + @Test + @DisplayName("Test creating UAttributes with null required attribute type priority") + public void test_create_uattributes_missing_required_attribute_priority() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.REQUEST, null) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.REQUEST, uAttributes.type()); + assertNull(uAttributes.priority()); + } + + @Test + @DisplayName("Test creating UAttribues with a null ttl") + public void test_create_uattributes_with_null_ttl() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withTtl(null) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertTrue(uAttributes.ttl().isEmpty()); + + } + + @Test + @DisplayName("Test creating UAttribues with a null or blank token") + public void test_create_uattributes_with_null_or_blank_token() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withToken(null) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertTrue(uAttributes.token().isEmpty()); + + final UAttributes uAttributes2 = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withToken(" ") + .build(); + assertEquals(id, uAttributes2.id()); + assertEquals(UMessageType.RESPONSE, uAttributes2.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes2.priority()); + assertTrue(uAttributes2.token().isEmpty()); + } + + @Test + @DisplayName("Test creating UAttribues with a null sink") + public void test_create_uattributes_with_null_sink() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(null) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertTrue(uAttributes.sink().isEmpty()); + } + + @Test + @DisplayName("Test creating UAttribues with a null permission level") + public void test_create_uattributes_with_null_permission_level() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withPermissionLevel(null) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertTrue(uAttributes.plevel().isEmpty()); + } + + @Test + @DisplayName("Test creating UAttribues with a null communication status") + public void test_create_uattributes_with_null_comm_status() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withCommStatus(null) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertTrue(uAttributes.commstatus().isEmpty()); + } + + @Test + @DisplayName("Test creating UAttribues with a null request id") + public void test_create_uattributes_with_null_request_id() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withReqId(null) + .build(); + assertEquals(id, uAttributes.id()); + assertEquals(UMessageType.RESPONSE, uAttributes.type()); + assertEquals(UPriority.REALTIME_INTERACTIVE, uAttributes.priority()); + assertTrue(uAttributes.commstatus().isEmpty()); + } + + @Test + @DisplayName("Test is this UAttributes configured for an RPC request payload") + public void test_is_uattributes_configured_for_rpc_request_payload() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UUri sink = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("body.access")) + .setResource(UResourceBuilder.forRpcRequest("ExecuteWindowCommand")) + .build(); + + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(sink) + .build(); + assertTrue(uAttributes.isRpcRequest()); + } + + @Test + @DisplayName("Test scenarios for UAttributes not configured for an RPC request payload") + public void test_scenarios_for_uattributes_not_configured_for_rpc_request_payload() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + + final UUri sink = UUri.newBuilder() + .setAuthority(UAuthority.newBuilder() + .setName("someVin.veh.ultifi.gm.com")) + .setEntity(UEntity.newBuilder().setName("body.access")) + .setResource(UResourceBuilder.forRpcRequest("ExecuteWindowCommand")) + .build(); + + final UAttributes uAttributesNoSink = new UAttributes.UAttributesBuilder(id, + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .build(); + assertFalse(uAttributesNoSink.isRpcRequest()); + + final UAttributes uAttributesWrongType = new UAttributes.UAttributesBuilder(id, + UMessageType.PUBLISH, UPriority.REALTIME_INTERACTIVE) + .withSink(sink) + .build(); + assertFalse(uAttributesWrongType.isRpcRequest()); + } + + @Test + @DisplayName("Test is this UAttributes configured for an RPC response payload") + public void test_is_uattributes_configured_for_rpc_response_payload() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UUID requestId = UUID.randomUUID(); + + final UUri sink = UUri.newBuilder() + .setAuthority(UAuthority.newBuilder() + .setName("azure.bo.ultifi.gm.com")) + .setEntity(UEntity.newBuilder() + .setName("petapp.ultifi.gm.com") + .setVersionMajor(1)) + .build(); + + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(sink) + .withReqId(requestId) + .build(); + assertTrue(uAttributes.isRpcResponse()); + } + + @Test + @DisplayName("Test scenarios for UAttributes not configured for an RPC response payload") + public void test_scenarios_for_uattributes_not_configured_for_rpc_response_payload() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UUID requestId = UUID.randomUUID(); + final UUri sink = UUri.newBuilder() + .setAuthority(UAuthority.newBuilder() + .setName("azure.bo.ultifi.gm.com")) + .setEntity(UEntity.newBuilder() + .setName("petapp.ultifi.gm.com") + .setVersionMajor(1)) + .build(); + + final UAttributes uAttributesNoSink = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withReqId(requestId) + .build(); + assertFalse(uAttributesNoSink.isRpcResponse()); + + final UAttributes uAttributesWrongType = new UAttributes.UAttributesBuilder(id, + UMessageType.PUBLISH, UPriority.REALTIME_INTERACTIVE) + .withSink(sink) + .withReqId(requestId) + .build(); + assertFalse(uAttributesWrongType.isRpcResponse()); + + final UAttributes uAttributesNoRequestId = new UAttributes.UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(sink) + .build(); + assertFalse(uAttributesNoRequestId.isRpcResponse()); + + final UAttributes simplePublish = new UAttributes.UAttributesBuilder(id, + UMessageType.PUBLISH, UPriority.REALTIME_INTERACTIVE) + .build(); + assertFalse(simplePublish.isRpcResponse()); + } + + @Test + @DisplayName("Test is this UAttributes configured for payload where there was no platform error") + public void test_is_uattributes_configured_for_payload_with_no_platform_error() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.PUBLISH, UPriority.REALTIME_INTERACTIVE) + .build(); + assertTrue(uAttributes.isPlatformTransportSuccess()); + + final UAttributes alsoOK = new UAttributes.UAttributesBuilder(id, + UMessageType.PUBLISH, UPriority.REALTIME_INTERACTIVE) + .withCommStatus(0) + .build(); + assertTrue(alsoOK.isPlatformTransportSuccess()); + } + + @Test + @DisplayName("Test is this UAttributes configured for payload where there was a platform error") + public void test_is_uattributes_configured_for_payload_with_platform_error() { + final UUID id = UUIDFactory.Factories.UPROTOCOL.factory().create(); + final UAttributes uAttributes = new UAttributes.UAttributesBuilder(id, + UMessageType.PUBLISH, UPriority.REALTIME_INTERACTIVE) + .withCommStatus(3) + .build(); + assertFalse(uAttributes.isPlatformTransportSuccess()); + } + + +} diff --git a/src/test/java/org/eclipse/uprotocol/transport/datamodel/UMessageTypeTest.java b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UMessageTypeTest.java new file mode 100644 index 00000000..3bcfa459 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UMessageTypeTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.transport.datamodel; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class UMessageTypeTest { + + @Test + @DisplayName("Test finding UMessageType from a numeric value") + public void test_find_UMessageType_from_number() { + assertTrue(UMessageType.from(0).isPresent()); + assertEquals(UMessageType.PUBLISH, UMessageType.from(0).get()); + + assertTrue(UMessageType.from(1).isPresent()); + assertEquals(UMessageType.REQUEST, UMessageType.from(1).get()); + + assertTrue(UMessageType.from(2).isPresent()); + assertEquals(UMessageType.RESPONSE, UMessageType.from(2).get()); + + } + + @Test + @DisplayName("Test finding UMessageType from a numeric value that does not exist") + public void test_find_UMessageType_from_number_that_does_not_exist() { + assertTrue(UMessageType.from(-42).isEmpty()); + } + + @Test + @DisplayName("Test finding UMessageType from a string value") + public void test_find_UMessageType_from_string() { + assertTrue(UMessageType.from("pub.v1").isPresent()); + assertEquals(UMessageType.PUBLISH, UMessageType.from("pub.v1").get()); + + assertTrue(UMessageType.from("req.v1").isPresent()); + assertEquals(UMessageType.REQUEST, UMessageType.from("req.v1").get()); + + assertTrue(UMessageType.from("res.v1").isPresent()); + assertEquals(UMessageType.RESPONSE, UMessageType.from("res.v1").get()); + + } + + @Test + @DisplayName("Test finding UMessageType from a numeric string that does not exist") + public void test_find_UMessageType_from_string_that_does_not_exist() { + assertTrue(UMessageType.from("BOOM").isEmpty()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/transport/datamodel/UPayloadTest.java b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UPayloadTest.java new file mode 100644 index 00000000..dc30b19e --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UPayloadTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.transport.datamodel; + +import nl.jqno.equalsverifier.EqualsVerifier; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.*; + +class UPayloadTest { + + @Test + @DisplayName("Make sure the equals and hash code works") + public void testHashCodeEquals() { + EqualsVerifier.forClass(UPayload.class).usingGetClass().verify(); + } + + @Test + @DisplayName("Make sure the toString works on empty") + public void testToString_with_empty() { + UPayload uPayload = UPayload.empty(); + assertEquals("UPayload{data=[], hint=UNKNOWN}", uPayload.toString()); + assertEquals(USerializationHint.UNKNOWN, uPayload.hint()); + } + + + @Test + @DisplayName("Create an empty UPayload") + public void create_an_empty_upayload() { + UPayload uPayload = UPayload.empty(); + assertEquals(0, uPayload.data().length); + assertTrue(uPayload.isEmpty()); + } + + @Test + @DisplayName("Create a UPayload with null") + public void create_upayload_with_null() { + UPayload uPayload = new UPayload(null, null); + assertEquals(0, uPayload.data().length); + assertTrue(uPayload.isEmpty()); + assertEquals(USerializationHint.UNKNOWN, uPayload.hint()); + } + + @Test + @DisplayName("Create a UPayload from string with hint") + public void create_upayload_from_string_with_hint() { + String stringData = "hello"; + UPayload uPayload = new UPayload(stringData.getBytes(StandardCharsets.UTF_8), USerializationHint.TEXT); + assertEquals(stringData.length(), uPayload.data().length); + assertFalse(uPayload.isEmpty()); + assertEquals(USerializationHint.TEXT, uPayload.hint()); + assertEquals(stringData, new String(uPayload.data())); + } + + @Test + @DisplayName("Create a UPayload from some string without hint") + public void create_upayload_from_string_without_hint() { + String stringData = "hello"; + UPayload uPayload = new UPayload(stringData.getBytes(StandardCharsets.UTF_8), null); + assertEquals(stringData.length(), uPayload.data().length); + assertFalse(uPayload.isEmpty()); + assertEquals(USerializationHint.UNKNOWN, uPayload.hint()); + } + + @Test + @DisplayName("Create a UPayload without a byte array but with some weird hint") + public void create_upayload_without_byte_array_but_with_weird_hint() { + UPayload uPayload = new UPayload(null, USerializationHint.PROTOBUF); + assertEquals(0, uPayload.data().length); + assertTrue(uPayload.isEmpty()); + assertEquals(USerializationHint.PROTOBUF, uPayload.hint()); + assertFalse(UPayload.empty().equals(uPayload)); + } +} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/transport/datamodel/UPriorityTest.java b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UPriorityTest.java new file mode 100644 index 00000000..19d82087 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UPriorityTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.transport.datamodel; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class UPriorityTest { + + @Test + @DisplayName("Test finding UPriority from a numeric value") + public void test_find_upriority_from_number() { + assertTrue(UPriority.from(0).isPresent()); + assertEquals(UPriority.LOW, UPriority.from(0).get()); + + assertTrue(UPriority.from(1).isPresent()); + assertEquals(UPriority.STANDARD, UPriority.from(1).get()); + + assertTrue(UPriority.from(2).isPresent()); + assertEquals(UPriority.OPERATIONS, UPriority.from(2).get()); + + assertTrue(UPriority.from(3).isPresent()); + assertEquals(UPriority.MULTIMEDIA_STREAMING, UPriority.from(3).get()); + + assertTrue(UPriority.from(4).isPresent()); + assertEquals(UPriority.REALTIME_INTERACTIVE, UPriority.from(4).get()); + + assertTrue(UPriority.from(5).isPresent()); + assertEquals(UPriority.SIGNALING, UPriority.from(5).get()); + + assertTrue(UPriority.from(6).isPresent()); + assertEquals(UPriority.NETWORK_CONTROL, UPriority.from(6).get()); + } + + @Test + @DisplayName("Test finding UPriority from a numeric value that does not exist") + public void test_find_upriority_from_number_that_does_not_exist() { + assertTrue(UPriority.from(-42).isEmpty()); + } + + @Test + @DisplayName("Test finding UPriority from a string value") + public void test_find_upriority_from_string() { + assertTrue(UPriority.from("CS0").isPresent()); + assertEquals(UPriority.LOW, UPriority.from("CS0").get()); + + assertTrue(UPriority.from("CS1").isPresent()); + assertEquals(UPriority.STANDARD, UPriority.from("CS1").get()); + + assertTrue(UPriority.from("CS2").isPresent()); + assertEquals(UPriority.OPERATIONS, UPriority.from("CS2").get()); + + assertTrue(UPriority.from("CS3").isPresent()); + assertEquals(UPriority.MULTIMEDIA_STREAMING, UPriority.from("CS3").get()); + + assertTrue(UPriority.from("CS4").isPresent()); + assertEquals(UPriority.REALTIME_INTERACTIVE, UPriority.from("CS4").get()); + + assertTrue(UPriority.from("CS5").isPresent()); + assertEquals(UPriority.SIGNALING, UPriority.from("CS5").get()); + + assertTrue(UPriority.from("CS6").isPresent()); + assertEquals(UPriority.NETWORK_CONTROL, UPriority.from("CS6").get()); + } + + @Test + @DisplayName("Test finding UPriority from a numeric string that does not exist") + public void test_find_upriority_from_string_that_does_not_exist() { + assertTrue(UPriority.from("BOOM").isEmpty()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/transport/datamodel/USerializationHintTest.java b/src/test/java/org/eclipse/uprotocol/transport/datamodel/USerializationHintTest.java new file mode 100644 index 00000000..bf25c343 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/transport/datamodel/USerializationHintTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.transport.datamodel; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class USerializationHintTest { + + @Test + @DisplayName("Test finding USerializationHint from a numeric value") + public void test_find_USerializationHint_from_number() { + assertTrue(USerializationHint.from(0).isPresent()); + assertEquals(USerializationHint.UNKNOWN, USerializationHint.from(0).get()); + + assertTrue(USerializationHint.from(1).isPresent()); + assertEquals(USerializationHint.PROTOBUF, USerializationHint.from(1).get()); + + assertTrue(USerializationHint.from(2).isPresent()); + assertEquals(USerializationHint.JSON, USerializationHint.from(2).get()); + + assertTrue(USerializationHint.from(3).isPresent()); + assertEquals(USerializationHint.SOMEIP, USerializationHint.from(3).get()); + + assertTrue(USerializationHint.from(4).isPresent()); + assertEquals(USerializationHint.RAW, USerializationHint.from(4).get()); + + } + + @Test + @DisplayName("Test finding USerializationHint from a numeric value that does not exist") + public void test_find_USerializationHint_from_number_that_does_not_exist() { + assertTrue(USerializationHint.from(-42).isEmpty()); + } + + @Test + @DisplayName("Test finding USerializationHint from a string value") + public void test_find_USerializationHint_from_string() { + assertTrue(USerializationHint.from("").isPresent()); + assertEquals(USerializationHint.UNKNOWN, USerializationHint.from("").get()); + + assertTrue(USerializationHint.from("application/x-protobuf").isPresent()); + assertEquals(USerializationHint.PROTOBUF, USerializationHint.from("application/x-protobuf").get()); + + assertTrue(USerializationHint.from("application/json").isPresent()); + assertEquals(USerializationHint.JSON, USerializationHint.from("application/json").get()); + + assertTrue(USerializationHint.from("application/x-someip").isPresent()); + assertEquals(USerializationHint.SOMEIP, USerializationHint.from("application/x-someip").get()); + + assertTrue(USerializationHint.from("application/octet-stream").isPresent()); + assertEquals(USerializationHint.RAW, USerializationHint.from("application/octet-stream").get()); + + } + + @Test + @DisplayName("Test finding USerializationHint from a numeric string that does not exist") + public void test_find_USerializationHint_from_string_that_does_not_exist() { + assertTrue(USerializationHint.from("BOOM").isEmpty()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/transport/datamodel/UStatusTest.java b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UStatusTest.java new file mode 100644 index 00000000..ebf56ec1 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/transport/datamodel/UStatusTest.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.transport.datamodel; + +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +class UStatusTest { + + @Test + @DisplayName("Make sure the equals and hash code works") + public void testHashCodeEquals() { + EqualsVerifier.forClass(UStatus.class) + .suppress(Warning.INHERITED_DIRECTLY_FROM_OBJECT) + .usingGetClass().verify(); + } + + @Test + @DisplayName("Make sure the equals and hash code for ok scenarios") + public void testHashCodeEquals_ok_scenarios() { + // Sets call equals and hash code - using them to test functionality + Set statuses = new HashSet<>(); + statuses.add(UStatus.ok()); + statuses.add(UStatus.ok()); + statuses.add(UStatus.ok("ackId")); + statuses.add("5"); + + assertEquals(3, statuses.size()); + } + + @Test + @DisplayName("Make sure the equals and hash code for fail scenarios") + public void testHashCodeEquals_fail_scenarios() { + // Sets call equals and hash code - using them to test functionality + Set statuses = new HashSet<>(); + // these two are the same + statuses.add(UStatus.failed()); + statuses.add(UStatus.failed()); + + // these two are the same + statuses.add(UStatus.failed("boom")); + statuses.add(UStatus.failed("boom", UStatus.Code.UNKNOWN)); + + statuses.add(UStatus.failed("bam")); + statuses.add(UStatus.failed("boom", UStatus.Code.UNSPECIFIED.value())); + statuses.add(UStatus.failed("boom", UStatus.Code.INVALID_ARGUMENT)); + statuses.add("5"); + + assertEquals(6, statuses.size()); + } + + @Test + @DisplayName("Make sure the equals barfs when we compare uStatus that are not the same") + public void testHashCodeEquals_barfs_when_not_same() { + UStatus ok = UStatus.ok(); + UStatus failed = UStatus.failed(); + assertFalse(failed.equals(ok)); + assertFalse(ok.equals(failed)); + } + + @Test + @DisplayName("Test equals when there are differences in message and code") + public void testHashCodeEquals_different_message_and_code() { + UStatus failed = UStatus.failed("boom", UStatus.Code.UNKNOWN); + UStatus failed1 = UStatus.failed("boom", UStatus.Code.INVALID_ARGUMENT); + UStatus failed2 = UStatus.failed("bang", UStatus.Code.UNKNOWN); + UStatus failed3 = UStatus.failed("bang", UStatus.Code.INVALID_ARGUMENT); + assertFalse(failed.equals(failed1)); + assertFalse(failed.equals(failed2)); + assertFalse(failed.equals(failed3)); + + assertFalse(failed1.equals(failed)); + assertFalse(failed1.equals(failed2)); + assertFalse(failed1.equals(failed3)); + + assertFalse(failed2.equals(failed)); + assertFalse(failed2.equals(failed1)); + assertFalse(failed2.equals(failed3)); + + assertFalse(failed3.equals(failed)); + assertFalse(failed3.equals(failed2)); + assertFalse(failed3.equals(failed1)); + } + + @Test + @DisplayName("Make sure the equals is successful when comparing the same failed status") + public void testHashCodeEquals_same_failed_status() { + UStatus failed = UStatus.failed("boom", UStatus.Code.UNKNOWN); + UStatus failed1 = UStatus.failed("boom", UStatus.Code.UNKNOWN); + assertTrue(failed.equals(failed1)); + } + + @Test + @DisplayName("Make sure the equals is successful when comparing the same ok status") + public void testHashCodeEquals_same_ok_status() { + UStatus ok = UStatus.ok(); + UStatus ok1 = UStatus.ok(); + assertTrue(ok.equals(ok1)); + } + + @Test + @DisplayName("Make sure the equals passing the same object is successful") + public void testHashCodeEquals_same_object() { + final UStatus ok = UStatus.ok(); + final UStatus failed = UStatus.failed(); + assertTrue(ok.equals(ok)); + assertTrue(failed.equals(failed)); + } + + @Test + @DisplayName("Make sure the equals passing null reports not equals") + public void testHashCodeEquals_null() { + final UStatus ok = UStatus.ok(); + final UStatus failed = UStatus.failed(); + assertFalse(ok.equals(null)); + assertFalse(failed.equals(null)); + } + + @Test + @DisplayName("Make sure the toString works on ok status") + public void testToString_for_ok_status() { + UStatus ok = UStatus.ok(); + assertEquals("UStatus ok id=ok code=0", ok.toString()); + } + + @Test + @DisplayName("Make sure the toString works on ok status with Id") + public void testToString_for_ok_status_with_id() { + UStatus ok = UStatus.ok("boo"); + assertEquals("UStatus ok id=boo code=0", ok.toString()); + } + + @Test + @DisplayName("Make sure the toString works on failed status") + public void testToString_for_failed_status() { + UStatus failed = UStatus.failed(); + assertEquals("UStatus failed msg=failed code=2", failed.toString()); + } + + @Test + @DisplayName("Make sure the toString works on failed status with message") + public void testToString_for_failed_status_with_getMessage() { + UStatus failed = UStatus.failed("boom"); + assertEquals("UStatus failed msg=boom code=2", failed.toString()); + } + + @Test + @DisplayName("Make sure the toString works on failed status with message and failure reason") + public void testToString_for_failed_status_with_message_and_failure_reason() { + UStatus failed = UStatus.failed("boom", UStatus.Code.INVALID_ARGUMENT.value()); + assertEquals("UStatus failed msg=boom code=3", failed.toString()); + } + + @Test + @DisplayName("Make sure the toString works on failed status with message and Code") + public void testToString_for_failed_status_with_message_and_code() { + UStatus failed = UStatus.failed("boom", UStatus.Code.INVALID_ARGUMENT); + assertEquals("UStatus failed msg=boom code=3", failed.toString()); + } + + @Test + @DisplayName("Create ok status") + public void create_ok_status() { + UStatus ok = UStatus.ok(); + assertTrue(ok.isSuccess()); + assertFalse(ok.isFailed()); + assertEquals("ok", ok.msg()); + assertEquals(0, ok.getCode()); + } + + @Test + @DisplayName("Create ok status with Id") + public void create_ok_status_with_id() { + UStatus ok = UStatus.ok("boo"); + assertTrue(ok.isSuccess()); + assertFalse(ok.isFailed()); + assertEquals("boo", ok.msg()); + assertEquals(0, ok.getCode()); + } + + @Test + @DisplayName("Create failed status") + public void create_failed_status() { + UStatus failed = UStatus.failed(); + assertFalse(failed.isSuccess()); + assertTrue(failed.isFailed()); + assertEquals("failed", failed.msg()); + assertEquals(2, failed.getCode()); + } + + @Test + @DisplayName("Create failed status with message") + public void create_failed_status_with_getMessage() { + UStatus failed = UStatus.failed("boom"); + assertFalse(failed.isSuccess()); + assertTrue(failed.isFailed()); + assertEquals("boom", failed.msg()); + assertEquals(2, failed.getCode()); + } + + @Test + @DisplayName("Create failed status with message and failure reason") + public void create_failed_status_with_message_and_failure_reason() { + UStatus failed = UStatus.failed("boom", UStatus.Code.INVALID_ARGUMENT.value()); + assertFalse(failed.isSuccess()); + assertTrue(failed.isFailed()); + assertEquals("boom", failed.msg()); + assertEquals(3, failed.getCode()); + } + + @Test + @DisplayName("Create failed status with message and Code") + public void create_failed_status_with_message_and_code() { + UStatus failed = UStatus.failed("boom", UStatus.Code.INVALID_ARGUMENT); + assertFalse(failed.isSuccess()); + assertTrue(failed.isFailed()); + assertEquals("boom", failed.msg()); + assertEquals(3, failed.getCode()); + } + + @Test + @DisplayName("Code from a known int code") + public void code_from_a_known_int_code() { + final Optional code = UStatus.Code.from(4); + assertTrue(code.isPresent()); + assertEquals("DEADLINE_EXCEEDED", code.get().name()); + } + + @Test + @DisplayName("Code from a unknown int code") + public void code_from_a_unknown_int_code() { + final Optional code = UStatus.Code.from(299); + assertTrue(code.isEmpty()); + } + + @Test + @DisplayName("Code from a known google code") + public void code_from_a_known_google_code() { + final Optional code = UStatus.Code.from(com.google.rpc.Code.INVALID_ARGUMENT); + assertTrue(code.isPresent()); + assertEquals("INVALID_ARGUMENT", code.get().name()); + } + + @Test + @DisplayName("Code from a null google code") + public void code_from_a_null_google_code() { + final Optional code = UStatus.Code.from(null); + assertTrue(code.isEmpty()); + } + + @Test + @DisplayName("Code from a UNRECOGNIZED google code") + public void code_from_a_UNRECOGNIZED_google_code() { + final Optional code = UStatus.Code.from(com.google.rpc.Code.UNRECOGNIZED); + assertTrue(code.isEmpty()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributesValidatorTest.java b/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributesValidatorTest.java new file mode 100644 index 00000000..15d0e8c4 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/transport/validator/UAttributesValidatorTest.java @@ -0,0 +1,987 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.transport.validator; + +import org.eclipse.uprotocol.transport.datamodel.UAttributes; +import org.eclipse.uprotocol.transport.datamodel.UMessageType; +import org.eclipse.uprotocol.transport.datamodel.UPriority; +import org.eclipse.uprotocol.transport.datamodel.UAttributes.UAttributesBuilder; +import org.eclipse.uprotocol.transport.datamodel.UStatus.Code; +import org.eclipse.uprotocol.transport.validate.UAttributesValidator; +import org.eclipse.uprotocol.uri.builder.UResourceBuilder; +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.uuid.factory.UUIDFactory; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.validation.ValidationResult; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +class UAttributesValidatorTest { + + @Test + @DisplayName("test fetching validator for valid types") + public void test_fetching_validator_for_valid_types() { + + UAttributesValidator publish = UAttributesValidator.getValidator( + new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW).build()); + assertEquals("UAttributesValidator.Publish", publish.toString()); + + UAttributesValidator request = UAttributesValidator.getValidator( + new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE).build()); + assertEquals("UAttributesValidator.Request", request.toString()); + + UAttributesValidator response = UAttributesValidator.getValidator( + new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE).build()); + assertEquals("UAttributesValidator.Response", response.toString()); + } + + @Test + @DisplayName("test fetching validator when message type is null") + public void test_fetching_validator_when_message_type_is_null() { + + UAttributesValidator publish = UAttributesValidator.getValidator( + new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + null, UPriority.LOW).build()); + assertEquals("UAttributesValidator.Publish", publish.toString()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published") + public void test_validate_uAttributes_for_publish_message_payload() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with all values") + public void test_validate_uAttributes_for_publish_message_payload_all_values() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(1000) + .withSink(buildSink()) + .withPermissionLevel(2) + .withCommStatus(3) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid id") + public void test_validate_uAttributes_for_publish_message_payload_invalid_id() { + final UAttributes attributes = new UAttributesBuilder(null, + UMessageType.PUBLISH, UPriority.LOW).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertTrue(status.getMessage().contains("Invalid UUID [null]")); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid type") + public void test_validate_uAttributes_for_publish_message_payload_invalid_type() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.LOW).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Wrong Attribute Type [RESPONSE]", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid priority") + public void test_validate_uAttributes_for_publish_message_payload_invalid_priority() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, null).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Priority is missing", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid time to live") + public void test_validate_uAttributes_for_publish_message_payload_invalid_ttl() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(-1) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid TTL [-1]", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid sink") + public void test_validate_uAttributes_for_publish_message_payload_invalid_sink() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withSink(UUri.getDefaultInstance()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid permission level") + public void test_validate_uAttributes_for_publish_message_payload_invalid_permission_level() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withPermissionLevel(-42) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Permission Level", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid communication status") + public void test_validate_uAttributes_for_publish_message_payload_invalid_communication_status() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withCommStatus(-42) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Communication Status Code", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published with invalid request id") + public void test_validate_uAttributes_for_publish_message_payload_invalid_request_id() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withReqId(UUID.randomUUID()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid UUID", status.getMessage()); + } + + // ---- + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request") + public void test_validate_uAttributes_for_rpc_request_message_payload() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(1000) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with all values") + public void test_validate_uAttributes_for_rpc_request_message_payload_all_values() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(1000) + .withPermissionLevel(2) + .withCommStatus(3) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid id") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_id() { + + final UAttributes attributes = new UAttributesBuilder(null, + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(1000) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertTrue(status.getMessage().contains("Invalid UUID [null]")); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid type") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_type() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(1000) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Wrong Attribute Type [RESPONSE]", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid priority") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_priority() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, null) + .withSink(buildSink()) + .withTtl(1000) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Priority is missing", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with missing time to live") + public void test_validate_uAttributes_for_rpc_request_message_payload_missing_ttl() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Missing TTL", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid time to live") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_ttl() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(-1) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid TTL [-1]", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with missing sink and missing ttl") + public void test_validate_uAttributes_for_rpc_request_message_payload_missing_sink_and_missing_ttl() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Missing TTL,Missing Sink", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid sink") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_sink() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(UUri.getDefaultInstance()) + .withTtl(1000) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid permission level") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_permission_level() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(1000) + .withPermissionLevel(-42) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Permission Level", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid communication status") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_communication_status() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(1000) + .withCommStatus(-42) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Communication Status Code", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC request with invalid request id") + public void test_validate_uAttributes_for_rpc_request_message_payload_invalid_request_id() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withTtl(1000) + .withReqId(UUID.randomUUID()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid UUID", status.getMessage()); + } + + // ---- + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response") + public void test_validate_uAttributes_for_rpc_response_message_payload() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with all values") + public void test_validate_uAttributes_for_rpc_response_message_payload_all_values() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .withPermissionLevel(2) + .withCommStatus(3) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid id") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_id() { + final UAttributes attributes = new UAttributesBuilder(null, + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertTrue(status.getMessage().contains("Invalid UUID [null]")); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid type") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_type() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Wrong Attribute Type [PUBLISH]", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid priority") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_priority() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, null) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Priority is missing", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid time to live") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_ttl() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .withTtl(-1) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid TTL [-1]", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with missing sink and missing request id") + public void test_validate_uAttributes_for_rpc_response_message_payload_missing_sink_and_missing_requestId() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Missing Sink,Missing correlationId", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid sink") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_sink() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(null) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Missing Sink", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid permission level") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_permission_level() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .withPermissionLevel(-42) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Permission Level", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid communication status") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_communication_status() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .withCommStatus(-42) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Communication Status Code", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with missing request id") + public void test_validate_uAttributes_for_rpc_response_message_payload_missing_request_id() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Missing correlationId", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be an RPC response with invalid request id") + public void test_validate_uAttributes_for_rpc_response_message_payload_invalid_request_id() { + final UUID reqid = UUID.randomUUID(); + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.REALTIME_INTERACTIVE) + .withSink(buildSink()) + .withReqId(reqid) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals(String.format("Invalid correlationId [%s]", reqid), status.getMessage()); + } + + // ---- + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published not expired") + public void test_validate_uAttributes_for_publish_message_payload_not_expired() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.isExpired(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published not expired with ttl zero") + public void test_validate_uAttributes_for_publish_message_payload_not_expired_with_ttl_zero() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(0) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.isExpired(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published not expired with ttl") + public void test_validate_uAttributes_for_publish_message_payload_not_expired_with_ttl() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(10000) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.isExpired(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published expired with ttl") + public void test_validate_uAttributes_for_publish_message_payload_expired_with_ttl() throws InterruptedException { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(1) + .build(); + + Thread.sleep(800); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.isExpired(attributes); + assertTrue(status.isFailure()); + assertEquals("Payload is expired", status.getMessage()); + } + + @Test + @DisplayName("Validate a UAttributes for payload that is meant to be published not expired cant calculate bad UUID") + public void test_validate_uAttributes_for_publish_message_payload_not_expired_cant_calculate_bad_uuid() { + final UAttributes attributes = new UAttributesBuilder(UUID.randomUUID(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(10000) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.isExpired(attributes); + assertFalse(status.isSuccess()); + assertEquals("Invalid Time", status.getMessage()); + } + + // ---- + + @Test + @DisplayName("test validating publish invalid ttl attribute") + public void test_validating_publish_invalid_ttl_attribute() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(-1).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateTtl(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid TTL [-1]", status.getMessage()); + } + + @Test + @DisplayName("test validating publish valid ttl attribute") + public void test_validating_valid_ttl_attribute() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withTtl(100).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateTtl(attributes); + assertEquals(ValidationResult.success(), status); + } + + @Test + @DisplayName("test validating invalid id attribute") + public void test_validating_invalid_id_attribute() { + + final UAttributes attributes = new UAttributesBuilder(null, + UMessageType.PUBLISH, UPriority.LOW).build(); + + final UAttributes attributes1 = new UAttributesBuilder(UUID.randomUUID(), + UMessageType.PUBLISH, UPriority.LOW).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + ValidationResult status = validator.validateId(attributes); + assertTrue(status.isFailure()); + assertTrue(status.getMessage().contains("Invalid UUID [null]")); + + ValidationResult status1 = validator.validateId(attributes1); + assertTrue(status1.isFailure()); + assertTrue(status.getMessage().contains("Invalid UUID [null]")); + } + + @Test + @DisplayName("test validating valid id attribute") + public void test_validating_valid_id_attribute() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateId(attributes); + assertEquals(ValidationResult.success(), status); + } + + @Test + @DisplayName("test validating invalid sink attribute") + public void test_validating_invalid_sink_attribute() { + final UUri uri = LongUriSerializer.instance().deserialize("//"); + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW).withSink(uri).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateSink(attributes); + + assertTrue(status.isFailure()); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("test validating valid sink attribute") + public void test_validating_valid_sink_attribute() { + final UUri uri = LongUriSerializer.instance().deserialize("/haartley/1"); + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW).withSink(uri).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateSink(attributes); + assertEquals(ValidationResult.success(), status); + } + + @Test + @DisplayName("test validating invalid ReqId attribute") + public void test_validating_invalid_ReqId_attribute() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW).withReqId(UUID.randomUUID()).build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateReqId(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid UUID", status.getMessage()); + } + + @Test + @DisplayName("test validating valid ReqId attribute") + public void test_validating_valid_ReqId_attribute() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateReqId(attributes); + assertEquals(ValidationResult.success(), status); + } + + + @Test + @DisplayName("test validating invalid PermissionLevel attribute") + public void test_validating_invalid_PermissionLevel_attribute() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withPermissionLevel(-1) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validatePermissionLevel(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Permission Level", status.getMessage()); + } + + @Test + @DisplayName("test validating valid PermissionLevel attribute") + public void test_validating_valid_PermissionLevel_attribute() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withPermissionLevel(3) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validatePermissionLevel(attributes); + assertEquals(ValidationResult.success(), status); + } + + @Test + @DisplayName("test validating valid PermissionLevel attribute") + public void test_validating_valid_PermissionLevel_attribute_invalid() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withPermissionLevel(0) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validatePermissionLevel(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid Permission Level", status.getMessage()); + } + + @Test + @DisplayName("test validating invalid commstatus attribute") + public void test_validating_invalid_commstatus_attribute() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withCommStatus(100) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateCommStatus(attributes); + assertTrue(status.isFailure()); + assertEquals( "Invalid Communication Status Code", status.getMessage()); + } + + @Test + @DisplayName("test validating valid commstatus attribute") + public void test_validating_valid_commstatus_attribute() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withCommStatus(Code.ABORTED.value()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + final ValidationResult status = validator.validateCommStatus(attributes); + assertEquals(ValidationResult.success(), status); + } + + + @Test + @DisplayName("test validating request message types") + public void test_validating_request_message_types() { + final UUri sink = LongUriSerializer.instance().deserialize("/hartley/1/rpc.response"); + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.NETWORK_CONTROL) + .withSink(buildSink()) + .withTtl(100) + .build(); + + final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); + assertEquals("UAttributesValidator.Request", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isSuccess()); + assertEquals("", status.getMessage()); + } + + @Test + @DisplayName("test validating request validator using wrong messagetype") + public void test_validating_request_validator_with_wrong_messagetype() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.NETWORK_CONTROL) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + assertEquals("UAttributesValidator.Request", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Wrong Attribute Type [PUBLISH],Missing TTL,Missing Sink", status.getMessage()); + } + + @Test + @DisplayName("test validating request validator using bad ttl") + public void test_validating_request_validator_with_wrong_bad_ttl() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.NETWORK_CONTROL) + .withSink(LongUriSerializer.instance().deserialize("/hartley/1/rpc.response")) + .withTtl(-1) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.REQUEST.validator(); + assertEquals("UAttributesValidator.Request", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid TTL [-1]", status.getMessage()); + } + + @Test + @DisplayName("test validating response validator using bad ttl") + public void test_validating_response_validator_with_wrong_bad_ttl() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.RESPONSE, UPriority.NETWORK_CONTROL) + .withSink(LongUriSerializer.instance().deserialize("/hartley/1/rpc.response")) + .withTtl(-1) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + assertEquals("UAttributesValidator.Response", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Invalid TTL [-1]", status.getMessage()); + } + + @Test + @DisplayName("test validating response validator using bad UUID") + public void test_validating_response_validator_with_bad_reqid() { + + final UUID id = UUID.randomUUID(); + final UAttributes attributes = new UAttributesBuilder(id, + UMessageType.RESPONSE, UPriority.NETWORK_CONTROL) + .withSink(LongUriSerializer.instance().deserialize("/hartley/1/rpc.response")) + .withTtl(100) + .withReqId(UUIDFactory.Factories.UPROTOCOL.factory().create()) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + assertEquals("UAttributesValidator.Response", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals(String.format("Invalid UUID [%s]", id), status.getMessage()); + } + + + @Test + @DisplayName("test validating publish validator with wrong messagetype") + public void test_validating_publish_validator_with_wrong_messagetype() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.REQUEST, UPriority.NETWORK_CONTROL) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.PUBLISH.validator(); + assertEquals("UAttributesValidator.Publish", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Wrong Attribute Type [REQUEST]", status.getMessage()); + } + + @Test + @DisplayName("test validating response validator with wrong messagetype") + public void test_validating_response_validator_with_wrong_messagetype() { + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.NETWORK_CONTROL) + .build(); + + final UAttributesValidator validator = UAttributesValidator.Validators.RESPONSE.validator(); + assertEquals("UAttributesValidator.Response", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertTrue(status.isFailure()); + assertEquals("Wrong Attribute Type [PUBLISH],Missing Sink,Missing correlationId", status.getMessage()); + } + + + @Test + @DisplayName("test validating request containing token") + public void test_validating_request_containing_token() { + + final UAttributes attributes = new UAttributesBuilder(UUIDFactory.Factories.UPROTOCOL.factory().create(), + UMessageType.PUBLISH, UPriority.LOW) + .withToken("null") + .build(); + + final UAttributesValidator validator = UAttributesValidator.getValidator(attributes); + assertEquals("UAttributesValidator.Publish", validator.toString()); + final ValidationResult status = validator.validate(attributes); + assertEquals(ValidationResult.success(), status); + } + + private UUri buildSink() { + return UUri.newBuilder() + .setAuthority(UAuthority.newBuilder().setName("vcu.someVin.veh.ultifi.gm.com")) + .setEntity(UEntity.newBuilder().setName("petapp.ultifi.gm.com").setVersionMajor(1)) + .setResource(UResourceBuilder.forRpcResponse()) + .build(); + } + +} diff --git a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UAuthorityTest.java b/src/test/java/org/eclipse/uprotocol/uri/datamodel/UAuthorityTest.java deleted file mode 100644 index cb2bf852..00000000 --- a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UAuthorityTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import nl.jqno.equalsverifier.EqualsVerifier; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class UAuthorityTest { - - @Test - @DisplayName("Make sure the equals and hash code works") - public void testHashCodeEquals() { - EqualsVerifier.forClass(UAuthority.class).usingGetClass().verify(); - } - - @Test - @DisplayName("Make sure the toString works") - public void testToString() { - UAuthority uAuthority = UAuthority.remote("VCU", "my_VIN"); - String sRemote = uAuthority.toString(); - String expectedRemote = "UAuthority{device='vcu', domain='my_vin', markedRemote=true}"; - assertEquals(expectedRemote, sRemote); - - UAuthority local = UAuthority.local(); - String sLocal = local.toString(); - String expectedLocal = "UAuthority{device='null', domain='null', markedRemote=false}"; - assertEquals(expectedLocal, sLocal); - - } - - @Test - @DisplayName("Make sure the toString works with case sensitivity") - public void testToString_case_sensitivity() { - UAuthority uAuthority = UAuthority.remote("vcU", "my_VIN"); - String sRemote = uAuthority.toString(); - String expectedRemote = "UAuthority{device='vcu', domain='my_vin', markedRemote=true}"; - assertEquals(expectedRemote, sRemote); - - UAuthority local = UAuthority.local(); - String sLocal = local.toString(); - String expectedLocal = "UAuthority{device='null', domain='null', markedRemote=false}"; - assertEquals(expectedLocal, sLocal); - - } - - @Test - @DisplayName("Test a local uAuthority") - public void test_local_uAuthority() { - UAuthority uAuthority = UAuthority.local(); - assertTrue(uAuthority.device().isEmpty()); - assertTrue(uAuthority.domain().isEmpty()); - assertTrue(uAuthority.isLocal()); - assertFalse(uAuthority.isMarkedRemote()); - } - - @Test - @DisplayName("Test a local uAuthority when one part is empty") - public void test_local_uAuthority_one_part_empty() { - UAuthority uAuthority = UAuthority.remote("", "My_VIN"); - assertFalse(uAuthority.isLocal()); - UAuthority uAuthority2 = UAuthority.remote("VCU", ""); - assertFalse(uAuthority2.isLocal()); - } - - @Test - @DisplayName("Test a remote uAuthority") - public void test_remote_uAuthority() { - UAuthority uAuthority = UAuthority.remote("VCU", "my_VIN"); - assertTrue(uAuthority.device().isPresent()); - assertEquals("vcu", uAuthority.device().get()); - assertTrue(uAuthority.domain().isPresent()); - assertEquals("my_vin", uAuthority.domain().get()); - assertTrue(uAuthority.isRemote()); - assertTrue(uAuthority.isMarkedRemote()); - } - - @Test - @DisplayName("Test a remote uAuthority with case sensitivity") - public void test_remote_uAuthority_case_sensitive() { - UAuthority uAuthority = UAuthority.remote("VCu", "my_VIN"); - assertTrue(uAuthority.device().isPresent()); - assertEquals("vcu", uAuthority.device().get()); - assertTrue(uAuthority.domain().isPresent()); - assertEquals("my_vin", uAuthority.domain().get()); - assertTrue(uAuthority.isRemote()); - assertTrue(uAuthority.isMarkedRemote()); - } - - @Test - @DisplayName("Test a blank remote uAuthority is actually local") - public void test_blank_remote_uAuthority_is_local() { - UAuthority uAuthority = UAuthority.remote(" ", " "); - assertTrue(uAuthority.device().isEmpty()); - assertTrue(uAuthority.domain().isEmpty()); - assertTrue(uAuthority.isLocal()); - assertFalse(uAuthority.isRemote()); - assertTrue(uAuthority.isMarkedRemote()); - } - - @Test - @DisplayName("Make sure the empty() works") - public void testEmpty() { - UAuthority uAuthority = UAuthority.empty(); - assertTrue(uAuthority.device().isEmpty()); - assertTrue(uAuthority.domain().isEmpty()); - } - - @Test - @DisplayName("Make sure the isLocal() works") - public void test_isLocal() { - UAuthority local = UAuthority.local(); - assertTrue(local.isLocal()); - assertFalse(local.isRemote()); - assertFalse(local.isMarkedRemote()); - } - - @Test - @DisplayName("Make sure the isRemote() works") - public void test_isRemote() { - UAuthority remote = UAuthority.remote("VCU", "my_VIN"); - assertFalse(remote.isLocal()); - assertTrue(remote.isRemote()); - assertTrue(remote.isMarkedRemote()); - } -} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UEntityTest.java b/src/test/java/org/eclipse/uprotocol/uri/datamodel/UEntityTest.java deleted file mode 100644 index 116d2b8a..00000000 --- a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UEntityTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import nl.jqno.equalsverifier.EqualsVerifier; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -class UEntityTest { - - @Test - @DisplayName("Make sure the equals and hash code works") - public void testHashCodeEquals() { - EqualsVerifier.forClass(UEntity.class).usingGetClass().verify(); - } - - @Test - @DisplayName("Make sure the toString works") - public void testToString() { - UEntity use = new UEntity("body.access", "1"); - assertEquals("body.access", use.name()); - assertTrue(use.version().isPresent()); - assertEquals("1", use.version().get()); - - String expected = "UEntity{name='body.access', version='1'}"; - assertEquals(expected, use.toString()); - - UEntity use1 = UEntity.fromName("body.access"); - assertEquals("UEntity{name='body.access', version='latest'}", use1.toString()); - } - - @Test - @DisplayName("Test creating a complete USE") - public void test_create_use() { - UEntity use = new UEntity("body.access", "1"); - assertEquals("body.access", use.name()); - assertTrue(use.version().isPresent()); - assertEquals("1", use.version().get()); - } - - @Test - @DisplayName("Test creating a complete USE with a null name, expect exception") - public void test_create_use_null_name() { - Exception exception = assertThrows(NullPointerException.class, () -> new UEntity(null, "1")); - assertTrue(exception.getMessage().contains(" Software Entity must have a name")); - } - - @Test - @DisplayName("Test creating a USE with no version") - public void test_create_use_with_no_version() { - UEntity use = new UEntity("body.access", " "); - assertEquals("body.access", use.name()); - assertTrue(use.version().isEmpty()); - - UEntity use2 = new UEntity("body.access", null); - assertEquals("body.access", use2.name()); - assertTrue(use2.version().isEmpty()); - } - - @Test - @DisplayName("Test creating a USE using the fromName static method") - public void test_create_use_with_no_version_using_fromName() { - UEntity use = UEntity.fromName("body.access"); - assertEquals("body.access", use.name()); - assertTrue(use.version().isEmpty()); - } - - @Test - @DisplayName("Test creating an empty USE using the empty static method") - public void test_create_empty_using_empty() { - UEntity use = UEntity.empty(); - assertTrue(use.name().isEmpty()); - assertTrue(use.version().isEmpty()); - } - - @Test - @DisplayName("Test the isEmpty static method") - public void test_is_empty() { - UEntity use = UEntity.empty(); - assertTrue(use.isEmpty()); - - UEntity use2 = new UEntity("", null); - assertTrue(use2.isEmpty()); - - UEntity use3 = new UEntity("", "1"); - assertFalse(use3.isEmpty()); - - UEntity use4 = new UEntity("petapp", null); - assertFalse(use4.isEmpty()); - } -} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UResourceTest.java b/src/test/java/org/eclipse/uprotocol/uri/datamodel/UResourceTest.java deleted file mode 100644 index 1387a86b..00000000 --- a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UResourceTest.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import nl.jqno.equalsverifier.EqualsVerifier; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class UResourceTest { - - @Test - @DisplayName("Make sure the equals and hash code works") - public void testHashCodeEquals() { - EqualsVerifier.forClass(UResource.class).usingGetClass().verify(); - } - - @Test - @DisplayName("Make sure the toString works") - public void testToString() { - UResource uResource = new UResource("door", "front_left", "Door"); - String expected = "UResource{name='door', instance='front_left', message='Door'}"; - assertEquals(expected, uResource.toString()); - } - - @Test - @DisplayName("Test creating a complete Resource") - public void test_create_Resource() { - UResource uResource = new UResource("door", "front_left", "Door"); - assertEquals("door", uResource.name()); - assertTrue(uResource.instance().isPresent()); - assertEquals("front_left", uResource.instance().get()); - assertTrue(uResource.message().isPresent()); - assertEquals("Door", uResource.message().get()); - } - - @Test - @DisplayName("Test creating a complete Resource with a null name, expect exception") - public void test_create_Resource_null_name() { - Exception exception = assertThrows(NullPointerException.class, () -> new UResource(null, "front_left", "Door")); - assertTrue(exception.getMessage().contains(" Resource must have a name.")); - } - - @Test - @DisplayName("Test creating an Resource for RPC command with a null command name, expect exception") - public void test_create_Resource_for_rpc_command_null_name() { - Exception exception = assertThrows(NullPointerException.class, () -> UResource.forRpc(null)); - assertTrue(exception.getMessage().contains(" Resource must have a command name.")); - } - - @Test - @DisplayName("Test creating a Resource with no instance and no message") - public void test_create_Resource_with_no_instance_and_no_message() { - UResource uResource = new UResource("door", " ", " "); - assertEquals("door", uResource.name()); - assertTrue(uResource.instance().isEmpty()); - assertTrue(uResource.message().isEmpty()); - - UResource uResource2 = new UResource("door", null, null); - assertEquals("door", uResource2.name()); - assertTrue(uResource.instance().isEmpty()); - assertTrue(uResource.message().isEmpty()); - } - - @Test - @DisplayName("Test creating a Resource using the fromName static method") - public void test_create_Resource_with_no_instance_and_no_message_using_fromName() { - UResource uResource = UResource.fromName("door"); - assertEquals("door", uResource.name()); - assertTrue(uResource.instance().isEmpty()); - assertTrue(uResource.message().isEmpty()); - } - - @Test - @DisplayName("Test creating a Resource using the fromNameWithInstance static method") - public void test_create_Resource_with_no_message_using_fromName() { - UResource uResource = UResource.fromNameWithInstance("door", "front_left"); - assertEquals("door", uResource.name()); - assertTrue(uResource.instance().isPresent()); - assertEquals("front_left", uResource.instance().get()); - assertTrue(uResource.message().isEmpty()); - } - - @Test - @DisplayName("Test creating a Resource for an RPC command on the resource") - public void test_create_Resource_for_rpc_commands() { - UResource uResource = UResource.forRpc("UpdateDoor"); - assertEquals("rpc", uResource.name()); - assertTrue(uResource.instance().isPresent()); - assertEquals("UpdateDoor", uResource.instance().get()); - assertTrue(uResource.isRPCMethod()); - } - - @Test - @DisplayName("Test if the resource represents an RPC method call") - public void test_Resource_represents_an_rpc_method_call() { - UResource uResource = UResource.fromNameWithInstance("rpc", "UpdateDoor"); - assertTrue(uResource.isRPCMethod()); - } - - @Test - @DisplayName("Test if the resource represents a resource and not an RPC method call") - public void test_Resource_represents_a_resource_and_not_an_rpc_method_call() { - UResource uResource = UResource.fromName("door"); - assertFalse(uResource.isRPCMethod()); - } - - @Test - @DisplayName("Test returning a name with instance when both name and instance are configured") - public void test_returning_a_name_with_instance_from_uResource_when_name_and_instance_are_configured() { - UResource uResource = UResource.fromNameWithInstance("doors", "front_left"); - final String nameWithInstance = uResource.nameWithInstance(); - assertEquals("doors.front_left", nameWithInstance); - } - - @Test - @DisplayName("Test returning a name with instance when only name is configured") - public void test_returning_a_name_with_instance_from_uResource_when_only_name_is_configured() { - UResource uResource = UResource.fromName("door"); - final String nameWithInstance = uResource.nameWithInstance(); - assertEquals("door", nameWithInstance); - } - - @Test - @DisplayName("Test returning a name with instance when all properties are configured") - public void test_returning_a_name_with_instance_from_uResource_when_all_properties_are_configured() { - UResource uResource = new UResource("doors", "front_left", "Door"); - final String nameWithInstance = uResource.nameWithInstance(); - assertEquals("doors.front_left", nameWithInstance); - } - - @Test - @DisplayName("Test creating an empty Resource using the empty static method") - public void test_create_empty_using_empty() { - UResource uResource = UResource.empty(); - assertTrue(uResource.name().isEmpty()); - assertTrue(uResource.instance().isEmpty()); - assertTrue(uResource.message().isEmpty()); - } - - @Test - @DisplayName("Test the isEmpty static method") - public void test_is_empty() { - UResource uResource = UResource.empty(); - assertTrue(uResource.isEmpty()); - - UResource uResource2 = new UResource("", null, null); - assertTrue(uResource2.isEmpty()); - - UResource uResource3 = new UResource("", "front_left", null); - assertFalse(uResource3.isEmpty()); - - UResource uResource4 = new UResource("", null, "Door"); - assertFalse(uResource4.isEmpty()); - } - - @Test - @DisplayName("Test creating an RPC response Resource using the response static method") - public void test_create_rpc_response_using_response_method() { - UResource uResource = UResource.response(); - assertFalse(uResource.name().isEmpty()); - assertEquals("rpc", uResource.name()); - assertEquals("response", uResource.instance().orElse("")); - assertTrue(uResource.message().isEmpty()); - } - -} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UUriTest.java b/src/test/java/org/eclipse/uprotocol/uri/datamodel/UUriTest.java deleted file mode 100644 index 86ad78af..00000000 --- a/src/test/java/org/eclipse/uprotocol/uri/datamodel/UUriTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.datamodel; - -import nl.jqno.equalsverifier.EqualsVerifier; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -class UriTest { - - @Test - @DisplayName("Make sure the equals and hash code works") - public void testHashCodeEquals() { - EqualsVerifier.forClass(UUri.class).usingGetClass().verify(); - } - - @Test - @DisplayName("Make sure the toString works") - public void testToString() { - UAuthority uAuthorityLocal = UAuthority.local(); - UAuthority uAuthorityRemote = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = new UEntity("body.access", "1"); - UResource uResource = UResource.fromNameWithInstance("door", "front_left"); - - UUri uri = new UUri(uAuthorityLocal, use, uResource); - - String expected = "Uri{uAuthority=UAuthority{device='null', domain='null', markedRemote=false}, " + - "uEntity=UEntity{name='body.access', version='1'}, " + - "uResource=UResource{name='door', instance='front_left', message='null'}}"; - assertEquals(expected, uri.toString()); - - UUri uriRemote = new UUri(uAuthorityRemote, use, uResource); - String expectedRemote = "Uri{uAuthority=UAuthority{device='vcu', domain='my_vin', markedRemote=true}, " + - "uEntity=UEntity{name='body.access', version='1'}, " + - "uResource=UResource{name='door', instance='front_left', message='null'}}"; - assertEquals(expectedRemote, uriRemote.toString()); - - UUri uri2 = new UUri(uAuthorityRemote, use, UResource.empty()); - String expectedUri2 = "Uri{uAuthority=UAuthority{device='vcu', domain='my_vin', markedRemote=true}, " + - "uEntity=UEntity{name='body.access', version='1'}, " + - "uResource=UResource{name='', instance='null', message='null'}}"; - assertEquals(expectedUri2, uri2.toString()); - } - - @Test - @DisplayName("Test creating full local uri") - public void test_create_full_local_uri() { - UAuthority uAuthority = UAuthority.local(); - UEntity use = UEntity.fromName("body.access"); - UResource uResource = UResource.fromNameWithInstance("door", "front_left"); - - UUri uri = new UUri(uAuthority, use, uResource); - - assertEquals(uAuthority, uri.uAuthority()); - assertEquals(use, uri.uEntity()); - assertEquals(uResource, uri.uResource()); - } - - @Test - @DisplayName("Test creating full remote uri") - public void test_create_full_remote_uri() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = new UEntity("body.access", "1"); - UResource uResource = new UResource("door", "front_left", "Door"); - - UUri uri = new UUri(uAuthority, use, uResource); - - assertEquals(uAuthority, uri.uAuthority()); - assertEquals(use, uri.uEntity()); - assertEquals(uResource, uri.uResource()); - } - - - @Test - @DisplayName("Test creating full uri with resource but no message using the constructor") - public void test_create_uri_no_message_with_constructor() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = new UEntity("body.access", "1"); - UResource uResource = UResource.fromName("door"); - - UUri uri = new UUri(uAuthority, use, "door"); - - assertEquals(uAuthority, uri.uAuthority()); - assertEquals(use, uri.uEntity()); - assertEquals(uResource, uri.uResource()); - } - - @Test - @DisplayName("Test creating a uri with a null authority, expect creation with an empty authority") - public void test_create_uri_null_authority() { - UEntity use = new UEntity("body.access", "1"); - UResource uResource = UResource.fromNameWithInstance("door", "front_left"); - - UUri uri = new UUri(null, use, uResource); - assertEquals(UAuthority.empty(), uri.uAuthority()); - } - - @Test - @DisplayName("Test creating a uri with a null software entity, expect creation with an empty software entity") - public void test_create_uri_null_use() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_VIN"); - UResource uResource = UResource.fromNameWithInstance("door", "front_left"); - - UUri uri = new UUri(uAuthority, null, uResource); - assertEquals(UEntity.empty(), uri.uEntity()); - } - - @Test - @DisplayName("Test creating a uri with a null ulitfi resource, expect creation with an empty resource") - public void test_create_uri_null_uResource() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = new UEntity("body.access", "1"); - UResource uResource = UResource.empty(); - - UUri uri = new UUri(uAuthority, use, uResource); - assertEquals(UResource.empty(), uri.uResource()); - } - - @Test - @DisplayName("Test creating an empty uri using the empty static method") - public void test_create_empty_using_empty() { - UUri uri = UUri.empty(); - - assertTrue(uri.uAuthority().isLocal()); - assertTrue(uri.uEntity().isEmpty()); - assertTrue(uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test the isEmpty static method") - public void test_is_empty() { - UUri uri = UUri.empty(); - assertTrue(uri.isEmpty()); - - UAuthority uAuthority = UAuthority.empty(); - UEntity use = UEntity.empty(); - UResource uResource = UResource.empty(); - - UUri uri2 = new UUri(uAuthority, use, uResource); - assertTrue(uri2.isEmpty()); - } - - @Test - @DisplayName("Test lazy initialization of the uProtocol routing string") - public void test_lazy_initialization_of_uprotocol_routing_string() { - UAuthority uAuthorityRemote = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = new UEntity("body.access", "1"); - UResource uResource = UResource.fromNameWithInstance("door", "front_left"); - UUri uri = new UUri(uAuthorityRemote, use, uResource); - - assertEquals("//vcu.my_vin/body.access/1/door.front_left", uri.uProtocolUri()); - - // call it again, should not call the function, but there is not really a way to test it. - assertEquals("//vcu.my_vin/body.access/1/door.front_left", uri.uProtocolUri()); - } - -} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/uri/factory/UriFactoryTest.java b/src/test/java/org/eclipse/uprotocol/uri/factory/UriFactoryTest.java deleted file mode 100644 index 4fef2cac..00000000 --- a/src/test/java/org/eclipse/uprotocol/uri/factory/UriFactoryTest.java +++ /dev/null @@ -1,972 +0,0 @@ -/* - * Copyright (c) 2023 General Motors GTO LLC - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.eclipse.uprotocol.uri.factory; - -import org.eclipse.uprotocol.uri.datamodel.UAuthority; -import org.eclipse.uprotocol.uri.datamodel.UEntity; -import org.eclipse.uprotocol.uri.datamodel.UResource; -import org.eclipse.uprotocol.uri.datamodel.UUri; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class UriFactoryTest { - - @Test - @DisplayName("Test parse uProtocol uri that is null") - public void test_parse_protocol_uri_when_is_null() { - UUri Uri = UriFactory.parseFromUri(null); - assertTrue(Uri.isEmpty()); - } - - - @Test - @DisplayName("Test parse uProtocol uri that is empty string") - public void test_parse_protocol_uri_when_is_empty_string() { - String uri = ""; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with schema and slash") - public void test_parse_protocol_uri_with_schema_and_slash() { - String uri = "/"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertTrue(Uri.isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with schema and double slash") - public void test_parse_protocol_uri_with_schema_and_double_slash() { - String uri = "//"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertTrue(Uri.uAuthority().isMarkedRemote()); - assertTrue(Uri.isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with schema and 3 slash and something") - public void test_parse_protocol_uri_with_schema_and_3_slash_and_something() { - String uri = "///body.access"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertTrue(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with schema and 4 slash and something") - public void test_parse_protocol_uri_with_schema_and_4_slash_and_something() { - String uri = "////body.access"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertTrue(Uri.uAuthority().isMarkedRemote()); - assertTrue(Uri.uEntity().name().isBlank()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("body.access", Uri.uEntity().version().get()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with schema and 5 slash and something") - public void test_parse_protocol_uri_with_schema_and_5_slash_and_something() { - String uri = "/////body.access"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertTrue(Uri.uAuthority().isMarkedRemote()); - assertTrue(Uri.uEntity().isEmpty()); - assertEquals("body", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("access", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with schema and 6 slash and something") - public void test_parse_protocol_uri_with_schema_and_6_slash_and_something() { - String uri = "//////body.access"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertTrue(Uri.uAuthority().isMarkedRemote()); - assertTrue(Uri.isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service no version") - public void test_parse_protocol_uri_with_local_service_no_version() { - String uri = "/body.access"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service with version") - public void test_parse_protocol_uri_with_local_service_with_version() { - String uri = "/body.access/1"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service no version with resource name only") - public void test_parse_protocol_uri_with_local_service_no_version_with_resource_name_only() { - String uri = "/body.access//door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isEmpty()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service with version with resource name only") - public void test_parse_protocol_uri_with_local_service_with_version_with_resource_name_only() { - String uri = "/body.access/1/door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isEmpty()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service no version with resource and instance only") - public void test_parse_protocol_uri_with_local_service_no_version_with_resource_with_instance() { - String uri = "/body.access//door.front_left"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service with version with resource and instance only") - public void test_parse_protocol_uri_with_local_service_with_version_with_resource_with_message() { - String uri = "/body.access/1/door.front_left"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service no version with resource with instance and message") - public void test_parse_protocol_uri_with_local_service_no_version_with_resource_with_instance_and_message() { - String uri = "/body.access//door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - } - - @Test - @DisplayName("Test parse uProtocol uri with local service with version with resource with instance and message") - public void test_parse_protocol_uri_with_local_service_with_version_with_resource_with_instance_and_message() { - String uri = "/body.access/1/door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - } - - @Test - @DisplayName("Test parse uProtocol RPC uri with local service no version") - public void test_parse_protocol_rpc_uri_with_local_service_no_version() { - String uri = "/petapp//rpc.response"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("petapp", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("rpc", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("response", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol RPC uri with local service with version") - public void test_parse_protocol_rpc_uri_with_local_service_with_version() { - String uri = "/petapp/1/rpc.response"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("petapp", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("rpc", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("response", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service only device no domain") - public void test_parse_protocol_uri_with_remote_service_only_device_no_domain() { - String uri = "//VCU"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isEmpty()); - assertTrue(Uri.uEntity().isEmpty()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service only device and domain") - public void test_parse_protocol_uri_with_remote_service_only_device_and_domain() { - String uri = "//VCU.MY_CAR_VIN"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertTrue(Uri.uEntity().isEmpty()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service only device and cloud domain") - public void test_parse_protocol_uri_with_remote_service_only_device_and_cloud_domain() { - String uri = "//cloud.uprotocol.example.com"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("cloud", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("uprotocol.example.com", Uri.uAuthority().domain().get()); - assertTrue(Uri.uEntity().isEmpty()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service no version") - public void test_parse_protocol_uri_with_remote_service_no_version() { - String uri = "//VCU.MY_CAR_VIN/body.access"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote cloud service no version") - public void test_parse_protocol_uri_with_remote_cloud_service_no_version() { - String uri = "//cloud.uprotocol.example.com/body.access"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("cloud", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("uprotocol.example.com", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service with version") - public void test_parse_protocol_uri_with_remote_service_with_version() { - String uri = "//VCU.MY_CAR_VIN/body.access/1"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote cloud service with version") - public void test_parse_protocol_uri_with_remote_cloud_service_with_version() { - String uri = "//cloud.uprotocol.example.com/body.access/1"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("cloud", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("uprotocol.example.com", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertTrue(Uri.uResource().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service no version with resource name only") - public void test_parse_protocol_uri_with_remote_service_no_version_with_resource_name_only() { - String uri = "//VCU.MY_CAR_VIN/body.access//door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isEmpty()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote cloud service no version with resource name only") - public void test_parse_protocol_uri_with_remote_cloud_service_no_version_with_resource_name_only() { - String uri = "//cloud.uprotocol.example.com/body.access//door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("cloud", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("uprotocol.example.com", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isEmpty()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service with version with resource name only") - public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_name_only() { - String uri = "//VCU.MY_CAR_VIN/body.access/1/door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isEmpty()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote cloud service with version with resource name only") - public void test_parse_protocol_uri_with_remote_service_cloud_with_version_with_resource_name_only() { - String uri = "//cloud.uprotocol.example.com/body.access/1/door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("cloud", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("uprotocol.example.com", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isEmpty()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service no version with resource and instance no message") - public void test_parse_protocol_uri_with_remote_service_no_version_with_resource_and_instance_no_message() { - String uri = "//VCU.MY_CAR_VIN/body.access//door.front_left"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service with version with resource and instance no message") - public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_and_instance_no_message() { - String uri = "//VCU.MY_CAR_VIN/body.access/1/door.front_left"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service no version with resource and instance and message") - public void test_parse_protocol_uri_with_remote_service_no_version_with_resource_and_instance_and_message() { - String uri = "//VCU.MY_CAR_VIN/body.access//door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote cloud service no version with resource and instance and message") - public void test_parse_protocol_uri_with_remote_cloud_service_no_version_with_resource_and_instance_and_message() { - String uri = "//cloud.uprotocol.example.com/body.access//door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("cloud", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("uprotocol.example.com", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service with version with resource and instance and message") - public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_and_instance_and_message() { - String uri = "//VCU.MY_CAR_VIN/body.access/1/door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("my_car_vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote cloud service with version with resource and instance and message") - public void test_parse_protocol_uri_with_remote_cloud_service_with_version_with_resource_and_instance_and_message() { - String uri = "//cloud.uprotocol.example.com/body.access/1/door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("cloud", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("uprotocol.example.com", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - } - - @Test - @DisplayName("Test parse uProtocol uri with remote service with version with resource with message when there is only device, no domain") - public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_with_message_device_no_domain() { - String uri = "//VCU/body.access/1/door.front_left"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isEmpty()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol RPC uri with remote service no version") - public void test_parse_protocol_rpc_uri_with_remote_service_no_version() { - String uri = "//bo.cloud/petapp//rpc.response"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("bo", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("cloud", Uri.uAuthority().domain().get()); - assertEquals("petapp", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("rpc", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("response", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test parse uProtocol RPC uri with remote service with version") - public void test_parse_protocol_rpc_uri_with_remote_service_with_version() { - String uri = "//bo.cloud/petapp/1/rpc.response"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isRemote()); - assertTrue(Uri.uAuthority().device().isPresent()); - assertEquals("bo", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("cloud", Uri.uAuthority().domain().get()); - assertEquals("petapp", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isPresent()); - assertEquals("1", Uri.uEntity().version().get()); - assertEquals("rpc", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("response", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isEmpty()); - } - - @Test - @DisplayName("Test Create a uProtocol URI from null") - public void test_build_protocol_uri_from__uri_when__uri_isnull() { - String uProtocolUri = UriFactory.buildUProtocolUri(null); - assertEquals("", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an empty URI Object") - public void test_build_protocol_uri_from__uri_when__uri_isEmpty() { - UUri Uri = UUri.empty(); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI object with an empty USE") - public void test_build_protocol_uri_from__uri_when__uri_has_empty_use() { - UEntity use = UEntity.empty(); - UUri Uri = new UUri(UAuthority.local(), use, UResource.fromName("door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, UResource.empty()); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.local(), use, UResource.empty()); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access/1", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version with resource") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version_with_resource() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, UResource.fromName("door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access//door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version with resource") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version_with_resource() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.local(), use, UResource.fromName("door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access/1/door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version with resource with instance no message") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version_with_resource_with_instance_no_message() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, UResource.fromNameWithInstance("door", "front_left")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access//door.front_left", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version with resource with instance no message") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version_with_resource_with_instance_no_message() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.local(), use, UResource.fromNameWithInstance("door", "front_left")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access/1/door.front_left", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version with resource with instance and message") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version_with_resource_with_instance_with_message() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.local(), use, new UResource("door", "front_left", "Door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access//door.front_left#Door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version with resource with instance and message") - public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version_with_resource_with_instance_with_message() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.local(), use, new UResource("door", "front_left", "Door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("/body.access/1/door.front_left#Door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service no version") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, UResource.empty()); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority no device with domain with service no version") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_no_device_with_domain_with_service_no_version() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.remote("", "MY_CAR_VIN"), use, UResource.empty()); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//my_car_vin/body.access", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service and version") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, UResource.empty()); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access/1", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote cloud authority with service and version") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_cloud_authority_service_and_version() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.remote("cloud", "uprotocol.example.com"), use, UResource.empty()); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//cloud.uprotocol.example.com/body.access/1", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service and version with resource") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version_with_resource() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, UResource.fromName("door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access/1/door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service no version with resource") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version_with_resource() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, UResource.fromName("door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access//door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service and version with resource with instance no message") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version_with_resource_with_instance_no_message() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, UResource.fromNameWithInstance("door", "front_left")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access/1/door.front_left", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote cloud authority with service and version with resource with instance no message") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_cloud_authority_service_and_version_with_resource_with_instance_no_message() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.remote("cloud", "uprotocol.example.com"), use, UResource.fromNameWithInstance("door", "front_left")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//cloud.uprotocol.example.com/body.access/1/door.front_left", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service no version with resource with instance no message") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version_with_resource_with_instance_no_message() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, UResource.fromNameWithInstance("door", "front_left")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access//door.front_left", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service and version with resource with instance and message") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version_with_resource_with_instance_and_message() { - UEntity use = new UEntity("body.access", "1"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, new UResource("door", "front_left", "Door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access/1/door.front_left#Door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from an URI Object with a remote authority with service no version with resource with instance and message") - public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version_with_resource_with_instance_and_message() { - UEntity use = UEntity.fromName("body.access"); - UUri Uri = new UUri(UAuthority.remote("VCU", "MY_CAR_VIN"), use, new UResource("door", "front_left", "Door")); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("//vcu.my_car_vin/body.access//door.front_left#Door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the source part of an RPC request, where the source is local") - public void test_build_protocol_uri_for_source_part_of_rpc_request_where_source_is_local() { - UAuthority uAuthority = UAuthority.local(); - UEntity use = new UEntity("petapp", "1"); - String uProtocolUri = UriFactory.buildUriForRpc(uAuthority, use); - assertEquals("/petapp/1/rpc.response", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the source part of an RPC request, where the source is remote") - public void test_build_protocol_uri_for_source_part_of_rpc_request_where_source_is_remote() { - UAuthority uAuthority = UAuthority.remote("cloud", "uprotocol.example.com"); - UEntity use = UEntity.fromName("petapp"); - String uProtocolUri = UriFactory.buildUriForRpc(uAuthority, use); - assertEquals("//cloud.uprotocol.example.com/petapp//rpc.response", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the service accepting the rpc, when authority is local with software entity no version") - public void test_build_protocol_uri_for_service_accepting_rpc_local_uauthority_with_use_no_version() { - UAuthority uAuthority = UAuthority.local(); - UEntity use = UEntity.fromName("body.access"); - String methodName = "UpdateDoor"; - String uProtocolUri = UriFactory.buildMethodUri(uAuthority, use, methodName); - assertEquals("/body.access//rpc.UpdateDoor", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the service accepting the rpc, when authority is local with software entity with version") - public void test_build_protocol_uri_for_service_accepting_rpc_local_uauthority_with_use_with_version() { - UAuthority uAuthority = UAuthority.local(); - UEntity use = new UEntity("body.access", "1"); - String methodName = "UpdateDoor"; - String uProtocolUri = UriFactory.buildMethodUri(uAuthority, use, methodName); - assertEquals("/body.access/1/rpc.UpdateDoor", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the service accepting the rpc, when authority is local, software entity is empty") - public void test_build_protocol_uri_for_service_accepting_rpc_local_uauthority_empty_use() { - UAuthority uAuthority = UAuthority.local(); - UEntity use = UEntity.fromName(" "); - String methodName = "UpdateDoor"; - String uProtocolUri = UriFactory.buildMethodUri(uAuthority, use, methodName); - assertEquals("///rpc.UpdateDoor", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the service accepting the rpc, when authority is remote with software entity no version") - public void test_build_protocol_uri_for_service_accepting_rpc_remote_uauthority_with_use_no_version() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = UEntity.fromName("body.access"); - String methodName = "UpdateDoor"; - String uProtocolUri = UriFactory.buildMethodUri(uAuthority, use, methodName); - assertEquals("//vcu.my_vin/body.access//rpc.UpdateDoor", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the service accepting the rpc, when authority is remote with software entity with version") - public void test_build_protocol_uri_for_service_accepting_rpc_remote_uauthority_with_use_with_version() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = new UEntity("body.access", "1"); - String methodName = "UpdateDoor"; - String uProtocolUri = UriFactory.buildMethodUri(uAuthority, use, methodName); - assertEquals("//vcu.my_vin/body.access/1/rpc.UpdateDoor", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the service accepting the rpc, when authority is remote cloud with software entity with version") - public void test_build_protocol_uri_for_service_accepting_rpc_remote_cloud_uauthority_with_use_with_version() { - UAuthority uAuthority = UAuthority.remote("cloud", "uprotocol.example.com"); - UEntity use = new UEntity("body.access", "1"); - String methodName = "UpdateDoor"; - String uProtocolUri = UriFactory.buildMethodUri(uAuthority, use, methodName); - assertEquals("//cloud.uprotocol.example.com/body.access/1/rpc.UpdateDoor", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI for the service accepting the rpc, when authority is remote, software entity is empty") - public void test_build_protocol_uri_for_service_accepting_rpc_remote_uauthority_empty_use() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_VIN"); - UEntity use = UEntity.fromName(" "); - String methodName = "UpdateDoor"; - String uProtocolUri = UriFactory.buildMethodUri(uAuthority, use, methodName); - assertEquals("//vcu.my_vin///rpc.UpdateDoor", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from parts that are null") - public void test_build_protocol_uri_from_parts_when_they_are_null() { - UAuthority uAuthority = null; - UEntity uSoftwareEntity = null; - UResource uResource = null; - UUri Uri = new UUri(uAuthority, uSoftwareEntity, uResource); - String uProtocolUri = UriFactory.buildUProtocolUri(Uri); - assertEquals("", uProtocolUri); - } - - @Test - @DisplayName("Test Create a uProtocol URI from the parts of URI Object with a remote authority with service and version with resource") - public void test_build_protocol_uri_from__uri_parts_when__uri_has_remote_authority_service_and_version_with_resource() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_CAR_VIN"); - UEntity use = new UEntity("body.access", "1"); - UResource uResource = UResource.fromName("door"); - String uProtocolUri = UriFactory.buildUProtocolUri(uAuthority, use, uResource); - assertEquals("//vcu.my_car_vin/body.access/1/door", uProtocolUri); - } - - @Test - @DisplayName("Test Create a URI using no scheme") - public void test_custom_scheme_no_scheme_empty() { - UAuthority uAuthority = null; - UEntity uSoftwareEntity = null; - UResource uResource = null; - String customUri = UriFactory.buildUProtocolUri(uAuthority, uSoftwareEntity, uResource); - assertTrue(customUri.isEmpty()); - } - - @Test - @DisplayName("Test Create a custom URI using no scheme") - public void test_custom_scheme_no_scheme() { - UAuthority uAuthority = UAuthority.remote("VCU", "MY_CAR_VIN"); - UEntity use = new UEntity("body.access", "1"); - UResource uResource = UResource.fromName("door"); - String ucustomUri = UriFactory.buildUProtocolUri(uAuthority, use, uResource); - assertEquals("//vcu.my_car_vin/body.access/1/door", ucustomUri); - } - - @Test - @DisplayName("Test parse local uProtocol uri with custom scheme") - public void test_parse_local_protocol_uri_with_custom_scheme() { - String uri = "custom:/body.access//door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertTrue(Uri.uAuthority().isLocal()); - assertFalse(Uri.uAuthority().isMarkedRemote()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - } - - @Test - @DisplayName("Test parse remote uProtocol uri with custom scheme") - public void test_parse_remote_protocol_uri_with_custom_scheme() { - String uri = "custom://vcu.vin/body.access//door.front_left#Door"; - String uri2 = "//vcu.vin/body.access//door.front_left#Door"; - UUri Uri = UriFactory.parseFromUri(uri); - assertFalse(Uri.uAuthority().isLocal()); - assertTrue(Uri.uAuthority().isMarkedRemote()); - assertEquals("vcu", Uri.uAuthority().device().get()); - assertTrue(Uri.uAuthority().domain().isPresent()); - assertEquals("vin", Uri.uAuthority().domain().get()); - assertEquals("body.access", Uri.uEntity().name()); - assertTrue(Uri.uEntity().version().isEmpty()); - assertEquals("door", Uri.uResource().name()); - assertTrue(Uri.uResource().instance().isPresent()); - assertEquals("front_left", Uri.uResource().instance().get()); - assertTrue(Uri.uResource().message().isPresent()); - assertEquals("Door", Uri.uResource().message().get()); - assertEquals(uri2, Uri.uProtocolUri()); - } -} \ No newline at end of file diff --git a/src/test/java/org/eclipse/uprotocol/uri/serializer/LongUriSerializerTest.java b/src/test/java/org/eclipse/uprotocol/uri/serializer/LongUriSerializerTest.java new file mode 100644 index 00000000..2d49db12 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/uri/serializer/LongUriSerializerTest.java @@ -0,0 +1,1006 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.uri.serializer; + +import org.eclipse.uprotocol.uri.builder.UResourceBuilder; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UUri; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + + +public class LongUriSerializerTest { + + @Test + @DisplayName("Test using the serializers") + public void test_using_the_serializers() { + final UUri uri = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("hartley")) + .setResource(UResourceBuilder.forRpcRequest("raise")) + .build(); + final String strUri = LongUriSerializer.instance().serialize(uri); + assertEquals("/hartley//rpc.raise", strUri); + final UUri uri2 = LongUriSerializer.instance().deserialize(strUri); + assertEquals(uri, uri2); + } +/* + @Test + @DisplayName("Test parse uProtocol uri that is null") + public void test_parse_protocol_uri_when_is_null() { + UUri uri = LongUriSerializer.instance().deserialize(null); + assertTrue(uri.isEmpty()); + assertFalse(uri.isResolved()); + assertTrue(uri.isLongForm()); + } + + @Test + @DisplayName("Test parse uProtocol uri that is empty string") + public void test_parse_protocol_uri_when_is_empty_string() { + String uri = ""; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.isEmpty()); + + String uri2 = LongUriSerializer.instance().serialize(null); + assertTrue(uri2.isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with schema and slash") + public void test_parse_protocol_uri_with_schema_and_slash() { + String uri = "/"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertTrue(Uri.isEmpty()); + + String uri2 = LongUriSerializer.instance().serialize(UUri.empty()); + assertTrue(uri2.isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with schema and double slash") + public void test_parse_protocol_uri_with_schema_and_double_slash() { + String uri = "//"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertFalse(Uri.getAuthority().isLocal()); + assertTrue(!Uri.getAuthority().getLocal()); + assertTrue(Uri.isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with schema and 3 slash and something") + public void test_parse_protocol_uri_with_schema_and_3_slash_and_something() { + String uri = "///body.access"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertFalse(Uri.getAuthority().isLocal()); + assertTrue(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with schema and 4 slash and something") + public void test_parse_protocol_uri_with_schema_and_4_slash_and_something() { + String uri = "////body.access"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertFalse(Uri.getAuthority().isLocal()); + assertTrue(!Uri.getAuthority().getLocal()); + assertTrue(Uri.getEntity().getName().isBlank()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with schema and 5 slash and something") + public void test_parse_protocol_uri_with_schema_and_5_slash_and_something() { + String uri = "/////body.access"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertFalse(Uri.getAuthority().isLocal()); + assertTrue(!Uri.getAuthority().getLocal()); + assertTrue(Uri.getEntity().isEmpty()); + assertEquals("body", Uri.getResource().getName()); + assertEquals("access", Uri.getResource().instance().orElse("")); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with schema and 6 slash and something") + public void test_parse_protocol_uri_with_schema_and_6_slash_and_something() { + String uri = "//////body.access"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertFalse(Uri.getAuthority().isLocal()); + assertTrue(!Uri.getAuthority().getLocal()); + assertTrue(Uri.isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service no version") + public void test_parse_protocol_uri_with_local_service_no_version() { + String uri = "/body.access"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service with version") + public void test_parse_protocol_uri_with_local_service_with_version() { + String uri = "/body.access/1"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertEquals(1, Uri.getEntity().version().orElse(10)); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service no version with resource name only") + public void test_parse_protocol_uri_with_local_service_no_version_with_resource_name_only() { + String uri = "/body.access//door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isEmpty()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service with version with resource name only") + public void test_parse_protocol_uri_with_local_service_with_version_with_resource_name_only() { + String uri = "/body.access/1/door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertEquals(1, Uri.getEntity().version().orElse(10)); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isEmpty()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service no version with resource and instance only") + public void test_parse_protocol_uri_with_local_service_no_version_with_resource_with_instance() { + String uri = "/body.access//door.front_left"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service with version with resource and instance only") + public void test_parse_protocol_uri_with_local_service_with_version_with_resource_with_getMessage() { + String uri = "/body.access/1/door.front_left"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service no version with resource with instance and message") + public void test_parse_protocol_uri_with_local_service_no_version_with_resource_with_instance_and_getMessage() { + String uri = "/body.access//door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isPresent()); + assertEquals("Door", Uri.getResource().getMessage().get()); + } + + @Test + @DisplayName("Test parse uProtocol uri with local service with version with resource with instance and message") + public void test_parse_protocol_uri_with_local_service_with_version_with_resource_with_instance_and_getMessage() { + String uri = "/body.access/1/door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isPresent()); + assertEquals("Door", Uri.getResource().getMessage().get()); + } + + @Test + @DisplayName("Test parse uProtocol RPC uri with local service no version") + public void test_parse_protocol_rpc_uri_with_local_service_no_version() { + String uri = "/petapp//rpc.response"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("petapp", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("rpc", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("response", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol RPC uri with local service with version") + public void test_parse_protocol_rpc_uri_with_local_service_with_version() { + String uri = "/petapp/1/rpc.response"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("petapp", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("rpc", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("response", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service only device no domain") + public void test_parse_protocol_uri_with_remote_service_only_device_no_domain() { + String uri = "//VCU"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isEmpty()); + assertTrue(Uri.getEntity().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service only device and domain") + public void test_parse_protocol_uri_with_remote_service_only_device_and_domain() { + String uri = "//VCU.MY_CAR_VIN"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertTrue(Uri.getEntity().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service only device and cloud domain") + public void test_parse_protocol_uri_with_remote_service_only_device_and_cloud_domain() { + String uri = "//cloud.uprotocol.example.com"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("cloud", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("uprotocol.example.com", Uri.getAuthority().domain().get()); + assertTrue(Uri.getEntity().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service no version") + public void test_parse_protocol_uri_with_remote_service_no_version() { + String uri = "//VCU.MY_CAR_VIN/body.access"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote cloud service no version") + public void test_parse_protocol_uri_with_remote_cloud_service_no_version() { + String uri = "//cloud.uprotocol.example.com/body.access"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("cloud", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("uprotocol.example.com", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service with version") + public void test_parse_protocol_uri_with_remote_service_with_version() { + String uri = "//VCU.MY_CAR_VIN/body.access/1"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote cloud service with version") + public void test_parse_protocol_uri_with_remote_cloud_service_with_version() { + String uri = "//cloud.uprotocol.example.com/body.access/1"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("cloud", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("uprotocol.example.com", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertTrue(Uri.getResource().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service no version with resource name only") + public void test_parse_protocol_uri_with_remote_service_no_version_with_resource_name_only() { + String uri = "//VCU.MY_CAR_VIN/body.access//door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isEmpty()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote cloud service no version with resource name only") + public void test_parse_protocol_uri_with_remote_cloud_service_no_version_with_resource_name_only() { + String uri = "//cloud.uprotocol.example.com/body.access//door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("cloud", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("uprotocol.example.com", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isEmpty()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service with version with resource name only") + public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_name_only() { + String uri = "//VCU.MY_CAR_VIN/body.access/1/door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isEmpty()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote cloud service with version with resource name only") + public void test_parse_protocol_uri_with_remote_service_cloud_with_version_with_resource_name_only() { + String uri = "//cloud.uprotocol.example.com/body.access/1/door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("cloud", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("uprotocol.example.com", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isEmpty()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service no version with resource and instance no message") + public void test_parse_protocol_uri_with_remote_service_no_version_with_resource_and_instance_no_getMessage() { + String uri = "//VCU.MY_CAR_VIN/body.access//door.front_left"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service with version with resource and instance no message") + public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_and_instance_no_getMessage() { + String uri = "//VCU.MY_CAR_VIN/body.access/1/door.front_left"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service no version with resource and instance and message") + public void test_parse_protocol_uri_with_remote_service_no_version_with_resource_and_instance_and_getMessage() { + String uri = "//VCU.MY_CAR_VIN/body.access//door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isPresent()); + assertEquals("Door", Uri.getResource().getMessage().get()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote cloud service no version with resource and instance and message") + public void test_parse_protocol_uri_with_remote_cloud_service_no_version_with_resource_and_instance_and_getMessage() { + String uri = "//cloud.uprotocol.example.com/body.access//door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("cloud", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("uprotocol.example.com", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isPresent()); + assertEquals("Door", Uri.getResource().getMessage().get()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service with version with resource and instance and message") + public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_and_instance_and_getMessage() { + String uri = "//VCU.MY_CAR_VIN/body.access/1/door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("my_car_vin", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isPresent()); + assertEquals("Door", Uri.getResource().getMessage().get()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote cloud service with version with resource and instance and message") + public void test_parse_protocol_uri_with_remote_cloud_service_with_version_with_resource_and_instance_and_getMessage() { + String uri = "//cloud.uprotocol.example.com/body.access/1/door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("cloud", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("uprotocol.example.com", Uri.getAuthority().domain().get()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isPresent()); + assertEquals("Door", Uri.getResource().getMessage().get()); + } + + @Test + @DisplayName("Test parse uProtocol uri with microRemote service with version with resource with message when there is only device, no domain") + public void test_parse_protocol_uri_with_remote_service_with_version_with_resource_with_message_device_no_domain() { + String uri = "//VCU/body.access/1/door.front_left"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("vcu", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isEmpty()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol RPC uri with microRemote service no version") + public void test_parse_protocol_rpc_uri_with_remote_service_no_version() { + String uri = "//bo.cloud/petapp//rpc.response"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("bo", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("cloud", Uri.getAuthority().domain().get()); + assertEquals("petapp", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("rpc", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("response", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test parse uProtocol RPC uri with microRemote service with version") + public void test_parse_protocol_rpc_uri_with_remote_service_with_version() { + String uri = "//bo.cloud/petapp/1/rpc.response"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isRemote()); + assertTrue(Uri.getAuthority().getName().isPresent()); + assertEquals("bo", Uri.getAuthority().getName().get()); + assertTrue(Uri.getAuthority().domain().isPresent()); + assertEquals("cloud", Uri.getAuthority().domain().get()); + assertEquals("petapp", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isPresent()); + assertEquals(1, Uri.getEntity().version().get()); + assertEquals("rpc", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("response", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isEmpty()); + } + + @Test + @DisplayName("Test Create a uProtocol URI from null") + public void test_build_protocol_uri_from__uri_when__uri_isnull() { + String uProtocolUri = LongUriSerializer.instance().serialize(null); + assertEquals("", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an empty URI Object") + public void test_build_protocol_uri_from__uri_when__uri_isEmpty() { + UUri Uri = UUri.empty(); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI object with an empty USE") + public void test_build_protocol_uri_from__uri_when__uri_has_empty_use() { + UEntity use = UEntity.empty(); + UUri Uri = new UUri(UAuthority.local(), use, UResource.longFormat("door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.local(), use, UResource.empty()); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.local(), use, UResource.empty()); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access/1", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version with resource") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version_with_resource() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.local(), use, UResource.longFormat("door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access//door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version with resource") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version_with_resource() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.local(), use, UResource.longFormat("door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access/1/door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version with resource with instance no message") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version_with_resource_with_instance_no_getMessage() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.local(), use, UResource.longFormat("door", "front_left", null)); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access//door.front_left", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version with resource with instance no message") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version_with_resource_with_instance_no_getMessage() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.local(), use, UResource.longFormat("door", "front_left", null)); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access/1/door.front_left", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service no version with resource with instance and message") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version_with_resource_with_instance_with_getMessage() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.local(), use, UResource.longFormat("door", "front_left", "Door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access//door.front_left#Door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a local authority with service and version with resource with instance and message") + public void test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_and_version_with_resource_with_instance_with_getMessage() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.local(), use, UResource.longFormat("door", "front_left", "Door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("/body.access/1/door.front_left#Door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service no version") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.empty()); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority no device with domain with service no version") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_no_device_with_domain_with_service_no_version() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.longRemote("", "MY_CAR_VIN"), use, UResource.empty()); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//my_car_vin/body.access", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service and version") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.empty()); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access/1", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote cloud authority with service and version") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_cloud_authority_service_and_version() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.longRemote("cloud", "uprotocol.example.com"), use, UResource.empty()); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//cloud.uprotocol.example.com/body.access/1", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service and version with resource") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version_with_resource() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.longFormat("door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access/1/door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service no version with resource") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version_with_resource() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.longFormat("door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access//door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service and version with resource with instance no message") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version_with_resource_with_instance_no_getMessage() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.longFormat("door", "front_left", null)); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access/1/door.front_left", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote cloud authority with service and version with resource with instance no message") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_cloud_authority_service_and_version_with_resource_with_instance_no_getMessage() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.longRemote("cloud", "uprotocol.example.com"), use, UResource.longFormat("door", "front_left", null)); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//cloud.uprotocol.example.com/body.access/1/door.front_left", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service no version with resource with instance no message") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version_with_resource_with_instance_no_getMessage() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.longFormat("door", "front_left", null)); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access//door.front_left", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service and version with resource with instance and message") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_and_version_with_resource_with_instance_and_getMessage() { + UEntity use = UEntity.longFormat("body.access", 1); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.longFormat("door", "front_left", "Door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access/1/door.front_left#Door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from an URI Object with a microRemote authority with service no version with resource with instance and message") + public void test_build_protocol_uri_from__uri_when__uri_has_remote_authority_service_no_version_with_resource_with_instance_and_getMessage() { + UEntity use = UEntity.longFormat("body.access"); + UUri Uri = new UUri(UAuthority.longRemote("VCU", "MY_CAR_VIN"), use, UResource.longFormat("door", "front_left", "Door")); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("//vcu.my_car_vin/body.access//door.front_left#Door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI for the source part of an RPC request, where the source is local") + public void test_build_protocol_uri_for_source_part_of_rpc_request_where_source_is_local() { + UAuthority uAuthority = UAuthority.local(); + UEntity use = UEntity.longFormat("petapp", 1); + String uProtocolUri = LongUriSerializer.instance().serialize(UUri.rpcResponse(uAuthority, use)); + assertEquals("/petapp/1/rpc.response", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI for the source part of an RPC request, where the source is microRemote") + public void test_build_protocol_uri_for_source_part_of_rpc_request_where_source_is_remote() { + UAuthority uAuthority = UAuthority.longRemote("cloud", "uprotocol.example.com"); + UEntity use = UEntity.longFormat("petapp"); + String uProtocolUri = LongUriSerializer.instance().serialize(UUri.rpcResponse(uAuthority, use)); + assertEquals("//cloud.uprotocol.example.com/petapp//rpc.response", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from parts that are null") + public void test_build_protocol_uri_from_parts_when_they_are_null() { + UAuthority uAuthority = null; + UEntity uSoftwareEntity = null; + UResource uResource = null; + UUri Uri = new UUri(uAuthority, uSoftwareEntity, uResource); + String uProtocolUri = LongUriSerializer.instance().serialize(Uri); + assertEquals("", uProtocolUri); + } + + @Test + @DisplayName("Test Create a uProtocol URI from the parts of URI Object with a microRemote authority with service and version with resource") + public void test_build_protocol_uri_from__uri_parts_when__uri_has_remote_authority_service_and_version_with_resource() { + UAuthority uAuthority = UAuthority.longRemote("VCU", "MY_CAR_VIN"); + UEntity use = UEntity.longFormat("body.access", 1); + UResource uResource = UResource.longFormat("door"); + String uProtocolUri = LongUriSerializer.instance().serialize(new UUri(uAuthority, use, uResource)); + assertEquals("//vcu.my_car_vin/body.access/1/door", uProtocolUri); + } + + @Test + @DisplayName("Test Create a URI using no scheme") + public void test_custom_scheme_no_scheme_empty() { + UAuthority uAuthority = null; + UEntity uSoftwareEntity = null; + UResource uResource = null; + String customUri = LongUriSerializer.instance().serialize(new UUri(uAuthority, uSoftwareEntity, uResource)); + assertTrue(customUri.isEmpty()); + } + + @Test + @DisplayName("Test Create a custom URI using no scheme") + public void test_custom_scheme_no_scheme() { + UAuthority uAuthority = UAuthority.longRemote("VCU", "MY_CAR_VIN"); + UEntity use = UEntity.longFormat("body.access", 1); + UResource uResource = UResource.longFormat("door"); + String ucustomUri = LongUriSerializer.instance().serialize(new UUri(uAuthority, use, uResource)); + assertEquals("//vcu.my_car_vin/body.access/1/door", ucustomUri); + } + + @Test + @DisplayName("Test parse local uProtocol uri with custom scheme") + public void test_parse_local_protocol_uri_with_custom_scheme() { + String uri = "custom:/body.access//door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertTrue(Uri.getAuthority().isLocal()); + assertFalse(!Uri.getAuthority().getLocal()); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertTrue(Uri.getResource().instance().isPresent()); + assertEquals("front_left", Uri.getResource().instance().get()); + assertTrue(Uri.getResource().getMessage().isPresent()); + assertEquals("Door", Uri.getResource().getMessage().get()); + } + + @Test + @DisplayName("Test parse microRemote uProtocol uri with custom scheme") + public void test_parse_remote_protocol_uri_with_custom_scheme() { + String uri = "custom://vcu.vin/body.access//door.front_left#Door"; + String uri2 = "//vcu.vin/body.access//door.front_left#Door"; + UUri Uri = LongUriSerializer.instance().deserialize(uri); + assertFalse(Uri.getAuthority().isLocal()); + assertTrue(!Uri.getAuthority().getLocal()); + assertEquals("vcu", Uri.getAuthority().getName().orElse("")); + assertEquals("vin", Uri.getAuthority().domain().orElse("")); + assertEquals("body.access", Uri.getEntity().getName()); + assertTrue(Uri.getEntity().version().isEmpty()); + assertEquals("door", Uri.getResource().getName()); + assertEquals("front_left", Uri.getResource().instance().orElse("")); + assertEquals("Door", Uri.getResource().getMessage().orElse("")); + assertEquals(uri2, LongUriSerializer.instance().serialize(Uri)); + } + + @Test + @DisplayName("Test build resolved uri passing null") + void test_deserialize_long_and_micro_passing_null() { + Optional uri = LongUriSerializer.instance().buildResolved(null, null); + assertTrue(uri.isPresent()); + assertTrue(uri.get().isEmpty()); + } + + @Test + @DisplayName("Test build resolved uri passing null long uri empty byte array") + void test_deserialize_long_and_micro_passing_null_long_uri_empty_byte_array() { + Optional uri = LongUriSerializer.instance().buildResolved(null, new byte[0]); + assertTrue(uri.isPresent()); + assertTrue(uri.get().isEmpty()); + } + + @Test + @DisplayName("Test build resolved uri passing empty long uri null byte array") + void test_deserialize_long_and_micro_passing_nullempty_long_uri_null_byte_array() { + Optional uri = LongUriSerializer.instance().buildResolved("", null); + assertTrue(uri.isPresent()); + assertTrue(uri.get().isEmpty()); + } + + @Test + @DisplayName("Test build resolved uri passing empty long uri, empty byte[]") + void test_deserialize_long_and_micro_passing_empty_long_uri_empty_byte_array() { + Optional uri = LongUriSerializer.instance().buildResolved("", new byte[0]); + assertTrue(uri.isPresent()); + assertTrue(uri.get().isEmpty()); + } + + @Test + @DisplayName("Test deserializer a long and micro uri passing UAuthority of different types (local vs remote)") + void test_deserialize_long_and_micro_passing_UAuthority_that_doesnt_match() { + String longUUri = "//vcu.vin/body.access//door.front_left#Door"; + byte[] microUUri = new byte[] {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + Optional uri = LongUriSerializer.instance().buildResolved(longUUri, microUUri); + assertTrue(uri.isEmpty()); + + String longUUri1 = "/body.access//door.front_left#Door"; + byte[] microUUri1 = new byte[] {0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + Optional uri1 = LongUriSerializer.instance().buildResolved(longUUri1, microUUri1); + assertTrue(uri1.isEmpty()); + } + + @Test + @DisplayName("Test deserializer a long and micro uri passing invalid values") + void test_deserialize_long_and_micro_passing_invalid_values() { + String goodLongUUri = "/body.access//door.front_left#Door"; + byte[] goodMicroUUri = new byte[] {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + String badLongUUri = "///"; + byte[] badMicroUUri = new byte[] {0x0, 0x0, 0x0, 0x0, 0x0}; + Optional uri = LongUriSerializer.instance().buildResolved(goodLongUUri, goodMicroUUri); + assertFalse(uri.isEmpty()); + Optional uri2 = LongUriSerializer.instance().buildResolved(goodLongUUri, badMicroUUri); + assertTrue(uri2.isEmpty()); + Optional uri3 = LongUriSerializer.instance().buildResolved(badLongUUri, goodMicroUUri); + assertTrue(uri3.isEmpty()); + Optional uri4 = LongUriSerializer.instance().buildResolved(badLongUUri, badMicroUUri); + assertTrue(uri4.isEmpty()); + Optional uri5 = LongUriSerializer.instance().buildResolved("", goodMicroUUri); + assertTrue(uri5.isEmpty()); + Optional uri6 = LongUriSerializer.instance().buildResolved("", badMicroUUri); + assertTrue(uri6.isEmpty()); + Optional uri7 = LongUriSerializer.instance().buildResolved(null, goodMicroUUri); + assertTrue(uri7.isEmpty()); + Optional uri8 = LongUriSerializer.instance().buildResolved(null, badMicroUUri); + assertTrue(uri8.isEmpty()); + + + Optional uri9 = LongUriSerializer.instance().buildResolved(goodLongUUri, null); + assertTrue(uri9.isEmpty()); + Optional uri10 = LongUriSerializer.instance().buildResolved(goodLongUUri, new byte[0]); + assertTrue(uri10.isEmpty()); + + } + + @Test + @DisplayName("Test deserializer a long and micro uri passing valid values") + void test_deserialize_long_and_micro_passing_valid_values() throws UnknownHostException { + UUri uri = new UUri(UAuthority.resolvedRemote("vcu", "vin", InetAddress.getByName("192.168.1.100")), + UEntity.resolvedFormat("hartley", 1, (short)5), + UResource.resolvedFormat("raise", "salary", "Pay", (short)2)); + String longUUri = LongUriSerializer.instance().serialize(uri); + byte[] microUUri = MicroUriSerializer.instance().serialize(uri); + + Optional uri2 = LongUriSerializer.instance().buildResolved(longUUri, microUUri); + assertEquals(uri, uri2.orElse(UUri.empty())); + } + */ +} diff --git a/src/test/java/org/eclipse/uprotocol/uri/serializer/MicroUriSerializerTest.java b/src/test/java/org/eclipse/uprotocol/uri/serializer/MicroUriSerializerTest.java new file mode 100644 index 00000000..a56f2cfa --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/uri/serializer/MicroUriSerializerTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.eclipse.uprotocol.uri.serializer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Base64; + +import org.eclipse.uprotocol.uri.builder.UResourceBuilder; +import org.eclipse.uprotocol.uri.validator.UriValidator; +import org.eclipse.uprotocol.v1.UAuthority; +import org.eclipse.uprotocol.v1.UEntity; +import org.eclipse.uprotocol.v1.UResource; +import org.eclipse.uprotocol.v1.UUri; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.annotation.Testable; + +public class MicroUriSerializerTest + { + + + @Test + @DisplayName("Test serialize and deserialize empty content") + public void test_empty() { + + byte[] bytes = MicroUriSerializer.instance().serialize(UUri.getDefaultInstance()); + + assertEquals(bytes.length, 0); + + UUri uri2 = MicroUriSerializer.instance().deserialize(bytes); + assertTrue(UriValidator.isEmpty(uri2)); + } + + @Test + @DisplayName("Test serialize and deserialize null content") + public void test_null() { + byte[] bytes = MicroUriSerializer.instance().serialize(null); + + assertEquals(bytes.length, 0); + + UUri uri2 = MicroUriSerializer.instance().deserialize(null); + assertTrue(UriValidator.isEmpty(uri2)); + } + + @Test + @DisplayName("Test happy path Byte serialization of local UUri") + public void test_serialize_uri() { + + UUri uri = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setId(29999).setVersionMajor(254)) + .setResource(UResource.newBuilder().setId(19999)) + .build(); + + + byte[] bytes = MicroUriSerializer.instance().serialize(uri); + UUri uri2 = MicroUriSerializer.instance().deserialize(bytes); + + assertEquals(uri, uri2); + } + + @Test + @DisplayName("Test Serialize a remote UUri to micro without the address") + public void test_serialize_remote_uri_without_address() { + UUri uri = UUri.newBuilder() + .setAuthority(UAuthority.newBuilder().setName("vcu.vin")) + .setEntity(UEntity.newBuilder().setId(29999).setVersionMajor(254)) + .setResource(UResource.newBuilder().setId(19999)) + .build(); + + byte[] bytes = MicroUriSerializer.instance().serialize(uri); + assertTrue(bytes.length == 0); + } + + @Test + @DisplayName("Test serialize Uri missing uE ID") + public void test_serialize_uri_missing_ids() { + UUri uri = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("hartley")) + .setResource(UResourceBuilder.forRpcResponse()) + .build(); + + byte[] bytes = MicroUriSerializer.instance().serialize(uri); + assertTrue(bytes.length == 0); + } + + @Test + @DisplayName("Test serialize Uri missing resource") + public void test_serialize_uri_missing_resource_id() { + UUri uri = UUri.newBuilder() + .setEntity(UEntity.newBuilder().setName("hartley")) + .build(); + + byte[] bytes = MicroUriSerializer.instance().serialize(uri); + assertTrue(bytes.length == 0); + } + +} diff --git a/src/test/java/org/eclipse/uprotocol/uri/validator/UriValidatorTest.java b/src/test/java/org/eclipse/uprotocol/uri/validator/UriValidatorTest.java new file mode 100644 index 00000000..8fea4c89 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/uri/validator/UriValidatorTest.java @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2023 General Motors GTO LLC + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.eclipse.uprotocol.uri.validator; + + +import org.eclipse.uprotocol.uri.serializer.LongUriSerializer; +import org.eclipse.uprotocol.v1.UUri; +import org.eclipse.uprotocol.validation.ValidationResult; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class UriValidatorTest { + + @Test + @DisplayName("Test validate blank uri") + public void test_validate_blank_uri() { + final UUri uri = LongUriSerializer.instance().deserialize(null); + final ValidationResult status = UriValidator.validate(uri); + assertTrue(UriValidator.isEmpty(uri)); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Test validate uri with no device name") + public void test_validate_uri_with_no_entity_getName() { + final UUri uri = LongUriSerializer.instance().deserialize("//"); + final ValidationResult status = UriValidator.validate(uri); + assertTrue(UriValidator.isEmpty(uri)); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Test validate uri with uEntity") + public void test_validate_uri_with_getEntity() { + final UUri uri = LongUriSerializer.instance().deserialize("/hartley"); + final ValidationResult status = UriValidator.validate(uri); + assertEquals(ValidationResult.success(), status); + } + + @Test + @DisplayName("Test validate with malformed URI") + public void test_validate_with_malformed_uri() { + final UUri uri = LongUriSerializer.instance().deserialize("hartley"); + final ValidationResult status = UriValidator.validate(uri); + assertTrue(UriValidator.isEmpty(uri)); + assertEquals("Uri is empty.", status.getMessage()); + } + + + @Test + @DisplayName("Test validate with blank UEntity Name") + public void test_validate_with_blank_uentity_name_uri() { + final ValidationResult status = UriValidator.validate(UUri.getDefaultInstance()); + assertTrue(status.isFailure()); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Test validateRpcMethod with valid URI") + public void test_validateRpcMethod_with_valid_uri() { + final UUri uri = LongUriSerializer.instance().deserialize("/hartley//rpc.echo"); + final ValidationResult status = UriValidator.validateRpcMethod(uri); + assertEquals(ValidationResult.success(), status); + } + + @Test + @DisplayName("Test validateRpcMethod with valid URI") + public void test_validateRpcMethod_with_invalid_uri() { + final UUri uri = LongUriSerializer.instance().deserialize("/hartley/echo"); + final ValidationResult status = UriValidator.validateRpcMethod(uri); + assertTrue(status.isFailure()); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Test validateRpcMethod with malformed URI") + public void test_validateRpcMethod_with_malformed_uri() { + final UUri uri = LongUriSerializer.instance().deserialize("hartley"); + final ValidationResult status = UriValidator.validateRpcMethod(uri); + assertTrue(UriValidator.isEmpty(uri)); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Test validateRpcResponse with valid URI") + public void test_validateRpcResponse_with_valid_uri() { + final UUri uri = LongUriSerializer.instance().deserialize("/hartley//rpc.response"); + final ValidationResult status = UriValidator.validateRpcResponse(uri); + assertEquals(ValidationResult.success(), status); + } + + @Test + @DisplayName("Test validateRpcResponse with malformed URI") + public void test_validateRpcResponse_with_malformed_uri() { + final UUri uri = LongUriSerializer.instance().deserialize("hartley"); + final ValidationResult status = UriValidator.validateRpcResponse(uri); + assertTrue(UriValidator.isEmpty(uri)); + assertEquals("Uri is empty.", status.getMessage()); + } + + @Test + @DisplayName("Test validateRpcResponse with rpc type") + public void test_validateRpcResponse_with_rpc_type() { + final UUri uri = LongUriSerializer.instance().deserialize("/hartley//dummy.wrong"); + final ValidationResult status = UriValidator.validateRpcResponse(uri); + assertTrue(status.isFailure()); + assertEquals("Invalid RPC response type.", status.getMessage()); + } + + @Test + @DisplayName("Test validateRpcResponse with invalid rpc response type") + public void test_validateRpcResponse_with_invalid_rpc_response_type() { + final UUri uri = LongUriSerializer.instance().deserialize("/hartley//rpc.wrong"); + final ValidationResult status = UriValidator.validateRpcResponse(uri); + assertTrue(status.isFailure()); + assertEquals("Invalid RPC response type.", status.getMessage()); + } + + @Test + @DisplayName("Test validate topic uri with version, when it is valid microRemote") + void test_topic_uri_with_version_when_it_is_valid_remote() { + + final String uri = "//VCU.MY_CAR_VIN/body.access/1/door.front_left#Door"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate topic uri no version, when it is valid microRemote") + void test_topic_uri_no_version_when_it_is_valid_remote() { + + final String uri = "//VCU.MY_CAR_VIN/body.access//door.front_left#Door"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate topic uri with version, when it is valid local") + void test_topic_uri_with_version_when_it_is_valid_local() { + + final String uri = "/body.access/1/door.front_left#Door"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate topic uri no version, when it is valid local") + void test_topic_uri_no_version_when_it_is_valid_local() { + + final String uri = "/body.access//door.front_left#Door"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate topic uri is invalid when uri contains nothing but schema") + void test_topic_uri_invalid_when_uri_has_schema_only() { + + final String uri = ":"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate topic uri is invalid when uri contains empty use name local") + void test_topic_uri_invalid_when_uri_has_empty_use_name_local() { + + final String uri = "/"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate topic uri is invalid when uri is microRemote but missing authority") + void test_topic_uri_invalid_when_uri_is_remote_no_authority() { + + final String uri = "//"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate topic uri is invalid when uri is microRemote with use but missing authority") + void test_topic_uri_invalid_when_uri_is_remote_no_authority_with_use() { + + final String uri = "///body.access/1/door.front_left#Door"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + + } + + @Test + @DisplayName("Test validate topic uri is invalid when uri has no use information") + void test_topic_uri_invalid_when_uri_is_missing_use_remote() { + + final String uri = "//VCU.myvin///door.front_left#Door"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate microRemote topic uri is invalid when uri is missing use name") + void test_topic_uri_invalid_when_uri_is_missing_use_name_remote() { + + final String uri = "/1/door.front_left#Door"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate local topic uri is invalid when uri is missing use name") + void test_topic_uri_invalid_when_uri_is_missing_use_name_local() { + + final String uri = "//VCU.myvin//1"; + + final ValidationResult status = UriValidator.validate(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + + @Test + @DisplayName("Test validate rpc topic uri with version, when it is valid microRemote") + void test_rpc_topic_uri_with_version_when_it_is_valid_remote() { + + final String uri = "//bo.cloud/petapp/1/rpc.response"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc topic uri no version, when it is valid microRemote") + void test_rpc_topic_uri_no_version_when_it_is_valid_remote() { + + final String uri = "//bo.cloud/petapp//rpc.response"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc topic uri with version, when it is valid local") + void test_rpc_topic_uri_with_version_when_it_is_valid_local() { + + final String uri = "/petapp/1/rpc.response"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc topic uri no version, when it is valid local") + void test_rpc_topic_uri_no_version_when_it_is_valid_local() { + + final String uri = "/petapp//rpc.response"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc topic uri is invalid when uri contains nothing but schema") + void test_rpc_topic_uri_invalid_when_uri_has_schema_only() { + + final String uri = ":"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc topic uri with version, when it is local but missing rpc.respons") + void test_rpc_topic_uri_with_version_when_it_is_not_valid_missing_rpc_response_local() { + + final String uri = "/petapp/1/dog"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc topic uri with version, when it is microRemote but missing rpc.respons") + void test_rpc_topic_uri_with_version_when_it_is_not_valid_missing_rpc_response_remote() { + + final String uri = "//petapp/1/dog"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc topic uri is invalid when uri is microRemote but missing authority") + void test_rpc_topic_uri_invalid_when_uri_is_remote_no_authority() { + + final String uri = "//"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc topic uri is invalid when uri is microRemote with use but missing authority") + void test_rpc_topic_uri_invalid_when_uri_is_remote_no_authority_with_use() { + + final String uri = "///body.access/1"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc topic uri is invalid when uri has no use information") + void test_rpc_topic_uri_invalid_when_uri_is_missing_use() { + + final String uri = "//VCU.myvin"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate microRemote rpc topic uri is invalid when uri is missing use name") + void test_rpc_topic_uri_invalid_when_uri_is_missing_use_name_remote() { + + final String uri = "/1"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate local rpc topic uri is invalid when uri is missing use name") + void test_rpc_topic_uri_invalid_when_uri_is_missing_use_name_local() { + + final String uri = "//VCU.myvin//1"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + + @Test + @DisplayName("Test validate rpc method uri with version, when it is valid microRemote") + void test_rpc_method_uri_with_version_when_it_is_valid_remote() { + + final String uri = "//VCU.myvin/body.access/1/rpc.UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc method uri no version, when it is valid microRemote") + void test_rpc_method_uri_no_version_when_it_is_valid_remote() { + + final String uri = "//VCU.myvin/body.access//rpc.UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc method uri with version, when it is valid local") + void test_rpc_method_uri_with_version_when_it_is_valid_local() { + + final String uri = "/body.access/1/rpc.UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc method uri no version, when it is valid local") + void test_rpc_method_uri_no_version_when_it_is_valid_local() { + + final String uri = "/body.access//rpc.UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isSuccess()); + } + + @Test + @DisplayName("Test validate rpc method uri is invalid when uri contains nothing but schema") + void test_rpc_method_uri_invalid_when_uri_has_schema_only() { + + final String uri = ":"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc method uri with version, when it is local but not an rpc method") + void test_rpc_method_uri_with_version_when_it_is_not_valid_not_rpc_method_local() { + + final String uri = "/body.access//UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc method uri with version, when it is microRemote but not an rpc method") + void test_rpc_method_uri_with_version_when_it_is_not_valid_not_rpc_method_remote() { + + final String uri = "//body.access/1/UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc method uri is invalid when uri is microRemote but missing authority") + void test_rpc_method_uri_invalid_when_uri_is_remote_no_authority() { + + final String uri = "//"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate rpc method uri is invalid when uri is microRemote with use but missing authority") + void test_rpc_method_uri_invalid_when_uri_is_remote_no_authority_with_use() { + + final String uri = "///body.access/1/rpc.UpdateDoor"; + + final UUri uuri = LongUriSerializer.instance().deserialize(uri); + final ValidationResult status = UriValidator.validateRpcMethod(uuri); + assertEquals("", uuri.toString()); + assertTrue(status.isFailure()); + + } + + @Test + @DisplayName("Test validate rpc method uri is invalid when uri has no use information") + void test_rpc_method_uri_invalid_when_uri_is_missing_use() { + + final String uri = "//VCU.myvin"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate local rpc method uri is invalid when uri is missing use name") + void test_rpc_method_uri_invalid_when_uri_is_missing_use_name_local() { + + final String uri = "/1/rpc.UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + + assertTrue(status.isFailure()); + } + + @Test + @DisplayName("Test validate microRemote rpc method uri is invalid when uri is missing use name") + void test_rpc_method_uri_invalid_when_uri_is_missing_use_name_remote() { + + final String uri = "//VCU.myvin//1/rpc.UpdateDoor"; + + final ValidationResult status = UriValidator.validateRpcMethod(LongUriSerializer.instance().deserialize(uri)); + assertTrue(status.isFailure()); + } + +} diff --git a/src/test/java/org/eclipse/uprotocol/uri/validator/uris.json b/src/test/java/org/eclipse/uprotocol/uri/validator/uris.json new file mode 100644 index 00000000..ebeb4905 --- /dev/null +++ b/src/test/java/org/eclipse/uprotocol/uri/validator/uris.json @@ -0,0 +1,38 @@ +{ + "validUris" : [ + "/", + "//", + "//vcu", + "//vcu.vin/", + "/hartley", + "/hartley//", + "hartley/0", + "/1", + "/body.access/1", + "/body.access/1/door.front_left#Door", + "//vcu.vin/body.access/1/door.front_left#Door", + "/body.access/1/rpc.OpenWindow", + "/body.access/1/rpc.response" + ], + "invalidUris" : [ + {"uri": "", "reason" : "Empty Uri"}, + {"uri": ":", "reason": "Contains only schema"}, + {"uri": "///", "reason" : "Empty Authority"}, + {"uri": "////", "reason" : "Empty Uri"}, + {"uri": "1", "reason" : "Invalid Uri, must begin with \"\/\""}, + {"uri": "a", "reason" : "Invalid Uri, must begin with \"\/\""}, + {"uri": "/1", "reason" : "Invalid Uri, must begin with \"\/\""} + ], + "validRpcUris": [ + "/petapp/1/rpc.OpenWindow", + "/petapp/1.2/rpc.response" + ], + "invalidRpcUris" : [ + {"uri": "/petapp//", "reason" : "Missing uE version"}, + {"uri": "/petapp", "reason" : "Missing uE version"}, + {"uri": "/petapp/1/", "reason" : "Missing RPC Method Name"}, + {"uri": "/petapp/1/rpc", "reason" : "Missing RPC Method Name"}, + {"uri": "/petapp/1/dummy", "reason" : "Missing RPC Method Name"}, + {"uri": "/petapp/1/rpc_dummy", "reason" : "Missing RPC Method Name"} + ] +} \ No newline at end of file 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 07acb962..ecaacc4c 100644 --- a/src/test/java/org/eclipse/uprotocol/uuid/validator/UuidValidatorTest.java +++ b/src/test/java/org/eclipse/uprotocol/uuid/validator/UuidValidatorTest.java @@ -21,10 +21,11 @@ package org.eclipse.uprotocol.uuid.validator; -import org.eclipse.uprotocol.cloudevent.validate.ValidationResult; import org.eclipse.uprotocol.uuid.factory.UUIDFactory; import org.eclipse.uprotocol.uuid.factory.UUIDUtils; import org.eclipse.uprotocol.uuid.validate.UuidValidator; +import org.eclipse.uprotocol.validation.ValidationResult; + import com.google.rpc.Code; import com.google.rpc.Status;