Remove unwrap() in integration/e2e tests#512
Conversation
Pull Request Test Coverage Report for Build 13057514318Details
💛 - Coveralls |
nothingmuch
left a comment
There was a problem hiding this comment.
cACK, partial review with a few comments.
Main takeaway is I'm not sure about when .expect() is preferred over .map_err() with format! and bubbling up...
ISTM that the benefits, in descending priority order are:
- eliminate
unwrap()to avoid vague failures without context (though?doesn't materially improve that), and to make any snippets copied from tests be better behaved in whatever context they end up in (where?does make a material difference) - simplifying types for things that should never fail
- concision helping readability
is that correct?
payjoin-cli/tests/e2e.rs
Outdated
| fn find_free_port() -> u16 { | ||
| let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); | ||
| listener.local_addr().unwrap().port() | ||
| assert!(payjoin_sent??.unwrap_or(false), "Payjoin send was not detected"); |
There was a problem hiding this comment.
I'm confused by .unwrap().unwrap_or(Some(false)).unwrap() becoming payjoin_sent??.unwrap_or(false).
It's a Result<Result<Option<bool>, Elapsed>, JoinError>, where the Option originates from the mpsc's recv(), the `bool is the value sent through the channel.
So isn't this equivalent to payjoin_sent.unwrap().unwrap().unwrap_or(false) instead, i.e. that a timeout bubbles up instead of becoming an assertion error? isn't it more appropriate for the assertion to fail in case of a timeout in which case .unwrap_or(Some(false)).ok_or(...)? would be closer in spirit to what it was, with i guess an anyhow error in the ... indicating the mpsc recv should have worked
also, using await? on the task seems like it reduce some of the noise... if you agree with this suggestion and the previous paragraph, i guess this implies the unwrap_or(Some(false).ok_or() is better done inside the task, so that await?? can bubble the task joining error if any, followed by the ok_or, and leaving payjoin_sent as just a bool?
There was a problem hiding this comment.
Great catch! I applied your suggestion, with expect instead of ok_or since the rx channel should never close early.
| pub fn take_directory_handle(&mut self) -> Option<JoinHandle<Result<(), BoxSendSyncError>>> { | ||
| self.directory.1.take() | ||
| pub fn take_directory_handle(&mut self) -> JoinHandle<Result<(), BoxSendSyncError>> { | ||
| self.directory.1.take().expect("directory handle not found") |
There was a problem hiding this comment.
hmm, i prefer the simpler type here over expecting the caller to bubble this up, since this kind of thing should never fail a test but indicates the test environment is not as expected, having an expect message puts that kind of failure into context...
but i want to make sure i'm not missing anything about tests returning Result, is it equivalent to the test runner doing .unwrap() for us? i found this mentioned in rust by example, which links to a seemingly stale doc link that leads back to rust by example discussing this in the context of main (https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.html) and ? is ~impossible to websearch for
There was a problem hiding this comment.
Yes, when an Error result bubbles up all the way to the test runner it fails the test and prints a debug representation of the error. The way it's displayed is slightly cleaner than when calling unwrap directly, e.g.:
unwrap:
---- integration::v1::v1_to_v1_p2pkh stdout ----
thread 'integration::v1::v1_to_v1_p2pkh' panicked at payjoin/tests/integration.rs:998:51:
called `Result::unwrap()` on an `Err` value: PsbtEncoding(ConsensusEncoding(Io(Error { kind: UnexpectedEof, error: None })))
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
?:
---- integration::v1::v1_to_v1_p2pkh stdout ----
Error: PsbtEncoding(ConsensusEncoding(Io(Error { kind: UnexpectedEof, error: None })))
payjoin-test-utils/src/lib.rs
Outdated
| .danger_accept_invalid_certs(true) | ||
| .use_rustls_tls() | ||
| .add_root_certificate(reqwest::tls::Certificate::from_der(cert_der.as_slice()).unwrap())) | ||
| .add_root_certificate(reqwest::tls::Certificate::from_der(cert_der.as_slice())?)) |
There was a problem hiding this comment.
in line with the remark on take_... variants, is this perhaps better handled with .expect()?
5ca026e to
988ded4
Compare
Yes - I'd add another benefit which is that |
DanGould
left a comment
There was a problem hiding this comment.
ACK 988ded4
I left some comments on further cleanups, but I think everything here is pointed in the right direction i.e. cleans up tech debt rather than takes new on and don't see big reasons not to merge and address the concerns in a follow up referencing the issues stated here.
| #[cfg(feature = "v2")] | ||
| #[tokio::test(flavor = "multi_thread", worker_threads = 4)] | ||
| async fn send_receive_payjoin() { | ||
| async fn send_receive_payjoin() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { |
There was a problem hiding this comment.
nit: Why not use BoxSendSyncError here?
There was a problem hiding this comment.
It would have to be imported in mod e2e but that results in a "unused" warning when the v2 feature is disabled. I suppose we could feature-gate the import, or put the v1 and v2 tests in separate modules like we do in integration.rs
There was a problem hiding this comment.
That's a good reason. It would also be more organized to separate v1, v2 modules (and even separate files that use super::* but is not a necessity.
988ded4 to
2f14846
Compare
|
My latest push addresses the minor issues Dan brought up, and should be good to merge as-is. |
| #[cfg(feature = "v2")] | ||
| #[tokio::test(flavor = "multi_thread", worker_threads = 4)] | ||
| async fn send_receive_payjoin() { | ||
| async fn send_receive_payjoin() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { |
There was a problem hiding this comment.
That's a good reason. It would also be more organized to separate v1, v2 modules (and even separate files that use super::* but is not a necessity.
Partially address #487.
There are other places to clean up, notably unit tests, that can be addressed in later PRs.
The commit messages might be a little repetitive but I wanted to keep each commit bite-sized for easier review. I can squash them if preferred.