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
@@ -0,0 +1,133 @@
1
+ require 'assert'
2
+
3
+ class Sanford::ErrorHandler
4
+
5
+ class BaseTest < Assert::Context
6
+ desc "Sanford::ErrorHandler"
7
+ setup do
8
+ @exception = RuntimeError.new('test')
9
+ @host_data = Sanford::HostData.new(EmptyHost, { :ip => "localhost", :port => 8000 })
10
+ @error_handler = Sanford::ErrorHandler.new(@exception, @host_data)
11
+ end
12
+ subject{ @error_handler }
13
+
14
+ should have_instance_methods :exception, :host_data, :request, :run
15
+
16
+ should "return a Sanford::Protocol::Response with `run`" do
17
+ assert_instance_of Sanford::Protocol::Response, subject.run
18
+ end
19
+
20
+ def generate_exception(exception_class, message = nil)
21
+ exception = nil
22
+ begin
23
+ raise exception_class, message
24
+ rescue Exception => exception
25
+ end
26
+ exception
27
+ end
28
+
29
+ end
30
+
31
+ class ResponseFromProcTest < BaseTest
32
+ desc "generating a respone from an error proc"
33
+ setup do
34
+ @host_defaults = { :ip => "localhost", :port => 8000 }
35
+ end
36
+
37
+ should "use the return-value of the error proc if it is a protocol response" do
38
+ error_proc = proc do |exception, host_data, request|
39
+ Sanford::Protocol::Response.new([ 567, 'custom message'], 'custom data')
40
+ end
41
+ host_data = Sanford::HostData.new(EmptyHost, @host_defaults.merge({
42
+ :error_proc => error_proc
43
+ }))
44
+ response = Sanford::ErrorHandler.new(@exception, host_data).run
45
+
46
+ assert_equal 567, response.code
47
+ assert_equal 'custom message', response.status.message
48
+ assert_equal 'custom data', response.data
49
+ end
50
+
51
+ should "use an integer returned by the error proc to generate a protocol response" do
52
+ host_data = Sanford::HostData.new(EmptyHost, @host_defaults.merge({
53
+ :error_proc => proc{ 345 }
54
+ }))
55
+ response = Sanford::ErrorHandler.new(@exception, host_data).run
56
+
57
+ assert_equal 345, response.code
58
+ assert_nil response.status.message
59
+ assert_nil response.data
60
+ end
61
+
62
+ should "use a symbol returned by the error proc to generate a protocol response" do
63
+ host_data = Sanford::HostData.new(EmptyHost, @host_defaults.merge({
64
+ :error_proc => proc{ :not_found }
65
+ }))
66
+ response = Sanford::ErrorHandler.new(@exception, host_data).run
67
+
68
+ assert_equal 404, response.code
69
+ assert_nil response.status.message
70
+ assert_nil response.data
71
+ end
72
+
73
+ should "use the default behavior if the error proc doesn't return a valid response result" do
74
+ host_data = Sanford::HostData.new(EmptyHost, @host_defaults.merge({
75
+ :error_proc => proc{ true }
76
+ }))
77
+ response = Sanford::ErrorHandler.new(@exception, host_data).run
78
+
79
+ assert_equal 500, response.code
80
+ assert_equal 'An unexpected error occurred.', response.status.message
81
+ end
82
+
83
+ should "use the default behavior for an exception raised by the error proc " \
84
+ "and ignore the original exception" do
85
+ host_data = Sanford::HostData.new(EmptyHost, @host_defaults.merge({
86
+ :error_proc => proc{ raise Sanford::NotFoundError }
87
+ }))
88
+ response = Sanford::ErrorHandler.new(@exception, host_data).run
89
+
90
+ assert_equal 404, response.code
91
+ assert_nil response.status.message
92
+ assert_nil response.data
93
+ end
94
+
95
+ end
96
+
97
+ class ResponseFromExceptionTest < BaseTest
98
+ desc "generating a respone from an exception"
99
+
100
+ should "build a 400 response with a protocol BadMessageError" do
101
+ exception = generate_exception(Sanford::Protocol::BadMessageError, 'bad message')
102
+ response = Sanford::ErrorHandler.new(exception, @host_data).run
103
+
104
+ assert_equal 400, response.code
105
+ assert_equal 'bad message', response.status.message
106
+ end
107
+
108
+ should "build a 400 response with a protocol BadRequestError" do
109
+ exception = generate_exception(Sanford::Protocol::BadRequestError, 'bad request')
110
+ response = Sanford::ErrorHandler.new(exception, @host_data).run
111
+
112
+ assert_equal 400, response.code
113
+ assert_equal 'bad request', response.status.message
114
+ end
115
+
116
+ should "build a 404 response with a NotFoundError" do
117
+ exception = generate_exception(Sanford::NotFoundError, 'not found')
118
+ response = Sanford::ErrorHandler.new(exception, @host_data).run
119
+
120
+ assert_equal 404, response.code
121
+ assert_nil response.status.message
122
+ end
123
+
124
+ should "build a 500 response with all other exceptions" do
125
+ response = Sanford::ErrorHandler.new(RuntimeError.new('test'), @host_data).run
126
+
127
+ assert_equal 500, response.code
128
+ assert_equal 'An unexpected error occurred.', response.status.message
129
+ end
130
+
131
+ end
132
+
133
+ end
@@ -0,0 +1,41 @@
1
+ require 'assert'
2
+
3
+ class Sanford::Host::Configuration
4
+
5
+ class BaseTest < Assert::Context
6
+ desc "Sanford::Host::Configuration"
7
+ setup do
8
+ @configuration = Sanford::Host::Configuration.new(EmptyHost.instance)
9
+ end
10
+ subject{ @configuration }
11
+
12
+ should have_instance_methods :name, :ip, :port, :pid_dir, :logger, :verbose_logging, :logger,
13
+ :error_proc
14
+
15
+ should "default name to the class name of the host" do
16
+ assert_equal 'EmptyHost', subject.name
17
+ end
18
+
19
+ should "default ip to 0.0.0.0" do
20
+ assert_equal '0.0.0.0', subject.ip
21
+ end
22
+
23
+ should "not default the port" do
24
+ assert_nil subject.port
25
+ end
26
+
27
+ should "default pid_dir to the current working directory" do
28
+ assert_equal Pathname.new(Dir.pwd), subject.pid_dir
29
+ end
30
+
31
+ should "default logger to a null logger" do
32
+ assert_instance_of Sanford::NullLogger, subject.logger
33
+ end
34
+
35
+ should "default verbose_logging to true" do
36
+ assert_equal true, subject.verbose_logging
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,65 @@
1
+ require 'assert'
2
+
3
+ require 'sanford/manager'
4
+
5
+ class Sanford::HostData
6
+
7
+ class BaseTest < Assert::Context
8
+ desc "Sanford::HostData"
9
+ setup do
10
+ @host_data = Sanford::HostData.new(TestHost)
11
+ end
12
+ subject{ @host_data }
13
+
14
+ should have_instance_methods :name, :ip, :port, :pid_dir, :logger, :verbose,
15
+ :error_proc, :handler_class_for
16
+
17
+ should "default it's configuration from the service host, but allow overrides" do
18
+ host_data = Sanford::HostData.new(TestHost, :ip => '1.2.3.4', :port => 12345)
19
+
20
+ assert_equal 'TestHost', host_data.name
21
+ assert_equal '1.2.3.4', host_data.ip
22
+ assert_equal 12345, host_data.port
23
+ end
24
+
25
+ should "constantize a host's handlers" do
26
+ handlers = subject.instance_variable_get("@handlers")
27
+
28
+ assert_equal TestHost::Authorized, handlers['v1']['authorized']
29
+ assert_equal TestHost::Bad, handlers['v1']['bad']
30
+ assert_equal TestHost::Echo, handlers['v1']['echo']
31
+ assert_equal TestHost::HaltIt, handlers['v1']['halt_it']
32
+ assert_equal TestHost::Multiply, handlers['v1']['multiply']
33
+ end
34
+
35
+ should "ignore nil values passed as overrides" do
36
+ host_data = Sanford::HostData.new(TestHost, :ip => nil)
37
+
38
+ assert_not_nil host_data.ip
39
+ end
40
+
41
+ should "raise a custom exception when passed invalid host" do
42
+ assert_raises(Sanford::InvalidHostError) do
43
+ Sanford::Manager.new(InvalidHost)
44
+ end
45
+ end
46
+
47
+ should "look up handler classes with #handler_class_for" do
48
+ assert_equal TestHost::Echo, subject.handler_class_for('v1', 'echo')
49
+ end
50
+
51
+ should "raise a custom error when handler_class_for is called with an unknown service" do
52
+ assert_raises(Sanford::NotFoundError) do
53
+ subject.handler_class_for('not', 'defined')
54
+ end
55
+ end
56
+
57
+ should "raise a custom error when a service is configured with an undefined class" do
58
+ assert_raises(Sanford::NoHandlerClassError) do
59
+ Sanford::HostData.new(UndefinedHandlersHost)
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -5,138 +5,46 @@ module Sanford::Host
5
5
  class BaseTest < Assert::Context
6
6
  desc "Sanford::Host"
7
7
  setup do
8
- Test::Environment.store_and_clear_hosts
9
- @host_class = Class.new do
10
- include Sanford::Host
11
- name 'anonymous_host'
12
- ip 'anonymous.local'
13
- end
14
- @host = @host_class.new({ :port => 12345 })
8
+ @configuration = MyHost.configuration.to_hash
15
9
  end
16
10
  teardown do
17
- Test::Environment.restore_hosts
11
+ MyHost.configuration.apply(@configuration)
18
12
  end
19
- subject{ @host }
13
+ subject{ MyHost.instance }
20
14
 
21
- should have_instance_methods :name, :config, :run
15
+ should have_instance_methods :configuration, :name, :ip, :port, :pid_dir, :logger,
16
+ :verbose_logging, :error, :version, :versioned_services
22
17
 
23
- should "set name to it's class #name" do
24
- assert_equal subject.class.name, subject.name
25
- end
18
+ should "get and set it's configuration options with their matching methods" do
19
+ subject.name 'my_awesome_host'
26
20
 
27
- should "proxy missing methods to it's config" do
28
- assert_equal subject.config.port, subject.port
29
- assert subject.respond_to?(:pid_dir)
30
- end
21
+ assert_equal 'my_awesome_host', subject.name
22
+ assert_equal subject.configuration.port, subject.port
31
23
 
32
- should "default it's configuration from the class and overwrite with values passed to new" do
33
- assert_equal 'anonymous.local', subject.config.ip
34
- assert_equal 12345, subject.config.port
35
- end
36
- end
37
24
 
38
- class ConfigTest < BaseTest
39
- desc "config"
40
- setup do
41
- @config = @host.config
42
25
  end
43
- subject{ @config }
44
-
45
- should have_instance_methods :name, :ip, :port, :pid_dir, :logger
46
- end
47
-
48
- class ClassMethodsTest < BaseTest
49
- desc "class methods"
50
- subject{ @host_class }
51
26
 
52
- should have_instance_methods :config, :version
53
- should have_instance_methods :name, :ip, :port, :pid_dir, :logger
27
+ should "add a version group with #version" do
28
+ subject.version('v1'){ }
54
29
 
55
- should "have registered the class with sanford's known hosts" do
56
- assert_includes subject, Sanford.config.hosts
57
- end
58
- end
59
-
60
- class InvalidTest < BaseTest
61
- desc "invalid configuration"
62
- setup do
63
- @host_class = Class.new do
64
- include Sanford::Host
65
- name 'invalid_host'
66
- end
30
+ assert_equal({}, subject.versioned_services["v1"])
67
31
  end
68
32
 
69
- should "raise a custom exception" do
70
- assert_raises(Sanford::InvalidHostError) do
71
- @host_class.new
72
- end
73
- end
74
33
  end
75
34
 
76
- class VersionTest < BaseTest
77
- desc "version class method"
78
- setup do
79
- @host_class.version('v1'){ }
80
- end
35
+ class ClassMethodsTest < Assert::Context
36
+ desc "Sanford::Host class"
37
+ subject{ MyHost }
81
38
 
82
- should "have added a version hash to the versioned_services config" do
83
- assert_equal({}, @host_class.config.versioned_services["v1"])
84
- end
85
- end
86
-
87
- class RunTest < BaseTest
88
- desc "run method"
89
- setup do
90
- @host_class.version('v1') do
91
- service 'test', 'DummyHost::Multiply'
92
- end
93
- @host = @host_class.new({ :port => 12000 })
94
- @request = Sanford::Protocol::Request.new('v1', 'test', { 'number' => 2 })
95
- @returned = @host.run(@request)
96
- end
97
- subject{ @returned }
98
-
99
- should "have returned the data of calling the `init` and `run` method of the handler" do
100
- expected_status_code = 200
101
- expected_data = 2 * @request.params['number']
102
-
103
- assert_equal expected_status_code, subject.first
104
- assert_equal expected_data, subject.last
105
- end
106
- end
107
-
108
- class RunNotFoundTest < BaseTest
109
- desc "run method with a service and no matching service handler"
110
- setup do
111
- @host_class.version('v1') do
112
- service 'test', 'DummyHost::Echo'
113
- end
114
- @host = @host_class.new({ :port => 12000 })
115
- @request = Sanford::Protocol::Request.new('v4', 'what', {})
116
- end
117
-
118
- should "raise a Sanford::NotFound exception" do
119
- assert_raises(Sanford::NotFoundError) do
120
- @host.run(@request)
121
- end
39
+ should "proxy it's method to it's instance" do
40
+ assert_equal subject.instance.name, subject.name
41
+ assert subject.respond_to?(:pid_dir)
122
42
  end
123
- end
124
43
 
125
- class RunNoHandlerClassTest < BaseTest
126
- desc "run method with a service handler that doesn't exist"
127
- setup do
128
- @host_class.version('v1') do
129
- service 'test', 'DoesntExist::AtAll'
130
- end
131
- @host = @host_class.new({ :port => 12000 })
132
- @request = Sanford::Protocol::Request.new('v1', 'test', {})
44
+ should "have registered the class with sanford's known hosts" do
45
+ assert_includes subject, Sanford.hosts
133
46
  end
134
47
 
135
- should "raise a Sanford::NoHandlerClass exception" do
136
- assert_raises(Sanford::NoHandlerClassError) do
137
- @host.run(@request)
138
- end
139
- end
140
48
  end
141
49
 
142
50
  end
@@ -0,0 +1,56 @@
1
+ require 'assert'
2
+
3
+ class Sanford::Hosts
4
+
5
+ class BaseTest < Assert::Context
6
+ desc "Sanford::hosts"
7
+ setup do
8
+ @hosts = Sanford::Hosts.new
9
+ end
10
+ subject{ @hosts }
11
+
12
+ should have_instance_methods :add, :first, :find
13
+
14
+ end
15
+
16
+ class FindTest < BaseTest
17
+ desc "find"
18
+ setup do
19
+ @hosts.add ::NotNamedHost
20
+ @hosts.add ::NamedHost
21
+ @hosts.add ::BadlyNamedHost
22
+ end
23
+
24
+ should "allow finding hosts by their class name or configured name" do
25
+ assert_includes NotNamedHost, subject
26
+ assert_includes NamedHost, subject
27
+ assert_equal NotNamedHost, subject.find('NotNamedHost')
28
+ assert_equal NamedHost, subject.find('NamedHost')
29
+ assert_equal NamedHost, subject.find('named_host')
30
+ end
31
+
32
+ should "check class name before configured name" do
33
+ assert_includes BadlyNamedHost, subject
34
+ assert_equal NotNamedHost, subject.find('NotNamedHost')
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'
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -1,13 +1,13 @@
1
1
  require 'assert'
2
- require 'ostruct'
2
+
3
+ require 'sanford/manager'
3
4
 
4
5
  class Sanford::Manager
5
6
 
6
7
  class BaseTest < Assert::Context
7
8
  desc "Sanford::Manager"
8
9
  setup do
9
- @dummy_host = DummyHost
10
- @manager = Sanford::Manager.new(@dummy_host)
10
+ @manager = Sanford::Manager.new(TestHost)
11
11
  end
12
12
  subject{ @manager }
13
13
 
@@ -0,0 +1,26 @@
1
+ require 'assert'
2
+
3
+ class Sanford::Runner
4
+
5
+ class BaseTest < Assert::Context
6
+ desc "Sanford::Runner"
7
+ setup do
8
+ request = Sanford::Protocol::Request.new('v1', 'test', {})
9
+ @runner = Sanford::Runner.new(BasicServiceHandler, request)
10
+ end
11
+ subject{ @runner }
12
+
13
+ should have_instance_methods :handler_class, :request, :logger, :run
14
+
15
+ should "run the handler and return the response it generates when `run` is called" do
16
+ response = subject.run
17
+
18
+ assert_instance_of Sanford::Protocol::Response, response
19
+ assert_equal 200, response.code
20
+ assert_equal 'Joe Test', response.data['name']
21
+ assert_equal 'joe.test@example.com', response.data['email']
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -1,18 +1,26 @@
1
1
  require 'assert'
2
2
 
3
+ require 'sanford/server'
4
+ require 'sanford/manager'
5
+
3
6
  class Sanford::Server
4
7
 
5
8
  class BaseTest < Assert::Context
6
9
  desc "Sanford::Server"
7
10
  setup do
8
- @service_host = DummyHost.new
9
- @server = Sanford::Server.new(@service_host)
11
+ @server = Sanford::Server.new(TestHost)
10
12
  end
11
13
  subject{ @server }
12
14
 
13
15
  should "include DatTCP::Server" do
14
16
  assert_includes DatTCP::Server, subject.class.included_modules
15
17
  end
18
+
19
+ should "use the service host's ip and port" do
20
+ assert_equal TestHost.ip, subject.host
21
+ assert_equal TestHost.port, subject.port
22
+ end
23
+
16
24
  end
17
25
 
18
26
  # Sanford::Server#serve is tested in test/system/request_handling_test.rb,