webmock 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +34 -0
  4. data/.rspec-tm +2 -0
  5. data/.travis.yml +19 -0
  6. data/CHANGELOG.md +1698 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE +20 -0
  9. data/README.md +1125 -0
  10. data/Rakefile +28 -0
  11. data/lib/webmock.rb +59 -0
  12. data/lib/webmock/api.rb +109 -0
  13. data/lib/webmock/assertion_failure.rb +11 -0
  14. data/lib/webmock/callback_registry.rb +35 -0
  15. data/lib/webmock/config.rb +18 -0
  16. data/lib/webmock/cucumber.rb +10 -0
  17. data/lib/webmock/deprecation.rb +9 -0
  18. data/lib/webmock/errors.rb +17 -0
  19. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +214 -0
  20. data/lib/webmock/http_lib_adapters/curb_adapter.rb +347 -0
  21. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +228 -0
  22. data/lib/webmock/http_lib_adapters/excon_adapter.rb +162 -0
  23. data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +7 -0
  24. data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +19 -0
  25. data/lib/webmock/http_lib_adapters/http_rb/client.rb +14 -0
  26. data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
  27. data/lib/webmock/http_lib_adapters/http_rb/response.rb +43 -0
  28. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
  29. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
  30. data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
  31. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +242 -0
  32. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +130 -0
  33. data/lib/webmock/http_lib_adapters/net_http.rb +361 -0
  34. data/lib/webmock/http_lib_adapters/net_http_response.rb +34 -0
  35. data/lib/webmock/http_lib_adapters/patron_adapter.rb +130 -0
  36. data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +174 -0
  37. data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
  38. data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
  39. data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
  40. data/lib/webmock/matchers/hash_including_matcher.rb +17 -0
  41. data/lib/webmock/minitest.rb +41 -0
  42. data/lib/webmock/rack_response.rb +69 -0
  43. data/lib/webmock/request_body_diff.rb +64 -0
  44. data/lib/webmock/request_execution_verifier.rb +77 -0
  45. data/lib/webmock/request_pattern.rb +370 -0
  46. data/lib/webmock/request_registry.rb +35 -0
  47. data/lib/webmock/request_signature.rb +54 -0
  48. data/lib/webmock/request_signature_snippet.rb +61 -0
  49. data/lib/webmock/request_stub.rb +100 -0
  50. data/lib/webmock/response.rb +153 -0
  51. data/lib/webmock/responses_sequence.rb +40 -0
  52. data/lib/webmock/rspec.rb +41 -0
  53. data/lib/webmock/rspec/matchers.rb +27 -0
  54. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +78 -0
  55. data/lib/webmock/rspec/matchers/webmock_matcher.rb +67 -0
  56. data/lib/webmock/stub_registry.rb +67 -0
  57. data/lib/webmock/stub_request_snippet.rb +38 -0
  58. data/lib/webmock/test_unit.rb +22 -0
  59. data/lib/webmock/util/hash_counter.rb +39 -0
  60. data/lib/webmock/util/hash_keys_stringifier.rb +25 -0
  61. data/lib/webmock/util/hash_validator.rb +17 -0
  62. data/lib/webmock/util/headers.rb +64 -0
  63. data/lib/webmock/util/json.rb +67 -0
  64. data/lib/webmock/util/query_mapper.rb +281 -0
  65. data/lib/webmock/util/uri.rb +110 -0
  66. data/lib/webmock/util/values_stringifier.rb +20 -0
  67. data/lib/webmock/util/version_checker.rb +111 -0
  68. data/lib/webmock/version.rb +3 -0
  69. data/lib/webmock/webmock.rb +161 -0
  70. data/minitest/test_helper.rb +34 -0
  71. data/minitest/test_webmock.rb +9 -0
  72. data/minitest/webmock_spec.rb +60 -0
  73. data/spec/acceptance/async_http_client/async_http_client_spec.rb +349 -0
  74. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  75. data/spec/acceptance/curb/curb_spec.rb +492 -0
  76. data/spec/acceptance/curb/curb_spec_helper.rb +147 -0
  77. data/spec/acceptance/em_http_request/em_http_request_spec.rb +406 -0
  78. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +77 -0
  79. data/spec/acceptance/excon/excon_spec.rb +77 -0
  80. data/spec/acceptance/excon/excon_spec_helper.rb +50 -0
  81. data/spec/acceptance/http_rb/http_rb_spec.rb +82 -0
  82. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
  83. data/spec/acceptance/httpclient/httpclient_spec.rb +217 -0
  84. data/spec/acceptance/httpclient/httpclient_spec_helper.rb +57 -0
  85. data/spec/acceptance/manticore/manticore_spec.rb +56 -0
  86. data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
  87. data/spec/acceptance/net_http/net_http_shared.rb +153 -0
  88. data/spec/acceptance/net_http/net_http_spec.rb +331 -0
  89. data/spec/acceptance/net_http/net_http_spec_helper.rb +64 -0
  90. data/spec/acceptance/net_http/real_net_http_spec.rb +20 -0
  91. data/spec/acceptance/patron/patron_spec.rb +125 -0
  92. data/spec/acceptance/patron/patron_spec_helper.rb +54 -0
  93. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +313 -0
  94. data/spec/acceptance/shared/callbacks.rb +148 -0
  95. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +36 -0
  96. data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +95 -0
  97. data/spec/acceptance/shared/precedence_of_stubs.rb +15 -0
  98. data/spec/acceptance/shared/request_expectations.rb +930 -0
  99. data/spec/acceptance/shared/returning_declared_responses.rb +409 -0
  100. data/spec/acceptance/shared/stubbing_requests.rb +643 -0
  101. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +135 -0
  102. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +60 -0
  103. data/spec/acceptance/webmock_shared.rb +41 -0
  104. data/spec/fixtures/test.txt +1 -0
  105. data/spec/quality_spec.rb +84 -0
  106. data/spec/spec_helper.rb +48 -0
  107. data/spec/support/example_curl_output.txt +22 -0
  108. data/spec/support/failures.rb +9 -0
  109. data/spec/support/my_rack_app.rb +53 -0
  110. data/spec/support/network_connection.rb +19 -0
  111. data/spec/support/webmock_server.rb +70 -0
  112. data/spec/unit/api_spec.rb +175 -0
  113. data/spec/unit/errors_spec.rb +129 -0
  114. data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +17 -0
  115. data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +12 -0
  116. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
  117. data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
  118. data/spec/unit/rack_response_spec.rb +112 -0
  119. data/spec/unit/request_body_diff_spec.rb +90 -0
  120. data/spec/unit/request_execution_verifier_spec.rb +208 -0
  121. data/spec/unit/request_pattern_spec.rb +601 -0
  122. data/spec/unit/request_registry_spec.rb +95 -0
  123. data/spec/unit/request_signature_snippet_spec.rb +89 -0
  124. data/spec/unit/request_signature_spec.rb +155 -0
  125. data/spec/unit/request_stub_spec.rb +199 -0
  126. data/spec/unit/response_spec.rb +282 -0
  127. data/spec/unit/stub_registry_spec.rb +103 -0
  128. data/spec/unit/stub_request_snippet_spec.rb +115 -0
  129. data/spec/unit/util/hash_counter_spec.rb +39 -0
  130. data/spec/unit/util/hash_keys_stringifier_spec.rb +27 -0
  131. data/spec/unit/util/headers_spec.rb +28 -0
  132. data/spec/unit/util/json_spec.rb +33 -0
  133. data/spec/unit/util/query_mapper_spec.rb +157 -0
  134. data/spec/unit/util/uri_spec.rb +361 -0
  135. data/spec/unit/util/version_checker_spec.rb +65 -0
  136. data/spec/unit/webmock_spec.rb +19 -0
  137. data/test/http_request.rb +24 -0
  138. data/test/shared_test.rb +108 -0
  139. data/test/test_helper.rb +23 -0
  140. data/test/test_webmock.rb +6 -0
  141. data/webmock.gemspec +45 -0
  142. metadata +496 -0
@@ -0,0 +1,35 @@
1
+ module WebMock
2
+
3
+ class RequestRegistry
4
+ include Singleton
5
+
6
+ attr_accessor :requested_signatures
7
+
8
+ def initialize
9
+ reset!
10
+ end
11
+
12
+ def reset!
13
+ self.requested_signatures = Util::HashCounter.new
14
+ end
15
+
16
+ def times_executed(request_pattern)
17
+ self.requested_signatures.select do |request_signature|
18
+ request_pattern.matches?(request_signature)
19
+ end.inject(0) { |sum, (_, times_executed)| sum + times_executed }
20
+ end
21
+
22
+ def to_s
23
+ if requested_signatures.hash.empty?
24
+ "No requests were made."
25
+ else
26
+ text = "".dup
27
+ self.requested_signatures.each do |request_signature, times_executed|
28
+ text << "#{request_signature} was made #{times_executed} time#{times_executed == 1 ? '' : 's' }\n"
29
+ end
30
+ text
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,54 @@
1
+ module WebMock
2
+
3
+ class RequestSignature
4
+
5
+ attr_accessor :method, :uri, :body
6
+ attr_reader :headers
7
+
8
+ def initialize(method, uri, options = {})
9
+ self.method = method.to_sym
10
+ self.uri = uri.is_a?(Addressable::URI) ? uri : WebMock::Util::URI.normalize_uri(uri)
11
+ assign_options(options)
12
+ end
13
+
14
+ def to_s
15
+ string = "#{self.method.to_s.upcase}".dup
16
+ string << " #{WebMock::Util::URI.strip_default_port_from_uri_string(self.uri.to_s)}"
17
+ string << " with body '#{body.to_s}'" if body && body.to_s != ''
18
+ if headers && !headers.empty?
19
+ string << " with headers #{WebMock::Util::Headers.sorted_headers_string(headers)}"
20
+ end
21
+ string
22
+ end
23
+
24
+ def headers=(headers)
25
+ @headers = WebMock::Util::Headers.normalize_headers(headers)
26
+ end
27
+
28
+ def hash
29
+ self.to_s.hash
30
+ end
31
+
32
+ def eql?(other)
33
+ self.to_s == other.to_s
34
+ end
35
+ alias == eql?
36
+
37
+ def url_encoded?
38
+ !!(headers && headers['Content-Type'] == 'application/x-www-form-urlencoded')
39
+ end
40
+
41
+ def json_headers?
42
+ !!(headers && headers['Content-Type'] == 'application/json')
43
+ end
44
+
45
+ private
46
+
47
+ def assign_options(options)
48
+ self.body = options[:body] if options.has_key?(:body)
49
+ self.headers = options[:headers] if options.has_key?(:headers)
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,61 @@
1
+ require "pp"
2
+
3
+ module WebMock
4
+ class RequestSignatureSnippet
5
+
6
+ attr_reader :request_signature, :request_stub
7
+
8
+ def initialize(request_signature)
9
+ @request_signature = request_signature
10
+ @request_stub = RequestStub.from_request_signature(request_signature)
11
+ end
12
+
13
+ def stubbing_instructions
14
+ return unless WebMock.show_stubbing_instructions?
15
+
16
+ "You can stub this request with the following snippet:\n\n" +
17
+ WebMock::StubRequestSnippet.new(request_stub).to_s
18
+ end
19
+
20
+ def request_stubs
21
+ return if WebMock::StubRegistry.instance.request_stubs.empty?
22
+
23
+ text = "registered request stubs:\n".dup
24
+ WebMock::StubRegistry.instance.request_stubs.each do |stub|
25
+ text << "\n#{WebMock::StubRequestSnippet.new(stub).to_s(false)}"
26
+ add_body_diff(stub, text) if WebMock.show_body_diff?
27
+ end
28
+ text
29
+ end
30
+
31
+ private
32
+
33
+ def add_body_diff(stub, text)
34
+ body_diff_str = signature_stub_body_diff(stub)
35
+ text << "\n\n#{body_diff_str}" unless body_diff_str.empty?
36
+ end
37
+
38
+ def signature_stub_body_diff(stub)
39
+ diff = RequestBodyDiff.new(request_signature, stub).body_diff
40
+ diff.empty? ? "" : "Body diff:\n #{pretty_print_to_string(diff)}"
41
+ end
42
+
43
+ def request_params
44
+ @request_params ||=
45
+ if request_signature.json_headers?
46
+ JSON.parse(request_signature.body)
47
+ else
48
+ ""
49
+ end
50
+ end
51
+
52
+ def pretty_print_to_string(string_to_print)
53
+ StringIO.open("".dup) do |stream|
54
+ PP.pp(string_to_print, stream)
55
+ stream.rewind
56
+ stream.read
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,100 @@
1
+ module WebMock
2
+ class RequestStub
3
+
4
+ attr_accessor :request_pattern
5
+
6
+ def initialize(method, uri)
7
+ @request_pattern = RequestPattern.new(method, uri)
8
+ @responses_sequences = []
9
+ self
10
+ end
11
+
12
+ def with(params = {}, &block)
13
+ @request_pattern.with(params, &block)
14
+ self
15
+ end
16
+
17
+ def to_return(*response_hashes, &block)
18
+ if block
19
+ @responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(block)])
20
+ else
21
+ @responses_sequences << ResponsesSequence.new([*response_hashes].flatten.map {|r| ResponseFactory.response_for(r)})
22
+ end
23
+ self
24
+ end
25
+ alias_method :and_return, :to_return
26
+
27
+ def to_rack(app, options={})
28
+ @responses_sequences << ResponsesSequence.new([RackResponse.new(app)])
29
+ end
30
+
31
+ def to_raise(*exceptions)
32
+ @responses_sequences << ResponsesSequence.new([*exceptions].flatten.map {|e|
33
+ ResponseFactory.response_for(exception: e)
34
+ })
35
+ self
36
+ end
37
+ alias_method :and_raise, :to_raise
38
+
39
+ def to_timeout
40
+ @responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(should_timeout: true)])
41
+ self
42
+ end
43
+ alias_method :and_timeout, :to_timeout
44
+
45
+ def response
46
+ if @responses_sequences.empty?
47
+ WebMock::Response.new
48
+ elsif @responses_sequences.length > 1
49
+ @responses_sequences.shift if @responses_sequences.first.end?
50
+ @responses_sequences.first.next_response
51
+ else
52
+ @responses_sequences[0].next_response
53
+ end
54
+ end
55
+
56
+ def has_responses?
57
+ !@responses_sequences.empty?
58
+ end
59
+
60
+ def then
61
+ self
62
+ end
63
+
64
+ def times(number)
65
+ raise "times(N) accepts integers >= 1 only" if !number.is_a?(Integer) || number < 1
66
+ if @responses_sequences.empty?
67
+ raise "Invalid WebMock stub declaration." +
68
+ " times(N) can be declared only after response declaration."
69
+ end
70
+ @responses_sequences.last.times_to_repeat += number-1
71
+ self
72
+ end
73
+
74
+ def matches?(request_signature)
75
+ self.request_pattern.matches?(request_signature)
76
+ end
77
+
78
+ def to_s
79
+ self.request_pattern.to_s
80
+ end
81
+
82
+ def self.from_request_signature(signature)
83
+ stub = self.new(signature.method.to_sym, signature.uri.to_s)
84
+
85
+ if signature.body.to_s != ''
86
+ body = if signature.url_encoded?
87
+ WebMock::Util::QueryMapper.query_to_values(signature.body, notation: Config.instance.query_values_notation)
88
+ else
89
+ signature.body
90
+ end
91
+ stub.with(body: body)
92
+ end
93
+
94
+ if (signature.headers && !signature.headers.empty?)
95
+ stub.with(headers: signature.headers)
96
+ end
97
+ stub
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,153 @@
1
+ require "pathname"
2
+
3
+ module WebMock
4
+
5
+ class ResponseFactory
6
+ def self.response_for(options)
7
+ if options.respond_to?(:call)
8
+ WebMock::DynamicResponse.new(options)
9
+ else
10
+ WebMock::Response.new(options)
11
+ end
12
+ end
13
+ end
14
+
15
+ class Response
16
+ def initialize(options = {})
17
+ if options.is_a?(IO) || options.is_a?(String)
18
+ self.options = read_raw_response(options)
19
+ else
20
+ self.options = options
21
+ end
22
+ end
23
+
24
+ def headers
25
+ @headers
26
+ end
27
+
28
+ def headers=(headers)
29
+ @headers = headers
30
+ if @headers && !@headers.is_a?(Proc)
31
+ @headers = Util::Headers.normalize_headers(@headers)
32
+ end
33
+ end
34
+
35
+ def body
36
+ @body || ''
37
+ end
38
+
39
+ def body=(body)
40
+ @body = body
41
+ assert_valid_body!
42
+ stringify_body!
43
+ end
44
+
45
+ def status
46
+ @status || [200, ""]
47
+ end
48
+
49
+ def status=(status)
50
+ @status = status.is_a?(Integer) ? [status, ""] : status
51
+ end
52
+
53
+ def exception
54
+ @exception
55
+ end
56
+
57
+ def exception=(exception)
58
+ @exception = case exception
59
+ when String then StandardError.new(exception)
60
+ when Class then exception.new('Exception from WebMock')
61
+ when Exception then exception
62
+ end
63
+ end
64
+
65
+ def raise_error_if_any
66
+ raise @exception if @exception
67
+ end
68
+
69
+ def should_timeout
70
+ @should_timeout == true
71
+ end
72
+
73
+ def options=(options)
74
+ options = WebMock::Util::HashKeysStringifier.stringify_keys!(options)
75
+ HashValidator.new(options).validate_keys('headers', 'status', 'body', 'exception', 'should_timeout')
76
+ self.headers = options['headers']
77
+ self.status = options['status']
78
+ self.body = options['body']
79
+ self.exception = options['exception']
80
+ @should_timeout = options['should_timeout']
81
+ end
82
+
83
+ def evaluate(request_signature)
84
+ self.body = @body.call(request_signature) if @body.is_a?(Proc)
85
+ self.headers = @headers.call(request_signature) if @headers.is_a?(Proc)
86
+ self.status = @status.call(request_signature) if @status.is_a?(Proc)
87
+ @should_timeout = @should_timeout.call(request_signature) if @should_timeout.is_a?(Proc)
88
+ @exception = @exception.call(request_signature) if @exception.is_a?(Proc)
89
+ self
90
+ end
91
+
92
+ def ==(other)
93
+ self.body == other.body &&
94
+ self.headers === other.headers &&
95
+ self.status == other.status &&
96
+ self.exception == other.exception &&
97
+ self.should_timeout == other.should_timeout
98
+ end
99
+
100
+ private
101
+
102
+ def stringify_body!
103
+ if @body.is_a?(IO) || @body.is_a?(Pathname)
104
+ io = @body
105
+ @body = io.read
106
+ io.close if io.respond_to?(:close)
107
+ end
108
+ end
109
+
110
+ def assert_valid_body!
111
+ valid_types = [Proc, IO, Pathname, String, Array]
112
+ return if @body.nil?
113
+ return if valid_types.any? { |c| @body.is_a?(c) }
114
+ raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given"
115
+ end
116
+
117
+ def read_raw_response(raw_response)
118
+ if raw_response.is_a?(IO)
119
+ string = raw_response.read
120
+ raw_response.close
121
+ raw_response = string
122
+ end
123
+ socket = ::Net::BufferedIO.new(raw_response)
124
+ response = ::Net::HTTPResponse.read_new(socket)
125
+ transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
126
+ response.reading_body(socket, true) {}
127
+
128
+ options = {}
129
+ options[:headers] = {}
130
+ response.each_header {|name, value| options[:headers][name] = value}
131
+ options[:headers]['transfer-encoding'] = transfer_encoding if transfer_encoding
132
+ options[:body] = response.read_body
133
+ options[:status] = [response.code.to_i, response.message]
134
+ options
135
+ end
136
+
137
+ InvalidBody = Class.new(StandardError)
138
+
139
+ end
140
+
141
+ class DynamicResponse < Response
142
+ attr_accessor :responder
143
+
144
+ def initialize(responder)
145
+ @responder = responder
146
+ end
147
+
148
+ def evaluate(request_signature)
149
+ options = @responder.call(request_signature)
150
+ Response.new(options)
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,40 @@
1
+ module WebMock
2
+
3
+ class ResponsesSequence
4
+
5
+ attr_accessor :times_to_repeat
6
+
7
+ def initialize(responses)
8
+ @times_to_repeat = 1
9
+ @responses = responses
10
+ @current_position = 0
11
+ end
12
+
13
+ def end?
14
+ @times_to_repeat == 0
15
+ end
16
+
17
+ def next_response
18
+ if @times_to_repeat > 0
19
+ response = @responses[@current_position]
20
+ increase_position
21
+ response
22
+ else
23
+ @responses.last
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def increase_position
30
+ if @current_position == (@responses.length - 1)
31
+ @current_position = 0
32
+ @times_to_repeat -= 1
33
+ else
34
+ @current_position += 1
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end