fakeweb-fi 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/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: []
|