sanford 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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,