-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix #2383: Use "service" if service type missing #2385
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good as it is now although there can be improvements.
let service_type = if config.service_type.is_empty() { | ||
"service".to_string() | ||
} else { | ||
config.service_type.clone() | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implementation is defenitely fine as of now, especially with the restricted time limit for the new release.
However, I've got the feeling that the ideal solution is to change the tedge_config API; If user tries to set an empty string, it works the same as "unset". The "service" is already used as the default value of service.type
. It's a little pity that we need to hard-code the same value here.
) -> Message { | ||
Message::new( | ||
) -> Result<Message, InvalidValueError> { | ||
// TODO: most of this noise can be eliminated by implementing `Serialize`/`Deserialize` for smartrest format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you said here, why not implementing the representation struct for SmartREST 101 and 102? We already have them for other message IDs, for operations.
https://github.com/thin-edge/thin-edge.io/blob/main/crates/core/c8y_api/src/smartrest/smartrest_serializer.rs
Sorry forgot to check compilation result.
|
||
#[error("Unexpected error")] | ||
UnexpectedError(#[from] anyhow::Error), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error case is unused.
In all cases, I don't see what's your intent when you write Unexpected part is supposed to denote that the error was not related due to invalid input, or the user doing something wrong, but some unexpected conditions occured that makes it so that the request cannot be completed. Like a panic!, it can be used when there is a logic error on part of the programmer, but unlike panic! it doesn't crash the entire program.
ConversionError
is already a ball of mug and I don't see how adding such an open case can help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used in crates/extensions/c8y_mapper_ext/src/converter.rs:290
and crates/extensions/c8y_mapper_ext/src/converter.rs:308
via ?
.
The motivation was the same as behind #2353 (comment): by adding a variant that has #[from] anyhow:Error
, if in the future we have to handle another type of error, then we can just use .context()
to transform it into an anyhow::Error
and then ?
to convert it into ConversionError::UnexpectedError
.
Additional enum variants are only useful as long as the calling code can reasonably match on them. In this case, UnexpectedError
doesn't fix ConversionError
much, but hopefully it introduces an idea of an opaque error, that we can start using more in the future to stop adding more variants, and also perhaps turn some of the variants we're not matching on into opaque errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
) -> Message { | ||
Message::new( | ||
) -> Result<Message, InvalidValueError> { | ||
if child_id.is_empty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that the scope of this PR is limited to services only, but since you added this check here, why not extend it to device_name
and device_type
as well?
let service_creation_message = output | ||
.into_iter() | ||
.find(|m| m.topic.name == SMARTREST_PUBLISH_TOPIC) | ||
.expect("service creation message should be present"); | ||
|
||
let mut smartrest_fields = service_creation_message.payload_str().unwrap().split(','); | ||
|
||
assert_eq!(smartrest_fields.next().unwrap(), "102"); | ||
assert_eq!( | ||
smartrest_fields.next().unwrap(), | ||
format!("{}:device:main:service:service1", converter.device_name) | ||
); | ||
assert_eq!(smartrest_fields.next().unwrap(), "service"); | ||
assert_eq!(smartrest_fields.next().unwrap(), "service1"); | ||
assert_eq!(smartrest_fields.next().unwrap(), "up"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use that helper.
let service_creation_message = output | |
.into_iter() | |
.find(|m| m.topic.name == SMARTREST_PUBLISH_TOPIC) | |
.expect("service creation message should be present"); | |
let mut smartrest_fields = service_creation_message.payload_str().unwrap().split(','); | |
assert_eq!(smartrest_fields.next().unwrap(), "102"); | |
assert_eq!( | |
smartrest_fields.next().unwrap(), | |
format!("{}:device:main:service:service1", converter.device_name) | |
); | |
assert_eq!(smartrest_fields.next().unwrap(), "service"); | |
assert_eq!(smartrest_fields.next().unwrap(), "service1"); | |
assert_eq!(smartrest_fields.next().unwrap(), "up"); | |
assert_messages_matching( | |
&messages, | |
[ | |
( | |
SMARTREST_PUBLISH_TOPIC, | |
"102,test-device:device:main:service:service1,service,service1,up".into(), | |
), | |
], | |
); |
Just noticed all the compilation failures. But the planned code changes look fine.
74c1208
to
7708405
Compare
Codecov Report
Additional details and impacted files
|
Robot Results
|
@Bravo555 Looking at the system test report the error looks to be legitimate. The following error was found in the log output of the test: Test Case: Test if all c8y services using default service type when service type configured as empty
|
@reubenmiller Yes, I missed one place where empty service type was passed to another actor. It seems to be that handling it on the |
7708405
to
3d44472
Compare
Some additions: 1. A C8y converter test was added to make sure that the emitted service creation message is valid if `service.type` is empty. 2. `c8y_api::inventory` functions which created C8y smartrest messages were changed to return `Result`. Currently we only check if values marked as mandatory in [SmartREST reference documentation][1] are not empty, but we could do more validation in the future. 3. Added `ConversionError::UnexpectedError` variant, which can be constructed from an `anyhow::Error`. _Unexpected_ part is supposed to denote that the error was not related due to invalid input, or the user doing something wrong, but some unexpected conditions occured that makes it so that the request cannot be completed. Like a `panic!`, it can be used when there is a logic error on part of the programmer, but unlike `panic!` it doesn't crash the entire program. More about the idea [here][2]. [1]: https://cumulocity.com/guides/reference/smartrest-two/#102 [2]: https://www.lpalmieri.com/posts/error-handling-rust/#avoid-ball-of-mud-error-enums
3d44472
to
65bc1ff
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved, to include this fix in the upcoming release.
However, this will have to be addressed at the config level as suggested by @rina23q and acknowledged by @Bravo555 as a less fragile solution
Proposed changes
Some additions:
A C8y converter test was added to make sure that the emitted service creation message is valid if
service.type
is empty.c8y_api::inventory
functions which created C8y smartrest messages were changed to returnResult
. Currently we only check if values marked as mandatory in SmartREST reference documentation are not empty, but we could do more validation in the future.Added
ConversionError::UnexpectedError
variant, which can be constructed from ananyhow::Error
.Unexpected part is supposed to denote that the error was not related due to invalid input, or the user doing something wrong, but some unexpected conditions occured that makes it so that the request cannot be completed. Like a
panic!
, it can be used when there is a logic error on part of the programmer, but unlikepanic!
it doesn't crash the entire program. More about the idea here.Types of changes
Paste Link to the issue
Checklist
cargo fmt
as mentioned in CODING_GUIDELINEScargo clippy
as mentioned in CODING_GUIDELINESFurther comments