goliath 1.0.4 → 1.0.5

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.

Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -4
  3. data/goliath.gemspec +10 -7
  4. data/lib/goliath/api.rb +1 -1
  5. data/lib/goliath/rack/jsonp.rb +7 -2
  6. data/lib/goliath/rack/params.rb +3 -2
  7. data/lib/goliath/rack/validator.rb +1 -1
  8. data/lib/goliath/request.rb +2 -2
  9. data/lib/goliath/runner.rb +4 -3
  10. data/lib/goliath/server.rb +17 -2
  11. data/lib/goliath/test_helper_sse.rb +76 -0
  12. data/lib/goliath/validation/error.rb +4 -1
  13. data/lib/goliath/version.rb +1 -1
  14. data/spec/integration/early_abort_spec.rb +3 -3
  15. data/spec/integration/event_stream_spec.rb +50 -0
  16. data/spec/integration/exception_handling_spec.rb +202 -0
  17. data/spec/integration/jsonp_spec.rb +61 -10
  18. data/spec/integration/test_helper_spec.rb +1 -1
  19. data/spec/integration/valid_spec.rb +21 -1
  20. data/spec/unit/api_spec.rb +1 -1
  21. data/spec/unit/env_spec.rb +5 -5
  22. data/spec/unit/headers_spec.rb +2 -2
  23. data/spec/unit/rack/formatters/json_spec.rb +2 -2
  24. data/spec/unit/rack/formatters/xml_spec.rb +2 -2
  25. data/spec/unit/rack/formatters/yaml_spec.rb +2 -2
  26. data/spec/unit/rack/params_spec.rb +41 -6
  27. data/spec/unit/rack/validation/default_params_spec.rb +2 -2
  28. data/spec/unit/rack/validation/numeric_range_spec.rb +2 -2
  29. data/spec/unit/rack/validation/param_spec.rb +18 -18
  30. data/spec/unit/rack/validation/required_param_spec.rb +25 -25
  31. data/spec/unit/rack/validation/required_value_spec.rb +10 -10
  32. data/spec/unit/request_spec.rb +3 -3
  33. data/spec/unit/runner_spec.rb +1 -1
  34. data/spec/unit/server_spec.rb +4 -4
  35. metadata +135 -94
  36. data/examples/around.rb +0 -38
  37. data/examples/clone.rb +0 -26
  38. data/examples/router.rb +0 -15
  39. data/examples/test.rb +0 -31
  40. data/examples/upload.rb +0 -17
@@ -6,26 +6,77 @@ class JSON_API < Goliath::API
6
6
  use Goliath::Rack::Render, 'json'
7
7
 
8
8
  def response(env)
9
- [200, {'CONTENT_TYPE' => 'application/json'}, "OK"]
9
+ headers = {
10
+ 'CONTENT_TYPE' => 'application/json',
11
+ # Note: specifically not 'CONTENT_LENGTH'. 'Content-Length' gets set by
12
+ # AsyncRack::ContentLength if not already present. So if we set
13
+ # 'CONTENT_LENGTH', no problem - AsyncRack recalculates the body's
14
+ # content length anyway and stores it in the 'Content-Length' header. But
15
+ # if we set 'Content-Length', AsyncRack will avoid overwriting it. We
16
+ # thus want the JSONP middleware to react to the case where we've
17
+ # *already* set the 'Content-Length' header before hitting it.
18
+ 'Content-Length' => '2',
19
+ }
20
+ [200, headers, 'OK']
10
21
  end
11
22
  end
12
23
 
13
24
  describe 'JSONP' do
14
25
  let(:err) { Proc.new { fail "API request failed" } }
15
26
 
16
- it 'sets the content type' do
17
- with_api(JSON_API) do
18
- get_request({:query => {:callback => 'test'}}, err) do |c|
19
- c.response_header['CONTENT_TYPE'].should =~ %r{^application/javascript}
27
+ context 'without a callback param' do
28
+ let(:query) { {} }
29
+
30
+ it 'does not alter the content type' do
31
+ with_api(JSON_API) do
32
+ get_request({ query: query }, err) do |c|
33
+ c.response_header['CONTENT_TYPE'].should =~ %r{^application/json}
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'does not alter the content length' do
39
+ with_api(JSON_API) do
40
+ get_request({ query: query }, err) do |c|
41
+ c.response_header['CONTENT_LENGTH'].to_i.should == 2
42
+ end
43
+ end
44
+ end
45
+
46
+ it 'does not wrap the response with anything' do
47
+ with_api(JSON_API) do
48
+ get_request({ query: query }, err) do |c|
49
+ c.response.should == 'OK'
50
+ end
20
51
  end
21
52
  end
22
53
  end
23
54
 
24
- it 'wraps response with callback' do
25
- with_api(JSON_API) do
26
- get_request({:query => {:callback => 'test'}}, err) do |c|
27
- c.response.should =~ /^test\(.*\)$/
55
+ context 'with a callback param' do
56
+ let(:query) { { callback: 'test' } }
57
+
58
+ it 'adjusts the content type' do
59
+ with_api(JSON_API) do
60
+ get_request({ query: query }, err) do |c|
61
+ c.response_header['CONTENT_TYPE'].should =~ %r{^application/javascript}
62
+ end
63
+ end
64
+ end
65
+
66
+ it 'adjusts the content length' do
67
+ with_api(JSON_API) do
68
+ get_request({ query: query }, err) do |c|
69
+ c.response_header['CONTENT_LENGTH'].to_i.should == 8
70
+ end
71
+ end
72
+ end
73
+
74
+ it 'wraps response with callback' do
75
+ with_api(JSON_API) do
76
+ get_request({ query: query }, err) do |c|
77
+ c.response.should =~ /^test\(.*\)$/
78
+ end
28
79
  end
29
80
  end
30
81
  end
31
- end
82
+ end
@@ -11,7 +11,7 @@ describe "with_api" do
11
11
  with_api(DummyServer, :log_file => "test.log") do |api|
12
12
  get_request({},err)
13
13
  end
14
- File.exist?("test.log").should be_true
14
+ File.exist?("test.log").should be_truthy
15
15
  File.unlink("test.log")
16
16
  end
17
17
 
@@ -54,7 +54,7 @@ end
54
54
 
55
55
  class ValidationErrorInEndpoint < Goliath::API
56
56
  def response(env)
57
- raise Goliath::Validation::Error.new(420, 'You Must Chill')
57
+ raise Goliath::Validation::Error.new(420, 'You Must Chill', {'Foo' => 'Bar'})
58
58
  end
59
59
  end
60
60
 
@@ -66,8 +66,28 @@ describe ValidationErrorInEndpoint do
66
66
  get_request({}, err) do |c|
67
67
  c.response.should == '[:error, "You Must Chill"]'
68
68
  c.response_header.status.should == 420
69
+ c.response_header["Foo"].should == 'Bar'
69
70
  end
70
71
  end
71
72
  end
72
73
  end
73
74
 
75
+ class ValidationErrorWhileParsing < Goliath::API
76
+ def on_headers(env, headers)
77
+ raise Goliath::Validation::Error.new(420, 'You Must Chill', {'Foo' => 'Bar'})
78
+ end
79
+ end
80
+
81
+ describe ValidationErrorWhileParsing do
82
+ let(:err) { Proc.new { fail "API request failed" } }
83
+
84
+ it 'handles Goliath::Validation::Error correctly' do
85
+ with_api(ValidationErrorInEndpoint) do
86
+ get_request({}, err) do |c|
87
+ c.response.should == '[:error, "You Must Chill"]'
88
+ c.response_header.status.should == 420
89
+ c.response_header["Foo"].should == 'Bar'
90
+ end
91
+ end
92
+ end
93
+ end
@@ -7,7 +7,7 @@ describe Goliath::API do
7
7
 
8
8
  describe "middlewares" do
9
9
  it "doesn't change after multi calls" do
10
- 2.times { DummyApi.should have(2).middlewares }
10
+ 2.times { DummyApi.middlewares.size.should eq(2) }
11
11
  end
12
12
  end
13
13
  end
@@ -31,25 +31,25 @@ describe Goliath::Env do
31
31
  context '#respond_to?' do
32
32
  it 'returns true for items in the hash' do
33
33
  @env['test'] = 'true'
34
- @env.respond_to?(:test).should be_true
34
+ @env.respond_to?(:test).should be true
35
35
  end
36
36
 
37
37
  it 'returns false for items not in hash' do
38
- @env.respond_to?(:test).should be_false
38
+ @env.respond_to?(:test).should be false
39
39
  end
40
40
 
41
41
  it 'returns true for items in the config hash' do
42
42
  @env['config'] = {'test' => true}
43
- @env.respond_to?(:test).should be_true
43
+ @env.respond_to?(:test).should be true
44
44
  end
45
45
 
46
46
  it 'returns false for items not in the config hash' do
47
47
  @env['config'] = {}
48
- @env.respond_to?(:test).should be_false
48
+ @env.respond_to?(:test).should be false
49
49
  end
50
50
 
51
51
  it 'delegates if not found' do
52
- @env.respond_to?(:[]).should be_true
52
+ @env.respond_to?(:[]).should be true
53
53
  end
54
54
  end
55
55
  end
@@ -19,11 +19,11 @@ describe Goliath::Headers do
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').should be_true
22
+ @h.has_key?('my_header').should 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').should be_false
26
+ @h.has_key?('my_header').should be false
27
27
  end
28
28
 
29
29
  it 'ignores nil values' do
@@ -13,11 +13,11 @@ 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'}).should be_true
16
+ @js.json_response?({'Content-Type' => 'application/json'}).should be_truthy
17
17
  end
18
18
 
19
19
  it 'returns false for non-applicaton/json types' do
20
- @js.json_response?({'Content-Type' => 'application/xml'}).should be_false
20
+ @js.json_response?({'Content-Type' => 'application/xml'}).should be_falsey
21
21
  end
22
22
 
23
23
  it 'calls the app with the provided environment' do
@@ -14,11 +14,11 @@ 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'}).should be_true
17
+ @xml.xml_response?({'Content-Type' => 'application/xml'}).should 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'}).should be_false
21
+ @xml.xml_response?({'Content-Type' => 'application/json'}).should be_falsey
22
22
  end
23
23
 
24
24
  it 'calls the app with the provided environment' do
@@ -13,11 +13,11 @@ 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'}).should be_true
16
+ @ym.yaml_response?({'Content-Type' => 'text/yaml'}).should 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'}).should be_false
20
+ @ym.yaml_response?({'Content-Type' => 'application/xml'}).should be_falsey
21
21
  end
22
22
 
23
23
  it 'calls the app with the provided environment' do
@@ -21,6 +21,13 @@ describe Goliath::Rack::Params do
21
21
  }.to raise_error(Goliath::Validation::BadRequestError)
22
22
  end
23
23
 
24
+ it 'handles ambiguous query strings' do
25
+ @env['QUERY_STRING'] = 'ambiguous[]=&ambiguous[4]='
26
+ expect {
27
+ @params.retrieve_params(@env)
28
+ }.to raise_error(Goliath::Validation::Error)
29
+ end
30
+
24
31
  it 'parses the query string' do
25
32
  @env['QUERY_STRING'] = 'foo=bar&baz=bonkey'
26
33
 
@@ -51,7 +58,7 @@ describe Goliath::Rack::Params do
51
58
  @env['QUERY_STRING'] = 'foo[]=bar&foo[]=baz&foo[]=foos'
52
59
 
53
60
  ret = @params.retrieve_params(@env)
54
- ret['foo'].is_a?(Array).should be_true
61
+ ret['foo'].is_a?(Array).should be true
55
62
  ret['foo'].length.should == 3
56
63
  ret['foo'].should == %w(bar baz foos)
57
64
  end
@@ -91,7 +98,7 @@ Berry\r
91
98
 
92
99
  it 'handles empty query and post body' do
93
100
  ret = @params.retrieve_params(@env)
94
- ret.is_a?(Hash).should be_true
101
+ ret.is_a?(Hash).should be true
95
102
  ret.should be_empty
96
103
  end
97
104
 
@@ -108,10 +115,7 @@ Berry\r
108
115
  end
109
116
 
110
117
  it 'sets the params into the environment' do
111
- @app.should_receive(:call).with do |app_env|
112
- app_env.has_key?('params').should be_true
113
- app_env['params']['a'].should == 'b'
114
- end
118
+ @app.should receive(:call).with(hash_including("params"=>{"a"=>"b"}))
115
119
 
116
120
  @env['QUERY_STRING'] = "a=b"
117
121
  @params.call(@env)
@@ -128,6 +132,37 @@ Berry\r
128
132
  body.should == app_body
129
133
  end
130
134
 
135
+ it 'returns a validation error if one is raised while parsing' do
136
+ expect(@app).to_not receive(:call)
137
+ params_exception = Goliath::Validation::Error.new(423, 'invalid')
138
+ expect(@params).to receive(:retrieve_params).and_raise(params_exception)
139
+ status, headers, body = @params.call(@env)
140
+ expect(status).to eq 423
141
+ expect(headers).to eq({})
142
+ expect(body).to eq(error: 'invalid')
143
+ end
144
+
145
+ it 'returns a 500 error if an unexpected error is raised while parsing' do
146
+ expect(@app).to_not receive(:call)
147
+
148
+ params_exception = Exception.new('uh oh')
149
+ expect(@params).to receive(:retrieve_params).and_raise(params_exception)
150
+
151
+ logger = double('logger').as_null_object
152
+ expect(@env).to receive(:logger).twice.and_return(logger)
153
+
154
+ status, headers, body = @params.call(@env)
155
+ expect(status).to eq 500
156
+ expect(headers).to eq({})
157
+ expect(body).to eq(error: 'uh oh')
158
+ end
159
+
160
+ it 'does not swallow exceptions from the app' do
161
+ app_exception = Class.new(Exception)
162
+ expect(@app).to receive(:call).and_raise(app_exception)
163
+ expect { @params.call(@env) }.to raise_error(app_exception)
164
+ end
165
+
131
166
  context 'content type' do
132
167
  it "parses application/x-www-form-urlencoded" do
133
168
  @env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8'
@@ -8,11 +8,11 @@ describe Goliath::Rack::Validation::DefaultParams do
8
8
  end
9
9
 
10
10
  it 'requires defaults to be set' do
11
- lambda { Goliath::Rack::Validation::DefaultParams.new('my app', {:key => 'test'}) }.should raise_error
11
+ lambda { Goliath::Rack::Validation::DefaultParams.new('my app', {:key => 'test'}) }.should raise_error('Must provide defaults to DefaultParams')
12
12
  end
13
13
 
14
14
  it 'requires key to be set' do
15
- lambda { Goliath::Rack::Validation::DefaultParams.new('my app', {:defaults => 'test'}) }.should raise_error
15
+ lambda { Goliath::Rack::Validation::DefaultParams.new('my app', {:defaults => 'test'}) }.should raise_error('must provide key to DefaultParams')
16
16
  end
17
17
 
18
18
  describe 'with middleware' do
@@ -66,11 +66,11 @@ describe Goliath::Rack::Validation::NumericRange do
66
66
  end
67
67
 
68
68
  it 'raises error if key is not set' do
69
- lambda { Goliath::Rack::Validation::NumericRange.new('app', {:min => 5}) }.should raise_error
69
+ lambda { Goliath::Rack::Validation::NumericRange.new('app', {:min => 5}) }.should raise_error('NumericRange key required')
70
70
  end
71
71
 
72
72
  it 'raises error if neither min nor max set' do
73
- lambda { Goliath::Rack::Validation::NumericRange.new('app', {:key => 5}) }.should raise_error
73
+ lambda { Goliath::Rack::Validation::NumericRange.new('app', {:key => 5}) }.should raise_error('NumericRange requires :min or :max')
74
74
  end
75
75
 
76
76
  it 'uses min if default not set' do
@@ -10,7 +10,7 @@ describe Goliath::Rack::Validation::Param do
10
10
  it "should not allow invalid options" do
11
11
  lambda {
12
12
  Goliath::Rack::Validation::Param.new(@app, {:key => 'user', :as => Class.new})
13
- }.should raise_error
13
+ }.should raise_error(Exception)
14
14
  end
15
15
 
16
16
  it "raises if key is not supplied" do
@@ -21,7 +21,7 @@ describe Goliath::Rack::Validation::Param do
21
21
 
22
22
  it "uses a default value if optional is not supplied" do
23
23
  cv = Goliath::Rack::Validation::Param.new(@app, :key => 'key')
24
- cv.optional.should be_false
24
+ cv.optional.should be false
25
25
  end
26
26
 
27
27
  it "should have default and message be optional" do
@@ -40,7 +40,7 @@ describe Goliath::Rack::Validation::Param do
40
40
  lambda {
41
41
  cv = Goliath::Rack::Validation::Param.new(@app, {:key => 'flag',
42
42
  :as => Goliath::Rack::Types::Boolean, :animal => :monkey})
43
- }.should raise_error
43
+ }.should raise_error('Unknown options: {:animal=>:monkey}')
44
44
  end
45
45
 
46
46
  context "fetch_key" do
@@ -127,52 +127,52 @@ describe Goliath::Rack::Validation::Param do
127
127
 
128
128
  context 'key_valid?' do
129
129
  it 'raises exception if the key is not provided' do
130
- @rp.key_valid?(@env['params']).should be_false
130
+ @rp.key_valid?(@env['params']).should be false
131
131
  end
132
132
 
133
133
  it 'raises exception if the key is blank' do
134
134
  @env['params']['mk'] = ''
135
- @rp.key_valid?(@env['params']).should be_false
135
+ @rp.key_valid?(@env['params']).should be false
136
136
  end
137
137
 
138
138
  it 'raises exception if the key is nil' do
139
139
  @env['params']['mk'] = nil
140
- @rp.key_valid?(@env['params']).should be_false
140
+ @rp.key_valid?(@env['params']).should be false
141
141
  end
142
142
 
143
143
  it 'handles an empty array' do
144
144
  @env['params']['mk'] = []
145
- @rp.key_valid?(@env['params']).should be_false
145
+ @rp.key_valid?(@env['params']).should be false
146
146
  end
147
147
 
148
148
  it 'handles an array of nils' do
149
149
  @env['params']['mk'] = [nil, nil, nil]
150
- @rp.key_valid?(@env['params']).should be_false
150
+ @rp.key_valid?(@env['params']).should be false
151
151
  end
152
152
 
153
153
  it 'handles an array of blanks' do
154
154
  @env['params']['mk'] = ['', '', '']
155
- @rp.key_valid?(@env['params']).should be_false
155
+ @rp.key_valid?(@env['params']).should be false
156
156
  end
157
157
 
158
158
  it "doesn't raise if the key provided" do
159
159
  @env['params']['mk'] = 'my value'
160
- @rp.key_valid?(@env['params']).should be_true
160
+ @rp.key_valid?(@env['params']).should be true
161
161
  end
162
162
 
163
163
  it "doesn't raise if the array contains valid data" do
164
164
  @env['params']['mk'] = [1, 2, 3, 4]
165
- @rp.key_valid?(@env['params']).should be_true
165
+ @rp.key_valid?(@env['params']).should be true
166
166
  end
167
167
 
168
168
  it "doesn't raise if the key provided is multiline and has blanks" do
169
169
  @env['params']['mk'] = "my\n \nvalue"
170
- @rp.key_valid?(@env['params']).should be_true
170
+ @rp.key_valid?(@env['params']).should be true
171
171
  end
172
172
 
173
173
  it "doesn't raise if the key provided is an array and contains multiline with blanks" do
174
174
  @env['params']['mk'] = ["my\n \nvalue", "my\n \nother\n \nvalue"]
175
- @rp.key_valid?(@env['params']).should be_true
175
+ @rp.key_valid?(@env['params']).should be true
176
176
  end
177
177
  end
178
178
  end
@@ -194,7 +194,7 @@ describe Goliath::Rack::Validation::Param do
194
194
  }
195
195
  }
196
196
 
197
- @rp.key_valid?(@env['params']).should be_false
197
+ @rp.key_valid?(@env['params']).should be false
198
198
  end
199
199
 
200
200
  it "return true if key is present" do
@@ -205,7 +205,7 @@ describe Goliath::Rack::Validation::Param do
205
205
  }
206
206
  }
207
207
 
208
- @rp.key_valid?(@env['params']).should be_true
208
+ @rp.key_valid?(@env['params']).should be true
209
209
  end
210
210
  end
211
211
 
@@ -225,7 +225,7 @@ describe Goliath::Rack::Validation::Param do
225
225
  }
226
226
  }
227
227
 
228
- @rp.key_valid?(@env['params']).should be_false
228
+ @rp.key_valid?(@env['params']).should be false
229
229
  end
230
230
 
231
231
  it "return true if key is present" do
@@ -236,7 +236,7 @@ describe Goliath::Rack::Validation::Param do
236
236
  }
237
237
  }
238
238
 
239
- @rp.key_valid?(@env['params']).should be_true
239
+ @rp.key_valid?(@env['params']).should be true
240
240
  end
241
241
  end
242
242
 
@@ -247,7 +247,7 @@ describe Goliath::Rack::Validation::Param do
247
247
  it "should only accept a class in the :as" do
248
248
  lambda {
249
249
  Goliath::Rack::Validation::Param.new(@app, {:key => 'user', :as => "not a class"})
250
- }.should raise_error
250
+ }.should raise_error('Params as must be a class')
251
251
  end
252
252
 
253
253
  context 'with middleware' do