webmock 1.8.6 → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/CI.yml +37 -0
- data/.gitignore +6 -0
- data/CHANGELOG.md +1198 -0
- data/Gemfile +3 -15
- data/README.md +761 -305
- data/Rakefile +13 -40
- data/lib/webmock/api.rb +63 -17
- data/lib/webmock/callback_registry.rb +1 -1
- data/lib/webmock/config.rb +8 -0
- data/lib/webmock/cucumber.rb +2 -0
- data/lib/webmock/errors.rb +8 -24
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +216 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +148 -84
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +224 -4
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +104 -34
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +64 -0
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +152 -86
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +145 -0
- data/lib/webmock/http_lib_adapters/net_http.rb +155 -46
- data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +16 -15
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +76 -82
- data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +4 -12
- data/lib/webmock/minitest.rb +29 -3
- data/lib/webmock/rack_response.rb +14 -7
- data/lib/webmock/request_body_diff.rb +64 -0
- data/lib/webmock/request_execution_verifier.rb +38 -17
- data/lib/webmock/request_pattern.rb +158 -38
- data/lib/webmock/request_registry.rb +3 -3
- data/lib/webmock/request_signature.rb +7 -3
- data/lib/webmock/request_signature_snippet.rb +61 -0
- data/lib/webmock/request_stub.rb +9 -6
- data/lib/webmock/response.rb +30 -15
- data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +38 -2
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +23 -2
- data/lib/webmock/rspec/matchers.rb +0 -1
- data/lib/webmock/rspec.rb +11 -2
- data/lib/webmock/stub_registry.rb +31 -10
- data/lib/webmock/stub_request_snippet.rb +14 -6
- data/lib/webmock/test_unit.rb +4 -4
- data/lib/webmock/util/hash_counter.rb +20 -6
- data/lib/webmock/util/hash_keys_stringifier.rb +5 -3
- data/lib/webmock/util/hash_validator.rb +17 -0
- data/lib/webmock/util/headers.rb +23 -2
- data/lib/webmock/util/json.rb +20 -7
- data/lib/webmock/util/query_mapper.rb +281 -0
- data/lib/webmock/util/uri.rb +29 -19
- data/lib/webmock/util/values_stringifier.rb +20 -0
- data/lib/webmock/util/version_checker.rb +40 -2
- data/lib/webmock/version.rb +1 -1
- data/lib/webmock/webmock.rb +56 -17
- data/lib/webmock.rb +56 -46
- data/minitest/test_helper.rb +8 -3
- data/minitest/test_webmock.rb +4 -1
- data/minitest/webmock_spec.rb +16 -6
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
- data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
- data/spec/acceptance/curb/curb_spec.rb +227 -68
- data/spec/acceptance/curb/curb_spec_helper.rb +11 -8
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +322 -28
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +15 -10
- data/spec/acceptance/excon/excon_spec.rb +66 -4
- data/spec/acceptance/excon/excon_spec_helper.rb +21 -7
- data/spec/acceptance/http_rb/http_rb_spec.rb +93 -0
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
- data/spec/acceptance/httpclient/httpclient_spec.rb +152 -11
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +25 -16
- data/spec/acceptance/manticore/manticore_spec.rb +107 -0
- data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
- data/spec/acceptance/net_http/net_http_shared.rb +52 -24
- data/spec/acceptance/net_http/net_http_spec.rb +164 -50
- data/spec/acceptance/net_http/net_http_spec_helper.rb +19 -10
- data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
- data/spec/acceptance/patron/patron_spec.rb +29 -40
- data/spec/acceptance/patron/patron_spec_helper.rb +15 -11
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +229 -58
- data/spec/acceptance/shared/callbacks.rb +32 -30
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +20 -5
- data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +14 -14
- data/spec/acceptance/shared/precedence_of_stubs.rb +6 -6
- data/spec/acceptance/shared/request_expectations.rb +560 -296
- data/spec/acceptance/shared/returning_declared_responses.rb +180 -138
- data/spec/acceptance/shared/stubbing_requests.rb +385 -154
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +78 -17
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +19 -15
- data/spec/acceptance/webmock_shared.rb +2 -2
- data/spec/fixtures/test.txt +1 -0
- data/spec/quality_spec.rb +27 -3
- data/spec/spec_helper.rb +11 -20
- data/spec/support/failures.rb +9 -0
- data/spec/support/my_rack_app.rb +8 -3
- data/spec/support/network_connection.rb +7 -13
- data/spec/support/webmock_server.rb +8 -3
- data/spec/unit/api_spec.rb +175 -0
- data/spec/unit/errors_spec.rb +116 -19
- data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +1 -1
- data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +2 -2
- data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
- data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
- data/spec/unit/rack_response_spec.rb +54 -16
- data/spec/unit/request_body_diff_spec.rb +90 -0
- data/spec/unit/request_execution_verifier_spec.rb +147 -39
- data/spec/unit/request_pattern_spec.rb +462 -198
- data/spec/unit/request_registry_spec.rb +29 -9
- data/spec/unit/request_signature_snippet_spec.rb +89 -0
- data/spec/unit/request_signature_spec.rb +91 -49
- data/spec/unit/request_stub_spec.rb +71 -70
- data/spec/unit/response_spec.rb +100 -81
- data/spec/unit/stub_registry_spec.rb +37 -20
- data/spec/unit/stub_request_snippet_spec.rb +51 -31
- data/spec/unit/util/hash_counter_spec.rb +6 -6
- data/spec/unit/util/hash_keys_stringifier_spec.rb +4 -4
- data/spec/unit/util/headers_spec.rb +4 -4
- data/spec/unit/util/json_spec.rb +29 -3
- data/spec/unit/util/query_mapper_spec.rb +157 -0
- data/spec/unit/util/uri_spec.rb +150 -36
- data/spec/unit/util/version_checker_spec.rb +15 -9
- data/spec/unit/webmock_spec.rb +57 -4
- data/test/http_request.rb +3 -3
- data/test/shared_test.rb +45 -13
- data/test/test_helper.rb +1 -1
- data/test/test_webmock.rb +6 -0
- data/webmock.gemspec +30 -11
- metadata +308 -199
- data/.rvmrc +0 -1
- data/.travis.yml +0 -11
- data/Guardfile +0 -24
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb +0 -151
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +0 -210
data/Rakefile
CHANGED
@@ -1,65 +1,38 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
|
-
|
3
1
|
require 'bundler'
|
4
2
|
Bundler::GemHelper.install_tasks
|
5
3
|
|
6
|
-
namespace :rvm do
|
7
|
-
desc 'Run specs against 1.8.6, REE, 1.8.7, 1.9.2 and jRuby'
|
8
|
-
task :specs do
|
9
|
-
# JCF: I'd love to be able to use RVM's `rvm {rubies} specs` command but
|
10
|
-
# the require tests in spec/other_net_http_libs_spec.rb break when doing
|
11
|
-
# so.
|
12
|
-
spec_files = Dir[File.dirname(__FILE__) + '/spec/**/*_spec.rb'].join(' ')
|
13
|
-
sh "rvm 1.8.6@webmock,ree@webmock,1.8.7@webmock,1.9.2@webmock,jruby@webmock exec rspec #{spec_files}"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
4
|
require "rspec/core/rake_task"
|
18
5
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
19
|
-
t.rspec_opts = [
|
6
|
+
t.rspec_opts = %w[
|
7
|
+
--force-color
|
8
|
+
--format progress
|
9
|
+
--require ./spec/spec_helper.rb
|
10
|
+
]
|
20
11
|
t.pattern = 'spec/**/*_spec.rb'
|
21
12
|
end
|
22
13
|
|
23
14
|
RSpec::Core::RakeTask.new(:spec_http_without_webmock) do |t|
|
24
|
-
t.rspec_opts = [
|
15
|
+
t.rspec_opts = %w[
|
16
|
+
--force-color
|
17
|
+
--format progress
|
18
|
+
--require ./spec/acceptance/net_http/real_net_http_spec.rb
|
19
|
+
]
|
25
20
|
t.pattern = 'spec/acceptance/net_http/real_net_http_spec.rb'
|
26
21
|
end
|
27
22
|
|
28
|
-
|
29
|
-
task :em_http_request_0_x_spec do
|
30
|
-
sh "EM_HTTP_REQUEST_0_X=true bundle install && bundle exec rspec spec/acceptance/em_http_request/em_http_request_spec.rb" if RUBY_VERSION <= "1.8.7"
|
31
|
-
end
|
32
|
-
|
33
23
|
require 'rake/testtask'
|
34
24
|
Rake::TestTask.new(:test) do |test|
|
35
25
|
test.test_files = FileList["test/**/*.rb"].exclude("test/test_helper.rb")
|
26
|
+
test.options = "--use-color"
|
36
27
|
test.verbose = false
|
37
28
|
test.warning = false
|
38
29
|
end
|
39
30
|
|
40
31
|
Rake::TestTask.new(:minitest) do |test|
|
41
32
|
test.test_files = FileList["minitest/**/*.rb"].exclude("test/test_helper.rb")
|
33
|
+
test.options = "--pride"
|
42
34
|
test.verbose = false
|
43
35
|
test.warning = false
|
44
36
|
end
|
45
37
|
|
46
|
-
|
47
|
-
task :default => [:spec, :spec_http_without_webmock, :test, :minitest]
|
48
|
-
|
49
|
-
require 'rdoc/task'
|
50
|
-
RDoc::Task.new do |rdoc|
|
51
|
-
$:.push File.expand_path('../lib', __FILE__)
|
52
|
-
require 'webmock/version'
|
53
|
-
|
54
|
-
rdoc.rdoc_dir = 'rdoc'
|
55
|
-
rdoc.title = "webmock #{WebMock::VERSION}"
|
56
|
-
rdoc.rdoc_files.include('README*')
|
57
|
-
rdoc.rdoc_files.include('lib/webmock/webmock.rb')
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
task :require_ruby_18 do
|
62
|
-
raise "This must be run on Ruby 1.8" unless RUBY_VERSION =~ /^1\.8/
|
63
|
-
end
|
64
|
-
|
65
|
-
task :release => [:require_ruby_18]
|
38
|
+
task default: [:spec, :spec_http_without_webmock, :test, :minitest]
|
data/lib/webmock/api.rb
CHANGED
@@ -17,46 +17,92 @@ module WebMock
|
|
17
17
|
alias :request :a_request
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
20
|
def assert_requested(*args, &block)
|
22
21
|
if not args[0].is_a?(WebMock::RequestStub)
|
23
|
-
args = convert_uri_method_and_options_to_request_and_options(
|
22
|
+
args = convert_uri_method_and_options_to_request_and_options(args[0], args[1], args[2], &block)
|
23
|
+
elsif block
|
24
|
+
raise ArgumentError, "assert_requested with a stub object, doesn't accept blocks"
|
24
25
|
end
|
25
|
-
assert_request_requested(*args
|
26
|
+
assert_request_requested(*args)
|
26
27
|
end
|
27
28
|
|
28
29
|
def assert_not_requested(*args, &block)
|
29
30
|
if not args[0].is_a?(WebMock::RequestStub)
|
30
|
-
args = convert_uri_method_and_options_to_request_and_options(
|
31
|
+
args = convert_uri_method_and_options_to_request_and_options(args[0], args[1], args[2], &block)
|
32
|
+
elsif block
|
33
|
+
raise ArgumentError, "assert_not_requested with a stub object, doesn't accept blocks"
|
34
|
+
end
|
35
|
+
assert_request_not_requested(*args)
|
36
|
+
end
|
37
|
+
alias refute_requested assert_not_requested
|
38
|
+
|
39
|
+
# Similar to RSpec::Mocks::ArgumentMatchers#hash_including()
|
40
|
+
#
|
41
|
+
# Matches a hash that includes the specified key(s) or key/value pairs.
|
42
|
+
# Ignores any additional keys.
|
43
|
+
#
|
44
|
+
# @example
|
45
|
+
#
|
46
|
+
# object.should_receive(:message).with(hash_including(:key => val))
|
47
|
+
# object.should_receive(:message).with(hash_including(:key))
|
48
|
+
# object.should_receive(:message).with(hash_including(:key, :key2 => val2))
|
49
|
+
def hash_including(*args)
|
50
|
+
if defined?(super)
|
51
|
+
super
|
52
|
+
else
|
53
|
+
WebMock::Matchers::HashIncludingMatcher.new(anythingize_lonely_keys(*args))
|
31
54
|
end
|
32
|
-
assert_request_not_requested(*args, &block)
|
33
55
|
end
|
34
56
|
|
35
|
-
def
|
36
|
-
if defined?(
|
37
|
-
|
38
|
-
elsif defined?(::Spec::Mocks::ArgumentMatchers::HashIncludingMatcher)
|
39
|
-
Spec::Mocks::ArgumentMatchers::HashIncludingMatcher.new(expected)
|
57
|
+
def hash_excluding(*args)
|
58
|
+
if defined?(super)
|
59
|
+
super
|
40
60
|
else
|
41
|
-
WebMock::Matchers::
|
61
|
+
WebMock::Matchers::HashExcludingMatcher.new(anythingize_lonely_keys(*args))
|
42
62
|
end
|
43
63
|
end
|
44
64
|
|
65
|
+
def remove_request_stub(stub)
|
66
|
+
WebMock::StubRegistry.instance.remove_request_stub(stub)
|
67
|
+
end
|
68
|
+
|
69
|
+
def reset_executed_requests!
|
70
|
+
WebMock::RequestRegistry.instance.reset!
|
71
|
+
end
|
72
|
+
|
45
73
|
private
|
46
74
|
|
47
|
-
def convert_uri_method_and_options_to_request_and_options(
|
48
|
-
|
49
|
-
|
75
|
+
def convert_uri_method_and_options_to_request_and_options(method, uri, options, &block)
|
76
|
+
options ||= {}
|
77
|
+
options_for_pattern = options.dup
|
78
|
+
[:times, :at_least_times, :at_most_times].each { |key| options_for_pattern.delete(key) }
|
79
|
+
request = WebMock::RequestPattern.new(method, uri, options_for_pattern)
|
80
|
+
request = request.with(&block) if block
|
81
|
+
[request, options]
|
50
82
|
end
|
51
83
|
|
52
84
|
def assert_request_requested(request, options = {})
|
53
|
-
|
85
|
+
times = options.delete(:times)
|
86
|
+
at_least_times = options.delete(:at_least_times)
|
87
|
+
at_most_times = options.delete(:at_most_times)
|
88
|
+
times = 1 if times.nil? && at_least_times.nil? && at_most_times.nil?
|
89
|
+
verifier = WebMock::RequestExecutionVerifier.new(request, times, at_least_times, at_most_times)
|
54
90
|
WebMock::AssertionFailure.failure(verifier.failure_message) unless verifier.matches?
|
55
91
|
end
|
56
92
|
|
57
93
|
def assert_request_not_requested(request, options = {})
|
58
|
-
|
59
|
-
|
94
|
+
times = options.delete(:times)
|
95
|
+
at_least_times = options.delete(:at_least_times)
|
96
|
+
at_most_times = options.delete(:at_most_times)
|
97
|
+
verifier = WebMock::RequestExecutionVerifier.new(request, times, at_least_times, at_most_times)
|
98
|
+
WebMock::AssertionFailure.failure(verifier.failure_message_when_negated) unless verifier.does_not_match?
|
99
|
+
end
|
100
|
+
|
101
|
+
#this is a based on RSpec::Mocks::ArgumentMatchers#anythingize_lonely_keys
|
102
|
+
def anythingize_lonely_keys(*args)
|
103
|
+
hash = args.last.class == Hash ? args.delete_at(-1) : {}
|
104
|
+
args.each { | arg | hash[arg] = WebMock::Matchers::AnyArgMatcher.new(nil) }
|
105
|
+
hash
|
60
106
|
end
|
61
107
|
|
62
108
|
end
|
data/lib/webmock/config.rb
CHANGED
@@ -2,9 +2,17 @@ module WebMock
|
|
2
2
|
class Config
|
3
3
|
include Singleton
|
4
4
|
|
5
|
+
def initialize
|
6
|
+
@show_stubbing_instructions = true
|
7
|
+
@show_body_diff = true
|
8
|
+
end
|
9
|
+
|
5
10
|
attr_accessor :allow_net_connect
|
6
11
|
attr_accessor :allow_localhost
|
7
12
|
attr_accessor :allow
|
8
13
|
attr_accessor :net_http_connect_on_start
|
14
|
+
attr_accessor :show_stubbing_instructions
|
15
|
+
attr_accessor :query_values_notation
|
16
|
+
attr_accessor :show_body_diff
|
9
17
|
end
|
10
18
|
end
|
data/lib/webmock/cucumber.rb
CHANGED
data/lib/webmock/errors.rb
CHANGED
@@ -1,33 +1,17 @@
|
|
1
1
|
module WebMock
|
2
2
|
|
3
|
-
class NetConnectNotAllowedError <
|
3
|
+
class NetConnectNotAllowedError < Exception
|
4
4
|
def initialize(request_signature)
|
5
|
-
|
6
|
-
text
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
request_signature_snippet = RequestSignatureSnippet.new(request_signature)
|
6
|
+
text = [
|
7
|
+
"Real HTTP connections are disabled. Unregistered request: #{request_signature}",
|
8
|
+
request_signature_snippet.stubbing_instructions,
|
9
|
+
request_signature_snippet.request_stubs,
|
10
|
+
"="*60
|
11
|
+
].compact.join("\n\n")
|
10
12
|
super(text)
|
11
13
|
end
|
12
14
|
|
13
|
-
private
|
14
|
-
|
15
|
-
def request_stubs
|
16
|
-
return "" if WebMock::StubRegistry.instance.request_stubs.empty?
|
17
|
-
text = "\n\nregistered request stubs:\n"
|
18
|
-
WebMock::StubRegistry.instance.request_stubs.each do |stub|
|
19
|
-
text << "\n#{WebMock::StubRequestSnippet.new(stub).to_s(false)}"
|
20
|
-
end
|
21
|
-
text
|
22
|
-
end
|
23
|
-
|
24
|
-
def stubbing_instructions(request_signature)
|
25
|
-
text = ""
|
26
|
-
request_stub = RequestStub.from_request_signature(request_signature)
|
27
|
-
text << "You can stub this request with the following snippet:\n\n"
|
28
|
-
text << WebMock::StubRequestSnippet.new(request_stub).to_s
|
29
|
-
text
|
30
|
-
end
|
31
15
|
end
|
32
16
|
|
33
17
|
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
begin
|
2
|
+
require 'async'
|
3
|
+
require 'async/http'
|
4
|
+
rescue LoadError
|
5
|
+
# async-http not found
|
6
|
+
end
|
7
|
+
|
8
|
+
if defined?(Async::HTTP)
|
9
|
+
module WebMock
|
10
|
+
module HttpLibAdapters
|
11
|
+
class AsyncHttpClientAdapter < HttpLibAdapter
|
12
|
+
adapter_for :async_http_client
|
13
|
+
|
14
|
+
OriginalAsyncHttpClient = Async::HTTP::Client unless const_defined?(:OriginalAsyncHttpClient)
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def enable!
|
18
|
+
Async::HTTP.send(:remove_const, :Client)
|
19
|
+
Async::HTTP.send(:const_set, :Client, Async::HTTP::WebMockClientWrapper)
|
20
|
+
end
|
21
|
+
|
22
|
+
def disable!
|
23
|
+
Async::HTTP.send(:remove_const, :Client)
|
24
|
+
Async::HTTP.send(:const_set, :Client, OriginalAsyncHttpClient)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Async
|
32
|
+
module HTTP
|
33
|
+
class WebMockClientWrapper < Client
|
34
|
+
def initialize(
|
35
|
+
endpoint,
|
36
|
+
protocol = endpoint.protocol,
|
37
|
+
scheme = endpoint.scheme,
|
38
|
+
authority = endpoint.authority,
|
39
|
+
**options
|
40
|
+
)
|
41
|
+
webmock_endpoint = WebMockEndpoint.new(scheme, authority, protocol)
|
42
|
+
|
43
|
+
@network_client = WebMockClient.new(endpoint, **options)
|
44
|
+
@webmock_client = WebMockClient.new(webmock_endpoint, **options)
|
45
|
+
|
46
|
+
@scheme = scheme
|
47
|
+
@authority = authority
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(request)
|
51
|
+
request.scheme ||= self.scheme
|
52
|
+
request.authority ||= self.authority
|
53
|
+
|
54
|
+
request_signature = build_request_signature(request)
|
55
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
56
|
+
webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
|
57
|
+
net_connect_allowed = WebMock.net_connect_allowed?(request_signature.uri)
|
58
|
+
real_request = false
|
59
|
+
|
60
|
+
if webmock_response
|
61
|
+
webmock_response.raise_error_if_any
|
62
|
+
raise Async::TimeoutError, 'WebMock timeout error' if webmock_response.should_timeout
|
63
|
+
WebMockApplication.add_webmock_response(request, webmock_response)
|
64
|
+
response = @webmock_client.call(request)
|
65
|
+
elsif net_connect_allowed
|
66
|
+
response = @network_client.call(request)
|
67
|
+
real_request = true
|
68
|
+
else
|
69
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature) unless webmock_response
|
70
|
+
end
|
71
|
+
|
72
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
73
|
+
webmock_response ||= build_webmock_response(response)
|
74
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
75
|
+
{
|
76
|
+
lib: :async_http_client,
|
77
|
+
real_request: real_request
|
78
|
+
},
|
79
|
+
request_signature,
|
80
|
+
webmock_response
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
response
|
85
|
+
end
|
86
|
+
|
87
|
+
def close
|
88
|
+
@network_client.close
|
89
|
+
@webmock_client.close
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def build_request_signature(request)
|
95
|
+
body = request.read
|
96
|
+
request.body = ::Protocol::HTTP::Body::Buffered.wrap(body)
|
97
|
+
WebMock::RequestSignature.new(
|
98
|
+
request.method.downcase.to_sym,
|
99
|
+
"#{request.scheme}://#{request.authority}#{request.path}",
|
100
|
+
headers: request.headers.to_h,
|
101
|
+
body: body
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_webmock_response(response)
|
106
|
+
body = response.read
|
107
|
+
response.body = ::Protocol::HTTP::Body::Buffered.wrap(body)
|
108
|
+
|
109
|
+
webmock_response = WebMock::Response.new
|
110
|
+
webmock_response.status = [
|
111
|
+
response.status,
|
112
|
+
::Protocol::HTTP1::Reason::DESCRIPTIONS[response.status]
|
113
|
+
]
|
114
|
+
webmock_response.headers = build_webmock_response_headers(response)
|
115
|
+
webmock_response.body = body
|
116
|
+
webmock_response
|
117
|
+
end
|
118
|
+
|
119
|
+
def build_webmock_response_headers(response)
|
120
|
+
response.headers.each.each_with_object({}) do |(k, v), o|
|
121
|
+
o[k] ||= []
|
122
|
+
o[k] << v
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class WebMockClient < Client
|
128
|
+
end
|
129
|
+
|
130
|
+
class WebMockEndpoint
|
131
|
+
def initialize(scheme, authority, protocol)
|
132
|
+
@scheme = scheme
|
133
|
+
@authority = authority
|
134
|
+
@protocol = protocol
|
135
|
+
end
|
136
|
+
|
137
|
+
attr :scheme, :authority, :protocol
|
138
|
+
|
139
|
+
def connect
|
140
|
+
server_socket, client_socket = create_connected_sockets
|
141
|
+
Async(transient: true) do
|
142
|
+
accept_socket(server_socket)
|
143
|
+
end
|
144
|
+
client_socket
|
145
|
+
end
|
146
|
+
|
147
|
+
def inspect
|
148
|
+
"\#<#{self.class}> #{scheme}://#{authority} protocol=#{protocol}"
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def create_connected_sockets
|
154
|
+
Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM).tap do |sockets|
|
155
|
+
sockets.each do |socket|
|
156
|
+
socket.instance_variable_set :@alpn_protocol, nil
|
157
|
+
socket.instance_eval do
|
158
|
+
def alpn_protocol
|
159
|
+
nil # means HTTP11 will be used for HTTPS
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def accept_socket(socket)
|
167
|
+
server = Async::HTTP::Server.new(WebMockApplication, self)
|
168
|
+
server.accept(socket, socket.remote_address)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
module WebMockApplication
|
173
|
+
WEBMOCK_REQUEST_ID_HEADER = 'x-webmock-request-id'.freeze
|
174
|
+
|
175
|
+
class << self
|
176
|
+
def call(request)
|
177
|
+
request.read
|
178
|
+
webmock_response = get_webmock_response(request)
|
179
|
+
build_response(webmock_response)
|
180
|
+
end
|
181
|
+
|
182
|
+
def add_webmock_response(request, webmock_response)
|
183
|
+
webmock_request_id = request.object_id.to_s
|
184
|
+
request.headers.add(WEBMOCK_REQUEST_ID_HEADER, webmock_request_id)
|
185
|
+
webmock_responses[webmock_request_id] = webmock_response
|
186
|
+
end
|
187
|
+
|
188
|
+
def get_webmock_response(request)
|
189
|
+
webmock_request_id = request.headers[WEBMOCK_REQUEST_ID_HEADER][0]
|
190
|
+
webmock_responses.fetch(webmock_request_id)
|
191
|
+
end
|
192
|
+
|
193
|
+
private
|
194
|
+
|
195
|
+
def webmock_responses
|
196
|
+
@webmock_responses ||= {}
|
197
|
+
end
|
198
|
+
|
199
|
+
def build_response(webmock_response)
|
200
|
+
headers = (webmock_response.headers || {}).each_with_object([]) do |(k, value), o|
|
201
|
+
Array(value).each do |v|
|
202
|
+
o.push [k, v]
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
::Protocol::HTTP::Response[
|
207
|
+
webmock_response.status[0],
|
208
|
+
headers,
|
209
|
+
webmock_response.body
|
210
|
+
]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|