deas 0.36.0 → 0.37.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/deas/error_handler.rb +46 -15
- data/lib/deas/handler_proxy.rb +22 -14
- data/lib/deas/logging.rb +2 -2
- data/lib/deas/route.rb +4 -3
- data/lib/deas/server.rb +182 -166
- data/lib/deas/server_data.rb +22 -0
- data/lib/deas/sinatra_app.rb +40 -19
- data/lib/deas/version.rb +1 -1
- data/test/support/factory.rb +25 -0
- data/test/support/fake_sinatra_call.rb +3 -8
- data/test/support/routes.rb +3 -3
- data/test/unit/error_handler_tests.rb +112 -63
- data/test/unit/handler_proxy_tests.rb +32 -29
- data/test/unit/logging_tests.rb +1 -3
- data/test/unit/route_tests.rb +9 -7
- data/test/unit/server_data_tests.rb +43 -0
- data/test/unit/server_tests.rb +144 -0
- data/test/unit/sinatra_app_tests.rb +19 -13
- data/test/unit/sinatra_runner_tests.rb +1 -2
- metadata +114 -88
- checksums.yaml +0 -7
- data/test/unit/server_configuration_tests.rb +0 -154
@@ -0,0 +1,22 @@
|
|
1
|
+
module Deas
|
2
|
+
|
3
|
+
class ServerData
|
4
|
+
|
5
|
+
# The server uses this to "compile" its configuration for speed. NsOptions
|
6
|
+
# is relatively slow everytime an option is read. To avoid this, we read the
|
7
|
+
# options one time here and memoize their values. This way, we don't pay the
|
8
|
+
# NsOptions overhead when reading them while handling a request.
|
9
|
+
|
10
|
+
attr_reader :error_procs, :logger, :router, :template_source
|
11
|
+
|
12
|
+
def initialize(args = nil)
|
13
|
+
args ||= {}
|
14
|
+
@error_procs = args[:error_procs] || []
|
15
|
+
@logger = args[:logger]
|
16
|
+
@router = args[:router]
|
17
|
+
@template_source = args[:template_source]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/deas/sinatra_app.rb
CHANGED
@@ -1,21 +1,23 @@
|
|
1
1
|
require 'sinatra/base'
|
2
2
|
require 'deas/error_handler'
|
3
|
+
require 'deas/server_data'
|
3
4
|
|
4
5
|
module Deas
|
6
|
+
|
5
7
|
module SinatraApp
|
6
8
|
|
7
9
|
def self.new(server_config)
|
10
|
+
# This is generic server initialization stuff. Eventually do this in the
|
11
|
+
# server's initialization logic more like Sanford does.
|
8
12
|
server_config.validate!
|
13
|
+
server_data = ServerData.new(server_config.to_hash)
|
9
14
|
|
10
15
|
Sinatra.new do
|
11
|
-
|
12
16
|
# built-in settings
|
13
|
-
set :environment,
|
14
|
-
set :root,
|
15
|
-
|
16
|
-
set :
|
17
|
-
set :views, server_config.views_root
|
18
|
-
|
17
|
+
set :environment, server_config.env
|
18
|
+
set :root, server_config.root
|
19
|
+
set :public_folder, server_config.public_root
|
20
|
+
set :views, server_config.views_root
|
19
21
|
set :dump_errors, server_config.dump_errors
|
20
22
|
set :method_override, server_config.method_override
|
21
23
|
set :sessions, server_config.sessions
|
@@ -24,18 +26,18 @@ module Deas
|
|
24
26
|
set :default_encoding, server_config.default_encoding
|
25
27
|
set :logging, false
|
26
28
|
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
29
|
+
# TODO: sucks to have to do this but b/c or Rack there is no better way
|
30
|
+
# to make the server data available to middleware. We should remove this
|
31
|
+
# once we remove Sinatra. Whatever rack app implemenation will needs to
|
32
|
+
# provide the server data or maybe the server data *will be* the rack app.
|
33
|
+
# Not sure right now, just jotting down notes.
|
34
|
+
set :deas_server_data, server_data
|
35
|
+
|
36
|
+
# raise_errors and show_exceptions prevent Deas error handlers from being
|
37
|
+
# called and Deas' logging doesn't finish. They should always be false.
|
30
38
|
set :raise_errors, false
|
31
39
|
set :show_exceptions, false
|
32
40
|
|
33
|
-
# custom settings
|
34
|
-
set :deas_error_procs, server_config.error_procs
|
35
|
-
set :logger, server_config.logger
|
36
|
-
set :router, server_config.router
|
37
|
-
set :template_source, server_config.template_source
|
38
|
-
|
39
41
|
# TODO: rework with `server_config.default_encoding` once we move off of using Sinatra
|
40
42
|
# TODO: could maybe move into a deas-json mixin once off of Sinatra
|
41
43
|
# Add charset to json content type responses - by default only added to these:
|
@@ -47,20 +49,39 @@ module Deas
|
|
47
49
|
|
48
50
|
# routes
|
49
51
|
server_config.routes.each do |route|
|
50
|
-
|
52
|
+
# TODO: `self` is the sinatra_call; eventually stop sending it
|
53
|
+
# (part of phasing out Sinatra)
|
54
|
+
send(route.method, route.path){ route.run(server_data, self) }
|
51
55
|
end
|
52
56
|
|
53
57
|
# error handling
|
54
58
|
not_found do
|
59
|
+
# `self` is the sinatra call in this context
|
55
60
|
env['sinatra.error'] ||= Sinatra::NotFound.new
|
56
|
-
ErrorHandler.run(env['sinatra.error'],
|
61
|
+
ErrorHandler.run(env['sinatra.error'], {
|
62
|
+
:server_data => server_data,
|
63
|
+
:request => self.request,
|
64
|
+
:response => self.response,
|
65
|
+
:handler_class => self.request.env['deas.handler_class'],
|
66
|
+
:handler => self.request.env['deas.handler'],
|
67
|
+
:params => self.request.env['deas.params'],
|
68
|
+
})
|
57
69
|
end
|
58
70
|
error do
|
59
|
-
|
71
|
+
# `self` is the sinatra call in this context
|
72
|
+
ErrorHandler.run(env['sinatra.error'], {
|
73
|
+
:server_data => server_data,
|
74
|
+
:request => self.request,
|
75
|
+
:response => self.response,
|
76
|
+
:handler_class => self.request.env['deas.handler_class'],
|
77
|
+
:handler => self.request.env['deas.handler'],
|
78
|
+
:params => self.request.env['deas.params'],
|
79
|
+
})
|
60
80
|
end
|
61
81
|
|
62
82
|
end
|
63
83
|
end
|
64
84
|
|
65
85
|
end
|
86
|
+
|
66
87
|
end
|
data/lib/deas/version.rb
CHANGED
data/test/support/factory.rb
CHANGED
@@ -1,6 +1,31 @@
|
|
1
1
|
require 'assert/factory'
|
2
|
+
require 'deas/logger'
|
3
|
+
require 'deas/router'
|
4
|
+
require 'deas/server_data'
|
5
|
+
require 'deas/template_source'
|
6
|
+
require 'test/support/fake_sinatra_call'
|
2
7
|
|
3
8
|
module Factory
|
4
9
|
extend Assert::Factory
|
5
10
|
|
11
|
+
def self.exception(klass = nil, message = nil)
|
12
|
+
klass ||= StandardError
|
13
|
+
message ||= Factory.text
|
14
|
+
exception = nil
|
15
|
+
begin; raise(klass, message); rescue klass => exception; end
|
16
|
+
exception
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.server_data(opts = nil)
|
20
|
+
Deas::ServerData.new({
|
21
|
+
:logger => Deas::NullLogger.new,
|
22
|
+
:router => Deas::Router.new,
|
23
|
+
:template_source => Deas::NullTemplateSource.new
|
24
|
+
}.merge(opts || {}))
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.sinatra_call(settings = nil)
|
28
|
+
FakeSinatraCall.new(settings)
|
29
|
+
end
|
30
|
+
|
6
31
|
end
|
@@ -1,7 +1,4 @@
|
|
1
1
|
require 'ostruct'
|
2
|
-
require 'deas/logger'
|
3
|
-
require 'deas/router'
|
4
|
-
require 'deas/template_source'
|
5
2
|
|
6
3
|
class FakeSinatraCall
|
7
4
|
|
@@ -11,7 +8,7 @@ class FakeSinatraCall
|
|
11
8
|
attr_accessor :request, :response, :params, :logger, :router, :session
|
12
9
|
attr_accessor :settings
|
13
10
|
|
14
|
-
def initialize(settings =
|
11
|
+
def initialize(settings = nil)
|
15
12
|
@request = FakeRequest.new('GET','/something', {}, OpenStruct.new)
|
16
13
|
@response = FakeResponse.new
|
17
14
|
@session = @request.session
|
@@ -25,10 +22,8 @@ class FakeSinatraCall
|
|
25
22
|
@headers = {}
|
26
23
|
|
27
24
|
@settings = OpenStruct.new({
|
28
|
-
:
|
29
|
-
|
30
|
-
:template_source => @template_source
|
31
|
-
}.merge(settings))
|
25
|
+
:deas_server_data => Factory.server_data
|
26
|
+
}.merge(settings || {}))
|
32
27
|
end
|
33
28
|
|
34
29
|
def halt(*args)
|
data/test/support/routes.rb
CHANGED
@@ -10,12 +10,12 @@ class DeasTestServer
|
|
10
10
|
|
11
11
|
set :a_setting, 'something'
|
12
12
|
|
13
|
-
error do |exception|
|
13
|
+
error do |exception, context|
|
14
14
|
case exception
|
15
15
|
when Sinatra::NotFound
|
16
|
-
|
16
|
+
[404, "Couldn't be found"]
|
17
17
|
when Exception
|
18
|
-
|
18
|
+
[500, "Oops, something went wrong"]
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -1,106 +1,155 @@
|
|
1
1
|
require 'assert'
|
2
2
|
require 'deas/error_handler'
|
3
3
|
|
4
|
-
require 'test/support/fake_sinatra_call'
|
5
|
-
|
6
4
|
class Deas::ErrorHandler
|
7
5
|
|
8
6
|
class UnitTests < Assert::Context
|
9
7
|
desc "Deas::ErrorHandler"
|
10
8
|
setup do
|
11
|
-
|
12
|
-
|
13
|
-
@
|
9
|
+
# always make sure there are multiple error procs or tests can be false
|
10
|
+
# positives
|
11
|
+
@error_proc_spies = (Factory.integer(3) + 1).times.map{ ErrorProcSpy.new }
|
12
|
+
@server_data = Factory.server_data(:error_procs => @error_proc_spies)
|
13
|
+
@request = Factory.string
|
14
|
+
@response = Factory.string
|
15
|
+
@handler_class = Factory.string
|
16
|
+
@handler = Factory.string
|
17
|
+
@params = Factory.string
|
18
|
+
|
19
|
+
@context_hash = {
|
20
|
+
:server_data => @server_data,
|
21
|
+
:request => @request,
|
22
|
+
:response => @response,
|
23
|
+
:handler_class => @handler_class,
|
24
|
+
:handler => @handler,
|
25
|
+
:params => @params,
|
26
|
+
}
|
27
|
+
|
28
|
+
@handler_class = Deas::ErrorHandler
|
14
29
|
end
|
15
|
-
subject{ @
|
30
|
+
subject{ @handler_class }
|
16
31
|
|
17
|
-
should
|
18
|
-
should have_class_methods :run
|
32
|
+
should have_imeths :run
|
19
33
|
|
20
34
|
end
|
21
35
|
|
22
|
-
class
|
23
|
-
desc "
|
36
|
+
class InitTests < UnitTests
|
37
|
+
desc "when init"
|
24
38
|
setup do
|
25
|
-
@
|
26
|
-
|
27
|
-
|
28
|
-
|
39
|
+
@exception = Factory.exception
|
40
|
+
@error_handler = @handler_class.new(@exception, @context_hash)
|
41
|
+
end
|
42
|
+
subject{ @error_handler }
|
43
|
+
|
44
|
+
should have_readers :exception, :context, :error_procs
|
45
|
+
should have_imeths :run
|
46
|
+
|
47
|
+
should "know its attrs" do
|
48
|
+
assert_equal @exception, subject.exception
|
49
|
+
|
50
|
+
exp = Context.new(@context_hash)
|
51
|
+
assert_equal exp, subject.context
|
29
52
|
|
30
|
-
|
53
|
+
exp = @server_data.error_procs.reverse
|
54
|
+
assert_equal exp, subject.error_procs
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class RunTests < InitTests
|
60
|
+
desc "and run"
|
61
|
+
setup do
|
31
62
|
@response = @error_handler.run
|
32
63
|
end
|
33
64
|
|
34
|
-
should "
|
35
|
-
|
65
|
+
should "call each of its procs" do
|
66
|
+
subject.error_procs.each do |proc_spy|
|
67
|
+
assert_true proc_spy.called
|
68
|
+
assert_equal subject.exception, proc_spy.exception
|
69
|
+
assert_equal subject.context, proc_spy.context
|
70
|
+
end
|
36
71
|
end
|
37
72
|
|
38
|
-
should "return
|
39
|
-
|
73
|
+
should "return the last non-nil response" do
|
74
|
+
assert_nil @response
|
75
|
+
|
76
|
+
exp = Factory.string
|
77
|
+
subject.error_procs.first.response = exp
|
78
|
+
assert_equal exp, subject.run
|
40
79
|
end
|
41
80
|
|
42
81
|
end
|
43
82
|
|
44
|
-
class
|
45
|
-
desc "run with
|
83
|
+
class RunWithProcsThatRaiseTests < InitTests
|
84
|
+
desc "and run with procs that raise exceptions"
|
46
85
|
setup do
|
47
|
-
@
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
proc do |exception|
|
53
|
-
settings.second_proc_run = true
|
54
|
-
'second'
|
55
|
-
end,
|
56
|
-
proc do |exception|
|
57
|
-
settings.third_proc_run = true
|
58
|
-
nil
|
59
|
-
end
|
60
|
-
]
|
61
|
-
|
62
|
-
@error_handler = Deas::ErrorHandler.new(@exception, @fake_sinatra_call, @error_procs)
|
63
|
-
@response = @error_handler.run
|
86
|
+
@first_exception, @last_exception = Factory.exception, Factory.exception
|
87
|
+
@error_handler.error_procs.first.raise_exception = @first_exception
|
88
|
+
@error_handler.error_procs.last.raise_exception = @last_exception
|
89
|
+
|
90
|
+
@error_handler.run
|
64
91
|
end
|
65
92
|
|
66
|
-
should "
|
67
|
-
|
68
|
-
assert_equal true, @fake_sinatra_call.settings.second_proc_run
|
69
|
-
assert_equal true, @fake_sinatra_call.settings.third_proc_run
|
93
|
+
should "call each of its procs" do
|
94
|
+
subject.error_procs.each{ |proc_spy| assert_true proc_spy.called }
|
70
95
|
end
|
71
96
|
|
72
|
-
should "
|
73
|
-
assert_equal
|
97
|
+
should "call each proc with the most recently raised exception" do
|
98
|
+
assert_equal @exception, @error_handler.error_procs.first.exception
|
99
|
+
assert_equal @first_exception, @error_handler.error_procs.last.exception
|
100
|
+
end
|
101
|
+
|
102
|
+
should "alter the handler's exception to be the last raised exception" do
|
103
|
+
assert_equal @last_exception, subject.exception
|
74
104
|
end
|
75
105
|
|
76
106
|
end
|
77
107
|
|
78
|
-
class
|
79
|
-
desc "
|
108
|
+
class ContextTests < UnitTests
|
109
|
+
desc "Context"
|
80
110
|
setup do
|
81
|
-
@
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
]
|
90
|
-
|
91
|
-
|
92
|
-
@
|
111
|
+
@context = Context.new(@context_hash)
|
112
|
+
end
|
113
|
+
subject{ @context }
|
114
|
+
|
115
|
+
should have_readers :server_data
|
116
|
+
should have_readers :request, :response, :handler_class, :handler, :params
|
117
|
+
|
118
|
+
should "know its attributes" do
|
119
|
+
assert_equal @context_hash[:server_data], subject.server_data
|
120
|
+
assert_equal @context_hash[:request], subject.request
|
121
|
+
assert_equal @context_hash[:response], subject.response
|
122
|
+
assert_equal @context_hash[:handler_class], subject.handler_class
|
123
|
+
assert_equal @context_hash[:handler], subject.handler
|
124
|
+
assert_equal @context_hash[:params], subject.params
|
93
125
|
end
|
94
126
|
|
95
|
-
should "
|
96
|
-
|
97
|
-
|
127
|
+
should "know if it equals another context" do
|
128
|
+
exp = Context.new(@context_hash)
|
129
|
+
assert_equal exp, subject
|
130
|
+
|
131
|
+
exp = Context.new({})
|
132
|
+
assert_not_equal exp, subject
|
98
133
|
end
|
99
134
|
|
100
|
-
|
101
|
-
|
135
|
+
end
|
136
|
+
|
137
|
+
class ErrorProcSpy
|
138
|
+
attr_reader :called, :exception, :context
|
139
|
+
attr_accessor :response, :raise_exception
|
140
|
+
|
141
|
+
def initialize
|
142
|
+
@called = false
|
102
143
|
end
|
103
144
|
|
145
|
+
def call(exception, context)
|
146
|
+
@called = true
|
147
|
+
@exception = exception
|
148
|
+
@context = context
|
149
|
+
|
150
|
+
raise self.raise_exception if self.raise_exception
|
151
|
+
@response
|
152
|
+
end
|
104
153
|
end
|
105
154
|
|
106
155
|
end
|
@@ -3,7 +3,6 @@ require 'deas/handler_proxy'
|
|
3
3
|
|
4
4
|
require 'deas/exceptions'
|
5
5
|
require 'deas/sinatra_runner'
|
6
|
-
require 'test/support/fake_sinatra_call'
|
7
6
|
require 'test/support/view_handlers'
|
8
7
|
|
9
8
|
class Deas::HandlerProxy
|
@@ -39,41 +38,43 @@ class Deas::HandlerProxy
|
|
39
38
|
|
40
39
|
Assert.stub(@proxy, :handler_class){ EmptyViewHandler }
|
41
40
|
|
42
|
-
@
|
43
|
-
@
|
41
|
+
@server_data = Factory.server_data
|
42
|
+
@fake_sinatra_call = Factory.sinatra_call
|
43
|
+
@proxy.run(@server_data, @fake_sinatra_call)
|
44
44
|
end
|
45
45
|
|
46
46
|
should "build and run a sinatra runner" do
|
47
47
|
assert_equal subject.handler_class, @runner_spy.handler_class
|
48
48
|
|
49
49
|
exp_args = {
|
50
|
-
:sinatra_call
|
51
|
-
:request
|
52
|
-
:response
|
53
|
-
:session
|
54
|
-
:params
|
55
|
-
:logger
|
56
|
-
:router
|
57
|
-
:template_source => @
|
50
|
+
:sinatra_call => @fake_sinatra_call,
|
51
|
+
:request => @fake_sinatra_call.request,
|
52
|
+
:response => @fake_sinatra_call.response,
|
53
|
+
:session => @fake_sinatra_call.session,
|
54
|
+
:params => @fake_sinatra_call.params,
|
55
|
+
:logger => @server_data.logger,
|
56
|
+
:router => @server_data.router,
|
57
|
+
:template_source => @server_data.template_source
|
58
58
|
}
|
59
59
|
assert_equal exp_args, @runner_spy.args
|
60
60
|
|
61
61
|
assert_true @runner_spy.run_called
|
62
62
|
end
|
63
63
|
|
64
|
-
should "add the
|
64
|
+
should "add data to the request env to make it available to Rack" do
|
65
|
+
exp = subject.handler_class
|
66
|
+
assert_equal exp, @fake_sinatra_call.request.env['deas.handler_class']
|
67
|
+
|
68
|
+
exp = @runner_spy.handler
|
69
|
+
assert_equal exp, @fake_sinatra_call.request.env['deas.handler']
|
70
|
+
|
65
71
|
exp = @runner_spy.params
|
66
72
|
assert_equal exp, @fake_sinatra_call.request.env['deas.params']
|
67
73
|
end
|
68
74
|
|
69
|
-
should "
|
70
|
-
exp = subject.handler_class.name
|
71
|
-
assert_equal exp, @fake_sinatra_call.request.env['deas.handler_class_name']
|
72
|
-
end
|
73
|
-
|
74
|
-
should "log the handler and params" do
|
75
|
+
should "log the handler class name and the params" do
|
75
76
|
exp_msgs = [
|
76
|
-
" Handler: #{subject.handler_class}",
|
77
|
+
" Handler: #{subject.handler_class.name}",
|
77
78
|
" Params: #{@runner_spy.params.inspect}"
|
78
79
|
]
|
79
80
|
assert_equal exp_msgs, @fake_sinatra_call.request.logging_msgs
|
@@ -84,7 +85,7 @@ class Deas::HandlerProxy
|
|
84
85
|
class SinatraRunnerSpy
|
85
86
|
|
86
87
|
attr_reader :run_called
|
87
|
-
attr_reader :handler_class, :args
|
88
|
+
attr_reader :handler_class, :handler, :args
|
88
89
|
attr_reader :sinatra_call
|
89
90
|
attr_reader :request, :response, :session, :params
|
90
91
|
attr_reader :logger, :router, :template_source
|
@@ -94,15 +95,17 @@ class Deas::HandlerProxy
|
|
94
95
|
end
|
95
96
|
|
96
97
|
def build(handler_class, args)
|
97
|
-
@handler_class
|
98
|
-
|
99
|
-
@
|
100
|
-
|
101
|
-
@
|
102
|
-
@
|
103
|
-
@
|
104
|
-
@
|
105
|
-
@
|
98
|
+
@handler_class = handler_class
|
99
|
+
@handler = handler_class.new(self)
|
100
|
+
@args = args
|
101
|
+
|
102
|
+
@sinatra_call = args[:sinatra_call]
|
103
|
+
@request = args[:request]
|
104
|
+
@response = args[:response]
|
105
|
+
@session = args[:session]
|
106
|
+
@params = args[:params]
|
107
|
+
@logger = args[:logger]
|
108
|
+
@router = args[:router]
|
106
109
|
@template_source = args[:template_source]
|
107
110
|
end
|
108
111
|
|