deas 0.36.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|