diff --git a/README.adoc b/README.adoc index aee2c81..ff84713 100644 --- a/README.adoc +++ b/README.adoc @@ -34,10 +34,11 @@ To set up SDK, follow the steps below: git clone https://github.com/eclipse-uprotocol/uprotocol-python.git ---- -. Execute the `pull_and_compile_protos.py` script using the following command: +. Execute the `pull_and_compile_protos.py` script using the following commands: + [source] ---- +cd scripts python pull_and_compile_protos.py ---- This script automates the following tasks: diff --git a/pyproject.toml b/pyproject.toml index 1c22c14..24359b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "up-python" -version = "0.1.2-dev" +version = "0.1.3-dev" description = "Language specific uProtocol library for building and using UUri, UUID, UAttributes, UTransport, and more." authors = ["Neelam Kushwah "] license = "The Apache License, Version 2.0" diff --git a/tests/test_cloudevent/test_datamodel/test_ucloudevent.py b/tests/test_cloudevent/test_datamodel/test_ucloudevent.py index 5aae1b2..e495d77 100644 --- a/tests/test_cloudevent/test_datamodel/test_ucloudevent.py +++ b/tests/test_cloudevent/test_datamodel/test_ucloudevent.py @@ -24,13 +24,13 @@ # # ------------------------------------------------------------------------- -from datetime import datetime, timezone, timedelta +from datetime import datetime, timezone from uprotocol.proto.uri_pb2 import UUri, UEntity, UResource from uprotocol.uri.serializer.longuriserializer import LongUriSerializer from uprotocol.cloudevent.cloudevents_pb2 import CloudEvent from uprotocol.proto.uattributes_pb2 import UMessageType, UPriority -from uprotocol.proto.upayload_pb2 import UPayloadFormat +from uprotocol.proto.upayload_pb2 import UPayloadFormat from uprotocol.cloudevent.factory.cloudeventfactory import CloudEventFactory from uprotocol.proto.ustatus_pb2 import UCode from uprotocol.uuid.factory.uuidfactory import Factories @@ -407,8 +407,6 @@ def test_from_message_with_valid_message(self): UCloudEvent.get_type(cloud_event1), ) - - def test_to_from_message_from_request_cloudevent(self): # additional attributes u_cloud_event_attributes = ( @@ -599,15 +597,15 @@ def test_cloud_event_to_string(self): def test_cloud_event_to_string_none(self): cloud_event_string = UCloudEvent.to_string(None) - self.assertEqual( - cloud_event_string, "null" - ) + self.assertEqual(cloud_event_string, "null") def test_get_upayload_format_from_content_type(self): - new_format = UCloudEvent().get_upayload_format_from_content_type("application/json") + new_format = UCloudEvent().get_upayload_format_from_content_type( + "application/json" + ) self.assertEqual(new_format, UPayloadFormat.UPAYLOAD_FORMAT_JSON) def test_to_message_none_entry(self): with self.assertRaises(ValueError) as context: UCloudEvent().toMessage(None) - self.assertTrue("Cloud Event can't be None" in context.exception) \ No newline at end of file + self.assertTrue("Cloud Event can't be None" in context.exception) diff --git a/tests/test_cloudevent/test_datamodel/test_ucloudeventattributes.py b/tests/test_cloudevent/test_datamodel/test_ucloudeventattributes.py index 39df384..6b1491a 100644 --- a/tests/test_cloudevent/test_datamodel/test_ucloudeventattributes.py +++ b/tests/test_cloudevent/test_datamodel/test_ucloudeventattributes.py @@ -1,4 +1,3 @@ - # ------------------------------------------------------------------------- # Copyright (c) 2023 General Motors GTO LLC @@ -27,45 +26,79 @@ import unittest -from uprotocol.cloudevent.datamodel.ucloudeventattributes import UCloudEventAttributesBuilder, \ - UCloudEventAttributes +from uprotocol.cloudevent.datamodel.ucloudeventattributes import ( + UCloudEventAttributesBuilder, + UCloudEventAttributes, +) from uprotocol.proto.uattributes_pb2 import UPriority class TestUCloudEventAttributes(unittest.TestCase): def test_to_string(self): - u_cloud_event_attributes = UCloudEventAttributesBuilder().with_hash("somehash").with_priority( - UPriority.UPRIORITY_CS1).with_ttl(3).with_token("someOAuthToken").build() + u_cloud_event_attributes = ( + UCloudEventAttributesBuilder() + .with_hash("somehash") + .with_priority(UPriority.UPRIORITY_CS1) + .with_ttl(3) + .with_token("someOAuthToken") + .build() + ) expected = "UCloudEventAttributes{hash='somehash', priority=UPRIORITY_CS1, ttl=3, token='someOAuthToken'}" self.assertEqual(expected, str(u_cloud_event_attributes)) def test_create_valid_with_blank_traceparent(self): - u_cloud_event_attributes = UCloudEventAttributesBuilder().with_hash("somehash").with_priority( - UPriority.UPRIORITY_CS1).with_ttl(3).with_token("someOAuthToken").with_traceparent(" ").build() + u_cloud_event_attributes = ( + UCloudEventAttributesBuilder() + .with_hash("somehash") + .with_priority(UPriority.UPRIORITY_CS1) + .with_ttl(3) + .with_token("someOAuthToken") + .with_traceparent(" ") + .build() + ) self.assertTrue(u_cloud_event_attributes.get_hash() is not None) self.assertEqual("somehash", u_cloud_event_attributes.get_hash()) - self.assertFalse(u_cloud_event_attributes.get_traceparent() is not None) + self.assertFalse( + u_cloud_event_attributes.get_traceparent() is not None + ) def test_create_empty_with_only_traceparent(self): - u_cloud_event_attributes = UCloudEventAttributesBuilder().with_traceparent("someTraceParent").build() + u_cloud_event_attributes = ( + UCloudEventAttributesBuilder() + .with_traceparent("someTraceParent") + .build() + ) self.assertFalse(u_cloud_event_attributes.get_hash() is not None) self.assertFalse(u_cloud_event_attributes.get_priority() is not None) self.assertFalse(u_cloud_event_attributes.get_token() is not None) self.assertFalse(u_cloud_event_attributes.get_ttl() is not None) self.assertTrue(u_cloud_event_attributes.get_traceparent() is not None) self.assertFalse(u_cloud_event_attributes.is_empty()) - self.assertEqual("someTraceParent", u_cloud_event_attributes.get_traceparent()) + self.assertEqual( + "someTraceParent", u_cloud_event_attributes.get_traceparent() + ) def test_create_valid(self): - u_cloud_event_attributes = UCloudEventAttributesBuilder().with_hash("somehash").with_priority( - UPriority.UPRIORITY_CS6).with_ttl(3).with_token("someOAuthToken").build() + u_cloud_event_attributes = ( + UCloudEventAttributesBuilder() + .with_hash("somehash") + .with_priority(UPriority.UPRIORITY_CS6) + .with_ttl(3) + .with_token("someOAuthToken") + .build() + ) self.assertEqual("somehash", u_cloud_event_attributes.get_hash()) - self.assertEqual(UPriority.Name(UPriority.UPRIORITY_CS6), u_cloud_event_attributes.get_priority()) + self.assertEqual( + UPriority.Name(UPriority.UPRIORITY_CS6), + u_cloud_event_attributes.get_priority(), + ) self.assertEqual(3, u_cloud_event_attributes.get_ttl()) - self.assertEqual("someOAuthToken", u_cloud_event_attributes.get_token()) + self.assertEqual( + "someOAuthToken", u_cloud_event_attributes.get_token() + ) def test_is_empty_function(self): u_cloud_event_attributes = UCloudEventAttributes.empty() @@ -75,7 +108,12 @@ def test_is_empty_function(self): self.assertTrue(u_cloud_event_attributes.ttl is None) def test_is_empty_function_when_built_with_blank_strings(self): - u_cloud_event_attributes = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() + u_cloud_event_attributes = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) self.assertTrue(u_cloud_event_attributes.is_empty()) self.assertTrue(u_cloud_event_attributes.hash.isspace()) self.assertTrue(u_cloud_event_attributes.priority is None) @@ -83,44 +121,115 @@ def test_is_empty_function_when_built_with_blank_strings(self): self.assertTrue(u_cloud_event_attributes.ttl is None) def test_is_empty_function_permutations(self): - u_cloud_event_attributes = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() + u_cloud_event_attributes = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) self.assertTrue(u_cloud_event_attributes.is_empty()) - u_cloud_event_attributes2 = UCloudEventAttributesBuilder().with_hash("someHash").with_token(" ").build() + u_cloud_event_attributes2 = ( + UCloudEventAttributesBuilder() + .with_hash("someHash") + .with_token(" ") + .build() + ) self.assertFalse(u_cloud_event_attributes2.is_empty()) - u_cloud_event_attributes3 = UCloudEventAttributesBuilder().with_hash(" ").with_token("SomeToken").build() + u_cloud_event_attributes3 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token("SomeToken") + .build() + ) self.assertFalse(u_cloud_event_attributes3.is_empty()) - u_cloud_event_attributes4 = UCloudEventAttributesBuilder().with_priority(UPriority.UPRIORITY_CS0).build() + u_cloud_event_attributes4 = ( + UCloudEventAttributesBuilder() + .with_priority(UPriority.UPRIORITY_CS0) + .build() + ) self.assertFalse(u_cloud_event_attributes4.is_empty()) - u_cloud_event_attributes5 = UCloudEventAttributesBuilder().with_ttl(8).build() + u_cloud_event_attributes5 = ( + UCloudEventAttributesBuilder().with_ttl(8).build() + ) self.assertFalse(u_cloud_event_attributes5.is_empty()) def test__eq__is_same(self): - u_cloud_event_attributes = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() - self.assertTrue(u_cloud_event_attributes.__eq__(u_cloud_event_attributes)) + u_cloud_event_attributes = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) + self.assertTrue( + u_cloud_event_attributes.__eq__(u_cloud_event_attributes) + ) def test__eq__is_equal(self): - u_cloud_event_attributes_1 = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() - u_cloud_event_attributes_2 = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() - self.assertTrue(u_cloud_event_attributes_1.__eq__(u_cloud_event_attributes_2)) - + u_cloud_event_attributes_1 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) + u_cloud_event_attributes_2 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) + self.assertTrue( + u_cloud_event_attributes_1.__eq__(u_cloud_event_attributes_2) + ) + def test__eq__is_not_equal(self): - u_cloud_event_attributes_1 = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() - u_cloud_event_attributes_2 = UCloudEventAttributesBuilder().with_hash(" ").with_token("12345").build() - self.assertFalse(u_cloud_event_attributes_1.__eq__(u_cloud_event_attributes_2)) + u_cloud_event_attributes_1 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) + u_cloud_event_attributes_2 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token("12345") + .build() + ) + self.assertFalse( + u_cloud_event_attributes_1.__eq__(u_cloud_event_attributes_2) + ) def test__hash__same(self): - u_cloud_event_attributes_1 = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() - self.assertEqual(hash(u_cloud_event_attributes_1), hash(u_cloud_event_attributes_1)) - - def test__hash__different(self): - u_cloud_event_attributes_1 = UCloudEventAttributesBuilder().with_hash(" ").with_token(" ").build() - u_cloud_event_attributes_2 = UCloudEventAttributesBuilder().with_hash(" ").with_token("12345").build() - self.assertNotEqual(hash(u_cloud_event_attributes_1), hash(u_cloud_event_attributes_2)) - + u_cloud_event_attributes_1 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) + self.assertEqual( + hash(u_cloud_event_attributes_1), hash(u_cloud_event_attributes_1) + ) -if __name__ == '__main__': + def test__hash__different(self): + u_cloud_event_attributes_1 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token(" ") + .build() + ) + u_cloud_event_attributes_2 = ( + UCloudEventAttributesBuilder() + .with_hash(" ") + .with_token("12345") + .build() + ) + self.assertNotEqual( + hash(u_cloud_event_attributes_1), hash(u_cloud_event_attributes_2) + ) + + +if __name__ == "__main__": unittest.main() diff --git a/tests/test_cloudevent/test_validator/test_cloudeventvalidator.py b/tests/test_cloudevent/test_validator/test_cloudeventvalidator.py index b08a1ff..3746d5c 100644 --- a/tests/test_cloudevent/test_validator/test_cloudeventvalidator.py +++ b/tests/test_cloudevent/test_validator/test_cloudeventvalidator.py @@ -640,4 +640,4 @@ def fetching_the_notification_validator(self): validator = CloudEventValidator.get_validator(cloud_event) status = validator.validate_type(cloud_event).to_status() self.assertEqual(status, ValidationResult.STATUS_SUCCESS) - self.assertEqual("CloudEventValidator.Notification", str(validator)) \ No newline at end of file + self.assertEqual("CloudEventValidator.Notification", str(validator)) diff --git a/tests/test_transport/test_builder/test_uattributesbuilder.py b/tests/test_transport/test_builder/test_uattributesbuilder.py index 152f683..026e98f 100644 --- a/tests/test_transport/test_builder/test_uattributesbuilder.py +++ b/tests/test_transport/test_builder/test_uattributesbuilder.py @@ -229,10 +229,9 @@ def test_response_reqid_is_none(self): def test_response_request_is_none(self): with self.assertRaises(ValueError) as context: - UAttributesBuilder.response( - None - ) + UAttributesBuilder.response(None) self.assertTrue("request cannot be null." in context.exception) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_transport/test_builder/test_upayloadbuilder.py b/tests/test_transport/test_builder/test_upayloadbuilder.py index 5f56f0c..a5a389a 100644 --- a/tests/test_transport/test_builder/test_upayloadbuilder.py +++ b/tests/test_transport/test_builder/test_upayloadbuilder.py @@ -162,12 +162,6 @@ def test_unpack_given_upayload_proto_returns_method(self): def test_unpack_exception(self): builder = self._create_upayload_builder() - original_msg: Message = Method( - name="name", - request_type_url="request_type_url", - response_type_url="response_type_url", - request_streaming=None, - ) upayload: UPayload = UPayload( format=UPayloadFormat.UPAYLOAD_FORMAT_PROTOBUF, value=b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", diff --git a/tests/test_transport/test_utransport.py b/tests/test_transport/test_utransport.py index bd45b6e..48d782c 100644 --- a/tests/test_transport/test_utransport.py +++ b/tests/test_transport/test_utransport.py @@ -8,20 +8,21 @@ class MyListener(UListener): def on_receive(self, message): - super().on_receive( message) + super().on_receive(message) pass class HappyUTransport(UTransport): def send(self, message): - super().send( message) + super().send(message) return UStatus( - code=UCode.INVALID_ARGUMENT if message is None else UCode.OK) + code=UCode.INVALID_ARGUMENT if message is None else UCode.OK + ) def register_listener(self, topic, listener): - super().register_listener( topic, listener) + super().register_listener(topic, listener) listener.on_receive(UMessage()) return UStatus(code=UCode.OK) @@ -32,16 +33,16 @@ def unregister_listener(self, topic, listener): class SadUTransport(UTransport): def send(self, message): - super().send( message) + super().send(message) return UStatus(code=UCode.INTERNAL) def register_listener(self, topic, listener): - super().register_listener( topic, listener) + super().register_listener(topic, listener) listener.on_receive(None) return UStatus(code=UCode.INTERNAL) def unregister_listener(self, topic, listener): - super().unregister_listener( topic, listener) + super().unregister_listener(topic, listener) return UStatus(code=UCode.INTERNAL) @@ -92,5 +93,5 @@ def test_unhappy_register_unlistener(self): self.assertEqual(status.code, UCode.INTERNAL) -if __name__ == '__main__': - unittest.main() \ No newline at end of file +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_transport/test_validate/test_uattributesvalidator.py b/tests/test_transport/test_validate/test_uattributesvalidator.py index 0b369e9..76ac1d0 100644 --- a/tests/test_transport/test_validate/test_uattributesvalidator.py +++ b/tests/test_transport/test_validate/test_uattributesvalidator.py @@ -26,7 +26,6 @@ import time import unittest -import uuid from uprotocol.proto.uattributes_pb2 import UPriority from uprotocol.proto.uri_pb2 import UUri, UAuthority, UEntity @@ -503,7 +502,9 @@ def test_validating_valid_ReqId_attribute(self): def test_validating_valid_type_attribute(self): attributes = ( - UAttributesBuilder.notification(build_source(), build_sink(), UPriority.UPRIORITY_CS0) + UAttributesBuilder.notification( + build_source(), build_sink(), UPriority.UPRIORITY_CS0 + ) .withReqId(Factories.UPROTOCOL.create()) .build() ) @@ -514,7 +515,9 @@ def test_validating_valid_type_attribute(self): def test_validating_valid_sink_attribute(self): attributes = ( - UAttributesBuilder.notification(build_source(), build_sink(), UPriority.UPRIORITY_CS0) + UAttributesBuilder.notification( + build_source(), build_sink(), UPriority.UPRIORITY_CS0 + ) .withReqId(Factories.UPROTOCOL.create()) .build() ) @@ -532,7 +535,9 @@ def test_validating_none_attribute(self): def test_validating_invalid_sink_attribute(self): attributes = ( - UAttributesBuilder.notification(build_source(), UUri(), UPriority.UPRIORITY_CS0) + UAttributesBuilder.notification( + build_source(), UUri(), UPriority.UPRIORITY_CS0 + ) .withReqId(Factories.UPROTOCOL.create()) .build() ) @@ -541,7 +546,6 @@ def test_validating_invalid_sink_attribute(self): status = validator.validate_sink(attributes) self.assertEqual("Missing Sink", status.get_message()) - def test_validating_invalid_PermissionLevel_attribute(self): with self.assertRaises(ValueError) as context: UAttributesBuilder.publish( @@ -705,6 +709,140 @@ def test_invalid_response_uri_in_sink(self): status = validator.validate(attributes) self.assertEqual("Invalid RPC response type.", status.get_message()) + def test_publish_validation_without_id(self): + attributes = UAttributesBuilder.publish( + build_source(), UPriority.UPRIORITY_CS0 + ).build() + attributes.ClearField("id") + validator = Validators.PUBLISH.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual("Missing id", status.get_message()) + + def test_notification_validation_without_id(self): + attributes = UAttributesBuilder.notification( + build_source(), build_sink(), UPriority.UPRIORITY_CS0 + ).build() + attributes.ClearField("id") + validator = Validators.NOTIFICATION.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual("Missing id", status.get_message()) + + def test_request_validation_without_id(self): + attributes = UAttributesBuilder.request( + build_source(), build_sink(), UPriority.UPRIORITY_CS0, 1000 + ).build() + attributes.ClearField("id") + validator = Validators.REQUEST.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual("Missing id", status.get_message()) + + def test_response_validation_without_id(self): + attributes = UAttributesBuilder.response( + build_source(), + build_sink(), + UPriority.UPRIORITY_CS0, + Factories.UPROTOCOL.create(), + ).build() + attributes.ClearField("id") + validator = Validators.RESPONSE.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual("Missing id", status.get_message()) + + def test_publish_validation_invalid_id(self): + attributes = UAttributesBuilder.publish( + build_source(), UPriority.UPRIORITY_CS0 + ).build() + attributes.id.CopyFrom(UUID()) + validator = Validators.PUBLISH.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual( + "Attributes must contain valid uProtocol UUID in id property", + status.get_message(), + ) + + def test_notification_validation_invalid_id(self): + attributes = UAttributesBuilder.notification( + build_source(), build_sink(), UPriority.UPRIORITY_CS0 + ).build() + attributes.id.CopyFrom(UUID()) + validator = Validators.NOTIFICATION.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual( + "Attributes must contain valid uProtocol UUID in id property", + status.get_message(), + ) + + def test_request_validation_invalid_id(self): + attributes = UAttributesBuilder.request( + build_source(), build_sink(), UPriority.UPRIORITY_CS0, 1000 + ).build() + attributes.id.CopyFrom(UUID()) + validator = Validators.REQUEST.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual( + "Attributes must contain valid uProtocol UUID in id property", + status.get_message(), + ) + + def test_response_validation_invalid_id(self): + attributes = UAttributesBuilder.response( + build_source(), + build_sink(), + UPriority.UPRIORITY_CS0, + Factories.UPROTOCOL.create(), + ).build() + attributes.id.CopyFrom(UUID()) + validator = Validators.RESPONSE.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual( + "Attributes must contain valid uProtocol UUID in id property", + status.get_message(), + ) + + def test_publish_validation_when_an_invalid_priority(self): + attributes = UAttributesBuilder.publish( + build_source(), UPriority.UPRIORITY_UNSPECIFIED + ).build() + validator = Validators.PUBLISH.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual( + "Invalid UPriority [UPRIORITY_UNSPECIFIED]", status.get_message() + ) + + def test_request_validation_with_invalid_priority(self): + attributes = UAttributesBuilder.request( + build_source(), build_sink(), UPriority.UPRIORITY_UNSPECIFIED, 1000 + ).build() + validator = Validators.REQUEST.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual( + "Invalid UPriority [UPRIORITY_UNSPECIFIED]", status.get_message() + ) + + def test_response_validation_with_invalid_priority(self): + attributes = UAttributesBuilder.response( + build_source(), + build_sink(), + UPriority.UPRIORITY_UNSPECIFIED, + Factories.UPROTOCOL.create(), + ).build() + validator = Validators.RESPONSE.validator() + status = validator.validate(attributes) + self.assertTrue(status.is_failure()) + self.assertEqual( + "Invalid UPriority [UPRIORITY_UNSPECIFIED]", status.get_message() + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_uri/test_serializer/test_longuriserializer.py b/tests/test_uri/test_serializer/test_longuriserializer.py index b64ea95..1ab70e5 100644 --- a/tests/test_uri/test_serializer/test_longuriserializer.py +++ b/tests/test_uri/test_serializer/test_longuriserializer.py @@ -525,12 +525,9 @@ def test_build_protocol_uri_from__uri_when__uri_isEmpty(self): self.assertEqual("", uprotocol_uri) def test_build_protocol_uri_from__uri_when__uri_has_empty_use(self): - use = UEntity() - uuri = UUri( - authority=UAuthority(), entity=use, resource=UResource(name="door") - ) + uuri = UUri(resource=UResource(name="door")) uprotocol_uri = LongUriSerializer().serialize(uuri) - self.assertEqual("/////door", uprotocol_uri) + self.assertEqual("///door", uprotocol_uri) def test_build_protocol_uri_from__uri_when__uri_has_local_authority_service_no_version( self, @@ -807,6 +804,39 @@ def test_parse_remote_protocol_uri_with_custom_scheme(self): self.assertEqual("Door", uuri.resource.message) self.assertEqual(uri2, LongUriSerializer().serialize(uuri)) + def test_b_prtcl_uri__uri__uri_rmte_auth_srvc_vsn_rsrc_emp_instc(self): + u_authority = UAuthority(name="vcu.my_car_vin") + use = UEntity(name="body.access", version_major=1) + resource = UResource(name="door", instance="", message="Door") + ucustom_uri = LongUriSerializer().serialize( + UUri(authority=u_authority, entity=use, resource=resource) + ) + self.assertEqual( + "//vcu.my_car_vin/body.access/1/door#Door", ucustom_uri + ) + + def test_b_prtcl_uri__uri__uri_rmte_auth_srvc_vsn_rsrc_emp_msg(self): + u_authority = UAuthority(name="vcu.my_car_vin") + use = UEntity(name="body.access", version_major=1) + resource = UResource(name="door", instance="front_left", message="") + ucustom_uri = LongUriSerializer().serialize( + UUri(authority=u_authority, entity=use, resource=resource) + ) + self.assertEqual( + "//vcu.my_car_vin/body.access/1/door.front_left", ucustom_uri + ) + + def test_b_prtcl_uri__uri__uri_empty_auth_service_ver_w_rsrc(self): + u_authority = UAuthority(name="") + use = UEntity(name="body.access", version_major=1) + resource = UResource( + name="door", instance="front_left", message="Door" + ) + ucustom_uri = LongUriSerializer().serialize( + UUri(authority=u_authority, entity=use, resource=resource) + ) + self.assertEqual("/body.access/1/door.front_left#Door", ucustom_uri) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_uri/test_serializer/test_microuriserializer.py b/tests/test_uri/test_serializer/test_microuriserializer.py index 44af680..6e95af0 100644 --- a/tests/test_uri/test_serializer/test_microuriserializer.py +++ b/tests/test_uri/test_serializer/test_microuriserializer.py @@ -22,7 +22,10 @@ def test_null(self): self.assertTrue(UriValidator.is_empty(uri2)) def test_serialize_uri(self): - uri = UUri(entity=UEntity(id=29999, version_major=254), resource=UResourceBuilder.from_id(19999)) + uri = UUri( + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.from_id(19999), + ) bytes_uuri = MicroUriSerializer().serialize(uri) uri2 = MicroUriSerializer().deserialize(bytes_uuri) self.assertTrue(UriValidator.is_micro_form(uri)) @@ -30,13 +33,19 @@ def test_serialize_uri(self): self.assertEqual(uri, uri2) def test_serialize_remote_uri_without_address(self): - uri = UUri(authority=UAuthority(name="vcu.vin"), entity=UEntity(id=29999, version_major=254), - resource=UResourceBuilder.for_rpc_response()) + uri = UUri( + authority=UAuthority(name="vcu.vin"), + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.for_rpc_response(), + ) bytes_uuri = MicroUriSerializer().serialize(uri) self.assertTrue(len(bytes_uuri) == 0) def test_serialize_uri_missing_ids(self): - uri = UUri(entity=UEntity(name="hartley"), resource=UResourceBuilder.for_rpc_response()) + uri = UUri( + entity=UEntity(name="hartley"), + resource=UResourceBuilder.for_rpc_response(), + ) bytes_uuri = MicroUriSerializer().serialize(uri) self.assertTrue(len(bytes_uuri) == 0) @@ -50,36 +59,53 @@ def test_deserialize_bad_microuri_length(self): uuri = MicroUriSerializer().deserialize(badMicroUUri) self.assertTrue(UriValidator.is_empty(uuri)) - badMicroUUri = bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]) + badMicroUUri = bytes( + [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] + ) uuri = MicroUriSerializer().deserialize(badMicroUUri) self.assertTrue(UriValidator.is_empty(uuri)) def test_deserialize_bad_microuri_not_version_1(self): - badMicroUUri = bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]) + badMicroUUri = bytes( + [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] + ) uuri = MicroUriSerializer().deserialize(badMicroUUri) self.assertTrue(UriValidator.is_empty(uuri)) def test_deserialize_bad_microuri_not_valid_address_type(self): - badMicroUUri = bytes([0x1, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]) + badMicroUUri = bytes( + [0x1, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] + ) uuri = MicroUriSerializer().deserialize(badMicroUUri) self.assertTrue(UriValidator.is_empty(uuri)) def test_deserialize_bad_microuri_valid_address_type_invalid_length(self): - badMicroUUri = bytes([0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]) + badMicroUUri = bytes( + [0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] + ) uuri = MicroUriSerializer().deserialize(badMicroUUri) self.assertTrue(UriValidator.is_empty(uuri)) - badMicroUUri = bytes([0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]) + badMicroUUri = bytes( + [0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] + ) uuri = MicroUriSerializer().deserialize(badMicroUUri) self.assertTrue(UriValidator.is_empty(uuri)) - badMicroUUri = bytes([0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]) + badMicroUUri = bytes( + [0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] + ) uuri = MicroUriSerializer().deserialize(badMicroUUri) self.assertTrue(UriValidator.is_empty(uuri)) def test_serialize_good_ipv4_based_authority(self): - uri = UUri(authority=UAuthority(ip=socket.inet_pton(socket.AF_INET, "10.0.3.3")), - entity=UEntity(id=29999, version_major=254), resource=UResourceBuilder.for_rpc_request(99)) + uri = UUri( + authority=UAuthority( + ip=socket.inet_pton(socket.AF_INET, "10.0.3.3") + ), + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.for_rpc_request(99), + ) bytes_uuri = MicroUriSerializer().serialize(uri) uri2 = MicroUriSerializer().deserialize(bytes_uuri) self.assertTrue(len(bytes_uuri) > 0) @@ -89,15 +115,24 @@ def test_serialize_good_ipv4_based_authority(self): self.assertTrue(uri == uri2) def test_serialize_bad_authority(self): - uri = UUri(authority=UAuthority(ip=b"123456789"), - entity=UEntity(id=29999, version_major=254), resource=UResourceBuilder.for_rpc_request(99)) + uri = UUri( + authority=UAuthority(ip=b"123456789"), + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.for_rpc_request(99), + ) bytes_uuri = MicroUriSerializer().serialize(uri) self.assertEqual(bytes_uuri, bytearray()) def test_serialize_good_ipv6_based_authority(self): - uri = UUri(authority=UAuthority( - ip=socket.inet_pton(socket.AF_INET6, "2001:0db8:85a3:0000:0000:8a2e:0370:7334")), - entity=UEntity(id=29999, version_major=254), resource=UResource(id=19999, name="rpc")) + uri = UUri( + authority=UAuthority( + ip=socket.inet_pton( + socket.AF_INET6, "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + ) + ), + entity=UEntity(id=29999, version_major=254), + resource=UResource(id=19999, name="rpc"), + ) bytes_uuri = MicroUriSerializer().serialize(uri) uri2 = MicroUriSerializer().deserialize(bytes_uuri) self.assertTrue(UriValidator.is_micro_form(uri)) @@ -107,8 +142,11 @@ def test_serialize_good_ipv6_based_authority(self): def test_serialize_id_based_authority(self): size = 13 byteArray = bytearray(i for i in range(size)) - uri = UUri(authority=UAuthority(id=bytes(byteArray)), entity=UEntity(id=29999, version_major=254), - resource=UResource(id=19999, name="rpc")) + uri = UUri( + authority=UAuthority(id=bytes(byteArray)), + entity=UEntity(id=29999, version_major=254), + resource=UResource(id=19999, name="rpc"), + ) bytes_uuri = MicroUriSerializer().serialize(uri) uri2 = MicroUriSerializer().deserialize(bytes_uuri) self.assertTrue(UriValidator.is_micro_form(uri)) @@ -117,22 +155,72 @@ def test_serialize_id_based_authority(self): def test_serialize_bad_length_ip_based_authority(self): byteArray = bytes([127, 1, 23, 123, 12, 6]) - uri = UUri(authority=UAuthority(ip=byteArray), entity=UEntity(id=29999, version_major=254), - resource=UResource(id=19999)) + uri = UUri( + authority=UAuthority(ip=byteArray), + entity=UEntity(id=29999, version_major=254), + resource=UResource(id=19999), + ) bytes_uuri = MicroUriSerializer().serialize(uri) self.assertTrue(len(bytes_uuri) == 0) def test_serialize_id_size_255_based_authority(self): size = 129 byteArray = bytes(i for i in range(size)) - uri = UUri(authority=UAuthority(id=byteArray), entity=UEntity(id=29999, version_major=254), - resource=UResourceBuilder.for_rpc_request(99)) + uri = UUri( + authority=UAuthority(id=byteArray), + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.for_rpc_request(99), + ) bytes_uuri = MicroUriSerializer().serialize(uri) self.assertEqual(len(bytes_uuri), 9 + size) uri2 = MicroUriSerializer().deserialize(bytes_uuri) self.assertTrue(UriValidator.is_micro_form(uri)) self.assertTrue(uri == uri2) + def test_serialize_id_out_of_range_2(self): + byteArray = bytearray(258) + for i in range(256): + byteArray[i] = i + byteArray = bytes(byteArray) + uri = UUri( + authority=UAuthority(id=byteArray), + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.from_id(19999), + ) + bytes_uuri = MicroUriSerializer().serialize(uri) + self.assertEqual(len(bytes_uuri), 0) + + def test_serialize_resource_id_out_of_range(self): + size = 129 + byteArray = bytes(i for i in range(size)) + uri = UUri( + authority=UAuthority(id=byteArray), + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.from_id(65536), + ) + bytes_uuri = MicroUriSerializer().serialize(uri) + self.assertEqual(len(bytes_uuri), 0) + + def test_serialize_entity_id_out_of_range(self): + size = 129 + byteArray = bytes(i for i in range(size)) + uri = UUri( + authority=UAuthority(id=byteArray), + entity=UEntity(id=65536, version_major=254), + resource=UResourceBuilder.from_id(19999), + ) + bytes_uuri = MicroUriSerializer().serialize(uri) + self.assertEqual(len(bytes_uuri), 0) + + def test_serialize_authority_ip_invalid(self): + uri = UUri( + authority=UAuthority(ip=b"123456789"), + entity=UEntity(id=29999, version_major=254), + resource=UResourceBuilder.from_id(19999), + ) + bytes_uuri = MicroUriSerializer().serialize(uri) + self.assertEqual(len(bytes_uuri), 0) + -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/test_uuid/test_factory/test_uuidutils.py b/tests/test_uuid/test_factory/test_uuidutils.py index 403aab2..1fe0ad4 100644 --- a/tests/test_uuid/test_factory/test_uuidutils.py +++ b/tests/test_uuid/test_factory/test_uuidutils.py @@ -26,11 +26,11 @@ import unittest import time +import datetime from uprotocol.transport.builder.uattributesbuilder import UAttributesBuilder from uprotocol.uuid.factory.uuidfactory import Factories from uprotocol.uuid.factory.uuidutils import UUIDUtils -from uprotocol.uri.factory.uresource_builder import UResourceBuilder from uprotocol.proto.uattributes_pb2 import UAttributes, UPriority from uprotocol.proto.uri_pb2 import UUri, UEntity, UAuthority, UResource @@ -117,3 +117,12 @@ def test_is_expired_attributes_no_ttl(self): build_source(), UPriority.UPRIORITY_CS0 ).build() self.assertFalse(UUIDUtils.is_expired(attributes)) + + def test_get_elapsed_time_invalid_uuid(self): + self.assertFalse(UUIDUtils.get_elapsed_time(None) is not None) + + def test_get_elapsed_time_past(self): + id: UUID = Factories.UPROTOCOL.create( + datetime.datetime.now() + datetime.timedelta(minutes=1) + ) + self.assertFalse(UUIDUtils.get_elapsed_time(id) is not None) diff --git a/uprotocol/cloudevent/datamodel/ucloudeventattributes.py b/uprotocol/cloudevent/datamodel/ucloudeventattributes.py index c6fc272..3e90356 100644 --- a/uprotocol/cloudevent/datamodel/ucloudeventattributes.py +++ b/uprotocol/cloudevent/datamodel/ucloudeventattributes.py @@ -212,4 +212,3 @@ def build(self): return UCloudEventAttributes( self.priority, self.hash, self.ttl, self.token, self.traceparent ) - diff --git a/uprotocol/transport/validate/uattributesvalidator.py b/uprotocol/transport/validate/uattributesvalidator.py index a0f2b26..bce957b 100644 --- a/uprotocol/transport/validate/uattributesvalidator.py +++ b/uprotocol/transport/validate/uattributesvalidator.py @@ -91,6 +91,7 @@ def validate(self, attributes: UAttributes) -> ValidationResult: self.validate_priority(attributes), self.validate_permission_level(attributes), self.validate_req_id(attributes), + self.validate_id(attributes) ] error_messages = [ @@ -204,6 +205,21 @@ def validate_req_id(attr: UAttributes) -> ValidationResult: else: return ValidationResult.success() + @staticmethod + def validate_id(attr: UAttributes) -> ValidationResult: + """ + Validate the Id for the default case. If the UAttributes object does + not contain an Id, the ValidationResult is failed. + + @param attr:Attributes object containing the Id to validate. + @return:Returns a ValidationResult that is success or failed + """ + if not attr.HasField("id"): + return ValidationResult.failure("Missing id") + if not UUIDUtils.is_uuid(attr.id): + return ValidationResult.failure("Attributes must contain valid uProtocol UUID in id property") + return ValidationResult.success() + @abstractmethod def validate_type(self, attr: UAttributes): """ diff --git a/uprotocol/uri/serializer/longuriserializer.py b/uprotocol/uri/serializer/longuriserializer.py index 3bb981f..bdd9139 100644 --- a/uprotocol/uri/serializer/longuriserializer.py +++ b/uprotocol/uri/serializer/longuriserializer.py @@ -55,7 +55,11 @@ def serialize(self, uri: UUri) -> str: sb = [] - if uri.HasField("authority"): + if ( + uri.HasField("authority") + and uri.authority.HasField("name") + and not uri.authority.name.strip() == "" + ): sb.append("//") sb.append(uri.authority.name) @@ -75,9 +79,15 @@ def build_resource_part_of_uri(uuri: UUri) -> str: sb = "/" + u_resource.name - if u_resource.instance: + if ( + u_resource.instance is not None + and not u_resource.instance.strip() == "" + ): sb += "." + u_resource.instance - if u_resource.message: + if ( + u_resource.message is not None + and not u_resource.message.strip() == "" + ): sb += "#" + u_resource.message return sb @@ -109,7 +119,7 @@ def deserialize(self, u_protocol_uri: str) -> UUri: if u_protocol_uri is None or u_protocol_uri.strip() == "": return UUri() uri = ( - u_protocol_uri[u_protocol_uri.index(":") + 1:] + u_protocol_uri[u_protocol_uri.index(":") + 1 :] if ":" in u_protocol_uri else u_protocol_uri.replace("\\", "/") ) diff --git a/uprotocol/uri/serializer/microuriserializer.py b/uprotocol/uri/serializer/microuriserializer.py index e021df5..4de3b74 100644 --- a/uprotocol/uri/serializer/microuriserializer.py +++ b/uprotocol/uri/serializer/microuriserializer.py @@ -72,6 +72,7 @@ class MicroUriSerializer(UriSerializer): IPV4_MICRO_URI_LENGTH = 12 IPV6_MICRO_URI_LENGTH = 24 UP_VERSION = 0x1 + MAX_ID_LENGTH = 255 def serialize(self, uri: UUri) -> bytes: """ @@ -109,6 +110,9 @@ def serialize(self, uri: UUri) -> bytes: byte_arr.append(address_type.value) + if maybe_uresource_id > 0xFFFF or maybe_ue_id > 0xFFFF: + return bytearray() + # URESOURCE_ID byte_arr.append(keep_8_least_significant_bits(maybe_uresource_id >> 8)) byte_arr.append(keep_8_least_significant_bits(maybe_uresource_id)) @@ -128,6 +132,9 @@ def serialize(self, uri: UUri) -> bytes: if address_type != AddressType.LOCAL: # Write the ID length if the type is ID if address_type == AddressType.ID: + # If the ID length is greater than the maximum allowed, return an empty byte[] + if len(uri.authority.id) > self.MAX_ID_LENGTH: + return bytearray() byte_arr.append( keep_8_least_significant_bits(len(uri.authority.id)) )