Conversation
opedhassan
approved these changes
May 7, 2024
327dd45 to
a1429fc
Compare
456a71a to
c421642
Compare
ArturT
approved these changes
May 8, 2024
Member
ArturT
left a comment
There was a problem hiding this comment.
Great work and awesome PR description with testing CI builds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Story
Ticket https://trello.com/c/nInb3gxY/359-knapsackpro-gem-dx-remove-manual-steps-for-webmock-vcr
Currently, setting up Knapsack Pro with WebMock/VCR requires additional steps because WebMock replaces
Net::HTTPwith its own client that (also) blocks requests to the Knapsack Pro API.Some codebases configure WM in a way that doesn't play well with Knapsack Pro, even when the manual configuration steps are followed.
For example, each call to
WebMock.disable_net_connect!without passingallow: ['api.knapsackpro.com']overrides the previousWebMock.disable_net_connect!(allow: ['api.knapsackpro.com'])call preventing requests toapi.knapsackpro.com.Users could have multiple calls to
WebMockthat "reset" the configuration including in before/after hooks. So it's difficult to solve the issue by using hooks to undo the reset.(Aside:
WebMock.reset!does not touchWebMock::Config.instance.allowso that does not pose a problem, onlydisable_net_connection!does.)This PR, introduces a mechanism to always call the original
Net::HTTPfor requests to the Knapsack Pro API preventing WM from interfering.In other words, users won't have to follow any additional steps to configure Knapsack Pro and WebMock/VCR. This will also eliminate all related support requests and people getting stuck.
What follows are the internal details on why this PR works. It may be overwhelming to understand it, so feel free to ignore. But I'm leaving notes for reference.
Test
I created a
webmockbranch (same name as the branch for this PR) inrails-app-with-knapsack-prowith:Since the branch names are the same, CI will use that for the E2E tests of this PR.
Here are:
I also built the API with this PR but without removing the custom WM/VCR config:
And built without the custom WM/VCR config:
Details for WebMock
WebMock enables itself at the beginning of a test run. Here's how it's done for RSpec:
https://github.com/bblimke/webmock/blob/fc6a2ab897a069d861adbc1c88e51b2cf8aa88ac/lib/webmock/rspec.rb#L30-L32
enable!ends up callingWebMock::HttpLibAdapters::NetHttpAdapter.enable!:https://github.com/bblimke/webmock/blob/fc6a2ab897a069d861adbc1c88e51b2cf8aa88ac/lib/webmock/http_lib_adapters/net_http.rb#L16-L21
which replaces
Net::HTTPwith@webMockNetHTTP:https://github.com/bblimke/webmock/blob/fc6a2ab897a069d861adbc1c88e51b2cf8aa88ac/lib/webmock/http_lib_adapters/net_http.rb#L40
Notice it also saves the original
Net::HTTPinWebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP:https://github.com/bblimke/webmock/blob/fc6a2ab897a069d861adbc1c88e51b2cf8aa88ac/lib/webmock/http_lib_adapters/net_http.rb#L14
Details for WebMock and VCR
When WM is used in tandem with VCR, the situation gets a bit more complicated.
When VCR starts it enables WebMock and monkey patches WM's
net_connect_allowed?to:https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/library_hooks/webmock.rb#L160-L171
which means if VCR is on it does not allow WM to block anything, otherwise it delegates to WM because
net_connect_allowed_without_vcr?is the original WM’snet_connect_allowed?.If VCR is off, we are in the WM-only situation explained above.
Otherwise, VCR interacts with WM’s
@webMockNetHTTPas follows.VCR hooks into WM's global stubs:
https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/library_hooks/webmock.rb#L134-L136
In turn, WM in
@webMockNetHTTP:https://github.com/bblimke/webmock/blob/fc6a2ab897a069d861adbc1c88e51b2cf8aa88ac/lib/webmock/http_lib_adapters/net_http.rb#L71-L108
So
requestinvokesWebMock::StubRegistry.instance.response_for_request(request_signature), which ends up calling VCR'sRequestHandler.new(req).handle.WebMock::StubRegistry.instance.response_for_request(request_signature)may return a stubbed response when:or it may return a fals-y value (
nil) and let WM perform the request. Remember thatnet_connect_allowed?is always true when using VCR.Here's how
handledoes it:https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/request_handler.rb#L6-L25
Where
https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/request_handler.rb#L33-L41
https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/library_hooks/webmock.rb#L97-L102
https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/request_handler.rb#L58-L64
https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/library_hooks/webmock.rb#L113-L129
https://github.com/vcr/vcr/blob/cde89346aebcbe5280299ba10aedb3d97860c557/lib/vcr/request_handler.rb#L87-L94
Checklist reminder
lib/knapsack_pro/pure/queue/rspec_pure.rbcontains pure functions that are unit tested.lib/knapsack_pro/extensions/rspec_extension.rbencapsulates calls to RSpec internals and is integration and e2e tested.lib/knapsack_pro/runners/queue/rspec_runner.rbinvokes the pure code and the extension to produce side effects, which are integration and e2e tested.