redrock 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +88 -0
- data/lib/redrock/server.rb +43 -0
- data/lib/redrock.rb +33 -0
- data/spec/redrock_spec.rb +465 -0
- data/spec/spec_helper.rb +8 -0
- metadata +114 -0
data/README.rdoc
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
= RedRock
|
2
|
+
|
3
|
+
== What is this?
|
4
|
+
|
5
|
+
A wrapper for running WebMock[link:http://github.com/bblimke/webmock] remotely
|
6
|
+
(ie mocking requests made by an application that's not running in the same
|
7
|
+
process as your tests).
|
8
|
+
|
9
|
+
== When might I want to use it?
|
10
|
+
|
11
|
+
If you're testing an application that makes remote web requests, and for some
|
12
|
+
reason you can't run the application code directly inside your test framework.
|
13
|
+
This might be because you're running integration tests against a stack of
|
14
|
+
applications, you're using something like
|
15
|
+
Culerity[link:http://github.com/langalex/culerity] or
|
16
|
+
Selenium[link:http://seleniumhq.org/], or maybe the application doesn't use one
|
17
|
+
of the HTTP libraries that WebMock supports, or isn't even written in Ruby.
|
18
|
+
|
19
|
+
== Getting started
|
20
|
+
|
21
|
+
gem install redrock
|
22
|
+
|
23
|
+
Somewhere in your tests:
|
24
|
+
|
25
|
+
require "redrock"
|
26
|
+
include RedRock
|
27
|
+
|
28
|
+
You can then make most of the same calls you would normally make to WebMock,
|
29
|
+
and they will be transparently handled by RedRock. For example:
|
30
|
+
|
31
|
+
stub_request :any, "localhost:4242/chunky/bacon"
|
32
|
+
# ...
|
33
|
+
RedRock.should have_requested :get, "http://localhost:4242/chunky/bacon"
|
34
|
+
|
35
|
+
The RedRock server starts automatically when required, but you can start it
|
36
|
+
manually if you want to run it on a different port:
|
37
|
+
|
38
|
+
RedRock.start 1234
|
39
|
+
|
40
|
+
You can also stop it manually:
|
41
|
+
|
42
|
+
RedRock.stop
|
43
|
+
|
44
|
+
If you want to use a host other than localhost, you can map it in
|
45
|
+
<tt>/etc/hosts</tt>. If you can't override the port your application talks to,
|
46
|
+
you'll have to set up a reverse proxy as well.
|
47
|
+
|
48
|
+
== How does it work?
|
49
|
+
|
50
|
+
RedRock fires up a thin[link:http://code.macournoyer.com/thin/] server (by
|
51
|
+
default on port 4242), which attempts to proxy all incoming requests using
|
52
|
+
Net::HTTP, at which point they are intercepted by WebMock. You point your
|
53
|
+
application under test at this server, instead of the real service it's
|
54
|
+
supposed to interact with.
|
55
|
+
|
56
|
+
All calls to WebMock methods in your tests are proxied through to the RedRock
|
57
|
+
server, which means that stubs and expectations are effectively being applied
|
58
|
+
to the requests being made by the application under test.
|
59
|
+
|
60
|
+
=== Unsupported WebMock features
|
61
|
+
|
62
|
+
Allowing real requests doesn't really make any sense for RedRock, so if you
|
63
|
+
call <tt>allow_net_connect!</tt> or <tt>disable_net_connect!</tt> you'll get an
|
64
|
+
error.
|
65
|
+
|
66
|
+
Raising exceptions or timing out won't work as expected, because the exceptions
|
67
|
+
will be handled in the RedRock server, not the application under test.
|
68
|
+
|
69
|
+
== TODO
|
70
|
+
|
71
|
+
* Better documentation!
|
72
|
+
* Refactor the server, which is currently a small ball of mud.
|
73
|
+
|
74
|
+
== Why "RedRock"?
|
75
|
+
|
76
|
+
I started with "Remote WebMock". "RWebMock" doesn't exactly trip off the
|
77
|
+
tongue, so I thought maybe "RebMock". That sounded like Scooby-Doo saying
|
78
|
+
"WebMock", although he'd probably say "RebRock". That sounded almost like
|
79
|
+
"RedRock", which is where I stopped. I'm a bit surprised that there isn't
|
80
|
+
already a redrock gem, given that a ruby is basically a red rock, but hey,
|
81
|
+
you've had seven years or so.
|
82
|
+
|
83
|
+
== Other random stuff
|
84
|
+
|
85
|
+
Version 0.1.0 was released on Whyday, 19 August 2010.
|
86
|
+
|
87
|
+
RedRock is intended to replace FakeTTP[link:http://github.com/kerryb/fakettp],
|
88
|
+
which no-one apart from me and a few colleagues ever used.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "thin"
|
2
|
+
require "net/http"
|
3
|
+
require "json"
|
4
|
+
require "webmock"
|
5
|
+
require "webmock/rspec"
|
6
|
+
|
7
|
+
Thin::Logging.silent = true
|
8
|
+
|
9
|
+
module RedRock
|
10
|
+
class Server
|
11
|
+
include Singleton
|
12
|
+
include WebMock
|
13
|
+
include WebMock::Matchers
|
14
|
+
|
15
|
+
def call env
|
16
|
+
request = Rack::Request.new env
|
17
|
+
http_method = request.request_method
|
18
|
+
request_body = request.body.read
|
19
|
+
request_headers = {}
|
20
|
+
env.each do |k, v|
|
21
|
+
request_headers[k.sub(/^HTTP_/, '')] = v if k =~ /^HTTP_|CONTENT_TYPE|CONTENT_LENGTH/
|
22
|
+
end
|
23
|
+
begin
|
24
|
+
::Net::HTTP.start(request_headers["HOST"]) do |http|
|
25
|
+
request_class = ::Net::HTTP.const_get(http_method.capitalize)
|
26
|
+
path = request.path_info
|
27
|
+
path << "?#{request.query_string}" unless request.query_string.empty?
|
28
|
+
request = request_class.new request.path_info, request_headers
|
29
|
+
request.body = request_body unless request_body.empty?
|
30
|
+
@response = http.request request
|
31
|
+
end
|
32
|
+
rescue WebMock::NetConnectNotAllowedError => e
|
33
|
+
return [500,
|
34
|
+
{"Content-Type" => "text/plain", "Content-Length" => e.message.length.to_s},
|
35
|
+
e.message]
|
36
|
+
end
|
37
|
+
response_headers = {}
|
38
|
+
@response.to_hash.each {|k,v| response_headers[k] = v.join "\n"}
|
39
|
+
response_headers.delete "status"
|
40
|
+
[@response.code, response_headers, @response.body]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/redrock.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "redrock/server"
|
2
|
+
|
3
|
+
module RedRock
|
4
|
+
def start port = 4242
|
5
|
+
raise "RedRock is already running" if @server_thread
|
6
|
+
@server_thread = Thread.new do
|
7
|
+
Thin::Server.start('0.0.0.0', port) do
|
8
|
+
run RedRock::Server.instance
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop
|
14
|
+
if @server_thread
|
15
|
+
@server_thread.exit
|
16
|
+
@server_thread = nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def allow_net_connect!
|
21
|
+
raise "RedRock does not support allowing real connections"
|
22
|
+
end
|
23
|
+
|
24
|
+
def disable_net_connect!
|
25
|
+
raise "RedRock does not support disabling real connections"
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing name, *args, &block
|
29
|
+
super unless Server.instance.respond_to? name
|
30
|
+
start unless @server_thread
|
31
|
+
Server.instance.send name, *args, &block
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,465 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
# Mostly uses curb to avoid going via net/http, to prove that the stubbing
|
4
|
+
# isn't happening locally.
|
5
|
+
|
6
|
+
describe RedRock do
|
7
|
+
after do
|
8
|
+
RedRock.stop
|
9
|
+
end
|
10
|
+
|
11
|
+
context "server" do
|
12
|
+
it "listens on port 4242 by default" do
|
13
|
+
stub_request :any, "localhost:4242"
|
14
|
+
curl = Curl::Easy.http_get "http://localhost:4242"
|
15
|
+
curl.response_code.should == 200
|
16
|
+
end
|
17
|
+
|
18
|
+
it "allows the port to be overridden" do
|
19
|
+
RedRock.start 4567
|
20
|
+
stub_request :any, "localhost:4567"
|
21
|
+
curl = Curl::Easy.http_get "http://localhost:4567"
|
22
|
+
curl.response_code.should == 200
|
23
|
+
end
|
24
|
+
|
25
|
+
it "silently ignores attempts to stop non-running server" do
|
26
|
+
lambda {RedRock.stop}.should_not raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it "only runs one server at a time" do
|
30
|
+
RedRock.start 4567
|
31
|
+
lambda {RedRock.start 4568}.should raise_error(RuntimeError, "RedRock is already running")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "on receipt of an unexpected request" do
|
36
|
+
let(:curl) { Curl::Easy.http_get "http://localhost:4567" }
|
37
|
+
|
38
|
+
it "returns a 500 error" do
|
39
|
+
curl.response_code.should == 500
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns a useful message in the body" do
|
43
|
+
curl.body_str.should =~ /Real HTTP connections are disabled/
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "stubbing with URI only and default response" do
|
48
|
+
before do
|
49
|
+
stub_request :any, "localhost:4242/foo"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "accepts matching requests" do
|
53
|
+
curl = Curl::Easy.http_get "http://localhost:4242/foo"
|
54
|
+
curl.response_code.should == 200
|
55
|
+
end
|
56
|
+
|
57
|
+
it "rejects non-matching requests" do
|
58
|
+
curl = Curl::Easy.http_get "http://localhost:4242/bar"
|
59
|
+
curl.response_code.should == 500
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "stubbing with method, URI, body and headers" do
|
64
|
+
before do
|
65
|
+
stub_request(:any, "localhost:4242/foo").with(:body => "onion", :headers => { "bacon-preference" => "chunky" })
|
66
|
+
end
|
67
|
+
|
68
|
+
it "accepts matching requests" do
|
69
|
+
curl = Curl::Easy.http_post "http://localhost:4242/foo", "onion" do |c|
|
70
|
+
c.headers["bacon-preference"] = "chunky"
|
71
|
+
end
|
72
|
+
curl.response_code.should == 200
|
73
|
+
end
|
74
|
+
|
75
|
+
it "rejects requests with the wrong URI" do
|
76
|
+
curl = Curl::Easy.http_post "http://localhost:4242/bar", "onion" do |c|
|
77
|
+
c.headers["bacon-preference"] = "chunky"
|
78
|
+
end
|
79
|
+
curl.response_code.should == 500
|
80
|
+
end
|
81
|
+
|
82
|
+
it "rejects requests with the wrong body" do
|
83
|
+
curl = Curl::Easy.http_post "http://localhost:4242/foo", "cabbage" do |c|
|
84
|
+
c.headers["bacon-preference"] = "chunky"
|
85
|
+
end
|
86
|
+
curl.response_code.should == 500
|
87
|
+
end
|
88
|
+
|
89
|
+
it "rejects requests with the wrong headers" do
|
90
|
+
curl = Curl::Easy.http_post "http://localhost:4242/foo", "onion" do |c|
|
91
|
+
c.headers["bacon-preference"] = "streaky"
|
92
|
+
end
|
93
|
+
curl.response_code.should == 500
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "matching request body and headers against regular expressions" do
|
98
|
+
before do
|
99
|
+
stub_request(:any, "localhost:4242/foo").with(:body => /nion/, :headers => { "bacon-preference" => /c.*y/ })
|
100
|
+
end
|
101
|
+
|
102
|
+
it "accepts matching requests" do
|
103
|
+
curl = Curl::Easy.http_post "http://localhost:4242/foo", "onion" do |c|
|
104
|
+
c.headers["bacon-preference"] = "chunky"
|
105
|
+
end
|
106
|
+
curl.response_code.should == 200
|
107
|
+
end
|
108
|
+
|
109
|
+
it "rejects requests with the wrong body" do
|
110
|
+
curl = Curl::Easy.http_post "http://localhost:4242/foo", "neon" do |c|
|
111
|
+
c.headers["bacon-preference"] = "crispy"
|
112
|
+
end
|
113
|
+
curl.response_code.should == 500
|
114
|
+
end
|
115
|
+
|
116
|
+
it "rejects requests with the wrong headers" do
|
117
|
+
curl = Curl::Easy.http_post "http://localhost:4242/foo", "bunion" do |c|
|
118
|
+
c.headers["bacon-preference"] = "streaky"
|
119
|
+
end
|
120
|
+
curl.response_code.should == 500
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "matching request body against a hash" do
|
125
|
+
before do
|
126
|
+
stub_http_request(:post, "localhost:4242").with(:body => {:data => {:a => '1', :b => 'five'}})
|
127
|
+
end
|
128
|
+
|
129
|
+
it "matches URL-encoded data" do
|
130
|
+
curl = Curl::Easy.http_post "http://localhost:4242/", "data[a]=1&data[b]=five" do |c|
|
131
|
+
c.headers["Content-Type"] = "application/x-www-form-urlencoded"
|
132
|
+
end
|
133
|
+
curl.response_code.should == 200
|
134
|
+
end
|
135
|
+
|
136
|
+
it "matches JSON data" do
|
137
|
+
curl = Curl::Easy.http_post "http://localhost:4242/", %({"data":{"a":"1","b":"five"}}) do |c|
|
138
|
+
c.headers["Content-Type"] = "application/json"
|
139
|
+
end
|
140
|
+
curl.response_code.should == 200
|
141
|
+
end
|
142
|
+
|
143
|
+
it "matches XML data" do
|
144
|
+
curl = Curl::Easy.http_post "http://localhost:4242/", %(<data a="1" b="five" />) do |c|
|
145
|
+
c.headers["Content-Type"] = "application/xml"
|
146
|
+
end
|
147
|
+
curl.response_code.should == 200
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "matching multiple headers with the same name" do
|
152
|
+
before do
|
153
|
+
stub_http_request(:get, "localhost:4242").with(:headers => {"Accept" => ["image/jpeg", "image/png"]})
|
154
|
+
end
|
155
|
+
|
156
|
+
it "matches when both header values are present" do
|
157
|
+
# Curb can't do multiple headers with the same name
|
158
|
+
req = Net::HTTP::Get.new("/")
|
159
|
+
req['Accept'] = ['image/png']
|
160
|
+
req.add_field('Accept', 'image/jpeg')
|
161
|
+
resp = Net::HTTP.start("localhost:4242") {|http| http.request(req) }
|
162
|
+
resp.should be_an_instance_of Net::HTTPOK
|
163
|
+
end
|
164
|
+
|
165
|
+
it "rejects requests with missing values" do
|
166
|
+
curl = Curl::Easy.http_get "http://localhost:4242/" do |c|
|
167
|
+
c.headers["Accept"] = "image/jpeg"
|
168
|
+
end
|
169
|
+
curl.response_code.should == 500
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "matching requests against a block" do
|
174
|
+
before do
|
175
|
+
stub_request(:post, "localhost:4242").with { |request| request.body == "abc" }
|
176
|
+
end
|
177
|
+
|
178
|
+
it "matches when the block returns true" do
|
179
|
+
curl = Curl::Easy.http_post "http://localhost:4242", "abc"
|
180
|
+
curl.response_code.should == 200
|
181
|
+
end
|
182
|
+
|
183
|
+
it "does not match when the block returns false" do
|
184
|
+
curl = Curl::Easy.http_post "http://localhost:4242", "def"
|
185
|
+
curl.response_code.should == 500
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context "using basic auth" do
|
190
|
+
before do
|
191
|
+
stub_request(:get, "user:pass@localhost:4242")
|
192
|
+
end
|
193
|
+
|
194
|
+
it "matches when the username and password are correct" do
|
195
|
+
curl = Curl::Easy.http_get "http://localhost:4242/" do |c|
|
196
|
+
c.http_auth_types = :basic
|
197
|
+
c.username = "user"
|
198
|
+
c.password = "pass"
|
199
|
+
end
|
200
|
+
curl.response_code.should == 200
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "matching URIs against regular expressions" do
|
205
|
+
before do
|
206
|
+
stub_request :any, %r(local.*/foo)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "accepts matching requests" do
|
210
|
+
curl = Curl::Easy.http_get "http://localhost:4242/wibble/foo"
|
211
|
+
curl.response_code.should == 200
|
212
|
+
end
|
213
|
+
|
214
|
+
it "rejects non-matching requests" do
|
215
|
+
curl = Curl::Easy.http_get "http://localhost:4242/bar"
|
216
|
+
curl.response_code.should == 500
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context "matching query params using a hash" do
|
221
|
+
before do
|
222
|
+
stub_http_request(:get, "localhost:4242").with(:query => {"a" => ["b", "c"]})
|
223
|
+
end
|
224
|
+
|
225
|
+
it "accepts matching requests" do
|
226
|
+
curl = Curl::Easy.http_get "http://localhost:4242?a[]=b&a[]=c"
|
227
|
+
curl.response_code.should == 200
|
228
|
+
end
|
229
|
+
|
230
|
+
it "rejects non-matching requests" do
|
231
|
+
curl = Curl::Easy.http_get "http://localhost:4242?a[]=d"
|
232
|
+
curl.response_code.should == 500
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context "returning a custom response" do
|
237
|
+
before do
|
238
|
+
stub_request(:any, "localhost:4242").to_return(:body => "abc", :status => 201,
|
239
|
+
:headers => { "Location" => "nowhere"})
|
240
|
+
end
|
241
|
+
|
242
|
+
let(:curl) { Curl::Easy.http_get "http://localhost:4242" }
|
243
|
+
|
244
|
+
it "returns the specified body" do
|
245
|
+
curl.body_str.should == "abc"
|
246
|
+
end
|
247
|
+
|
248
|
+
it "returns the specified response code" do
|
249
|
+
curl.response_code.should == 201
|
250
|
+
end
|
251
|
+
|
252
|
+
it "returns the specified headers" do
|
253
|
+
curl.header_str.should =~ /location: nowhere/
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
it "supports specification of a response body as an IO object" do
|
258
|
+
stub_request(:any, "localhost:4242").to_return(:body => StringIO.new("chunky bacon"), :status => 200)
|
259
|
+
curl = Curl::Easy.http_get "http://localhost:4242"
|
260
|
+
curl.body_str.should == "chunky bacon"
|
261
|
+
end
|
262
|
+
|
263
|
+
context "returning a custom status message" do
|
264
|
+
before do
|
265
|
+
stub_request(:any, "localhost:4242").to_return(:status => [500, "Pixies are on strike"])
|
266
|
+
end
|
267
|
+
|
268
|
+
let(:resp) do
|
269
|
+
uri = URI.parse "http://localhost:4242"
|
270
|
+
Net::HTTP.start(uri.host, uri.port) {|http|
|
271
|
+
http.get "/"
|
272
|
+
}
|
273
|
+
end
|
274
|
+
|
275
|
+
it "returns the specified response code" do
|
276
|
+
resp.code.should == "500"
|
277
|
+
end
|
278
|
+
|
279
|
+
it "returns the specified message" do
|
280
|
+
resp.message.should == "Pixies are on strike"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context "replaying raw responses recorded with curl -is" do
|
285
|
+
let(:raw_response) do
|
286
|
+
<<-EOF
|
287
|
+
HTTP/1.1 200 OK
|
288
|
+
Date: Wed, 18 Aug 2010 13:24:53 GMT
|
289
|
+
Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 Phusion_Passenger/2.2.11
|
290
|
+
Last-Modified: Mon, 29 Jun 2009 12:57:40 GMT
|
291
|
+
ETag: "13b358c-117-46d7c3c301900"
|
292
|
+
Accept-Ranges: bytes
|
293
|
+
Content-Length: 13
|
294
|
+
Content-Type: text/p[ain
|
295
|
+
|
296
|
+
Chunky bacon!
|
297
|
+
EOF
|
298
|
+
end
|
299
|
+
|
300
|
+
shared_examples_for "a raw response" do
|
301
|
+
it "returns the response" do
|
302
|
+
curl = Curl::Easy.http_get "http://localhost:4242"
|
303
|
+
curl.body_str.should == "Chunky bacon!"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context "as a file" do
|
308
|
+
before do
|
309
|
+
File.open "response", "w" do |f|
|
310
|
+
f.puts raw_response
|
311
|
+
end
|
312
|
+
stub_request(:any, "localhost:4242").to_return File.new("response")
|
313
|
+
end
|
314
|
+
|
315
|
+
after do
|
316
|
+
FileUtils.rm_rf "response"
|
317
|
+
end
|
318
|
+
|
319
|
+
it_should_behave_like "a raw response"
|
320
|
+
end
|
321
|
+
|
322
|
+
context "as a string" do
|
323
|
+
before do
|
324
|
+
stub_request(:any, "localhost:4242").to_return raw_response
|
325
|
+
end
|
326
|
+
|
327
|
+
it_should_behave_like "a raw response"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
context "dynamically evaluating responses" do
|
332
|
+
shared_examples_for "a dynamic response" do
|
333
|
+
it "returns the correct response" do
|
334
|
+
curl = Curl::Easy.http_post "http://localhost:4242", "!nocab yknuhC"
|
335
|
+
curl.body_str.should == "Chunky bacon!"
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
context "from a block" do
|
340
|
+
before do
|
341
|
+
stub_request(:any, "localhost:4242").to_return { |request| {:body => request.body.reverse} }
|
342
|
+
end
|
343
|
+
|
344
|
+
it_should_behave_like "a dynamic response"
|
345
|
+
end
|
346
|
+
|
347
|
+
context "from a lambda" do
|
348
|
+
before do
|
349
|
+
stub_request(:any, "localhost:4242").to_return(lambda { |request| {:body => request.body.reverse} })
|
350
|
+
end
|
351
|
+
|
352
|
+
it_should_behave_like "a dynamic response"
|
353
|
+
end
|
354
|
+
|
355
|
+
context "by part" do
|
356
|
+
before do
|
357
|
+
stub_request(:any, "localhost:4242").to_return(:body => lambda { |request| request.body.reverse })
|
358
|
+
end
|
359
|
+
|
360
|
+
it_should_behave_like "a dynamic response"
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
context "setting multiple responses" do
|
365
|
+
shared_examples_for "multiple responses" do
|
366
|
+
it "returns the correct values" do
|
367
|
+
curl = Curl::Easy.new "http://localhost:4242"
|
368
|
+
(1..3).map do
|
369
|
+
curl.http_get
|
370
|
+
curl.body_str
|
371
|
+
end.should == %w(chunky chunky bacon)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
context "individually" do
|
376
|
+
before do
|
377
|
+
stub_request(:get, "localhost:4242").to_return({:body => "chunky"},
|
378
|
+
{:body => "chunky"},
|
379
|
+
{:body => "bacon"})
|
380
|
+
end
|
381
|
+
|
382
|
+
it_should_behave_like "multiple responses"
|
383
|
+
end
|
384
|
+
|
385
|
+
context "using method chaining" do
|
386
|
+
before do
|
387
|
+
stub_request(:get, "localhost:4242").to_return({:body => "chunky"}).then.
|
388
|
+
to_return({:body => "chunky"}).then.to_return({:body => "bacon"})
|
389
|
+
end
|
390
|
+
|
391
|
+
it_should_behave_like "multiple responses"
|
392
|
+
end
|
393
|
+
|
394
|
+
context "specifying the number of times to return a given response" do
|
395
|
+
before do
|
396
|
+
stub_request(:get, "localhost:4242").to_return({:body => "chunky"}).times(2).then.
|
397
|
+
to_return({:body => "bacon"})
|
398
|
+
end
|
399
|
+
|
400
|
+
it_should_behave_like "multiple responses"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
context "assertions" do
|
405
|
+
before do
|
406
|
+
stub_request :any, "localhost:4242/foo"
|
407
|
+
Curl::Easy.http_get "http://localhost:4242/foo"
|
408
|
+
end
|
409
|
+
|
410
|
+
context "in the test/unit style" do
|
411
|
+
it "can assert requests made" do
|
412
|
+
assert_requested :get, "http://localhost:4242/foo"
|
413
|
+
end
|
414
|
+
|
415
|
+
it "can assert requests not made" do
|
416
|
+
assert_not_requested :get, "http://localhost:4242/bar"
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
context "in the rspec style" do
|
421
|
+
it "can assert requests made" do
|
422
|
+
RedRock.should have_requested :get, "http://localhost:4242/foo"
|
423
|
+
end
|
424
|
+
|
425
|
+
it "can assert requests not made" do
|
426
|
+
RedRock.should_not have_requested :get, "http://localhost:4242/bar"
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
context "in the alternative rspec style" do
|
431
|
+
it "can assert requests made" do
|
432
|
+
request(:get, "http://localhost:4242/foo").should have_been_made
|
433
|
+
end
|
434
|
+
|
435
|
+
it "can assert requests not made" do
|
436
|
+
request(:get, "http://localhost:4242/bar").should_not have_been_made
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
context "resetting" do
|
442
|
+
before do
|
443
|
+
stub_request :any, "localhost:4242"
|
444
|
+
Curl::Easy.http_get "http://localhost:4242"
|
445
|
+
reset_webmock
|
446
|
+
end
|
447
|
+
|
448
|
+
it "clears stubs" do
|
449
|
+
curl = Curl::Easy.http_get "http://localhost:4242"
|
450
|
+
curl.response_code.should == 500
|
451
|
+
end
|
452
|
+
|
453
|
+
it "clears history" do
|
454
|
+
request(:get, "http://localhost:4242").should_not have_been_made
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
it "does not support enabling local requests" do
|
459
|
+
lambda {allow_net_connect!}.should raise_error RuntimeError, "RedRock does not support allowing real connections"
|
460
|
+
end
|
461
|
+
|
462
|
+
it "does not support disabling local requests" do
|
463
|
+
lambda {disable_net_connect!}.should raise_error RuntimeError, "RedRock does not support disabling real connections"
|
464
|
+
end
|
465
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redrock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Kerry Buckley
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-19 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: thin
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
version: "1.0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: curb
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
type: :development
|
63
|
+
version_requirements: *id003
|
64
|
+
description:
|
65
|
+
email: kerryjbuckley@gmail.com
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files:
|
71
|
+
- README.rdoc
|
72
|
+
files:
|
73
|
+
- spec/redrock_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
- lib/redrock/server.rb
|
76
|
+
- lib/redrock.rb
|
77
|
+
- README.rdoc
|
78
|
+
has_rdoc: true
|
79
|
+
homepage: http://github.com/kerryb/redrock
|
80
|
+
licenses: []
|
81
|
+
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options:
|
84
|
+
- --main
|
85
|
+
- README.rdoc
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 3
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
106
|
+
requirements: []
|
107
|
+
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 1.3.7
|
110
|
+
signing_key:
|
111
|
+
specification_version: 3
|
112
|
+
summary: Proxy for using WebMock remotely
|
113
|
+
test_files: []
|
114
|
+
|