sanford 0.1.0 → 0.2.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.
Files changed (43) hide show
  1. data/bench/report.txt +34 -4
  2. data/bench/runner.rb +122 -1
  3. data/bench/services.rb +5 -2
  4. data/lib/sanford/error_handler.rb +60 -0
  5. data/lib/sanford/exceptions.rb +11 -10
  6. data/lib/sanford/host.rb +79 -101
  7. data/lib/sanford/host_data.rb +55 -0
  8. data/lib/sanford/logger.rb +23 -0
  9. data/lib/sanford/manager.rb +13 -22
  10. data/lib/sanford/rake.rb +1 -0
  11. data/lib/sanford/runner.rb +50 -0
  12. data/lib/sanford/server.rb +31 -15
  13. data/lib/sanford/service_handler.rb +34 -43
  14. data/lib/sanford/test_runner.rb +47 -0
  15. data/lib/sanford/version.rb +1 -1
  16. data/lib/sanford/worker.rb +124 -0
  17. data/lib/sanford.rb +49 -6
  18. data/sanford.gemspec +1 -1
  19. data/test/helper.rb +1 -0
  20. data/test/support/fake_connection.rb +18 -0
  21. data/test/support/helpers.rb +6 -10
  22. data/test/support/service_handlers.rb +56 -68
  23. data/test/support/services.rb +55 -10
  24. data/test/system/managing_test.rb +18 -18
  25. data/test/system/request_handling_test.rb +10 -100
  26. data/test/unit/config_test.rb +1 -43
  27. data/test/unit/error_handler_test.rb +133 -0
  28. data/test/unit/host_configuration_test.rb +41 -0
  29. data/test/unit/host_data_test.rb +65 -0
  30. data/test/unit/host_test.rb +20 -112
  31. data/test/unit/{host/version_group_test.rb → host_version_group_test.rb} +0 -0
  32. data/test/unit/hosts_test.rb +56 -0
  33. data/test/unit/manager_test.rb +3 -3
  34. data/test/unit/runner_test.rb +26 -0
  35. data/test/unit/server_test.rb +10 -2
  36. data/test/unit/service_handler_test.rb +126 -115
  37. data/test/unit/worker_test.rb +195 -0
  38. metadata +28 -16
  39. data/lib/sanford/config.rb +0 -33
  40. data/lib/sanford/connection.rb +0 -70
  41. data/lib/sanford/exception_handler.rb +0 -43
  42. data/test/unit/connection_test.rb +0 -23
  43. data/test/unit/exception_handler_test.rb +0 -69
@@ -1,115 +1,103 @@
1
- # A bunch of service handler examples. These are defined to implement certain
2
- # edge cases and are for specific tests within the test suite.
3
- #
4
-
5
- class StaticServiceHandler
1
+ class TestServiceHandler
6
2
  include Sanford::ServiceHandler
7
3
 
8
- # builds with the same request and logger always, just for convenience
9
-
10
- def initialize(logger = nil, request = nil)
11
- request ||= Sanford::Protocol::Request.new('v1', 'name', {})
12
- super(logger || Sanford::NullLogger.new, request)
13
- end
14
-
15
4
  end
16
5
 
17
- class ManualThrowServiceHandler < StaticServiceHandler
6
+ class BasicServiceHandler
7
+ include Sanford::ServiceHandler
18
8
 
19
9
  def run!
20
- throw(:halt, 'halted!')
10
+ { 'name' => 'Joe Test', 'email' => "joe.test@example.com" }
21
11
  end
22
12
 
23
13
  end
24
14
 
25
- class HaltWithServiceHandler < StaticServiceHandler
15
+ class FlagServiceHandler
16
+ include Sanford::ServiceHandler
26
17
 
27
- def initialize(halt_with)
28
- request = Sanford::Protocol::Request.new('v1', 'name', {
29
- 'halt_with' => halt_with.dup
30
- })
31
- super(Sanford::NullLogger.new, request)
32
- end
18
+ attr_reader :before_init_called, :init_bang_called, :after_init_called,
19
+ :before_run_called, :run_bang_called, :after_run_called
33
20
 
34
- def run!
35
- params['halt_with'].tap do |halt_with|
36
- halt(halt_with.delete('code'), halt_with)
37
- end
21
+ def before_init
22
+ @before_init_called = true
38
23
  end
39
24
 
40
- end
25
+ def init!
26
+ @init_bang_called = true
27
+ end
41
28
 
42
- class NoopServiceHandler < StaticServiceHandler
29
+ def after_init
30
+ @after_init_called = true
31
+ end
43
32
 
44
- # simply overwrites the default `run!` so it doesn't error
33
+ def before_run
34
+ @before_run_called = true
35
+ end
45
36
 
46
37
  def run!
47
- # nothing!
38
+ @run_bang_called = true
39
+ end
40
+
41
+ def after_run
42
+ @after_run_called = true
48
43
  end
49
44
 
50
45
  end
51
46
 
52
- class FlaggedServiceHandler < NoopServiceHandler
47
+ class HaltServiceHandler
48
+ include Sanford::ServiceHandler
53
49
 
54
- # flags a bunch of methods as they are run by setting instance variables
50
+ def run!
51
+ halt params['code'], :message => params['message'], :data => params['data']
52
+ end
55
53
 
56
- FLAGGED_METHODS = {
57
- 'init' => :init_called,
58
- 'init!' => :init_bang_called,
59
- 'run!' => :run_bang_called,
60
- 'before_run' => :before_run_called,
61
- 'after_run' => :after_run_called
62
- }
63
- FLAGS = FLAGGED_METHODS.values
54
+ end
64
55
 
65
- attr_reader *FLAGS
56
+ class HaltingBehaviorServiceHandler < FlagServiceHandler
66
57
 
67
- def initialize(*passed)
58
+ def before_init
68
59
  super
69
- FLAGS.each{|name| self.instance_variable_set("@#{name}", false) }
60
+ halt_when('before_init')
70
61
  end
71
62
 
72
- FLAGGED_METHODS.each do |method_name, instance_variable_name|
73
-
74
- # def before_run
75
- # super
76
- # @before_run_called = true
77
- # end
78
- define_method(method_name) do
79
- super
80
- self.instance_variable_set("@#{instance_variable_name}", true)
81
- end
82
-
63
+ def init!
64
+ super
65
+ halt_when('init!')
83
66
  end
84
67
 
85
- end
86
-
87
- class ConfigurableServiceHandler < FlaggedServiceHandler
88
-
89
- def initialize(options = {})
90
- @options = options
68
+ def after_init
91
69
  super
70
+ halt_when('after_init')
92
71
  end
93
72
 
94
73
  def before_run
95
74
  super
96
- if @options[:before_run]
97
- self.instance_eval(&@options[:before_run])
98
- end
75
+ halt_when('before_run')
99
76
  end
100
77
 
101
78
  def run!
102
79
  super
103
- if @options[:run!]
104
- self.instance_eval(&@options[:run!])
105
- end
80
+ halt_when('run!')
106
81
  end
107
82
 
108
83
  def after_run
109
84
  super
110
- if @options[:after_run]
111
- self.instance_eval(&@options[:after_run])
112
- end
85
+ halt_when('after_run')
86
+ end
87
+
88
+ def halt_when(method_name)
89
+ return if ![*params['when']].include?(method_name)
90
+ halt(200, {
91
+ :message => "#{method_name} halting",
92
+ :data => {
93
+ :before_init_called => @before_init_called,
94
+ :init_bang_called => @init_bang_called,
95
+ :after_init_called => @after_init_called,
96
+ :before_run_called => @before_run_called,
97
+ :run_bang_called => @run_bang_called,
98
+ :after_run_called => @after_run_called
99
+ }
100
+ })
113
101
  end
114
102
 
115
103
  end
@@ -1,23 +1,32 @@
1
1
  require 'logger'
2
2
 
3
- class DummyHost
3
+ class TestHost
4
4
  include Sanford::Host
5
5
 
6
6
  ip 'localhost'
7
7
  port 12000
8
8
  pid_dir File.expand_path('../../../tmp/', __FILE__)
9
9
 
10
- logger = Logger.new(File.expand_path("../../../log/test.log", __FILE__))
11
- logger.level = Logger::DEBUG
10
+ logger(Logger.new(File.expand_path("../../../log/test.log", __FILE__)).tap do |logger|
11
+ logger.level = Logger::DEBUG
12
+ end)
13
+ verbose_logging true
12
14
 
13
- version 'v1' do
14
- service_handler_ns 'DummyHost'
15
+ error do |exception, host_data, request|
16
+ if exception.kind_of?(::MyCustomError)
17
+ Sanford::Protocol::Response.new([ 987, 'custom error!' ])
18
+ end
19
+ end
15
20
 
16
- service 'echo', 'Echo'
17
- service 'bad', 'Bad'
18
- service 'multiply', 'Multiply'
19
- service 'halt_it', '::DummyHost::HaltIt'
20
- service 'authorized', 'Authorized'
21
+ version 'v1' do
22
+ service_handler_ns 'TestHost'
23
+
24
+ service 'echo', 'Echo'
25
+ service 'bad', 'Bad'
26
+ service 'multiply', 'Multiply'
27
+ service 'halt_it', '::TestHost::HaltIt'
28
+ service 'authorized', 'Authorized'
29
+ service 'custom_error', 'CustomError'
21
30
  end
22
31
 
23
32
  class Echo
@@ -69,4 +78,40 @@ class DummyHost
69
78
 
70
79
  end
71
80
 
81
+ ::MyCustomError = Class.new(RuntimeError)
82
+
83
+ class CustomError
84
+ include Sanford::ServiceHandler
85
+
86
+ def run!
87
+ raise ::MyCustomError
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ class MyHost
95
+ include Sanford::Host
96
+
97
+ name 'my_host'
98
+ ip 'my.local'
99
+ end
100
+
101
+ class InvalidHost
102
+ include Sanford::Host
103
+
104
+ name 'invalid_host'
105
+ end
106
+
107
+ class UndefinedHandlersHost
108
+ include Sanford::Host
109
+
110
+ version 'v1' do
111
+ service 'undefined', 'ThisIsNotDefined'
112
+ end
113
+ end
114
+
115
+ class EmptyHost
116
+ include Sanford::Host
72
117
  end
@@ -1,5 +1,7 @@
1
1
  require 'assert'
2
2
 
3
+ require 'sanford/manager'
4
+
3
5
  class ManagingTest < Assert::Context
4
6
  desc "Using Sanford's manager"
5
7
  setup do
@@ -15,7 +17,7 @@ class ManagingTest < Assert::Context
15
17
  include Test::ForkManagerHelper
16
18
 
17
19
  setup do
18
- Sanford.config.hosts.add(DummyHost)
20
+ Sanford.register(TestHost)
19
21
  end
20
22
  end
21
23
 
@@ -23,11 +25,9 @@ class ManagingTest < Assert::Context
23
25
  desc "to run a service host"
24
26
 
25
27
  should "start a sanford server for the only service host that is configured" do
26
- host = Sanford.config.hosts.first
27
-
28
28
  self.call_sanford_manager(:run) do
29
- assert_nothing_raised{ self.open_socket(host.config.ip, host.config.port) }
30
- assert File.exists?(self.expected_pid_file(host, host.config.ip, host.config.port))
29
+ assert_nothing_raised{ self.open_socket(TestHost.ip, TestHost.port) }
30
+ assert File.exists?(self.expected_pid_file(TestHost, TestHost.ip, TestHost.port))
31
31
  end
32
32
  end
33
33
  end
@@ -35,17 +35,17 @@ class ManagingTest < Assert::Context
35
35
  class RunWithOptionsTest < CallTest
36
36
  desc "to run a service host and passing options"
37
37
  setup do
38
- # make sure that DummyHost isn't the only 'host'
39
- Sanford.config.hosts.add(Class.new)
38
+ # make sure that TestHost isn't the only 'host'
39
+ Sanford.register(Class.new)
40
40
  end
41
41
 
42
42
  should "start a sanford server for the specified service host and " \
43
43
  "use the passed options to override it's configuration" do
44
- host = Sanford.config.find_host('DummyHost')
44
+ host = Sanford.hosts.find('TestHost')
45
45
 
46
- self.call_sanford_manager(:run, { :host => 'DummyHost', :port => 12345 }) do
47
- assert_nothing_raised{ self.open_socket(host.config.ip, 12345) }
48
- assert File.exists?(self.expected_pid_file(host, host.config.ip, 12345))
46
+ self.call_sanford_manager(:run, { :host => 'TestHost', :port => 12345 }) do
47
+ assert_nothing_raised{ self.open_socket(host.ip, 12345) }
48
+ assert File.exists?(self.expected_pid_file(host, host.ip, 12345))
49
49
  end
50
50
  end
51
51
  end
@@ -54,10 +54,10 @@ class ManagingTest < Assert::Context
54
54
  desc "to run a service host and setting env vars"
55
55
  setup do
56
56
  @current = ENV.delete('SANFORD_HOST'), ENV.delete('SANFORD_IP'), ENV.delete('SANFORD_PORT')
57
- ENV['SANFORD_HOST'] = 'DummyHost'
57
+ ENV['SANFORD_HOST'] = 'TestHost'
58
58
  ENV['SANFORD_IP'], ENV['SANFORD_PORT'] = 'localhost', '54321'
59
- # make sure that DummyHost isn't the only 'host'
60
- Sanford.config.hosts.add(Class.new)
59
+ # make sure that TestHost isn't the only 'host'
60
+ Sanford.register(Class.new)
61
61
  end
62
62
  teardown do
63
63
  ENV['SANFORD_HOST'], ENV['SANFORD_IP'], ENV['SANFORD_PORT'] = @current
@@ -65,7 +65,7 @@ class ManagingTest < Assert::Context
65
65
 
66
66
  should "start a sanford server for the specified service host and " \
67
67
  "use the env vars to override it's configuration" do
68
- host = Sanford.config.find_host(ENV['SANFORD_HOST'])
68
+ host = Sanford.hosts.find(ENV['SANFORD_HOST'])
69
69
  port = ENV['SANFORD_PORT'].to_i
70
70
 
71
71
  self.call_sanford_manager(:run) do
@@ -78,8 +78,8 @@ class ManagingTest < Assert::Context
78
78
  class BadHostTest < ManagingTest
79
79
  desc "with a bad host name"
80
80
  setup do
81
- Sanford.config.hosts.clear
82
- Sanford.config.hosts.add(Class.new)
81
+ Sanford.hosts.clear
82
+ Sanford.register(Class.new)
83
83
  end
84
84
 
85
85
  should "raise an exception when a service host can't be found" do
@@ -92,7 +92,7 @@ class ManagingTest < Assert::Context
92
92
  class NoHostsTest < ManagingTest
93
93
  desc "with no hosts"
94
94
  setup do
95
- Sanford.config.hosts.clear
95
+ Sanford.hosts.clear
96
96
  end
97
97
 
98
98
  should "raise an exception when there aren't any service hosts" do
@@ -1,16 +1,18 @@
1
1
  # This test is intended as a high level test against Sanford's server. This will
2
2
  # use multiple request scenarios to test out Sanford's behavior and how it
3
- # responds.
3
+ # responds. These tests depend on a socket (or the protocol's connection) and
4
+ # thus are a system level test.
4
5
  #
5
6
  require 'assert'
6
7
 
8
+ require 'sanford/manager'
9
+
7
10
  class RequestHandlingTest < Assert::Context
8
11
  include Test::ForkServerHelper
9
12
 
10
13
  desc "Sanford's handling of requests"
11
14
  setup do
12
- @service_host = DummyHost.new
13
- @server = Sanford::Server.new(@service_host, { :ready_timeout => 0 })
15
+ @server = Sanford::Server.new(TestHost, { :ready_timeout => 0 })
14
16
  end
15
17
 
16
18
  # Simple service test that echos back the params sent to it
@@ -19,7 +21,7 @@ class RequestHandlingTest < Assert::Context
19
21
 
20
22
  should "return a successful response and echo the params sent to it" do
21
23
  self.start_server(@server) do
22
- response = SimpleClient.call_with_request(@service_host, 'v1', 'echo', {
24
+ response = SimpleClient.call_with_request(TestHost, 'v1', 'echo', {
23
25
  :message => 'test'
24
26
  })
25
27
 
@@ -47,7 +49,7 @@ class RequestHandlingTest < Assert::Context
47
49
  should "return a bad request response with an error message" do
48
50
  self.start_server(@server) do
49
51
  bytes = [ Sanford::Protocol.msg_version, "\000" ].join
50
- response = SimpleClient.call_with(@service_host, bytes)
52
+ response = SimpleClient.call_with(TestHost, bytes)
51
53
 
52
54
  assert_equal 400, response.status.code
53
55
  assert_match "size", response.status.message
@@ -63,7 +65,7 @@ class RequestHandlingTest < Assert::Context
63
65
  should "return a bad request response with an error message" do
64
66
  self.start_server(@server) do
65
67
  bytes = [ Sanford::Protocol.msg_version, "\000" ].join
66
- response = SimpleClient.call_with_msg_body(@service_host, {}, nil, "\000")
68
+ response = SimpleClient.call_with_msg_body(TestHost, {}, nil, "\000")
67
69
 
68
70
  assert_equal 400, response.status.code
69
71
  assert_match "Protocol version", response.status.message
@@ -77,7 +79,7 @@ class RequestHandlingTest < Assert::Context
77
79
  desc "when sent a request with an invalid body"
78
80
  should "return a bad request response with an error message" do
79
81
  self.start_server(@server) do
80
- response = SimpleClient.call_with_encoded_msg_body(@service_host, "\000\001\010\011" * 2)
82
+ response = SimpleClient.call_with_encoded_msg_body(TestHost, "\000\001\010\011" * 2)
81
83
 
82
84
  assert_equal 400, response.status.code
83
85
  assert_match "body", response.status.message
@@ -86,98 +88,6 @@ class RequestHandlingTest < Assert::Context
86
88
  end
87
89
  end
88
90
 
89
- class MissingServiceNameTest < ErroringRequestTest
90
- desc "when sent a request with no service name"
91
-
92
- should "return a bad request response" do
93
- self.start_server(@server) do
94
- request_hash = Sanford::Protocol::Request.new('v1', 'what', {}).to_hash
95
- request_hash.delete('name')
96
- response = SimpleClient.call_with_msg_body(@service_host, request_hash)
97
-
98
- assert_equal 400, response.status.code
99
- assert_match "request", response.status.message
100
- assert_match "name", response.status.message
101
- assert_equal nil, response.data
102
- end
103
- end
104
- end
105
-
106
- class MissingServiceVersionTest < ErroringRequestTest
107
- desc "when sent a request with no service version"
108
-
109
- should "return a bad request response" do
110
- self.start_server(@server) do
111
- request_hash = Sanford::Protocol::Request.new('v1', 'what', {}).to_hash
112
- request_hash.delete('version')
113
- response = SimpleClient.call_with_msg_body(@service_host, request_hash)
114
-
115
- assert_equal 400, response.status.code
116
- assert_match "request", response.status.message
117
- assert_match "version", response.status.message
118
- assert_equal nil, response.data
119
- end
120
- end
121
- end
122
-
123
- # Requesting a service that is not defined
124
- class NotFoundServiceTest < ErroringRequestTest
125
- desc "when sent a request with no matching service name"
126
-
127
- should "return a bad request response" do
128
- self.start_server(@server) do
129
- response = SimpleClient.call_with_request(@service_host, 'v1', 'what', {})
130
-
131
- assert_equal 404, response.status.code
132
- assert_equal nil, response.status.message
133
- assert_equal nil, response.data
134
- end
135
- end
136
- end
137
-
138
- # Hitting a service that throws an exception
139
- class ErrorServiceTest < ErroringRequestTest
140
- desc "when sent a request that errors on the server"
141
-
142
- should "return a bad request response" do
143
- self.start_server(@server) do
144
- response = SimpleClient.call_with_request(@service_host, 'v1', 'bad', {})
145
-
146
- assert_equal 500, response.status.code
147
- assert_match "error", response.status.message
148
- assert_equal nil, response.data
149
- end
150
- end
151
- end
152
-
153
- class HaltTest < RequestHandlingTest
154
- desc "when sent a request that halts"
155
-
156
- should "return the response that was halted" do
157
- self.start_server(@server) do
158
- response = SimpleClient.call_with_request(@service_host, 'v1', 'halt_it', {})
159
-
160
- assert_equal 728, response.status.code
161
- assert_equal "I do what I want", response.status.message
162
- assert_equal [ 1, true, 'yes' ], response.data
163
- end
164
- end
165
- end
166
-
167
- class AuthorizeRequestTest < RequestHandlingTest
168
- desc "when sent a request that halts in a callback"
169
-
170
- should "return the response that was halted" do
171
- self.start_server(@server) do
172
- response = SimpleClient.call_with_request(@service_host, 'v1', 'authorized', {})
173
-
174
- assert_equal 401, response.status.code
175
- assert_equal "Not authorized", response.status.message
176
- assert_equal nil, response.data
177
- end
178
- end
179
- end
180
-
181
91
  class HangingRequestTest < ErroringRequestTest
182
92
  desc "when a client connects but doesn't send anything"
183
93
  setup do
@@ -189,7 +99,7 @@ class RequestHandlingTest < Assert::Context
189
99
 
190
100
  should "timeout" do
191
101
  self.start_server(@server) do
192
- client = SimpleClient.new(@service_host, :with_delay => 0.2)
102
+ client = SimpleClient.new(TestHost, :with_delay => 0.2)
193
103
  response = client.call_with_request('v1', 'echo', { :message => 'test' })
194
104
 
195
105
  assert_equal 408, response.status.code
@@ -6,49 +6,7 @@ module Sanford::Config
6
6
  desc "Sanford::Config"
7
7
  subject{ Sanford::Config }
8
8
 
9
- should have_instance_methods :hosts, :services_config, :find_host
10
- end
11
-
12
- class FindHostTest < BaseTest
13
- desc "find_host"
14
- setup do
15
- Test::Environment.store_and_clear_hosts
16
- Sanford::Config.hosts.add(NotNamedHost)
17
- Sanford::Config.hosts.add(NamedHost)
18
- Sanford::Config.hosts.add(BadlyNamedHost)
19
- end
20
- teardown do
21
- Test::Environment.restore_hosts
22
- end
23
-
24
- should "allow finding hosts by their class name or configured name" do
25
- assert_includes NotNamedHost, subject.hosts
26
- assert_includes NamedHost, subject.hosts
27
- assert_equal NotNamedHost, subject.find_host('NotNamedHost')
28
- assert_equal NamedHost, subject.find_host('NamedHost')
29
- assert_equal NamedHost, subject.find_host('named_host')
30
- end
31
- should "check class name before configured name" do
32
- assert_includes BadlyNamedHost, subject.hosts
33
- assert_equal NotNamedHost, subject.find_host('NotNamedHost')
34
- end
35
- end
36
-
37
- # Using this syntax because these classes need to be defined as top-level
38
- # constants for ease in using their class names in the tests
39
-
40
- ::NotNamedHost = Class.new do
41
- include Sanford::Host
42
- end
43
-
44
- ::NamedHost = Class.new do
45
- include Sanford::Host
46
- name 'named_host'
47
- end
48
-
49
- ::BadlyNamedHost = Class.new do
50
- include Sanford::Host
51
- name 'NotNamedHost'
9
+ should have_instance_methods :services_config
52
10
  end
53
11
 
54
12
  end