roda 2.2.0 → 2.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 +4 -4
- data/CHANGELOG +34 -0
- data/Rakefile +22 -46
- data/doc/release_notes/2.3.0.txt +109 -0
- data/lib/roda/plugins/assets.rb +2 -1
- data/lib/roda/plugins/caching.rb +1 -1
- data/lib/roda/plugins/chunked.rb +1 -1
- data/lib/roda/plugins/error_email.rb +1 -1
- data/lib/roda/plugins/head.rb +6 -0
- data/lib/roda/plugins/heartbeat.rb +40 -0
- data/lib/roda/plugins/json.rb +23 -3
- data/lib/roda/plugins/json_parser.rb +72 -0
- data/lib/roda/plugins/mailer.rb +22 -5
- data/lib/roda/plugins/named_templates.rb +2 -2
- data/lib/roda/plugins/path_rewriter.rb +82 -0
- data/lib/roda/plugins/precompile_templates.rb +87 -0
- data/lib/roda/plugins/render.rb +111 -43
- data/lib/roda/plugins/render_each.rb +1 -1
- data/lib/roda/plugins/shared_vars.rb +1 -1
- data/lib/roda/plugins/view_options.rb +28 -3
- data/lib/roda/version.rb +1 -1
- data/spec/composition_spec.rb +3 -3
- data/spec/env_spec.rb +1 -1
- data/spec/freeze_spec.rb +6 -6
- data/spec/integration_spec.rb +16 -15
- data/spec/matchers_spec.rb +110 -110
- data/spec/opts_spec.rb +8 -8
- data/spec/plugin/_erubis_escaping_spec.rb +34 -3
- data/spec/plugin/all_verbs_spec.rb +8 -8
- data/spec/plugin/assets_spec.rb +164 -150
- data/spec/plugin/backtracking_array_spec.rb +18 -18
- data/spec/plugin/caching_spec.rb +70 -70
- data/spec/plugin/chunked_spec.rb +38 -38
- data/spec/plugin/class_level_routing_spec.rb +78 -78
- data/spec/plugin/content_for_spec.rb +2 -2
- data/spec/plugin/cookies_spec.rb +4 -4
- data/spec/plugin/csrf_spec.rb +8 -8
- data/spec/plugin/default_headers_spec.rb +6 -6
- data/spec/plugin/delay_build_spec.rb +7 -6
- data/spec/plugin/delegate_spec.rb +2 -2
- data/spec/plugin/delete_empty_headers_spec.rb +2 -2
- data/spec/plugin/drop_body_spec.rb +6 -6
- data/spec/plugin/empty_root_spec.rb +3 -3
- data/spec/plugin/environments_spec.rb +7 -7
- data/spec/plugin/error_email_spec.rb +23 -23
- data/spec/plugin/error_handler_spec.rb +14 -14
- data/spec/plugin/flash_spec.rb +30 -29
- data/spec/plugin/h_spec.rb +1 -1
- data/spec/plugin/halt_spec.rb +16 -16
- data/spec/plugin/hash_matcher_spec.rb +5 -5
- data/spec/plugin/head_spec.rb +10 -10
- data/spec/plugin/header_matchers_spec.rb +13 -13
- data/spec/plugin/heartbeat_spec.rb +74 -0
- data/spec/plugin/hooks_spec.rb +20 -20
- data/spec/plugin/indifferent_params_spec.rb +1 -1
- data/spec/plugin/json_parser_spec.rb +72 -0
- data/spec/plugin/json_spec.rb +22 -9
- data/spec/plugin/mailer_spec.rb +72 -58
- data/spec/plugin/match_affix_spec.rb +2 -2
- data/spec/plugin/middleware_spec.rb +7 -7
- data/spec/plugin/module_include_spec.rb +4 -4
- data/spec/plugin/multi_route_spec.rb +66 -66
- data/spec/plugin/multi_run_spec.rb +21 -21
- data/spec/plugin/named_templates_spec.rb +6 -6
- data/spec/plugin/not_allowed_spec.rb +17 -17
- data/spec/plugin/not_found_spec.rb +14 -14
- data/spec/plugin/padrino_render_spec.rb +2 -2
- data/spec/plugin/param_matchers_spec.rb +6 -6
- data/spec/plugin/partials_spec.rb +3 -3
- data/spec/plugin/pass_spec.rb +7 -7
- data/spec/plugin/path_matchers_spec.rb +6 -6
- data/spec/plugin/path_rewriter_spec.rb +37 -0
- data/spec/plugin/path_spec.rb +41 -40
- data/spec/plugin/per_thread_caching_spec.rb +6 -6
- data/spec/plugin/precompile_templates_spec.rb +74 -0
- data/spec/plugin/render_each_spec.rb +4 -4
- data/spec/plugin/render_spec.rb +179 -76
- data/spec/plugin/shared_vars_spec.rb +4 -4
- data/spec/plugin/sinatra_helpers_spec.rb +121 -121
- data/spec/plugin/slash_path_empty_spec.rb +10 -10
- data/spec/plugin/static_spec.rb +4 -4
- data/spec/plugin/streaming_spec.rb +11 -11
- data/spec/plugin/symbol_matchers_spec.rb +24 -24
- data/spec/plugin/symbol_views_spec.rb +3 -3
- data/spec/plugin/view_options_spec.rb +10 -10
- data/spec/plugin_spec.rb +2 -2
- data/spec/redirect_spec.rb +10 -10
- data/spec/request_spec.rb +8 -8
- data/spec/response_spec.rb +23 -23
- data/spec/session_spec.rb +4 -4
- data/spec/spec_helper.rb +5 -19
- data/spec/version_spec.rb +4 -4
- data/spec/views/iv.erb +1 -0
- metadata +16 -5
@@ -17,24 +17,24 @@ describe "backtracking_array plugin" do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
tests = lambda do
|
20
|
-
status.
|
21
|
-
|
22
|
-
body("/a").
|
23
|
-
body("/a/b").
|
24
|
-
status("/a/b/").
|
25
|
-
|
26
|
-
body("/c/d").
|
27
|
-
body("/c/e").
|
28
|
-
body("/c/d/d").
|
29
|
-
body("/c/d/e").
|
30
|
-
status("/c/d/").
|
31
|
-
|
32
|
-
body("/f").
|
33
|
-
body("/f/g").
|
34
|
-
body("/g").
|
35
|
-
body("/g/h").
|
36
|
-
status("/f/g/").
|
37
|
-
status("/g/h/").
|
20
|
+
status.must_equal 404
|
21
|
+
|
22
|
+
body("/a").must_equal 'a'
|
23
|
+
body("/a/b").must_equal 'a/b'
|
24
|
+
status("/a/b/").must_equal 404
|
25
|
+
|
26
|
+
body("/c/d").must_equal 'c-d'
|
27
|
+
body("/c/e").must_equal 'c-e'
|
28
|
+
body("/c/d/d").must_equal 'c/d-d'
|
29
|
+
body("/c/d/e").must_equal 'c/d-e'
|
30
|
+
status("/c/d/").must_equal 404
|
31
|
+
|
32
|
+
body("/f").must_equal 'f'
|
33
|
+
body("/f/g").must_equal 'f/g'
|
34
|
+
body("/g").must_equal 'g'
|
35
|
+
body("/g/h").must_equal 'g/h'
|
36
|
+
status("/f/g/").must_equal 404
|
37
|
+
status("/g/h/").must_equal 404
|
38
38
|
end
|
39
39
|
|
40
40
|
tests.call
|
data/spec/plugin/caching_spec.rb
CHANGED
@@ -5,14 +5,14 @@ describe 'response.cache_control' do
|
|
5
5
|
app(:caching) do |r|
|
6
6
|
response.cache_control :public=>true, :no_cache=>true, :max_age => 60
|
7
7
|
end
|
8
|
-
header('Cache-Control').split(', ').sort.
|
8
|
+
header('Cache-Control').split(', ').sort.must_equal ['max-age=60', 'no-cache', 'public']
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'does not add a Cache-Control header if it would be empty' do
|
12
12
|
app(:caching) do |r|
|
13
13
|
response.cache_control({})
|
14
14
|
end
|
15
|
-
header('Cache-Control').
|
15
|
+
header('Cache-Control').must_equal nil
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -21,16 +21,16 @@ describe 'response.expires' do
|
|
21
21
|
app(:caching) do |r|
|
22
22
|
response.expires 60, :public=>true, :no_cache=>true
|
23
23
|
end
|
24
|
-
header('Cache-Control').split(', ').sort.
|
25
|
-
((Time.httpdate(header('Expires')) - Time.now).round - 60).abs.
|
24
|
+
header('Cache-Control').split(', ').sort.must_equal ['max-age=60', 'no-cache', 'public']
|
25
|
+
((Time.httpdate(header('Expires')) - Time.now).round - 60).abs.must_be :<=, 1
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'can be called with only one argument' do
|
29
29
|
app(:caching) do |r|
|
30
30
|
response.expires 60
|
31
31
|
end
|
32
|
-
header('Cache-Control').split(', ').sort.
|
33
|
-
((Time.httpdate(header('Expires')) - Time.now).round - 60).abs.
|
32
|
+
header('Cache-Control').split(', ').sort.must_equal ['max-age=60']
|
33
|
+
((Time.httpdate(header('Expires')) - Time.now).round - 60).abs.must_be :<=, 1
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -39,16 +39,16 @@ describe 'response.finish' do
|
|
39
39
|
app(:caching) do |r|
|
40
40
|
response.status = 304
|
41
41
|
end
|
42
|
-
header('Content-Type').
|
43
|
-
header('Content-Length').
|
42
|
+
header('Content-Type').must_equal nil
|
43
|
+
header('Content-Length').must_equal nil
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'does not change non-304 responses' do
|
47
47
|
app(:caching) do |r|
|
48
48
|
response.status = 200
|
49
49
|
end
|
50
|
-
header('Content-Type').
|
51
|
-
header('Content-Length').
|
50
|
+
header('Content-Type').must_equal 'text/html'
|
51
|
+
header('Content-Length').must_equal '0'
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -57,7 +57,7 @@ describe 'request.last_modified' do
|
|
57
57
|
app(:caching) do |r|
|
58
58
|
r.last_modified nil
|
59
59
|
end
|
60
|
-
header('Last-Modified').
|
60
|
+
header('Last-Modified').must_equal nil
|
61
61
|
end
|
62
62
|
|
63
63
|
it 'does not change a status other than 200' do
|
@@ -65,16 +65,16 @@ describe 'request.last_modified' do
|
|
65
65
|
response.status = 201
|
66
66
|
r.last_modified Time.now
|
67
67
|
end
|
68
|
-
status.
|
69
|
-
status('HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT').
|
70
|
-
status('HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2000 23:43:52 GMT').
|
68
|
+
status.must_equal 201
|
69
|
+
status('HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT').must_equal 201
|
70
|
+
status('HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2000 23:43:52 GMT').must_equal 201
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
describe 'request.last_modified' do
|
75
75
|
def res(a={})
|
76
76
|
s, h, b = req(a)
|
77
|
-
h['Last-Modified'].
|
77
|
+
h['Last-Modified'].must_equal @last_modified.httpdate
|
78
78
|
[s, b.join]
|
79
79
|
end
|
80
80
|
|
@@ -87,39 +87,39 @@ describe 'request.last_modified' do
|
|
87
87
|
end
|
88
88
|
|
89
89
|
it 'just sets Last-Modified if no If-Modified-Since header' do
|
90
|
-
res.
|
90
|
+
res.must_equal [200, 'ok']
|
91
91
|
end
|
92
92
|
|
93
93
|
it 'just sets Last-Modified if bogus If-Modified-Since header' do
|
94
|
-
res('HTTP_IF_MODIFIED_SINCE' => 'a really weird date').
|
94
|
+
res('HTTP_IF_MODIFIED_SINCE' => 'a really weird date').must_equal [200, 'ok']
|
95
95
|
end
|
96
96
|
|
97
97
|
it 'just sets Last-Modified if modified since If-Modified-Since header' do
|
98
|
-
res('HTTP_IF_MODIFIED_SINCE' => (@last_modified - 1).httpdate).
|
98
|
+
res('HTTP_IF_MODIFIED_SINCE' => (@last_modified - 1).httpdate).must_equal [200, 'ok']
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'sets Last-Modified and returns 304 if modified on If-Modified-Since header' do
|
102
|
-
res('HTTP_IF_MODIFIED_SINCE' => @last_modified.httpdate).
|
102
|
+
res('HTTP_IF_MODIFIED_SINCE' => @last_modified.httpdate).must_equal [304, '']
|
103
103
|
end
|
104
104
|
|
105
105
|
it 'sets Last-Modified and returns 304 if modified before If-Modified-Since header' do
|
106
|
-
res('HTTP_IF_MODIFIED_SINCE' => (@last_modified + 1).httpdate).
|
106
|
+
res('HTTP_IF_MODIFIED_SINCE' => (@last_modified + 1).httpdate).must_equal [304, '']
|
107
107
|
end
|
108
108
|
|
109
109
|
it 'sets Last-Modified if If-None-Match header present' do
|
110
|
-
res('HTTP_IF_NONE_MATCH' => '*', 'HTTP_IF_MODIFIED_SINCE' => (@last_modified + 1).httpdate).
|
110
|
+
res('HTTP_IF_NONE_MATCH' => '*', 'HTTP_IF_MODIFIED_SINCE' => (@last_modified + 1).httpdate).must_equal [200, 'ok']
|
111
111
|
end
|
112
112
|
|
113
113
|
it 'sets Last-Modified if modified before If-Unmodified-Since header' do
|
114
|
-
res('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified + 1).httpdate).
|
114
|
+
res('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified + 1).httpdate).must_equal [200, 'ok']
|
115
115
|
end
|
116
116
|
|
117
117
|
it 'sets Last-Modified if modified on If-Unmodified-Since header' do
|
118
|
-
res('HTTP_IF_UNMODIFIED_SINCE' => @last_modified.httpdate).
|
118
|
+
res('HTTP_IF_UNMODIFIED_SINCE' => @last_modified.httpdate).must_equal [200, 'ok']
|
119
119
|
end
|
120
120
|
|
121
121
|
it 'sets Last-Modified and returns 412 if modified after If-Unmodified-Since header' do
|
122
|
-
res('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified - 1).httpdate).
|
122
|
+
res('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified - 1).httpdate).must_equal [412, '']
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
@@ -138,198 +138,198 @@ describe 'request.etag' do
|
|
138
138
|
end
|
139
139
|
|
140
140
|
it 'uses a weak etag with the :weak option' do
|
141
|
-
header('ETag', 'weak'=>true).
|
141
|
+
header('ETag', 'weak'=>true).must_equal 'W/"foo"'
|
142
142
|
end
|
143
143
|
|
144
144
|
describe 'for GET requests' do
|
145
145
|
def res(a={})
|
146
146
|
s, h, b = req(a)
|
147
|
-
h['ETag'].
|
147
|
+
h['ETag'].must_equal '"foo"'
|
148
148
|
[s, b.join]
|
149
149
|
end
|
150
150
|
|
151
151
|
it "sets etag if no If-None-Match" do
|
152
|
-
res.
|
152
|
+
res.must_equal [200, 'ok']
|
153
153
|
end
|
154
154
|
|
155
155
|
it "sets etag and returns 304 if If-None-Match is *" do
|
156
|
-
res('HTTP_IF_NONE_MATCH' => '*').
|
156
|
+
res('HTTP_IF_NONE_MATCH' => '*').must_equal [304, '']
|
157
157
|
end
|
158
158
|
|
159
159
|
it "sets etag and if If-None-Match is * and it is a new resource" do
|
160
|
-
res('HTTP_IF_NONE_MATCH' => '*', 'new_resource'=>true).
|
160
|
+
res('HTTP_IF_NONE_MATCH' => '*', 'new_resource'=>true).must_equal [200, 'ok']
|
161
161
|
end
|
162
162
|
|
163
163
|
it "sets etag and returns 304 if If-None-Match is etag" do
|
164
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"').
|
164
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"').must_equal [304, '']
|
165
165
|
end
|
166
166
|
|
167
167
|
it "sets etag and returns 304 if If-None-Match includes etag" do
|
168
|
-
res('HTTP_IF_NONE_MATCH' => '"bar", "foo"').
|
168
|
+
res('HTTP_IF_NONE_MATCH' => '"bar", "foo"').must_equal [304, '']
|
169
169
|
end
|
170
170
|
|
171
171
|
it "sets etag if If-None-Match does not include etag" do
|
172
|
-
res('HTTP_IF_NONE_MATCH' => '"bar", "baz"').
|
172
|
+
res('HTTP_IF_NONE_MATCH' => '"bar", "baz"').must_equal [200, 'ok']
|
173
173
|
end
|
174
174
|
|
175
175
|
it "sets etag and does not change status code if status code set and not 2xx or 304 if If-None-Match is etag" do
|
176
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>499).
|
176
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>499).must_equal [499, 'ok']
|
177
177
|
end
|
178
178
|
|
179
179
|
it "sets etag and returns 304 if status code set to 2xx if If-None-Match is etag" do
|
180
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>201).
|
180
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>201).must_equal [304, '']
|
181
181
|
end
|
182
182
|
|
183
183
|
it "sets etag and returns 304 if status code is already 304 if If-None-Match is etag" do
|
184
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>304).
|
184
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>304).must_equal [304, '']
|
185
185
|
end
|
186
186
|
|
187
187
|
it "sets etag if If-Match is *" do
|
188
|
-
res('HTTP_IF_MATCH' => '*').
|
188
|
+
res('HTTP_IF_MATCH' => '*').must_equal [200, 'ok']
|
189
189
|
end
|
190
190
|
|
191
191
|
it "sets etag if If-Match is etag" do
|
192
|
-
res('HTTP_IF_MATCH' => '"foo"').
|
192
|
+
res('HTTP_IF_MATCH' => '"foo"').must_equal [200, 'ok']
|
193
193
|
end
|
194
194
|
|
195
195
|
it "sets etag if If-Match includes etag" do
|
196
|
-
res('HTTP_IF_MATCH' => '"bar", "foo"').
|
196
|
+
res('HTTP_IF_MATCH' => '"bar", "foo"').must_equal [200, 'ok']
|
197
197
|
end
|
198
198
|
|
199
199
|
it "sets etag and returns 412 if If-Match is * for new resources" do
|
200
|
-
res('HTTP_IF_MATCH' => '*', 'new_resource'=>true).
|
200
|
+
res('HTTP_IF_MATCH' => '*', 'new_resource'=>true).must_equal [412, '']
|
201
201
|
end
|
202
202
|
|
203
203
|
it "sets etag if If-Match does not include etag" do
|
204
|
-
res('HTTP_IF_MATCH' => '"bar", "baz"', 'new_resource'=>true).
|
204
|
+
res('HTTP_IF_MATCH' => '"bar", "baz"', 'new_resource'=>true).must_equal [412, '']
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
208
|
describe 'for PUT requests' do
|
209
209
|
def res(a={})
|
210
210
|
s, h, b = req(a.merge('REQUEST_METHOD'=>'PUT'))
|
211
|
-
h['ETag'].
|
211
|
+
h['ETag'].must_equal '"foo"'
|
212
212
|
[s, b.join]
|
213
213
|
end
|
214
214
|
|
215
215
|
it "sets etag if no If-None-Match" do
|
216
|
-
res.
|
216
|
+
res.must_equal [200, 'ok']
|
217
217
|
end
|
218
218
|
|
219
219
|
it "sets etag and returns 412 if If-None-Match is *" do
|
220
|
-
res('HTTP_IF_NONE_MATCH' => '*').
|
220
|
+
res('HTTP_IF_NONE_MATCH' => '*').must_equal [412, '']
|
221
221
|
end
|
222
222
|
|
223
223
|
it "sets etag and if If-None-Match is * and it is a new resource" do
|
224
|
-
res('HTTP_IF_NONE_MATCH' => '*', 'new_resource'=>true).
|
224
|
+
res('HTTP_IF_NONE_MATCH' => '*', 'new_resource'=>true).must_equal [200, 'ok']
|
225
225
|
end
|
226
226
|
|
227
227
|
it "sets etag and returns 412 if If-None-Match is etag" do
|
228
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"').
|
228
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"').must_equal [412, '']
|
229
229
|
end
|
230
230
|
|
231
231
|
it "sets etag and returns 412 if If-None-Match includes etag" do
|
232
|
-
res('HTTP_IF_NONE_MATCH' => '"bar", "foo"').
|
232
|
+
res('HTTP_IF_NONE_MATCH' => '"bar", "foo"').must_equal [412, '']
|
233
233
|
end
|
234
234
|
|
235
235
|
it "sets etag if If-None-Match does not include etag" do
|
236
|
-
res('HTTP_IF_NONE_MATCH' => '"bar", "baz"').
|
236
|
+
res('HTTP_IF_NONE_MATCH' => '"bar", "baz"').must_equal [200, 'ok']
|
237
237
|
end
|
238
238
|
|
239
239
|
it "sets etag and does not change status code if status code set and not 2xx or 304 if If-None-Match is etag" do
|
240
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>499).
|
240
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>499).must_equal [499, 'ok']
|
241
241
|
end
|
242
242
|
|
243
243
|
it "sets etag and returns 304 if status code set to 2xx if If-None-Match is etag" do
|
244
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>201).
|
244
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>201).must_equal [412, '']
|
245
245
|
end
|
246
246
|
|
247
247
|
it "sets etag and returns 304 if status code is already 304 if If-None-Match is etag" do
|
248
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>304).
|
248
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>304).must_equal [412, '']
|
249
249
|
end
|
250
250
|
|
251
251
|
it "sets etag if If-Match is *" do
|
252
|
-
res('HTTP_IF_MATCH' => '*').
|
252
|
+
res('HTTP_IF_MATCH' => '*').must_equal [200, 'ok']
|
253
253
|
end
|
254
254
|
|
255
255
|
it "sets etag if If-Match is etag" do
|
256
|
-
res('HTTP_IF_MATCH' => '"foo"').
|
256
|
+
res('HTTP_IF_MATCH' => '"foo"').must_equal [200, 'ok']
|
257
257
|
end
|
258
258
|
|
259
259
|
it "sets etag if If-Match includes etag" do
|
260
|
-
res('HTTP_IF_MATCH' => '"bar", "foo"').
|
260
|
+
res('HTTP_IF_MATCH' => '"bar", "foo"').must_equal [200, 'ok']
|
261
261
|
end
|
262
262
|
|
263
263
|
it "sets etag and returns 412 if If-Match is * for new resources" do
|
264
|
-
res('HTTP_IF_MATCH' => '*', 'new_resource'=>true).
|
264
|
+
res('HTTP_IF_MATCH' => '*', 'new_resource'=>true).must_equal [412, '']
|
265
265
|
end
|
266
266
|
|
267
267
|
it "sets etag if If-Match does not include etag" do
|
268
|
-
res('HTTP_IF_MATCH' => '"bar", "baz"', 'new_resource'=>true).
|
268
|
+
res('HTTP_IF_MATCH' => '"bar", "baz"', 'new_resource'=>true).must_equal [412, '']
|
269
269
|
end
|
270
270
|
end
|
271
271
|
|
272
272
|
describe 'for POST requests' do
|
273
273
|
def res(a={})
|
274
274
|
s, h, b = req(a.merge('REQUEST_METHOD'=>'POST'))
|
275
|
-
h['ETag'].
|
275
|
+
h['ETag'].must_equal '"foo"'
|
276
276
|
[s, b.join]
|
277
277
|
end
|
278
278
|
|
279
279
|
it "sets etag if no If-None-Match" do
|
280
|
-
res.
|
280
|
+
res.must_equal [200, 'ok']
|
281
281
|
end
|
282
282
|
|
283
283
|
it "sets etag and returns 412 if If-None-Match is * and it is not a new resource" do
|
284
|
-
res('HTTP_IF_NONE_MATCH' => '*', 'new_resource'=>false).
|
284
|
+
res('HTTP_IF_NONE_MATCH' => '*', 'new_resource'=>false).must_equal [412, '']
|
285
285
|
end
|
286
286
|
|
287
287
|
it "sets etag and if If-None-Match is *" do
|
288
|
-
res('HTTP_IF_NONE_MATCH' => '*').
|
288
|
+
res('HTTP_IF_NONE_MATCH' => '*').must_equal [200, 'ok']
|
289
289
|
end
|
290
290
|
|
291
291
|
it "sets etag and returns 412 if If-None-Match is etag" do
|
292
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"').
|
292
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"').must_equal [412, '']
|
293
293
|
end
|
294
294
|
|
295
295
|
it "sets etag and returns 412 if If-None-Match includes etag" do
|
296
|
-
res('HTTP_IF_NONE_MATCH' => '"bar", "foo"').
|
296
|
+
res('HTTP_IF_NONE_MATCH' => '"bar", "foo"').must_equal [412, '']
|
297
297
|
end
|
298
298
|
|
299
299
|
it "sets etag if If-None-Match does not include etag" do
|
300
|
-
res('HTTP_IF_NONE_MATCH' => '"bar", "baz"').
|
300
|
+
res('HTTP_IF_NONE_MATCH' => '"bar", "baz"').must_equal [200, 'ok']
|
301
301
|
end
|
302
302
|
|
303
303
|
it "sets etag and does not change status code if status code set and not 2xx or 304 if If-None-Match is etag" do
|
304
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>499).
|
304
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>499).must_equal [499, 'ok']
|
305
305
|
end
|
306
306
|
|
307
307
|
it "sets etag and returns 304 if status code set to 2xx if If-None-Match is etag" do
|
308
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>201).
|
308
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>201).must_equal [412, '']
|
309
309
|
end
|
310
310
|
|
311
311
|
it "sets etag and returns 304 if status code is already 304 if If-None-Match is etag" do
|
312
|
-
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>304).
|
312
|
+
res('HTTP_IF_NONE_MATCH' => '"foo"', 'status'=>304).must_equal [412, '']
|
313
313
|
end
|
314
314
|
|
315
315
|
it "sets etag if If-Match is * and this is not a new resource" do
|
316
|
-
res('HTTP_IF_MATCH' => '*', 'new_resource'=>false).
|
316
|
+
res('HTTP_IF_MATCH' => '*', 'new_resource'=>false).must_equal [200, 'ok']
|
317
317
|
end
|
318
318
|
|
319
319
|
it "sets etag if If-Match is etag" do
|
320
|
-
res('HTTP_IF_MATCH' => '"foo"').
|
320
|
+
res('HTTP_IF_MATCH' => '"foo"').must_equal [200, 'ok']
|
321
321
|
end
|
322
322
|
|
323
323
|
it "sets etag if If-Match includes etag" do
|
324
|
-
res('HTTP_IF_MATCH' => '"bar", "foo"').
|
324
|
+
res('HTTP_IF_MATCH' => '"bar", "foo"').must_equal [200, 'ok']
|
325
325
|
end
|
326
326
|
|
327
327
|
it "sets etag and returns 412 if If-Match is * for new resources" do
|
328
|
-
res('HTTP_IF_MATCH' => '*').
|
328
|
+
res('HTTP_IF_MATCH' => '*').must_equal [412, '']
|
329
329
|
end
|
330
330
|
|
331
331
|
it "sets etag if If-Match does not include etag" do
|
332
|
-
res('HTTP_IF_MATCH' => '"bar", "baz"', 'new_resource'=>true).
|
332
|
+
res('HTTP_IF_MATCH' => '"bar", "baz"', 'new_resource'=>true).must_equal [412, '']
|
333
333
|
end
|
334
334
|
end
|
335
335
|
end
|
data/spec/plugin/chunked_spec.rb
CHANGED
@@ -15,18 +15,18 @@ describe "chunked plugin" do
|
|
15
15
|
chunked(:inline=>'m', :layout=>{:inline=>'h<%= yield %>t'})
|
16
16
|
end
|
17
17
|
|
18
|
-
cbody.
|
19
|
-
body.
|
18
|
+
cbody.must_equal "1\r\nh\r\n1\r\nm\r\n1\r\nt\r\n0\r\n\r\n"
|
19
|
+
body.must_equal "hmt"
|
20
20
|
end
|
21
21
|
|
22
22
|
it "hex encodes chunk sizes" do
|
23
23
|
m = 'm' * 31
|
24
24
|
app(:chunked) do |r|
|
25
|
-
chunked(:inline=>m, :layout=>{:inline=>'h<%= yield %>t'})
|
25
|
+
chunked(:inline=>m.dup, :layout=>{:inline=>'h<%= yield %>t'})
|
26
26
|
end
|
27
27
|
|
28
|
-
cbody.
|
29
|
-
body.
|
28
|
+
cbody.must_equal "1\r\nh\r\n1f\r\n#{m}\r\n1\r\nt\r\n0\r\n\r\n"
|
29
|
+
body.must_equal "h#{m}t"
|
30
30
|
end
|
31
31
|
|
32
32
|
it "accepts a block that is called after layout yielding but before content when streaming" do
|
@@ -36,8 +36,8 @@ describe "chunked plugin" do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
cbody.
|
40
|
-
body.
|
39
|
+
cbody.must_equal "2\r\nmh\r\n1\r\nt\r\n0\r\n\r\n"
|
40
|
+
body.must_equal "hmht"
|
41
41
|
end
|
42
42
|
|
43
43
|
it "has delay accept block that is called after layout yielding but before content when streaming" do
|
@@ -51,13 +51,13 @@ describe "chunked plugin" do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
cbody.
|
55
|
-
body.
|
54
|
+
cbody.must_equal "1\r\nh\r\n4\r\nmhij\r\n1\r\nt\r\n0\r\n\r\n"
|
55
|
+
body.must_equal "hijmhijt"
|
56
56
|
end
|
57
57
|
|
58
58
|
it "has delay raise if not given a block" do
|
59
59
|
app(:chunked){|r| delay}
|
60
|
-
proc{body}.
|
60
|
+
proc{body}.must_raise(Roda::RodaError)
|
61
61
|
end
|
62
62
|
|
63
63
|
it "works when a layout is not used" do
|
@@ -65,8 +65,8 @@ describe "chunked plugin" do
|
|
65
65
|
chunked(:inline=>'m', :layout=>nil)
|
66
66
|
end
|
67
67
|
|
68
|
-
cbody.
|
69
|
-
body.
|
68
|
+
cbody.must_equal "1\r\nm\r\n0\r\n\r\n"
|
69
|
+
body.must_equal "m"
|
70
70
|
end
|
71
71
|
|
72
72
|
it "streams partial template responses if flush is used in content template" do
|
@@ -74,8 +74,8 @@ describe "chunked plugin" do
|
|
74
74
|
chunked(:inline=>'m<%= flush %>n', :layout=>{:inline=>'h<%= yield %>t'})
|
75
75
|
end
|
76
76
|
|
77
|
-
cbody.
|
78
|
-
body.
|
77
|
+
cbody.must_equal "1\r\nh\r\n1\r\nm\r\n1\r\nn\r\n1\r\nt\r\n0\r\n\r\n"
|
78
|
+
body.must_equal "hmnt"
|
79
79
|
end
|
80
80
|
|
81
81
|
it "streams partial template responses if flush is used in layout template" do
|
@@ -83,8 +83,8 @@ describe "chunked plugin" do
|
|
83
83
|
chunked(:inline=>'m', :layout=>{:inline=>'h<%= flush %>i<%= yield %>t'})
|
84
84
|
end
|
85
85
|
|
86
|
-
cbody.
|
87
|
-
body.
|
86
|
+
cbody.must_equal "1\r\nh\r\n1\r\ni\r\n1\r\nm\r\n1\r\nt\r\n0\r\n\r\n"
|
87
|
+
body.must_equal "himt"
|
88
88
|
end
|
89
89
|
|
90
90
|
it "does not stream if no_chunk! is used" do
|
@@ -93,8 +93,8 @@ describe "chunked plugin" do
|
|
93
93
|
chunked(:inline=>'m', :layout=>{:inline=>'h<%= yield %>t'})
|
94
94
|
end
|
95
95
|
|
96
|
-
cbody.
|
97
|
-
body.
|
96
|
+
cbody.must_equal "hmt"
|
97
|
+
body.must_equal "hmt"
|
98
98
|
end
|
99
99
|
|
100
100
|
it "streams existing response body before call" do
|
@@ -103,8 +103,8 @@ describe "chunked plugin" do
|
|
103
103
|
response.write chunked(:inline=>'m', :layout=>{:inline=>'h<%= yield %>t'})
|
104
104
|
end
|
105
105
|
|
106
|
-
cbody.
|
107
|
-
body.
|
106
|
+
cbody.must_equal "1\r\na\r\n1\r\nh\r\n1\r\nm\r\n1\r\nt\r\n0\r\n\r\n"
|
107
|
+
body.must_equal "ahmt"
|
108
108
|
end
|
109
109
|
|
110
110
|
it "should not include Content-Length header even if body is already written to" do
|
@@ -113,8 +113,8 @@ describe "chunked plugin" do
|
|
113
113
|
response.write chunked(:inline=>'m', :layout=>{:inline=>'h<%= yield %>t'})
|
114
114
|
end
|
115
115
|
|
116
|
-
header('Content-Length', 'HTTP_VERSION'=>'HTTP/1.1').
|
117
|
-
header('Content-Length', 'HTTP_VERSION'=>'HTTP/1.0').
|
116
|
+
header('Content-Length', 'HTTP_VERSION'=>'HTTP/1.1').must_equal nil
|
117
|
+
header('Content-Length', 'HTTP_VERSION'=>'HTTP/1.0').must_equal '4'
|
118
118
|
end
|
119
119
|
|
120
120
|
it "stream template responses for view if :chunk_by_default is used" do
|
@@ -125,8 +125,8 @@ describe "chunked plugin" do
|
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
|
-
cbody.
|
129
|
-
body.
|
128
|
+
cbody.must_equal "1\r\nh\r\n1\r\nm\r\n1\r\nt\r\n0\r\n\r\n"
|
129
|
+
body.must_equal "hmt"
|
130
130
|
end
|
131
131
|
|
132
132
|
it "uses Transfer-Encoding header when chunking" do
|
@@ -134,8 +134,8 @@ describe "chunked plugin" do
|
|
134
134
|
chunked(:inline=>'m', :layout=>{:inline=>'h<%= yield %>t'})
|
135
135
|
end
|
136
136
|
|
137
|
-
header('Transfer-Encoding', 'HTTP_VERSION'=>'HTTP/1.1').
|
138
|
-
header('Transfer-Encoding', 'HTTP_VERSION'=>'HTTP/1.0').
|
137
|
+
header('Transfer-Encoding', 'HTTP_VERSION'=>'HTTP/1.1').must_equal 'chunked'
|
138
|
+
header('Transfer-Encoding', 'HTTP_VERSION'=>'HTTP/1.0').must_equal nil
|
139
139
|
end
|
140
140
|
|
141
141
|
it "uses given :headers when chunking" do
|
@@ -146,8 +146,8 @@ describe "chunked plugin" do
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
149
|
-
header('Foo', 'HTTP_VERSION'=>'HTTP/1.1').
|
150
|
-
header('Foo', 'HTTP_VERSION'=>'HTTP/1.0').
|
149
|
+
header('Foo', 'HTTP_VERSION'=>'HTTP/1.1').must_equal 'bar'
|
150
|
+
header('Foo', 'HTTP_VERSION'=>'HTTP/1.0').must_equal nil
|
151
151
|
end
|
152
152
|
|
153
153
|
it "handles multiple arguments to chunked" do
|
@@ -159,8 +159,8 @@ describe "chunked plugin" do
|
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
|
-
cbody.
|
163
|
-
body.
|
162
|
+
cbody.must_equal "1\r\nh\r\nb\r\n<h1>m</h1>\n\r\n1\r\nt\r\n0\r\n\r\n"
|
163
|
+
body.must_equal "h<h1>m</h1>\nt"
|
164
164
|
end
|
165
165
|
|
166
166
|
it "handles multiple hash arguments to chunked" do
|
@@ -168,8 +168,8 @@ describe "chunked plugin" do
|
|
168
168
|
chunked({:inline=>'m'}, :layout=>{:inline=>'h<%= yield %>t'})
|
169
169
|
end
|
170
170
|
|
171
|
-
cbody.
|
172
|
-
body.
|
171
|
+
cbody.must_equal "1\r\nh\r\n1\r\nm\r\n1\r\nt\r\n0\r\n\r\n"
|
172
|
+
body.must_equal "hmt"
|
173
173
|
end
|
174
174
|
|
175
175
|
it "handles :layout_opts option" do
|
@@ -177,24 +177,24 @@ describe "chunked plugin" do
|
|
177
177
|
chunked(:inline=>'m', :layout=>{:inline=>'<%= h %><%= yield %>t'}, :layout_opts=>{:locals=>{:h=>'h'}})
|
178
178
|
end
|
179
179
|
|
180
|
-
cbody.
|
181
|
-
body.
|
180
|
+
cbody.must_equal "1\r\nh\r\n1\r\nm\r\n1\r\nt\r\n0\r\n\r\n"
|
181
|
+
body.must_equal "hmt"
|
182
182
|
end
|
183
183
|
|
184
184
|
it "uses handle_chunk_error for handling errors when chunking" do
|
185
185
|
app(:chunked) do |r|
|
186
186
|
chunked(:inline=>'m', :layout=>{:inline=>'h<%= yield %><% raise %>'})
|
187
187
|
end
|
188
|
-
proc{cbody}.
|
189
|
-
proc{body}.
|
188
|
+
proc{cbody}.must_raise RuntimeError
|
189
|
+
proc{body}.must_raise RuntimeError
|
190
190
|
|
191
191
|
app.send(:define_method, :handle_chunk_error) do |v|
|
192
192
|
@_out_buf = 'e'
|
193
193
|
flush
|
194
194
|
end
|
195
195
|
|
196
|
-
cbody.
|
197
|
-
proc{body}.
|
196
|
+
cbody.must_equal "1\r\nh\r\n1\r\nm\r\n1\r\ne\r\n0\r\n\r\n"
|
197
|
+
proc{body}.must_raise RuntimeError
|
198
198
|
end
|
199
199
|
end
|
200
200
|
end
|