rack-robustness 1.1.0 → 2.0.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/CHANGELOG.md +68 -6
- data/Gemfile +2 -7
- data/README.md +16 -8
- data/Rakefile +1 -3
- data/lib/rack/robustness/version.rb +8 -0
- data/lib/rack/robustness.rb +23 -7
- data/spec/test_context.rb +3 -3
- data/spec/test_ensure.rb +10 -10
- data/spec/test_header_names.rb +98 -0
- data/spec/test_last_resort.rb +17 -17
- data/spec/test_rescue.rb +6 -6
- data/spec/test_response.rb +4 -4
- data/spec/test_robustness.rb +46 -46
- data/spec/test_subclass.rb +3 -3
- data/tasks/gem.rake +25 -59
- data/tasks/test.rake +11 -0
- metadata +66 -63
- data/Gemfile.lock +0 -25
- data/Manifest.txt +0 -15
- data/rack-robustness.gemspec +0 -188
- data/tasks/spec_test.rake +0 -71
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 13cdad67517d9891e673d38c26fd1efa91fafd03bbf52d552fef3b779596e572
|
|
4
|
+
data.tar.gz: b58b64c4c92eb4a1659aaffc31153c8bbf70bb507c1b9864c06a02b8a1142efa
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 41fa4ce5a8f8f7bf2ff190c5c3a44515162526a3777d41d22bc959b5873db6a82d99f475d617be0e75397ffe37240585e84e495799144ba52100987412c241b7
|
|
7
|
+
data.tar.gz: 4a262606fedaaf85c842cc43d899cc652a1563bfb606838a1debb6a393d3edba260f3c68a42634bda9ca1c08ebc74fe0d3f6f429d8a4e826dcf0778046ea56de
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,66 @@
|
|
|
1
|
-
|
|
1
|
+
## 2.0.0 / 2026-09-29
|
|
2
|
+
|
|
3
|
+
The Rack 3 release.
|
|
4
|
+
|
|
5
|
+
* BREAKING: response header names are now emitted in lowercase, as required
|
|
6
|
+
by the Rack 3 SPEC ("Header keys must not contain uppercase ASCII
|
|
7
|
+
characters"). Names given to the DSL are normalized, so `'content-type'`,
|
|
8
|
+
`'Content-Type'` and `'CONTENT-TYPE'` all name the same header:
|
|
9
|
+
|
|
10
|
+
use Rack::Robustness do |g|
|
|
11
|
+
g.headers 'X-Error' => 'boom' # emitted as x-error
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Under Rack 3 this was mostly already the case, since Rack::Response
|
|
15
|
+
normalizes what it is given. The path that was genuinely non-compliant was
|
|
16
|
+
the last resort response, returned as a raw triple when error handling
|
|
17
|
+
itself fails. Header names are case-insensitive on the wire, so the change
|
|
18
|
+
is invisible to clients; it is only visible to code asserting on the raw
|
|
19
|
+
Rack triple, or to a middleware reading headers case-sensitively.
|
|
20
|
+
|
|
21
|
+
* BREAKING: fixed the default headers silently winning over a configured one
|
|
22
|
+
written in another case. `g.headers('content-type' => 'application/json')`
|
|
23
|
+
used to be ignored, the `'Content-Type' => 'text/plain'` default taking
|
|
24
|
+
precedence, because the two keys did not collide and clauses are applied
|
|
25
|
+
with `||=`. Lowercase being what Rack 3 users naturally write, this was
|
|
26
|
+
easy to hit and silent. Applications that worked around it by writing
|
|
27
|
+
`'Content-Type'` are unaffected.
|
|
28
|
+
|
|
29
|
+
* BREAKING: Ruby >= 3.2 is now required, and the test matrix covers 3.2, 3.3
|
|
30
|
+
and 3.4. Ruby 2.7 and 3.1 have both reached end of life.
|
|
31
|
+
|
|
32
|
+
* BREAKING: Rack 3 is now required. Rack 2 reached its last feature release
|
|
33
|
+
in 2022 and nothing here is worth keeping a compatibility branch for. Stay
|
|
34
|
+
on the 1.x line if you are still on Rack 2.
|
|
35
|
+
|
|
36
|
+
* `rack` is now a proper runtime dependency, `>= 3.0, < 4.0`. It was only a
|
|
37
|
+
development dependency before, even though the middleware has always used
|
|
38
|
+
`Rack::Request` and `Rack::Response`. `lib/rack/robustness.rb` requires it
|
|
39
|
+
explicitly rather than assuming the host application already did.
|
|
40
|
+
|
|
41
|
+
* The version moved to `rack/robustness/version.rb`, so that the gemspec can
|
|
42
|
+
read it without loading Rack, which would activate a Rack version before
|
|
43
|
+
Bundler gets to constrain it.
|
|
44
|
+
|
|
45
|
+
* Fixed `rake` being entirely broken: `tasks/gem.rake` eval'd the gemspec
|
|
46
|
+
without a filename, so `__FILE__` resolved to `(eval)` and the `$LOAD_PATH`
|
|
47
|
+
entry it computes pointed nowhere.
|
|
48
|
+
|
|
49
|
+
* Development dependencies were stale to the point of being wrong (rspec
|
|
50
|
+
~> 2.12 while the suite is rspec 3, rake ~> 10, rack ~> 1.5). They now
|
|
51
|
+
match what is actually used, rack-test included, moving from 0.6 to 2.x.
|
|
52
|
+
|
|
53
|
+
* The gemspec dropped its Noe boilerplate, along with `Manifest.txt` and the
|
|
54
|
+
dangling `rack-robustness.noespec` entry it carried. `.travis.yml` is
|
|
55
|
+
removed too, CI having moved to GitHub Actions.
|
|
56
|
+
|
|
57
|
+
## 1.2.0 / 2023-06-09
|
|
58
|
+
|
|
59
|
+
* Modernize with test matrix on ruby 2.7, 3.1, and 3.2
|
|
60
|
+
|
|
61
|
+
* Fix usage of Fixnum to be compatible with Ruby 3.x
|
|
62
|
+
|
|
63
|
+
## 1.1.0 / 2013-04-16
|
|
2
64
|
|
|
3
65
|
* Fixed catching of non standard errors (e.g. SecurityError)
|
|
4
66
|
|
|
@@ -16,7 +78,7 @@
|
|
|
16
78
|
g.rescue(SecurityError, 403)
|
|
17
79
|
end
|
|
18
80
|
|
|
19
|
-
* Added suppport for ensure clause(s), called after `rescue` blocks
|
|
81
|
+
* Added suppport for ensure clause(s), always called after `rescue` blocks
|
|
20
82
|
|
|
21
83
|
* Rack's `env` is now available in all error handling blocks, e.g.,
|
|
22
84
|
|
|
@@ -27,15 +89,15 @@
|
|
|
27
89
|
g.ensure{|ex| ... env ... }
|
|
28
90
|
end
|
|
29
91
|
|
|
30
|
-
* Similarly, Rack::Robustness now internally uses instances of Rack::Request and Rack::Response
|
|
31
|
-
|
|
92
|
+
* Similarly, Rack::Robustness now internally uses instances of Rack::Request and Rack::Response;
|
|
93
|
+
`request` and `response` are available in all blocks. The specific Response
|
|
32
94
|
object to use can be built using the `response` DSL method, e.g.,
|
|
33
95
|
|
|
34
96
|
use Rack::Robustness do |g|
|
|
35
97
|
g.response{|ex| MyOwnRackResponse.new }
|
|
36
98
|
end
|
|
37
99
|
|
|
38
|
-
* Rack::Robustness may now be subclassed as an alternative to inline use
|
|
100
|
+
* Rack::Robustness may now be subclassed as an alternative to inline `use`, e.g.
|
|
39
101
|
|
|
40
102
|
class Shield < Rack::Robustness
|
|
41
103
|
self.body {|ex| ... }
|
|
@@ -46,7 +108,7 @@
|
|
|
46
108
|
# in Rack-based configuration
|
|
47
109
|
use Shield
|
|
48
110
|
|
|
49
|
-
|
|
111
|
+
## 1.0.0 / 2013-02-26
|
|
50
112
|
|
|
51
113
|
* Enhancements
|
|
52
114
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Rack::Robustness is the rescue clause of your Rack's call stack. In other words, a middleware that ensures the robustness of your web stack, because exceptions occur either intentionally or unintentionally. Rack::Robustness is the rack middleware you would have written manually (see below) but provides a DSL for scaling from zero configuration (a default shield) to specific rescue clauses for specific errors.
|
|
4
4
|
|
|
5
|
-
[](https://gemnasium.com/blambeau/rack-robustness)
|
|
5
|
+
[](https://github.com/blambeau/rack-robustness/actions/workflows/integration.yml)
|
|
7
6
|
|
|
8
7
|
```ruby
|
|
9
8
|
##
|
|
@@ -19,9 +18,9 @@ class Robustness
|
|
|
19
18
|
def call(env)
|
|
20
19
|
@app.call(env)
|
|
21
20
|
rescue ArgumentError => ex
|
|
22
|
-
[400, { '
|
|
21
|
+
[400, { 'content-type' => 'text/plain' }, [ ex.message ] ] # suppose the message can be safely used
|
|
23
22
|
rescue SecurityError => ex
|
|
24
|
-
[403, { '
|
|
23
|
+
[403, { 'content-type' => 'text/plain' }, [ ex.message ] ]
|
|
25
24
|
ensure
|
|
26
25
|
env['rack.errors'].write(ex.message) if ex
|
|
27
26
|
end
|
|
@@ -48,6 +47,15 @@ use Rack::Robustness do |g|
|
|
|
48
47
|
end
|
|
49
48
|
```
|
|
50
49
|
|
|
50
|
+
## Requirements
|
|
51
|
+
|
|
52
|
+
Ruby >= 3.2 and Rack 3. Use the 1.x line if you are still on Rack 2.
|
|
53
|
+
|
|
54
|
+
Response header names are always emitted in lowercase, as the Rack 3 SPEC
|
|
55
|
+
requires. You may write them in any case you like -- `'content-type'`,
|
|
56
|
+
`'Content-Type'` and `'CONTENT-TYPE'` all name the same header -- they are
|
|
57
|
+
normalized before reaching the response.
|
|
58
|
+
|
|
51
59
|
## Links
|
|
52
60
|
|
|
53
61
|
* https://github.com/blambeau/rack-robustness
|
|
@@ -178,7 +186,7 @@ end
|
|
|
178
186
|
#
|
|
179
187
|
# Respond with
|
|
180
188
|
# status: 500,
|
|
181
|
-
# headers: {'
|
|
189
|
+
# headers: {'content-type' => 'text/plain'}
|
|
182
190
|
# body: [ "Sorry, an error occured." ]
|
|
183
191
|
#
|
|
184
192
|
use Rack::Robustness
|
|
@@ -194,7 +202,7 @@ use Rack::Robustness
|
|
|
194
202
|
#
|
|
195
203
|
use Rack::Robustness do |g|
|
|
196
204
|
g.status 400
|
|
197
|
-
g.headers '
|
|
205
|
+
g.headers 'content-type' => 'text/html'
|
|
198
206
|
g.content_type 'text/html' # shortcut over headers
|
|
199
207
|
g.body "<p>an error occured</p>"
|
|
200
208
|
end
|
|
@@ -212,10 +220,10 @@ use Rack::Robustness do |g|
|
|
|
212
220
|
g.status{|ex| ArgumentError===ex ? 400 : 500 }
|
|
213
221
|
|
|
214
222
|
# global dynamic headers
|
|
215
|
-
g.headers{|ex| {'
|
|
223
|
+
g.headers{|ex| {'content-type' => 'text/plain', ...} }
|
|
216
224
|
|
|
217
225
|
# local dynamic and/or static headers
|
|
218
|
-
g.headers '
|
|
226
|
+
g.headers 'content-type' => lambda{|ex| ... },
|
|
219
227
|
'Foo' => 'Bar'
|
|
220
228
|
|
|
221
229
|
# dynamic content type
|
data/Rakefile
CHANGED
data/lib/rack/robustness.rb
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
+
require 'rack'
|
|
2
|
+
require 'rack/robustness/version'
|
|
3
|
+
|
|
1
4
|
module Rack
|
|
2
5
|
class Robustness
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
# Downcases header names, as required by the Rack 3 SPEC: "Header keys
|
|
8
|
+
# must not contain uppercase ASCII characters (A-Z)".
|
|
9
|
+
#
|
|
10
|
+
# Header names are case-insensitive on the wire, so this is applied to
|
|
11
|
+
# whatever the DSL is given, rather than rejecting capitalized names.
|
|
12
|
+
def self.normalize_headers(headers)
|
|
13
|
+
headers.each_with_object({}) do |(name, value), normalized|
|
|
14
|
+
normalized[name.to_s.downcase] = value
|
|
15
|
+
end
|
|
16
|
+
end
|
|
5
17
|
|
|
6
18
|
def self.new(app, &bl)
|
|
7
19
|
return super(app) if bl.nil? and not(Robustness==self)
|
|
@@ -22,7 +34,7 @@ module Rack
|
|
|
22
34
|
@rescue_clauses = {}
|
|
23
35
|
@ensure_clauses = []
|
|
24
36
|
@status_clause = 500
|
|
25
|
-
@headers_clause = {'
|
|
37
|
+
@headers_clause = {'content-type' => "text/plain"}
|
|
26
38
|
@body_clause = ["Sorry, a fatal error occured."]
|
|
27
39
|
@response_builder = lambda{|ex| ::Rack::Response.new }
|
|
28
40
|
@catch_all = true
|
|
@@ -67,12 +79,12 @@ module Rack
|
|
|
67
79
|
if h.nil?
|
|
68
80
|
@headers_clause = bl
|
|
69
81
|
else
|
|
70
|
-
@headers_clause.merge!(h)
|
|
82
|
+
@headers_clause.merge!(Robustness.normalize_headers(h))
|
|
71
83
|
end
|
|
72
84
|
end
|
|
73
85
|
|
|
74
86
|
def content_type(ct=nil, &bl)
|
|
75
|
-
headers('
|
|
87
|
+
headers('content-type' => ct || bl)
|
|
76
88
|
end
|
|
77
89
|
|
|
78
90
|
def body(b=nil, &bl)
|
|
@@ -164,7 +176,7 @@ module Rack
|
|
|
164
176
|
def handle_error(ex, rescue_clause)
|
|
165
177
|
case rescue_clause
|
|
166
178
|
when NilClass then handle_error(ex, [status_clause, {}, body_clause])
|
|
167
|
-
when
|
|
179
|
+
when Integer then handle_error(ex, [rescue_clause, {}, body_clause])
|
|
168
180
|
when String then handle_error(ex, [status_clause, {}, rescue_clause])
|
|
169
181
|
when Hash then handle_error(ex, [status_clause, rescue_clause, body_clause])
|
|
170
182
|
when Proc then handle_error(ex, handle_value(ex, rescue_clause))
|
|
@@ -181,8 +193,12 @@ module Rack
|
|
|
181
193
|
@response.status = handle_value(ex, status)
|
|
182
194
|
end
|
|
183
195
|
|
|
196
|
+
# `headers` may come from a block, and therefore carry names in any case.
|
|
197
|
+
# They are normalized here so that a name given as 'Content-Type' and one
|
|
198
|
+
# given as 'content-type' are the same header.
|
|
184
199
|
def handle_headers(ex, headers)
|
|
185
|
-
handle_value(ex, headers)
|
|
200
|
+
normalized = Robustness.normalize_headers(handle_value(ex, headers))
|
|
201
|
+
normalized.each_pair do |key,value|
|
|
186
202
|
@response[key] ||= handle_value(ex, value)
|
|
187
203
|
end
|
|
188
204
|
end
|
|
@@ -203,7 +219,7 @@ module Rack
|
|
|
203
219
|
|
|
204
220
|
def last_resort(ex)
|
|
205
221
|
[ 500,
|
|
206
|
-
{'
|
|
222
|
+
{'content-type' => 'text/plain'},
|
|
207
223
|
[ 'An internal error occured, sorry for the disagreement.' ] ]
|
|
208
224
|
end
|
|
209
225
|
|
data/spec/test_context.rb
CHANGED
|
@@ -33,13 +33,13 @@ describe Rack::Robustness, 'the context in which blocks execute' do
|
|
|
33
33
|
|
|
34
34
|
it 'should let `env`, `request` and `response` be available in all blocks' do
|
|
35
35
|
get '/argument-error'
|
|
36
|
-
last_response.status.
|
|
37
|
-
last_response.body.
|
|
36
|
+
expect(last_response.status).to eq(400)
|
|
37
|
+
expect(last_response.body).to eq('argument-error')
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
it 'executes the ensure block as well' do
|
|
41
41
|
get '/argument-error'
|
|
42
|
-
$seen_ex.
|
|
42
|
+
expect($seen_ex).to be_a(ArgumentError)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
end
|
data/spec/test_ensure.rb
CHANGED
|
@@ -18,20 +18,20 @@ describe Rack::Robustness, 'ensure' do
|
|
|
18
18
|
|
|
19
19
|
it 'should be called in all cases when an error occurs' do
|
|
20
20
|
get '/argument-error'
|
|
21
|
-
last_response.status.
|
|
22
|
-
last_response.body.
|
|
23
|
-
$seen_true.
|
|
24
|
-
$seen_false.
|
|
25
|
-
$seen_none.
|
|
21
|
+
expect(last_response.status).to eq(400)
|
|
22
|
+
expect(last_response.body).to eq("error")
|
|
23
|
+
expect($seen_true).to eq([ArgumentError])
|
|
24
|
+
expect($seen_false).to eq([ArgumentError])
|
|
25
|
+
expect($seen_none).to eq([ArgumentError])
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it 'should not be called when explicit bypass on happy paths' do
|
|
29
29
|
get '/happy'
|
|
30
|
-
last_response.status.
|
|
31
|
-
last_response.body.
|
|
32
|
-
$seen_true.
|
|
33
|
-
$seen_false.
|
|
34
|
-
$seen_none.
|
|
30
|
+
expect(last_response.status).to eq(200)
|
|
31
|
+
expect(last_response.body).to eq("happy")
|
|
32
|
+
expect($seen_true).to be_nil
|
|
33
|
+
expect($seen_false).to eq([NilClass])
|
|
34
|
+
expect($seen_none).to eq([NilClass])
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# The Rack 3 SPEC requires response header names to be lowercase: "Header keys
|
|
4
|
+
# must not contain uppercase ASCII characters (A-Z)".
|
|
5
|
+
#
|
|
6
|
+
# These examples look at the raw response triple on purpose. Rack::Test, and
|
|
7
|
+
# Rack::Response itself, normalize header names on read, so going through
|
|
8
|
+
# `last_response` would hide both a capitalized name and a duplicated one.
|
|
9
|
+
describe Rack::Robustness, 'header names' do
|
|
10
|
+
|
|
11
|
+
def headers_of(app)
|
|
12
|
+
_, headers, _ = app.to_app.call(Rack::MockRequest.env_for("/"))
|
|
13
|
+
headers
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def failing_app(&bl)
|
|
17
|
+
Rack::Builder.new do
|
|
18
|
+
use Rack::Robustness, &bl
|
|
19
|
+
run lambda{|env| raise ArgumentError, "an argument error" }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context 'with the default configuration' do
|
|
24
|
+
it 'emits a lowercase content-type' do
|
|
25
|
+
expect(headers_of(failing_app).keys).to eq(['content-type'])
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'on the happy path' do
|
|
30
|
+
let(:app) {
|
|
31
|
+
Rack::Builder.new do
|
|
32
|
+
use Rack::Robustness
|
|
33
|
+
run lambda{|env| [200, {'Content-Type' => 'text/plain'}, ['happy']] }
|
|
34
|
+
end
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
it 'emits lowercase names, whatever the application uses' do
|
|
38
|
+
expect(headers_of(app)).to eq({'content-type' => 'text/plain'})
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context 'when the DSL is given capitalized names' do
|
|
43
|
+
it 'emits them lowercased, without duplicating content-type' do
|
|
44
|
+
app = failing_app do |g|
|
|
45
|
+
g.headers 'Content-Type' => 'text/test', 'X-Foo' => 'Bar'
|
|
46
|
+
end
|
|
47
|
+
expect(headers_of(app)).to eq({
|
|
48
|
+
'content-type' => 'text/test',
|
|
49
|
+
'x-foo' => 'Bar'
|
|
50
|
+
})
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Before 2.0.0 the default headers were keyed 'Content-Type', so configuring
|
|
55
|
+
# 'content-type' added a *second* entry rather than overriding. Since the
|
|
56
|
+
# clauses are applied with `||=`, the default won and the configured value
|
|
57
|
+
# was silently dropped -- and lowercase is precisely what Rack 3 users write.
|
|
58
|
+
context 'when the DSL overrides a default header in another case' do
|
|
59
|
+
['content-type', 'Content-Type', 'CONTENT-TYPE'].each do |name|
|
|
60
|
+
it "honours the value given as #{name}" do
|
|
61
|
+
app = failing_app{|g| g.headers name => 'application/json' }
|
|
62
|
+
expect(headers_of(app)).to eq({'content-type' => 'application/json'})
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'when a headers block returns capitalized names' do
|
|
68
|
+
it 'emits them lowercased' do
|
|
69
|
+
app = failing_app do |g|
|
|
70
|
+
g.headers{|ex| { 'Content-Type' => 'text/test', 'X-Foo' => 'Bar' } }
|
|
71
|
+
end
|
|
72
|
+
expect(headers_of(app)).to eq({
|
|
73
|
+
'content-type' => 'text/test',
|
|
74
|
+
'x-foo' => 'Bar'
|
|
75
|
+
})
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context 'when a rescue clause returns capitalized names' do
|
|
80
|
+
it 'emits them lowercased' do
|
|
81
|
+
app = failing_app do |g|
|
|
82
|
+
g.rescue(ArgumentError){|ex| [400, {'X-Foo' => 'Bar'}, ['nope']] }
|
|
83
|
+
end
|
|
84
|
+
expect(headers_of(app).keys.sort).to eq(['content-type', 'x-foo'])
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context 'in last resort' do
|
|
89
|
+
it 'emits a lowercase content-type' do
|
|
90
|
+
app = Rack::Builder.new do
|
|
91
|
+
use(Rack::Robustness){|g| g.response{|ex| NoSuchResponseClass.new } }
|
|
92
|
+
run lambda{|env| raise ArgumentError, "an argument error" }
|
|
93
|
+
end
|
|
94
|
+
expect(headers_of(app).keys).to eq(['content-type'])
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
data/spec/test_last_resort.rb
CHANGED
|
@@ -16,16 +16,16 @@ describe Rack::Robustness, 'last resort' do
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
it 'reraises the internal error' do
|
|
19
|
-
|
|
19
|
+
expect{
|
|
20
20
|
get '/argument-error'
|
|
21
|
-
}.
|
|
21
|
+
}.to raise_error(NameError, /NoSuchResponseClass/)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'passes into the ensure block with the original error' do
|
|
25
|
-
|
|
25
|
+
expect{
|
|
26
26
|
get '/argument-error'
|
|
27
|
-
}.
|
|
28
|
-
$seen_ex.
|
|
27
|
+
}.to raise_error(NameError, /NoSuchResponseClass/)
|
|
28
|
+
expect($seen_ex).to be_a(ArgumentError)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -38,9 +38,9 @@ describe Rack::Robustness, 'last resort' do
|
|
|
38
38
|
|
|
39
39
|
it 'falls back to last resort response' do
|
|
40
40
|
get '/argument-error'
|
|
41
|
-
last_response.status.
|
|
42
|
-
last_response.content_type.
|
|
43
|
-
last_response.body.
|
|
41
|
+
expect(last_response.status).to eq(500)
|
|
42
|
+
expect(last_response.content_type).to eq("text/plain")
|
|
43
|
+
expect(last_response.body).to eq("An internal error occured, sorry for the disagreement.")
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
@@ -53,9 +53,9 @@ describe Rack::Robustness, 'last resort' do
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
it 'reraises the internal error' do
|
|
56
|
-
|
|
56
|
+
expect{
|
|
57
57
|
get '/argument-error'
|
|
58
|
-
}.
|
|
58
|
+
}.to raise_error(NameError, /NoSuchResponseClass/)
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
@@ -68,9 +68,9 @@ describe Rack::Robustness, 'last resort' do
|
|
|
68
68
|
|
|
69
69
|
it 'reraises the internal error' do
|
|
70
70
|
get '/argument-error'
|
|
71
|
-
last_response.status.
|
|
72
|
-
last_response.content_type.
|
|
73
|
-
last_response.body.
|
|
71
|
+
expect(last_response.status).to eq(500)
|
|
72
|
+
expect(last_response.content_type).to eq("text/plain")
|
|
73
|
+
expect(last_response.body).to eq("An internal error occured, sorry for the disagreement.")
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
@@ -88,10 +88,10 @@ describe Rack::Robustness, 'last resort' do
|
|
|
88
88
|
|
|
89
89
|
it 'sets a default response object for the ensure clause' do
|
|
90
90
|
get '/argument-error'
|
|
91
|
-
last_response.status.
|
|
92
|
-
last_response.content_type.
|
|
93
|
-
last_response.body.
|
|
94
|
-
$seen_response.
|
|
91
|
+
expect(last_response.status).to eq(500)
|
|
92
|
+
expect(last_response.content_type).to eq("text/plain")
|
|
93
|
+
expect(last_response.body).to eq("An internal error occured, sorry for the disagreement.")
|
|
94
|
+
expect($seen_response).to_not be_nil
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
|
data/spec/test_rescue.rb
CHANGED
|
@@ -13,20 +13,20 @@ describe Rack::Robustness, 'rescue' do
|
|
|
13
13
|
|
|
14
14
|
it 'correctly rescues specified errors' do
|
|
15
15
|
get '/argument-error'
|
|
16
|
-
last_response.status.
|
|
17
|
-
last_response.body.
|
|
16
|
+
expect(last_response.status).to eq(400)
|
|
17
|
+
expect(last_response.body).to eq("argument-error")
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
it 'correctly support a non-block shortcut' do
|
|
21
21
|
get '/security-error'
|
|
22
|
-
last_response.status.
|
|
23
|
-
last_response.body.
|
|
22
|
+
expect(last_response.status).to eq(400)
|
|
23
|
+
expect(last_response.body).to eq("security-error")
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
it 'is has a `on` alias' do
|
|
27
27
|
get '/type-error'
|
|
28
|
-
last_response.status.
|
|
29
|
-
last_response.body.
|
|
28
|
+
expect(last_response.status).to eq(400)
|
|
29
|
+
expect(last_response.body).to eq("type-error")
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
end
|
data/spec/test_response.rb
CHANGED
|
@@ -24,17 +24,17 @@ describe Rack::Robustness, 'response' do
|
|
|
24
24
|
|
|
25
25
|
it 'correctly sets the status' do
|
|
26
26
|
get '/argument-error'
|
|
27
|
-
last_response.status.
|
|
27
|
+
expect(last_response.status).to eq(400)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
xit 'correctly sets the body' do
|
|
31
31
|
get '/argument-error'
|
|
32
|
-
last_response.body.
|
|
32
|
+
expect(last_response.body).to eq("response text")
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it 'correctly sets the content type' do
|
|
36
36
|
get '/argument-error'
|
|
37
|
-
last_response.content_type.
|
|
37
|
+
expect(last_response.content_type).to eq("application/json")
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
end
|