fakeweb-fi 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +248 -0
- data/LICENSE.txt +19 -0
- data/README.rdoc +203 -0
- data/lib/fake_web.rb +213 -0
- data/lib/fake_web/ext/net_http.rb +60 -0
- data/lib/fake_web/registry.rb +132 -0
- data/lib/fake_web/responder.rb +127 -0
- data/lib/fake_web/response.rb +10 -0
- data/lib/fake_web/stub_socket.rb +23 -0
- data/lib/fake_web/utility.rb +98 -0
- data/lib/fakeweb.rb +2 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 742a936bc6d1a455aca033093a1e4bd14fff4f061fd2ceb03a9459d16eafaa15
|
4
|
+
data.tar.gz: 9691ac5c32afbd62d81b5ca4dd6ee290925874ed2834276a6afaf52049448025
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9d3eee80f16fe00194e90f408c65a9b0db584cf5c10abb5b253d8964edf67b97ec093487c0fa1350bf7ad4919532e2401182c66287b69a6473be8e2e1107927e
|
7
|
+
data.tar.gz: b1df647b979d76fbdebdbd2a54ffe5d56016847f6ed564583fb65d2ed046ee737af2f5463dd1d48bf884e2cd9a9ad9582434f50f4376cc9559f1af8a6ef52d5f
|
data/CHANGELOG
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
fakeweb (master branch pending release)
|
2
|
+
|
3
|
+
* fix a variety of NoMethodErrors when Net::HTTP#read_timeout= or
|
4
|
+
Net::HTTP#continue_timeout= is called after a Net::HTTP object has handled a
|
5
|
+
first fake request under newer versions of Ruby and/or some gems (Mechanize,
|
6
|
+
aws-sdk, etc.) [Marcel Massana, Trevor Rowe, Chris Kampmeier]
|
7
|
+
|
8
|
+
* add ability to accept a StringIO as a fake response body
|
9
|
+
[Larry Diehl, Andy Delcambre, Chris Kampmeier]
|
10
|
+
|
11
|
+
* fix an exception when an IO is passed in as a fake response body
|
12
|
+
[Chris Kampmeier]
|
13
|
+
|
14
|
+
* stub responses with no bodies (e.g. to a HEAD request) now return nil for
|
15
|
+
#body, not an empty string, to match Net::HTTP's behavior [Myron Marston]
|
16
|
+
|
17
|
+
* fix warnings on post-1.8 versions of Ruby [Peter Hellberg, Kenichi Kamiya]
|
18
|
+
|
19
|
+
* fix that the options hash passed to FakeWeb.register_uri would sometimes be
|
20
|
+
modified [Chris Kampmeier]
|
21
|
+
|
22
|
+
* raise an ArgumentError when FakeWeb.register_uri's third argument can't be
|
23
|
+
handled as an options hash [David Cornu, Josef Strzibny, Chris Kampmeier]
|
24
|
+
|
25
|
+
* raise the more-specific ArgumentError instead of StandardError when the object
|
26
|
+
passed to FakeWeb.register_uri's :response option can't be handled; this
|
27
|
+
should be relatively backwards-compatible because ArgumentError descends from
|
28
|
+
StandardError [Chris Kampmeier]
|
29
|
+
|
30
|
+
* deprecation warnings now detect the caller more robustly to work with JRuby's
|
31
|
+
backtraces [Chris Kampmeier]
|
32
|
+
|
33
|
+
|
34
|
+
fakeweb (1.3.0)
|
35
|
+
|
36
|
+
* improve response header registration so you can pass an array to set a header
|
37
|
+
more than once [Myron Marston]
|
38
|
+
|
39
|
+
* fix an exception when the response's :body option was set to nil [Chris Zingel]
|
40
|
+
|
41
|
+
* fix that stubbed requests weren't mutating the Net::HTTP request object to set
|
42
|
+
the body and content-length, like real requests do [Chris Kampmeier]
|
43
|
+
|
44
|
+
* add FakeWeb.last_request [Chris Kampmeier]
|
45
|
+
|
46
|
+
* assigning a String or Regexp to FakeWeb.allow_net_connect= sets a whitelist
|
47
|
+
for outbound requests [Dan Dofter, Tim Carey-Smith, Ben Woosley]
|
48
|
+
|
49
|
+
|
50
|
+
fakeweb (1.2.8)
|
51
|
+
|
52
|
+
* support Pathname objects where a filename is expected [Chris Kampmeier]
|
53
|
+
|
54
|
+
* fix compatibility with Ruby 1.9.2 [Chris Kampmeier]
|
55
|
+
|
56
|
+
* simplify storage of FakeWeb::VERSION [Josh Peek, Woody Peterson, Ben Woosley]
|
57
|
+
|
58
|
+
|
59
|
+
fakeweb (1.2.7)
|
60
|
+
|
61
|
+
* revert to sorting query params before matching requests against regexps,
|
62
|
+
instead of the 1.2.6 behavior that tried every possible order combination;
|
63
|
+
that was factorial-time, which made matching hang for requests with long query
|
64
|
+
strings [Jason Wadsworth, David Dollar, Blaine Cook]
|
65
|
+
|
66
|
+
* print a warning when FakeWeb is loaded before RightHttpConnection or after
|
67
|
+
Samuel, other libs that patch Net::HTTP [Chris Kampmeier, Ben Brinckerhoff]
|
68
|
+
|
69
|
+
|
70
|
+
fakeweb (1.2.6)
|
71
|
+
|
72
|
+
* fix that query params in a regex would have to be sorted for it to ever match
|
73
|
+
a request URI [Chris Kampmeier, Ben Hall]
|
74
|
+
|
75
|
+
* improve regex handling so registration with an explicit port (like
|
76
|
+
/example.com:80/) matches a request that uses an implied port
|
77
|
+
(like "http://example.com/") [Chris Kampmeier, Dan Dofter]
|
78
|
+
|
79
|
+
* refactor URI registry to reduce duplication; now about twice as fast at
|
80
|
+
handling requests [Chris Kampmeier]
|
81
|
+
|
82
|
+
* Add FakeWeb::VERSION so you can programmatically determine what version of
|
83
|
+
FakeWeb is loaded without using RubyGems [Chris Kampmeier, Chris Wanstrath]
|
84
|
+
|
85
|
+
|
86
|
+
fakeweb (1.2.5)
|
87
|
+
|
88
|
+
* fix handling of userinfo strings that contain percent-encoded unsafe
|
89
|
+
characters [Chris Kampmeier, Ken Mayer]
|
90
|
+
|
91
|
+
* fix that exact matches against strings/URIs with the :any method had a lower
|
92
|
+
precedence than regex matches using a real HTTP method (exact matches now
|
93
|
+
always take precedence) [Chris Kampmeier]
|
94
|
+
|
95
|
+
* change request handling to raise an exception when more than one registered
|
96
|
+
regex matches a request URI [Chris Kampmeier]
|
97
|
+
|
98
|
+
|
99
|
+
fakeweb (1.2.4)
|
100
|
+
|
101
|
+
* add experimental support for matching URIs via regular expressions
|
102
|
+
[Jacqui Maher, Tiago Albineli Motta, Peter Wagene]
|
103
|
+
|
104
|
+
* fix an exception when registering with the :response option and a string that
|
105
|
+
is the same as the name of a directory in the current path [Chris Kampmeier]
|
106
|
+
|
107
|
+
* DEPRECATION: Calling FakeWeb.register_uri with a :string or :file option is
|
108
|
+
now deprecated. Both options have been replaced with a unified :body option,
|
109
|
+
since they supply the response body (as opposed to :response, which supplies
|
110
|
+
the full response including headers) [Chris Kampmeier]
|
111
|
+
|
112
|
+
* add support for specifying HTTP headers as options to FakeWeb.register_uri
|
113
|
+
when using the :string or :file response types, since those methods only
|
114
|
+
specify a response body [David Michael, Chris Kampmeier]
|
115
|
+
|
116
|
+
* DEPRECATION: Calling FakeWeb.register_uri and FakeWeb.registered_uri? without
|
117
|
+
an HTTP method as the first argument is now deprecated. To match against any
|
118
|
+
HTTP method (the pre-1.2.0 behavior), use :any [Chris Kampmeier]
|
119
|
+
|
120
|
+
|
121
|
+
fakeweb (1.2.3)
|
122
|
+
|
123
|
+
* fix the #http_version of :file and :string responses, which was returning the
|
124
|
+
request URI instead of something sensible like "1.0" [Chris Kampmeier]
|
125
|
+
|
126
|
+
* add method aliases in the Net::HTTP patch to eliminate warnings when running
|
127
|
+
with -w [Joshua Clingenpeel]
|
128
|
+
|
129
|
+
* fix that removing the redefinition of OpenURI::HTTPError in 1.2.0 caused
|
130
|
+
:exception responses to raise when OpenURI isn't available [Chris Kampmeier]
|
131
|
+
|
132
|
+
* fix registering an :exception response with classes that require arguments for
|
133
|
+
instantiation, like Interrupt's subclasses [Chris Kampmeier]
|
134
|
+
|
135
|
+
|
136
|
+
fakeweb (1.2.2)
|
137
|
+
|
138
|
+
* fix that HTTP Digest and OAuth requests could raise URI::InvalidURIErrors
|
139
|
+
[Bill Kocik, Chris Kampmeier]
|
140
|
+
|
141
|
+
|
142
|
+
fakeweb (1.2.1)
|
143
|
+
|
144
|
+
* fix that query parameters are handled correctly when registering with a URI
|
145
|
+
object [Anselmo Alves, Chris Kampmeier]
|
146
|
+
|
147
|
+
* fix an exception when registering with the :response option and a string
|
148
|
+
containing "\0" [Jonathan Baudanza, Chris Kampmeier]
|
149
|
+
|
150
|
+
* fix that trailing slashes were considered significant for requests to the root
|
151
|
+
of a domain [Chris Kampmeier]
|
152
|
+
|
153
|
+
* add support for HTTP basic authentication via userinfo strings in URIs
|
154
|
+
[Michael Bleigh]
|
155
|
+
|
156
|
+
|
157
|
+
fakeweb (1.2.0)
|
158
|
+
|
159
|
+
* add lib/fakeweb.rb so you can require "fakeweb" as well [Chris Kampmeier]
|
160
|
+
|
161
|
+
* fix compatibility with Ruby 1.9.1 [Chris Kampmeier]
|
162
|
+
|
163
|
+
* fix that newlines in file-based responses could be doubled in the response
|
164
|
+
object's body [Mark Menard, Chris Kampmeier]
|
165
|
+
|
166
|
+
* fix unnecessary munging of the transfer-encoding header, which improves
|
167
|
+
compatibility with mechanize [Mark Menard]
|
168
|
+
|
169
|
+
* fix a test and the RCov dependency to be compatible with JRuby [Mark Menard]
|
170
|
+
|
171
|
+
* remove an unnecessary redefinition of OpenURI::HTTPError [Josh Nichols]
|
172
|
+
|
173
|
+
* rearrange implementation code into separate files, one per class [Josh Nichols]
|
174
|
+
|
175
|
+
* fix a bug where FakeWeb.response_for would raise if the request wasn't
|
176
|
+
registered [Chris Kampmeier]
|
177
|
+
|
178
|
+
* add HTTP method support, so FakeWeb takes both the URI and method into
|
179
|
+
account for registration, requests, and responses. Backwards-compatible with
|
180
|
+
the old method signatures, which didn't have a method param. [Chris Kampmeier]
|
181
|
+
|
182
|
+
* start work on Ruby 1.9 compatibility [Chris Kampmeier]
|
183
|
+
|
184
|
+
* add FakeWeb.allow_net_connect= to enable/disable the pass-through to
|
185
|
+
Net::HTTP for unregistered URIs [Mislav Marohnić, Chris Kampmeier]
|
186
|
+
|
187
|
+
* remove setup.rb, since most people use RubyGems [Mislav Marohnić]
|
188
|
+
|
189
|
+
* fix that 'http://example.com/?' (empty query) matches a registered
|
190
|
+
'http://example.com/', and vice-versa [Mislav Marohnić]
|
191
|
+
|
192
|
+
* improve the test suite to not rely on an internet connection [Chris Kampmeier]
|
193
|
+
|
194
|
+
* use `rake test` instead of `rake tests` [Josh Nichols]
|
195
|
+
|
196
|
+
* fix an incompatibility with Ruby 1.8.6 p36 where you'd get "Errno::EINTR:
|
197
|
+
Interrupted system call" exceptions in Socket#sysread for any non-faked
|
198
|
+
request [Chris Kampmeier]
|
199
|
+
|
200
|
+
* response rotation: you can now optionally call FakeWeb.register_uri with an
|
201
|
+
array of options hashes; these are used, in order, to respond to
|
202
|
+
repeated requests (to repeat a response more than once before rotating, use
|
203
|
+
the :times option). Once you run out of responses, further requests always
|
204
|
+
receive the last response. [Michael Shapiro]
|
205
|
+
|
206
|
+
* add support for Net::HTTP's undocumented full-URI request style (fixes
|
207
|
+
URI::InvalidURIErrors that you might see in older libraries) [Chris Kampmeier]
|
208
|
+
|
209
|
+
* sort query params before storing internally, so that
|
210
|
+
http://example.com/?a=1&b=2 and http://example.com/?b=2&a=1 are considered the
|
211
|
+
same URL (although this is technically incorrect, it's much more
|
212
|
+
convenient--most web apps work that way, and Net::HTTP's use of a hash to pass
|
213
|
+
query params means that the order in which FakeWeb stores them can be
|
214
|
+
unpredictable) [Chris Kampmeier]
|
215
|
+
|
216
|
+
* add support for ports in URLs, so that http://example.com/ and
|
217
|
+
http://example.com:3000/ are not the same [Chris Kampmeier]
|
218
|
+
|
219
|
+
* fix for non-faked SSL requests failing with "Unable to create local socket"
|
220
|
+
[Chris Kampmeier]
|
221
|
+
|
222
|
+
* update Rakefile to fix warning about deprecated code [Chris Kampmeier]
|
223
|
+
|
224
|
+
|
225
|
+
fakeweb (1.1.2)
|
226
|
+
|
227
|
+
* add required dependencies to GemSpec to ensure that tests pass in firebrigade
|
228
|
+
(http://firebrigade.seattlerb.org/) [Blaine Cook]
|
229
|
+
|
230
|
+
|
231
|
+
fakeweb (1.1.1)
|
232
|
+
|
233
|
+
* fix for non-existence of :string method on File as presented by open-uri
|
234
|
+
[Blaine Cook]
|
235
|
+
|
236
|
+
* fix for curl example test - google redirects to ccTLDs for those outside US
|
237
|
+
[Blaine Cook]
|
238
|
+
|
239
|
+
|
240
|
+
fakeweb (1.1.0)
|
241
|
+
|
242
|
+
* update code to correspond to ruby 1.8.4 (breaks compatibility with ruby 1.8.2)
|
243
|
+
[Blaine Cook]
|
244
|
+
|
245
|
+
|
246
|
+
fakeweb (1.0.0)
|
247
|
+
|
248
|
+
* initial import [Blaine Cook]
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright 2006-2010 Blaine Cook, Chris Kampmeier, and other contributors
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
= FakeWeb
|
2
|
+
|
3
|
+
FakeWeb is a helper for faking web requests in Ruby. It works at a global
|
4
|
+
level, without modifying code or writing extensive stubs.
|
5
|
+
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
* You can install the latest release from RubyGems:
|
10
|
+
|
11
|
+
gem install fakeweb
|
12
|
+
|
13
|
+
Note that the gem was previously registered as +FakeWeb+, switching
|
14
|
+
to +fakeweb+ in 2009. All releases are available under the new name.
|
15
|
+
|
16
|
+
* If your application uses Bundler, add a line like this to your Gemfile:
|
17
|
+
|
18
|
+
gem "fakeweb", "~> 1.3"
|
19
|
+
|
20
|
+
You may want to specify <tt>:group => :test</tt> and/or
|
21
|
+
<tt>:require => false</tt>, depending on how you use Bundler.
|
22
|
+
|
23
|
+
* If you're developing a gem, add a line like this to your gemspec:
|
24
|
+
|
25
|
+
spec.add_development_dependency "fakeweb", ["~> 1.3"]
|
26
|
+
|
27
|
+
|
28
|
+
== Help and discussion
|
29
|
+
|
30
|
+
RDocs for the current release are available at http://fakeweb.rubyforge.org.
|
31
|
+
|
32
|
+
There's a mailing list for questions and discussion at
|
33
|
+
https://groups.google.com/d/forum/fakeweb-users.
|
34
|
+
|
35
|
+
The main source repository is https://github.com/chrisk/fakeweb.
|
36
|
+
|
37
|
+
{<img src="https://travis-ci.org/chrisk/fakeweb.png?branch=master" alt="Build Status" style="vertical-align: text-top" />}[https://travis-ci.org/chrisk/fakeweb] FakeWeb's tests run at https://travis-ci.org/chrisk/fakeweb.
|
38
|
+
|
39
|
+
== Examples
|
40
|
+
|
41
|
+
Start by requiring FakeWeb:
|
42
|
+
|
43
|
+
require 'fakeweb'
|
44
|
+
|
45
|
+
=== Registering basic string responses
|
46
|
+
|
47
|
+
FakeWeb.register_uri(:get, "http://example.com/test1", :body => "Hello World!")
|
48
|
+
|
49
|
+
Net::HTTP.get(URI.parse("http://example.com/test1"))
|
50
|
+
=> "Hello World!"
|
51
|
+
|
52
|
+
Net::HTTP.get(URI.parse("http://example.com/test2"))
|
53
|
+
=> FakeWeb is bypassed and the response from a real request is returned
|
54
|
+
|
55
|
+
You can also call <tt>register_uri</tt> with a regular expression, to match
|
56
|
+
more than one URI.
|
57
|
+
|
58
|
+
FakeWeb.register_uri(:get, %r|http://example\.com/|, :body => "Hello World!")
|
59
|
+
|
60
|
+
Net::HTTP.get(URI.parse("http://example.com/test3"))
|
61
|
+
=> "Hello World!"
|
62
|
+
|
63
|
+
=== Replaying a recorded response
|
64
|
+
|
65
|
+
page = `curl -is http://www.google.com/`
|
66
|
+
FakeWeb.register_uri(:get, "http://www.google.com/", :response => page)
|
67
|
+
|
68
|
+
Net::HTTP.get(URI.parse("http://www.google.com/"))
|
69
|
+
# => Full response, including headers
|
70
|
+
|
71
|
+
=== Adding a custom status to the response
|
72
|
+
|
73
|
+
FakeWeb.register_uri(:get, "http://example.com/", :body => "Nothing to be found 'round here",
|
74
|
+
:status => ["404", "Not Found"])
|
75
|
+
|
76
|
+
Net::HTTP.start("example.com") do |req|
|
77
|
+
response = req.get("/")
|
78
|
+
response.code # => "404"
|
79
|
+
response.message # => "Not Found"
|
80
|
+
response.body # => "Nothing to be found 'round here"
|
81
|
+
end
|
82
|
+
|
83
|
+
=== Responding to any HTTP method
|
84
|
+
|
85
|
+
FakeWeb.register_uri(:any, "http://example.com", :body => "response for any HTTP method")
|
86
|
+
|
87
|
+
If you use the <tt>:any</tt> symbol, the URI you specify will be completely
|
88
|
+
stubbed out (regardless of the HTTP method of the request). This can be useful
|
89
|
+
for RPC-style services, where the HTTP method isn't significant. (Older
|
90
|
+
versions of FakeWeb always behaved like this, and didn't accept the first
|
91
|
+
+method+ argument above; this syntax is now deprecated.)
|
92
|
+
|
93
|
+
=== Rotating responses
|
94
|
+
|
95
|
+
You can optionally call <tt>FakeWeb.register_uri</tt> with an array of options
|
96
|
+
hashes; these are used, in order, to respond to repeated requests. Once you run
|
97
|
+
out of responses, further requests always receive the last response. (You can
|
98
|
+
also send a response more than once before rotating, by specifying a
|
99
|
+
<tt>:times</tt> option for that response.)
|
100
|
+
|
101
|
+
FakeWeb.register_uri(:delete, "http://example.com/posts/1",
|
102
|
+
[{:body => "Post 1 deleted.", :status => ["200", "OK"]},
|
103
|
+
{:body => "Post not found", :status => ["404", "Not Found"]}])
|
104
|
+
|
105
|
+
Net::HTTP.start("example.com") do |req|
|
106
|
+
req.delete("/posts/1").body # => "Post 1 deleted"
|
107
|
+
req.delete("/posts/1").body # => "Post not found"
|
108
|
+
req.delete("/posts/1").body # => "Post not found"
|
109
|
+
end
|
110
|
+
|
111
|
+
=== Using HTTP basic authentication
|
112
|
+
|
113
|
+
You can fake requests that use basic authentication by adding +userinfo+ strings
|
114
|
+
to your URIs:
|
115
|
+
|
116
|
+
FakeWeb.register_uri(:get, "http://example.com/secret", :body => "Unauthorized", :status => ["401", "Unauthorized"])
|
117
|
+
FakeWeb.register_uri(:get, "http://user:pass@example.com/secret", :body => "Authorized")
|
118
|
+
|
119
|
+
Net::HTTP.start("example.com") do |http|
|
120
|
+
req = Net::HTTP::Get.new("/secret")
|
121
|
+
http.request(req) # => "Unauthorized"
|
122
|
+
req.basic_auth("user", "pass")
|
123
|
+
http.request(req) # => "Authorized"
|
124
|
+
end
|
125
|
+
|
126
|
+
=== Clearing registered URIs
|
127
|
+
|
128
|
+
The FakeWeb registry is a singleton that lasts for the duration of your program,
|
129
|
+
maintaining every fake response you register. If needed, you can clean out the
|
130
|
+
registry and remove all registered URIs:
|
131
|
+
|
132
|
+
FakeWeb.clean_registry
|
133
|
+
|
134
|
+
=== Blocking all real requests
|
135
|
+
|
136
|
+
When you're using FakeWeb to replace _all_ of your requests, it's useful to
|
137
|
+
catch when requests are made for unregistered URIs (unlike the default
|
138
|
+
behavior, which is to pass those requests through to Net::HTTP as usual).
|
139
|
+
|
140
|
+
FakeWeb.allow_net_connect = false
|
141
|
+
Net::HTTP.get(URI.parse("http://example.com/"))
|
142
|
+
=> raises FakeWeb::NetConnectNotAllowedError
|
143
|
+
|
144
|
+
FakeWeb.allow_net_connect = true
|
145
|
+
Net::HTTP.get(URI.parse("http://example.com/"))
|
146
|
+
=> FakeWeb is bypassed and the response from a real request is returned
|
147
|
+
|
148
|
+
It's recommended that you set <tt>FakeWeb.allow_net_connect = false</tt> in the
|
149
|
+
setup for your tests.
|
150
|
+
|
151
|
+
==== Allowing requests to a specific server
|
152
|
+
|
153
|
+
If you want to prevent your tests from hitting the internet while allowing
|
154
|
+
access to a specific server for integration testing, you can assign a URI or
|
155
|
+
+Regexp+ to be used as a whitelist for outbound requests:
|
156
|
+
|
157
|
+
FakeWeb.allow_net_connect = %r[^https?://localhost]
|
158
|
+
Net::HTTP.get(URI.parse("http://localhost/path")) # => allowed
|
159
|
+
Net::HTTP.get(URI.parse("http://example.com/")) # => raises FakeWeb::NetConnectNotAllowedError
|
160
|
+
|
161
|
+
=== Specifying HTTP response headers
|
162
|
+
|
163
|
+
When you register a response using the <tt>:body</tt> option, you're only
|
164
|
+
setting the body of the response. If you want to add headers to these responses,
|
165
|
+
simply add the header as an option to +register_uri+:
|
166
|
+
|
167
|
+
FakeWeb.register_uri(:get, "http://example.com/hello.txt", :body => "Hello", :content_type => "text/plain")
|
168
|
+
|
169
|
+
This sets the "Content-Type" header in the response.
|
170
|
+
|
171
|
+
=== Checking the last request
|
172
|
+
|
173
|
+
It's often useful to retrieve the last request made by your code, so you can
|
174
|
+
write tests for its content. FakeWeb keeps track of the last request, whether it
|
175
|
+
was stubbed or not:
|
176
|
+
|
177
|
+
Net::HTTP.get(URI.parse("http://example.com"))
|
178
|
+
FakeWeb.last_request # => Net::HTTP::Get request object
|
179
|
+
|
180
|
+
== More info
|
181
|
+
|
182
|
+
FakeWeb lets you decouple your test environment from live services without
|
183
|
+
modifying code or writing extensive stubs.
|
184
|
+
|
185
|
+
In addition to the conceptual advantage of having idempotent request
|
186
|
+
behaviour, FakeWeb makes tests run faster than if they were made to remote (or
|
187
|
+
even local) web servers. It also makes it possible to run tests without a
|
188
|
+
network connection or in situations where the server is behind a firewall or
|
189
|
+
has host-based access controls.
|
190
|
+
|
191
|
+
FakeWeb works with anything based on Net::HTTP--both higher-level wrappers,
|
192
|
+
like OpenURI, as well as a ton of libraries for popular web services.
|
193
|
+
|
194
|
+
|
195
|
+
== Known Issues
|
196
|
+
|
197
|
+
* Request bodies are ignored, including PUT and POST parameters. If you need
|
198
|
+
different responses for different request bodies, you need to request
|
199
|
+
different URLs, and register different responses for each. (Query strings are
|
200
|
+
fully supported, though.) We're currently considering how the API should
|
201
|
+
change to add support for request bodies in 1.3.0. Your input would be really
|
202
|
+
helpful: see https://groups.google.com/d/msg/fakeweb-users/RNGQprEuQnM/ryCiMeBD91YJ
|
203
|
+
for a discussion of some different options. Thanks!
|
data/lib/fake_web.rb
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'fake_web/ext/net_http'
|
2
|
+
require 'fake_web/registry'
|
3
|
+
require 'fake_web/response'
|
4
|
+
require 'fake_web/responder'
|
5
|
+
require 'fake_web/stub_socket'
|
6
|
+
require 'fake_web/utility'
|
7
|
+
|
8
|
+
FakeWeb::Utility.record_loaded_net_http_replacement_libs
|
9
|
+
FakeWeb::Utility.puts_warning_for_net_http_around_advice_libs_if_needed
|
10
|
+
|
11
|
+
module FakeWeb
|
12
|
+
|
13
|
+
# Returns the version string for the copy of FakeWeb you have loaded.
|
14
|
+
VERSION = '1.3.0'
|
15
|
+
|
16
|
+
# Resets the FakeWeb Registry. This will force all subsequent web requests to
|
17
|
+
# behave as real requests.
|
18
|
+
def self.clean_registry
|
19
|
+
Registry.instance.clean_registry
|
20
|
+
end
|
21
|
+
|
22
|
+
# Enables or disables real HTTP connections for requests that don't match
|
23
|
+
# registered URIs.
|
24
|
+
#
|
25
|
+
# If you set <tt>FakeWeb.allow_net_connect = false</tt> and subsequently try
|
26
|
+
# to make a request to a URI you haven't registered with .register_uri, a
|
27
|
+
# NetConnectNotAllowedError will be raised. This is handy when you want to
|
28
|
+
# make sure your tests are self-contained, or want to catch the scenario
|
29
|
+
# when a URI is changed in implementation code without a corresponding test
|
30
|
+
# change.
|
31
|
+
#
|
32
|
+
# When <tt>FakeWeb.allow_net_connect = true</tt> (the default), requests to
|
33
|
+
# URIs not stubbed with FakeWeb are passed through to Net::HTTP.
|
34
|
+
#
|
35
|
+
# If you assign a +String+, +URI+, or +Regexp+ object, unstubbed requests
|
36
|
+
# will be allowed if they match that value. This is useful when you want to
|
37
|
+
# allow access to a local server for integration testing, while still
|
38
|
+
# preventing your tests from using the internet.
|
39
|
+
def self.allow_net_connect=(allowed)
|
40
|
+
case allowed
|
41
|
+
when String, URI, Regexp
|
42
|
+
@allow_all_connections = false
|
43
|
+
Registry.instance.register_passthrough_uri(allowed)
|
44
|
+
else
|
45
|
+
@allow_all_connections = allowed
|
46
|
+
Registry.instance.remove_passthrough_uri
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Enable pass-through to Net::HTTP by default.
|
51
|
+
self.allow_net_connect = true
|
52
|
+
|
53
|
+
# Returns +true+ if requests to URIs not registered with FakeWeb are passed
|
54
|
+
# through to Net::HTTP for normal processing (the default). Returns +false+
|
55
|
+
# if an exception is raised for these requests.
|
56
|
+
#
|
57
|
+
# If you've assigned a +String+, +URI+, or +Regexp+ to
|
58
|
+
# <tt>FakeWeb.allow_net_connect=</tt>, you must supply a URI to check
|
59
|
+
# against that filter. Otherwise, an ArgumentError will be raised.
|
60
|
+
def self.allow_net_connect?(uri = nil)
|
61
|
+
if Registry.instance.passthrough_uri_map.any?
|
62
|
+
raise ArgumentError, "You must supply a URI to test" if uri.nil?
|
63
|
+
Registry.instance.passthrough_uri_matches?(uri)
|
64
|
+
else
|
65
|
+
@allow_all_connections
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# This exception is raised if you set <tt>FakeWeb.allow_net_connect =
|
70
|
+
# false</tt> and subsequently try to make a request to a URI you haven't
|
71
|
+
# stubbed.
|
72
|
+
class NetConnectNotAllowedError < StandardError; end;
|
73
|
+
|
74
|
+
# This exception is raised if a Net::HTTP request matches more than one of
|
75
|
+
# the stubs you've registered. To fix the problem, remove a duplicate
|
76
|
+
# registration or disambiguate any regular expressions by making them more
|
77
|
+
# specific.
|
78
|
+
class MultipleMatchingURIsError < StandardError; end;
|
79
|
+
|
80
|
+
# call-seq:
|
81
|
+
# FakeWeb.register_uri(method, uri, options)
|
82
|
+
#
|
83
|
+
# Register requests using the HTTP method specified by the symbol +method+
|
84
|
+
# for +uri+ to be handled according to +options+. If you specify the method
|
85
|
+
# <tt>:any</tt>, the response will be reigstered for any request for +uri+.
|
86
|
+
# +uri+ can be a +String+, +URI+, or +Regexp+ object. +options+ must be either
|
87
|
+
# a +Hash+ or an +Array+ of +Hashes+ (see below), which must contain one of
|
88
|
+
# these two keys:
|
89
|
+
#
|
90
|
+
# <tt>:body</tt>::
|
91
|
+
# A string which is used as the body of the response. If the string refers
|
92
|
+
# to a valid filesystem path, the contents of that file will be read and used
|
93
|
+
# as the body of the response instead. (This used to be two options,
|
94
|
+
# <tt>:string</tt> and <tt>:file</tt>, respectively. These are now deprecated.)
|
95
|
+
# <tt>:response</tt>::
|
96
|
+
# Either a <tt>Net::HTTPResponse</tt>, +IO+, +StringIO+, or +String+, which
|
97
|
+
# is used as the full response for the request.
|
98
|
+
#
|
99
|
+
# The easier way by far is to pass the <tt>:response</tt> option to
|
100
|
+
# +register_uri+ as a +String+ or an (open for reads) +IO+ object which
|
101
|
+
# will be used as the complete HTTP response, including headers and body.
|
102
|
+
# If the string points to a readable file, this file will be used as the
|
103
|
+
# content for the request.
|
104
|
+
#
|
105
|
+
# To obtain a complete response document, you can use the +curl+ command,
|
106
|
+
# like so:
|
107
|
+
#
|
108
|
+
# curl -i http://example.com > response_from_example.com
|
109
|
+
#
|
110
|
+
# which can then be used in your test environment like so:
|
111
|
+
#
|
112
|
+
# FakeWeb.register_uri(:get, "http://example.com", :response => "response_from_example.com")
|
113
|
+
#
|
114
|
+
# See the <tt>Net::HTTPResponse</tt>
|
115
|
+
# documentation[http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTPResponse.html]
|
116
|
+
# for more information on creating custom response objects.
|
117
|
+
#
|
118
|
+
# +options+ may also be an +Array+ containing a list of the above-described
|
119
|
+
# +Hash+. In this case, FakeWeb will rotate through each response. You can
|
120
|
+
# optionally repeat a response more than once before rotating:
|
121
|
+
#
|
122
|
+
# <tt>:times</tt>::
|
123
|
+
# The number of times this response will be used before moving on to the
|
124
|
+
# next one. The last response will be repeated indefinitely, regardless of
|
125
|
+
# its <tt>:times</tt> parameter.
|
126
|
+
#
|
127
|
+
# Two optional arguments are also accepted:
|
128
|
+
#
|
129
|
+
# <tt>:status</tt>::
|
130
|
+
# Passing <tt>:status</tt> as a two-value array will set the response code
|
131
|
+
# and message. The defaults are <tt>200</tt> and <tt>OK</tt>, respectively.
|
132
|
+
# Example:
|
133
|
+
# FakeWeb.register_uri(:get, "http://example.com", :body => "Go away!", :status => [404, "Not Found"])
|
134
|
+
# <tt>:exception</tt>::
|
135
|
+
# The argument passed via <tt>:exception</tt> will be raised when the
|
136
|
+
# specified URL is requested. Any +Exception+ class is valid. Example:
|
137
|
+
# FakeWeb.register_uri(:get, "http://example.com", :exception => Net::HTTPError)
|
138
|
+
#
|
139
|
+
# If you're using the <tt>:body</tt> response type, you can pass additional
|
140
|
+
# options to specify the HTTP headers to be used in the response. Example:
|
141
|
+
#
|
142
|
+
# FakeWeb.register_uri(:get, "http://example.com/index.txt", :body => "Hello", :content_type => "text/plain")
|
143
|
+
#
|
144
|
+
# You can also pass an array of header values to include a header in the
|
145
|
+
# response more than once:
|
146
|
+
#
|
147
|
+
# FakeWeb.register_uri(:get, "http://example.com", :set_cookie => ["name=value", "example=1"])
|
148
|
+
def self.register_uri(*args)
|
149
|
+
case args.length
|
150
|
+
when 3
|
151
|
+
Registry.instance.register_uri(*args)
|
152
|
+
when 2
|
153
|
+
print_missing_http_method_deprecation_warning(*args)
|
154
|
+
Registry.instance.register_uri(:any, *args)
|
155
|
+
else
|
156
|
+
raise ArgumentError.new("wrong number of arguments (#{args.length} for 3)")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# call-seq:
|
161
|
+
# FakeWeb.response_for(method, uri)
|
162
|
+
#
|
163
|
+
# Returns the faked Net::HTTPResponse object associated with +method+ and +uri+.
|
164
|
+
def self.response_for(*args, &block) #:nodoc: :yields: response
|
165
|
+
case args.length
|
166
|
+
when 2
|
167
|
+
Registry.instance.response_for(*args, &block)
|
168
|
+
when 1
|
169
|
+
print_missing_http_method_deprecation_warning(*args)
|
170
|
+
Registry.instance.response_for(:any, *args, &block)
|
171
|
+
else
|
172
|
+
raise ArgumentError.new("wrong number of arguments (#{args.length} for 2)")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# call-seq:
|
177
|
+
# FakeWeb.registered_uri?(method, uri)
|
178
|
+
#
|
179
|
+
# Returns true if a +method+ request for +uri+ is registered with FakeWeb.
|
180
|
+
# Specify a method of <tt>:any</tt> to check against all HTTP methods.
|
181
|
+
def self.registered_uri?(*args)
|
182
|
+
case args.length
|
183
|
+
when 2
|
184
|
+
Registry.instance.registered_uri?(*args)
|
185
|
+
when 1
|
186
|
+
print_missing_http_method_deprecation_warning(*args)
|
187
|
+
Registry.instance.registered_uri?(:any, *args)
|
188
|
+
else
|
189
|
+
raise ArgumentError.new("wrong number of arguments (#{args.length} for 2)")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Returns the request object from the last request made via Net::HTTP.
|
194
|
+
def self.last_request
|
195
|
+
@last_request
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.last_request=(request) #:nodoc:
|
199
|
+
@last_request = request
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
def self.print_missing_http_method_deprecation_warning(*args)
|
205
|
+
method = caller.first.match(/`(.*?)'/)[1]
|
206
|
+
new_args = args.map { |a| a.inspect }.unshift(":any")
|
207
|
+
new_args.last.gsub!(/^\{|\}$/, "").gsub!("=>", " => ") if args.last.is_a?(Hash)
|
208
|
+
$stderr.puts
|
209
|
+
$stderr.puts "Deprecation warning: FakeWeb requires an HTTP method argument (or use :any). Try this:"
|
210
|
+
$stderr.puts " FakeWeb.#{method}(#{new_args.join(', ')})"
|
211
|
+
$stderr.puts "Called at #{caller[1]}"
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module Net #:nodoc: all
|
6
|
+
|
7
|
+
class BufferedIO
|
8
|
+
eval <<-RUBY
|
9
|
+
def initialize_with_fakeweb(*args#{", **opts" if RUBY_VERSION >= "2.4.0" })
|
10
|
+
initialize_without_fakeweb(*args#{", **opts" if RUBY_VERSION >= "2.4.0" })
|
11
|
+
@io = FakeWeb::Utility.io_from_fake_response_object(@io)
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
alias_method :initialize_without_fakeweb, :initialize
|
15
|
+
alias_method :initialize, :initialize_with_fakeweb
|
16
|
+
end
|
17
|
+
|
18
|
+
class HTTP
|
19
|
+
class << self
|
20
|
+
def socket_type_with_fakeweb
|
21
|
+
FakeWeb::StubSocket
|
22
|
+
end
|
23
|
+
alias_method :socket_type_without_fakeweb, :socket_type
|
24
|
+
alias_method :socket_type, :socket_type_with_fakeweb
|
25
|
+
end
|
26
|
+
|
27
|
+
def request_with_fakeweb(request, body = nil, &block)
|
28
|
+
FakeWeb.last_request = request
|
29
|
+
|
30
|
+
uri = FakeWeb::Utility.request_uri_as_string(self, request)
|
31
|
+
method = request.method.downcase.to_sym
|
32
|
+
|
33
|
+
if FakeWeb.registered_uri?(method, uri)
|
34
|
+
@socket = Net::HTTP.socket_type.new
|
35
|
+
FakeWeb::Utility.produce_side_effects_of_net_http_request(request, body)
|
36
|
+
FakeWeb.response_for(method, uri, &block)
|
37
|
+
elsif FakeWeb.allow_net_connect?(uri)
|
38
|
+
connect_without_fakeweb
|
39
|
+
request_without_fakeweb(request, body, &block)
|
40
|
+
else
|
41
|
+
uri = FakeWeb::Utility.strip_default_port_from_uri(uri)
|
42
|
+
raise FakeWeb::NetConnectNotAllowedError,
|
43
|
+
"Real HTTP connections are disabled. Unregistered request: #{request.method} #{uri}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
alias_method :request_without_fakeweb, :request
|
47
|
+
alias_method :request, :request_with_fakeweb
|
48
|
+
|
49
|
+
|
50
|
+
def connect_with_fakeweb
|
51
|
+
unless @@alredy_checked_for_net_http_replacement_libs ||= false
|
52
|
+
FakeWeb::Utility.puts_warning_for_net_http_replacement_libs_if_needed
|
53
|
+
@@alredy_checked_for_net_http_replacement_libs = true
|
54
|
+
end
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
alias_method :connect_without_fakeweb, :connect
|
58
|
+
alias_method :connect, :connect_with_fakeweb
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module FakeWeb
|
4
|
+
class Registry #:nodoc:
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
attr_accessor :uri_map, :passthrough_uri_map
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
clean_registry
|
11
|
+
end
|
12
|
+
|
13
|
+
def clean_registry
|
14
|
+
self.uri_map = Hash.new { |hash, key| hash[key] = {} }
|
15
|
+
end
|
16
|
+
|
17
|
+
def register_uri(method, uri, options)
|
18
|
+
uri_map[normalize_uri(uri)][method] = [*[options]].flatten.collect do |option|
|
19
|
+
if !option.respond_to?(:keys)
|
20
|
+
raise ArgumentError.new("Expected options hash: #{option.inspect}")
|
21
|
+
end
|
22
|
+
FakeWeb::Responder.new(method, uri, option, option[:times])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def registered_uri?(method, uri)
|
27
|
+
!responders_for(method, uri).empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
def response_for(method, uri, &block)
|
31
|
+
responders = responders_for(method, uri)
|
32
|
+
return nil if responders.empty?
|
33
|
+
|
34
|
+
next_responder = responders.last
|
35
|
+
responders.each do |responder|
|
36
|
+
if responder.times and responder.times > 0
|
37
|
+
responder.times -= 1
|
38
|
+
next_responder = responder
|
39
|
+
break
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
next_responder.response(&block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def register_passthrough_uri(uri)
|
47
|
+
self.passthrough_uri_map = {normalize_uri(uri) => {:any => true}}
|
48
|
+
end
|
49
|
+
|
50
|
+
def remove_passthrough_uri
|
51
|
+
self.passthrough_uri_map = {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def passthrough_uri_matches?(uri)
|
55
|
+
uri = normalize_uri(uri)
|
56
|
+
uri_map_matches(passthrough_uri_map, :any, uri, URI) ||
|
57
|
+
uri_map_matches(passthrough_uri_map, :any, uri, Regexp)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def responders_for(method, uri)
|
63
|
+
uri = normalize_uri(uri)
|
64
|
+
|
65
|
+
uri_map_matches(uri_map, method, uri, URI) ||
|
66
|
+
uri_map_matches(uri_map, :any, uri, URI) ||
|
67
|
+
uri_map_matches(uri_map, method, uri, Regexp) ||
|
68
|
+
uri_map_matches(uri_map, :any, uri, Regexp) ||
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
|
72
|
+
def uri_map_matches(map, method, uri, type_to_check = URI)
|
73
|
+
uris_to_check = variations_of_uri_as_strings(uri)
|
74
|
+
|
75
|
+
matches = map.select { |registered_uri, method_hash|
|
76
|
+
registered_uri.is_a?(type_to_check) && method_hash.has_key?(method)
|
77
|
+
}.select { |registered_uri, method_hash|
|
78
|
+
if type_to_check == URI
|
79
|
+
uris_to_check.include?(registered_uri.to_s)
|
80
|
+
elsif type_to_check == Regexp
|
81
|
+
uris_to_check.any? { |u| u.match(registered_uri) }
|
82
|
+
end
|
83
|
+
}
|
84
|
+
|
85
|
+
if matches.size > 1
|
86
|
+
raise MultipleMatchingURIsError,
|
87
|
+
"More than one registered URI matched this request: #{method.to_s.upcase} #{uri}"
|
88
|
+
end
|
89
|
+
|
90
|
+
matches.map { |_, method_hash| method_hash[method] }.first
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def variations_of_uri_as_strings(uri_object)
|
95
|
+
normalized_uri = normalize_uri(uri_object.dup)
|
96
|
+
normalized_uri_string = normalized_uri.to_s
|
97
|
+
|
98
|
+
variations = [normalized_uri_string]
|
99
|
+
|
100
|
+
# if the port is implied in the original, add a copy with an explicit port
|
101
|
+
if normalized_uri.default_port == normalized_uri.port
|
102
|
+
variations << normalized_uri_string.sub(
|
103
|
+
/#{Regexp.escape(normalized_uri.request_uri)}$/,
|
104
|
+
":#{normalized_uri.port}#{normalized_uri.request_uri}")
|
105
|
+
end
|
106
|
+
|
107
|
+
variations
|
108
|
+
end
|
109
|
+
|
110
|
+
def normalize_uri(uri)
|
111
|
+
return uri if uri.is_a?(Regexp)
|
112
|
+
normalized_uri =
|
113
|
+
case uri
|
114
|
+
when URI then uri
|
115
|
+
when String
|
116
|
+
uri = 'http://' + uri unless uri.match('^https?://')
|
117
|
+
URI.parse(uri)
|
118
|
+
end
|
119
|
+
normalized_uri.query = sort_query_params(normalized_uri.query)
|
120
|
+
normalized_uri.normalize
|
121
|
+
end
|
122
|
+
|
123
|
+
def sort_query_params(query)
|
124
|
+
if query.nil? || query.empty?
|
125
|
+
nil
|
126
|
+
else
|
127
|
+
query.split('&').sort.join('&')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module FakeWeb
|
2
|
+
class Responder #:nodoc:
|
3
|
+
|
4
|
+
attr_accessor :method, :uri, :options, :times
|
5
|
+
KNOWN_OPTIONS = [:body, :exception, :response, :status].freeze
|
6
|
+
|
7
|
+
def initialize(method, uri, options, times)
|
8
|
+
self.method = method
|
9
|
+
self.uri = uri
|
10
|
+
self.options = options
|
11
|
+
self.times = times ? times : 1
|
12
|
+
|
13
|
+
if options.has_key?(:file) || options.has_key?(:string)
|
14
|
+
print_file_string_options_deprecation_warning
|
15
|
+
options[:body] = options.delete(:file) || options.delete(:string)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def response(&block)
|
20
|
+
if has_baked_response?
|
21
|
+
response = baked_response
|
22
|
+
else
|
23
|
+
code, msg = meta_information
|
24
|
+
response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg)
|
25
|
+
response.instance_variable_set(:@body, body)
|
26
|
+
headers_extracted_from_options.each do |name, value|
|
27
|
+
if value.respond_to?(:each)
|
28
|
+
value.each { |v| response.add_field(name, v) }
|
29
|
+
else
|
30
|
+
response[name] = value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
response.instance_variable_set(:@read, true)
|
36
|
+
response.extend FakeWeb::Response
|
37
|
+
|
38
|
+
optionally_raise(response)
|
39
|
+
|
40
|
+
yield response if block_given?
|
41
|
+
|
42
|
+
response
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def headers_extracted_from_options
|
48
|
+
options.reject {|name, _| KNOWN_OPTIONS.include?(name) }.map { |name, value|
|
49
|
+
[name.to_s.split("_").map { |segment| segment.capitalize }.join("-"), value]
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def body
|
54
|
+
body = options[:body]
|
55
|
+
return nil if body.to_s == ''
|
56
|
+
|
57
|
+
body = body.to_s if defined?(Pathname) && body.is_a?(Pathname)
|
58
|
+
|
59
|
+
if !body.include?("\0") && File.exist?(body) && !File.directory?(body)
|
60
|
+
File.read(body)
|
61
|
+
else
|
62
|
+
body
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def baked_response
|
67
|
+
response = options[:response]
|
68
|
+
response = response.to_s if defined?(Pathname) && response.is_a?(Pathname)
|
69
|
+
|
70
|
+
if response.is_a?(String) || response.is_a?(IO) || response.is_a?(StringIO)
|
71
|
+
socket = Net::BufferedIO.new(response)
|
72
|
+
r = Net::HTTPResponse.read_new(socket)
|
73
|
+
|
74
|
+
# Store the original transfer-encoding
|
75
|
+
saved_transfer_encoding = r.instance_eval {
|
76
|
+
@header['transfer-encoding'] if @header.key?('transfer-encoding')
|
77
|
+
}
|
78
|
+
|
79
|
+
# Read the body of response
|
80
|
+
r.instance_eval { @header['transfer-encoding'] = nil }
|
81
|
+
r.reading_body(socket, true) {}
|
82
|
+
|
83
|
+
# Delete the transfer-encoding key from r.@header if there wasn't one;
|
84
|
+
# otherwise, restore the saved_transfer_encoding
|
85
|
+
if saved_transfer_encoding.nil?
|
86
|
+
r.instance_eval { @header.delete('transfer-encoding') }
|
87
|
+
else
|
88
|
+
r.instance_eval { @header['transfer-encoding'] = saved_transfer_encoding }
|
89
|
+
end
|
90
|
+
r
|
91
|
+
elsif response.is_a?(Net::HTTPResponse)
|
92
|
+
response
|
93
|
+
else
|
94
|
+
raise ArgumentError, "Handler not implemented for response #{response.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def has_baked_response?
|
99
|
+
options.has_key?(:response)
|
100
|
+
end
|
101
|
+
|
102
|
+
def optionally_raise(response)
|
103
|
+
return unless options.has_key?(:exception)
|
104
|
+
|
105
|
+
case options[:exception].to_s
|
106
|
+
when "Net::HTTPError", "OpenURI::HTTPError"
|
107
|
+
raise options[:exception].new('Exception from FakeWeb', response)
|
108
|
+
else
|
109
|
+
raise options[:exception].new('Exception from FakeWeb')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def meta_information
|
114
|
+
options.has_key?(:status) ? options[:status] : [200, 'OK']
|
115
|
+
end
|
116
|
+
|
117
|
+
def print_file_string_options_deprecation_warning
|
118
|
+
which = options.has_key?(:file) ? :file : :string
|
119
|
+
first_external_caller = caller.detect { |line| !line.include?("/lib/fake_web") }
|
120
|
+
$stderr.puts
|
121
|
+
$stderr.puts "Deprecation warning: FakeWeb's :#{which} option has been renamed to :body."
|
122
|
+
$stderr.puts "Just replace :#{which} with :body in your FakeWeb.register_uri calls."
|
123
|
+
$stderr.puts "Called at #{first_external_caller}"
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FakeWeb
|
2
|
+
class StubSocket #:nodoc:
|
3
|
+
|
4
|
+
Net::BufferedIO.instance_methods.grep(/_timeout$/).each do |timeout|
|
5
|
+
attr_accessor timeout
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def closed?
|
12
|
+
@closed ||= false
|
13
|
+
@closed
|
14
|
+
end
|
15
|
+
|
16
|
+
def close
|
17
|
+
@closed = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def readuntil(*args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module FakeWeb
|
2
|
+
module Utility #:nodoc:
|
3
|
+
|
4
|
+
def self.decode_userinfo_from_header(header)
|
5
|
+
header.sub(/^Basic /, "").unpack("m").first
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.encode_unsafe_chars_in_userinfo(userinfo)
|
9
|
+
unsafe_in_userinfo = /[^#{URI::REGEXP::PATTERN::UNRESERVED};&=+$,]|^(#{URI::REGEXP::PATTERN::ESCAPED})/
|
10
|
+
userinfo.split(":").map { |part| uri_escape(part, unsafe_in_userinfo) }.join(":")
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.strip_default_port_from_uri(uri)
|
14
|
+
case uri
|
15
|
+
when %r{^http://} then uri.sub(%r{:80(/|$)}, '\1')
|
16
|
+
when %r{^https://} then uri.sub(%r{:443(/|$)}, '\1')
|
17
|
+
else uri
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a string with a normalized version of a Net::HTTP request's URI.
|
22
|
+
def self.request_uri_as_string(net_http, request)
|
23
|
+
protocol = net_http.use_ssl? ? "https" : "http"
|
24
|
+
|
25
|
+
path = request.path
|
26
|
+
path = URI.parse(request.path).request_uri if request.path =~ /^http/
|
27
|
+
|
28
|
+
if request["authorization"] =~ /^Basic /
|
29
|
+
userinfo = FakeWeb::Utility.decode_userinfo_from_header(request["authorization"])
|
30
|
+
userinfo = FakeWeb::Utility.encode_unsafe_chars_in_userinfo(userinfo) + "@"
|
31
|
+
else
|
32
|
+
userinfo = ""
|
33
|
+
end
|
34
|
+
|
35
|
+
"#{protocol}://#{userinfo}#{net_http.address}:#{net_http.port}#{path}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Wrapper that falls back to URI.escape for compatibility with 1.8
|
39
|
+
def self.uri_escape(*args)
|
40
|
+
houdini = URI.const_defined?(:Parser) ? URI::Parser.new : URI
|
41
|
+
houdini.escape(*args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.produce_side_effects_of_net_http_request(request, body)
|
45
|
+
request.set_body_internal(body)
|
46
|
+
request.content_length = request.body.length unless request.body.nil?
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.io_from_fake_response_object(obj)
|
50
|
+
case obj
|
51
|
+
when Socket, OpenSSL::SSL::SSLSocket, StringIO, IO
|
52
|
+
obj # usable as-is
|
53
|
+
when String
|
54
|
+
if !obj.include?("\0") && File.exist?(obj) && !File.directory?(obj)
|
55
|
+
File.open(obj, "r")
|
56
|
+
else
|
57
|
+
StringIO.new(obj)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise ArgumentError, "Unable to create fake socket from #{obj}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.puts_warning_for_net_http_around_advice_libs_if_needed
|
65
|
+
libs = {"Samuel" => defined?(Samuel)}
|
66
|
+
warnings = libs.select { |_, loaded| loaded }.map do |name, _|
|
67
|
+
<<-TEXT.gsub(/ {10}/, '')
|
68
|
+
\e[1mWarning: FakeWeb was loaded after #{name}\e[0m
|
69
|
+
* #{name}'s code is being ignored when a request is handled by FakeWeb,
|
70
|
+
because both libraries work by patching Net::HTTP.
|
71
|
+
* To fix this, just reorder your requires so that FakeWeb is before #{name}.
|
72
|
+
TEXT
|
73
|
+
end
|
74
|
+
$stderr.puts "\n" + warnings.join("\n") + "\n" if warnings.any?
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.record_loaded_net_http_replacement_libs
|
78
|
+
libs = {"RightHttpConnection" => defined?(RightHttpConnection)}
|
79
|
+
@loaded_net_http_replacement_libs = libs.map { |name, loaded| name if loaded }.compact
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.puts_warning_for_net_http_replacement_libs_if_needed
|
83
|
+
libs = {"RightHttpConnection" => defined?(RightHttpConnection)}
|
84
|
+
warnings = libs.select { |_, loaded| loaded }.
|
85
|
+
reject { |name, _| @loaded_net_http_replacement_libs.include?(name) }.
|
86
|
+
map do |name, _|
|
87
|
+
<<-TEXT.gsub(/ {10}/, '')
|
88
|
+
\e[1mWarning: #{name} was loaded after FakeWeb\e[0m
|
89
|
+
* FakeWeb's code is being ignored, because #{name} replaces parts of
|
90
|
+
Net::HTTP without deferring to other libraries. This will break Net::HTTP requests.
|
91
|
+
* To fix this, just reorder your requires so that #{name} is before FakeWeb.
|
92
|
+
TEXT
|
93
|
+
end
|
94
|
+
$stderr.puts "\n" + warnings.join("\n") + "\n" if warnings.any?
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
data/lib/fakeweb.rb
ADDED
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fakeweb-fi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Kampmeier
|
8
|
+
- Blaine Cook
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2018-09-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mocha
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.0'
|
21
|
+
- - "!="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.11.0
|
24
|
+
- - "!="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.10.3
|
27
|
+
- - "!="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.10.2
|
30
|
+
type: :development
|
31
|
+
prerelease: false
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1.0'
|
37
|
+
- - "!="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.11.0
|
40
|
+
- - "!="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.10.3
|
43
|
+
- - "!="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.10.2
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - "~>"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '12.0'
|
53
|
+
type: :development
|
54
|
+
prerelease: false
|
55
|
+
version_requirements: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '12.0'
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: ZenTest
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '4.9'
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '4.9'
|
74
|
+
- !ruby/object:Gem::Dependency
|
75
|
+
name: sdoc
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
type: :development
|
82
|
+
prerelease: false
|
83
|
+
version_requirements: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
- !ruby/object:Gem::Dependency
|
89
|
+
name: simplecov
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0.7'
|
95
|
+
type: :development
|
96
|
+
prerelease: false
|
97
|
+
version_requirements: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.7'
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: simplecov-console
|
104
|
+
requirement: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0.1'
|
109
|
+
type: :development
|
110
|
+
prerelease: false
|
111
|
+
version_requirements: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0.1'
|
116
|
+
- !ruby/object:Gem::Dependency
|
117
|
+
name: json
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '1.7'
|
123
|
+
type: :development
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '1.7'
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
name: test-unit
|
132
|
+
requirement: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - "~>"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '3.2'
|
137
|
+
type: :development
|
138
|
+
prerelease: false
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '3.2'
|
144
|
+
description: FakeWeb is a helper for faking web requests in Ruby. It works at a global
|
145
|
+
level, without modifying code or writing extensive stubs.
|
146
|
+
email:
|
147
|
+
- chris@kampers.net
|
148
|
+
- romeda@gmail.com
|
149
|
+
executables: []
|
150
|
+
extensions: []
|
151
|
+
extra_rdoc_files:
|
152
|
+
- CHANGELOG
|
153
|
+
- LICENSE.txt
|
154
|
+
- README.rdoc
|
155
|
+
files:
|
156
|
+
- CHANGELOG
|
157
|
+
- LICENSE.txt
|
158
|
+
- README.rdoc
|
159
|
+
- lib/fake_web.rb
|
160
|
+
- lib/fake_web/ext/net_http.rb
|
161
|
+
- lib/fake_web/registry.rb
|
162
|
+
- lib/fake_web/responder.rb
|
163
|
+
- lib/fake_web/response.rb
|
164
|
+
- lib/fake_web/stub_socket.rb
|
165
|
+
- lib/fake_web/utility.rb
|
166
|
+
- lib/fakeweb.rb
|
167
|
+
homepage: https://github.com/chrisk/fakeweb
|
168
|
+
licenses:
|
169
|
+
- MIT
|
170
|
+
metadata: {}
|
171
|
+
post_install_message:
|
172
|
+
rdoc_options:
|
173
|
+
- "--show-hash --charset=UTF-8"
|
174
|
+
require_paths:
|
175
|
+
- lib
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubyforge_project: fakeweb
|
188
|
+
rubygems_version: 2.7.6
|
189
|
+
signing_key:
|
190
|
+
specification_version: 4
|
191
|
+
summary: A tool for faking responses to HTTP requests
|
192
|
+
test_files: []
|