webmock 3.0.1 → 3.18.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/CI.yml +38 -0
  3. data/CHANGELOG.md +496 -2
  4. data/Gemfile +1 -1
  5. data/README.md +169 -34
  6. data/Rakefile +12 -4
  7. data/lib/webmock/api.rb +12 -0
  8. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +221 -0
  9. data/lib/webmock/http_lib_adapters/curb_adapter.rb +19 -5
  10. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +7 -4
  11. data/lib/webmock/http_lib_adapters/excon_adapter.rb +5 -2
  12. data/lib/webmock/http_lib_adapters/http_rb/client.rb +2 -1
  13. data/lib/webmock/http_lib_adapters/http_rb/request.rb +7 -1
  14. data/lib/webmock/http_lib_adapters/http_rb/response.rb +27 -3
  15. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +9 -3
  16. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +7 -3
  17. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +28 -9
  18. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +33 -15
  19. data/lib/webmock/http_lib_adapters/net_http.rb +36 -89
  20. data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
  21. data/lib/webmock/http_lib_adapters/patron_adapter.rb +4 -4
  22. data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
  23. data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
  24. data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
  25. data/lib/webmock/matchers/hash_including_matcher.rb +4 -23
  26. data/lib/webmock/rack_response.rb +1 -1
  27. data/lib/webmock/request_body_diff.rb +1 -1
  28. data/lib/webmock/request_execution_verifier.rb +2 -3
  29. data/lib/webmock/request_pattern.rb +129 -51
  30. data/lib/webmock/request_registry.rb +1 -1
  31. data/lib/webmock/request_signature.rb +3 -3
  32. data/lib/webmock/request_signature_snippet.rb +4 -4
  33. data/lib/webmock/request_stub.rb +15 -0
  34. data/lib/webmock/response.rb +19 -13
  35. data/lib/webmock/rspec.rb +10 -3
  36. data/lib/webmock/stub_registry.rb +26 -11
  37. data/lib/webmock/stub_request_snippet.rb +10 -6
  38. data/lib/webmock/test_unit.rb +1 -3
  39. data/lib/webmock/util/hash_counter.rb +3 -3
  40. data/lib/webmock/util/headers.rb +17 -2
  41. data/lib/webmock/util/json.rb +1 -2
  42. data/lib/webmock/util/query_mapper.rb +9 -7
  43. data/lib/webmock/util/uri.rb +10 -10
  44. data/lib/webmock/util/values_stringifier.rb +20 -0
  45. data/lib/webmock/version.rb +1 -1
  46. data/lib/webmock/webmock.rb +20 -3
  47. data/lib/webmock.rb +53 -48
  48. data/minitest/webmock_spec.rb +3 -3
  49. data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
  50. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  51. data/spec/acceptance/curb/curb_spec.rb +44 -0
  52. data/spec/acceptance/em_http_request/em_http_request_spec.rb +57 -1
  53. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +2 -2
  54. data/spec/acceptance/excon/excon_spec.rb +4 -2
  55. data/spec/acceptance/excon/excon_spec_helper.rb +2 -0
  56. data/spec/acceptance/http_rb/http_rb_spec.rb +20 -0
  57. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +5 -2
  58. data/spec/acceptance/httpclient/httpclient_spec.rb +8 -1
  59. data/spec/acceptance/manticore/manticore_spec.rb +51 -0
  60. data/spec/acceptance/net_http/net_http_shared.rb +47 -10
  61. data/spec/acceptance/net_http/net_http_spec.rb +102 -24
  62. data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
  63. data/spec/acceptance/patron/patron_spec.rb +26 -21
  64. data/spec/acceptance/patron/patron_spec_helper.rb +3 -3
  65. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +14 -14
  66. data/spec/acceptance/shared/callbacks.rb +3 -2
  67. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +1 -1
  68. data/spec/acceptance/shared/request_expectations.rb +14 -0
  69. data/spec/acceptance/shared/returning_declared_responses.rb +36 -15
  70. data/spec/acceptance/shared/stubbing_requests.rb +95 -0
  71. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +1 -1
  72. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +1 -1
  73. data/spec/support/webmock_server.rb +1 -0
  74. data/spec/unit/api_spec.rb +103 -3
  75. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
  76. data/spec/unit/request_execution_verifier_spec.rb +12 -12
  77. data/spec/unit/request_pattern_spec.rb +207 -49
  78. data/spec/unit/request_signature_snippet_spec.rb +2 -2
  79. data/spec/unit/request_signature_spec.rb +21 -1
  80. data/spec/unit/request_stub_spec.rb +35 -0
  81. data/spec/unit/response_spec.rb +51 -19
  82. data/spec/unit/stub_request_snippet_spec.rb +30 -10
  83. data/spec/unit/util/query_mapper_spec.rb +13 -0
  84. data/spec/unit/util/uri_spec.rb +74 -2
  85. data/spec/unit/webmock_spec.rb +108 -5
  86. data/test/shared_test.rb +15 -2
  87. data/test/test_webmock.rb +6 -0
  88. data/webmock.gemspec +15 -7
  89. metadata +86 -37
  90. data/.travis.yml +0 -20
data/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  WebMock
2
2
  =======
3
- [![Gem Version](https://badge.fury.io/rb/webmock.svg)](http://badge.fury.io/rb/webmock) [![Build Status](https://secure.travis-ci.org/bblimke/webmock.svg?branch=master)](http://travis-ci.org/bblimke/webmock) [![Dependency Status](https://gemnasium.com/bblimke/webmock.svg)](http://gemnasium.com/bblimke/webmock) [![Code Climate](https://codeclimate.com/github/bblimke/webmock/badges/gpa.svg)](https://codeclimate.com/github/bblimke/webmock) [![Inline docs](http://inch-ci.org/github/bblimke/webmock.svg?branch=master)](http://inch-ci.org/github/bblimke/webmock)
3
+ [![Gem Version](https://badge.fury.io/rb/webmock.svg)](http://badge.fury.io/rb/webmock)
4
+ [![Build Status](https://github.com/bblimke/webmock/workflows/CI/badge.svg?branch=master)](https://github.com/bblimke/webmock/actions)
5
+ [![Code Climate](https://codeclimate.com/github/bblimke/webmock/badges/gpa.svg)](https://codeclimate.com/github/bblimke/webmock)
6
+ [![Mentioned in Awesome Ruby](https://awesome.re/mentioned-badge.svg)](https://github.com/markets/awesome-ruby)
7
+ [![Inline docs](http://inch-ci.org/github/bblimke/webmock.svg?branch=master)](http://inch-ci.org/github/bblimke/webmock)
8
+ [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=webmock&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=webmock&package-manager=bundler&version-scheme=semver)
4
9
 
5
10
  Library for stubbing and setting expectations on HTTP requests in Ruby.
6
11
 
@@ -19,30 +24,42 @@ Features
19
24
  Supported HTTP libraries
20
25
  ------------------------
21
26
 
22
- * Net::HTTP and libraries based on Net::HTTP (i.e RightHttpConnection, REST Client, HTTParty)
23
- * HTTPClient
24
- * Patron
25
- * EM-HTTP-Request
26
- * Curb (currently only Curb::Easy)
27
- * Typhoeus (currently only Typhoeus::Hydra)
28
- * Excon
29
- * HTTP Gem
30
- * Manticore
27
+ * [Async::HTTP::Client](https://github.com/socketry/async-http)
28
+ * [Curb](https://github.com/taf2/curb) (currently only Curb::Easy)
29
+ * [EM-HTTP-Request](https://github.com/igrigorik/em-http-request)
30
+ * [Excon](https://github.com/excon/excon)
31
+ * [HTTPClient](https://github.com/nahi/httpclient)
32
+ * [HTTP Gem (also known as http.rb)](https://github.com/httprb/http)
33
+ * [httpx](https://honeyryderchuck.gitlab.io/httpx/wiki/Webmock-Adapter)
34
+ * [Manticore](https://github.com/cheald/manticore)
35
+ * [Net::HTTP](https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html) and other libraries based on Net::HTTP, e.g.:
36
+ * [HTTParty](https://github.com/jnunemaker/httparty)
37
+ * [REST Client](https://github.com/rest-client/rest-client)
38
+ * [Patron](https://github.com/toland/patron)
39
+ * [Typhoeus](https://github.com/typhoeus/typhoeus) (currently only Typhoeus::Hydra)
31
40
 
32
41
  Supported Ruby Interpreters
33
42
  ---------------------------
34
43
 
35
- * MRI 2.0
36
- * MRI 2.1
37
- * MRI 2.2
38
- * MRI 2.3
39
- * MRI 2.4
44
+ * MRI 2.5
45
+ * MRI 2.6
46
+ * MRI 2.7
40
47
  * JRuby
41
48
  * Rubinius
42
49
 
43
50
  ## Installation
44
51
 
52
+ ```bash
45
53
  gem install webmock
54
+ ```
55
+ or alternatively:
56
+
57
+ ```ruby
58
+ # add to your Gemfile
59
+ group :test do
60
+ gem "webmock"
61
+ end
62
+ ```
46
63
 
47
64
  ### or to install the latest development version from github master
48
65
 
@@ -54,36 +71,36 @@ Supported Ruby Interpreters
54
71
 
55
72
  WebMock 2.x has changed somewhat since version 1.x. Changes are listed in [CHANGELOG.md](CHANGELOG.md)
56
73
 
57
- ### Test::Unit
74
+ ### Cucumber
58
75
 
59
- Add the following code to `test/test_helper.rb`
76
+ Create a file `features/support/webmock.rb` with the following contents:
60
77
 
61
78
  ```ruby
62
- require 'webmock/test_unit'
79
+ require 'webmock/cucumber'
63
80
  ```
64
81
 
65
- ### RSpec
82
+ ### MiniTest
66
83
 
67
- Add the following code to `spec/spec_helper`:
84
+ Add the following code to `test/test_helper`:
68
85
 
69
86
  ```ruby
70
- require 'webmock/rspec'
87
+ require 'webmock/minitest'
71
88
  ```
72
89
 
73
- ### MiniTest
90
+ ### RSpec
74
91
 
75
- Add the following code to `test/test_helper`:
92
+ Add the following code to `spec/spec_helper`:
76
93
 
77
94
  ```ruby
78
- require 'webmock/minitest'
95
+ require 'webmock/rspec'
79
96
  ```
80
97
 
81
- ### Cucumber
98
+ ### Test::Unit
82
99
 
83
- Create a file `features/support/webmock.rb` with the following contents:
100
+ Add the following code to `test/test_helper.rb`
84
101
 
85
102
  ```ruby
86
- require 'webmock/cucumber'
103
+ require 'webmock/test_unit'
87
104
  ```
88
105
 
89
106
  ### Outside a test framework
@@ -97,13 +114,10 @@ include WebMock::API
97
114
  WebMock.enable!
98
115
  ```
99
116
 
100
- ## Examples
101
-
102
-
117
+ # Examples
103
118
 
104
119
  ## Stubbing
105
120
 
106
-
107
121
  ### Stubbed request based on uri only and with the default response
108
122
 
109
123
  ```ruby
@@ -236,6 +250,12 @@ stub_request(:any, /example/)
236
250
  Net::HTTP.get('www.example.com', '/') # ===> Success
237
251
  ```
238
252
 
253
+ ### Matching uris using lambda
254
+
255
+ ```ruby
256
+ stub_request(:any, ->(uri) { true })
257
+ ```
258
+
239
259
  ### Matching uris using RFC 6570 - Basic Example
240
260
 
241
261
  ```ruby
@@ -273,6 +293,16 @@ stub_request(:get, "www.example.com").
273
293
  RestClient.get("http://www.example.com/?a[]=b&a[]=c&x=1") # ===> Success
274
294
  ```
275
295
 
296
+ ### Matching partial query params using hash_excluding
297
+
298
+ ```ruby
299
+ stub_request(:get, "www.example.com").
300
+ with(query: hash_excluding({"a" => "b"}))
301
+
302
+ RestClient.get("http://www.example.com/?a=b") # ===> Failure
303
+ RestClient.get("http://www.example.com/?a=c") # ===> Success
304
+ ```
305
+
276
306
  ### Stubbing with custom response
277
307
 
278
308
  ```ruby
@@ -283,6 +313,12 @@ stub_request(:any, "www.example.com").
283
313
  Net::HTTP.get("www.example.com", '/') # ===> "abc"
284
314
  ```
285
315
 
316
+ Set appropriate Content-Type for HTTParty's `parsed_response`.
317
+
318
+ ```ruby
319
+ stub_request(:any, "www.example.com").to_return body: '{}', headers: {content_type: 'application/json'}
320
+ ```
321
+
286
322
  ### Response with body specified as IO object
287
323
 
288
324
  ```ruby
@@ -514,9 +550,9 @@ RestClient.get('sample.org', '/bar') # ===> Failure
514
550
  With an object that responds to `#call`, receiving a `URI` object and returning a boolean:
515
551
 
516
552
  ```ruby
517
- blacklist = ['google.com', 'facebook.com', 'apple.com']
553
+ denylist = ['google.com', 'facebook.com', 'apple.com']
518
554
  allowed_sites = lambda{|uri|
519
- blacklist.none?{|site| uri.host.include?(site) }
555
+ denylist.none?{|site| uri.host.include?(site) }
520
556
  }
521
557
  WebMock.disable_net_connect!(allow: allowed_sites)
522
558
 
@@ -696,6 +732,28 @@ Net::HTTP.get('www.example.com', '/') # ===> Failure
696
732
  assert_not_requested :get, "www.example.com" # ===> Success
697
733
  ```
698
734
 
735
+ ## Clearing request counters
736
+
737
+ If you want to reset **only** the counters of the executed requests use `WebMock.reset_executed_requests!`
738
+
739
+ ```ruby
740
+ stub = stub_request(:get, "www.example.com")
741
+ stub2 = stub_request(:get, "www.example2.com")
742
+
743
+ Net::HTTP.get('www.example.com', '/')
744
+ Net::HTTP.get('www.example.com', '/')
745
+
746
+ Net::HTTP.get('www.example2.com', '/')
747
+
748
+ expect(stub).to have_been_requested.times(2)
749
+ expect(stub2).to have_been_requested.times(1)
750
+
751
+ WebMock.reset_executed_requests!
752
+
753
+ expect(stub).not_to have_been_requested
754
+ expect(stub2).not_to have_been_requested
755
+ ```
756
+
699
757
  ## Disabling and enabling WebMock or only some http client adapters
700
758
 
701
759
  ```ruby
@@ -841,6 +899,10 @@ end
841
899
 
842
900
  Please submit them here [http://github.com/bblimke/webmock/issues](http://github.com/bblimke/webmock/issues)
843
901
 
902
+ ## Issue triage [![Open Source Helpers](https://www.codetriage.com/bblimke/webmock/badges/users.svg)](https://www.codetriage.com/bblimke/webmock)
903
+
904
+ You can contribute by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to webmock on CodeTriage](https://www.codetriage.com/bblimke/webmock).
905
+
844
906
  ## Suggestions
845
907
 
846
908
  If you have any suggestions on how to improve WebMock please send an email to the mailing list [groups.google.com/group/webmock-users](http://groups.google.com/group/webmock-users)
@@ -1035,13 +1097,86 @@ People who submitted patches and new features or suggested improvements. Many th
1035
1097
  * George Ulmer
1036
1098
  * Christof Koenig
1037
1099
  * Chung-Yi Chi
1100
+ * Olexandr Hoshylyk
1101
+ * Janko Marohnić
1102
+ * Pat Allan
1103
+ * Rick Song
1104
+ * NARUSE, Yui
1105
+ * Piotr Boniecki
1106
+ * Olia Kremmyda
1107
+ * Michał Matyas
1108
+ * Matt Brictson
1109
+ * Kenny Ortmann
1110
+ * redbar0n
1111
+ * Lukas Pokorny
1112
+ * Arkadiy Tetelman
1113
+ * Kazato Sugimoto
1114
+ * Olle Jonsson
1115
+ * Pavel Rosický
1116
+ * Geremia Taglialatela
1117
+ * Koichi Sasada
1118
+ * Yusuke Endoh
1119
+ * Grey Baker
1120
+ * SoonKhen OwYong
1121
+ * Pavel Valena
1122
+ * Adam Sokolnicki
1123
+ * Jeff Felchner
1124
+ * Eike Send
1125
+ * Claudio Poli
1126
+ * Csaba Apagyi
1127
+ * Frederick Cheung
1128
+ * Fábio D. Batista
1129
+ * Andriy Yanko
1130
+ * y-yagi
1131
+ * Rafael França
1132
+ * George Claghorn
1133
+ * Alex Junger
1134
+ * Orien Madgwick
1135
+ * Andrei Sidorov
1136
+ * Marco Costa
1137
+ * Ryan Davis
1138
+ * Brandur
1139
+ * Samuel Williams
1140
+ * Patrik Ragnarsson
1141
+ * Alex Coomans
1142
+ * Vesa Laakso
1143
+ * John Hawthorn
1144
+ * guppy0356
1145
+ * Thilo Rusche
1146
+ * Andrew Stuntz
1147
+ * Lucas Uyezu
1148
+ * Bruno Sutic
1149
+ * Ryan Kerr
1150
+ * Adam Harwood
1151
+ * Ben Koshy
1152
+ * Jesse Bowes
1153
+ * Marek Kasztelnik
1154
+ * ce07c3
1155
+ * Jun Jiang
1156
+ * Oleksiy Kovyrin
1157
+ * Matt Larraz
1158
+ * Tony Schneider
1159
+ * Niklas Hösl
1160
+ * Johanna Hartmann
1161
+ * Alex Vondrak
1162
+ * Will Storey
1163
+ * Eduardo Hernandez
1164
+ * ojab
1165
+ * Giorgio Gambino
1166
+ * Timmitry
1167
+ * Michael Fairley
1168
+ * Ray Zane
1169
+ * Go Sueyoshi
1170
+ * Cedric Sohrauer
1171
+ * Akira Matsuda
1172
+ * Mark Spangler
1038
1173
 
1039
1174
  For a full list of contributors you can visit the
1040
1175
  [contributors](https://github.com/bblimke/webmock/contributors) page.
1041
1176
 
1042
1177
  ## Background
1043
1178
 
1044
- Thank you Fakeweb! This library was inspired by [FakeWeb](http://fakeweb.rubyforge.org).
1179
+ Thank you Fakeweb! This library was inspired by [FakeWeb](https://github.com/chrisk/fakeweb).
1045
1180
  I imported some solutions from that project to WebMock. I also copied some code i.e Net:HTTP adapter.
1046
1181
  Fakeweb architecture unfortunately didn't allow me to extend it easily with the features I needed.
1047
1182
  I also preferred some things to work differently i.e request stub precedence.
data/Rakefile CHANGED
@@ -1,28 +1,36 @@
1
- #!/usr/bin/env rake
2
-
3
1
  require 'bundler'
4
2
  Bundler::GemHelper.install_tasks
5
3
 
6
4
  require "rspec/core/rake_task"
7
5
  RSpec::Core::RakeTask.new(:spec) do |t|
8
- t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
6
+ t.rspec_opts = %w[
7
+ --force-color
8
+ --format progress
9
+ --require ./spec/spec_helper.rb
10
+ ]
9
11
  t.pattern = 'spec/**/*_spec.rb'
10
12
  end
11
13
 
12
14
  RSpec::Core::RakeTask.new(:spec_http_without_webmock) do |t|
13
- t.rspec_opts = ["-c", "-f progress", "-r ./spec/acceptance/net_http/real_net_http_spec.rb"]
15
+ t.rspec_opts = %w[
16
+ --force-color
17
+ --format progress
18
+ --require ./spec/acceptance/net_http/real_net_http_spec.rb
19
+ ]
14
20
  t.pattern = 'spec/acceptance/net_http/real_net_http_spec.rb'
15
21
  end
16
22
 
17
23
  require 'rake/testtask'
18
24
  Rake::TestTask.new(:test) do |test|
19
25
  test.test_files = FileList["test/**/*.rb"].exclude("test/test_helper.rb")
26
+ test.options = "--use-color"
20
27
  test.verbose = false
21
28
  test.warning = false
22
29
  end
23
30
 
24
31
  Rake::TestTask.new(:minitest) do |test|
25
32
  test.test_files = FileList["minitest/**/*.rb"].exclude("test/test_helper.rb")
33
+ test.options = "--pride"
26
34
  test.verbose = false
27
35
  test.warning = false
28
36
  end
data/lib/webmock/api.rb CHANGED
@@ -54,10 +54,22 @@ module WebMock
54
54
  end
55
55
  end
56
56
 
57
+ def hash_excluding(*args)
58
+ if defined?(super)
59
+ super
60
+ else
61
+ WebMock::Matchers::HashExcludingMatcher.new(anythingize_lonely_keys(*args))
62
+ end
63
+ end
64
+
57
65
  def remove_request_stub(stub)
58
66
  WebMock::StubRegistry.instance.remove_request_stub(stub)
59
67
  end
60
68
 
69
+ def reset_executed_requests!
70
+ WebMock::RequestRegistry.instance.reset!
71
+ end
72
+
61
73
  private
62
74
 
63
75
  def convert_uri_method_and_options_to_request_and_options(method, uri, options, &block)
@@ -0,0 +1,221 @@
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
+ pair = begin
155
+ Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
156
+ rescue Errno::EAFNOSUPPORT
157
+ Async::IO::Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM)
158
+ end
159
+ pair.tap do |sockets|
160
+ sockets.each do |socket|
161
+ socket.instance_variable_set :@alpn_protocol, nil
162
+ socket.instance_eval do
163
+ def alpn_protocol
164
+ nil # means HTTP11 will be used for HTTPS
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ def accept_socket(socket)
172
+ server = Async::HTTP::Server.new(WebMockApplication, self)
173
+ server.accept(socket, socket.remote_address)
174
+ end
175
+ end
176
+
177
+ module WebMockApplication
178
+ WEBMOCK_REQUEST_ID_HEADER = 'x-webmock-request-id'.freeze
179
+
180
+ class << self
181
+ def call(request)
182
+ request.read
183
+ webmock_response = get_webmock_response(request)
184
+ build_response(webmock_response)
185
+ end
186
+
187
+ def add_webmock_response(request, webmock_response)
188
+ webmock_request_id = request.object_id.to_s
189
+ request.headers.add(WEBMOCK_REQUEST_ID_HEADER, webmock_request_id)
190
+ webmock_responses[webmock_request_id] = webmock_response
191
+ end
192
+
193
+ def get_webmock_response(request)
194
+ webmock_request_id = request.headers[WEBMOCK_REQUEST_ID_HEADER][0]
195
+ webmock_responses.fetch(webmock_request_id)
196
+ end
197
+
198
+ private
199
+
200
+ def webmock_responses
201
+ @webmock_responses ||= {}
202
+ end
203
+
204
+ def build_response(webmock_response)
205
+ headers = (webmock_response.headers || {}).each_with_object([]) do |(k, value), o|
206
+ Array(value).each do |v|
207
+ o.push [k, v]
208
+ end
209
+ end
210
+
211
+ ::Protocol::HTTP::Response[
212
+ webmock_response.status[0],
213
+ headers,
214
+ webmock_response.body
215
+ ]
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -5,7 +5,7 @@ rescue LoadError
5
5
  end
6
6
 
7
7
  if defined?(Curl)
8
- WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '0.9.1', ['0.8.7']).check_version!
8
+ WebMock::VersionChecker.new('Curb', Curl::CURB_VERSION, '0.7.16', '1.0.1', ['0.8.7']).check_version!
9
9
 
10
10
  module WebMock
11
11
  module HttpLibAdapters
@@ -54,7 +54,6 @@ if defined?(Curl)
54
54
 
55
55
  module Curl
56
56
  class WebMockCurlEasy < Curl::Easy
57
-
58
57
  def curb_or_webmock
59
58
  request_signature = build_request_signature
60
59
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
@@ -129,7 +128,7 @@ if defined?(Curl)
129
128
  def headers_as_hash(headers)
130
129
  if headers.is_a?(Array)
131
130
  headers.inject({}) {|hash, header|
132
- name, value = header.split(":").map(&:strip)
131
+ name, value = header.split(":", 2).map(&:strip)
133
132
  hash[name] = value
134
133
  hash
135
134
  }
@@ -153,7 +152,7 @@ if defined?(Curl)
153
152
  @body_str = webmock_response.body
154
153
  @response_code = webmock_response.status[0]
155
154
 
156
- @header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n"
155
+ @header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n".dup
157
156
 
158
157
  @on_debug.call(@header_str, 1) if defined?( @on_debug )
159
158
 
@@ -183,7 +182,7 @@ if defined?(Curl)
183
182
  self.url = location
184
183
 
185
184
  curb_or_webmock do
186
- send( "http_#{@webmock_method}_without_webmock" )
185
+ send( :http, {'method' => @webmock_method} )
187
186
  end
188
187
 
189
188
  self.url = first_url
@@ -271,6 +270,8 @@ if defined?(Curl)
271
270
  def perform
272
271
  @webmock_method ||= :get
273
272
  curb_or_webmock { super }
273
+ ensure
274
+ reset_webmock_method
274
275
  end
275
276
 
276
277
  def put_data= data
@@ -332,6 +333,19 @@ if defined?(Curl)
332
333
  end
333
334
  METHOD
334
335
  end
336
+
337
+ def reset_webmock_method
338
+ @webmock_method = :get
339
+ end
340
+
341
+ def reset
342
+ instance_variable_set(:@body_str, nil)
343
+ instance_variable_set(:@content_type, nil)
344
+ instance_variable_set(:@header_str, nil)
345
+ instance_variable_set(:@last_effective_url, nil)
346
+ instance_variable_set(:@response_code, nil)
347
+ super
348
+ end
335
349
  end
336
350
  end
337
351
  end