Skip to content

Commit 964e1de

Browse files
committed
[#249] Cover all UAttributes spec items
Added missing references to specitems to existing code and/or added some new code that implements uncovered items.
1 parent c8c9b61 commit 964e1de

File tree

4 files changed

+242
-20
lines changed

4 files changed

+242
-20
lines changed

Diff for: src/uattributes.rs

+17
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub use upriority::*;
2323
pub use crate::up_core_api::uattributes::*;
2424
use crate::UUID;
2525

26+
const UPRIORITY_DEFAULT: UPriority = UPriority::UPRIORITY_CS1;
27+
2628
#[derive(Debug)]
2729
pub enum UAttributesError {
2830
ValidationError(String),
@@ -57,6 +59,15 @@ impl std::fmt::Display for UAttributesError {
5759
impl std::error::Error for UAttributesError {}
5860

5961
impl UAttributes {
62+
/// Checks if a given priority class is the default priority class.
63+
///
64+
/// Messages that do not have a priority class set explicity, are assigned to
65+
/// the default prioritiy class.
66+
pub(crate) fn is_default_priority(prio: UPriority) -> bool {
67+
// [impl->dsn~up-attributes-priority~1]
68+
prio == UPRIORITY_DEFAULT
69+
}
70+
6071
/// Checks if these are the attributes for a Publish message.
6172
///
6273
/// # Examples
@@ -135,9 +146,11 @@ impl UAttributes {
135146
pub fn check_expired(&self) -> Result<(), UAttributesError> {
136147
let ttl = match self.ttl {
137148
Some(t) if t > 0 => u64::from(t),
149+
// [impl->dsn~up-attributes-ttl~1]
138150
_ => return Ok(()),
139151
};
140152

153+
// [impl->dsn~up-attributes-ttl-timeout~1]
141154
if let Some(creation_time) = self.id.as_ref().and_then(UUID::get_time) {
142155
let delta = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
143156
Ok(duration) => {
@@ -182,11 +195,15 @@ mod tests {
182195
}
183196

184197
#[test_case(None, None, false; "for message without ID nor TTL")]
198+
// [utest->dsn~up-attributes-ttl~1]
185199
#[test_case(None, Some(0), false; "for message without ID with TTL 0")]
186200
#[test_case(None, Some(500), false; "for message without ID with TTL")]
187201
#[test_case(Some(build_n_ms_in_past(1000)), None, false; "for message with ID without TTL")]
202+
// [utest->dsn~up-attributes-ttl~1]
188203
#[test_case(Some(build_n_ms_in_past(1000)), Some(0), false; "for message with ID and TTL 0")]
204+
// [utest->dsn~up-attributes-ttl-timeout~1]
189205
#[test_case(Some(build_n_ms_in_past(1000)), Some(500), true; "for message with ID and expired TTL")]
206+
// [utest->dsn~up-attributes-ttl-timeout~1]
190207
#[test_case(Some(build_n_ms_in_past(1000)), Some(2000), false; "for message with ID and non-expired TTL")]
191208
fn test_is_expired(id: Option<UUID>, ttl: Option<u32>, should_be_expired: bool) {
192209
let attributes = UAttributes {

Diff for: src/uattributes/uattributesvalidator.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub trait UAttributesValidator: Send {
5959
///
6060
/// Returns an error if [`UAttributes::id`] does not contain a [valid uProtocol UUID](`crate::UUID::is_uprotocol_uuid`).
6161
fn validate_id(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
62+
// [impl->dsn~up-attributes-id~1]
6263
if attributes
6364
.id
6465
.as_ref()
@@ -253,6 +254,7 @@ impl UAttributesValidator for PublishValidator {
253254
/// * if the source URI contains any wildcards, or
254255
/// * if the source URI has a resource ID of 0.
255256
fn validate_source(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
257+
// [impl->dsn~up-attributes-publish-source~1]
256258
if let Some(source) = attributes.source.as_ref() {
257259
source.verify_event().map_err(|e| {
258260
UAttributesError::validation_error(format!("Invalid source URI: {}", e))
@@ -270,6 +272,7 @@ impl UAttributesValidator for PublishValidator {
270272
///
271273
/// If the [`UAttributes::sink`] property contains any URI, an error is returned.
272274
fn validate_sink(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
275+
// [impl->dsn~up-attributes-publish-sink~1]
273276
if attributes.sink.as_ref().is_some() {
274277
Err(UAttributesError::validation_error(
275278
"Attributes for a publish message must not contain a sink URI",
@@ -329,6 +332,7 @@ impl UAttributesValidator for NotificationValidator {
329332
/// * if the source URI is an RPC response URI, or
330333
/// * if the source URI contains any wildcards.
331334
fn validate_source(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
335+
// [impl->dsn~up-attributes-notification-source~1]
332336
if let Some(source) = attributes.source.as_ref() {
333337
if source.is_rpc_response() {
334338
Err(UAttributesError::validation_error(
@@ -356,6 +360,7 @@ impl UAttributesValidator for NotificationValidator {
356360
/// * if the sink URI's resource ID is != 0, or
357361
/// * if the sink URI contains any wildcards.
358362
fn validate_sink(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
363+
// [impl->dsn~up-attributes-notification-sink~1]
359364
if let Some(sink) = attributes.sink.as_ref() {
360365
if !sink.is_notification_destination() {
361366
Err(UAttributesError::validation_error(
@@ -384,6 +389,7 @@ impl RequestValidator {
384389
///
385390
/// Returns an error if [`UAttributes::ttl`] (time-to-live) is empty or contains a value less than 1.
386391
pub fn validate_ttl(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
392+
// [impl->dsn~up-attributes-request-ttl~1]
387393
match attributes.ttl {
388394
Some(ttl) if ttl > 0 => Ok(()),
389395
Some(invalid_ttl) => Err(UAttributesError::validation_error(format!(
@@ -443,6 +449,7 @@ impl UAttributesValidator for RequestValidator {
443449
/// Returns an error if the [`UAttributes::source`] property does not contain a valid reply-to-address according to
444450
/// [`UUri::verify_rpc_response`].
445451
fn validate_source(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
452+
// [impl->dsn~up-attributes-request-source~1]
446453
if let Some(source) = attributes.source.as_ref() {
447454
UUri::verify_rpc_response(source).map_err(|e| {
448455
UAttributesError::validation_error(format!("Invalid source URI: {}", e))
@@ -459,6 +466,7 @@ impl UAttributesValidator for RequestValidator {
459466
/// Returns an erro if the [`UAttributes::sink`] property does not contain a URI representing a method according to
460467
/// [`UUri::verify_rpc_method`].
461468
fn validate_sink(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
469+
// [impl->dsn~up-attributes-request-sink~1]
462470
if let Some(sink) = attributes.sink.as_ref() {
463471
UUri::verify_rpc_method(sink)
464472
.map_err(|e| UAttributesError::validation_error(format!("Invalid sink URI: {}", e)))
@@ -564,6 +572,7 @@ impl UAttributesValidator for ResponseValidator {
564572
/// Returns an error if the [`UAttributes::source`] property does not contain a URI representing a method according to
565573
/// [`UUri::verify_rpc_method`].
566574
fn validate_source(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
575+
// [impl->dsn~up-attributes-response-source~1]
567576
if let Some(source) = attributes.source.as_ref() {
568577
UUri::verify_rpc_method(source).map_err(|e| {
569578
UAttributesError::validation_error(format!("Invalid source URI: {}", e))
@@ -581,6 +590,7 @@ impl UAttributesValidator for ResponseValidator {
581590
/// Returns an error if the [`UAttributes::sink`] property does not contain a valid reply-to-address according to
582591
/// [`UUri::verify_rpc_response`].
583592
fn validate_sink(&self, attributes: &UAttributes) -> Result<(), UAttributesError> {
593+
// [impl->dsn~up-attributes-response-sink~1]
584594
if let Some(sink) = &attributes.sink.as_ref() {
585595
UUri::verify_rpc_response(sink)
586596
.map_err(|e| UAttributesError::validation_error(format!("Invalid sink URI: {}", e)))
@@ -637,11 +647,16 @@ mod tests {
637647
}
638648

639649
#[test_case(Some(UUID::build()), Some(publish_topic()), None, None, true; "succeeds for topic only")]
650+
// [utest->dsn~up-attributes-publish-sink~1]
640651
#[test_case(Some(UUID::build()), Some(publish_topic()), Some(destination()), None, false; "fails for message containing destination")]
641652
#[test_case(Some(UUID::build()), Some(publish_topic()), None, Some(100), true; "succeeds for valid attributes")]
653+
// [utest->dsn~up-attributes-publish-source~1]
642654
#[test_case(Some(UUID::build()), None, None, None, false; "fails for missing topic")]
655+
// [utest->dsn~up-attributes-publish-source~1]
643656
#[test_case(Some(UUID::build()), Some(UUri { resource_id: 0x54, ..Default::default()}), None, None, false; "fails for invalid topic")]
657+
// [utest->dsn~up-attributes-id~1]
644658
#[test_case(None, Some(publish_topic()), None, None, false; "fails for missing message ID")]
659+
// [utest->dsn~up-attributes-id~1]
645660
#[test_case(
646661
Some(UUID {
647662
// invalid UUID version (not 0b1000 but 0b1010)
@@ -689,14 +704,20 @@ mod tests {
689704
}
690705
}
691706

707+
// [utest->dsn~up-attributes-notification-sink~1]
692708
#[test_case(Some(UUID::build()), Some(origin()), None, None, false; "fails for missing destination")]
693709
#[test_case(Some(UUID::build()), Some(origin()), Some(destination()), None, true; "succeeds for both origin and destination")]
694710
#[test_case(Some(UUID::build()), Some(origin()), Some(destination()), Some(100), true; "succeeds for valid attributes")]
711+
// [utest->dsn~up-attributes-notification-source~1]
695712
#[test_case(Some(UUID::build()), None, Some(destination()), None, false; "fails for missing origin")]
713+
// [utest->dsn~up-attributes-notification-source~1]
696714
#[test_case(Some(UUID::build()), Some(UUri::default()), Some(destination()), None, false; "fails for invalid origin")]
715+
// [utest->dsn~up-attributes-notification-sink~1]
697716
#[test_case(Some(UUID::build()), Some(origin()), Some(UUri { ue_id: 0xabcd, ue_version_major: 0x01, resource_id: 0x0011, ..Default::default() }), None, false; "fails for invalid destination")]
698717
#[test_case(Some(UUID::build()), None, None, None, false; "fails for neither origin nor destination")]
718+
// [utest->dsn~up-attributes-id~1]
699719
#[test_case(None, Some(origin()), Some(destination()), None, false; "fails for missing message ID")]
720+
// [utest->dsn~up-attributes-id~1]
700721
#[test_case(
701722
Some(UUID {
702723
// invalid UUID version (not 0b1000 but 0b1010)
@@ -746,7 +767,9 @@ mod tests {
746767

747768
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), None, Some(2000), Some(UPriority::UPRIORITY_CS4), None, true; "succeeds for mandatory attributes")]
748769
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), Some(1), Some(2000), Some(UPriority::UPRIORITY_CS4), Some(String::from("token")), true; "succeeds for valid attributes")]
770+
// [utest->dsn~up-attributes-id~1]
749771
#[test_case(None, Some(method_to_invoke()), Some(reply_to_address()), Some(1), Some(2000), Some(UPriority::UPRIORITY_CS4), Some(String::from("token")), false; "fails for missing message ID")]
772+
// [utest->dsn~up-attributes-id~1]
750773
#[test_case(
751774
Some(UUID {
752775
// invalid UUID version (not 0b1000 but 0b1010)
@@ -762,14 +785,20 @@ mod tests {
762785
None,
763786
false;
764787
"fails for invalid message id")]
788+
// [utest->dsn~up-attributes-request-source~1]
765789
#[test_case(Some(UUID::build()), Some(method_to_invoke()), None, None, Some(2000), Some(UPriority::UPRIORITY_CS4), None, false; "fails for missing reply-to-address")]
790+
// [utest->dsn~up-attributes-request-source~1]
766791
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(UUri { resource_id: 0x0001, ..Default::default()}), None, Some(2000), Some(UPriority::UPRIORITY_CS4), None, false; "fails for invalid reply-to-address")]
792+
// [utest->dsn~up-attributes-request-sink~1]
767793
#[test_case(Some(UUID::build()), None, Some(reply_to_address()), None, Some(2000), Some(UPriority::UPRIORITY_CS4), None, false; "fails for missing method-to-invoke")]
794+
// [utest->dsn~up-attributes-request-sink~1]
768795
#[test_case(Some(UUID::build()), Some(UUri::default()), Some(reply_to_address()), None, Some(2000), Some(UPriority::UPRIORITY_CS4), None, false; "fails for invalid method-to-invoke")]
769796
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), Some(1), Some(2000), None, None, false; "fails for missing priority")]
770797
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), Some(1), Some(2000), Some(UPriority::UPRIORITY_CS3), None, false; "fails for invalid priority")]
798+
// [utest->dsn~up-attributes-request-ttl~1]
771799
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), None, None, Some(UPriority::UPRIORITY_CS4), None, false; "fails for missing ttl")]
772-
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), None, Some(0), Some(UPriority::UPRIORITY_CS4), None, false; "fails for ttl < 1")]
800+
// [utest->dsn~up-attributes-request-ttl~1]
801+
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), None, Some(0), Some(UPriority::UPRIORITY_CS4), None, false; "fails for ttl = 0")]
773802
#[test_case(Some(UUID::build()), Some(method_to_invoke()), Some(reply_to_address()), Some(1), Some(2000), Some(UPriority::UPRIORITY_CS4), None, true; "succeeds for valid permission level")]
774803
#[allow(clippy::too_many_arguments)]
775804
fn test_validate_attributes_for_rpc_request_message(
@@ -815,7 +844,9 @@ mod tests {
815844

816845
#[test_case(Some(UUID::build()), Some(reply_to_address()), Some(method_to_invoke()), Some(UUID::build()), None, None, Some(UPriority::UPRIORITY_CS4), true; "succeeds for mandatory attributes")]
817846
#[test_case(Some(UUID::build()), Some(reply_to_address()), Some(method_to_invoke()), Some(UUID::build()), Some(EnumOrUnknown::from(UCode::CANCELLED)), Some(100), Some(UPriority::UPRIORITY_CS4), true; "succeeds for valid attributes")]
847+
// [utest->dsn~up-attributes-id~1]
818848
#[test_case(None, Some(reply_to_address()), Some(method_to_invoke()), Some(UUID::build()), Some(EnumOrUnknown::from(UCode::CANCELLED)), Some(100), Some(UPriority::UPRIORITY_CS4), false; "fails for missing message ID")]
849+
// [utest->dsn~up-attributes-id~1]
819850
#[test_case(
820851
Some(UUID {
821852
// invalid UUID version (not 0b1000 but 0b1010)
@@ -831,9 +862,13 @@ mod tests {
831862
Some(UPriority::UPRIORITY_CS4),
832863
false;
833864
"fails for invalid message id")]
865+
// [utest->dsn~up-attributes-response-sink~1]
834866
#[test_case(Some(UUID::build()), None, Some(method_to_invoke()), Some(UUID::build()), None, None, Some(UPriority::UPRIORITY_CS4), false; "fails for missing reply-to-address")]
867+
// [utest->dsn~up-attributes-response-sink~1]
835868
#[test_case(Some(UUID::build()), Some(UUri { resource_id: 0x0001, ..Default::default()}), Some(method_to_invoke()), Some(UUID::build()), None, None, Some(UPriority::UPRIORITY_CS4), false; "fails for invalid reply-to-address")]
869+
// [utest->dsn~up-attributes-response-source~1]
836870
#[test_case(Some(UUID::build()), Some(reply_to_address()), None, Some(UUID::build()), None, None, Some(UPriority::UPRIORITY_CS4), false; "fails for missing invoked-method")]
871+
// [utest->dsn~up-attributes-response-source~1]
837872
#[test_case(Some(UUID::build()), Some(reply_to_address()), Some(UUri::default()), Some(UUID::build()), None, None, Some(UPriority::UPRIORITY_CS4), false; "fails for invalid invoked-method")]
838873
#[test_case(Some(UUID::build()), Some(reply_to_address()), Some(method_to_invoke()), Some(UUID::build()), Some(EnumOrUnknown::from(UCode::CANCELLED)), None, Some(UPriority::UPRIORITY_CS4), true; "succeeds for valid commstatus")]
839874
#[test_case(Some(UUID::build()), Some(reply_to_address()), Some(method_to_invoke()), Some(UUID::build()), Some(EnumOrUnknown::from_i32(-42)), None, Some(UPriority::UPRIORITY_CS4), false; "fails for invalid commstatus")]

Diff for: src/umessage.rs

+8
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,14 @@ impl UMessage {
141141
self.attributes
142142
.as_ref()
143143
.and_then(|attribs| attribs.priority.enum_value().ok())
144+
// [impl->dsn~up-attributes-priority~1]
145+
.map(|prio| {
146+
if prio == UPriority::UPRIORITY_UNSPECIFIED {
147+
UPriority::UPRIORITY_CS1
148+
} else {
149+
prio
150+
}
151+
})
144152
}
145153

146154
/// Gets this message's priority.

0 commit comments

Comments
 (0)