sk-hoth 0.0.1 → 0.3.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/README.rdoc +69 -39
- data/THANKS.md +9 -0
- data/TODO +2 -0
- data/lib/hoth/encoding/json.rb +28 -0
- data/lib/hoth/encoding/no_op.rb +19 -0
- data/lib/hoth/endpoint.rb +28 -0
- data/lib/hoth/exceptions.rb +14 -0
- data/lib/hoth/extension/core/exception.rb +15 -0
- data/lib/hoth/modules.rb +27 -0
- data/lib/hoth/providers/bertrpc_provider.rb +35 -0
- data/lib/hoth/providers/rack_provider.rb +45 -0
- data/lib/hoth/service.rb +50 -0
- data/lib/hoth/service_definition.rb +18 -0
- data/lib/hoth/service_module.rb +49 -0
- data/lib/hoth/service_registry.rb +34 -0
- data/lib/hoth/services.rb +51 -0
- data/lib/hoth/transport/base.rb +19 -0
- data/lib/hoth/transport/bert.rb +87 -0
- data/lib/hoth/transport/http.rb +41 -0
- data/lib/hoth/transport/http_hmac.rb +37 -0
- data/lib/hoth/transport/workling.rb +23 -0
- data/lib/hoth/transport.rb +48 -0
- data/lib/hoth/util/logger.rb +46 -0
- data/lib/hoth.rb +56 -0
- data/spec/spec_helper.rb +7 -26
- data/spec/unit/encoding/json_spec.rb +25 -0
- data/spec/unit/endpoint_spec.rb +34 -0
- data/spec/unit/extension/core/exception_spec.rb +34 -0
- data/spec/unit/hoth_spec.rb +30 -0
- data/spec/unit/providers/rack_provider_spec.rb +49 -0
- data/spec/unit/service_definition_spec.rb +21 -0
- data/spec/unit/service_module_spec.rb +59 -0
- data/spec/unit/service_spec.rb +77 -0
- data/spec/unit/transport/base_spec.rb +43 -0
- data/spec/unit/transport/http_hmac_spec.rb +44 -0
- data/spec/unit/transport/http_spec.rb +73 -0
- data/spec/unit/transport/workling_spec.rb +42 -0
- data/spec/unit/transport_spec.rb +29 -0
- metadata +86 -23
- data/lib/king_soa/rack/middleware.rb +0 -47
- data/lib/king_soa/registry.rb +0 -55
- data/lib/king_soa/service.rb +0 -88
- data/lib/king_soa.rb +0 -56
- data/spec/king_soa/rack/middleware_spec.rb +0 -36
- data/spec/king_soa/registry_spec.rb +0 -28
- data/spec/king_soa/service_spec.rb +0 -46
- data/spec/server/app.rb +0 -26
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Hoth
|
4
|
+
module Transport
|
5
|
+
class Http < Base
|
6
|
+
def call_remote_with(*params)
|
7
|
+
begin
|
8
|
+
handle_response post_payload(params)
|
9
|
+
rescue Exception => e
|
10
|
+
raise TransportError.wrap(e)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_response(response)
|
15
|
+
case response
|
16
|
+
when Net::HTTPSuccess
|
17
|
+
Hoth::Logger.debug "response.body: #{response.body}"
|
18
|
+
encoder.decode(response.body)["result"]
|
19
|
+
when Net::HTTPServerError
|
20
|
+
begin
|
21
|
+
Hoth::Logger.debug "response.body: #{response.body}"
|
22
|
+
raise encoder.decode(response.body)["error"]
|
23
|
+
rescue JSON::ParserError => jpe
|
24
|
+
raise TransportError.wrap(jpe)
|
25
|
+
end
|
26
|
+
when Net::HTTPRedirection, Net::HTTPClientError, Net::HTTPInformation, Net::HTTPUnknownResponse
|
27
|
+
raise NotImplementedError, "code: #{response.code}, message: #{response.body}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def post_payload(payload)
|
32
|
+
uri = URI.parse(self.endpoint.to_url)
|
33
|
+
return Net::HTTP.post_form(uri,
|
34
|
+
'name' => self.name.to_s,
|
35
|
+
'params' => encoder.encode(payload)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'king_hmac'
|
2
|
+
require 'net/http'
|
3
|
+
module Hoth
|
4
|
+
module Transport
|
5
|
+
class HttpHmac < Http
|
6
|
+
attr_accessor :hmac_access_id, :hmac_secret
|
7
|
+
# just for testing request
|
8
|
+
attr_accessor :req
|
9
|
+
# Manually construct the HTTP request because it needs to be signed with
|
10
|
+
# hmac before.
|
11
|
+
# This function is more or less a copy of HTTP.post_form
|
12
|
+
# == Prerequisites
|
13
|
+
# you must set both instance variables: hmac_access_id, hmac_secret before
|
14
|
+
# the call can be made
|
15
|
+
# === Returns
|
16
|
+
# <Object>:. Net::HTTPResponse
|
17
|
+
def post_payload(payload)
|
18
|
+
raise TransportError, 'no hmac credentials set for hmac transport' unless hmac_access_id && hmac_secret
|
19
|
+
uri = URI.parse(self.endpoint.to_url)
|
20
|
+
# construct request object
|
21
|
+
self.req = Net::HTTP::Post.new(uri.path)
|
22
|
+
# add its form data
|
23
|
+
self.req.form_data = {'name' => self.name.to_s,
|
24
|
+
'params' => encoder.encode(payload) }
|
25
|
+
# ensure a date header is set, needed for hmac
|
26
|
+
self.req['Date'] = Time.now.httpdate if self.req['Date'].nil?
|
27
|
+
# sign request object => set Authorisation header
|
28
|
+
KingHmac::Auth.sign!(self.req, hmac_access_id, hmac_secret)
|
29
|
+
# go for it
|
30
|
+
return Net::HTTP.new(uri.host, uri.port).start {|http|
|
31
|
+
http.request(self.req)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
begin
|
2
|
+
require 'simple_publisher'
|
3
|
+
rescue LoadError
|
4
|
+
STDERR.puts "You need the simple_publisher gem if you want to use Workling/Starling transport."
|
5
|
+
end
|
6
|
+
|
7
|
+
module Hoth
|
8
|
+
module Transport
|
9
|
+
|
10
|
+
class Workling < Base
|
11
|
+
|
12
|
+
def call_remote_with(*args)
|
13
|
+
topic = SimplePublisher::Topic.new(:name => "#{self.module.name.to_s.underscore}_subscribers__#{name.to_s.underscore}")
|
14
|
+
connection = SimplePublisher::StarlingConnection.new(:host => endpoint.host, :port => endpoint.port)
|
15
|
+
|
16
|
+
publisher = SimplePublisher::Publisher.new(:topic => topic, :connection => connection)
|
17
|
+
publisher.publish(encoder.encode(args))
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'hoth/transport/base'
|
2
|
+
require 'hoth/transport/http'
|
3
|
+
require 'hoth/transport/http_hmac'
|
4
|
+
require 'hoth/transport/bert'
|
5
|
+
require 'hoth/transport/workling'
|
6
|
+
|
7
|
+
require 'hoth/encoding/json'
|
8
|
+
require 'hoth/encoding/no_op'
|
9
|
+
|
10
|
+
module Hoth
|
11
|
+
module Transport
|
12
|
+
|
13
|
+
POSSIBLE_TRANSPORTS = {
|
14
|
+
:json_via_http => {
|
15
|
+
:transport_class => Transport::Http,
|
16
|
+
:encoder => Encoding::Json
|
17
|
+
},
|
18
|
+
:http => :json_via_http,
|
19
|
+
:json_via_http_hmac => {
|
20
|
+
:transport_class => Transport::HttpHmac,
|
21
|
+
:encoder => Encoding::Json
|
22
|
+
},
|
23
|
+
:http_hmac => :json_via_http_hmac,
|
24
|
+
:workling => {
|
25
|
+
:transport_class => Transport::Workling
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
class <<self
|
30
|
+
def create(transport_name, service)
|
31
|
+
new_transport_with_encoding(transport_name, service)
|
32
|
+
end
|
33
|
+
|
34
|
+
def new_transport_with_encoding(transport_name, service)
|
35
|
+
if POSSIBLE_TRANSPORTS[transport_name.to_sym]
|
36
|
+
if POSSIBLE_TRANSPORTS[transport_name.to_sym].kind_of?(Hash)
|
37
|
+
POSSIBLE_TRANSPORTS[transport_name.to_sym][:transport_class].new(service, :encoder => POSSIBLE_TRANSPORTS[transport_name.to_sym][:encoder])
|
38
|
+
else
|
39
|
+
new_transport_with_encoding(POSSIBLE_TRANSPORTS[transport_name.to_sym], service)
|
40
|
+
end
|
41
|
+
else
|
42
|
+
raise TransportException.new("specified transport '#{transport_name}' does not exist, use one of these: #{POSSIBLE_TRANSPORTS.keys.join(", ")}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Hoth
|
2
|
+
class Logger
|
3
|
+
class <<self
|
4
|
+
|
5
|
+
def log_provider=(log_provider)
|
6
|
+
@log_provider = log_provider
|
7
|
+
end
|
8
|
+
|
9
|
+
def init_logging!
|
10
|
+
Hoth::Logger.log_provider = if Object.const_defined?("Rails")
|
11
|
+
Rails.logger
|
12
|
+
else
|
13
|
+
require 'logger'
|
14
|
+
::Logger.new("/tmp/hoth.log")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug(msg)
|
19
|
+
log_provider.debug msg
|
20
|
+
end
|
21
|
+
|
22
|
+
def info(msg)
|
23
|
+
log_provider.info msg
|
24
|
+
end
|
25
|
+
|
26
|
+
def warn(msg)
|
27
|
+
log_provider.warn msg
|
28
|
+
end
|
29
|
+
|
30
|
+
def error(msg)
|
31
|
+
log_provider.error msg
|
32
|
+
end
|
33
|
+
|
34
|
+
def fatal(msg)
|
35
|
+
log_provider.fatal msg
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def log_provider
|
41
|
+
@log_provider || init_logging!
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
data/lib/hoth.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require 'active_support/inflector'
|
4
|
+
|
5
|
+
# must be loaded after alls transports and all encodings
|
6
|
+
require 'hoth/transport'
|
7
|
+
|
8
|
+
require 'hoth/service_definition'
|
9
|
+
require 'hoth/service_module'
|
10
|
+
require 'hoth/endpoint'
|
11
|
+
require 'hoth/service'
|
12
|
+
require 'hoth/modules'
|
13
|
+
require 'hoth/service_registry'
|
14
|
+
require 'hoth/services'
|
15
|
+
|
16
|
+
require 'hoth/util/logger'
|
17
|
+
|
18
|
+
require 'hoth/extension/core/exception'
|
19
|
+
require 'hoth/exceptions'
|
20
|
+
|
21
|
+
module Hoth
|
22
|
+
|
23
|
+
class <<self
|
24
|
+
def init!
|
25
|
+
load_service_definition
|
26
|
+
load_module_definition
|
27
|
+
Logger.init_logging!
|
28
|
+
end
|
29
|
+
|
30
|
+
def config_path
|
31
|
+
@config_path || "config/"
|
32
|
+
end
|
33
|
+
|
34
|
+
def config_path=(config_path)
|
35
|
+
@config_path = config_path
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_service_definition
|
39
|
+
require File.join(config_path, "service_definition")
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_module_definition
|
43
|
+
require File.join(config_path, "module_definition")
|
44
|
+
end
|
45
|
+
|
46
|
+
def env
|
47
|
+
@env || ENV["HOTH_ENV"] || (Object.const_defined?("Rails") ? Rails.env.to_sym : :development)
|
48
|
+
end
|
49
|
+
|
50
|
+
def env=(env)
|
51
|
+
@env = env.to_sym
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,36 +2,17 @@ require 'rubygems'
|
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
4
4
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
-
require '
|
5
|
+
require 'hoth'
|
6
6
|
require 'spec'
|
7
7
|
require 'spec/autorun'
|
8
8
|
# for mocking web requests
|
9
9
|
require 'webmock/rspec'
|
10
|
-
require 'rack/test'
|
11
10
|
include WebMock
|
12
11
|
|
12
|
+
Hoth.env = "test"
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# end
|
20
|
-
|
21
|
-
# Rack::Builder.new do
|
22
|
-
# use KingSoa::Rack::Middleware
|
23
|
-
# app = proc do |env|
|
24
|
-
# [ 200, {'Content-Type' => 'text/plain'}, "b" ]
|
25
|
-
# end
|
26
|
-
# run app
|
27
|
-
# end.to_app
|
28
|
-
# def app
|
29
|
-
# Rack::Builder.new {
|
30
|
-
# # URLs starting with /account (logged in users) go to Rails
|
31
|
-
# map "/soa" do
|
32
|
-
# run KingSoa::Rack::Middleware.new
|
33
|
-
# end
|
34
|
-
# }.to_app
|
35
|
-
# end
|
36
|
-
# app.run
|
37
|
-
end
|
14
|
+
Spec::Matchers.define :string_matching do |regex|
|
15
|
+
match do |string|
|
16
|
+
string =~ regex
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../', 'spec_helper'))
|
2
|
+
|
3
|
+
module Hoth
|
4
|
+
module Encoding
|
5
|
+
|
6
|
+
describe Json do
|
7
|
+
|
8
|
+
it "should decode a JSON string" do
|
9
|
+
decoded_json = Json.decode '{"test":23}'
|
10
|
+
decoded_json.should ==({"test" => 23})
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should encode a JSON string" do
|
14
|
+
encoded_json = Json.encode({"test" => 23})
|
15
|
+
'{"test":23}'.should == encoded_json
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should know its ContentType" do
|
19
|
+
Json.content_type.should == "application/json"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
module Hoth
|
4
|
+
|
5
|
+
describe Endpoint do
|
6
|
+
|
7
|
+
it "should have a port" do
|
8
|
+
endpoint = Endpoint.new { port 3000 }
|
9
|
+
endpoint.port.should == 3000
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have a host name" do
|
13
|
+
endpoint = Endpoint.new { host "example.com" }
|
14
|
+
endpoint.host.should == "example.com"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have a transport name" do
|
18
|
+
endpoint = Endpoint.new { transport :json_via_http }
|
19
|
+
endpoint.transport.should == :json_via_http
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should should cast itself to URL string" do
|
23
|
+
endpoint = Endpoint.new { port 3000; host "example.com" }
|
24
|
+
endpoint.to_url.should == "http://example.com:3000/execute"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should should know the deployment module this endpoint is associated to" do
|
28
|
+
endpoint = Endpoint.new { module_name "TestModule" }
|
29
|
+
endpoint.module_name.should == "TestModule"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../../', 'spec_helper'))
|
2
|
+
|
3
|
+
describe Exception do
|
4
|
+
|
5
|
+
it "should be able to create json with empty backtrace" do
|
6
|
+
e = Exception.new "message"
|
7
|
+
e.to_json.should == "{\"json_class\":\"Exception\",\"message\":\"message\",\"backtrace\":null}"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should be able to create json with backtrace" do
|
11
|
+
e = Exception.new "message"
|
12
|
+
e.set_backtrace ["back", "trace"]
|
13
|
+
e.to_json.should == "{\"json_class\":\"Exception\",\"message\":\"message\",\"backtrace\":[\"back\",\"trace\"]}"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be able to deserialize exception from json" do
|
17
|
+
e = Exception.new "message"
|
18
|
+
e.set_backtrace ["back", "trace"]
|
19
|
+
deserialized = JSON(e.to_json)
|
20
|
+
deserialized.message.should == "message"
|
21
|
+
deserialized.backtrace.should == ["back", "trace"]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be able to serialize and deserialize descendants of the Exception class" do
|
25
|
+
class ExceptionSpec < Exception; end
|
26
|
+
e = ExceptionSpec.new "message"
|
27
|
+
e.set_backtrace ["back", "trace"]
|
28
|
+
deserialized = JSON(e.to_json)
|
29
|
+
deserialized.message.should == "message"
|
30
|
+
deserialized.backtrace.should == ["back", "trace"]
|
31
|
+
deserialized.should be_a ExceptionSpec
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hoth do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@old_hoth_env = Hoth.env
|
7
|
+
Hoth.instance_variable_set "@env", nil
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
Hoth.env = @old_hoth_env
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set the environment explicitly" do
|
15
|
+
Hoth.env = :test
|
16
|
+
Hoth.env.should == :test
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should default to :development if no environment is set" do
|
20
|
+
Hoth.env.should equal(:development)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return the Rails env if Rails is available" do
|
24
|
+
module Rails; end
|
25
|
+
Rails.should_receive(:env).and_return(:production)
|
26
|
+
Hoth.env.should equal(:production)
|
27
|
+
Object.send :remove_const, :Rails
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../', 'spec_helper'))
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../../', 'lib', 'hoth', 'providers', 'rack_provider'))
|
4
|
+
|
5
|
+
require 'rack/mock'
|
6
|
+
|
7
|
+
module Hoth
|
8
|
+
module Providers
|
9
|
+
|
10
|
+
describe RackProvider do
|
11
|
+
|
12
|
+
it "should get transport and encoder based on called service" do
|
13
|
+
app = stub("ApplicationStub").as_null_object
|
14
|
+
middleware = Hoth::Providers::RackProvider.new(app)
|
15
|
+
|
16
|
+
encoder = mock("EncoderMock")
|
17
|
+
encoder.should_receive(:decode).with("some_parameter").and_return(decoded_params = "some_parameter_decoded")
|
18
|
+
encoder.should_receive(:content_type).and_return("application/json")
|
19
|
+
|
20
|
+
transport = mock("TransportMock")
|
21
|
+
transport.should_receive(:encoder).exactly(3).times.and_return(encoder)
|
22
|
+
|
23
|
+
service = mock("ServiceMock")
|
24
|
+
service.should_receive(:transport).exactly(3).times.and_return(transport)
|
25
|
+
ServiceRegistry.should_receive(:locate_service).with("service_name").and_return(service)
|
26
|
+
|
27
|
+
Hoth::Services.should_receive(:send).with("service_name", *decoded_params).and_return(service_result = "result")
|
28
|
+
encoder.should_receive(:encode).with({"result" => service_result}).and_return("result_encoded")
|
29
|
+
|
30
|
+
mock_request = Rack::MockRequest.new(middleware)
|
31
|
+
mock_request.post("http://localhost/execute?name=service_name¶ms=some_parameter")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be able to handle exceptions" do
|
35
|
+
app = stub("ApplicationStub").as_null_object
|
36
|
+
middleware = Hoth::Providers::RackProvider.new app
|
37
|
+
env = {"PATH_INFO" => "/execute/some_method", "other_params" => nil}
|
38
|
+
Rack::Request.should_receive(:new).and_raise(RuntimeError)
|
39
|
+
|
40
|
+
rack_response = middleware.call env
|
41
|
+
rack_response.first.should == 500 #status code
|
42
|
+
rack_response.last.should be_a_kind_of(Array)
|
43
|
+
rack_response.last.first.should == "An error occuered! (RuntimeError)"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
module Hoth
|
4
|
+
describe ServiceDefinition do
|
5
|
+
|
6
|
+
it "should create a Service and add it to the registry instance" do
|
7
|
+
service_name = :my_service
|
8
|
+
|
9
|
+
definition = ServiceDefinition.new
|
10
|
+
definition.service service_name do |some_params|
|
11
|
+
returns :nothing
|
12
|
+
end
|
13
|
+
|
14
|
+
service = ServiceRegistry.locate_service(service_name)
|
15
|
+
service.should_not be(nil)
|
16
|
+
service.params_arity.should be(1)
|
17
|
+
service.return_nothing?.should be(true)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
module Hoth
|
4
|
+
|
5
|
+
describe ServiceModule do
|
6
|
+
|
7
|
+
it "should have a name" do
|
8
|
+
service_module = ServiceModule.new :name => :my_service_module
|
9
|
+
service_module.name.should equal(:my_service_module)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have an environment" do
|
13
|
+
service_module = ServiceModule.new(:name => "service_module_name")
|
14
|
+
block = Proc.new {}
|
15
|
+
service_module.env :test, &block
|
16
|
+
service_module[:test].should be_a(ServiceModule::Environment)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have multiple environments" do
|
20
|
+
service_module = ServiceModule.new(:name => "service_module_name")
|
21
|
+
block = Proc.new {}
|
22
|
+
service_module.env :test, :development, &block
|
23
|
+
service_module[:test].should be_a(ServiceModule::Environment)
|
24
|
+
service_module[:development].should be_a(ServiceModule::Environment)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to add services" do
|
28
|
+
service_module = ServiceModule.new(:name => "service_module_name")
|
29
|
+
block = Proc.new {}
|
30
|
+
|
31
|
+
service_module.env :test, &block
|
32
|
+
|
33
|
+
ServiceRegistry.should_receive(:locate_service).with(:service_name).and_return(service = mock("ServiceMock"))
|
34
|
+
service.should_receive(:module=).with(service_module)
|
35
|
+
service.should_receive(:via_endpoint).with(:special_endpoint)
|
36
|
+
|
37
|
+
service_module.add_service("service_name", :via => :special_endpoint)
|
38
|
+
end
|
39
|
+
|
40
|
+
describe ServiceModule::Environment do
|
41
|
+
|
42
|
+
it "should have an endpoint" do
|
43
|
+
endpoint_mock = mock("Endpoint", :null_object => true)
|
44
|
+
|
45
|
+
endpoint_block = Proc.new do
|
46
|
+
endpoint :development do
|
47
|
+
host 'localhost'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
env = ServiceModule::Environment.new(&endpoint_block)
|
52
|
+
env[:development].should_not be(nil)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
class TestServiceImpl
|
4
|
+
def self.execute(param1, param2)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Hoth
|
9
|
+
|
10
|
+
describe Service do
|
11
|
+
|
12
|
+
it "should define parameters and return values" do
|
13
|
+
service_block = Proc.new { |param_1, param_2, param_3| returns :some_data }
|
14
|
+
|
15
|
+
service = Service.new("TestService", &service_block)
|
16
|
+
|
17
|
+
service.params_arity.should be(3)
|
18
|
+
service.return_nothing?.should be(false)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should know its service-impl class" do
|
22
|
+
service = Service.new("TestService") {}
|
23
|
+
service.impl_class
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should know that its service-impl class is not available" do
|
27
|
+
service = Service.new("TestServiceWithoutImplClass") {}
|
28
|
+
service.impl_class.should be(false)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should know if it is local or not based on Impl-Class availability" do
|
32
|
+
service = Service.new("TestServiceWithoutImplClass") {}
|
33
|
+
service.is_local?.should be(false)
|
34
|
+
|
35
|
+
service = Service.new("test_service") {}
|
36
|
+
service.is_local?.should be(true)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should execute the service stub locally if its impl-class was found" do
|
40
|
+
service = Service.new("test_service") { |p1, p2| returns :nothing }
|
41
|
+
|
42
|
+
service.should_receive(:is_local?).and_return(true)
|
43
|
+
service.impl_class.should_receive(:execute).with(:arg1, :arg2)
|
44
|
+
|
45
|
+
service.execute(:arg1, :arg2).should be(nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should execute the service stub locally if its impl-class was found and return a value" do
|
49
|
+
service = Service.new("test_service") { |p1, p2| returns :value }
|
50
|
+
|
51
|
+
service.should_receive(:is_local?).and_return(true)
|
52
|
+
service.impl_class.should_receive(:execute).with(:arg1, :arg2).and_return(result = mock("ResultMock"))
|
53
|
+
|
54
|
+
service.execute(:arg1, :arg2).should be(result)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should call the remote service if impl-class does not exist" do
|
58
|
+
service = Service.new("test_service_without_impl") { |p1, p2| returns :nothing }
|
59
|
+
|
60
|
+
service.should_receive(:is_local?).and_return(false)
|
61
|
+
service.should_receive(:transport).and_return(transport = mock("TransportMock"))
|
62
|
+
transport.should_receive(:call_remote_with).with(:arg1, :arg2)
|
63
|
+
|
64
|
+
service.execute(:arg1, :arg2)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should create transport instance based on endpoint" do
|
68
|
+
service = Service.new("test_service") { |p1, p2| returns :nothing }
|
69
|
+
service.should_receive(:endpoint).and_return(endpoint = mock("EndpointMock"))
|
70
|
+
endpoint.should_receive(:transport).and_return(:http)
|
71
|
+
Hoth::Transport.should_receive(:create).with(:http, service)
|
72
|
+
service.transport
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../', 'spec_helper'))
|
2
|
+
|
3
|
+
module Hoth
|
4
|
+
module Transport
|
5
|
+
|
6
|
+
describe "Base" do
|
7
|
+
|
8
|
+
it "should initialize with service-delegate" do
|
9
|
+
service = mock("ServiceMock")
|
10
|
+
transport = Base.new(service)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should use an NoOp encoder if no encoder class was given at all" do
|
14
|
+
service = mock("ServiceMock")
|
15
|
+
transport = Base.new(service)
|
16
|
+
transport.encoder.should == Encoding::NoOp
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should delegate calls to service-delegate" do
|
20
|
+
service = mock("ServiceMock")
|
21
|
+
service.should_receive(:name)
|
22
|
+
service.should_receive(:module)
|
23
|
+
service.should_receive(:endpoint)
|
24
|
+
service.should_receive(:params)
|
25
|
+
service.should_receive(:return_nothing?)
|
26
|
+
transport = Base.new(service)
|
27
|
+
|
28
|
+
[:name, :module, :endpoint, :params, :return_nothing?].each do |method|
|
29
|
+
transport.send(method)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have an encoder" do
|
34
|
+
service = mock("ServiceMock")
|
35
|
+
encoder = mock("EncoderMock")
|
36
|
+
transport = Base.new(service, :encoder => encoder)
|
37
|
+
transport.encoder.should be(encoder)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|