Skip to content
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

[WIP] Add async tests #32

Merged
merged 0 commits into from
Sep 7, 2020
Merged

[WIP] Add async tests #32

merged 0 commits into from
Sep 7, 2020

Conversation

bbqsrc
Copy link
Member

@bbqsrc bbqsrc commented Jul 29, 2019

I've begun adding async support to Cucumber.

Async test running functionality

  • Running async tests
  • Basic async steps
  • Regex async steps
  • Regex typed async steps
  • Ability to configure whether scenarios should run in parallel

Async ergonomics

  • Add support for async tests
  • Add support for async regex tests
  • Ability to select executor to use
  • Re-implement nice printed output
  • Document usage

@bbqsrc bbqsrc force-pushed the feature/async branch 2 times, most recently from 728d500 to 63ef56f Compare July 29, 2019 19:13
@ghost

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@ghost

This comment has been minimized.

@ghost

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@ghost

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@ghost

This comment has been minimized.

Copy link
Contributor

@killercup killercup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this because IMHO the main advantage of async/await as a lang feature is that "normalizes" the usage of async code. Ideally, a user of cucumber can expect async functions to just work. The amount of code to maintain will only increase with merging this, sure, but implementation still seems pretty straightforward.

I've noted a few minor things that could be refactored, but I've not read every single line. Maybe some reorganization can make parts of this more readable, too, like representing the test types like {sync,async}x{static name,regex} (I think you already mentioned that when talking about proc macro stuff) and introducing traits to "overload" the builder API and reduce the API surface.

src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/output/default.rs Outdated Show resolved Hide resolved
src/output/default.rs Outdated Show resolved Hide resolved
.travis.yml Outdated Show resolved Hide resolved
@bbqsrc bbqsrc mentioned this pull request Jan 5, 2020
3 tasks
@humb1t

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@humb1t

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@humb1t

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@humb1t

This comment has been minimized.

@humb1t

This comment has been minimized.

@bbqsrc

This comment has been minimized.

@bbqsrc
Copy link
Member Author

bbqsrc commented Jan 12, 2020

My current work on this, inspired by @humb1t, is on the develop branch.

@bbqsrc
Copy link
Member Author

bbqsrc commented Jan 14, 2020

Updated the feature/async branch to the work done on develop so far.

The old branch is now feature/async-old.

@nbigaouette
Copy link

Would love to see async support. Without it I cannot use the crate for a specific project :(

@bbqsrc
Copy link
Member Author

bbqsrc commented Apr 30, 2020

I would too, but time is a dictator! 😄

What's your specific use case? I might be able to help with a workaround or other advice.

@nbigaouette
Copy link

I understand the time constraint, no worry!

I would like to automate some end-to-end testing of a complex system which includes interacting with a webapp, Azure cloud and a Windows machine (🤯).

I can manually do this as I have all the required building blocks, but I would have preferred having a kind of framework to dictate some kind of structure to this testing, including nice output and stats about failures and success. I think it fits nicely in BDD and cucumber-rust seems to be the most active BDD crate.

The building blocks I mentioned are async (tokio) so I absolutely need a runtime to drive them.

@bbqsrc
Copy link
Member Author

bbqsrc commented May 20, 2020

@nbigaouette I'll be working on this again on the weekend, so I'd appreciate it if you have another try next week. If I get it done, there'll be documentation, and I'll try to ensure that your use case actually works. 😄

@bbqsrc
Copy link
Member Author

bbqsrc commented May 24, 2020

@nbigaouette I added an async fn to the test in this branch. I'm going to merge it into develop and I would appreciate it if you could make a pull request against that that demonstrates the issue you were having. 😄

@nbigaouette
Copy link

Thanks for this! I unfortunately did not have time to put on this last week.

I've opened a PR (#51) with a simple modification to the method. You can see the compilation failure in CI: https://travis-ci.org/github/bbqsrc/cucumber-rust/jobs/690704653

Before trying out cucumber, I expected having a single MyWorld instance with a couple of mutable methods on it. This way I can setup initial conditions and let the given steps mutate this state into what I want to test. All this expects running the tests sequentially. And since what I want to test is an external system, I cannot run tests in parallel as the tests steps will mutate that system.

I could try to work on a immutable self to bypass this, but I know I did stored some kind of states between the steps (f.e. number of items found in the system before an action is taken).

@bbqsrc
Copy link
Member Author

bbqsrc commented May 24, 2020

I'll have a look, thanks!

@bbqsrc
Copy link
Member Author

bbqsrc commented May 24, 2020

@nbigaouette I have pushed to develop, does the change I made to cucumber_builder help?

@bbqsrc
Copy link
Member Author

bbqsrc commented May 24, 2020

@nbigaouette also really really want to change CI from Travis to Github Actions, if you have any interest in doing that, I'd appreciate it (I do enough CI for my day job that any moment not thinking about this is a moment of bliss hahaha) - made an issue for that #52

@nbigaouette
Copy link

Ok, so wrapping the async block in a std::panic::AssertUnwindSafe() did the trick.

Will that be required for or is there something more ergonomic in the pipeline?

I'll next try the develop branch in my project...

@bbqsrc
Copy link
Member Author

bbqsrc commented May 25, 2020

@nbigaouette this is, shall we say, the "primitive" implementation. Once we've got this down, I will make a procedural macro that hides the dirtiness so we can write tests more naturally.

Something like steps.given(#[step] async |world, _step| { ... }), as we can put attributes in that position now in procedural macros.

As they say, premature optimisation is the root of all evil. 😄

@AidaPaul
Copy link
Contributor

After playing with it I have few notes about the events regarding Scenario Events API. Namely consider:

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScenarioEvent {
    Starting,
    Background(Rc<gherkin::Step>, StepEvent),
    Step(Rc<gherkin::Step>, StepEvent),
    Skipped,
    Passed,
    Failed,
}

Every step and background ends in one way or another, there is no limbo for them. And yet if you want to handle either of the three possible handles you must tackle it as separate event, one which doesn't get the details about what has failed, as this is only provided in Background and Step. This means that if you want either of the finishing Events to know what is it working with, you must manage the context yourself. That has a long term issue if we ever want to create parallel runners as managing this context will become problematic.

Although more importantly I think the API right now could be much better if we simply reduced it to structure like this:

pub enum ResultType {
    Success,
    Failure,
    Skipped
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScenarioEvent {
    PreScenario,
    Background(Rc<gherkin::Step>, StepEvent, Result: ResultType),
    Step(Rc<gherkin::Step>, StepEvent, Result: ResultType),
    PostScenario
}

And similar implementation for the steps. This way you are only processing the actual thing that happened (scenario executed, step ran, etc) and have all the context needed available right away, without the separate actions multiple events. I think that would be a much clearer result and save us a lot of annoyance down the line.

@bbqsrc
Copy link
Member Author

bbqsrc commented May 28, 2020

Mm, I think in either case managing context is going to be necessary, due to the interplay between rules and scenarios. I can, however, have the failed step propagate its failure to the Failed arms of all the Scenario and Rule events.

I have also considered parallelization while designing this. My decision was that the synchronisation point would be up to the stream sending the output events, so in a parallel mode, you would get a serial batch of step events for each scenario that runs. So in that case, it would also still make sense for a ScenarioEvent to have some kind of StepsSummary argument for the conclusion events.

I'm also wary of separating out the completion result into its own type, we had done something similar before and it became rather complicated as distinguishing between a step result from a scenario result from a rule result was a bit of a hassle.

That said, I'm glad you brought this up. I'll mull over it and consider some changes on the weekend.

@nbigaouette
Copy link

Playing again with this (04c3475 on develop branch)...

My world now looks like this:

pub struct MyWorld {
    member: Arc<RwLock<MyOtherStruct>>,
    // ...
}

It's a bit unfortunate and ugly, but I'm ok with it.

I tested the given/when/then with &self, &mut self, returning Result and panicking methods. All work as expected 🎉.

I saw something weird in the feature file; if I "comment" some lines (with #) in a feature file, the whole thing crashes weirdly:

     Running `target/debug/end2end`
[2020-05-28T16:08:43Z DEBUG globset] glob converted to regex: Glob { glob: "**/*.feature", re: "(?-u)(?i)^(?:/?|.*/)[^/]*\\.feature$", opts: GlobOptions { case_insensitive: true, literal_separator: true, backslash_escape: true }, tokens: Tokens([RecursivePrefix, ZeroOrMore, Literal('.'), Literal('f'), Literal('e'), Literal('a'), Literal('t'), Literal('u'), Literal('r'), Literal('e')]) }
[2020-05-28T16:08:43Z DEBUG globset] built glob set; 0 literals, 0 basenames, 0 extensions, 0 prefixes, 0 suffixes, 0 required extensions, 1 regexes
thread 'main' panicked at 'Box<Any>', <::std::macros::panic macros>:2:4
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
   1: backtrace::backtrace::trace_unsynchronized
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:78
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:59
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1063
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1426
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:62
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:204
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:224
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:470
  11: std::panicking::begin_panic
  12: cucumber_rust::cucumber::Cucumber<W>::features::{{closure}}
             at ./<::std::macros::panic macros>:2
  13: core::result::Result<T,E>::unwrap_or_else
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libcore/result.rs:851
  14: cucumber_rust::cucumber::Cucumber<W>::features
             at /Users/nbigaouette/.cargo/git/checkouts/cucumber-rust-eaba67609642419e/04c3475/src/cucumber.rs:67
  15: end2end::main::{{closure}}
             at end2end/src/main.rs:233
  16: <std::future::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
  17: tokio::runtime::enter::Enter::block_on::{{closure}}
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/enter.rs:163
  18: tokio::coop::with_budget::{{closure}}
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:127
  19: std::thread::local::LocalKey<T>::try_with
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:262
  20: std::thread::local::LocalKey<T>::with
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:239
  21: tokio::coop::with_budget
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:120
  22: tokio::coop::budget
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:96
  23: tokio::runtime::enter::Enter::block_on
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/enter.rs:163
  24: tokio::runtime::thread_pool::ThreadPool::block_on
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/thread_pool/mod.rs:82
  25: tokio::runtime::Runtime::block_on::{{closure}}
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/mod.rs:446
  26: tokio::runtime::context::enter
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/context.rs:72
  27: tokio::runtime::handle::Handle::enter
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/handle.rs:76
  28: tokio::runtime::Runtime::block_on
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/mod.rs:441
  29: end2end::main
             at end2end/src/main.rs:40
  30: std::rt::lang_start::{{closure}}
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/rt.rs:67
  31: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:52
  32: std::panicking::try::do_call
             at src/libstd/panicking.rs:303
  33: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:86
  34: std::panicking::try
             at src/libstd/panicking.rs:281
  35: std::panic::catch_unwind
             at src/libstd/panic.rs:394
  36: std::rt::lang_start_internal
             at src/libstd/rt.rs:51
  37: std::rt::lang_start
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/rt.rs:67
  38: <end2end::MyWorld as cucumber_rust::World>::new::__new
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

I guess the file parser does not support those types of comments.

Another observation is that all output to stdout/stderr is hidden; I thus cannot see any logs. I'll switch from env_logger to one that saves to a file. It would be interesting if cucumber could redirect itself outputs to a file.

I'll port the remaining of my tests to see how it goes. But I like what I'm seeing! Good job!

@bbqsrc
Copy link
Member Author

bbqsrc commented May 28, 2020

So one of my idiosyncrasies is that when I write a grammar, I tend to forget to handle comments properly at all (and I've written about 3 grammars this month, all displaying the same bug... haha). I'll look into that one the weekend.

Redirecting the stdout and stderr to a file is actually possible, I'll put it on the backlog!

I'm glad you're enjoying it. Thanks for the feedback!

@nbigaouette
Copy link

Forget to say... Constructing MyWorld using cucumber::World::new() does not support failure (new() returns Self) so I have to unwrap() any failable operations there (which there is a couple). For example if I panic inside new() the whole thing crashes:

[Cucumber v0.7.0]
Feature: Cucumber example                                                                                              features/dummy/test.feature:1:1 

 Scenario: One Simple steps                                                                                            features/dummy/test.feature:3:5 
thread 'main' panicked at 'oh no!', end2end/src/main.rs:246:9
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
   1: backtrace::backtrace::trace_unsynchronized
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:78
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:59
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1063
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1426
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:62
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:204
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:224
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:470
  11: std::panicking::begin_panic
  12: <end2end::MyWorld as cucumber_rust::World>::new::__new::{{closure}}
             at end2end/src/main.rs:246
  13: <std::future::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
  14: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libcore/future/future.rs:118
  15: std::future::poll_with_tls_context
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:102
  16: cucumber_rust::runner::Runner<W>::run_scenario::{{closure}}
             at /Users/nbigaouette/.cargo/git/checkouts/cucumber-rust-eaba67609642419e/04c3475/src/runner.rs:190
  17: <std::future::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
  18: <async_stream::async_stream::AsyncStream<T,U> as futures_core::stream::Stream>::poll_next
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/async-stream-0.2.1/src/async_stream.rs:53
  19: <core::pin::Pin<P> as futures_core::stream::Stream>::poll_next
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.5/src/stream.rs:121
  20: futures_util::stream::stream::StreamExt::poll_next_unpin
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/stream/stream/mod.rs:1323
  21: <futures_util::stream::stream::next::Next<St> as core::future::future::Future>::poll
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/stream/stream/next.rs:35
  22: std::future::poll_with_tls_context
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:102
  23: cucumber_rust::runner::Runner<W>::run_feature::{{closure}}
             at /Users/nbigaouette/.cargo/git/checkouts/cucumber-rust-eaba67609642419e/04c3475/src/runner.rs:132
  24: <std::future::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
  25: <async_stream::async_stream::AsyncStream<T,U> as futures_core::stream::Stream>::poll_next
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/async-stream-0.2.1/src/async_stream.rs:53
  26: <core::pin::Pin<P> as futures_core::stream::Stream>::poll_next
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.5/src/stream.rs:121
  27: futures_util::stream::stream::StreamExt::poll_next_unpin
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/stream/stream/mod.rs:1323
  28: <futures_util::stream::stream::next::Next<St> as core::future::future::Future>::poll
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/stream/stream/next.rs:35
  29: std::future::poll_with_tls_context
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:102
  30: cucumber_rust::runner::Runner<W>::run::{{closure}}
             at /Users/nbigaouette/.cargo/git/checkouts/cucumber-rust-eaba67609642419e/04c3475/src/runner.rs:268
  31: <std::future::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
  32: <async_stream::async_stream::AsyncStream<T,U> as futures_core::stream::Stream>::poll_next
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/async-stream-0.2.1/src/async_stream.rs:53
  33: <core::pin::Pin<P> as futures_core::stream::Stream>::poll_next
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.5/src/stream.rs:121
  34: futures_util::stream::stream::StreamExt::poll_next_unpin
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/stream/stream/mod.rs:1323
  35: <futures_util::stream::stream::next::Next<St> as core::future::future::Future>::poll
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.5/src/stream/stream/next.rs:35
  36: std::future::poll_with_tls_context
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:102
  37: cucumber_rust::cucumber::Cucumber<W>::run::{{closure}}
             at /Users/nbigaouette/.cargo/git/checkouts/cucumber-rust-eaba67609642419e/04c3475/src/cucumber.rs:78
  38: <std::future::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
  39: std::future::poll_with_tls_context
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:102
  40: end2end::main::{{closure}}
             at end2end/src/main.rs:225
  41: <std::future::GenFuture<T> as core::future::future::Future>::poll
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
  42: tokio::runtime::enter::Enter::block_on::{{closure}}
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/enter.rs:163
  43: tokio::coop::with_budget::{{closure}}
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:127
  44: std::thread::local::LocalKey<T>::try_with
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:262
  45: std::thread::local::LocalKey<T>::with
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:239
  46: tokio::coop::with_budget
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:120
  47: tokio::coop::budget
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/coop.rs:96
  48: tokio::runtime::enter::Enter::block_on
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/enter.rs:163
  49: tokio::runtime::thread_pool::ThreadPool::block_on
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/thread_pool/mod.rs:82
  50: tokio::runtime::Runtime::block_on::{{closure}}
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/mod.rs:446
  51: tokio::runtime::context::enter
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/context.rs:72
  52: tokio::runtime::handle::Handle::enter
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/handle.rs:76
  53: tokio::runtime::Runtime::block_on
             at /Users/nbigaouette/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/runtime/mod.rs:441
  54: end2end::main
             at end2end/src/main.rs:40
  55: std::rt::lang_start::{{closure}}
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/rt.rs:67
  56: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:52
  57: std::panicking::try::do_call
             at src/libstd/panicking.rs:303
  58: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:86
  59: std::panicking::try
             at src/libstd/panicking.rs:281
  60: std::panic::catch_unwind
             at src/libstd/panic.rs:394
  61: std::rt::lang_start_internal
             at src/libstd/rt.rs:51
  62: std::rt::lang_start
             at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/rt.rs:67
  63: <end2end::MyWorld as cucumber_rust::World>::new::__new
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

@bbqsrc
Copy link
Member Author

bbqsrc commented May 28, 2020

Haha, yes, I took a shortcut there, knowingly! Not surprised you came across that, given you've found every other edge case and lazy option I took. I'll look at that on the weekend too. xD

@nbigaouette
Copy link

Haha :D If we weren't lazy, we wouldn't automate our testing, wouldn't we? ;)

@bbqsrc
Copy link
Member Author

bbqsrc commented May 28, 2020

look

@nbigaouette
Copy link

eurg.... I'm still hit by the borrowing issue:

error[E0505]: cannot move out of `world` because it is borrowed
   --> end2end/src/main.rs:149:21
    |
146 |                     let mut tmp = world.member.write().unwrap();
    |                                  --------------------- borrow of `world.member` occurs here
...
149 |                     world
    |                     ^^^^^ move out of `world` occurs here
150 |                 })
    |                 - borrow might be used here, when `tmp` is dropped and runs the `Drop` code for type `std::sync::RwLockWriteGuard`

error: aborting due to previous error

Here's the code:

.given_regex(
    r#"Name name="(.*)" is present"#,
    Rc::new(|world, matches, _step| {
        std::panic::AssertUnwindSafe(async move {
            let name = &matches[0];
            let mut tmp = world.member.write().unwrap();
            let roles = tmp.async_method_taking_mut_self().await;

            world
        })
        .catch_unwind()
        .boxed_local()
    }),
)

I need a temporary variable or else I get a error[E0716]: temporary value dropped while borrowed.

@bbqsrc
Copy link
Member Author

bbqsrc commented May 28, 2020

Something like https://docs.rs/tokio/0.2.21/tokio/sync/struct.RwLock.html may help here. Holding a lock across an await boundary is often not permissible, and my guess is that might be the issue here.

It might also be that you need to do:

let tmp = Arc::clone(&world.member);
let mut tmp = tmp.write().unwrap();

@nbigaouette
Copy link

The member is already a RwLock. Cloning the Arc was the magic incantation, thanks! :D

@bbqsrc
Copy link
Member Author

bbqsrc commented May 28, 2020

@nbigaouette there is a difference between a tokio RwLock and a std RwLock though, as the tokio one is asynchronous. It has some cases where using a std one will not work, though I can't remember the precise case I needed it, but it was within the last week heh

@nbigaouette
Copy link

Haaa good to know, I'll keep that in mind if I have another issue. I'm using a std lock for now.

@bbqsrc
Copy link
Member Author

bbqsrc commented May 30, 2020

@nbigaouette World is now failable (it will crash right now, just made it unwrap, but will make it handle panics and errors properly), and gherkin has been fixed to handle spaces in front of comments. :)

@nbigaouette
Copy link

Thanks! I want to try it but can't for now. the error type of World trait is std::error::Error:
https://github.com/bbqsrc/cucumber-rust/blob/develop/src/lib.rs#L43
Since I'm using anyhow to for error handling (which anyhow::error::Error doesn't impl Error) I cannot do the following:

#[async_trait(?Send)]
impl cucumber::World for AccessGovernorWorld {
    type Error = anyhow::Error;
...

I get the following:

error[E0046]: not all trait items implemented, missing: `Error`
   --> src/main.rs:483:1
    |
483 | impl cucumber::World for MyWorld {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error` in implementation
    |
    = help: implement the missing item: `type Error = Type;`

See for example/reference:

Not sure what the best approach would be here. Should I handle this myself (creating a new error type that implements Error) or can cucumber be more flexible for this? It's kind of weird that anyhow::Error does not implement std::error::Error (it's explained in the issues linked) but how World is defined I'm not sure the conversion is possible?

@bbqsrc
Copy link
Member Author

bbqsrc commented Jun 1, 2020

Workaround here: dtolnay/anyhow#63 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants