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.
- checksums.yaml +4 -4
- data/README.md +5 -4
- data/goliath.gemspec +11 -7
- data/lib/goliath/api.rb +1 -1
- 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/jsonp.rb +7 -2
- data/lib/goliath/rack/params.rb +4 -3
- data/lib/goliath/rack/validator.rb +1 -1
- data/lib/goliath/request.rb +37 -20
- data/lib/goliath/response.rb +2 -0
- data/lib/goliath/runner.rb +4 -3
- data/lib/goliath/server.rb +17 -2
- data/lib/goliath/test_helper_sse.rb +76 -0
- data/lib/goliath/validation/error.rb +4 -1
- 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 +6 -6
- data/spec/integration/echo_spec.rb +7 -7
- data/spec/integration/empty_body_spec.rb +2 -2
- data/spec/integration/event_stream_spec.rb +50 -0
- data/spec/integration/exception_handling_spec.rb +202 -0
- data/spec/integration/http_log_spec.rb +16 -16
- data/spec/integration/jsonp_spec.rb +61 -10
- 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 +25 -5
- 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 +99 -62
- 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 +39 -39
- 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 +149 -94
- data/examples/around.rb +0 -38
- data/examples/clone.rb +0 -26
- data/examples/router.rb +0 -15
- data/examples/test.rb +0 -31
- 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.
|
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.
|
57
|
-
c.response_header['SPECIAL'].
|
58
|
-
c.response.
|
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").
|
67
|
-
hl.to_http_header("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.
|
79
|
-
c.response_header["PARAMS"].
|
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.
|
93
|
-
c.response_header['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.
|
107
|
-
c.response_header["HEADERS"].
|
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.
|
121
|
-
c.response_header["METHOD"].
|
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.
|
133
|
-
c.response_header["METHOD"].
|
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
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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'].
|
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'].
|
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.
|
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.
|
35
|
-
(Time.now.to_f - start).
|
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).
|
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).
|
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).
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
56
|
-
c.response_header.status.
|
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").
|
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}.
|
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.
|
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'].
|
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'].
|
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.
|
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.
|
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.
|
68
|
-
c.response_header.status.
|
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.
|
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.
|
38
|
+
expect(client.receive.data).to eq("hello")
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
data/spec/spec_helper.rb
CHANGED