webmock 1.6.4 → 1.7.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.
- data/.gemtest +0 -0
- data/.gitignore +3 -1
- data/.travis.yml +6 -0
- data/CHANGELOG.md +211 -118
- data/Gemfile +16 -1
- data/Guardfile +24 -0
- data/LICENSE +1 -1
- data/README.md +64 -15
- data/Rakefile +19 -6
- data/lib/webmock.rb +9 -4
- data/lib/webmock/api.rb +5 -4
- data/lib/webmock/assertion_failure.rb +1 -1
- data/lib/webmock/callback_registry.rb +1 -1
- data/lib/webmock/config.rb +2 -2
- data/lib/webmock/cucumber.rb +1 -1
- data/lib/webmock/errors.rb +17 -5
- data/lib/webmock/http_lib_adapters/{curb.rb → curb_adapter.rb} +79 -49
- data/lib/webmock/http_lib_adapters/{em_http_request.rb → em_http_request/em_http_request_0_x.rb} +20 -15
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +201 -0
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +11 -0
- data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +7 -0
- data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +19 -0
- data/lib/webmock/http_lib_adapters/{httpclient.rb → httpclient_adapter.rb} +35 -8
- data/lib/webmock/http_lib_adapters/net_http.rb +84 -25
- data/lib/webmock/http_lib_adapters/net_http_response.rb +17 -17
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +124 -0
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +166 -0
- data/lib/webmock/minitest.rb +15 -0
- data/lib/webmock/rack_response.rb +52 -0
- data/lib/webmock/request_pattern.rb +4 -2
- data/lib/webmock/request_signature.rb +4 -0
- data/lib/webmock/request_stub.rb +35 -2
- data/lib/webmock/responses_sequence.rb +2 -2
- data/lib/webmock/rspec.rb +2 -2
- data/lib/webmock/rspec/matchers.rb +9 -4
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +1 -1
- data/lib/webmock/stub_registry.rb +1 -1
- data/lib/webmock/stub_request_snippet.rb +14 -11
- data/lib/webmock/util/hash_keys_stringifier.rb +4 -4
- data/lib/webmock/util/headers.rb +3 -3
- data/lib/webmock/util/json.rb +54 -0
- data/lib/webmock/util/uri.rb +1 -1
- data/lib/webmock/version.rb +1 -1
- data/lib/webmock/webmock.rb +20 -3
- data/minitest/test_helper.rb +29 -0
- data/minitest/test_webmock.rb +6 -0
- data/minitest/webmock_spec.rb +30 -0
- data/spec/curb_spec.rb +26 -8
- data/spec/curb_spec_helper.rb +6 -6
- data/spec/em_http_request_spec.rb +95 -1
- data/spec/em_http_request_spec_helper.rb +16 -16
- data/spec/errors_spec.rb +19 -4
- data/spec/example_curl_output.txt +22 -22
- data/spec/http_lib_adapters/http_lib_adapter_registry_spec.rb +17 -0
- data/spec/http_lib_adapters/http_lib_adapter_spec.rb +12 -0
- data/spec/httpclient_spec.rb +1 -1
- data/spec/httpclient_spec_helper.rb +3 -38
- data/spec/my_rack_app.rb +18 -0
- data/spec/net_http_shared.rb +125 -0
- data/spec/net_http_spec.rb +27 -31
- data/spec/net_http_spec_helper.rb +4 -34
- data/spec/network_connection.rb +1 -1
- data/spec/patron_spec_helper.rb +4 -7
- data/spec/quality_spec.rb +60 -0
- data/spec/rack_response_spec.rb +33 -0
- data/spec/real_net_http_spec.rb +20 -0
- data/spec/request_execution_verifier_spec.rb +8 -8
- data/spec/request_pattern_spec.rb +3 -3
- data/spec/request_stub_spec.rb +19 -19
- data/spec/response_spec.rb +8 -8
- data/spec/spec_helper.rb +14 -11
- data/spec/stub_request_snippet_spec.rb +85 -37
- data/spec/support/webmock_server.rb +62 -0
- data/spec/typhoeus_hydra_spec.rb +53 -0
- data/spec/typhoeus_hydra_spec_helper.rb +50 -0
- data/spec/util/headers_spec.rb +5 -5
- data/spec/util/json_spec.rb +7 -0
- data/spec/util/uri_spec.rb +1 -1
- data/spec/vendor/addressable/lib/uri.rb +1 -0
- data/spec/vendor/crack/lib/crack.rb +1 -0
- data/spec/vendor/right_http_connection-1.2.4/History.txt +4 -4
- data/spec/vendor/right_http_connection-1.2.4/README.txt +4 -4
- data/spec/vendor/right_http_connection-1.2.4/Rakefile +3 -3
- data/spec/vendor/right_http_connection-1.2.4/lib/net_fix.rb +4 -4
- data/spec/vendor/right_http_connection-1.2.4/setup.rb +4 -4
- data/spec/webmock_shared.rb +375 -143
- data/spec/webmock_spec.rb +7 -0
- data/test/http_request.rb +24 -0
- data/test/shared_test.rb +47 -0
- data/test/test_helper.rb +6 -3
- data/test/test_webmock.rb +2 -67
- data/webmock.gemspec +8 -7
- metadata +153 -88
- data/lib/webmock/http_lib_adapters/patron.rb +0 -100
- data/spec/other_net_http_libs_spec.rb +0 -30
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# This code is entierly copied from VCR (http://github.com/myronmarston/vcr) by courtesy of Myron Marston
|
|
1
|
+
# This code is entierly copied from VCR (http://github.com/myronmarston/vcr) by courtesy of Myron Marston
|
|
2
2
|
|
|
3
3
|
# A Net::HTTP response that has already been read raises an IOError when #read_body
|
|
4
4
|
# is called with a destination string or block.
|
|
@@ -11,22 +11,22 @@
|
|
|
11
11
|
# after it has aleady been read. This attemps to preserve the behavior of
|
|
12
12
|
# #read_body, acting just as if it had never been read.
|
|
13
13
|
|
|
14
|
-
module WebMock
|
|
15
|
-
module Net
|
|
16
|
-
module HTTPResponse
|
|
17
|
-
def read_body(dest = nil, &block)
|
|
18
|
-
return super if @__read_body_previously_called
|
|
19
|
-
return @body if dest.nil? && block.nil?
|
|
20
|
-
raise ArgumentError.new("both arg and block given for HTTP method") if dest && block
|
|
21
|
-
return nil if @body.nil?
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
module Net
|
|
16
|
+
module WebMockHTTPResponse
|
|
17
|
+
def read_body(dest = nil, &block)
|
|
18
|
+
return super if @__read_body_previously_called
|
|
19
|
+
return @body if dest.nil? && block.nil?
|
|
20
|
+
raise ArgumentError.new("both arg and block given for HTTP method") if dest && block
|
|
21
|
+
return nil if @body.nil?
|
|
22
|
+
|
|
23
|
+
dest ||= ::Net::ReadAdapter.new(block)
|
|
24
|
+
dest << @body
|
|
25
|
+
@body = dest
|
|
26
|
+
ensure
|
|
27
|
+
# allow subsequent calls to #read_body to proceed as normal, without our hack...
|
|
28
|
+
@__read_body_previously_called = true
|
|
30
29
|
end
|
|
31
30
|
end
|
|
32
|
-
end
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'patron'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
# patron not found
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
if defined?(::Patron)
|
|
8
|
+
module WebMock
|
|
9
|
+
module HttpLibAdapters
|
|
10
|
+
class PatronAdapter < ::WebMock::HttpLibAdapter
|
|
11
|
+
adapter_for :patron
|
|
12
|
+
|
|
13
|
+
OriginalPatronSession = ::Patron::Session unless const_defined?(:OriginalPatronSession)
|
|
14
|
+
|
|
15
|
+
class WebMockPatronSession < ::Patron::Session
|
|
16
|
+
def handle_request_with_webmock(req)
|
|
17
|
+
request_signature =
|
|
18
|
+
WebMock::HttpLibAdapters::PatronAdapter.build_request_signature(req)
|
|
19
|
+
|
|
20
|
+
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
21
|
+
|
|
22
|
+
if WebMock::StubRegistry.instance.registered_request?(request_signature)
|
|
23
|
+
webmock_response =
|
|
24
|
+
WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
25
|
+
WebMock::HttpLibAdapters::PatronAdapter.
|
|
26
|
+
handle_file_name(req, webmock_response)
|
|
27
|
+
res = WebMock::HttpLibAdapters::PatronAdapter.
|
|
28
|
+
build_patron_response(webmock_response)
|
|
29
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
30
|
+
{:lib => :patron}, request_signature, webmock_response)
|
|
31
|
+
res
|
|
32
|
+
elsif WebMock.net_connect_allowed?(request_signature.uri)
|
|
33
|
+
res = handle_request_without_webmock(req)
|
|
34
|
+
if WebMock::CallbackRegistry.any_callbacks?
|
|
35
|
+
webmock_response = WebMock::HttpLibAdapters::PatronAdapter.
|
|
36
|
+
build_webmock_response(res)
|
|
37
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
38
|
+
{:lib => :patron, :real_request => true}, request_signature,
|
|
39
|
+
webmock_response)
|
|
40
|
+
end
|
|
41
|
+
res
|
|
42
|
+
else
|
|
43
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
alias_method :handle_request_without_webmock, :handle_request
|
|
48
|
+
alias_method :handle_request, :handle_request_with_webmock
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.enable!
|
|
52
|
+
Patron.send(:remove_const, :Session)
|
|
53
|
+
Patron.send(:const_set, :Session, WebMockPatronSession)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.disable!
|
|
57
|
+
Patron.send(:remove_const, :Session)
|
|
58
|
+
Patron.send(:const_set, :Session, OriginalPatronSession)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.handle_file_name(req, webmock_response)
|
|
62
|
+
if req.action == :get && req.file_name
|
|
63
|
+
begin
|
|
64
|
+
File.open(req.file_name, "w") do |f|
|
|
65
|
+
f.write webmock_response.body
|
|
66
|
+
end
|
|
67
|
+
rescue Errno::EACCES
|
|
68
|
+
raise ArgumentError.new("Unable to open specified file.")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.build_request_signature(req)
|
|
74
|
+
uri = WebMock::Util::URI.heuristic_parse(req.url)
|
|
75
|
+
uri.path = uri.normalized_path.gsub("[^:]//","/")
|
|
76
|
+
uri.user = req.username
|
|
77
|
+
uri.password = req.password
|
|
78
|
+
|
|
79
|
+
if [:put, :post].include?(req.action)
|
|
80
|
+
if req.file_name
|
|
81
|
+
if !File.exist?(req.file_name) || !File.readable?(req.file_name)
|
|
82
|
+
raise ArgumentError.new("Unable to open specified file.")
|
|
83
|
+
end
|
|
84
|
+
request_body = File.read(req.file_name)
|
|
85
|
+
elsif req.upload_data
|
|
86
|
+
request_body = req.upload_data
|
|
87
|
+
else
|
|
88
|
+
raise ArgumentError.new("Must provide either data or a filename when doing a PUT or POST")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
request_signature = WebMock::RequestSignature.new(
|
|
93
|
+
req.action,
|
|
94
|
+
uri.to_s,
|
|
95
|
+
:body => request_body,
|
|
96
|
+
:headers => req.headers
|
|
97
|
+
)
|
|
98
|
+
request_signature
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.build_patron_response(webmock_response)
|
|
102
|
+
raise ::Patron::TimeoutError if webmock_response.should_timeout
|
|
103
|
+
webmock_response.raise_error_if_any
|
|
104
|
+
res = ::Patron::Response.new
|
|
105
|
+
res.instance_variable_set(:@body, webmock_response.body)
|
|
106
|
+
res.instance_variable_set(:@status, webmock_response.status[0])
|
|
107
|
+
res.instance_variable_set(:@status_line, webmock_response.status[1])
|
|
108
|
+
res.instance_variable_set(:@headers, webmock_response.headers)
|
|
109
|
+
res
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def self.build_webmock_response(patron_response)
|
|
113
|
+
webmock_response = WebMock::Response.new
|
|
114
|
+
reason = patron_response.status_line.
|
|
115
|
+
scan(%r(\AHTTP/(\d+\.\d+)\s+(\d\d\d)\s*([^\r\n]+)?))[0][2]
|
|
116
|
+
webmock_response.status = [patron_response.status, reason]
|
|
117
|
+
webmock_response.body = patron_response.body
|
|
118
|
+
webmock_response.headers = patron_response.headers
|
|
119
|
+
webmock_response
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'typhoeus'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
# typhoeus not found
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
if defined?(Typhoeus)
|
|
8
|
+
|
|
9
|
+
module WebMock
|
|
10
|
+
module HttpLibAdapters
|
|
11
|
+
class TyphoeusAdapter < HttpLibAdapter
|
|
12
|
+
adapter_for :typhoeus
|
|
13
|
+
|
|
14
|
+
def self.enable!
|
|
15
|
+
@disabled = false
|
|
16
|
+
add_after_request_callback
|
|
17
|
+
::Typhoeus::Hydra.allow_net_connect = true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.disable!
|
|
21
|
+
@disabled = true
|
|
22
|
+
remove_after_request_callback
|
|
23
|
+
::Typhoeus::Hydra.allow_net_connect = true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.disabled?
|
|
27
|
+
!!@disabled
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.add_after_request_callback
|
|
31
|
+
unless Typhoeus::Hydra.
|
|
32
|
+
global_hooks[:after_request_before_on_complete].
|
|
33
|
+
include?(AFTER_REQUEST_CALLBACK)
|
|
34
|
+
Typhoeus::Hydra.
|
|
35
|
+
global_hooks[:after_request_before_on_complete] << AFTER_REQUEST_CALLBACK
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.remove_after_request_callback
|
|
40
|
+
Typhoeus::Hydra.global_hooks[:after_request_before_on_complete].
|
|
41
|
+
delete_if {|v| v == AFTER_REQUEST_CALLBACK }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.build_request_signature(req)
|
|
45
|
+
uri = WebMock::Util::URI.heuristic_parse(req.url)
|
|
46
|
+
uri.path = uri.normalized_path.gsub("[^:]//","/")
|
|
47
|
+
if req.username
|
|
48
|
+
uri.user = req.username
|
|
49
|
+
uri.password = req.password
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
request_signature = WebMock::RequestSignature.new(
|
|
53
|
+
req.method,
|
|
54
|
+
uri.to_s,
|
|
55
|
+
:body => req.body,
|
|
56
|
+
:headers => req.headers
|
|
57
|
+
)
|
|
58
|
+
request_signature
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.build_webmock_response(typhoeus_response)
|
|
62
|
+
webmock_response = WebMock::Response.new
|
|
63
|
+
webmock_response.status = [typhoeus_response.code, typhoeus_response.status_message]
|
|
64
|
+
webmock_response.body = typhoeus_response.body
|
|
65
|
+
webmock_response.headers = typhoeus_response.headers_hash
|
|
66
|
+
webmock_response
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.stub_typhoeus(request_signature, webmock_response, typhoeus)
|
|
70
|
+
response = if webmock_response.should_timeout
|
|
71
|
+
::Typhoeus::Response.new(
|
|
72
|
+
:code => 0,
|
|
73
|
+
:status_message => "",
|
|
74
|
+
:body => "",
|
|
75
|
+
:headers_hash => {}
|
|
76
|
+
)
|
|
77
|
+
else
|
|
78
|
+
::Typhoeus::Response.new(
|
|
79
|
+
:code => webmock_response.status[0],
|
|
80
|
+
:status_message => webmock_response.status[1],
|
|
81
|
+
:body => webmock_response.body,
|
|
82
|
+
:headers_hash => webmock_response.headers
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
typhoeus.stub(
|
|
88
|
+
request_signature.method || :any,
|
|
89
|
+
/.*/,
|
|
90
|
+
:webmock_stub => true
|
|
91
|
+
).and_return(response)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.request_hash(request_signature)
|
|
95
|
+
hash = {}
|
|
96
|
+
|
|
97
|
+
hash[:body] = request_signature.body
|
|
98
|
+
hash[:headers] = request_signature.headers
|
|
99
|
+
|
|
100
|
+
hash
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
AFTER_REQUEST_CALLBACK = Proc.new do |request|
|
|
104
|
+
request_signature =
|
|
105
|
+
::WebMock::HttpLibAdapters::TyphoeusAdapter.
|
|
106
|
+
build_request_signature(request)
|
|
107
|
+
webmock_response =
|
|
108
|
+
::WebMock::HttpLibAdapters::TyphoeusAdapter.
|
|
109
|
+
build_webmock_response(request.response)
|
|
110
|
+
if request.response.mock?
|
|
111
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
112
|
+
{:lib => :typhoeus},
|
|
113
|
+
request_signature,
|
|
114
|
+
webmock_response
|
|
115
|
+
)
|
|
116
|
+
else
|
|
117
|
+
WebMock::CallbackRegistry.invoke_callbacks(
|
|
118
|
+
{:lib => :typhoeus, :real_request => true},
|
|
119
|
+
request_signature,
|
|
120
|
+
webmock_response
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
module Typhoeus
|
|
130
|
+
class Hydra
|
|
131
|
+
def queue_with_webmock(request)
|
|
132
|
+
self.clear_webmock_stubs
|
|
133
|
+
|
|
134
|
+
if WebMock::HttpLibAdapters::TyphoeusAdapter.disabled?
|
|
135
|
+
return queue_without_webmock(request)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
request_signature =
|
|
139
|
+
::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request)
|
|
140
|
+
|
|
141
|
+
::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
|
|
142
|
+
|
|
143
|
+
if ::WebMock::StubRegistry.instance.registered_request?(request_signature)
|
|
144
|
+
webmock_response =
|
|
145
|
+
::WebMock::StubRegistry.instance.response_for_request(request_signature)
|
|
146
|
+
::WebMock::HttpLibAdapters::TyphoeusAdapter.
|
|
147
|
+
stub_typhoeus(request_signature, webmock_response, self)
|
|
148
|
+
webmock_response.raise_error_if_any
|
|
149
|
+
elsif !WebMock.net_connect_allowed?(request_signature.uri)
|
|
150
|
+
raise WebMock::NetConnectNotAllowedError.new(request_signature)
|
|
151
|
+
end
|
|
152
|
+
queue_without_webmock(request)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
alias_method :queue_without_webmock, :queue
|
|
156
|
+
alias_method :queue, :queue_with_webmock
|
|
157
|
+
|
|
158
|
+
def clear_webmock_stubs
|
|
159
|
+
self.stubs = [] unless self.stubs
|
|
160
|
+
self.stubs.delete_if {|s|
|
|
161
|
+
s.instance_variable_get(:@options)[:webmock_stub]
|
|
162
|
+
}
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'minitest/unit'
|
|
2
|
+
require 'webmock'
|
|
3
|
+
|
|
4
|
+
MiniTest::Unit::TestCase.class_eval do
|
|
5
|
+
include WebMock::API
|
|
6
|
+
|
|
7
|
+
alias_method :teardown_without_webmock, :teardown
|
|
8
|
+
def teardown_with_webmock
|
|
9
|
+
teardown_without_webmock
|
|
10
|
+
WebMock.reset!
|
|
11
|
+
end
|
|
12
|
+
alias_method :teardown, :teardown_with_webmock
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
WebMock::AssertionFailure.error_class = MiniTest::Assertion
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module WebMock
|
|
2
|
+
class RackResponse < Response
|
|
3
|
+
def initialize(app)
|
|
4
|
+
@app = app
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def evaluate(request)
|
|
8
|
+
env = build_rack_env(request)
|
|
9
|
+
|
|
10
|
+
status, headers, response = @app.call(env)
|
|
11
|
+
|
|
12
|
+
Response.new(
|
|
13
|
+
:body => response.join,
|
|
14
|
+
:headers => headers,
|
|
15
|
+
:status => status
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def build_rack_env(request)
|
|
20
|
+
uri = request.uri
|
|
21
|
+
headers = request.headers || {}
|
|
22
|
+
body = request.body || ''
|
|
23
|
+
|
|
24
|
+
env = {
|
|
25
|
+
# CGI variables specified by Rack
|
|
26
|
+
'REQUEST_METHOD' => request.method.to_s.upcase,
|
|
27
|
+
'CONTENT_TYPE' => headers.delete('Content-Type'),
|
|
28
|
+
'CONTENT_LENGTH' => body.size,
|
|
29
|
+
'PATH_INFO' => uri.path,
|
|
30
|
+
'QUERY_STRING' => uri.query || '',
|
|
31
|
+
'SERVER_NAME' => uri.host
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Rack-specific variables
|
|
35
|
+
env['rack.input'] = StringIO.new(body)
|
|
36
|
+
env['rack.version'] = Rack::VERSION
|
|
37
|
+
env['rack.url_scheme'] = uri.scheme
|
|
38
|
+
env['rack.run_once'] = true
|
|
39
|
+
env['rack.session'] = session
|
|
40
|
+
|
|
41
|
+
headers.each do |k, v|
|
|
42
|
+
env["HTTP_#{k.tr('-','_').upcase}"] = v
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
env
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def session
|
|
49
|
+
@session ||= {}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -2,6 +2,8 @@ module WebMock
|
|
|
2
2
|
|
|
3
3
|
class RequestPattern
|
|
4
4
|
|
|
5
|
+
attr_reader :method_pattern, :uri_pattern, :body_pattern, :headers_pattern
|
|
6
|
+
|
|
5
7
|
def initialize(method, uri, options = {})
|
|
6
8
|
@method_pattern = MethodPattern.new(method)
|
|
7
9
|
@uri_pattern = create_uri_pattern(uri)
|
|
@@ -40,7 +42,7 @@ module WebMock
|
|
|
40
42
|
@headers_pattern = HeadersPattern.new(options[:headers]) if options.has_key?(:headers)
|
|
41
43
|
@uri_pattern.add_query_params(options[:query]) if options.has_key?(:query)
|
|
42
44
|
end
|
|
43
|
-
|
|
45
|
+
|
|
44
46
|
def create_uri_pattern(uri)
|
|
45
47
|
if uri.is_a?(Regexp)
|
|
46
48
|
URIRegexpPattern.new(uri)
|
|
@@ -143,7 +145,7 @@ module WebMock
|
|
|
143
145
|
|
|
144
146
|
case BODY_FORMATS[content_type]
|
|
145
147
|
when :json then
|
|
146
|
-
matching_hashes?(
|
|
148
|
+
matching_hashes?(WebMock::Util::JSON.parse(body), @pattern)
|
|
147
149
|
when :xml then
|
|
148
150
|
matching_hashes?(Crack::XML.parse(body), @pattern)
|
|
149
151
|
else
|
data/lib/webmock/request_stub.rb
CHANGED
|
@@ -23,13 +23,17 @@ module WebMock
|
|
|
23
23
|
self
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def to_rack(app, options={})
|
|
27
|
+
@responses_sequences << ResponsesSequence.new([RackResponse.new(app)])
|
|
28
|
+
end
|
|
29
|
+
|
|
26
30
|
def to_raise(*exceptions)
|
|
27
|
-
@responses_sequences << ResponsesSequence.new([*exceptions].flatten.map {|e|
|
|
31
|
+
@responses_sequences << ResponsesSequence.new([*exceptions].flatten.map {|e|
|
|
28
32
|
ResponseFactory.response_for(:exception => e)
|
|
29
33
|
})
|
|
30
34
|
self
|
|
31
35
|
end
|
|
32
|
-
|
|
36
|
+
|
|
33
37
|
def to_timeout
|
|
34
38
|
@responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(:should_timeout => true)])
|
|
35
39
|
self
|
|
@@ -46,6 +50,10 @@ module WebMock
|
|
|
46
50
|
end
|
|
47
51
|
end
|
|
48
52
|
|
|
53
|
+
def has_responses?
|
|
54
|
+
!@responses_sequences.empty?
|
|
55
|
+
end
|
|
56
|
+
|
|
49
57
|
def then
|
|
50
58
|
self
|
|
51
59
|
end
|
|
@@ -60,5 +68,30 @@ module WebMock
|
|
|
60
68
|
self
|
|
61
69
|
end
|
|
62
70
|
|
|
71
|
+
def matches?(request_signature)
|
|
72
|
+
self.request_pattern.matches?(request_signature)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def to_s
|
|
76
|
+
self.request_pattern.to_s
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.from_request_signature(signature)
|
|
80
|
+
stub = self.new(signature.method.to_sym, signature.uri.to_s)
|
|
81
|
+
|
|
82
|
+
if signature.body.to_s != ''
|
|
83
|
+
body = if signature.url_encoded?
|
|
84
|
+
Addressable::URI.parse('?' + signature.body).query_values
|
|
85
|
+
else
|
|
86
|
+
signature.body
|
|
87
|
+
end
|
|
88
|
+
stub.with(:body => body)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
if (signature.headers && !signature.headers.empty?)
|
|
92
|
+
stub.with(:headers => signature.headers)
|
|
93
|
+
end
|
|
94
|
+
stub
|
|
95
|
+
end
|
|
63
96
|
end
|
|
64
97
|
end
|