goliath 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of goliath might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/goliath.gemspec +1 -0
- data/lib/goliath/connection.rb +15 -11
- data/lib/goliath/constants.rb +1 -0
- data/lib/goliath/rack/default_response_format.rb +3 -9
- data/lib/goliath/rack/formatters/json.rb +1 -1
- data/lib/goliath/rack/params.rb +1 -1
- data/lib/goliath/request.rb +35 -18
- data/lib/goliath/response.rb +2 -0
- data/lib/goliath/version.rb +1 -1
- data/spec/integration/async_request_processing.rb +2 -2
- data/spec/integration/chunked_streaming_spec.rb +1 -1
- data/spec/integration/early_abort_spec.rb +5 -5
- data/spec/integration/echo_spec.rb +7 -7
- data/spec/integration/empty_body_spec.rb +2 -2
- data/spec/integration/event_stream_spec.rb +3 -3
- data/spec/integration/exception_handling_spec.rb +16 -16
- data/spec/integration/http_log_spec.rb +16 -16
- data/spec/integration/jsonp_spec.rb +6 -6
- data/spec/integration/keepalive_spec.rb +2 -2
- data/spec/integration/pipelining_spec.rb +3 -3
- data/spec/integration/reloader_spec.rb +3 -3
- data/spec/integration/template_spec.rb +7 -7
- data/spec/integration/test_helper_spec.rb +3 -3
- data/spec/integration/trace_spec.rb +2 -2
- data/spec/integration/valid_spec.rb +8 -8
- data/spec/integration/websocket_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -3
- data/spec/unit/api_spec.rb +1 -1
- data/spec/unit/connection_spec.rb +8 -8
- data/spec/unit/console_spec.rb +3 -3
- data/spec/unit/env_spec.rb +9 -9
- data/spec/unit/headers_spec.rb +8 -8
- data/spec/unit/rack/default_mime_type_spec.rb +3 -3
- data/spec/unit/rack/formatters/json_spec.rb +35 -13
- data/spec/unit/rack/formatters/plist_spec.rb +8 -8
- data/spec/unit/rack/formatters/xml_spec.rb +18 -18
- data/spec/unit/rack/formatters/yaml_spec.rb +13 -13
- data/spec/unit/rack/heartbeat_spec.rb +15 -15
- data/spec/unit/rack/params_spec.rb +62 -60
- data/spec/unit/rack/render_spec.rb +14 -14
- data/spec/unit/rack/validation/boolean_value_spec.rb +6 -6
- data/spec/unit/rack/validation/default_params_spec.rb +13 -13
- data/spec/unit/rack/validation/numeric_range_spec.rb +17 -17
- data/spec/unit/rack/validation/param_spec.rb +75 -75
- data/spec/unit/rack/validation/request_method_spec.rb +9 -9
- data/spec/unit/rack/validation/required_param_spec.rb +28 -28
- data/spec/unit/rack/validation/required_value_spec.rb +19 -19
- data/spec/unit/request_spec.rb +18 -18
- data/spec/unit/response_spec.rb +6 -6
- data/spec/unit/runner_spec.rb +31 -31
- data/spec/unit/server_spec.rb +21 -21
- data/spec/unit/validation/standard_http_errors_spec.rb +6 -6
- metadata +16 -2
data/spec/unit/headers_spec.rb
CHANGED
@@ -8,46 +8,46 @@ describe Goliath::Headers do
|
|
8
8
|
|
9
9
|
it 'outputs in the correct format' do
|
10
10
|
@h['my_header'] = 'my_value'
|
11
|
-
@h.to_s.
|
11
|
+
expect(@h.to_s).to eq("my_header: my_value\r\n")
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'suppresses duplicate keys' do
|
15
15
|
@h['my_header'] = 'my_value1'
|
16
16
|
@h['my_header'] = 'my_value2'
|
17
|
-
@h.to_s.
|
17
|
+
expect(@h.to_s).to eq("my_header: my_value1\r\n")
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'returns true if a key has been set' do
|
21
21
|
@h['my_header'] = 'my_value'
|
22
|
-
@h.has_key?('my_header').
|
22
|
+
expect(@h.has_key?('my_header')).to be true
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'returns false if the key has not been set' do
|
26
|
-
@h.has_key?('my_header').
|
26
|
+
expect(@h.has_key?('my_header')).to be false
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'ignores nil values' do
|
30
30
|
@h['my_header'] = nil
|
31
|
-
@h.to_s.
|
31
|
+
expect(@h.to_s).to eq('')
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'allows a value after setting nil' do
|
35
35
|
@h['my_header'] = nil
|
36
36
|
@h['my_header'] = 'my_value'
|
37
|
-
@h.to_s.
|
37
|
+
expect(@h.to_s).to eq("my_header: my_value\r\n")
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'formats time as an http time' do
|
41
41
|
time = Time.now
|
42
42
|
@h['my_time'] = time
|
43
|
-
@h.to_s.
|
43
|
+
expect(@h.to_s).to eq("my_time: #{time.httpdate}\r\n")
|
44
44
|
end
|
45
45
|
|
46
46
|
%w(Set-Cookie Set-Cookie2 Warning WWW-Authenticate).each do |key|
|
47
47
|
it "allows #{key} as to be duplicate" do
|
48
48
|
@h[key] = 'value1'
|
49
49
|
@h[key] = 'value2'
|
50
|
-
@h.to_s.
|
50
|
+
expect(@h.to_s).to eq("#{key}: value1\r\n#{key}: value2\r\n")
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -14,21 +14,21 @@ describe Goliath::Rack::DefaultMimeType do
|
|
14
14
|
context 'accept header cleanup' do
|
15
15
|
it 'handles a nil header' do
|
16
16
|
env['HTTP_ACCEPT'] = nil
|
17
|
-
|
17
|
+
expect { dmt.call(env) }.not_to raise_error
|
18
18
|
end
|
19
19
|
|
20
20
|
%w(gzip deflate compressed identity).each do |type|
|
21
21
|
it "removes #{type} from the accept header" do
|
22
22
|
env['HTTP_ACCEPT'] = "text/html, #{type}, text/javascript"
|
23
23
|
dmt.call(env)
|
24
|
-
env['HTTP_ACCEPT'].
|
24
|
+
expect(env['HTTP_ACCEPT']).to eq('text/html, text/javascript')
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'sets to */* if all entries removed' do
|
29
29
|
env['HTTP_ACCEPT'] = 'identity'
|
30
30
|
dmt.call(env)
|
31
|
-
env['HTTP_ACCEPT'].
|
31
|
+
expect(env['HTTP_ACCEPT']).to eq('*/*')
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -3,7 +3,7 @@ require 'goliath/rack/formatters/json'
|
|
3
3
|
|
4
4
|
describe Goliath::Rack::Formatters::JSON do
|
5
5
|
it 'accepts an app' do
|
6
|
-
|
6
|
+
expect { Goliath::Rack::Formatters::JSON.new('my app') }.not_to raise_error
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'with a formatter' do
|
@@ -13,41 +13,63 @@ describe Goliath::Rack::Formatters::JSON do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'checks content type for application/json' do
|
16
|
-
@js.json_response?({'Content-Type' => 'application/json'}).
|
16
|
+
expect(@js.json_response?({'Content-Type' => 'application/json'})).to be_truthy
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'checks content type for application/vnd.api+json' do
|
20
|
+
expect(@js.json_response?({'Content-Type' => 'application/vnd.api+json'})).to be_truthy
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'checks content type for application/javascript' do
|
24
|
+
expect(@js.json_response?({'Content-Type' => 'application/javascript'})).to be_truthy
|
17
25
|
end
|
18
26
|
|
19
27
|
it 'returns false for non-applicaton/json types' do
|
20
|
-
@js.json_response?({'Content-Type' => 'application/xml'}).
|
28
|
+
expect(@js.json_response?({'Content-Type' => 'application/xml'})).to be_falsey
|
21
29
|
end
|
22
30
|
|
23
31
|
it 'calls the app with the provided environment' do
|
24
32
|
env_mock = double('env').as_null_object
|
25
|
-
@app.
|
33
|
+
expect(@app).to receive(:call).with(env_mock).and_return([200, {}, {"a" => 1}])
|
26
34
|
@js.call(env_mock)
|
27
35
|
end
|
28
36
|
|
29
37
|
it 'formats the body into json if content-type is json' do
|
30
|
-
@app.
|
38
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/json'}, {:a => 1, :b => 2}])
|
39
|
+
|
40
|
+
status, header, body = @js.call({})
|
41
|
+
expect { expect(MultiJson.load(body.first)['a']).to eq(1) }.not_to raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'formats the body into json if content-type is vnd.api+json' do
|
45
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/vnd.api+json'}, {:a => 1, :b => 2}])
|
46
|
+
|
47
|
+
status, header, body = @js.call({})
|
48
|
+
expect { expect(MultiJson.load(body.first)['a']).to eq(1) }.not_to raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'formats the body into json if content-type is javascript' do
|
52
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/javascript'}, {:a => 1, :b => 2}])
|
31
53
|
|
32
54
|
status, header, body = @js.call({})
|
33
|
-
|
55
|
+
expect { expect(MultiJson.load(body.first)['a']).to eq(1) }.not_to raise_error
|
34
56
|
end
|
35
57
|
|
36
58
|
it "doesn't format to json if the type is not application/json" do
|
37
|
-
@app.
|
59
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, {:a => 1, :b => 2}])
|
38
60
|
|
39
|
-
MultiJson.
|
61
|
+
expect(MultiJson).not_to receive(:dump)
|
40
62
|
status, header, body = @js.call({})
|
41
|
-
body[:a].
|
63
|
+
expect(body[:a]).to eq(1)
|
42
64
|
end
|
43
65
|
|
44
66
|
it 'returns the status and headers' do
|
45
|
-
@app.
|
67
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, {:a => 1, :b => 2}])
|
46
68
|
|
47
|
-
MultiJson.
|
69
|
+
expect(MultiJson).not_to receive(:dump)
|
48
70
|
status, header, body = @js.call({})
|
49
|
-
status.
|
50
|
-
header.
|
71
|
+
expect(status).to eq(200)
|
72
|
+
expect(header).to eq({'Content-Type' => 'application/xml'})
|
51
73
|
end
|
52
74
|
end
|
53
75
|
end
|
@@ -17,7 +17,7 @@ describe Goliath::Rack::Formatters::PLIST do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'accepts an app' do
|
20
|
-
|
20
|
+
expect { Goliath::Rack::Formatters::PLIST.new('my app') }.not_to raise_error
|
21
21
|
end
|
22
22
|
|
23
23
|
describe 'with a formatter' do
|
@@ -27,23 +27,23 @@ describe Goliath::Rack::Formatters::PLIST do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'formats the body into plist if content-type is plist' do
|
30
|
-
@app.
|
30
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/x-plist'}, {:a => 1, :b => 2}])
|
31
31
|
|
32
32
|
status, header, body = @m.call({})
|
33
|
-
body.
|
33
|
+
expect(body).to eq(["plist: {:a=>1, :b=>2}"])
|
34
34
|
end
|
35
35
|
|
36
36
|
it "doesn't format to plist if the type is not plist" do
|
37
|
-
@app.
|
37
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, {:a => 1, :b => 2}])
|
38
38
|
status, header, body = @m.call({})
|
39
|
-
status.
|
40
|
-
header.
|
39
|
+
expect(status).to eq(200)
|
40
|
+
expect(header).to eq({'Content-Type' => 'application/xml'})
|
41
41
|
|
42
|
-
body[:a].
|
42
|
+
expect(body[:a]).to eq(1)
|
43
43
|
end
|
44
44
|
|
45
45
|
it 'returns the status and headers' do
|
46
|
-
@app.
|
46
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, {:a => 1, :b => 2}])
|
47
47
|
|
48
48
|
status, header, body = @m.call({})
|
49
49
|
end
|
@@ -4,7 +4,7 @@ require 'nokogiri'
|
|
4
4
|
|
5
5
|
describe Goliath::Rack::Formatters::XML do
|
6
6
|
it 'accepts an app' do
|
7
|
-
|
7
|
+
expect { Goliath::Rack::Formatters::XML.new('my app') }.not_to raise_error
|
8
8
|
end
|
9
9
|
|
10
10
|
describe 'with a formatter' do
|
@@ -14,52 +14,52 @@ describe Goliath::Rack::Formatters::XML do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'checks content type for application/xml' do
|
17
|
-
@xml.xml_response?({'Content-Type' => 'application/xml'}).
|
17
|
+
expect(@xml.xml_response?({'Content-Type' => 'application/xml'})).to be_truthy
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'returns false for non-applicaton/xml types' do
|
21
|
-
@xml.xml_response?({'Content-Type' => 'application/json'}).
|
21
|
+
expect(@xml.xml_response?({'Content-Type' => 'application/json'})).to be_falsey
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'calls the app with the provided environment' do
|
25
25
|
env_mock = double('env').as_null_object
|
26
|
-
@app.
|
26
|
+
expect(@app).to receive(:call).with(env_mock).and_return([200, {}, {"a" => 1}])
|
27
27
|
@xml.call(env_mock)
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'formats the body into xml if content-type is xml' do
|
31
|
-
@app.
|
31
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, {:a => 1, :b => 2}])
|
32
32
|
|
33
33
|
status, header, body = @xml.call({})
|
34
|
-
|
34
|
+
expect { expect(Nokogiri.parse(body.first).search('a').inner_text).to eq('1') }.not_to raise_error
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'generates arrays correctly' do
|
38
|
-
@app.
|
38
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, [1, 2]])
|
39
39
|
|
40
40
|
status, header, body = @xml.call({})
|
41
|
-
|
41
|
+
expect {
|
42
42
|
doc = Nokogiri.parse(body.first)
|
43
|
-
doc.search('item').first.inner_text.
|
44
|
-
doc.search('item').last.inner_text.
|
45
|
-
}.
|
43
|
+
expect(doc.search('item').first.inner_text).to eq('1')
|
44
|
+
expect(doc.search('item').last.inner_text).to eq('2')
|
45
|
+
}.not_to raise_error
|
46
46
|
end
|
47
47
|
|
48
48
|
it "doesn't format to xml if the type is not application/xml" do
|
49
|
-
@app.
|
49
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/json'}, {:a => 1, :b => 2}])
|
50
50
|
|
51
|
-
@xml.
|
51
|
+
expect(@xml).not_to receive(:to_xml)
|
52
52
|
status, header, body = @xml.call({})
|
53
|
-
body[:a].
|
53
|
+
expect(body[:a]).to eq(1)
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'returns the status and headers' do
|
57
|
-
@app.
|
57
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/json'}, {:a => 1, :b => 2}])
|
58
58
|
|
59
|
-
@xml.
|
59
|
+
expect(@xml).not_to receive(:to_xml)
|
60
60
|
status, header, body = @xml.call({})
|
61
|
-
status.
|
62
|
-
header.
|
61
|
+
expect(status).to eq(200)
|
62
|
+
expect(header).to eq({'Content-Type' => 'application/json'})
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
@@ -3,7 +3,7 @@ require 'goliath/rack/formatters/yaml'
|
|
3
3
|
|
4
4
|
describe Goliath::Rack::Formatters::YAML do
|
5
5
|
it 'accepts an app' do
|
6
|
-
|
6
|
+
expect { Goliath::Rack::Formatters::YAML.new('my app') }.not_to raise_error
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'with a formatter' do
|
@@ -13,41 +13,41 @@ describe Goliath::Rack::Formatters::YAML do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'checks content type for text/yaml' do
|
16
|
-
@ym.yaml_response?({'Content-Type' => 'text/yaml'}).
|
16
|
+
expect(@ym.yaml_response?({'Content-Type' => 'text/yaml'})).to be_truthy
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'returns false for non-applicaton/yaml types' do
|
20
|
-
@ym.yaml_response?({'Content-Type' => 'application/xml'}).
|
20
|
+
expect(@ym.yaml_response?({'Content-Type' => 'application/xml'})).to be_falsey
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'calls the app with the provided environment' do
|
24
24
|
env_mock = double('env').as_null_object
|
25
|
-
@app.
|
25
|
+
expect(@app).to receive(:call).with(env_mock).and_return([200, {}, {"a" => 1}])
|
26
26
|
@ym.call(env_mock)
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'formats the body into yaml if content-type is yaml' do
|
30
|
-
@app.
|
30
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'text/yaml'}, {:a => 1, :b => 2}])
|
31
31
|
|
32
32
|
status, header, body = @ym.call({})
|
33
|
-
|
33
|
+
expect { expect(YAML.load(body.first)[:a]).to eq(1) }.not_to raise_error
|
34
34
|
end
|
35
35
|
|
36
36
|
it "doesn't format to yaml if the type is not text/yaml" do
|
37
|
-
@app.
|
37
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, {:a => 1, :b => 2}])
|
38
38
|
|
39
|
-
YAML.
|
39
|
+
expect(YAML).not_to receive(:encode)
|
40
40
|
status, header, body = @ym.call({})
|
41
|
-
body[:a].
|
41
|
+
expect(body[:a]).to eq(1)
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'returns the status and headers' do
|
45
|
-
@app.
|
45
|
+
expect(@app).to receive(:call).and_return([200, {'Content-Type' => 'application/xml'}, {:a => 1, :b => 2}])
|
46
46
|
|
47
|
-
YAML.
|
47
|
+
expect(YAML).not_to receive(:encode)
|
48
48
|
status, header, body = @ym.call({})
|
49
|
-
status.
|
50
|
-
header.
|
49
|
+
expect(status).to eq(200)
|
50
|
+
expect(header).to eq({'Content-Type' => 'application/xml'})
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -4,7 +4,7 @@ require 'goliath/env'
|
|
4
4
|
|
5
5
|
describe Goliath::Rack::Heartbeat do
|
6
6
|
it 'accepts an app' do
|
7
|
-
|
7
|
+
expect { Goliath::Rack::Heartbeat.new('my app') }.not_to raise_error
|
8
8
|
end
|
9
9
|
|
10
10
|
describe 'with the middleware' do
|
@@ -16,54 +16,54 @@ describe Goliath::Rack::Heartbeat do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'allows /status as a path prefix' do
|
19
|
-
@app.
|
19
|
+
expect(@app).to receive(:call)
|
20
20
|
@env['PATH_INFO'] = '/status_endpoint'
|
21
21
|
@hb.call(@env)
|
22
22
|
end
|
23
23
|
|
24
24
|
it "doesn't call the app when request /status" do
|
25
|
-
@app.
|
25
|
+
expect(@app).not_to receive(:call)
|
26
26
|
@env['PATH_INFO'] = '/status'
|
27
27
|
@hb.call(@env)
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'returns the status, headers and body from the app on non-/status' do
|
31
31
|
@env['PATH_INFO'] = '/v1'
|
32
|
-
@app.
|
32
|
+
expect(@app).to receive(:call).and_return([200, {'a' => 'b'}, {'c' => 'd'}])
|
33
33
|
status, headers, body = @hb.call(@env)
|
34
|
-
status.
|
35
|
-
headers.
|
36
|
-
body.
|
34
|
+
expect(status).to eq(200)
|
35
|
+
expect(headers).to eq({'a' => 'b'})
|
36
|
+
expect(body).to eq({'c' => 'd'})
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'returns the correct status, headers and body on /status' do
|
40
40
|
@env['PATH_INFO'] = '/status'
|
41
41
|
status, headers, body = @hb.call(@env)
|
42
|
-
status.
|
43
|
-
headers.
|
44
|
-
body.
|
42
|
+
expect(status).to eq(200)
|
43
|
+
expect(headers).to eq({})
|
44
|
+
expect(body).to eq('OK')
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'allows path and response to be set using options' do
|
48
48
|
@hb = Goliath::Rack::Heartbeat.new(@app, :path => '/isup', :response => [204, {}, nil])
|
49
49
|
@env['PATH_INFO'] = '/isup'
|
50
50
|
status, headers, body = @hb.call(@env)
|
51
|
-
status.
|
52
|
-
headers.
|
53
|
-
body.
|
51
|
+
expect(status).to eq(204)
|
52
|
+
expect(headers).to eq({})
|
53
|
+
expect(body).to eq(nil)
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'does not log the request by default' do
|
57
57
|
@env['PATH_INFO'] = '/status'
|
58
58
|
@hb.call(@env)
|
59
|
-
@env[Goliath::Constants::RACK_LOGGER].
|
59
|
+
expect(@env[Goliath::Constants::RACK_LOGGER]).to eq(Log4r::Logger.root)
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'logs the request only if asked' do
|
63
63
|
@env['PATH_INFO'] = '/status'
|
64
64
|
@hb = Goliath::Rack::Heartbeat.new(@app, :log => true)
|
65
65
|
@hb.call(@env)
|
66
|
-
@env[Goliath::Constants::RACK_LOGGER].
|
66
|
+
expect(@env[Goliath::Constants::RACK_LOGGER]).not_to eq(Log4r::Logger.root)
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
@@ -3,7 +3,7 @@ require 'goliath/rack/params'
|
|
3
3
|
|
4
4
|
describe Goliath::Rack::Params do
|
5
5
|
it 'accepts an app' do
|
6
|
-
|
6
|
+
expect { Goliath::Rack::Params.new('my app') }.not_to raise_error
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'with middleware' do
|
@@ -32,15 +32,15 @@ describe Goliath::Rack::Params do
|
|
32
32
|
@env['QUERY_STRING'] = 'foo=bar&baz=bonkey'
|
33
33
|
|
34
34
|
ret = @params.retrieve_params(@env)
|
35
|
-
ret['foo'].
|
36
|
-
ret['baz'].
|
35
|
+
expect(ret['foo']).to eq('bar')
|
36
|
+
expect(ret['baz']).to eq('bonkey')
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'parses the nested query string' do
|
40
40
|
@env['QUERY_STRING'] = 'foo[bar]=baz'
|
41
41
|
|
42
42
|
ret = @params.retrieve_params(@env)
|
43
|
-
ret['foo'].
|
43
|
+
expect(ret['foo']).to eq({'bar' => 'baz'})
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'parses the post body' do
|
@@ -49,18 +49,18 @@ describe Goliath::Rack::Params do
|
|
49
49
|
@env['rack.input'].rewind
|
50
50
|
|
51
51
|
ret = @params.retrieve_params(@env)
|
52
|
-
ret['foo'].
|
53
|
-
ret['baz'].
|
54
|
-
ret['zonk'].
|
52
|
+
expect(ret['foo']).to eq('bar')
|
53
|
+
expect(ret['baz']).to eq('bonkey')
|
54
|
+
expect(ret['zonk']).to eq({'donk' => 'monk'})
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'parses arrays of data' do
|
58
58
|
@env['QUERY_STRING'] = 'foo[]=bar&foo[]=baz&foo[]=foos'
|
59
59
|
|
60
60
|
ret = @params.retrieve_params(@env)
|
61
|
-
ret['foo'].is_a?(Array).
|
62
|
-
ret['foo'].length.
|
63
|
-
ret['foo'].
|
61
|
+
expect(ret['foo'].is_a?(Array)).to be true
|
62
|
+
expect(ret['foo'].length).to eq(3)
|
63
|
+
expect(ret['foo']).to eq(%w(bar baz foos))
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'parses multipart data' do
|
@@ -80,8 +80,8 @@ Berry\r
|
|
80
80
|
@env[Goliath::Constants::CONTENT_LENGTH] = @env['rack.input'].length
|
81
81
|
|
82
82
|
ret = @params.retrieve_params(@env)
|
83
|
-
ret['submit-name'].
|
84
|
-
ret['submit-name-with-content'].
|
83
|
+
expect(ret['submit-name']).to eq('Larry')
|
84
|
+
expect(ret['submit-name-with-content']).to eq('Berry')
|
85
85
|
end
|
86
86
|
|
87
87
|
it 'combines query string and post body params' do
|
@@ -92,14 +92,14 @@ Berry\r
|
|
92
92
|
@env['rack.input'].rewind
|
93
93
|
|
94
94
|
ret = @params.retrieve_params(@env)
|
95
|
-
ret['baz'].
|
96
|
-
ret['foos'].
|
95
|
+
expect(ret['baz']).to eq('bar')
|
96
|
+
expect(ret['foos']).to eq('bonkey')
|
97
97
|
end
|
98
98
|
|
99
99
|
it 'handles empty query and post body' do
|
100
100
|
ret = @params.retrieve_params(@env)
|
101
|
-
ret.is_a?(Hash).
|
102
|
-
ret.
|
101
|
+
expect(ret.is_a?(Hash)).to be true
|
102
|
+
expect(ret).to be_empty
|
103
103
|
end
|
104
104
|
|
105
105
|
it 'prefers post body over query string' do
|
@@ -110,12 +110,12 @@ Berry\r
|
|
110
110
|
@env['rack.input'].rewind
|
111
111
|
|
112
112
|
ret = @params.retrieve_params(@env)
|
113
|
-
ret['foo'].
|
114
|
-
ret['baz'].
|
113
|
+
expect(ret['foo']).to eq('bar2')
|
114
|
+
expect(ret['baz']).to eq('bonkey')
|
115
115
|
end
|
116
116
|
|
117
117
|
it 'sets the params into the environment' do
|
118
|
-
@app.
|
118
|
+
expect(@app).to receive(:call).with(hash_including("params"=>{"a"=>"b"}))
|
119
119
|
|
120
120
|
@env['QUERY_STRING'] = "a=b"
|
121
121
|
@params.call(@env)
|
@@ -124,12 +124,12 @@ Berry\r
|
|
124
124
|
it 'returns status, headers and body from the app' do
|
125
125
|
app_headers = {'Content-Type' => 'hash'}
|
126
126
|
app_body = {:a => 1, :b => 2}
|
127
|
-
@app.
|
127
|
+
expect(@app).to receive(:call).and_return([200, app_headers, app_body])
|
128
128
|
|
129
129
|
status, headers, body = @params.call(@env)
|
130
|
-
status.
|
131
|
-
headers.
|
132
|
-
body.
|
130
|
+
expect(status).to eq(200)
|
131
|
+
expect(headers).to eq(app_headers)
|
132
|
+
expect(body).to eq(app_body)
|
133
133
|
end
|
134
134
|
|
135
135
|
it 'returns a validation error if one is raised while parsing' do
|
@@ -171,44 +171,46 @@ Berry\r
|
|
171
171
|
@env['rack.input'].rewind
|
172
172
|
|
173
173
|
ret = @params.retrieve_params(@env)
|
174
|
-
ret['foos'].
|
174
|
+
expect(ret['foos']).to eq('bonkey')
|
175
175
|
end
|
176
176
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
177
|
+
['application/json', 'application/vnd.api+json', 'application/javascript'].each do |content_type|
|
178
|
+
it "parses #{content_type}" do
|
179
|
+
@env['CONTENT_TYPE'] = content_type
|
180
|
+
@env['rack.input'] = StringIO.new
|
181
|
+
@env['rack.input'] << %|{"foo":"bar"}|
|
182
|
+
@env['rack.input'].rewind
|
183
|
+
|
184
|
+
ret = @params.retrieve_params(@env)
|
185
|
+
expect(ret['foo']).to eq('bar')
|
186
|
+
end
|
187
|
+
|
188
|
+
it "parses #{content_type} that does not evaluate to a hash" do
|
189
|
+
@env['CONTENT_TYPE'] = content_type
|
190
|
+
@env['rack.input'] = StringIO.new
|
191
|
+
@env['rack.input'] << %|["foo","bar"]|
|
192
|
+
@env['rack.input'].rewind
|
193
|
+
|
194
|
+
ret = @params.retrieve_params(@env)
|
195
|
+
expect(ret['_json']).to eq(['foo', 'bar'])
|
196
|
+
end
|
197
|
+
|
198
|
+
it "handles empty input gracefully on #{content_type} JSON" do
|
199
|
+
@env['CONTENT_TYPE'] = content_type
|
200
|
+
@env['rack.input'] = StringIO.new
|
201
|
+
|
202
|
+
ret = @params.retrieve_params(@env)
|
203
|
+
expect(ret).to be_empty
|
204
|
+
end
|
205
|
+
|
206
|
+
it "raises a BadRequestError on invalid #{content_type} JSON" do
|
207
|
+
@env['CONTENT_TYPE'] = content_type
|
208
|
+
@env['rack.input'] = StringIO.new
|
209
|
+
@env['rack.input'] << %|{"foo":"bar" BORKEN}|
|
210
|
+
@env['rack.input'].rewind
|
211
|
+
|
212
|
+
expect{ @params.retrieve_params(@env) }.to raise_error(Goliath::Validation::BadRequestError)
|
213
|
+
end
|
212
214
|
end
|
213
215
|
|
214
216
|
it "doesn't parse unknown content types" do
|
@@ -218,7 +220,7 @@ Berry\r
|
|
218
220
|
@env['rack.input'].rewind
|
219
221
|
|
220
222
|
ret = @params.retrieve_params(@env)
|
221
|
-
ret.
|
223
|
+
expect(ret).to eq({})
|
222
224
|
end
|
223
225
|
end
|
224
226
|
end
|