-
Notifications
You must be signed in to change notification settings - Fork 124
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
Any suggested pattern for closing the Client on test failure? #250
Comments
+1 Following.. |
Thanks for the detailed write-up, and sorry for the late reply! This is indeed a thing that sort of plagues the async ecosystem, and has, to my knowledge, no current good solutions. Asynchronous dropping is simply really annoying, and when paired with panics, it's even more of a pain. Now, the good news is that tokio will catch panics from tasks and not shut down the runtime. And, since the client is just a channel sender: Line 40 in bce77b0
A panic in the thing that holds the client shouldn't automatically terminate the actual connection (which is held by the Lines 520 to 527 in bce77b0
However, I suspect what happens in your case is that you have something that boils down to this: #[tokio::test]
async fn foo() {
let client = /* ... */;
assert!(false);
} What happens here is that #[test]
fn foo() {
tokio::runtime::Runtime::new()
.block_on(async move {
let client = /* ... */;
// real test code
assert!(false);
}); It uses #[test]
fn foo() {
tokio::runtime::Runtime::new()
.block_on(async move {
let client1 = /* ... */;
let client = client1.clone();
let r = tokio::spawn(async move {
// real test code
assert!(false);
}).await;
client1.close().await;
if let Err(e) = r {
std::panic::resume_unwind(e);
}
}); That way, even if the real test code panics, you'll make sure you close the session. You could probably wrap this in a little nice macro so that you don't have to repeat it for every test. Alternatively, you may be able to utilize the Best of luck! |
Oh, and |
Another option is to make use of something like what tokio uses to catch the panics from futures under the hood: async fn run_with_client<F, Fut, T>(f: F) -> T
where
F: FnOnce(&mut Client) -> Fut,
Fut: Future<Output = T>,
{
let mut client = Client;
let res = futures::future::FutureExt::catch_unwind(AssertUnwindSafe(f(&mut client))).await;
client.close().await;
match res {
Ok(t) => t,
Err(panic) => std::panic::resume_unwind(panic),
}
} |
(I'm not a fan of "question" issues, but I'm at the end of my tether here, so please forgive me. In my defence, if I can get even the slightest hint towards a solution to my problem, I promise a lovingly hand-crafted docs PR that will make old men weep and small children stare in awe.)
I've started using fantoccini for doing headless UI testing, and it's wonderful. Knowing that I'm testing against real browsers, doing real things, with JS and everything, is absolute awesomesauce. I've found fantoccini easy as heckfire and delightful to use. Thank you for building it.
Except! Whenever a test fails for any reason, that means that the client doesn't get closed, which means the session never gets closed, which means that all the bad things predicted in the
Client::close()
docs happen.Since Rust's whole testing philosophy is predicated on "assertion failed? time to bail!", I figure I'm not going to be able to avoid the panic on failure issue, so I need a workaround so that I don't have to constantly restart geckodriver. However, so far, I haven't been able to actually make anything work. On the assumption that I'm not the first person to have come up against this, and that I'm absolutely terrible with anything involving async code, I'm assuming there's a solution out there.
What I've tried so far:
AsyncDrop
trait (which has only just recently appeared) on a wrapper type. I got that to compile, but theasync_drop
method never seemed to ever actually get called. I don't like relying on unstable features anyway, so I didn't spend ages on trying to figure it out.It's entirely possible that any of the above approaches might work, in the hands of someone who knows what they're doing, but I haven't been able to get it work. Alternately, there may very well be dozens of other approaches that I just haven't thought of.
What I'm doing now is going completely panic-free in my tests, putting all the "interesting" code in a separate function that I pass the client, and having that function return a Result that's Err if anything went wrong or a condition wasn't met. The top-level test method then closes the client and panics on Err. This works, but it's fugly as all get out, and thoroughly unergonomic (all my hard-earned assert!() finger macros, just... gone).
In short... halp!
The text was updated successfully, but these errors were encountered: