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

Harmonize Rack dependency and tests #27

Merged
merged 27 commits into from
Nov 11, 2024
Merged

Harmonize Rack dependency and tests #27

merged 27 commits into from
Nov 11, 2024

Conversation

julik
Copy link
Owner

@julik julik commented Nov 4, 2024

  • Set up Appraisal for testing against both Rack 2 and 3
  • Ensure all HTTP header uses are lowercase
  • Support non-rewindable request bodies
  • Use Rack::Lint when running tests
  • Bring tests more in line with the Rack spec

julik and others added 5 commits November 4, 2024 13:25
Since rack 3 is now supported by Rails, it seems important to ensure that this middleware has a proper support for it. Issues with rack 3 are difficult to notice or debug. To help prevent issues with compatibility and the time that it takes to manually debug and resolve those - I suggest that we integrate `Rack::Lint` into the test suite.

Rack::Lint would ensure that middleware adheres to the SPEC.

Please be patient, since I' still figuring out how this works ;-)

Related documentation (for me to read through multiple times):
- https://github.com/rack/rack/blob/744f92d099653f873ced3380e425a6f82f0c6c6c/UPGRADE-GUIDE.md?plain=1#L185
- https://github.com/rack/rack/blob/744f92d099653f873ced3380e425a6f82f0c6c6c/SPEC.rdoc

---------

Co-authored-by: Julik Tarkhanov <me@julik.nl>
Make sure fingerprinting works with non-rewindable request bodies, and add tests to make sure everything contributes to the fingerprint correctly
Something that supports to_ary "just" supports it anyway
@julik julik changed the title Harmonize rack support Harmonize Rack dependencies and tests Nov 4, 2024
as it doesn't make much sense with Rack 3.0 streaming bodies - we may be able to read out the request body, or we may not be able to. If we are not able - the fingerprint will be the same.
as Lint is appropriately hinting
because if it works on 2.7 it will work on 3 just as well, and we are not using 3.x specific syntax (and have standardrb rules configured accordingly)
lib/idempo.rb Outdated Show resolved Hide resolved
lib/idempo.rb Show resolved Hide resolved
@julik julik marked this pull request as ready for review November 8, 2024 14:02
@julik
Copy link
Owner Author

julik commented Nov 8, 2024

@skatkov feel free to chime in on the review if you feel like it, I've integrated as much of your prior work as I could

@julik julik changed the title Harmonize Rack dependencies and tests Harmonize Rack dependency and tests Nov 8, 2024
idempo.gemspec Outdated Show resolved Hide resolved
lib/idempo.rb Show resolved Hide resolved
lib/idempo/version.rb Outdated Show resolved Hide resolved
yielder.yield(env["rack.input"].read)
end
[200, {"X-Foo" => "bar", "Content-Length" => "9999999999999"}, body]
pre_sized_body = PreSizedBody.new(999999999)
Copy link
Contributor

@skatkov skatkov Nov 8, 2024

Choose a reason for hiding this comment

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

suggestion: Interesting trick with PreSizedBody!

I see that we're not testing that small request body doesn't get saved. Should be easy to add with PreSizedBody class?

Copy link
Owner Author

Choose a reason for hiding this comment

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

A small request body should get saved. What we are not testing is that while the body is not saved, there is still concurrency protection - but testing that would need bypassing rack-spec, because there is no provision for multiple Fibers running simultaneous requests in it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, true! Misread the code, thanks for pointing that out.

Rakefile Show resolved Hide resolved
@julik
Copy link
Owner Author

julik commented Nov 10, 2024

@franzliedke take a look when you have a moment

Copy link
Collaborator

@franzliedke franzliedke left a comment

Choose a reason for hiding this comment

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

I can't really comment on the Rack 2 vs. 3 specifics, but the code changes look good to me.

runs-on: ubuntu-22.04
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
strategy:
matrix:
ruby:
- "2.7"
- "3.2"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was this intentionall removed? Testing on a recent Ruby version seems useful.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes, because then the matrix turns into 4 versions - and I had some trouble loading older ActiveRecord on the newer Ruby versions. I presume what works on 2.7 will work on 3.x anyway, so it felt like a good comproimse

Comment on lines -171 to -181
it "is not idempotent if the request body is different" do
post "/", "somedata", "HTTP_X_IDEMPOTENCY_KEY" => "idem"
expect(last_response).to be_ok
expect(last_response.headers["X-Foo"]).to eq("bar")
first_response_body = last_response.body

post "/", "somedata2", "HTTP_X_IDEMPOTENCY_KEY" => "idem"
expect(last_response).to be_ok
expect(last_response.headers["X-Foo"]).to eq("bar")
expect(last_response.body).not_to eq(first_response_body) # response should not have been reused
end
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about the removed specs?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Some were irrelevant - this one, for example, does not work with Rack 3 because the request body is no longer rewindable - and thus can't contribute to the fingerprint. Other tests do cover the "standard happy path" well IMO.

Comment on lines +43 to +66
it "takes all the key HTTP headers and the body into account" do
combinations = {
"rack.input" => [StringIO.new(""), StringIO.new("some body")],
"SCRIPT_NAME" => ["script", ""],
"PATH_INFO" => ["/hello", "/hello?one=1", ""],
"REQUEST_METHOD" => ["GET", "POST", "PUT"],
"HTTP_AUTHORIZATION" => ["Bearer abcdef", nil]
}

# Create combinations of all possible values of different headers, and
# make sure they all produce different fingerprints
initial_array = Array(combinations.values.first)
product_with = combinations.values[1..]
all_value_permutations = initial_array.product(*product_with)
fingerprints = all_value_permutations.flat_map do |values|
combination_of_possible_rack_env_values = combinations.keys.zip(values).to_h
["key1", "key2"].map do |idempotency_key|
request = Rack::Request.new(combination_of_possible_rack_env_values)
described_class.call(idempotency_key, request)
end
end

expect(fingerprints.uniq.length).to eq(fingerprints.length)
end
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like this test. 😁 👍🏼

(The extra variables initial_array and product_with led me a bit astray first, but I guess inlining it all wouldn't be more readable either.)

@julik julik merged commit b82aa59 into main Nov 11, 2024
4 checks passed
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.

3 participants