lostisland / faraday

Simple, but flexible HTTP client library, with support for multiple backends.
https://lostisland.github.io/faraday
MIT License
5.72k stars 972 forks source link

Tests with the combination of `strict_mode` and `FlatParamsEncoder` may fail #1411

Closed yykamei closed 2 years ago

yykamei commented 2 years ago

With strict_mode, the Testing adapter tries to check the equality of parameters here.

https://github.com/lostisland/faraday/blob/24b3fd36e670e4c49e977bd23d6c1314c89d7089/lib/faraday/adapter/test.rb#L202

This check sometimes return false with FlatParamsEncoder because an array value may contain elements by different order. For example,

stubs = Faraday::Adapter::Test::Stubs.new do |stub|
  stub.get("/foo?key=123&key=234&key=abc") do |_env|
    [200, { content_type: "application/json" }, JSON.dump(status: "OK")]
  end
end
conn = Faraday.new { |b| b.adapter(:test, stubs) }
conn.get("/foo", { key: [123, 234, "abc"] })
stubs.verify_stubbed_calls # => Error with this comparison: `Set.new(key: [123, 234, "abc]) == Set.new(key: ["abc", 123, 234])`

In general, the order of query is not important, so I want to check keys without order.

What do you think?

Related PRs: #1298 #1316

iMacTia commented 2 years ago

This makes sense, but I can see someone coming in future and asking how to write a test that also checks the specific order of things... Ideally, it would be great to support both scenarios and let the developer choose which one they want to apply in any given case. I'd also feel reluctant in changing the current behaviour as this would cause existing tests relying on the adapter to fail.

A possible solution to all these points could be the following:

I like this because it would be flexible enough to support all cases, while also keeping the existing behaviour, but I'm not sure about the complexity of such a change, so I'm open to alternative suggestions as far as they respect the points I highlighted above!

yykamei commented 2 years ago

Oh, I understood FlatParamsEncoder has a feature to sort parameters.

https://github.com/lostisland/faraday/blob/24b3fd36e670e4c49e977bd23d6c1314c89d7089/lib/faraday/encoders/flat_params_encoder.rb#L38

As you said, it would be necessary for someone who wants to check the specific order of parameter values.

Introducing query looks great 👍 Of course, the Test adapter must consider parameters included in path as well as query, but it would be useful to construct parameters with the Hash value. So, I think it's worth implementing 😄

By the way, is query good for the argument name? Faraday's methods seem to use params for the URL query parameters. For example, Connection#get has params for its method argument.

https://github.com/lostisland/faraday/blob/24b3fd36e670e4c49e977bd23d6c1314c89d7089/lib/faraday/connection.rb#L135

iMacTia commented 2 years ago

The idea behind using query and body instead of just params is that you'll be able to distinguish them on HTTP methods that support both (e.g. POST).

Of course, the Test adapter must consider parameters included in path as well as query

Good point, I think I see where this is coming from. Could you show an example of this just to be sure we're on the same page?

yykamei commented 2 years ago

OK, using query makes sense 👍

I think changing here might be the first step:

https://github.com/lostisland/faraday/blob/24b3fd36e670e4c49e977bd23d6c1314c89d7089/lib/faraday/adapter/test.rb#L151

Stub seems to have query as a string, but we will have to merge this query with the new parameter query, which comes from the argument of #new_stub. So, I'm considering changing Stub#query from string to Hash.

The example code in #new_stub here.

path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
query = convert_to_hash(query) # NOTE: convert_to_hash is something like URI.decode_www_form
query.merge!(query_from_args)

stub = Stub.new(host, path, query, headers, body, @strict_mode, block)
iMacTia commented 2 years ago

That makes sense to me, Stub can use any internal representation for query as far as it works in the same way 😄! Sorry I was sure I got back to you already on this 🙈

yykamei commented 2 years ago

Oh, I misunderstood the implementation of FlatParamesEncoder. I reconsidered this issue and keeping as-is might be the best way. Thanks for thinking about this issue.

By the way, adding query for testing adapters might be a nice to have. This is out of this issue 😄