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

Example for Cucumber step definitions #66

Closed
schmijos opened this issue Jan 8, 2024 · 3 comments
Closed

Example for Cucumber step definitions #66

schmijos opened this issue Jan 8, 2024 · 3 comments

Comments

@schmijos
Copy link

schmijos commented Jan 8, 2024

I've got the following Cucumber step definitions implemented:

Given(/^the client is connected to the relay$/) do
  Async do |task|
    @endpoint = Async::HTTP::Endpoint.parse("ws://127.0.0.1:3000")
    @connection = Async::WebSocket::Client.connect(@endpoint)
    puts "1"
  end
  puts "2"
end

When(/^the client sends$/) do |message|
  @connection.write(message)
end

Then(/^the server responds with ([A-Z]+)$/) do |type|
  message = @connection.read
  assert_equal type, JSON.parse(message).first
end

Running them returns the following stdout:

1
 0.48s     warn: Async::Pool::Controller: Async::Pool::Controller Gardener [oid=0x10cc] [ec=0x10e0] [pid=70992] [2024-01-08 13:20:33 +0100]
               | Closing resource while still in use!
               | {"resource":"#<Async::HTTP::Protocol::HTTP1::Client:0x000000011eacdfe0>","usage":1}
2

The assertion passes. Everything works as expected. But I don't like this warning. Where does this come from?

@schmijos
Copy link
Author

schmijos commented Jan 8, 2024

Using an around hook instead of a single step works correctly without warning.

Around("@connected") do |scenario, block|
  Async do
    @endpoint = Async::HTTP::Endpoint.parse("ws://127.0.0.1:3000")
    Async::WebSocket::Client.connect(@endpoint) do |connection|
      @connection = connection
      block.call
    end
  end
end

I guess this is because connect ensures connection closing itself if called with a block?

The following works as well

Around("@connected") do |scenario, block|
  Async do
    @endpoint = Async::HTTP::Endpoint.parse("ws://127.0.0.1:3000")
    @connection = Async::WebSocket::Client.connect(@endpoint)
    block.call
  ensure
    @connection.close
  end
end

And this more generic version works as well.
But it bugs me that I cannot find out how to generically delay the Async::Stop until all the work is done.

Given(/^the client is connected to the relay$/) do
  @endpoint = Async::HTTP::Endpoint.parse("ws://127.0.0.1:3000")
  @connection = Async::WebSocket::Client.connect(@endpoint)
end

Around do |scenario, block|
  Async do
    block.call
  ensure
    @connection&.close
  end
end

@ioquatix
Copy link
Member

ioquatix commented Jan 8, 2024

As you figured out, the connection is closed automatically when it goes out of scope. But the connection is still in use by the WebSocket instance. So, a warning is issued that we are closing the HTTP connection while it still appears to be in use (i.e. not checked back into the connection pool).

As you implemented, calling @connection.close is the correct solution, as this closes the WebSocket correctly and returns the HTTP connection to the connection pool.

Async::Stop is used at the end of the top level Async{} block to shut down all tasks. There is no way to persist a task outside of the Async{} block by design. However, the Fiber.scheduler interface does not enforce this. Generally speaking, you don't want to leak resources between tests, so this should be the right behaviour.

Does that answer your question?

@schmijos
Copy link
Author

schmijos commented Jan 9, 2024

Yes, thank you very much!
I ended up with the following "idiomatic" solution to Cucumber testing with Async:

  1. "Configure" Async support for Cucumber:
# features/support/env.rb
Around do |_scenario, block|
  Async { block.call }
end
  1. Use Async-dependent tools like Async::WebSocket in step definitions
# features/step_definitions/connection.rb
Given(/^the client is connected to the relay$/) do
  @endpoint = Async::HTTP::Endpoint.parse("ws://127.0.0.1:3000")
  @connection = Async::WebSocket::Client.connect(@endpoint)
end

After do
  @connection&.close
end

@schmijos schmijos closed this as completed Jan 9, 2024
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

No branches or pull requests

2 participants