webmachine 1.2.2 → 1.3.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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -11
- data/README.md +85 -89
- data/Rakefile +0 -1
- data/documentation/adapters.md +39 -0
- data/documentation/authentication-and-authorization.md +37 -0
- data/documentation/configurator.md +19 -0
- data/documentation/error-handling.md +86 -0
- data/documentation/examples.md +215 -0
- data/documentation/how-it-works.md +76 -0
- data/documentation/routes.md +97 -0
- data/documentation/validation.md +159 -0
- data/documentation/versioning-apis.md +74 -0
- data/documentation/visual-debugger.md +38 -0
- data/examples/application.rb +2 -2
- data/examples/debugger.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/lib/webmachine/adapter.rb +7 -13
- data/lib/webmachine/adapters.rb +1 -2
- data/lib/webmachine/adapters/httpkit.rb +74 -0
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -2
- data/lib/webmachine/adapters/rack.rb +37 -21
- data/lib/webmachine/adapters/reel.rb +21 -23
- data/lib/webmachine/adapters/webrick.rb +16 -16
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +3 -4
- data/lib/webmachine/constants.rb +75 -0
- data/lib/webmachine/decision/conneg.rb +12 -10
- data/lib/webmachine/decision/flow.rb +31 -21
- data/lib/webmachine/decision/fsm.rb +10 -18
- data/lib/webmachine/decision/helpers.rb +9 -37
- data/lib/webmachine/dispatcher.rb +13 -10
- data/lib/webmachine/dispatcher/route.rb +18 -8
- data/lib/webmachine/errors.rb +7 -1
- data/lib/webmachine/header_negotiation.rb +25 -0
- data/lib/webmachine/headers.rb +7 -2
- data/lib/webmachine/locale/en.yml +7 -5
- data/lib/webmachine/media_type.rb +10 -8
- data/lib/webmachine/request.rb +44 -15
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/resource/callbacks.rb +6 -4
- data/lib/webmachine/spec/IO_response.body +1 -0
- data/lib/webmachine/spec/adapter_lint.rb +70 -36
- data/lib/webmachine/spec/test_resource.rb +10 -4
- data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
- data/lib/webmachine/streaming/io_encoder.rb +6 -0
- data/lib/webmachine/trace.rb +1 -0
- data/lib/webmachine/trace/fsm.rb +20 -10
- data/lib/webmachine/trace/resource_proxy.rb +2 -0
- data/lib/webmachine/translation.rb +2 -1
- data/lib/webmachine/version.rb +3 -3
- data/memory_test.rb +37 -0
- data/spec/spec_helper.rb +9 -9
- data/spec/webmachine/adapter_spec.rb +14 -15
- data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
- data/spec/webmachine/adapters/rack_spec.rb +6 -6
- data/spec/webmachine/adapters/reel_spec.rb +15 -11
- data/spec/webmachine/adapters/webrick_spec.rb +2 -2
- data/spec/webmachine/application_spec.rb +18 -17
- data/spec/webmachine/chunked_body_spec.rb +3 -3
- data/spec/webmachine/configuration_spec.rb +5 -5
- data/spec/webmachine/cookie_spec.rb +13 -13
- data/spec/webmachine/decision/conneg_spec.rb +48 -42
- data/spec/webmachine/decision/falsey_spec.rb +4 -4
- data/spec/webmachine/decision/flow_spec.rb +194 -144
- data/spec/webmachine/decision/fsm_spec.rb +17 -17
- data/spec/webmachine/decision/helpers_spec.rb +20 -20
- data/spec/webmachine/dispatcher/route_spec.rb +73 -27
- data/spec/webmachine/dispatcher_spec.rb +34 -24
- data/spec/webmachine/errors_spec.rb +1 -1
- data/spec/webmachine/etags_spec.rb +19 -19
- data/spec/webmachine/events_spec.rb +6 -6
- data/spec/webmachine/headers_spec.rb +14 -14
- data/spec/webmachine/media_type_spec.rb +36 -36
- data/spec/webmachine/request_spec.rb +33 -33
- data/spec/webmachine/resource/authentication_spec.rb +6 -6
- data/spec/webmachine/response_spec.rb +12 -12
- data/spec/webmachine/trace/fsm_spec.rb +8 -8
- data/spec/webmachine/trace/resource_proxy_spec.rb +9 -9
- data/spec/webmachine/trace/trace_store_spec.rb +5 -5
- data/spec/webmachine/trace_spec.rb +3 -3
- data/webmachine.gemspec +2 -6
- metadata +48 -206
- data/lib/webmachine/adapters/hatetepe.rb +0 -108
- data/lib/webmachine/adapters/mongrel.rb +0 -127
- data/lib/webmachine/dispatcher/not_found_resource.rb +0 -5
- data/lib/webmachine/fiber18.rb +0 -88
- data/spec/webmachine/adapters/hatetepe_spec.rb +0 -60
- data/spec/webmachine/adapters/mongrel_spec.rb +0 -16
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Webmachine::Decision::Falsey do
|
4
|
-
specify { (described_class.=== false).
|
5
|
-
specify { (described_class.=== nil).
|
6
|
-
specify { (described_class.=== true).
|
7
|
-
specify { (described_class.=== []).
|
4
|
+
specify { expect(described_class.=== false).to be(true) }
|
5
|
+
specify { expect(described_class.=== nil).to be(true) }
|
6
|
+
specify { expect(described_class.=== true).to be(false) }
|
7
|
+
specify { expect(described_class.=== []).to be(false) }
|
8
8
|
end
|
@@ -16,7 +16,7 @@ describe Webmachine::Decision::Flow do
|
|
16
16
|
# ... [except 1xx or 5xx]
|
17
17
|
after(:each) do
|
18
18
|
unless response.code < 200 || response.code >= 500
|
19
|
-
response.headers.
|
19
|
+
expect(response.headers).to have_key('Date')
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -46,7 +46,7 @@ describe Webmachine::Decision::Flow do
|
|
46
46
|
it "should respond with 503 when the service is unavailable" do
|
47
47
|
resource.available = false
|
48
48
|
subject.run
|
49
|
-
response.code.
|
49
|
+
expect(response.code).to eq 503
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -59,7 +59,7 @@ describe Webmachine::Decision::Flow do
|
|
59
59
|
|
60
60
|
it "should respond with 501 when the method is unknown" do
|
61
61
|
subject.run
|
62
|
-
response.code.
|
62
|
+
expect(response.code).to eq 501
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -72,7 +72,7 @@ describe Webmachine::Decision::Flow do
|
|
72
72
|
|
73
73
|
it "should respond with 414 when the URI is too long" do
|
74
74
|
subject.run
|
75
|
-
response.code.
|
75
|
+
expect(response.code).to eq 414
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
@@ -85,8 +85,8 @@ describe Webmachine::Decision::Flow do
|
|
85
85
|
|
86
86
|
it "should respond with 405 when the method is not allowed" do
|
87
87
|
subject.run
|
88
|
-
response.code.
|
89
|
-
response.headers['Allow'].
|
88
|
+
expect(response.code).to eq 405
|
89
|
+
expect(response.headers['Allow']).to eq "POST"
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -95,7 +95,7 @@ describe Webmachine::Decision::Flow do
|
|
95
95
|
|
96
96
|
it "should respond with 400 when the request is malformed" do
|
97
97
|
subject.run
|
98
|
-
response.code.
|
98
|
+
expect(response.code).to eq 400
|
99
99
|
end
|
100
100
|
|
101
101
|
context "when the Content-MD5 header is present" do
|
@@ -112,31 +112,61 @@ describe Webmachine::Decision::Flow do
|
|
112
112
|
let(:body) { "This is the body." }
|
113
113
|
let(:headers) { Webmachine::Headers["Content-Type" => "text/plain"] }
|
114
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
|
+
|
115
145
|
it "should respond with 400 when the request body does not match the header" do
|
116
|
-
headers['Content-MD5'] = "thiswillnotmatchthehash"
|
146
|
+
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
117
147
|
subject.run
|
118
|
-
response.code.
|
148
|
+
expect(response.code).to eq 400
|
119
149
|
end
|
120
150
|
|
121
151
|
it "should respond with 400 when the resource invalidates the checksum" do
|
122
152
|
resource.validation = false
|
123
|
-
headers['Content-MD5'] = "thiswillnotmatchthehash"
|
153
|
+
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
124
154
|
subject.run
|
125
|
-
response.code.
|
155
|
+
expect(response.code).to eq 400
|
126
156
|
end
|
127
157
|
|
128
158
|
it "should not respond with 400 when the resource validates the checksum" do
|
129
159
|
resource.validation = true
|
130
|
-
headers['Content-MD5'] = "thiswillnotmatchthehash"
|
160
|
+
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
131
161
|
subject.run
|
132
|
-
response.code.
|
162
|
+
expect(response.code).to_not eq 400
|
133
163
|
end
|
134
164
|
|
135
165
|
it "should respond with the given code when the resource returns a code while validating" do
|
136
166
|
resource.validation = 500
|
137
|
-
headers['Content-MD5'] = "thiswillnotmatchthehash"
|
167
|
+
headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash")
|
138
168
|
subject.run
|
139
|
-
response.code.
|
169
|
+
expect(response.code).to eq 500
|
140
170
|
end
|
141
171
|
end
|
142
172
|
end
|
@@ -147,26 +177,26 @@ describe Webmachine::Decision::Flow do
|
|
147
177
|
it "should reply with 401 when the client is unauthorized" do
|
148
178
|
resource.auth = false
|
149
179
|
subject.run
|
150
|
-
response.code.
|
180
|
+
expect(response.code).to eq 401
|
151
181
|
end
|
152
182
|
|
153
183
|
it "should reply with 401 when the resource gives a challenge" do
|
154
184
|
resource.auth = "Basic realm=Webmachine"
|
155
185
|
subject.run
|
156
|
-
response.code.
|
157
|
-
response.headers['WWW-Authenticate'].
|
186
|
+
expect(response.code).to eq 401
|
187
|
+
expect(response.headers['WWW-Authenticate']).to eq "Basic realm=Webmachine"
|
158
188
|
end
|
159
189
|
|
160
190
|
it "should halt with the given code when the resource returns a status code" do
|
161
191
|
resource.auth = 400
|
162
192
|
subject.run
|
163
|
-
response.code.
|
193
|
+
expect(response.code).to eq 400
|
164
194
|
end
|
165
195
|
|
166
196
|
it "should not reply with 401 when the client is authorized" do
|
167
197
|
resource.auth = true
|
168
198
|
subject.run
|
169
|
-
response.code.
|
199
|
+
expect(response.code).to_not eq 401
|
170
200
|
end
|
171
201
|
end
|
172
202
|
|
@@ -176,19 +206,19 @@ describe Webmachine::Decision::Flow do
|
|
176
206
|
it "should reply with 403 when the request is forbidden" do
|
177
207
|
resource.forbid = true
|
178
208
|
subject.run
|
179
|
-
response.code.
|
209
|
+
expect(response.code).to eq 403
|
180
210
|
end
|
181
211
|
|
182
212
|
it "should not reply with 403 when the request is permitted" do
|
183
213
|
resource.forbid = false
|
184
214
|
subject.run
|
185
|
-
response.code.
|
215
|
+
expect(response.code).to_not eq 403
|
186
216
|
end
|
187
217
|
|
188
218
|
it "should halt with the given code when the resource returns a status code" do
|
189
219
|
resource.forbid = 400
|
190
220
|
subject.run
|
191
|
-
response.code.
|
221
|
+
expect(response.code).to eq 400
|
192
222
|
end
|
193
223
|
end
|
194
224
|
|
@@ -204,12 +234,12 @@ describe Webmachine::Decision::Flow do
|
|
204
234
|
it "should reply with 501 when an invalid Content-* header is present" do
|
205
235
|
headers['Content-Fail'] = "yup"
|
206
236
|
subject.run
|
207
|
-
response.code.
|
237
|
+
expect(response.code).to eq 501
|
208
238
|
end
|
209
239
|
|
210
240
|
it "should not reply with 501 when all Content-* headers are valid" do
|
211
241
|
subject.run
|
212
|
-
response.code.
|
242
|
+
expect(response.code).to_not eq 501
|
213
243
|
end
|
214
244
|
end
|
215
245
|
|
@@ -229,13 +259,13 @@ describe Webmachine::Decision::Flow do
|
|
229
259
|
it "should reply with 415 when the Content-Type is unknown" do
|
230
260
|
headers['Content-Type'] = "application/x-unknown-type"
|
231
261
|
subject.run
|
232
|
-
response.code.
|
262
|
+
expect(response.code).to eq 415
|
233
263
|
end
|
234
264
|
|
235
265
|
it "should not reply with 415 when the Content-Type is known" do
|
236
266
|
headers['Content-Type'] = "text/plain"
|
237
267
|
subject.run
|
238
|
-
response.code.
|
268
|
+
expect(response.code).to_not eq 415
|
239
269
|
end
|
240
270
|
end
|
241
271
|
|
@@ -254,7 +284,7 @@ describe Webmachine::Decision::Flow do
|
|
254
284
|
let(:body) { "Big" * 100 }
|
255
285
|
it "should reply with 413" do
|
256
286
|
subject.run
|
257
|
-
response.code.
|
287
|
+
expect(response.code).to eq 413
|
258
288
|
end
|
259
289
|
end
|
260
290
|
|
@@ -263,7 +293,7 @@ describe Webmachine::Decision::Flow do
|
|
263
293
|
|
264
294
|
it "should not reply with 413" do
|
265
295
|
subject.run
|
266
|
-
response.code.
|
296
|
+
expect(response.code).to_not eq 413
|
267
297
|
end
|
268
298
|
end
|
269
299
|
end
|
@@ -273,7 +303,7 @@ describe Webmachine::Decision::Flow do
|
|
273
303
|
let(:resource){ resource_with { def allowed_methods; %w[GET HEAD OPTIONS]; end } }
|
274
304
|
it "should reply with 200 when the request method is OPTIONS" do
|
275
305
|
subject.run
|
276
|
-
response.code.
|
306
|
+
expect(response.code).to eq 200
|
277
307
|
end
|
278
308
|
end
|
279
309
|
|
@@ -283,23 +313,23 @@ describe Webmachine::Decision::Flow do
|
|
283
313
|
it "should reply with 406 when the type is unacceptable" do
|
284
314
|
headers['Accept'] = "text/plain"
|
285
315
|
subject.run
|
286
|
-
response.code.
|
316
|
+
expect(response.code).to eq 406
|
287
317
|
end
|
288
318
|
|
289
319
|
it "should not reply with 406 when the type is acceptable" do
|
290
320
|
headers['Accept'] = "text/*"
|
291
321
|
subject.run
|
292
|
-
response.code.
|
293
|
-
response.headers['Content-Type'].
|
322
|
+
expect(response.code).to_not eq 406
|
323
|
+
expect(response.headers['Content-Type']).to eq "text/html"
|
294
324
|
end
|
295
325
|
end
|
296
326
|
|
297
327
|
context "when the Accept header does not exist" do
|
298
328
|
it "should not negotiate a media type" do
|
299
|
-
headers['Accept'].
|
300
|
-
subject.
|
329
|
+
expect(headers['Accept']).to be_nil
|
330
|
+
expect(subject).to_not receive(:c4)
|
301
331
|
subject.run
|
302
|
-
response.headers['Content-Type'].
|
332
|
+
expect(response.headers['Content-Type']).to eq 'text/html'
|
303
333
|
end
|
304
334
|
end
|
305
335
|
end
|
@@ -310,25 +340,25 @@ describe Webmachine::Decision::Flow do
|
|
310
340
|
it "should reply with 406 when the language is unacceptable" do
|
311
341
|
headers['Accept-Language'] = "es, de"
|
312
342
|
subject.run
|
313
|
-
response.code.
|
343
|
+
expect(response.code).to eq 406
|
314
344
|
end
|
315
345
|
|
316
346
|
it "should not reply with 406 when the language is acceptable" do
|
317
347
|
headers['Accept-Language'] = "en-GB, en;q=0.7"
|
318
348
|
subject.run
|
319
|
-
response.code.
|
320
|
-
response.headers['Content-Language'].
|
321
|
-
resource.instance_variable_get(:@language).
|
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'
|
322
352
|
end
|
323
353
|
end
|
324
354
|
|
325
355
|
context "when the Accept-Language header is absent" do
|
326
356
|
it "should not negotiate the language" do
|
327
|
-
headers['Accept-Language'].
|
328
|
-
subject.
|
357
|
+
expect(headers['Accept-Language']).to be_nil
|
358
|
+
expect(subject).to_not receive(:d5)
|
329
359
|
subject.run
|
330
|
-
response.headers['Content-Language'].
|
331
|
-
resource.instance_variable_get(:@language).
|
360
|
+
expect(response.headers['Content-Language']).to eq 'en-US'
|
361
|
+
expect(resource.instance_variable_get(:@language)).to eq 'en-US'
|
332
362
|
end
|
333
363
|
end
|
334
364
|
end
|
@@ -348,23 +378,23 @@ describe Webmachine::Decision::Flow do
|
|
348
378
|
it "should reply with 406 when the charset is unacceptable" do
|
349
379
|
headers['Accept-Charset'] = "utf-16"
|
350
380
|
subject.run
|
351
|
-
response.code.
|
381
|
+
expect(response.code).to eq 406
|
352
382
|
end
|
353
383
|
|
354
384
|
it "should not reply with 406 when the charset is acceptable" do
|
355
385
|
headers['Accept-Charset'] = "iso8859-1"
|
356
386
|
subject.run
|
357
|
-
response.code.
|
358
|
-
response.headers['Content-Type'].
|
387
|
+
expect(response.code).to_not eq 406
|
388
|
+
expect(response.headers['Content-Type']).to eq "text/html;charset=iso8859-1"
|
359
389
|
end
|
360
390
|
end
|
361
391
|
|
362
392
|
context "when the Accept-Charset header is absent" do
|
363
393
|
it "should not negotiate the language" do
|
364
|
-
headers['Accept-Charset'].
|
365
|
-
subject.
|
394
|
+
expect(headers['Accept-Charset']).to be_nil
|
395
|
+
expect(subject).to_not receive(:e6)
|
366
396
|
subject.run
|
367
|
-
response.headers['Content-Type'].
|
397
|
+
expect(response.headers['Content-Type']).to eq 'text/html;charset=iso8859-1'
|
368
398
|
end
|
369
399
|
end
|
370
400
|
end
|
@@ -382,27 +412,27 @@ describe Webmachine::Decision::Flow do
|
|
382
412
|
it "should reply with 406 if the encoding is unacceptable" do
|
383
413
|
headers['Accept-Encoding'] = 'deflate, identity;q=0.0'
|
384
414
|
subject.run
|
385
|
-
response.code.
|
415
|
+
expect(response.code).to eq 406
|
386
416
|
end
|
387
417
|
|
388
418
|
it "should not reply with 406 if the encoding is acceptable" do
|
389
419
|
headers['Accept-Encoding'] = 'gzip, deflate'
|
390
420
|
subject.run
|
391
|
-
response.code.
|
392
|
-
response.headers['Content-Encoding'].
|
421
|
+
expect(response.code).to_not eq 406
|
422
|
+
expect(response.headers['Content-Encoding']).to eq 'gzip'
|
393
423
|
# It should be compressed
|
394
|
-
response.body.
|
424
|
+
expect(response.body).to_not eq 'test resource'
|
395
425
|
end
|
396
426
|
end
|
397
427
|
|
398
428
|
context "when the Accept-Encoding header is not present" do
|
399
429
|
it "should not negotiate an encoding" do
|
400
|
-
headers['Accept-Encoding'].
|
401
|
-
subject.
|
430
|
+
expect(headers['Accept-Encoding']).to be_nil
|
431
|
+
expect(subject).to_not receive(:f7)
|
402
432
|
subject.run
|
403
|
-
response.code.
|
433
|
+
expect(response.code).to_not eq 406
|
404
434
|
# It should not be compressed
|
405
|
-
response.body.
|
435
|
+
expect(response.body).to eq 'test resource'
|
406
436
|
end
|
407
437
|
end
|
408
438
|
end
|
@@ -412,28 +442,28 @@ describe Webmachine::Decision::Flow do
|
|
412
442
|
|
413
443
|
it "should not enter conditional requests if missing (and eventually reply with 404)" do
|
414
444
|
resource.exist = false
|
415
|
-
subject.
|
445
|
+
expect(subject).to_not receive(:g8)
|
416
446
|
subject.run
|
417
|
-
response.code.
|
447
|
+
expect(response.code).to eq 404
|
418
448
|
end
|
419
449
|
|
420
450
|
it "should not reply with 404 if it does exist" do
|
421
451
|
resource.exist = true
|
422
|
-
subject.
|
452
|
+
expect(subject).to_not receive(:h7)
|
423
453
|
subject.run
|
424
|
-
response.code.
|
454
|
+
expect(response.code).to_not eq 404
|
425
455
|
end
|
426
456
|
|
427
457
|
it "should not reply with 404 for truthy non-booleans" do
|
428
458
|
resource.exist = []
|
429
459
|
subject.run
|
430
|
-
response.code.
|
460
|
+
expect(response.code).to_not eq 404
|
431
461
|
end
|
432
462
|
|
433
463
|
it "should reply with 404 for nil" do
|
434
464
|
resource.exist = nil
|
435
465
|
subject.run
|
436
|
-
response.code.
|
466
|
+
expect(response.code).to eq 404
|
437
467
|
end
|
438
468
|
end
|
439
469
|
|
@@ -441,26 +471,26 @@ describe Webmachine::Decision::Flow do
|
|
441
471
|
describe "#g8, #g9, #g10 (ETag match)" do
|
442
472
|
let(:resource) { resource_with { def generate_etag; "etag"; end } }
|
443
473
|
it "should skip ETag matching when If-Match is missing" do
|
444
|
-
headers['If-Match'].
|
445
|
-
subject.
|
446
|
-
subject.
|
474
|
+
expect(headers['If-Match']).to be_nil
|
475
|
+
expect(subject).to_not receive(:g9)
|
476
|
+
expect(subject).to_not receive(:g11)
|
447
477
|
subject.run
|
448
|
-
response.code.
|
478
|
+
expect(response.code).to_not eq 412
|
449
479
|
end
|
450
480
|
it "should not reply with 304 when If-Match is *" do
|
451
481
|
headers['If-Match'] = "*"
|
452
482
|
subject.run
|
453
|
-
response.code.
|
483
|
+
expect(response.code).to_not eq 412
|
454
484
|
end
|
455
485
|
it "should reply with 412 if the ETag is not in If-Match" do
|
456
486
|
headers['If-Match'] = '"notetag"'
|
457
487
|
subject.run
|
458
|
-
response.code.
|
488
|
+
expect(response.code).to eq 412
|
459
489
|
end
|
460
490
|
it "should not reply with 412 if the ETag is in If-Match" do
|
461
491
|
headers['If-Match'] = '"etag"'
|
462
492
|
subject.run
|
463
|
-
response.code.
|
493
|
+
expect(response.code).to_not eq 412
|
464
494
|
end
|
465
495
|
end
|
466
496
|
|
@@ -469,30 +499,30 @@ describe Webmachine::Decision::Flow do
|
|
469
499
|
before { @now = resource.now = Time.now }
|
470
500
|
|
471
501
|
it "should skip LM matching if IUMS is missing" do
|
472
|
-
headers['If-Unmodified-Since'].
|
473
|
-
subject.
|
474
|
-
subject.
|
502
|
+
expect(headers['If-Unmodified-Since']).to be_nil
|
503
|
+
expect(subject).to_not receive(:h11)
|
504
|
+
expect(subject).to_not receive(:h12)
|
475
505
|
subject.run
|
476
|
-
response.code.
|
506
|
+
expect(response.code).to_not eq 412
|
477
507
|
end
|
478
508
|
|
479
509
|
it "should skip LM matching if IUMS is an invalid date" do
|
480
510
|
headers['If-Unmodified-Since'] = "garbage"
|
481
|
-
subject.
|
511
|
+
expect(subject).to_not receive(:h12)
|
482
512
|
subject.run
|
483
|
-
response.code.
|
513
|
+
expect(response.code).to_not eq 412
|
484
514
|
end
|
485
515
|
|
486
516
|
it "should not reply with 412 if LM is <= IUMS" do
|
487
517
|
headers['If-Unmodified-Since'] = (@now + 100).httpdate
|
488
518
|
subject.run
|
489
|
-
response.code.
|
519
|
+
expect(response.code).to_not eq 412
|
490
520
|
end
|
491
521
|
|
492
522
|
it "should reply with 412 if LM is > IUMS" do
|
493
523
|
headers['If-Unmodified-Since'] = (@now - 100).httpdate
|
494
524
|
subject.run
|
495
|
-
response.code.
|
525
|
+
expect(response.code).to eq 412
|
496
526
|
end
|
497
527
|
end
|
498
528
|
|
@@ -506,18 +536,18 @@ describe Webmachine::Decision::Flow do
|
|
506
536
|
end
|
507
537
|
|
508
538
|
it "should skip ETag matching if If-None-Match is missing" do
|
509
|
-
headers['If-None-Match'].
|
539
|
+
expect(headers['If-None-Match']).to be_nil
|
510
540
|
%w{i13 k13 j18}.each do |m|
|
511
|
-
subject.
|
541
|
+
expect(subject).to_not receive(m.to_sym)
|
512
542
|
end
|
513
543
|
subject.run
|
514
|
-
[304, 412].
|
544
|
+
expect([304, 412]).to_not include(response.code)
|
515
545
|
end
|
516
546
|
|
517
547
|
it "should not reply with 412 or 304 if the ETag is not in If-None-Match" do
|
518
548
|
headers['If-None-Match'] = '"notetag"'
|
519
549
|
subject.run
|
520
|
-
[304, 412].
|
550
|
+
expect([304, 412]).to_not include(response.code)
|
521
551
|
end
|
522
552
|
|
523
553
|
context "when the method is GET or HEAD" do
|
@@ -528,7 +558,7 @@ describe Webmachine::Decision::Flow do
|
|
528
558
|
it "should reply with 304 when the ETag is in If-None-Match" do
|
529
559
|
headers['If-None-Match'] = '"etag", "foobar"'
|
530
560
|
end
|
531
|
-
after { subject.run; response.code.
|
561
|
+
after { subject.run; expect(response.code).to eq 304 }
|
532
562
|
end
|
533
563
|
|
534
564
|
context "when the method is not GET or HEAD" do
|
@@ -543,7 +573,27 @@ describe Webmachine::Decision::Flow do
|
|
543
573
|
it "should reply with 412 when the ETag is in If-None-Match" do
|
544
574
|
headers['If-None-Match'] = '"etag"'
|
545
575
|
end
|
546
|
-
after { subject.run; response.code.
|
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
|
547
597
|
end
|
548
598
|
end
|
549
599
|
|
@@ -551,41 +601,41 @@ describe Webmachine::Decision::Flow do
|
|
551
601
|
let(:resource) { resource_with { attr_accessor :now; def last_modified; @now; end } }
|
552
602
|
before { @now = resource.now = Time.now }
|
553
603
|
it "should skip LM matching if IMS is missing" do
|
554
|
-
headers['If-Modified-Since'].
|
604
|
+
expect(headers['If-Modified-Since']).to be_nil
|
555
605
|
%w{l14 l15 l17}.each do |m|
|
556
|
-
subject.
|
606
|
+
expect(subject).to_not receive(m.to_sym)
|
557
607
|
end
|
558
608
|
subject.run
|
559
|
-
response.code.
|
609
|
+
expect(response.code).to_not eq 304
|
560
610
|
end
|
561
611
|
|
562
612
|
it "should skip LM matching if IMS is an invalid date" do
|
563
613
|
headers['If-Modified-Since'] = "garbage"
|
564
614
|
%w{l15 l17}.each do |m|
|
565
|
-
subject.
|
615
|
+
expect(subject).to_not receive(m.to_sym)
|
566
616
|
end
|
567
617
|
subject.run
|
568
|
-
response.code.
|
618
|
+
expect(response.code).to_not eq 304
|
569
619
|
end
|
570
620
|
|
571
621
|
it "should skip LM matching if IMS is later than current time" do
|
572
622
|
headers['If-Modified-Since'] = (@now + 1000).httpdate
|
573
|
-
subject.
|
623
|
+
expect(subject).to_not receive(:l17)
|
574
624
|
subject.run
|
575
|
-
response.code.
|
625
|
+
expect(response.code).to_not eq 304
|
576
626
|
end
|
577
627
|
|
578
628
|
it "should reply with 304 if LM is <= IMS" do
|
579
629
|
headers['If-Modified-Since'] = (@now - 1).httpdate
|
580
630
|
resource.now = @now - 1000
|
581
631
|
subject.run
|
582
|
-
response.code.
|
632
|
+
expect(response.code).to eq 304
|
583
633
|
end
|
584
634
|
|
585
635
|
it "should not reply with 304 if LM is > IMS" do
|
586
636
|
headers['If-Modified-Since'] = (@now - 1000).httpdate
|
587
637
|
subject.run
|
588
|
-
response.code.
|
638
|
+
expect(response.code).to_not eq 304
|
589
639
|
end
|
590
640
|
end
|
591
641
|
|
@@ -595,13 +645,13 @@ describe Webmachine::Decision::Flow do
|
|
595
645
|
it "should reply with 412 when the If-Match header is *" do
|
596
646
|
headers['If-Match'] = '"*"'
|
597
647
|
subject.run
|
598
|
-
response.code.
|
648
|
+
expect(response.code).to eq 412
|
599
649
|
end
|
600
650
|
|
601
651
|
it "should not reply with 412 when the If-Match header is missing or not *" do
|
602
652
|
headers['If-Match'] = ['"etag"', nil][rand(1)]
|
603
653
|
subject.run
|
604
|
-
response.code.
|
654
|
+
expect(response.code).to_not eq 412
|
605
655
|
end
|
606
656
|
end
|
607
657
|
|
@@ -619,22 +669,22 @@ describe Webmachine::Decision::Flow do
|
|
619
669
|
let(:method){ "PUT" }
|
620
670
|
|
621
671
|
it "should not reach state k7" do
|
622
|
-
subject.
|
672
|
+
expect(subject).to_not receive(:k7)
|
623
673
|
subject.run
|
624
674
|
end
|
625
675
|
|
626
|
-
after { [404, 410, 303].
|
676
|
+
after { expect([404, 410, 303]).to_not include(response.code) }
|
627
677
|
end
|
628
678
|
|
629
679
|
context "when the method is not PUT" do
|
630
680
|
let(:method){ %W{GET HEAD POST DELETE}[rand(4)] }
|
631
681
|
|
632
682
|
it "should not reach state i4" do
|
633
|
-
subject.
|
683
|
+
expect(subject).to_not receive(:i4)
|
634
684
|
subject.run
|
635
685
|
end
|
636
686
|
|
637
|
-
after { response.code.
|
687
|
+
after { expect(response.code).to_not eq 409 }
|
638
688
|
end
|
639
689
|
end
|
640
690
|
|
@@ -653,14 +703,14 @@ describe Webmachine::Decision::Flow do
|
|
653
703
|
it "should reply with 301 when the resource has moved" do
|
654
704
|
resource.location = URI.parse("http://localhost:8098/newuri")
|
655
705
|
subject.run
|
656
|
-
response.code.
|
657
|
-
response.headers['Location'].
|
706
|
+
expect(response.code).to eq 301
|
707
|
+
expect(response.headers['Location']).to eq resource.location.to_s
|
658
708
|
end
|
659
709
|
|
660
710
|
it "should not reply with 301 when resource has not moved" do
|
661
711
|
resource.location = false
|
662
712
|
subject.run
|
663
|
-
response.code.
|
713
|
+
expect(response.code).to_not eq 301
|
664
714
|
end
|
665
715
|
end
|
666
716
|
|
@@ -682,13 +732,13 @@ describe Webmachine::Decision::Flow do
|
|
682
732
|
it "should reply with 301 when the resource has moved permanently" do
|
683
733
|
uri = resource.moved_perm = URI.parse("http://www.google.com/")
|
684
734
|
subject.run
|
685
|
-
response.code.
|
686
|
-
response.headers['Location'].
|
735
|
+
expect(response.code).to eq 301
|
736
|
+
expect(response.headers['Location']).to eq uri.to_s
|
687
737
|
end
|
688
738
|
it "should not reply with 301 when the resource has not moved permanently" do
|
689
739
|
resource.moved_perm = false
|
690
740
|
subject.run
|
691
|
-
response.code.
|
741
|
+
expect(response.code).to_not eq 301
|
692
742
|
end
|
693
743
|
end
|
694
744
|
|
@@ -697,34 +747,34 @@ describe Webmachine::Decision::Flow do
|
|
697
747
|
it "should reply with 307 when the resource has moved temporarily" do
|
698
748
|
uri = resource.moved_temp = URI.parse("http://www.basho.com/")
|
699
749
|
subject.run
|
700
|
-
response.code.
|
701
|
-
response.headers['Location'].
|
750
|
+
expect(response.code).to eq 307
|
751
|
+
expect(response.headers['Location']).to eq uri.to_s
|
702
752
|
end
|
703
753
|
it "should not reply with 307 when the resource has not moved temporarily" do
|
704
754
|
resource.moved_temp = false
|
705
755
|
subject.run
|
706
|
-
response.code.
|
756
|
+
expect(response.code).to_not eq 307
|
707
757
|
end
|
708
758
|
end
|
709
759
|
|
710
760
|
describe "#m5 (POST?), #n5 (POST to missing resource?)" do
|
711
761
|
before { resource.moved_perm = resource.moved_temp = false }
|
712
762
|
it "should reply with 410 when the method is not POST" do
|
713
|
-
method.
|
763
|
+
expect(method).to_not eq "POST"
|
714
764
|
subject.run
|
715
|
-
response.code.
|
765
|
+
expect(response.code).to eq 410
|
716
766
|
end
|
717
767
|
it "should reply with 410 when the resource disallows missing POSTs" do
|
718
768
|
@method = "POST"
|
719
769
|
resource.allow_missing = false
|
720
770
|
subject.run
|
721
|
-
response.code.
|
771
|
+
expect(response.code).to eq 410
|
722
772
|
end
|
723
773
|
it "should not reply with 410 when the resource allows missing POSTs" do
|
724
774
|
@method = "POST"
|
725
775
|
resource.allow_missing = true
|
726
776
|
subject.run
|
727
|
-
response.code.
|
777
|
+
expect(response.code).to eq 410
|
728
778
|
end
|
729
779
|
end
|
730
780
|
end
|
@@ -741,21 +791,21 @@ describe Webmachine::Decision::Flow do
|
|
741
791
|
end
|
742
792
|
let(:method){ @method || "GET" }
|
743
793
|
it "should reply with 404 when the method is not POST" do
|
744
|
-
method.
|
794
|
+
expect(method).to_not eq "POST"
|
745
795
|
subject.run
|
746
|
-
response.code.
|
796
|
+
expect(response.code).to eq 404
|
747
797
|
end
|
748
798
|
it "should reply with 404 when the resource disallows missing POSTs" do
|
749
799
|
@method = "POST"
|
750
800
|
resource.allow_missing = false
|
751
801
|
subject.run
|
752
|
-
response.code.
|
802
|
+
expect(response.code).to eq 404
|
753
803
|
end
|
754
804
|
it "should not reply with 404 when the resource allows missing POSTs" do
|
755
805
|
@method = "POST"
|
756
806
|
resource.allow_missing = true
|
757
807
|
subject.run
|
758
|
-
response.code.
|
808
|
+
expect(response.code).to_not eq 404
|
759
809
|
end
|
760
810
|
end
|
761
811
|
|
@@ -771,12 +821,12 @@ describe Webmachine::Decision::Flow do
|
|
771
821
|
it "should reply with 409 if the resource is in conflict" do
|
772
822
|
resource.conflict = true
|
773
823
|
subject.run
|
774
|
-
response.code.
|
824
|
+
expect(response.code).to eq 409
|
775
825
|
end
|
776
826
|
it "should not reply with 409 if the resource is in conflict" do
|
777
827
|
resource.conflict = false
|
778
828
|
subject.run
|
779
|
-
response.code.
|
829
|
+
expect(response.code).to_not eq 409
|
780
830
|
end
|
781
831
|
end
|
782
832
|
|
@@ -801,14 +851,14 @@ describe Webmachine::Decision::Flow do
|
|
801
851
|
it "should reply with 303 if the resource redirected" do
|
802
852
|
resource.new_loc = URI.parse("/foo/bar")
|
803
853
|
subject.run
|
804
|
-
response.code.
|
805
|
-
response.headers['Location'].
|
854
|
+
expect(response.code).to eq 303
|
855
|
+
expect(response.headers['Location']).to eq "/foo/bar"
|
806
856
|
end
|
807
857
|
|
808
858
|
it "should not reply with 303 if the resource did not redirect" do
|
809
859
|
resource.new_loc = nil
|
810
860
|
subject.run
|
811
|
-
response.code.
|
861
|
+
expect(response.code).to_not eq 303
|
812
862
|
end
|
813
863
|
end
|
814
864
|
end
|
@@ -845,13 +895,13 @@ describe Webmachine::Decision::Flow do
|
|
845
895
|
resource.exist = e
|
846
896
|
resource.new_loc = "http://ruby-doc.org/"
|
847
897
|
subject.run
|
848
|
-
response.code.
|
898
|
+
expect(response.code).to eq 201
|
849
899
|
end
|
850
900
|
it "should not reply with 201 when the Location header has been set" do
|
851
901
|
resource.exist = e
|
852
902
|
subject.run
|
853
|
-
response.headers['Location'].
|
854
|
-
response.code.
|
903
|
+
expect(response.headers['Location']).to be_nil
|
904
|
+
expect(response.code).to_not eq 201
|
855
905
|
end
|
856
906
|
end
|
857
907
|
end
|
@@ -866,19 +916,19 @@ describe Webmachine::Decision::Flow do
|
|
866
916
|
resource.new_loc = created = "/foo/bar/baz"
|
867
917
|
resource.create = true
|
868
918
|
subject.run
|
869
|
-
response.code.
|
870
|
-
response.headers['Location'].
|
919
|
+
expect(response.code).to eq 201
|
920
|
+
expect(response.headers['Location']).to eq created
|
871
921
|
end
|
872
922
|
it "should reply with 500 when post_is_create is true and create_path returns nil" do
|
873
923
|
resource.create = true
|
874
924
|
subject.run
|
875
|
-
response.code.
|
876
|
-
response.error.
|
925
|
+
expect(response.code).to eq 500
|
926
|
+
expect(response.error).to_not be_nil
|
877
927
|
end
|
878
928
|
it "should not reply with 201 when post_is_create is false" do
|
879
929
|
resource.create = false
|
880
930
|
subject.run
|
881
|
-
response.code.
|
931
|
+
expect(response.code).to_not eq 201
|
882
932
|
end
|
883
933
|
end
|
884
934
|
end
|
@@ -897,12 +947,12 @@ describe Webmachine::Decision::Flow do
|
|
897
947
|
it "should reply with 409 if the resource is in conflict" do
|
898
948
|
resource.conflict = true
|
899
949
|
subject.run
|
900
|
-
response.code.
|
950
|
+
expect(response.code).to eq 409
|
901
951
|
end
|
902
952
|
it "should not reply with 409 if the resource is in conflict" do
|
903
953
|
resource.conflict = false
|
904
954
|
subject.run
|
905
|
-
response.code.
|
955
|
+
expect(response.code).to_not eq 409
|
906
956
|
end
|
907
957
|
end
|
908
958
|
|
@@ -919,23 +969,23 @@ describe Webmachine::Decision::Flow do
|
|
919
969
|
it "should not reply with 202 if the method is not DELETE" do
|
920
970
|
@method = "GET"
|
921
971
|
subject.run
|
922
|
-
response.code.
|
972
|
+
expect(response.code).to_not eq 202
|
923
973
|
end
|
924
974
|
it "should reply with 500 if the DELETE fails" do
|
925
975
|
resource.deleted = false
|
926
976
|
subject.run
|
927
|
-
response.code.
|
977
|
+
expect(response.code).to eq 500
|
928
978
|
end
|
929
979
|
it "should reply with 202 if the DELETE succeeds but is not complete" do
|
930
980
|
resource.deleted = true
|
931
981
|
resource.completed = false
|
932
982
|
subject.run
|
933
|
-
response.code.
|
983
|
+
expect(response.code).to eq 202
|
934
984
|
end
|
935
985
|
it "should not reply with 202 if the DELETE succeeds and completes" do
|
936
986
|
resource.completed = resource.deleted = true
|
937
987
|
subject.run
|
938
|
-
response.code.
|
988
|
+
expect(response.code).to_not eq 202
|
939
989
|
end
|
940
990
|
end
|
941
991
|
|
@@ -980,13 +1030,13 @@ describe Webmachine::Decision::Flow do
|
|
980
1030
|
resource.multiple = false
|
981
1031
|
subject.run
|
982
1032
|
puts response.error if response.code == 500
|
983
|
-
response.code.
|
1033
|
+
expect(response.code).to eq 200
|
984
1034
|
end
|
985
1035
|
it "should reply with 300 if there are multiple representations" do
|
986
1036
|
resource.multiple = true
|
987
1037
|
subject.run
|
988
1038
|
puts response.error if response.code == 500
|
989
|
-
response.code.
|
1039
|
+
expect(response.code).to eq 300
|
990
1040
|
end
|
991
1041
|
end
|
992
1042
|
end
|
@@ -1028,7 +1078,7 @@ describe Webmachine::Decision::Flow do
|
|
1028
1078
|
@method = m
|
1029
1079
|
resource.exist = e
|
1030
1080
|
subject.run
|
1031
|
-
response.code.
|
1081
|
+
expect(response.code).to_not eq 204
|
1032
1082
|
end
|
1033
1083
|
end
|
1034
1084
|
end
|
@@ -1044,7 +1094,7 @@ describe Webmachine::Decision::Flow do
|
|
1044
1094
|
@method = m
|
1045
1095
|
resource.exist = e
|
1046
1096
|
subject.run
|
1047
|
-
response.code.
|
1097
|
+
expect(response.code).to eq 204
|
1048
1098
|
end
|
1049
1099
|
end
|
1050
1100
|
end
|
@@ -1061,13 +1111,13 @@ describe Webmachine::Decision::Flow do
|
|
1061
1111
|
end
|
1062
1112
|
|
1063
1113
|
it "calls handle_exception" do
|
1064
|
-
resource.
|
1114
|
+
expect(resource).to receive(:handle_exception).with instance_of(RuntimeError)
|
1065
1115
|
subject.run
|
1066
1116
|
end
|
1067
1117
|
|
1068
1118
|
it "sets the response code to 500" do
|
1069
1119
|
subject.run
|
1070
|
-
response.code.
|
1120
|
+
expect(response.code).to eq 500
|
1071
1121
|
end
|
1072
1122
|
end
|
1073
1123
|
|
@@ -1086,12 +1136,12 @@ describe Webmachine::Decision::Flow do
|
|
1086
1136
|
|
1087
1137
|
it "can define a response body" do
|
1088
1138
|
subject.run
|
1089
|
-
response.body.
|
1139
|
+
expect(response.body).to eq "error"
|
1090
1140
|
end
|
1091
1141
|
|
1092
1142
|
it "sets the response code to 500" do
|
1093
1143
|
subject.run
|
1094
|
-
response.code.
|
1144
|
+
expect(response.code).to eq 500
|
1095
1145
|
end
|
1096
1146
|
end
|
1097
1147
|
end
|