webmachine 1.6.0 → 2.0.0.beta
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +2 -5
- data/documentation/adapters.md +2 -11
- data/examples/debugger.rb +5 -3
- data/examples/logging.rb +2 -2
- data/examples/webrick.rb +2 -2
- data/lib/webmachine/adapter.rb +0 -3
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -1
- data/lib/webmachine/adapters/rack.rb +38 -34
- data/lib/webmachine/adapters/rack_mapped.rb +1 -2
- data/lib/webmachine/adapters/webrick.rb +11 -12
- data/lib/webmachine/adapters.rb +0 -2
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +1 -1
- data/lib/webmachine/configuration.rb +1 -1
- data/lib/webmachine/constants.rb +12 -12
- data/lib/webmachine/cookie.rb +20 -18
- data/lib/webmachine/decision/conneg.rb +24 -24
- data/lib/webmachine/decision/falsey.rb +0 -1
- data/lib/webmachine/decision/flow.rb +19 -20
- data/lib/webmachine/decision/fsm.rb +4 -4
- data/lib/webmachine/decision/helpers.rb +21 -21
- data/lib/webmachine/dispatcher/route.rb +28 -28
- data/lib/webmachine/dispatcher.rb +3 -2
- data/lib/webmachine/errors.rb +7 -8
- data/lib/webmachine/etags.rb +2 -1
- data/lib/webmachine/header_negotiation.rb +5 -6
- data/lib/webmachine/headers.rb +5 -5
- data/lib/webmachine/media_type.rb +5 -5
- data/lib/webmachine/quoted_string.rb +3 -3
- data/lib/webmachine/request.rb +7 -10
- data/lib/webmachine/rescueable_exception.rb +3 -3
- data/lib/webmachine/resource/authentication.rb +3 -4
- data/lib/webmachine/resource/callbacks.rb +3 -3
- data/lib/webmachine/resource/encodings.rb +3 -9
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/response.rb +7 -9
- data/lib/webmachine/spec/adapter_lint.rb +67 -69
- data/lib/webmachine/spec/test_resource.rb +22 -22
- data/lib/webmachine/streaming/encoder.rb +3 -2
- data/lib/webmachine/streaming/io_encoder.rb +4 -3
- data/lib/webmachine/trace/fsm.rb +25 -18
- data/lib/webmachine/trace/resource_proxy.rb +10 -9
- data/lib/webmachine/trace/static/http-headers-status-v3.png +0 -0
- data/lib/webmachine/trace/trace_resource.rb +22 -24
- data/lib/webmachine/trace.rb +7 -6
- data/lib/webmachine/translation.rb +3 -3
- data/lib/webmachine/version.rb +1 -1
- metadata +52 -86
- data/.gitignore +0 -31
- data/Gemfile +0 -46
- data/Guardfile +0 -11
- data/RELEASING.md +0 -21
- data/Rakefile +0 -44
- data/lib/webmachine/adapters/httpkit.rb +0 -74
- data/lib/webmachine/adapters/reel.rb +0 -113
- data/memory_test.rb +0 -37
- data/spec/spec_helper.rb +0 -56
- data/spec/webmachine/adapter_spec.rb +0 -39
- data/spec/webmachine/adapters/httpkit_spec.rb +0 -10
- data/spec/webmachine/adapters/rack_mapped_spec.rb +0 -71
- data/spec/webmachine/adapters/rack_spec.rb +0 -62
- data/spec/webmachine/adapters/reel_spec.rb +0 -76
- data/spec/webmachine/adapters/webrick_spec.rb +0 -12
- data/spec/webmachine/application_spec.rb +0 -74
- data/spec/webmachine/chunked_body_spec.rb +0 -30
- data/spec/webmachine/configuration_spec.rb +0 -27
- data/spec/webmachine/cookie_spec.rb +0 -99
- data/spec/webmachine/decision/conneg_spec.rb +0 -166
- data/spec/webmachine/decision/falsey_spec.rb +0 -8
- data/spec/webmachine/decision/flow_spec.rb +0 -1148
- data/spec/webmachine/decision/fsm_spec.rb +0 -163
- data/spec/webmachine/decision/helpers_spec.rb +0 -216
- data/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb +0 -22
- data/spec/webmachine/dispatcher/route_spec.rb +0 -248
- data/spec/webmachine/dispatcher_spec.rb +0 -104
- data/spec/webmachine/errors_spec.rb +0 -13
- data/spec/webmachine/etags_spec.rb +0 -75
- data/spec/webmachine/events_spec.rb +0 -58
- data/spec/webmachine/headers_spec.rb +0 -99
- data/spec/webmachine/media_type_spec.rb +0 -85
- data/spec/webmachine/request_spec.rb +0 -273
- data/spec/webmachine/rescueable_exception_spec.rb +0 -15
- data/spec/webmachine/resource/authentication_spec.rb +0 -68
- data/spec/webmachine/response_spec.rb +0 -51
- data/spec/webmachine/trace/fsm_spec.rb +0 -37
- data/spec/webmachine/trace/resource_proxy_spec.rb +0 -34
- data/spec/webmachine/trace/trace_store_spec.rb +0 -29
- data/spec/webmachine/trace_spec.rb +0 -17
- data/webmachine.gemspec +0 -25
@@ -1,1148 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Webmachine::Decision::Flow do
|
4
|
-
subject { Webmachine::Decision::FSM.new(resource, request, response) }
|
5
|
-
let(:method) { 'GET' }
|
6
|
-
let(:uri) { URI.parse("http://localhost/") }
|
7
|
-
let(:headers) { Webmachine::Headers.new }
|
8
|
-
let(:body) { "" }
|
9
|
-
let(:request) { Webmachine::Request.new(method, uri, headers, body) }
|
10
|
-
let(:response) { Webmachine::Response.new }
|
11
|
-
let(:default_resource) { resource_with }
|
12
|
-
let(:missing_resource) { missing_resource_with }
|
13
|
-
|
14
|
-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18:
|
15
|
-
# Origin servers MUST include a Date header field in all responses
|
16
|
-
# ... [except 1xx or 5xx]
|
17
|
-
after(:each) do
|
18
|
-
unless response.code < 200 || response.code >= 500
|
19
|
-
expect(response.headers).to have_key('Date')
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def resource_with(&block)
|
24
|
-
klass = Class.new(Webmachine::Resource) do
|
25
|
-
def to_html; "test resource"; end
|
26
|
-
end
|
27
|
-
klass.module_eval(&block) if block_given?
|
28
|
-
klass.new(request, response)
|
29
|
-
end
|
30
|
-
|
31
|
-
def missing_resource_with(&block)
|
32
|
-
resource_with do
|
33
|
-
def resource_exists?; false; end
|
34
|
-
self.module_eval(&block) if block
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "#b13 (Service Available?)" do
|
39
|
-
let(:resource) do
|
40
|
-
resource_with do
|
41
|
-
attr_accessor :available
|
42
|
-
def service_available?; @available; end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should respond with 503 when the service is unavailable" do
|
47
|
-
resource.available = false
|
48
|
-
subject.run
|
49
|
-
expect(response.code).to eq 503
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe "#b12 (Known method?)" do
|
54
|
-
let(:resource) do
|
55
|
-
resource_with do
|
56
|
-
def known_methods; ['HEAD']; end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should respond with 501 when the method is unknown" do
|
61
|
-
subject.run
|
62
|
-
expect(response.code).to eq 501
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "#b11 (URI too long?)" do
|
67
|
-
let(:resource) do
|
68
|
-
resource_with do
|
69
|
-
def uri_too_long?(uri); true; end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should respond with 414 when the URI is too long" do
|
74
|
-
subject.run
|
75
|
-
expect(response.code).to eq 414
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe "#b10 (Method allowed?)" do
|
80
|
-
let(:resource) do
|
81
|
-
resource_with do
|
82
|
-
def allowed_methods; ['POST']; end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should respond with 405 when the method is not allowed" do
|
87
|
-
subject.run
|
88
|
-
expect(response.code).to eq 405
|
89
|
-
expect(response.headers['Allow']).to eq "POST"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
describe "#b9 (Malformed request?)" do
|
94
|
-
let(:resource) { resource_with { def malformed_request?; true; end } }
|
95
|
-
|
96
|
-
it "should respond with 400 when the request is malformed" do
|
97
|
-
subject.run
|
98
|
-
expect(response.code).to eq 400
|
99
|
-
end
|
100
|
-
|
101
|
-
context "when the Content-MD5 header is present" do
|
102
|
-
let(:resource) do
|
103
|
-
resource_with do
|
104
|
-
def allowed_methods; ['POST']; end;
|
105
|
-
def process_post; true; end;
|
106
|
-
attr_accessor :validation
|
107
|
-
def validate_content_checksum; @validation; end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
let(:method) { "POST" }
|
112
|
-
let(:body) { "This is the body." }
|
113
|
-
let(:headers) { Webmachine::Headers["Content-Type" => "text/plain"] }
|
114
|
-
|
115
|
-
it "should respond with 204 when the request body does match the header" do
|
116
|
-
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest(body)
|
117
|
-
subject.run
|
118
|
-
expect(response.code).to eq 204
|
119
|
-
end
|
120
|
-
|
121
|
-
it "should bypass validation when the header has a nil value" do
|
122
|
-
headers['Content-MD5'] = nil
|
123
|
-
subject.run
|
124
|
-
expect(response.code).to eq 204
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should respond with 400 when the header has a empty string value" do
|
128
|
-
headers['Content-MD5'] = ""
|
129
|
-
subject.run
|
130
|
-
expect(response.code).to eq 400
|
131
|
-
end
|
132
|
-
|
133
|
-
it "should respond with 400 when the header has a non-hashed, non-encoded value" do
|
134
|
-
headers["Content-MD5"] = body
|
135
|
-
subject.run
|
136
|
-
expect(response.code).to eq 400
|
137
|
-
end
|
138
|
-
|
139
|
-
it "should respond with 400 when the header is not encoded as Base64 but digest matches the body" do
|
140
|
-
headers['Content-MD5'] = Digest::MD5.hexdigest(body)
|
141
|
-
subject.run
|
142
|
-
expect(response.code).to eq 400
|
143
|
-
end
|
144
|
-
|
145
|
-
it "should respond with 400 when the request body does not match the header" do
|
146
|
-
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
147
|
-
subject.run
|
148
|
-
expect(response.code).to eq 400
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should respond with 400 when the resource invalidates the checksum" do
|
152
|
-
resource.validation = false
|
153
|
-
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
154
|
-
subject.run
|
155
|
-
expect(response.code).to eq 400
|
156
|
-
end
|
157
|
-
|
158
|
-
it "should not respond with 400 when the resource validates the checksum" do
|
159
|
-
resource.validation = true
|
160
|
-
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
161
|
-
subject.run
|
162
|
-
expect(response.code).to_not eq 400
|
163
|
-
end
|
164
|
-
|
165
|
-
it "should respond with the given code when the resource returns a code while validating" do
|
166
|
-
resource.validation = 500
|
167
|
-
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
168
|
-
subject.run
|
169
|
-
expect(response.code).to eq 500
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
describe "#b8 (Authorized?)" do
|
175
|
-
let(:resource) { resource_with { attr_accessor :auth; def is_authorized?(header); @auth; end } }
|
176
|
-
|
177
|
-
it "should reply with 401 when the client is unauthorized" do
|
178
|
-
resource.auth = false
|
179
|
-
subject.run
|
180
|
-
expect(response.code).to eq 401
|
181
|
-
end
|
182
|
-
|
183
|
-
it "should reply with 401 when the resource gives a challenge" do
|
184
|
-
resource.auth = "Basic realm=Webmachine"
|
185
|
-
subject.run
|
186
|
-
expect(response.code).to eq 401
|
187
|
-
expect(response.headers['WWW-Authenticate']).to eq "Basic realm=Webmachine"
|
188
|
-
end
|
189
|
-
|
190
|
-
it "should halt with the given code when the resource returns a status code" do
|
191
|
-
resource.auth = 400
|
192
|
-
subject.run
|
193
|
-
expect(response.code).to eq 400
|
194
|
-
end
|
195
|
-
|
196
|
-
it "should not reply with 401 when the client is authorized" do
|
197
|
-
resource.auth = true
|
198
|
-
subject.run
|
199
|
-
expect(response.code).to_not eq 401
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
describe "#b7 (Forbidden?)" do
|
204
|
-
let(:resource) { resource_with { attr_accessor :forbid; def forbidden?; @forbid; end } }
|
205
|
-
|
206
|
-
it "should reply with 403 when the request is forbidden" do
|
207
|
-
resource.forbid = true
|
208
|
-
subject.run
|
209
|
-
expect(response.code).to eq 403
|
210
|
-
end
|
211
|
-
|
212
|
-
it "should not reply with 403 when the request is permitted" do
|
213
|
-
resource.forbid = false
|
214
|
-
subject.run
|
215
|
-
expect(response.code).to_not eq 403
|
216
|
-
end
|
217
|
-
|
218
|
-
it "should halt with the given code when the resource returns a status code" do
|
219
|
-
resource.forbid = 400
|
220
|
-
subject.run
|
221
|
-
expect(response.code).to eq 400
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
describe "#b6 (Unsupported Content-* header?)" do
|
226
|
-
let(:resource) do
|
227
|
-
resource_with do
|
228
|
-
def valid_content_headers?(contents)
|
229
|
-
contents['Content-Fail'].nil?
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
it "should reply with 501 when an invalid Content-* header is present" do
|
235
|
-
headers['Content-Fail'] = "yup"
|
236
|
-
subject.run
|
237
|
-
expect(response.code).to eq 501
|
238
|
-
end
|
239
|
-
|
240
|
-
it "should not reply with 501 when all Content-* headers are valid" do
|
241
|
-
subject.run
|
242
|
-
expect(response.code).to_not eq 501
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
describe "#b5 (Known Content-Type?)" do
|
247
|
-
let(:method) { "POST" }
|
248
|
-
let(:body) { "This is the body." }
|
249
|
-
let(:resource) do
|
250
|
-
resource_with do
|
251
|
-
def known_content_type?(type) type !~ /unknown/; end;
|
252
|
-
def process_post; true; end
|
253
|
-
def allowed_methods; %w{POST}; end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
before { headers['Content-Length'] = body.length.to_s }
|
258
|
-
|
259
|
-
it "should reply with 415 when the Content-Type is unknown" do
|
260
|
-
headers['Content-Type'] = "application/x-unknown-type"
|
261
|
-
subject.run
|
262
|
-
expect(response.code).to eq 415
|
263
|
-
end
|
264
|
-
|
265
|
-
it "should not reply with 415 when the Content-Type is known" do
|
266
|
-
headers['Content-Type'] = "text/plain"
|
267
|
-
subject.run
|
268
|
-
expect(response.code).to_not eq 415
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
describe "#b4 (Request entity too large?)" do
|
273
|
-
let(:resource) do
|
274
|
-
resource_with do
|
275
|
-
def allowed_methods; %w{POST}; end
|
276
|
-
def process_post; true; end
|
277
|
-
def valid_entity_length?(length); length.to_i < 100; end
|
278
|
-
end
|
279
|
-
end
|
280
|
-
let(:method) { "POST" }
|
281
|
-
before { headers['Content-Type'] = "text/plain"; headers['Content-Length'] = body.size.to_s }
|
282
|
-
|
283
|
-
context "when the request body is too large" do
|
284
|
-
let(:body) { "Big" * 100 }
|
285
|
-
it "should reply with 413" do
|
286
|
-
subject.run
|
287
|
-
expect(response.code).to eq 413
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
context "when the request body is not too large" do
|
292
|
-
let(:body) { "small" }
|
293
|
-
|
294
|
-
it "should not reply with 413" do
|
295
|
-
subject.run
|
296
|
-
expect(response.code).to_not eq 413
|
297
|
-
end
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
describe "#b3 (OPTIONS?)" do
|
302
|
-
let(:method){ "OPTIONS" }
|
303
|
-
let(:resource){ resource_with { def allowed_methods; %w[GET HEAD OPTIONS]; end } }
|
304
|
-
it "should reply with 200 when the request method is OPTIONS" do
|
305
|
-
subject.run
|
306
|
-
expect(response.code).to eq 200
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
describe "#c3, #c4 (Acceptable media types)" do
|
311
|
-
let(:resource) { default_resource }
|
312
|
-
context "when the Accept header exists" do
|
313
|
-
it "should reply with 406 when the type is unacceptable" do
|
314
|
-
headers['Accept'] = "text/plain"
|
315
|
-
subject.run
|
316
|
-
expect(response.code).to eq 406
|
317
|
-
end
|
318
|
-
|
319
|
-
it "should not reply with 406 when the type is acceptable" do
|
320
|
-
headers['Accept'] = "text/*"
|
321
|
-
subject.run
|
322
|
-
expect(response.code).to_not eq 406
|
323
|
-
expect(response.headers['Content-Type']).to eq "text/html"
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
context "when the Accept header does not exist" do
|
328
|
-
it "should not negotiate a media type" do
|
329
|
-
expect(headers['Accept']).to be_nil
|
330
|
-
expect(subject).to_not receive(:c4)
|
331
|
-
subject.run
|
332
|
-
expect(response.headers['Content-Type']).to eq 'text/html'
|
333
|
-
end
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
describe "#d4, #d5 (Acceptable languages)" do
|
338
|
-
let(:resource) { resource_with { def languages_provided; %w{en-US fr}; end } }
|
339
|
-
context "when the Accept-Language header exists" do
|
340
|
-
it "should reply with 406 when the language is unacceptable" do
|
341
|
-
headers['Accept-Language'] = "es, de"
|
342
|
-
subject.run
|
343
|
-
expect(response.code).to eq 406
|
344
|
-
end
|
345
|
-
|
346
|
-
it "should not reply with 406 when the language is acceptable" do
|
347
|
-
headers['Accept-Language'] = "en-GB, en;q=0.7"
|
348
|
-
subject.run
|
349
|
-
expect(response.code).to_not eq 406
|
350
|
-
expect(response.headers['Content-Language']).to eq "en-US"
|
351
|
-
expect(resource.instance_variable_get(:@language)).to eq 'en-US'
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
context "when the Accept-Language header is absent" do
|
356
|
-
it "should not negotiate the language" do
|
357
|
-
expect(headers['Accept-Language']).to be_nil
|
358
|
-
expect(subject).to_not receive(:d5)
|
359
|
-
subject.run
|
360
|
-
expect(response.headers['Content-Language']).to eq 'en-US'
|
361
|
-
expect(resource.instance_variable_get(:@language)).to eq 'en-US'
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
describe "#e5, #e6 (Acceptable charsets)" do
|
367
|
-
let(:resource) do
|
368
|
-
resource_with do
|
369
|
-
def charsets_provided
|
370
|
-
[["iso8859-1", :to_iso],["utf-8", :to_utf]];
|
371
|
-
end
|
372
|
-
def to_iso(chunk); chunk; end
|
373
|
-
def to_utf(chunk); chunk; end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
context "when the Accept-Charset header exists" do
|
378
|
-
it "should reply with 406 when the charset is unacceptable" do
|
379
|
-
headers['Accept-Charset'] = "utf-16"
|
380
|
-
subject.run
|
381
|
-
expect(response.code).to eq 406
|
382
|
-
end
|
383
|
-
|
384
|
-
it "should not reply with 406 when the charset is acceptable" do
|
385
|
-
headers['Accept-Charset'] = "iso8859-1"
|
386
|
-
subject.run
|
387
|
-
expect(response.code).to_not eq 406
|
388
|
-
expect(response.headers['Content-Type']).to eq "text/html;charset=iso8859-1"
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
context "when the Accept-Charset header is absent" do
|
393
|
-
it "should not negotiate the language" do
|
394
|
-
expect(headers['Accept-Charset']).to be_nil
|
395
|
-
expect(subject).to_not receive(:e6)
|
396
|
-
subject.run
|
397
|
-
expect(response.headers['Content-Type']).to eq 'text/html;charset=iso8859-1'
|
398
|
-
end
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
describe "#f6, #f7 (Acceptable encodings)" do
|
403
|
-
let(:resource) do
|
404
|
-
resource_with do
|
405
|
-
def encodings_provided
|
406
|
-
super.merge("gzip" => :encode_gzip)
|
407
|
-
end
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
context "when the Accept-Encoding header is present" do
|
412
|
-
it "should reply with 406 if the encoding is unacceptable" do
|
413
|
-
headers['Accept-Encoding'] = 'deflate, identity;q=0.0'
|
414
|
-
subject.run
|
415
|
-
expect(response.code).to eq 406
|
416
|
-
end
|
417
|
-
|
418
|
-
it "should not reply with 406 if the encoding is acceptable" do
|
419
|
-
headers['Accept-Encoding'] = 'gzip, deflate'
|
420
|
-
subject.run
|
421
|
-
expect(response.code).to_not eq 406
|
422
|
-
expect(response.headers['Content-Encoding']).to eq 'gzip'
|
423
|
-
# It should be compressed
|
424
|
-
expect(response.body).to_not eq 'test resource'
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
428
|
-
context "when the Accept-Encoding header is not present" do
|
429
|
-
it "should not negotiate an encoding" do
|
430
|
-
expect(headers['Accept-Encoding']).to be_nil
|
431
|
-
expect(subject).to_not receive(:f7)
|
432
|
-
subject.run
|
433
|
-
expect(response.code).to_not eq 406
|
434
|
-
# It should not be compressed
|
435
|
-
expect(response.body).to eq 'test resource'
|
436
|
-
end
|
437
|
-
end
|
438
|
-
end
|
439
|
-
|
440
|
-
describe "#g7 (Resource exists?)" do
|
441
|
-
let(:resource) { resource_with { attr_accessor :exist; def resource_exists?; @exist; end } }
|
442
|
-
|
443
|
-
it "should not enter conditional requests if missing (and eventually reply with 404)" do
|
444
|
-
resource.exist = false
|
445
|
-
expect(subject).to_not receive(:g8)
|
446
|
-
subject.run
|
447
|
-
expect(response.code).to eq 404
|
448
|
-
end
|
449
|
-
|
450
|
-
it "should not reply with 404 if it does exist" do
|
451
|
-
resource.exist = true
|
452
|
-
expect(subject).to_not receive(:h7)
|
453
|
-
subject.run
|
454
|
-
expect(response.code).to_not eq 404
|
455
|
-
end
|
456
|
-
|
457
|
-
it "should not reply with 404 for truthy non-booleans" do
|
458
|
-
resource.exist = []
|
459
|
-
subject.run
|
460
|
-
expect(response.code).to_not eq 404
|
461
|
-
end
|
462
|
-
|
463
|
-
it "should reply with 404 for nil" do
|
464
|
-
resource.exist = nil
|
465
|
-
subject.run
|
466
|
-
expect(response.code).to eq 404
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
|
-
# Conditional requests/preconditions
|
471
|
-
describe "#g8, #g9, #g10 (ETag match)" do
|
472
|
-
let(:resource) { resource_with { def generate_etag; "etag"; end } }
|
473
|
-
it "should skip ETag matching when If-Match is missing" do
|
474
|
-
expect(headers['If-Match']).to be_nil
|
475
|
-
expect(subject).to_not receive(:g9)
|
476
|
-
expect(subject).to_not receive(:g11)
|
477
|
-
subject.run
|
478
|
-
expect(response.code).to_not eq 412
|
479
|
-
end
|
480
|
-
it "should not reply with 304 when If-Match is *" do
|
481
|
-
headers['If-Match'] = "*"
|
482
|
-
subject.run
|
483
|
-
expect(response.code).to_not eq 412
|
484
|
-
end
|
485
|
-
it "should reply with 412 if the ETag is not in If-Match" do
|
486
|
-
headers['If-Match'] = '"notetag"'
|
487
|
-
subject.run
|
488
|
-
expect(response.code).to eq 412
|
489
|
-
end
|
490
|
-
it "should not reply with 412 if the ETag is in If-Match" do
|
491
|
-
headers['If-Match'] = '"etag"'
|
492
|
-
subject.run
|
493
|
-
expect(response.code).to_not eq 412
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
describe "#h10, #h11, #h12 (If-Unmodified-Since match [IUMS])" do
|
498
|
-
let(:resource) { resource_with { attr_accessor :now; def last_modified; @now; end } }
|
499
|
-
before { @now = resource.now = Time.now }
|
500
|
-
|
501
|
-
it "should skip LM matching if IUMS is missing" do
|
502
|
-
expect(headers['If-Unmodified-Since']).to be_nil
|
503
|
-
expect(subject).to_not receive(:h11)
|
504
|
-
expect(subject).to_not receive(:h12)
|
505
|
-
subject.run
|
506
|
-
expect(response.code).to_not eq 412
|
507
|
-
end
|
508
|
-
|
509
|
-
it "should skip LM matching if IUMS is an invalid date" do
|
510
|
-
headers['If-Unmodified-Since'] = "garbage"
|
511
|
-
expect(subject).to_not receive(:h12)
|
512
|
-
subject.run
|
513
|
-
expect(response.code).to_not eq 412
|
514
|
-
end
|
515
|
-
|
516
|
-
it "should not reply with 412 if LM is <= IUMS" do
|
517
|
-
headers['If-Unmodified-Since'] = (@now + 100).httpdate
|
518
|
-
subject.run
|
519
|
-
expect(response.code).to_not eq 412
|
520
|
-
end
|
521
|
-
|
522
|
-
it "should reply with 412 if LM is > IUMS" do
|
523
|
-
headers['If-Unmodified-Since'] = (@now - 100).httpdate
|
524
|
-
subject.run
|
525
|
-
expect(response.code).to eq 412
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
|
-
describe "#i12, #i13, #k13, #j18 (If-None-Match match)" do
|
530
|
-
let(:resource) do
|
531
|
-
resource_with do
|
532
|
-
def generate_etag; "etag"; end;
|
533
|
-
def process_post; true; end
|
534
|
-
def allowed_methods; %w{GET HEAD POST}; end
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
it "should skip ETag matching if If-None-Match is missing" do
|
539
|
-
expect(headers['If-None-Match']).to be_nil
|
540
|
-
%w{i13 k13 j18}.each do |m|
|
541
|
-
expect(subject).to_not receive(m.to_sym)
|
542
|
-
end
|
543
|
-
subject.run
|
544
|
-
expect([304, 412]).to_not include(response.code)
|
545
|
-
end
|
546
|
-
|
547
|
-
it "should not reply with 412 or 304 if the ETag is not in If-None-Match" do
|
548
|
-
headers['If-None-Match'] = '"notetag"'
|
549
|
-
subject.run
|
550
|
-
expect([304, 412]).to_not include(response.code)
|
551
|
-
end
|
552
|
-
|
553
|
-
context "when the method is GET or HEAD" do
|
554
|
-
let(:method){ %w{GET HEAD}[rand(1)] }
|
555
|
-
it "should reply with 304 when If-None-Match is *" do
|
556
|
-
headers['If-None-Match'] = '*'
|
557
|
-
end
|
558
|
-
it "should reply with 304 when the ETag is in If-None-Match" do
|
559
|
-
headers['If-None-Match'] = '"etag", "foobar"'
|
560
|
-
end
|
561
|
-
after { subject.run; expect(response.code).to eq 304 }
|
562
|
-
end
|
563
|
-
|
564
|
-
context "when the method is not GET or HEAD" do
|
565
|
-
let(:method){ "POST" }
|
566
|
-
let(:body) { "This is the body." }
|
567
|
-
let(:headers){ Webmachine::Headers["Content-Type" => "text/plain"] }
|
568
|
-
|
569
|
-
it "should reply with 412 when If-None-Match is *" do
|
570
|
-
headers['If-None-Match'] = '*'
|
571
|
-
end
|
572
|
-
|
573
|
-
it "should reply with 412 when the ETag is in If-None-Match" do
|
574
|
-
headers['If-None-Match'] = '"etag"'
|
575
|
-
end
|
576
|
-
after { subject.run; expect(response.code).to eq 412 }
|
577
|
-
end
|
578
|
-
|
579
|
-
context "when the resource does not define an ETag" do
|
580
|
-
let(:resource) do
|
581
|
-
resource_with do
|
582
|
-
def generate_etag; nil; end
|
583
|
-
end
|
584
|
-
end
|
585
|
-
|
586
|
-
it "should reply with 200 when If-None-Match is missing" do
|
587
|
-
headers.delete 'If-None-Match'
|
588
|
-
subject.run
|
589
|
-
expect(response.code).to eq 200
|
590
|
-
end
|
591
|
-
|
592
|
-
it "should reply with 200 when If-None-Match is present" do
|
593
|
-
headers['If-None-Match'] = '"etag"'
|
594
|
-
subject.run
|
595
|
-
expect(response.code).to eq 200
|
596
|
-
end
|
597
|
-
end
|
598
|
-
end
|
599
|
-
|
600
|
-
describe "#l13, #l14, #l15, #l17 (If-Modified-Since match)" do
|
601
|
-
let(:resource) { resource_with { attr_accessor :now; def last_modified; @now; end } }
|
602
|
-
before { @now = resource.now = Time.now }
|
603
|
-
it "should skip LM matching if IMS is missing" do
|
604
|
-
expect(headers['If-Modified-Since']).to be_nil
|
605
|
-
%w{l14 l15 l17}.each do |m|
|
606
|
-
expect(subject).to_not receive(m.to_sym)
|
607
|
-
end
|
608
|
-
subject.run
|
609
|
-
expect(response.code).to_not eq 304
|
610
|
-
end
|
611
|
-
|
612
|
-
it "should skip LM matching if IMS is an invalid date" do
|
613
|
-
headers['If-Modified-Since'] = "garbage"
|
614
|
-
%w{l15 l17}.each do |m|
|
615
|
-
expect(subject).to_not receive(m.to_sym)
|
616
|
-
end
|
617
|
-
subject.run
|
618
|
-
expect(response.code).to_not eq 304
|
619
|
-
end
|
620
|
-
|
621
|
-
it "should skip LM matching if IMS is later than current time" do
|
622
|
-
headers['If-Modified-Since'] = (@now + 1000).httpdate
|
623
|
-
expect(subject).to_not receive(:l17)
|
624
|
-
subject.run
|
625
|
-
expect(response.code).to_not eq 304
|
626
|
-
end
|
627
|
-
|
628
|
-
it "should reply with 304 if LM is <= IMS" do
|
629
|
-
headers['If-Modified-Since'] = (@now - 1).httpdate
|
630
|
-
resource.now = @now - 1000
|
631
|
-
subject.run
|
632
|
-
expect(response.code).to eq 304
|
633
|
-
end
|
634
|
-
|
635
|
-
it "should not reply with 304 if LM is > IMS" do
|
636
|
-
headers['If-Modified-Since'] = (@now - 1000).httpdate
|
637
|
-
subject.run
|
638
|
-
expect(response.code).to_not eq 304
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
# Resource missing branch (upper right)
|
643
|
-
describe "#h7 (If-Match: * exists?)" do
|
644
|
-
let(:resource) { missing_resource }
|
645
|
-
it "should reply with 412 when the If-Match header is *" do
|
646
|
-
headers['If-Match'] = '"*"'
|
647
|
-
subject.run
|
648
|
-
expect(response.code).to eq 412
|
649
|
-
end
|
650
|
-
|
651
|
-
it "should not reply with 412 when the If-Match header is missing or not *" do
|
652
|
-
headers['If-Match'] = ['"etag"', nil][rand(1)]
|
653
|
-
subject.run
|
654
|
-
expect(response.code).to_not eq 412
|
655
|
-
end
|
656
|
-
end
|
657
|
-
|
658
|
-
describe "#i7 (PUT?)" do
|
659
|
-
let(:resource) do
|
660
|
-
missing_resource_with do
|
661
|
-
def allowed_methods; %w{GET HEAD PUT POST}; end
|
662
|
-
def process_post; true; end
|
663
|
-
end
|
664
|
-
end
|
665
|
-
let(:body) { %W{GET HEAD DELETE}.include?(method) ? nil : "This is the body." }
|
666
|
-
before { headers['Content-Type'] = 'text/plain' }
|
667
|
-
|
668
|
-
context "when the method is PUT" do
|
669
|
-
let(:method){ "PUT" }
|
670
|
-
|
671
|
-
it "should not reach state k7" do
|
672
|
-
expect(subject).to_not receive(:k7)
|
673
|
-
subject.run
|
674
|
-
end
|
675
|
-
|
676
|
-
after { expect([404, 410, 303]).to_not include(response.code) }
|
677
|
-
end
|
678
|
-
|
679
|
-
context "when the method is not PUT" do
|
680
|
-
let(:method){ %W{GET HEAD POST DELETE}[rand(4)] }
|
681
|
-
|
682
|
-
it "should not reach state i4" do
|
683
|
-
expect(subject).to_not receive(:i4)
|
684
|
-
subject.run
|
685
|
-
end
|
686
|
-
|
687
|
-
after { expect(response.code).to_not eq 409 }
|
688
|
-
end
|
689
|
-
end
|
690
|
-
|
691
|
-
describe "#i4 (Apply to a different URI?)" do
|
692
|
-
let(:resource) do
|
693
|
-
missing_resource_with do
|
694
|
-
attr_accessor :location
|
695
|
-
def moved_permanently?; @location; end
|
696
|
-
def allowed_methods; %w[PUT]; end
|
697
|
-
end
|
698
|
-
end
|
699
|
-
let(:method){ "PUT" }
|
700
|
-
let(:body){ "This is the body." }
|
701
|
-
let(:headers) { Webmachine::Headers["Content-Type" => "text/plain", "Content-Length" => body.size.to_s] }
|
702
|
-
|
703
|
-
it "should reply with 301 when the resource has moved" do
|
704
|
-
resource.location = URI.parse("http://localhost:8098/newuri")
|
705
|
-
subject.run
|
706
|
-
expect(response.code).to eq 301
|
707
|
-
expect(response.headers['Location']).to eq resource.location.to_s
|
708
|
-
end
|
709
|
-
|
710
|
-
it "should not reply with 301 when resource has not moved" do
|
711
|
-
resource.location = false
|
712
|
-
subject.run
|
713
|
-
expect(response.code).to_not eq 301
|
714
|
-
end
|
715
|
-
end
|
716
|
-
|
717
|
-
describe "Redirection (Resource previously existed)" do
|
718
|
-
let(:resource) do
|
719
|
-
missing_resource_with do
|
720
|
-
attr_writer :moved_perm, :moved_temp, :allow_missing
|
721
|
-
def previously_existed?; true; end
|
722
|
-
def moved_permanently?; @moved_perm; end
|
723
|
-
def moved_temporarily?; @moved_temp; end
|
724
|
-
def allow_missing_post?; @allow_missing; end
|
725
|
-
def allowed_methods; %W{GET POST}; end
|
726
|
-
def process_post; true; end
|
727
|
-
end
|
728
|
-
end
|
729
|
-
let(:method){ @method || "GET" }
|
730
|
-
|
731
|
-
describe "#k5 (Moved permanently?)" do
|
732
|
-
it "should reply with 301 when the resource has moved permanently" do
|
733
|
-
uri = resource.moved_perm = URI.parse("http://www.google.com/")
|
734
|
-
subject.run
|
735
|
-
expect(response.code).to eq 301
|
736
|
-
expect(response.headers['Location']).to eq uri.to_s
|
737
|
-
end
|
738
|
-
it "should not reply with 301 when the resource has not moved permanently" do
|
739
|
-
resource.moved_perm = false
|
740
|
-
subject.run
|
741
|
-
expect(response.code).to_not eq 301
|
742
|
-
end
|
743
|
-
end
|
744
|
-
|
745
|
-
describe "#l5 (Moved temporarily?)" do
|
746
|
-
before { resource.moved_perm = false }
|
747
|
-
it "should reply with 307 when the resource has moved temporarily" do
|
748
|
-
uri = resource.moved_temp = URI.parse("http://www.basho.com/")
|
749
|
-
subject.run
|
750
|
-
expect(response.code).to eq 307
|
751
|
-
expect(response.headers['Location']).to eq uri.to_s
|
752
|
-
end
|
753
|
-
it "should not reply with 307 when the resource has not moved temporarily" do
|
754
|
-
resource.moved_temp = false
|
755
|
-
subject.run
|
756
|
-
expect(response.code).to_not eq 307
|
757
|
-
end
|
758
|
-
end
|
759
|
-
|
760
|
-
describe "#m5 (POST?), #n5 (POST to missing resource?)" do
|
761
|
-
before { resource.moved_perm = resource.moved_temp = false }
|
762
|
-
it "should reply with 410 when the method is not POST" do
|
763
|
-
expect(method).to_not eq "POST"
|
764
|
-
subject.run
|
765
|
-
expect(response.code).to eq 410
|
766
|
-
end
|
767
|
-
it "should reply with 410 when the resource disallows missing POSTs" do
|
768
|
-
@method = "POST"
|
769
|
-
resource.allow_missing = false
|
770
|
-
subject.run
|
771
|
-
expect(response.code).to eq 410
|
772
|
-
end
|
773
|
-
it "should not reply with 410 when the resource allows missing POSTs" do
|
774
|
-
@method = "POST"
|
775
|
-
resource.allow_missing = true
|
776
|
-
subject.run
|
777
|
-
expect(response.code).to eq 410
|
778
|
-
end
|
779
|
-
end
|
780
|
-
end
|
781
|
-
|
782
|
-
describe "#l7 (POST?), #m7 (POST to missing resource?)" do
|
783
|
-
let(:resource) do
|
784
|
-
missing_resource_with do
|
785
|
-
attr_accessor :allow_missing
|
786
|
-
def allowed_methods; %W{GET POST}; end
|
787
|
-
def previously_existed?; false; end
|
788
|
-
def allow_missing_post?; @allow_missing; end
|
789
|
-
def process_post; true; end
|
790
|
-
end
|
791
|
-
end
|
792
|
-
let(:method){ @method || "GET" }
|
793
|
-
it "should reply with 404 when the method is not POST" do
|
794
|
-
expect(method).to_not eq "POST"
|
795
|
-
subject.run
|
796
|
-
expect(response.code).to eq 404
|
797
|
-
end
|
798
|
-
it "should reply with 404 when the resource disallows missing POSTs" do
|
799
|
-
@method = "POST"
|
800
|
-
resource.allow_missing = false
|
801
|
-
subject.run
|
802
|
-
expect(response.code).to eq 404
|
803
|
-
end
|
804
|
-
it "should not reply with 404 when the resource allows missing POSTs" do
|
805
|
-
@method = "POST"
|
806
|
-
resource.allow_missing = true
|
807
|
-
subject.run
|
808
|
-
expect(response.code).to_not eq 404
|
809
|
-
end
|
810
|
-
end
|
811
|
-
|
812
|
-
describe "#p3 (Conflict?)" do
|
813
|
-
let(:resource) do
|
814
|
-
missing_resource_with do
|
815
|
-
attr_writer :conflict
|
816
|
-
def allowed_methods; %W{PUT}; end
|
817
|
-
def is_conflict?; @conflict; end
|
818
|
-
end
|
819
|
-
end
|
820
|
-
let(:method){ "PUT" }
|
821
|
-
it "should reply with 409 if the resource is in conflict" do
|
822
|
-
resource.conflict = true
|
823
|
-
subject.run
|
824
|
-
expect(response.code).to eq 409
|
825
|
-
end
|
826
|
-
it "should not reply with 409 if the resource is in conflict" do
|
827
|
-
resource.conflict = false
|
828
|
-
subject.run
|
829
|
-
expect(response.code).to_not eq 409
|
830
|
-
end
|
831
|
-
end
|
832
|
-
|
833
|
-
# Bottom right
|
834
|
-
describe "#n11 (Redirect?)" do
|
835
|
-
let(:method) { "POST" }
|
836
|
-
let(:resource) do
|
837
|
-
resource_with do
|
838
|
-
attr_writer :new_loc, :exist
|
839
|
-
def allowed_methods; %w{POST}; end
|
840
|
-
def allow_missing_post?; true; end
|
841
|
-
def process_post
|
842
|
-
response.redirect_to(@new_loc) if @new_loc
|
843
|
-
true
|
844
|
-
end
|
845
|
-
end
|
846
|
-
end
|
847
|
-
[true, false].each do |e|
|
848
|
-
context "and the resource #{ e ? "does not exist" : 'exists'}" do
|
849
|
-
before { resource.exist = e }
|
850
|
-
|
851
|
-
it "should reply with 303 if the resource redirected" do
|
852
|
-
resource.new_loc = URI.parse("/foo/bar")
|
853
|
-
subject.run
|
854
|
-
expect(response.code).to eq 303
|
855
|
-
expect(response.headers['Location']).to eq "/foo/bar"
|
856
|
-
end
|
857
|
-
|
858
|
-
it "should not reply with 303 if the resource did not redirect" do
|
859
|
-
resource.new_loc = nil
|
860
|
-
subject.run
|
861
|
-
expect(response.code).to_not eq 303
|
862
|
-
end
|
863
|
-
end
|
864
|
-
end
|
865
|
-
end
|
866
|
-
|
867
|
-
describe "#p11 (New resource?)" do
|
868
|
-
let(:resource) do
|
869
|
-
resource_with do
|
870
|
-
attr_writer :exist, :new_loc, :create
|
871
|
-
|
872
|
-
def allowed_methods; %W{PUT POST}; end
|
873
|
-
def resource_exists?; @exist; end
|
874
|
-
def process_post; true; end
|
875
|
-
def allow_missing_post?; true; end
|
876
|
-
def post_is_create?; @create; end
|
877
|
-
def create_path; @new_loc; end
|
878
|
-
def content_types_accepted; [["text/plain", :accept_text]]; end
|
879
|
-
def accept_text
|
880
|
-
response.headers['Location'] = @new_loc.to_s if @new_loc
|
881
|
-
true
|
882
|
-
end
|
883
|
-
end
|
884
|
-
end
|
885
|
-
let(:body) { "new content" }
|
886
|
-
let(:headers){ Webmachine::Headers['content-type' => 'text/plain'] }
|
887
|
-
|
888
|
-
context "when the method is PUT" do
|
889
|
-
let(:method){ "PUT" }
|
890
|
-
[true, false].each do |e|
|
891
|
-
context "and the resource #{ e ? "does not exist" : 'exists'}" do
|
892
|
-
before { resource.exist = e }
|
893
|
-
|
894
|
-
it "should reply with 201 when the Location header has been set" do
|
895
|
-
resource.exist = e
|
896
|
-
resource.new_loc = "http://ruby-doc.org/"
|
897
|
-
subject.run
|
898
|
-
expect(response.code).to eq 201
|
899
|
-
end
|
900
|
-
it "should not reply with 201 when the Location header has been set" do
|
901
|
-
resource.exist = e
|
902
|
-
subject.run
|
903
|
-
expect(response.headers['Location']).to be_nil
|
904
|
-
expect(response.code).to_not eq 201
|
905
|
-
end
|
906
|
-
end
|
907
|
-
end
|
908
|
-
end
|
909
|
-
|
910
|
-
context "when the method is POST" do
|
911
|
-
let(:method){ "POST" }
|
912
|
-
[true, false].each do |e|
|
913
|
-
context "and the resource #{ e ? 'exists' : "does not exist"}" do
|
914
|
-
before { resource.exist = e }
|
915
|
-
it "should reply with 201 when post_is_create is true and create_path returns a URI" do
|
916
|
-
resource.new_loc = created = "/foo/bar/baz"
|
917
|
-
resource.create = true
|
918
|
-
subject.run
|
919
|
-
expect(response.code).to eq 201
|
920
|
-
expect(response.headers['Location']).to eq created
|
921
|
-
end
|
922
|
-
it "should reply with 500 when post_is_create is true and create_path returns nil" do
|
923
|
-
resource.create = true
|
924
|
-
subject.run
|
925
|
-
expect(response.code).to eq 500
|
926
|
-
expect(response.error).to_not be_nil
|
927
|
-
end
|
928
|
-
it "should not reply with 201 when post_is_create is false" do
|
929
|
-
resource.create = false
|
930
|
-
subject.run
|
931
|
-
expect(response.code).to_not eq 201
|
932
|
-
end
|
933
|
-
end
|
934
|
-
end
|
935
|
-
end
|
936
|
-
end
|
937
|
-
|
938
|
-
describe "#o14 (Conflict?)" do
|
939
|
-
let(:resource) do
|
940
|
-
resource_with do
|
941
|
-
attr_writer :conflict
|
942
|
-
def allowed_methods; %W{PUT}; end
|
943
|
-
def is_conflict?; @conflict; end
|
944
|
-
end
|
945
|
-
end
|
946
|
-
let(:method){ "PUT" }
|
947
|
-
it "should reply with 409 if the resource is in conflict" do
|
948
|
-
resource.conflict = true
|
949
|
-
subject.run
|
950
|
-
expect(response.code).to eq 409
|
951
|
-
end
|
952
|
-
it "should not reply with 409 if the resource is in conflict" do
|
953
|
-
resource.conflict = false
|
954
|
-
subject.run
|
955
|
-
expect(response.code).to_not eq 409
|
956
|
-
end
|
957
|
-
end
|
958
|
-
|
959
|
-
describe "#m16 (DELETE?), #m20 (Delete enacted?)" do
|
960
|
-
let(:method){ @method || "DELETE" }
|
961
|
-
let(:resource) do
|
962
|
-
resource_with do
|
963
|
-
attr_writer :deleted, :completed
|
964
|
-
def allowed_methods; %w{GET DELETE}; end
|
965
|
-
def delete_resource; @deleted; end
|
966
|
-
def delete_completed?; @completed; end
|
967
|
-
end
|
968
|
-
end
|
969
|
-
it "should not reply with 202 if the method is not DELETE" do
|
970
|
-
@method = "GET"
|
971
|
-
subject.run
|
972
|
-
expect(response.code).to_not eq 202
|
973
|
-
end
|
974
|
-
it "should reply with 500 if the DELETE fails" do
|
975
|
-
resource.deleted = false
|
976
|
-
subject.run
|
977
|
-
expect(response.code).to eq 500
|
978
|
-
end
|
979
|
-
it "should reply with 202 if the DELETE succeeds but is not complete" do
|
980
|
-
resource.deleted = true
|
981
|
-
resource.completed = false
|
982
|
-
subject.run
|
983
|
-
expect(response.code).to eq 202
|
984
|
-
end
|
985
|
-
it "should not reply with 202 if the DELETE succeeds and completes" do
|
986
|
-
resource.completed = resource.deleted = true
|
987
|
-
subject.run
|
988
|
-
expect(response.code).to_not eq 202
|
989
|
-
end
|
990
|
-
end
|
991
|
-
|
992
|
-
# These decisions are covered by dozens of other examples. Leaving
|
993
|
-
# commented for now.
|
994
|
-
# describe "#n16 (POST?)" do it; end
|
995
|
-
# describe "#o16 (PUT?)" do it; end
|
996
|
-
|
997
|
-
describe "#o18 (Multiple representations?)" do
|
998
|
-
let(:resource) do
|
999
|
-
resource_with do
|
1000
|
-
attr_writer :exist, :multiple
|
1001
|
-
def delete_resource
|
1002
|
-
response.body = "Response content."
|
1003
|
-
true
|
1004
|
-
end
|
1005
|
-
def delete_completed?; true; end
|
1006
|
-
def allowed_methods; %W{GET HEAD PUT POST DELETE}; end
|
1007
|
-
def resource_exists?; @exist; end
|
1008
|
-
def allow_missing_post?; true; end
|
1009
|
-
def content_types_accepted; [[request.content_type, :accept_all]]; end
|
1010
|
-
def multiple_choices?; @multiple; end
|
1011
|
-
def process_post
|
1012
|
-
response.body = "Response content."
|
1013
|
-
true
|
1014
|
-
end
|
1015
|
-
def accept_all
|
1016
|
-
response.body = "Response content."
|
1017
|
-
true
|
1018
|
-
end
|
1019
|
-
end
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
[["GET", true],["HEAD", true],["PUT", true],["PUT", false],["POST",true],["POST",false],
|
1023
|
-
["DELETE", true]].each do |m, e|
|
1024
|
-
context "when the method is #{m} and the resource #{e ? 'exists' : 'does not exist' }" do
|
1025
|
-
let(:method){ m }
|
1026
|
-
let(:body) { %W{PUT POST}.include?(m) ? "request body" : "" }
|
1027
|
-
let(:headers) { %W{PUT POST}.include?(m) ? Webmachine::Headers['content-type' => 'text/plain'] : Webmachine::Headers.new }
|
1028
|
-
before { resource.exist = e }
|
1029
|
-
it "should reply with 200 if there are not multiple representations" do
|
1030
|
-
resource.multiple = false
|
1031
|
-
subject.run
|
1032
|
-
puts response.error if response.code == 500
|
1033
|
-
expect(response.code).to eq 200
|
1034
|
-
end
|
1035
|
-
it "should reply with 300 if there are multiple representations" do
|
1036
|
-
resource.multiple = true
|
1037
|
-
subject.run
|
1038
|
-
puts response.error if response.code == 500
|
1039
|
-
expect(response.code).to eq 300
|
1040
|
-
end
|
1041
|
-
end
|
1042
|
-
end
|
1043
|
-
end
|
1044
|
-
|
1045
|
-
describe "#o20 (Response has entity?)" do
|
1046
|
-
let(:resource) do
|
1047
|
-
resource_with do
|
1048
|
-
attr_writer :exist, :body
|
1049
|
-
def delete_resource; true; end
|
1050
|
-
def delete_completed?; true; end
|
1051
|
-
def allowed_methods; %{GET PUT POST DELETE}; end
|
1052
|
-
def resource_exists?; @exist; end
|
1053
|
-
def allow_missing_post?; true; end
|
1054
|
-
def content_types_accepted; [[request.content_type, :accept_all]]; end
|
1055
|
-
def process_post
|
1056
|
-
response.body = @body if @body
|
1057
|
-
true
|
1058
|
-
end
|
1059
|
-
def accept_all
|
1060
|
-
response.body = @body if @body
|
1061
|
-
true
|
1062
|
-
end
|
1063
|
-
end
|
1064
|
-
end
|
1065
|
-
let(:method) { @method || "GET" }
|
1066
|
-
let(:headers) { %{PUT POST}.include?(method) ? Webmachine::Headers["content-type" => "text/plain"] : Webmachine::Headers.new }
|
1067
|
-
let(:body) { %{PUT POST}.include?(method) ? "This is the body." : nil }
|
1068
|
-
context "when a response body is present" do
|
1069
|
-
before { resource.body = "Hello, world!" }
|
1070
|
-
[
|
1071
|
-
["PUT", false],
|
1072
|
-
["POST", false],
|
1073
|
-
["DELETE", true],
|
1074
|
-
["POST", true],
|
1075
|
-
["PUT", true]
|
1076
|
-
].each do |m, e|
|
1077
|
-
it "should not reply with 204 (via exists:#{e}, #{m})" do
|
1078
|
-
@method = m
|
1079
|
-
resource.exist = e
|
1080
|
-
subject.run
|
1081
|
-
expect(response.code).to_not eq 204
|
1082
|
-
end
|
1083
|
-
end
|
1084
|
-
end
|
1085
|
-
context "when a response body is not present" do
|
1086
|
-
[
|
1087
|
-
["PUT", false],
|
1088
|
-
["POST", false],
|
1089
|
-
["DELETE", true],
|
1090
|
-
["POST", true],
|
1091
|
-
["PUT", true]
|
1092
|
-
].each do |m, e|
|
1093
|
-
it "should reply with 204 (via exists:#{e}, #{m})" do
|
1094
|
-
@method = m
|
1095
|
-
resource.exist = e
|
1096
|
-
subject.run
|
1097
|
-
expect(response.code).to eq 204
|
1098
|
-
end
|
1099
|
-
end
|
1100
|
-
end
|
1101
|
-
end
|
1102
|
-
|
1103
|
-
describe "On error" do
|
1104
|
-
context "handle_exception is inherited." do
|
1105
|
-
let :resource do
|
1106
|
-
resource_with do
|
1107
|
-
def to_html
|
1108
|
-
raise
|
1109
|
-
end
|
1110
|
-
end
|
1111
|
-
end
|
1112
|
-
|
1113
|
-
it "calls handle_exception" do
|
1114
|
-
expect(resource).to receive(:handle_exception).with instance_of(RuntimeError)
|
1115
|
-
subject.run
|
1116
|
-
end
|
1117
|
-
|
1118
|
-
it "sets the response code to 500" do
|
1119
|
-
subject.run
|
1120
|
-
expect(response.code).to eq 500
|
1121
|
-
end
|
1122
|
-
end
|
1123
|
-
|
1124
|
-
context "handle_exception is defined" do
|
1125
|
-
let :resource do
|
1126
|
-
resource_with do
|
1127
|
-
def handle_exception(e)
|
1128
|
-
response.body = "error"
|
1129
|
-
end
|
1130
|
-
|
1131
|
-
def to_html
|
1132
|
-
raise
|
1133
|
-
end
|
1134
|
-
end
|
1135
|
-
end
|
1136
|
-
|
1137
|
-
it "can define a response body" do
|
1138
|
-
subject.run
|
1139
|
-
expect(response.body).to eq "error"
|
1140
|
-
end
|
1141
|
-
|
1142
|
-
it "sets the response code to 500" do
|
1143
|
-
subject.run
|
1144
|
-
expect(response.code).to eq 500
|
1145
|
-
end
|
1146
|
-
end
|
1147
|
-
end
|
1148
|
-
end
|