goliath 1.0.4 → 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.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -4
  3. data/goliath.gemspec +11 -7
  4. data/lib/goliath/api.rb +1 -1
  5. data/lib/goliath/connection.rb +15 -11
  6. data/lib/goliath/constants.rb +1 -0
  7. data/lib/goliath/rack/default_response_format.rb +3 -9
  8. data/lib/goliath/rack/formatters/json.rb +1 -1
  9. data/lib/goliath/rack/jsonp.rb +7 -2
  10. data/lib/goliath/rack/params.rb +4 -3
  11. data/lib/goliath/rack/validator.rb +1 -1
  12. data/lib/goliath/request.rb +37 -20
  13. data/lib/goliath/response.rb +2 -0
  14. data/lib/goliath/runner.rb +4 -3
  15. data/lib/goliath/server.rb +17 -2
  16. data/lib/goliath/test_helper_sse.rb +76 -0
  17. data/lib/goliath/validation/error.rb +4 -1
  18. data/lib/goliath/version.rb +1 -1
  19. data/spec/integration/async_request_processing.rb +2 -2
  20. data/spec/integration/chunked_streaming_spec.rb +1 -1
  21. data/spec/integration/early_abort_spec.rb +6 -6
  22. data/spec/integration/echo_spec.rb +7 -7
  23. data/spec/integration/empty_body_spec.rb +2 -2
  24. data/spec/integration/event_stream_spec.rb +50 -0
  25. data/spec/integration/exception_handling_spec.rb +202 -0
  26. data/spec/integration/http_log_spec.rb +16 -16
  27. data/spec/integration/jsonp_spec.rb +61 -10
  28. data/spec/integration/keepalive_spec.rb +2 -2
  29. data/spec/integration/pipelining_spec.rb +3 -3
  30. data/spec/integration/reloader_spec.rb +3 -3
  31. data/spec/integration/template_spec.rb +7 -7
  32. data/spec/integration/test_helper_spec.rb +3 -3
  33. data/spec/integration/trace_spec.rb +2 -2
  34. data/spec/integration/valid_spec.rb +25 -5
  35. data/spec/integration/websocket_spec.rb +2 -2
  36. data/spec/spec_helper.rb +1 -3
  37. data/spec/unit/api_spec.rb +1 -1
  38. data/spec/unit/connection_spec.rb +8 -8
  39. data/spec/unit/console_spec.rb +3 -3
  40. data/spec/unit/env_spec.rb +9 -9
  41. data/spec/unit/headers_spec.rb +8 -8
  42. data/spec/unit/rack/default_mime_type_spec.rb +3 -3
  43. data/spec/unit/rack/formatters/json_spec.rb +35 -13
  44. data/spec/unit/rack/formatters/plist_spec.rb +8 -8
  45. data/spec/unit/rack/formatters/xml_spec.rb +18 -18
  46. data/spec/unit/rack/formatters/yaml_spec.rb +13 -13
  47. data/spec/unit/rack/heartbeat_spec.rb +15 -15
  48. data/spec/unit/rack/params_spec.rb +99 -62
  49. data/spec/unit/rack/render_spec.rb +14 -14
  50. data/spec/unit/rack/validation/boolean_value_spec.rb +6 -6
  51. data/spec/unit/rack/validation/default_params_spec.rb +13 -13
  52. data/spec/unit/rack/validation/numeric_range_spec.rb +17 -17
  53. data/spec/unit/rack/validation/param_spec.rb +75 -75
  54. data/spec/unit/rack/validation/request_method_spec.rb +9 -9
  55. data/spec/unit/rack/validation/required_param_spec.rb +39 -39
  56. data/spec/unit/rack/validation/required_value_spec.rb +19 -19
  57. data/spec/unit/request_spec.rb +18 -18
  58. data/spec/unit/response_spec.rb +6 -6
  59. data/spec/unit/runner_spec.rb +31 -31
  60. data/spec/unit/server_spec.rb +21 -21
  61. data/spec/unit/validation/standard_http_errors_spec.rb +6 -6
  62. metadata +149 -94
  63. data/examples/around.rb +0 -38
  64. data/examples/clone.rb +0 -26
  65. data/examples/router.rb +0 -15
  66. data/examples/test.rb +0 -31
  67. data/examples/upload.rb +0 -17
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require File.join(File.dirname(__FILE__), '../../', 'lib/goliath/test_helper_sse')
3
+ require File.join(File.dirname(__FILE__), '../../', 'lib/goliath')
4
+ require File.join(File.dirname(__FILE__), '../../', 'lib/goliath/api')
5
+
6
+ class EventStreamEndpoint < Goliath::API
7
+ def self.events
8
+ @events ||= EM::Queue.new
9
+ end
10
+
11
+ def response(env)
12
+ self.class.events.pop do |event|
13
+ payload = if event.key?(:name)
14
+ "event: #{event[:name]}\ndata: #{event[:data]}\n\n"
15
+ else
16
+ "data: #{event[:data]}\n\n"
17
+ end
18
+ env.stream_send(payload)
19
+ end
20
+ streaming_response(200, 'Content-Type' => 'text/event-stream')
21
+ end
22
+ end
23
+
24
+ describe 'EventStream' do
25
+ include Goliath::TestHelper
26
+
27
+ context 'named events' do
28
+ it 'should accept stream' do
29
+ with_api(EventStreamEndpoint, {:verbose => true, :log_stdout => true}) do |server|
30
+ sse_client_connect('/stream') do |client|
31
+ client.listen_to('custom_event')
32
+ EventStreamEndpoint.events.push(name: 'custom_event', data: 'content')
33
+ expect(client.receive_on('custom_event')).to eq(['content'])
34
+ expect(client.receive).to eq([])
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'unnamed events' do
41
+ it 'should accept stream' do
42
+ with_api(EventStreamEndpoint, {:verbose => true, :log_stdout => true}) do |server|
43
+ sse_client_connect('/stream') do |client|
44
+ EventStreamEndpoint.events.push(data: 'content')
45
+ expect(client.receive).to eq(['content'])
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,202 @@
1
+ # This integration spec isn't *quite* about exception handling. It's more of a
2
+ # regression test, since Goliath::Rack::Params used to swallow any exception
3
+ # generated downstream from it in the middleware chain (even though
4
+ # Goliath::API#call handles exceptions already).
5
+
6
+ require 'spec_helper'
7
+
8
+ class ExceptionHandlingMiddleware
9
+ include Goliath::Rack::AsyncMiddleware
10
+ include Goliath::Constants
11
+
12
+ def call(env)
13
+ # This kind of relies on downstream middleware raising their own exceptions
14
+ # if something goes wrong. Alternatively, they could rescue the exception
15
+ # and set env[RACK_EXCEPTION]. See #post_process.
16
+ super
17
+ rescue Exception => e
18
+ handle_exception(e)
19
+ end
20
+
21
+ def post_process(env, status, headers, body)
22
+ # If an exception was raised by Goliath::API#call, it will store the
23
+ # exception in env[RACK_EXCEPTION] and automatically generate an error
24
+ # response. We circumvent the usual error response by returning our own.
25
+ return handle_exception(env[RACK_EXCEPTION]) if env[RACK_EXCEPTION]
26
+ [status, headers, body]
27
+ end
28
+
29
+ private
30
+
31
+ def handle_exception(e)
32
+ # You could imagine this middleware having some sort of side effect, like
33
+ # sending your team an email alert detailing the exception. For the
34
+ # purposes of the spec, we'll just return some text.
35
+ [200, {}, "Exception raised: #{e.message}"]
36
+ end
37
+ end
38
+
39
+ class ExceptionRaisingMiddleware
40
+ def initialize(app)
41
+ @app = app
42
+ end
43
+
44
+ def call(env)
45
+ raise env.params['raise'] if env.params['raise']
46
+ @app.call(env)
47
+ end
48
+ end
49
+
50
+ class ExceptionHandlingAPI < Goliath::API
51
+ # The exception handling middleware should come first in the chain so that
52
+ # any exception in the rest of the chain gets rescued.
53
+ use ExceptionHandlingMiddleware
54
+
55
+ # Require param parsing before the exception raising middleware, because the
56
+ # latter depends on params being parsed. Herein lies the regression:
57
+ # Goliath::Rack::Params used to swallow any exceptions raised downstream from
58
+ # it (here, ExceptionRaisingMiddleware), so any upstream middleware (here,
59
+ # ExceptionHandlingMiddleware) would be none the wiser. Really, the only
60
+ # thing Goliath::Rack::Params should be worried about is whether it can parse
61
+ # the params.
62
+ use Goliath::Rack::Params
63
+
64
+ # Allow us to raise an exception on demand with the param raise=<message>.
65
+ # You could imagine something less dumb for a real-life application that
66
+ # incidentally raises an exception, if you'd like.
67
+ use ExceptionRaisingMiddleware
68
+
69
+ def response(env)
70
+ # Goliath::API#call ensures that any exceptions raised here get rescued and
71
+ # stored in env[RACK_EXCEPTION].
72
+ fail env.params['fail'] if env.params['fail']
73
+ [200, {}, 'No exceptions raised']
74
+ end
75
+ end
76
+
77
+ describe ExceptionHandlingAPI do
78
+ let(:err) { Proc.new { fail 'API request failed' } }
79
+
80
+ context 'when no exceptions get raised' do
81
+ let(:query) { '' }
82
+
83
+ it 'returns a normal response' do
84
+ with_api(ExceptionHandlingAPI) do
85
+ get_request({ query: query }, err) do |c|
86
+ expect(c.response_header.status).to eq(200)
87
+ expect(c.response).to eq('No exceptions raised')
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'when a middleware raises an exception' do
94
+ let(:query) { 'raise=zoinks' }
95
+
96
+ it 'handles the exception using ExceptionHandlingMiddleware' do
97
+ with_api(ExceptionHandlingAPI) do
98
+ get_request({ query: query }, err) do |c|
99
+ expect(c.response_header.status).to eq(200)
100
+ expect(c.response).to eq('Exception raised: zoinks')
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'when the API raises an exception' do
107
+ let(:query) { 'fail=jinkies' }
108
+
109
+ it 'handles the exception using ExceptionHandlingMiddleware' do
110
+ with_api(ExceptionHandlingAPI) do
111
+ get_request({ query: query }, err) do |c|
112
+ expect(c.response_header.status).to eq(200)
113
+ expect(c.response).to eq('Exception raised: jinkies')
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ context 'when param parsing raises an exception' do
120
+ let(:query) { 'ambiguous[]=&ambiguous[4]=' }
121
+
122
+ it 'returns a validation error generated by Goliath::Rack::Params' do
123
+ with_api(ExceptionHandlingAPI) do
124
+ get_request({ query: query }, err) do |c|
125
+ expect(c.response_header.status).to eq(400)
126
+ expect(c.response).to eq("[:error, \"Invalid parameters: Rack::Utils::ParameterTypeError\"]")
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ # This API has the same setup as ExceptionHandlingAPI, except for the crucial
134
+ # difference that it does *not* use ExceptionHandlingMiddleware. This is to
135
+ # make sure that exceptions are still rescued somewhere in an API call, even
136
+ # though they aren't getting swallowed by Goliath::Rack::Params anymore.
137
+
138
+ class PassiveExceptionHandlingAPI < Goliath::API
139
+ use Goliath::Rack::Params
140
+ use ExceptionRaisingMiddleware
141
+
142
+ def response(env)
143
+ fail env.params['fail'] if env.params['fail']
144
+ [200, {}, 'No exceptions raised']
145
+ end
146
+ end
147
+
148
+ describe PassiveExceptionHandlingAPI do
149
+ let(:err) { Proc.new { fail 'API request failed' } }
150
+
151
+ context 'when no exceptions get raised' do
152
+ let(:query) { '' }
153
+
154
+ it 'returns a normal response' do
155
+ with_api(PassiveExceptionHandlingAPI) do
156
+ get_request({ query: query }, err) do |c|
157
+ expect(c.response_header.status).to eq(200)
158
+ expect(c.response).to eq('No exceptions raised')
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ context 'when a middleware raises an exception' do
165
+ let(:query) { 'raise=ruh-roh' }
166
+
167
+ it 'returns the server error generated by Goliath::Request#process' do
168
+ with_api(PassiveExceptionHandlingAPI) do
169
+ get_request({ query: query }, err) do |c|
170
+ expect(c.response_header.status).to eq(500)
171
+ expect(c.response).to eq('ruh-roh')
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ context 'when the API raises an exception' do
178
+ let(:query) { 'fail=puppy-power' }
179
+
180
+ it 'returns the validation error generated by Goliath::API#call' do
181
+ with_api(PassiveExceptionHandlingAPI) do
182
+ get_request({ query: query }, err) do |c|
183
+ expect(c.response_header.status).to eq(500)
184
+ expect(c.response).to eq('[:error, "puppy-power"]')
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ context 'when param parsing raises an exception' do
191
+ let(:query) { 'ambiguous[]=&ambiguous[4]=' }
192
+
193
+ it 'returns a validation error generated by Goliath::Rack::Params' do
194
+ with_api(PassiveExceptionHandlingAPI) do
195
+ get_request({ query: query }, err) do |c|
196
+ expect(c.response_header.status).to eq(400)
197
+ expect(c.response).to eq('[:error, "Invalid parameters: Rack::Utils::ParameterTypeError"]')
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -42,7 +42,7 @@ describe HttpLog do
42
42
  mock_mongo(api)
43
43
 
44
44
  get_request({}, err) do |c|
45
- c.response_header.status.should == 200
45
+ expect(c.response_header.status).to eq(200)
46
46
  end
47
47
  end
48
48
  end
@@ -53,9 +53,9 @@ describe HttpLog do
53
53
  mock_mongo(api)
54
54
 
55
55
  get_request({}, err) do |c|
56
- c.response_header.status.should == 200
57
- c.response_header['SPECIAL'].should == 'Header'
58
- c.response.should == 'Hello from Responder'
56
+ expect(c.response_header.status).to eq(200)
57
+ expect(c.response_header['SPECIAL']).to eq('Header')
58
+ expect(c.response).to eq('Hello from Responder')
59
59
  end
60
60
  end
61
61
  end
@@ -63,8 +63,8 @@ describe HttpLog do
63
63
  context 'HTTP header handling' do
64
64
  it 'transforms back properly' do
65
65
  hl = HttpLog.new
66
- hl.to_http_header("SPECIAL").should == 'Special'
67
- hl.to_http_header("CONTENT_TYPE").should == 'Content-Type'
66
+ expect(hl.to_http_header("SPECIAL")).to eq('Special')
67
+ expect(hl.to_http_header("CONTENT_TYPE")).to eq('Content-Type')
68
68
  end
69
69
  end
70
70
 
@@ -75,8 +75,8 @@ describe HttpLog do
75
75
  mock_mongo(api)
76
76
 
77
77
  get_request({:query => {:first => :foo, :second => :bar, :third => :baz}}, err) do |c|
78
- c.response_header.status.should == 200
79
- c.response_header["PARAMS"].should == "first: foo|second: bar|third: baz"
78
+ expect(c.response_header.status).to eq(200)
79
+ expect(c.response_header["PARAMS"]).to eq("first: foo|second: bar|third: baz")
80
80
  end
81
81
  end
82
82
  end
@@ -89,8 +89,8 @@ describe HttpLog do
89
89
  mock_mongo(api)
90
90
 
91
91
  get_request({:path => '/my/request/path'}, err) do |c|
92
- c.response_header.status.should == 200
93
- c.response_header['PATH'].should == '/my/request/path'
92
+ expect(c.response_header.status).to eq(200)
93
+ expect(c.response_header['PATH']).to eq('/my/request/path')
94
94
  end
95
95
  end
96
96
  end
@@ -103,8 +103,8 @@ describe HttpLog do
103
103
  mock_mongo(api)
104
104
 
105
105
  get_request({:head => {:first => :foo, :second => :bar}}, err) do |c|
106
- c.response_header.status.should == 200
107
- c.response_header["HEADERS"].should =~ /First: foo\|Second: bar/
106
+ expect(c.response_header.status).to eq(200)
107
+ expect(c.response_header["HEADERS"]).to match(/First: foo\|Second: bar/)
108
108
  end
109
109
  end
110
110
  end
@@ -117,8 +117,8 @@ describe HttpLog do
117
117
  mock_mongo(api)
118
118
 
119
119
  get_request({}, err) do |c|
120
- c.response_header.status.should == 200
121
- c.response_header["METHOD"].should == "GET"
120
+ expect(c.response_header.status).to eq(200)
121
+ expect(c.response_header["METHOD"]).to eq("GET")
122
122
  end
123
123
  end
124
124
  end
@@ -129,8 +129,8 @@ describe HttpLog do
129
129
  mock_mongo(api)
130
130
 
131
131
  post_request({}, err) do |c|
132
- c.response_header.status.should == 200
133
- c.response_header["METHOD"].should == "POST"
132
+ expect(c.response_header.status).to eq(200)
133
+ expect(c.response_header["METHOD"]).to eq("POST")
134
134
  end
135
135
  end
136
136
  end
@@ -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
+ expect(c.response_header['CONTENT_TYPE']).to match(%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
+ expect(c.response_header['CONTENT_LENGTH'].to_i).to eq(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
+ expect(c.response).to eq('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
+ expect(c.response_header['CONTENT_TYPE']).to match(%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
+ expect(c.response_header['CONTENT_LENGTH'].to_i).to eq(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
+ expect(c.response).to match(/^test\(.*\)$/)
78
+ end
28
79
  end
29
80
  end
30
81
  end
31
- end
82
+ end
@@ -10,13 +10,13 @@ describe 'HTTP Keep-Alive support' do
10
10
  r1.errback { fail }
11
11
  r1.callback do |c|
12
12
  b = MultiJson.load(c.response)
13
- b['response'].should == 'test'
13
+ expect(b['response']).to eq('test')
14
14
 
15
15
  r2 = conn.get(:query => {:echo => 'test2'})
16
16
  r2.errback { fail }
17
17
  r2.callback do |c|
18
18
  b = MultiJson.load(c.response)
19
- b['response'].should == 'test2'
19
+ expect(b['response']).to eq('test2')
20
20
 
21
21
  stop
22
22
  end
@@ -24,15 +24,15 @@ describe 'HTTP Pipelining support' do
24
24
  r1.errback { fail }
25
25
  r1.callback do |c|
26
26
  res << c.response
27
- c.response.should match('0.3')
27
+ expect(c.response).to match('0.3')
28
28
  end
29
29
 
30
30
  r2.errback { fail }
31
31
  r2.callback do |c|
32
32
  res << c.response
33
33
 
34
- res.should == ['0.3', '0.2']
35
- (Time.now.to_f - start).should be_within(0.1).of(0.3)
34
+ expect(res).to eq(['0.3', '0.2'])
35
+ expect(Time.now.to_f - start).to be_within(0.1).of(0.3)
36
36
 
37
37
  stop
38
38
  end
@@ -29,15 +29,15 @@ describe "Reloader" do
29
29
  end
30
30
 
31
31
  it 'adds reloader in dev mode' do
32
- count(ReloaderDev).should == 1
32
+ expect(count(ReloaderDev)).to eq(1)
33
33
  end
34
34
 
35
35
  it "doesn't add if it's already there in dev mode" do
36
- count(ReloaderAlreadyLoaded).should == 1
36
+ expect(count(ReloaderAlreadyLoaded)).to eq(1)
37
37
  end
38
38
 
39
39
  it "doesn't add in prod mode" do
40
40
  Goliath.env = :production
41
- count(ReloaderProd).should == 0
41
+ expect(count(ReloaderProd)).to eq(0)
42
42
  end
43
43
  end
@@ -11,7 +11,7 @@ describe Template do
11
11
  it 'renders haml template with default haml layout' do
12
12
  with_api(Template, api_options) do
13
13
  get_request(:path => '/') do |c|
14
- c.response.should =~ %r{<li><a href="/joke">Tell me a joke</a></li>}
14
+ expect(c.response).to match(%r{<li><a href="/joke">Tell me a joke</a></li>})
15
15
  end
16
16
  end
17
17
  end
@@ -19,7 +19,7 @@ describe Template do
19
19
  it 'renders haml template from string with default haml layout' do
20
20
  with_api(Template, api_options) do
21
21
  get_request(:path => '/haml_str') do |c|
22
- c.response.should =~ %r{<h1>Header</h1>}
22
+ expect(c.response).to match(%r{<h1>Header</h1>})
23
23
  end
24
24
  end
25
25
  end
@@ -27,7 +27,7 @@ describe Template do
27
27
  it 'renders a markdown template with default haml layout' do
28
28
  with_api(Template, api_options) do
29
29
  get_request(:path => '/joke') do |c|
30
- c.response.should =~ %r{<code>Arr, I dunno matey -- but it is driving me nuts!\s*</code>}m
30
+ expect(c.response).to match(%r{<code>Arr, I dunno matey -- but it is driving me nuts!\s*</code>}m)
31
31
  end
32
32
  end
33
33
  end
@@ -35,7 +35,7 @@ describe Template do
35
35
  it 'lets me specify an alternate layout engine' do
36
36
  with_api(Template, api_options) do
37
37
  get_request(:path => '/erb_me') do |c|
38
- c.response.should =~ %r{I AM ERB</h1>}m
38
+ expect(c.response).to match(%r{I AM ERB</h1>}m)
39
39
  end
40
40
  end
41
41
  end
@@ -43,7 +43,7 @@ describe Template do
43
43
  it 'accepts local variables' do
44
44
  with_api(Template, api_options) do
45
45
  get_request(:path => '/erb_me') do |c|
46
- c.response.should =~ %r{<title>HERE IS A JOKE</title>}m
46
+ expect(c.response).to match(%r{<title>HERE IS A JOKE</title>}m)
47
47
  end
48
48
  end
49
49
  end
@@ -52,8 +52,8 @@ describe Template do
52
52
  it 'raises an explanatory 500 error' do
53
53
  with_api(Template, api_options) do
54
54
  get_request(:path => '/oops') do |c|
55
- c.response.should =~ %r{^\[:error, "Template no_such_template not found in .*examples/views for haml"\]$}
56
- c.response_header.status.should == 500
55
+ expect(c.response).to match(%r{^\[:error, "Template no_such_template not found in .*examples/views for haml"\]$})
56
+ expect(c.response_header.status).to eq(500)
57
57
  end
58
58
  end
59
59
  end
@@ -11,20 +11,20 @@ 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
+ expect(File.exist?("test.log")).to be_truthy
15
15
  File.unlink("test.log")
16
16
  end
17
17
 
18
18
  it "should log on console if requested" do
19
19
  with_api(DummyServer, {:log_stdout => true }) do |api|
20
- api.logger.outputters.select {|o| o.is_a? Log4r::StdoutOutputter}.should_not be_empty
20
+ expect(api.logger.outputters.select {|o| o.is_a? Log4r::StdoutOutputter}).not_to be_empty
21
21
  EM.stop
22
22
  end
23
23
  end
24
24
 
25
25
  it "should be verbose if asked" do
26
26
  with_api(DummyServer, {:verbose => true, :log_stdout => true }) do |api|
27
- api.logger.level.should == Log4r::DEBUG
27
+ expect(api.logger.level).to eq(Log4r::DEBUG)
28
28
  EM.stop
29
29
  end
30
30
 
@@ -8,7 +8,7 @@ describe Goliath::Rack::Tracer do
8
8
  it 'injects a trace param on a 200 (via async callback)' do
9
9
  with_api(Echo) do
10
10
  get_request({:query => {:echo => 'test'}}, err) do |c|
11
- c.response_header['X_POSTRANK'].should =~ /trace\.start: [\d\.]+, total: [\d\.]+/
11
+ expect(c.response_header['X_POSTRANK']).to match(/trace\.start: [\d\.]+, total: [\d\.]+/)
12
12
  end
13
13
  end
14
14
  end
@@ -16,7 +16,7 @@ describe Goliath::Rack::Tracer do
16
16
  it 'injects a trace param on a 400 (direct callback)' do
17
17
  with_api(Echo) do
18
18
  get_request({}, err) do |c|
19
- c.response_header['X_POSTRANK'].should =~ /trace\.start: [\d\.]+, total: [\d\.]+/
19
+ expect(c.response_header['X_POSTRANK']).to match(/trace\.start: [\d\.]+, total: [\d\.]+/)
20
20
  end
21
21
  end
22
22
  end
@@ -38,7 +38,7 @@ describe ValidSingleParam do
38
38
  it 'returns OK with param' do
39
39
  with_api(ValidSingleParam) do
40
40
  get_request({:query => {:test => 'test'}}, err) do |c|
41
- c.response.should == 'OK'
41
+ expect(c.response).to eq('OK')
42
42
  end
43
43
  end
44
44
  end
@@ -46,7 +46,7 @@ describe ValidSingleParam do
46
46
  it 'returns error without param' do
47
47
  with_api(ValidSingleParam) do
48
48
  get_request({}, err) do |c|
49
- c.response.should == '[:error, "test identifier missing"]'
49
+ expect(c.response).to eq('[:error, "test identifier missing"]')
50
50
  end
51
51
  end
52
52
  end
@@ -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
 
@@ -64,10 +64,30 @@ describe ValidationErrorInEndpoint do
64
64
  it 'handles Goliath::Validation::Error correctly' do
65
65
  with_api(ValidationErrorInEndpoint) do
66
66
  get_request({}, err) do |c|
67
- c.response.should == '[:error, "You Must Chill"]'
68
- c.response_header.status.should == 420
67
+ expect(c.response).to eq('[:error, "You Must Chill"]')
68
+ expect(c.response_header.status).to eq(420)
69
+ expect(c.response_header["Foo"]).to eq('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
+ expect(c.response).to eq('[:error, "You Must Chill"]')
88
+ expect(c.response_header.status).to eq(420)
89
+ expect(c.response_header["Foo"]).to eq('Bar')
90
+ end
91
+ end
92
+ end
93
+ end
@@ -26,7 +26,7 @@ describe "WebSocket" do
26
26
 
27
27
  it "should accept connection" do
28
28
  with_api(WebSocketEndPoint, {:verbose => true, :log_stdout => true}) do |server|
29
- WebSocketEndPoint.any_instance.should_receive(:on_open)
29
+ expect_any_instance_of(WebSocketEndPoint).to receive(:on_open)
30
30
  ws_client_connect('/ws')
31
31
  end
32
32
  end
@@ -35,7 +35,7 @@ describe "WebSocket" do
35
35
  with_api(WebSocketEndPoint, {:verbose => true, :log_stdout => true}) do |server|
36
36
  ws_client_connect('/ws') do |client|
37
37
  client.send "hello"
38
- client.receive.data.should == "hello"
38
+ expect(client.receive.data).to eq("hello")
39
39
  end
40
40
  end
41
41
  end
data/spec/spec_helper.rb CHANGED
@@ -8,7 +8,5 @@ require 'goliath/test_helper'
8
8
  Goliath.env = :test
9
9
 
10
10
  RSpec.configure do |c|
11
- c.include Goliath::TestHelper, :example_group => {
12
- :file_path => /spec\/integration/
13
- }
11
+ c.include Goliath::TestHelper, :file_path => /spec\/integration/
14
12
  end