rspec-crampy 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.platform = Gem::Platform::RUBY
3
+ s.name = 'rspec-crampy'
4
+ s.version = '0.1.3'
5
+ s.summary = 'RSpec helpers for Crampy.'
6
+ s.description = 'RSpec extension library for Cramp.'
7
+
8
+ s.author = 'Martin Bilski'
9
+ s.email = 'gyamtso@gmail.com'
10
+ s.homepage = 'https://github.com/Vasfed/rspec-cramp'
11
+
12
+ s.add_dependency('rack', '~> 1.3')
13
+ s.add_dependency('eventmachine', '~> 1.0.0')
14
+ s.add_dependency('http_router', '>= 0.11')
15
+ s.add_dependency('rspec', '~> 2.6')
16
+ s.files = Dir['README.md', 'MIT-LICENSE', '*.gemspec', 'Rakefile', 'lib/**/*', 'spec/**/*']
17
+ s.has_rdoc = false
18
+
19
+ s.add_development_dependency "rake"
20
+
21
+ s.require_path = 'lib'
22
+ end
@@ -0,0 +1,60 @@
1
+ require File.join(File.dirname(__FILE__), "../spec_helper")
2
+ require File.join(File.dirname(__FILE__), "sample_actions")
3
+
4
+ # Decorate your spec with :cramp => true
5
+ describe HelloWorld, :cramp => true do
6
+
7
+ # You need to define this method
8
+ def app
9
+ HelloWorld # Here goes your cramp application, action or http routes.
10
+ end
11
+
12
+ # Matching on status code.
13
+ it "should respond to a GET request" do
14
+ get("/").should respond_with :status => :ok # Matches responses from 200 to 299.
15
+ get("/").should respond_with :status => 200 # Matches only 200.
16
+ get("/").should respond_with :status => "200" # Same as above.
17
+ get("/").should respond_with :status => /^2.*/ # Matches response codes starting with 2.
18
+ get("/").should_not respond_with :status => :error # Matches any HTTP error.
19
+ end
20
+
21
+ # Matching on response body.
22
+ it "should respond with text starting with 'Hello'" do
23
+ get("/").should respond_with :body => /^Hello.*/
24
+ end
25
+ it "should respond with 'Hello, world!'" do
26
+ get("/").should respond_with :body => "Hello, world!"
27
+ end
28
+
29
+ # Matching on response headers.
30
+ it "should respond with html" do
31
+ get("/").should respond_with :headers => {"Content-Type" => "text/html"}
32
+ get("/").should_not respond_with :headers => {"Content-Type" => "text/plain"}
33
+ get("/").should_not respond_with :headers => {"Unexpected-Header" => /.*/}
34
+ end
35
+
36
+ # Matching using lambdas.
37
+ it "should match my sophisticated custom matchers" do
38
+ # Entire headers.
39
+ status_check = lambda {|status| status.between?(200, 299)}
40
+ body_check = lambda {|body| body =~ /.*el.*/}
41
+ headers_check = lambda {|headers| true} # Any headers will do.
42
+ get("/").should respond_with :status => status_check, :body => body_check, :headers => headers_check
43
+ # Header value.
44
+ get("/").should respond_with :headers => {"Content-Type" => lambda {|value| value == "text/html"}}
45
+ get("/").should_not respond_with :headers => {"Content-Type" => lambda {|value| value == "text/plain"}}
46
+ end
47
+
48
+ # Supports POST/GET/PUT/DELETE and you don't have to use the matcher.
49
+ it "should work without a matcher" do
50
+ get "/"
51
+ post "/"
52
+ put "/"
53
+ delete "/"
54
+ end
55
+
56
+ # Request params & custom headers.
57
+ it "should accept my params" do
58
+ post("/", :params => {:text => "whatever"}, :headers => {"Custom-Header" => "blah"})
59
+ end
60
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), "../spec_helper")
2
+ require File.join(File.dirname(__FILE__), "sample_actions")
3
+
4
+ describe "Error handling", :cramp => true do
5
+ def app
6
+ HttpRouter.new do
7
+ add('/error_before_start').to ErrorBeforeStart
8
+ add('/error_on_start').to ErrorOnStart
9
+ add('/error_on_finish').to ErrorOnFinish
10
+ end
11
+ end
12
+
13
+ it "should handle error in before_start handler" do
14
+ get("/error_before_start").should respond_with :status => 500
15
+ end
16
+
17
+ it "should handle error in on_start handler" do
18
+ # Headers were already sent by the time the exception was raised.
19
+ get("/error_on_start").should respond_with :body => /.*Error in on_start.*/, :status => 200
20
+ end
21
+
22
+ it "should handle error in on_finish handler" do
23
+ # Headers were already sent by the time the exception was raised.
24
+ get("/error_on_finish").should respond_with :body => /.*Error in on_finish.*/, :status => 200
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ require File.join(File.dirname(__FILE__), "../spec_helper")
2
+ require File.join(File.dirname(__FILE__), "sample_actions")
3
+
4
+ describe CustomHeader, :cramp => true do
5
+ def app
6
+ CustomHeader
7
+ end
8
+
9
+ it "should render the value of the custom header" do
10
+ get("/", :headers => {"Custom-Header" => "SAMPLE VALUE"}).should respond_with :body => /^SAMPLE VALUE$/
11
+ get("/", :headers => {"Custom-Header" => "SAMPLE VALUE"}).should respond_with :body => "SAMPLE VALUE"
12
+ end
13
+
14
+ it "should include the custom header in response headers" do
15
+ # Exact match using string & regex.
16
+ get("/", :headers => {"Custom-Header" => "SAMPLE VALUE"}).should respond_with :headers => {"Custom-Header" => "SAMPLE VALUE"}
17
+ get("/", :headers => {"Custom-Header" => "SAMPLE VALUE"}).should respond_with :headers => {"Custom-Header" => /^SAMPLE VALUE$/}
18
+
19
+ # Header field names are case insensitive - use regex match.
20
+ get("/", :headers => {"Custom-Header" => "SAMPLE VALUE"}).should respond_with :headers => {/Custom\-Header/i => "SAMPLE VALUE"}
21
+
22
+ # Negative match.
23
+ get("/", :headers => {"Custom-Header" => "SAMPLE VALUE"}).should_not respond_with :headers => {"Custom-Header" => "ANOTHER VALUE"}
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), "../spec_helper")
2
+ require File.join(File.dirname(__FILE__), "sample_actions")
3
+
4
+ describe HelloWorld, :cramp => true do
5
+ def app
6
+ HelloWorld
7
+ end
8
+
9
+ it "should respond to a GET request" do
10
+ get("/") do |response|
11
+ response.status.should == 200
12
+ response.headers.should have_key "Content-Type"
13
+ response.should be_matching :status => :ok
14
+ stop # This is important.
15
+ end
16
+ end
17
+ it "should match the body" do
18
+ get("/") do |response|
19
+ response.read_body do
20
+ response.body.should include "Hello, world!" # MockResponse::body returns an Array.
21
+ response.should be_matching :body => "Hello, world!"
22
+ # Note: no call to stop here.
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ class HelloWorld < Cramp::Action
2
+ def start
3
+ render "Hello, world!"
4
+ finish
5
+ end
6
+ end
7
+
8
+ class ErrorOnStart < Cramp::Action
9
+ on_start :raise_error
10
+ def raise_error
11
+ raise "Error in on_start"
12
+ end
13
+ end
14
+
15
+ class ErrorBeforeStart < Cramp::Action
16
+ before_start :raise_error
17
+ def raise_error
18
+ raise "Error in before_start"
19
+ end
20
+ end
21
+
22
+ class ErrorOnFinish < Cramp::Action
23
+ on_start :just_finish
24
+ on_finish :raise_error
25
+ def just_finish
26
+ finish
27
+ end
28
+ def raise_error
29
+ raise "Error in on_finish"
30
+ end
31
+ end
32
+
33
+ class CustomHeader < Cramp::Action
34
+ on_start :render_custom_header
35
+ def respond_with
36
+ [200, {'Content-Type' => 'text/html', 'Custom-Header' => @env["HTTP_CUSTOM_HEADER"]}]
37
+ end
38
+ def render_custom_header
39
+ render @env["HTTP_CUSTOM_HEADER"]
40
+ finish
41
+ end
42
+ end
@@ -0,0 +1,513 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ module Cramp
4
+
5
+ describe "rspec-cramp" do
6
+ class SuccessfulResponse < Cramp::Action
7
+ on_start :render_and_finish
8
+ def render_and_finish
9
+ render "ok"
10
+ finish
11
+ end
12
+ end
13
+
14
+ class HelloWorldResponse < Cramp::Action
15
+ on_start :render_and_finish
16
+ def render_and_finish
17
+ render "Hello, world"
18
+ finish
19
+ end
20
+ end
21
+
22
+ class MultipartResponse < Cramp::Action
23
+ on_start :render_and_finish
24
+ def render_and_finish
25
+ render "part1"
26
+ render "part2"
27
+ finish
28
+ end
29
+ end
30
+
31
+ class ErrorResponse < Cramp::Action
32
+ on_start :just_finish
33
+ def respond_with
34
+ [500, {'Content-Type' => 'text/html'}]
35
+ end
36
+ def just_finish
37
+ finish
38
+ end
39
+ end
40
+
41
+
42
+ class RaiseBeforeStart < Cramp::Action
43
+ before_start :raise_error
44
+ def raise_error
45
+ raise "Error in before_start"
46
+ end
47
+ end
48
+
49
+ class RaiseOnStart < Cramp::Action
50
+ on_start :raise_error
51
+ def raise_error
52
+ raise "Error in on_start"
53
+ end
54
+ end
55
+
56
+ class RaiseOnFinish < Cramp::Action
57
+ on_start :just_finish
58
+ on_finish :raise_error
59
+ def just_finish
60
+ finish
61
+ end
62
+ def raise_error
63
+ raise "Error in on_finish"
64
+ end
65
+ end
66
+
67
+ class NoResponse < Cramp::Action
68
+ on_start :noop
69
+ def noop
70
+ end
71
+ end
72
+
73
+ class CustomHeaders < Cramp::Action
74
+ on_start :ok_and_finish
75
+ def respond_with
76
+ [200, {'Extra-Header' => 'ABCD', 'Another-One' => 'QWERTY'}]
77
+ end
78
+ def ok_and_finish
79
+ render "ok"
80
+ finish
81
+ end
82
+ end
83
+
84
+ class SseAction < Cramp::Action
85
+ self.transport = :sse
86
+ periodic_timer :write_hello, :every => 0.5
87
+ def write_hello
88
+ @num ||= 1
89
+ render "Hello #{@num}"
90
+ @num += 1
91
+ end
92
+ end
93
+
94
+ class SseNoRenderAction < Cramp::Action
95
+ self.transport = :sse
96
+ end
97
+
98
+ class RequestHeaders < Cramp::Action
99
+ on_start :render_request_headers
100
+ def render_request_headers
101
+ response = http_headers.inject("Request headers:\n") {|acc, (k,v)| acc << "#{k}: #{v}\n"; acc}
102
+ render response
103
+ finish
104
+ end
105
+
106
+ private
107
+
108
+ def http_headers
109
+ @env.inject({}){|acc, (k,v)| acc[$1.upcase] = v if k =~ /^http_(.*)/i; acc}
110
+ end
111
+ end
112
+
113
+ class RequestParams < Cramp::Action
114
+ on_start :render_and_finish
115
+ def render_and_finish
116
+ render params[:text]
117
+ finish
118
+ end
119
+ end
120
+
121
+
122
+ def routes
123
+ HttpRouter.new do
124
+ add('/200').to SuccessfulResponse
125
+ add('/hello_world').to HelloWorldResponse
126
+ add('/multipart').to MultipartResponse
127
+ add('/500').to ErrorResponse
128
+ add('/no_response').to NoResponse
129
+ add('/custom_header').to CustomHeaders
130
+ add('/raise_before_start').to RaiseBeforeStart
131
+ add('/raise_on_start').to RaiseOnStart
132
+ add('/raise_on_finish').to RaiseOnFinish
133
+ add('/sse').to SseAction
134
+ add('/sse_no_render').to SseNoRenderAction
135
+ get('/get_only').to SuccessfulResponse
136
+ post('/post_only').to SuccessfulResponse
137
+ put('/put_only').to SuccessfulResponse
138
+ delete('/delete_only').to SuccessfulResponse
139
+ add('/request_headers').to RequestHeaders
140
+ add('/request_params').to RequestParams
141
+ end
142
+ end
143
+
144
+ describe "'respond_with' matcher", :cramp => true do
145
+ def app
146
+ routes
147
+ end
148
+
149
+ it "should raise error for unsupported match options" do
150
+ lambda { get("/200").should respond_with :whatever => "ABC" }.should raise_error
151
+ end
152
+
153
+ shared_examples_for "async_request" do |method|
154
+
155
+ describe "timeout" do
156
+ it "- timeout when no response" do
157
+ lambda { send(method, "/no_response") }.should raise_error Timeout::Error
158
+ end
159
+ it "- allow the timeout to be defined by the user" do
160
+ lambda do
161
+ timeout(2) do
162
+ lambda {send(method, "/no_response", {:timeout => 1}) }.should raise_error Timeout::Error
163
+ end
164
+ end.should_not raise_error Timeout::Error
165
+ end
166
+ end
167
+
168
+ describe "exact match on response status" do
169
+ it "should match successful response" do
170
+ send(method, "/200").should respond_with :status => 200
171
+ send(method, "/200").should respond_with :status => "200"
172
+ send(method, "/200").should respond_with :status => :ok
173
+ end
174
+ it "should match error response" do
175
+ send(method, "/500").should respond_with :status => 500
176
+ send(method, "/500").should respond_with :status => "500"
177
+ send(method, "/500").should respond_with :status => :error
178
+ send(method, "/500").should_not respond_with :status => 200
179
+ send(method, "/500").should_not respond_with :status => "200"
180
+ send(method, "/500").should_not respond_with :status => :ok
181
+ end
182
+ it "should match non-async errors from http router" do
183
+ send(method, "/404").should respond_with :status => 404
184
+ send(method, "/404").should respond_with :status => "404"
185
+ end
186
+ end
187
+
188
+ describe "regex match on response status" do
189
+ it "should match successful response" do
190
+ send(method, "/200").should respond_with :status => /^2.*/
191
+ end
192
+ it "should match error response" do
193
+ send(method, "/500").should respond_with :status => /^5.*/
194
+ send(method, "/500").should_not respond_with :status => /^2.*/
195
+ end
196
+ it "should match non-sync errors from http router" do
197
+ send(method, "/404").should respond_with :status => /^4.*/
198
+ end
199
+ end
200
+
201
+ describe "lambda match on response status" do
202
+ it "should match when true" do
203
+ send(method, "/200").should respond_with :status => lambda {|status| status == 200}
204
+ end
205
+ it "should not match when false" do
206
+ send(method, "/200").should_not respond_with :status => lambda {|status| status == 500}
207
+ end
208
+ end
209
+
210
+ describe "exact match on response header values" do
211
+ it "should match with one expected header" do
212
+ send(method, "/custom_header").should respond_with :headers => {"Extra-Header" => "ABCD"}
213
+ end
214
+ it "should match all with two expected headers" do
215
+ send(method, "/custom_header").should respond_with :headers => {"Extra-Header" => "ABCD", "Another-One" => "QWERTY"}
216
+ end
217
+ it "should not match if value does not match" do
218
+ send(method, "/custom_header").should_not respond_with :headers => {"Extra-Header" => "1234"}
219
+ end
220
+ it "should not match iff the header isn't there" do
221
+ send(method, "/custom_header").should_not respond_with :headers => {"Non-Existent-One" => "QWERTY"}
222
+ end
223
+ end
224
+
225
+ describe "regex match on response header values" do
226
+ it "should match with one expected header" do
227
+ send(method, "/custom_header").should respond_with :headers => {"Extra-Header" => /^ABCD$/}
228
+ end
229
+ it "should match all with two expected headers" do
230
+ send(method, "/custom_header").should respond_with :headers => {"Extra-Header" => /^ABCD$/, "Another-One" => /^QWERTY$/}
231
+ end
232
+ it "should not match if value does not match" do
233
+ send(method, "/custom_header").should_not respond_with :headers => {"Extra-Header" => /^1234$/}
234
+ end
235
+ it "should not match iff the header isn't there" do
236
+ send(method, "/custom_header").should_not respond_with :headers => {"Non-Existent-One" => /^QWERTY$/}
237
+ end
238
+ end
239
+
240
+ describe "lambda match on response header values" do
241
+ it "should match when true" do
242
+ send(method, "/custom_header").should respond_with :headers => {"Extra-Header" => lambda {|value| value == "ABCD"}}
243
+ end
244
+ it "should not match when false" do
245
+ send(method, "/custom_header").should_not respond_with :headers => {"Extra-Header" => lambda {|value| value == "WRONG"}}
246
+ end
247
+ end
248
+
249
+ describe "regex match on response header fields" do
250
+ it "should match with one expected header" do
251
+ send(method, "/custom_header").should respond_with :headers => {/Extra\-Header/i => /^ABCD$/}
252
+ end
253
+ it "should match all with two expected headers" do
254
+ send(method, "/custom_header").should respond_with :headers => {/Extra\-Header/i => /^ABCD$/, "Another-One" => /^QWERTY$/}
255
+ end
256
+ it "should not match if value does not match" do
257
+ send(method, "/custom_header").should_not respond_with :headers => {/Extra\-Header/i => /^1234$/}
258
+ end
259
+ it "should not match iff the header isn't there" do
260
+ send(method, "/custom_header").should_not respond_with :headers => {/Non\-Existent\-One/i => /^QWERTY$/}
261
+ end
262
+ end
263
+
264
+ describe "lambda match on entire header " do
265
+ it "should match when true" do
266
+ match_headers = lambda do |headers|
267
+ headers.find {|(k, v)| k == "Extra-Header" && v == "ABCD"}
268
+ end
269
+ send(method, "/custom_header").should respond_with :headers => match_headers
270
+ end
271
+ it "should not match when false" do
272
+ match_headers = lambda do |headers|
273
+ headers.find {|(k, v)| k == "Non-Existent-One" && v == "QWERTY"}
274
+ end
275
+ send(method, "/custom_header").should_not respond_with :headers => match_headers
276
+ end
277
+ end
278
+
279
+ # FIXME How to handle a situation where nothing is rendered? get reads the body...
280
+
281
+ describe "exact match on response body" do
282
+ it "should match with successful response" do
283
+ send(method, "/200").should respond_with :body => "ok"
284
+ send(method, "/200").should_not respond_with :body => "wrong"
285
+ end
286
+ it "should not load body on error response" do
287
+ # TODO Not sure about this behaviour. What do you think? Use "Something went wrong"?
288
+ send(method, "/500").should respond_with :body => /.*Cramp::Body.*/
289
+ end
290
+ it "should match non-async response from http router" do
291
+ send(method, "/404").should respond_with :body => "Something went wrong"
292
+ end
293
+ end
294
+ describe "regex match on response body" do
295
+ it "should match the body" do
296
+ send(method, "/hello_world").should respond_with :body => /.*Hello.*/
297
+ send(method, "/hello_world").should_not respond_with :body => /.*incorrect.*/
298
+ end
299
+ end
300
+
301
+ describe "lambda match on response body" do
302
+ it "should match when true" do
303
+ send(method, "/hello_world").should respond_with :body => lambda {|body| body =~ /.*Hello.*/}
304
+ end
305
+ it "should not match when false" do
306
+ send(method, "/hello_world").should_not respond_with :body => lambda {|body| body =~ /.*incorrect.*/}
307
+ end
308
+ end
309
+
310
+ describe "exact match on multipart response body" do
311
+ it "should match with successful response" do
312
+ send(method, "/multipart", :max_chunks => 2).should respond_with :body => "part1part2"
313
+ send(method, "/multipart", :max_chunks => 2).should_not respond_with :body => "whatever"
314
+ end
315
+ end
316
+ describe "regex match on multipart response body" do
317
+ it "should match the body" do
318
+ send(method, "/multipart", :max_chunks => 2).should respond_with :body => /.*part.*/
319
+ send(method, "/multipart", :max_chunks => 2).should_not respond_with :body => /.*incorrect.*/
320
+ end
321
+ end
322
+
323
+ describe "exact match on response body chunks" do
324
+ it "should match with successful response" do
325
+ send(method, "/multipart", :max_chunks => 2).should respond_with :chunks => ["part1", "part2"]
326
+ send(method, "/multipart", :max_chunks => 2).should_not respond_with :chunks => ["whatever1", "whatever2"]
327
+ end
328
+ end
329
+ describe "regex match on response body chunks" do
330
+ # Note: In theory, an exact match would also work but because the content also contains an event-id,
331
+ # it is not practical.
332
+ it "should match with successful response" do
333
+ send(method, "/multipart", :max_chunks => 2).should respond_with :chunks => [/part1/, /part2/]
334
+ send(method, "/multipart", :max_chunks => 2).should_not respond_with :chunks => [/whatever1/, /whatever2/]
335
+ end
336
+ end
337
+
338
+ describe "lambda match on response body chunks" do
339
+ it "should match when true" do
340
+ send(method, "/multipart", :max_chunks => 2).should respond_with(:chunks => lambda do |chunks|
341
+ chunks[0] =~ /part1/ && chunks[1] =~ /part2/
342
+ end)
343
+ end
344
+ it "should not match when false" do
345
+ send(method, "/multipart", :max_chunks => 2).should_not respond_with(:chunks => lambda do |chunks|
346
+ chunks[0] =~ /whatever1/ || chunks[1] =~ /whatever2/
347
+ end)
348
+ end
349
+ end
350
+
351
+
352
+ describe "multiple conditions" do
353
+ it "should match on status and body" do
354
+ send(method, "/200").should respond_with :status => :ok, :body => "ok"
355
+ send(method, "/200").should_not respond_with :status => :ok, :body => "incorrect"
356
+ send(method, "/200").should_not respond_with :status => :error, :body => "ok"
357
+ end
358
+ end
359
+
360
+ describe "sse support" do
361
+ # Note: In theory, xact match would also work but because the content also contains an event-id,
362
+ # it is not practical.
363
+ it "should match with successful response" do
364
+ send(method, "/sse", :max_chunks => 2).should respond_with :chunks => [/^data: Hello 1.*/, /^data: Hello 2.*/]
365
+ send(method, "/sse", :max_chunks => 2).should_not respond_with :chunks => [/.*Incorrect 1.*/, /.*Incorrect 2.*/]
366
+ end
367
+
368
+ it "should not wait for body if it is skipped explicitly" do
369
+ lambda { send(method, "/sse_no_render", :max_chunks => 0) }.should_not raise_error Timeout::Error
370
+ send(method, "/sse_no_render", :max_chunks => 0).should respond_with :status => 200, :body => ""
371
+ end
372
+ end
373
+
374
+ it "should correctly handle exception in the callbacks" do
375
+ send(method, "/raise_on_start").should respond_with :status => 200 # Unfortunately, the headers have been already sent.
376
+ end
377
+
378
+ describe "when an action raises an exception" do
379
+ it "should handle error in before_start handler" do
380
+ get("/raise_before_start").should respond_with :status => 500
381
+ end
382
+
383
+ it "should handle error in on_start handler" do
384
+ # Headers were already sent by the time the exception was raised.
385
+ get("/raise_on_start").should respond_with :body => /.*Error in on_start.*/, :status => 200
386
+ end
387
+
388
+ it "should handle error in on_finish handler" do
389
+ # Headers were already sent by the time the exception was raised.
390
+ get("/raise_on_finish").should respond_with :body => /.*Error in on_finish.*/, :status => 200
391
+ end
392
+ end
393
+
394
+ it "should support custom request headers" do
395
+ get("/request_headers", :headers => {"Custom1" => "ABC", "Custom2" => "DEF"}).should respond_with :body => /.*^Custom1: ABC$.*/i
396
+ get("/request_headers", :headers => {"Custom1" => "ABC", "Custom2" => "DEF"}).should respond_with :body => /.*^Custom2: DEF$.*/i
397
+ end
398
+
399
+ it "should support request params" do
400
+ get("/request_params", :params => {:text => "Hello, world!"}).should respond_with :body => "Hello, world!"
401
+ end
402
+
403
+ it "should pass body chunks to the block" do
404
+ actual_chunks = []
405
+ get("/sse", :max_chunks => 2).should respond_with(:chunks => lambda {|chunks| actual_chunks = chunks; true})
406
+ actual_chunks.should have(2).elements
407
+ actual_chunks[0].should include "Hello 1"
408
+ actual_chunks[1].should include "Hello 2"
409
+ end
410
+ end
411
+
412
+ describe "GET request" do
413
+ it_should_behave_like "async_request", :get
414
+
415
+ it "should be able to access paths accessible only with GET" do
416
+ get("/get_only").should respond_with :status => :ok
417
+ end
418
+ it "should not be able to access paths non-accessible with GET" do
419
+ get("/post_only").should respond_with :status => 405
420
+ end
421
+ end
422
+
423
+ describe "POST request" do
424
+ it_should_behave_like "async_request", :post
425
+
426
+ it "should be able to access paths accessible only with POST" do
427
+ post("/post_only").should respond_with :status => :ok
428
+ end
429
+ it "should not be able to access paths non-accessible with POST" do
430
+ post("/get_only").should respond_with :status => 405
431
+ end
432
+ end
433
+
434
+ describe "DELETE request" do
435
+ it_should_behave_like "async_request", :delete
436
+
437
+ it "should be able to access paths accessible only with DELETE" do
438
+ delete("/delete_only").should respond_with :status => :ok
439
+ end
440
+ it "should not be able to access paths non-accessible with DELETE" do
441
+ delete("/post_only").should respond_with :status => 405
442
+ end
443
+ end
444
+
445
+ describe "PUT request" do
446
+ it_should_behave_like "async_request", :put
447
+
448
+ it "should be able to access paths accessible only with PUT" do
449
+ put("/put_only").should respond_with :status => :ok
450
+ end
451
+ it "should not be able to access paths non-accessible with PUT" do
452
+ put("/post_only").should respond_with :status => 405
453
+ end
454
+ end
455
+ end
456
+
457
+ # FIXME Better failure message for response matcher.
458
+ describe "'be_matching' matcher", :cramp => true do
459
+ def app
460
+ routes
461
+ end
462
+
463
+ # Note: Only basic specs here because respond_with matcher uses the same code and is extensively tested.
464
+
465
+ it "should support expectations on response status" do
466
+ get("/200") do |response|
467
+ response.should be_matching :status => 200
468
+ response.should be_matching :status => :ok
469
+ response.should_not be_matching :status => 500
470
+ stop
471
+ end
472
+ end
473
+ it "should support expectations on response body" do
474
+ get("/200") do |response|
475
+ response.read_body do
476
+ response.body.should == ["ok"]
477
+ response.body.should_not == ["whatever"]
478
+ end
479
+ end
480
+ end
481
+ it "should support array access" do
482
+ get("/200") do |response|
483
+ response[0].should == 200
484
+ response[1].should be_a Hash
485
+ response[2].should be_a Cramp::Body
486
+ response[-1].should be_a Cramp::Body
487
+ stop
488
+ end
489
+ end
490
+ it "should handle exceptions in block" do
491
+ lambda { get("/404") do |response|
492
+ raise "this is an error"
493
+ end }.should raise_error
494
+ end
495
+
496
+ describe "improper body access" do
497
+ it "should warn user if body is accessed via an attribute without read_body" do
498
+ get("/200") do |response|
499
+ lambda { response.body }.should raise_error
500
+ stop
501
+ end
502
+ end
503
+ it "should warn user if body is accessed via an attribute outside read_body" do
504
+ get("/200") do |response|
505
+ response.read_body
506
+ lambda { response.body }.should raise_error
507
+ stop
508
+ end
509
+ end
510
+ end
511
+ end
512
+ end
513
+ end