skein 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +69 -0
- data/README.md +57 -0
- data/RELEASES.md +4 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/bin/skein +186 -0
- data/config/.gitignore +3 -0
- data/config/skein.yml.example +11 -0
- data/lib/skein.rb +24 -0
- data/lib/skein/client.rb +51 -0
- data/lib/skein/client/publisher.rb +14 -0
- data/lib/skein/client/rpc.rb +96 -0
- data/lib/skein/client/subscriber.rb +25 -0
- data/lib/skein/client/worker.rb +51 -0
- data/lib/skein/config.rb +87 -0
- data/lib/skein/connected.rb +52 -0
- data/lib/skein/context.rb +38 -0
- data/lib/skein/handler.rb +86 -0
- data/lib/skein/handler/async.rb +9 -0
- data/lib/skein/handler/threaded.rb +7 -0
- data/lib/skein/rabbitmq.rb +44 -0
- data/lib/skein/reporter.rb +11 -0
- data/lib/skein/rpc.rb +24 -0
- data/lib/skein/rpc/base.rb +23 -0
- data/lib/skein/rpc/error.rb +34 -0
- data/lib/skein/rpc/notification.rb +2 -0
- data/lib/skein/rpc/request.rb +62 -0
- data/lib/skein/rpc/response.rb +38 -0
- data/lib/skein/support.rb +67 -0
- data/skein.gemspec +95 -0
- data/test/data/sample_config.yml +13 -0
- data/test/helper.rb +42 -0
- data/test/script/em_example +28 -0
- data/test/unit/test_skein_client.rb +18 -0
- data/test/unit/test_skein_client_publisher.rb +10 -0
- data/test/unit/test_skein_client_subscriber.rb +41 -0
- data/test/unit/test_skein_client_worker.rb +61 -0
- data/test/unit/test_skein_config.rb +33 -0
- data/test/unit/test_skein_context.rb +44 -0
- data/test/unit/test_skein_rabbitmq.rb +14 -0
- data/test/unit/test_skein_reporter.rb +4 -0
- data/test/unit/test_skein_rpc_error.rb +10 -0
- data/test/unit/test_skein_rpc_request.rb +93 -0
- data/test/unit/test_skein_support.rb +95 -0
- metadata +148 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
$LOAD_PATH << File.expand_path('../lib', File.dirname(__FILE__))
|
4
|
+
|
5
|
+
require 'skein'
|
6
|
+
|
7
|
+
# Simulate Rails 'test' environment
|
8
|
+
ENV['RAILS_ENV'] = 'test'
|
9
|
+
|
10
|
+
# Ensure tests are run from the root of the project so that configuration
|
11
|
+
# files can be found and loaded.
|
12
|
+
Dir.chdir(File.expand_path('../', File.dirname(__FILE__)))
|
13
|
+
|
14
|
+
class Test::Unit::TestCase
|
15
|
+
def assert_mapping(map)
|
16
|
+
result_map = map.each_with_object({ }) do |(k,v), h|
|
17
|
+
h[k] = yield(k)
|
18
|
+
end
|
19
|
+
|
20
|
+
assert_equal map, result_map do
|
21
|
+
result_map.each_with_object([ ]) do |(k,v), a|
|
22
|
+
unless (v == map[k])
|
23
|
+
a << k
|
24
|
+
end
|
25
|
+
end.map do |s|
|
26
|
+
"Input: #{s.inspect}\n Expected: #{map[s].inspect}\n Result: #{result_map[s].inspect}\n"
|
27
|
+
end.join
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def assert_no_threads(message = nil)
|
32
|
+
threads = Thread.list.length
|
33
|
+
|
34
|
+
yield
|
35
|
+
|
36
|
+
assert_equal threads, Thread.list.length, message
|
37
|
+
end
|
38
|
+
|
39
|
+
def data_path(name)
|
40
|
+
File.expand_path(File.join('data', name), File.dirname(__FILE__))
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
gem 'eventmachine'
|
6
|
+
require 'eventmachine'
|
7
|
+
|
8
|
+
$LOAD_PATH << File.expand_path('../../lib', File.dirname(__FILE__))
|
9
|
+
|
10
|
+
require 'skein'
|
11
|
+
|
12
|
+
# == Support Classes ========================================================
|
13
|
+
|
14
|
+
class EchoWorker < Skein::Client::Worker
|
15
|
+
def echo(*args)
|
16
|
+
yield(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def async?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# == Main ===================================================================
|
25
|
+
|
26
|
+
EventMachine.run do
|
27
|
+
EchoWorker.new('test_echo')
|
28
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
class TestSkeinClient < Test::Unit::TestCase
|
4
|
+
def test_default
|
5
|
+
client = nil
|
6
|
+
|
7
|
+
assert_no_threads do
|
8
|
+
client = Skein::Client.new
|
9
|
+
|
10
|
+
assert client.context
|
11
|
+
|
12
|
+
client.close
|
13
|
+
end
|
14
|
+
|
15
|
+
# ensure
|
16
|
+
# client and client.close
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
class TestSkeinClientSubscriber < Test::Unit::TestCase
|
4
|
+
def test_cycle
|
5
|
+
client = Skein::Client.new
|
6
|
+
|
7
|
+
publisher = client.publisher('test')
|
8
|
+
|
9
|
+
received = nil
|
10
|
+
|
11
|
+
subscriber = client.subscriber('test', '*.*')
|
12
|
+
subscribing = false
|
13
|
+
|
14
|
+
thread = Thread.new do
|
15
|
+
Thread.abort_on_exception = true
|
16
|
+
|
17
|
+
subscribing = true
|
18
|
+
|
19
|
+
subscriber.listen do |payload|
|
20
|
+
received = payload
|
21
|
+
|
22
|
+
Thread.exit
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
while (!subscribing)
|
27
|
+
# Spin-lock to wait for the subscriber to come online
|
28
|
+
end
|
29
|
+
|
30
|
+
publisher.publish!({ data: true }, 'test.notification')
|
31
|
+
|
32
|
+
thread.join
|
33
|
+
|
34
|
+
assert_equal({ "data" => true }, received)
|
35
|
+
|
36
|
+
ensure
|
37
|
+
publisher and publisher.close
|
38
|
+
subscriber and subscriber.close
|
39
|
+
client and client.close
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
class TestSkeinClientWorker < Test::Unit::TestCase
|
4
|
+
class ErrorGenerator < Skein::Client::Worker
|
5
|
+
class CustomError < RuntimeError
|
6
|
+
end
|
7
|
+
|
8
|
+
def raises_error
|
9
|
+
raise CustomError, 'Example error!'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_example
|
14
|
+
worker = Skein::Client::Worker.new('test_rpc')
|
15
|
+
handler = Skein::Handler.for(worker)
|
16
|
+
|
17
|
+
message = {
|
18
|
+
method: 'ident',
|
19
|
+
params: [ ],
|
20
|
+
id: '43d8352c-4907-4c32-9c81-fc34e91a3884'
|
21
|
+
}
|
22
|
+
|
23
|
+
handler.handle(JSON.dump(message)) do |response_json, error|
|
24
|
+
response = JSON.load(response_json)
|
25
|
+
|
26
|
+
expected = {
|
27
|
+
'result' => worker.ident,
|
28
|
+
'error' => nil,
|
29
|
+
'id' => message[:id]
|
30
|
+
}
|
31
|
+
|
32
|
+
assert_equal(expected, response)
|
33
|
+
end
|
34
|
+
|
35
|
+
ensure
|
36
|
+
worker and worker.close
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_throws_exception
|
40
|
+
worker = ErrorGenerator.new('test_error')
|
41
|
+
handler = Skein::Handler.for(worker)
|
42
|
+
|
43
|
+
message = {
|
44
|
+
method: 'raises_error',
|
45
|
+
id: '29fe8a40-fccf-43c6-ba48-818598c66e6f'
|
46
|
+
}
|
47
|
+
|
48
|
+
handler.handle(JSON.dump(message)) do |response_json, error|
|
49
|
+
expected = {
|
50
|
+
'result' => nil,
|
51
|
+
'error' => '[TestSkeinClientWorker::ErrorGenerator::CustomError] Example error!',
|
52
|
+
'id' => message[:id]
|
53
|
+
}
|
54
|
+
|
55
|
+
assert_equal(expected.to_json, response_json)
|
56
|
+
end
|
57
|
+
|
58
|
+
ensure
|
59
|
+
worker and worker.close
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
class TestSkeinConfig < Test::Unit::TestCase
|
4
|
+
def test_env
|
5
|
+
assert_equal('test', Skein::Config.env)
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_default_state
|
9
|
+
config = Skein::Config.new(false)
|
10
|
+
|
11
|
+
assert config
|
12
|
+
|
13
|
+
assert_equal('127.0.0.1', config.host)
|
14
|
+
assert_equal(5672, config.port)
|
15
|
+
assert_equal('guest', config.username)
|
16
|
+
assert_equal('guest', config.password)
|
17
|
+
assert_equal(nil, config.namespace)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_with_config_path
|
21
|
+
config = Skein::Config.new(data_path('sample_config.yml'))
|
22
|
+
|
23
|
+
assert_equal('test.host', config.host)
|
24
|
+
assert_equal(5670, config.port)
|
25
|
+
assert_equal('test_user', config.username)
|
26
|
+
assert_equal('test_password', config.password)
|
27
|
+
assert_equal('test', config.namespace)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_config_exists
|
31
|
+
assert_equal(true, Skein::Config.exist?)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
class TestSkeinContext < Test::Unit::TestCase
|
4
|
+
def test_default
|
5
|
+
context = Skein::Context.default
|
6
|
+
|
7
|
+
assert(context)
|
8
|
+
|
9
|
+
assert_equal(Skein::Support.hostname, context.hostname)
|
10
|
+
assert_equal(Skein::Support.process_name, context.process_name)
|
11
|
+
assert_equal(Skein::Support.process_id, context.process_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_defaults
|
15
|
+
context = Skein::Context.new
|
16
|
+
|
17
|
+
assert_equal(Skein::Support.hostname, context.hostname)
|
18
|
+
assert_equal(Skein::Support.process_name, context.process_name)
|
19
|
+
assert_equal(Skein::Support.process_id, context.process_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_override
|
23
|
+
context = Skein::Context.new(
|
24
|
+
hostname: 'sample.host',
|
25
|
+
process_name: 'test_process',
|
26
|
+
process_id: 20301
|
27
|
+
)
|
28
|
+
|
29
|
+
assert_equal('sample.host', context.hostname)
|
30
|
+
assert_equal('test_process', context.process_name)
|
31
|
+
assert_equal(20301, context.process_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_generate_ident
|
35
|
+
context = Skein::Context.new
|
36
|
+
|
37
|
+
ident = context.ident(self)
|
38
|
+
|
39
|
+
assert(ident)
|
40
|
+
|
41
|
+
assert_not_equal(ident, context.ident(context))
|
42
|
+
assert_equal(ident, context.ident(self))
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
class TestSkeinRPCRequest < Test::Unit::TestCase
|
4
|
+
def test_default
|
5
|
+
request = Skein::RPC::Request.new
|
6
|
+
|
7
|
+
assert request.id
|
8
|
+
assert request.id.match(/\A\h{8}\-\h{4}\-\h{4}\-\h{4}\-\h{12}\z/)
|
9
|
+
|
10
|
+
assert_equal nil, request.method
|
11
|
+
assert_equal nil, request.params
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_with_invalid_method_name
|
15
|
+
request = Skein::RPC::Request.new(
|
16
|
+
method: 'invalid name',
|
17
|
+
id: 'aa8304bd-5c4a-4b77-a1bf-87f90d59b3af'
|
18
|
+
)
|
19
|
+
|
20
|
+
rescue Skein::RPC::InvalidMethod => e
|
21
|
+
assert e
|
22
|
+
|
23
|
+
assert e.request.is_a?(Skein::RPC::Request)
|
24
|
+
assert_equal 'aa8304bd-5c4a-4b77-a1bf-87f90d59b3af', e.to_error.id
|
25
|
+
else
|
26
|
+
fail
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_with_no_method_name
|
30
|
+
request = Skein::RPC::Request.new(
|
31
|
+
method: nil,
|
32
|
+
id: 'aa8304bd-5c4a-4b77-a1bf-87f90d59b3af'
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_with_single_param
|
37
|
+
request = Skein::RPC::Request.new(
|
38
|
+
method: 'single_param',
|
39
|
+
params: 'single'
|
40
|
+
)
|
41
|
+
|
42
|
+
assert_equal %w[ single ], request.params
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_from_json_string
|
46
|
+
raw = {
|
47
|
+
method: 'test_method',
|
48
|
+
params: nil,
|
49
|
+
id: 'e0b6cffa-8040-4c44-bc11-7fc3d8f4662c'
|
50
|
+
}
|
51
|
+
|
52
|
+
json = JSON.dump(raw)
|
53
|
+
|
54
|
+
request = Skein::RPC::Request.new(json)
|
55
|
+
|
56
|
+
assert_equal 'test_method', request.method
|
57
|
+
assert_equal nil, request.params
|
58
|
+
assert_equal 'e0b6cffa-8040-4c44-bc11-7fc3d8f4662c', request.id
|
59
|
+
|
60
|
+
assert_equal raw, request.to_h
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_from_hash
|
64
|
+
raw = {
|
65
|
+
method: 'test_method',
|
66
|
+
params: nil,
|
67
|
+
id: 'e0b6cffa-8040-4c44-bc11-7fc3d8f4662c'
|
68
|
+
}
|
69
|
+
|
70
|
+
request = Skein::RPC::Request.new(raw)
|
71
|
+
|
72
|
+
assert_equal 'test_method', request.method
|
73
|
+
assert_equal nil, request.params
|
74
|
+
assert_equal 'e0b6cffa-8040-4c44-bc11-7fc3d8f4662c', request.id
|
75
|
+
|
76
|
+
assert_equal raw, request.to_h
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_to_response_result
|
80
|
+
request = Skein::RPC::Request.new(
|
81
|
+
method: 'test_method',
|
82
|
+
params: 'test',
|
83
|
+
id: 'd8b625f1-5e0b-4bcf-bf6e-569e9edc634d'
|
84
|
+
)
|
85
|
+
|
86
|
+
response = request.response(
|
87
|
+
result: %w[ result ]
|
88
|
+
)
|
89
|
+
|
90
|
+
assert_equal request.id, response.id
|
91
|
+
assert_equal %w[ result ], response.result
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
|
3
|
+
class TestSkeinSupport < Test::Unit::TestCase
|
4
|
+
def test_symbolize_keys_simple_hash
|
5
|
+
hash = {
|
6
|
+
'test' => 'test_value',
|
7
|
+
true => 'true_value',
|
8
|
+
2 => 'two'
|
9
|
+
}
|
10
|
+
|
11
|
+
expected = {
|
12
|
+
test: 'test_value',
|
13
|
+
true: 'true_value',
|
14
|
+
'2': 'two'
|
15
|
+
}
|
16
|
+
|
17
|
+
assert_equal(expected, Skein::Support.symbolize_keys(hash))
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_symbolize_keys_on_array
|
21
|
+
array = [
|
22
|
+
{
|
23
|
+
'test' => :value,
|
24
|
+
'nested' => {
|
25
|
+
'hash' => true
|
26
|
+
}
|
27
|
+
},
|
28
|
+
{
|
29
|
+
'second' => :hash
|
30
|
+
}
|
31
|
+
]
|
32
|
+
|
33
|
+
expected = [
|
34
|
+
{
|
35
|
+
test: :value,
|
36
|
+
nested: {
|
37
|
+
hash: true
|
38
|
+
}
|
39
|
+
},
|
40
|
+
{
|
41
|
+
second: :hash
|
42
|
+
}
|
43
|
+
]
|
44
|
+
|
45
|
+
assert_equal(expected, Skein::Support.symbolize_keys(array))
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_symbolize_keys_on_non_hashes
|
49
|
+
assert_mapping(
|
50
|
+
1 => 1,
|
51
|
+
true => true,
|
52
|
+
nil => nil,
|
53
|
+
'test' => 'test',
|
54
|
+
:symbol => :symbol
|
55
|
+
) do |value|
|
56
|
+
Skein::Support.symbolize_keys(value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_hostname
|
61
|
+
hostname = Skein::Support.hostname
|
62
|
+
|
63
|
+
assert_equal(String, hostname.class)
|
64
|
+
assert(hostname.length > 0)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_process_name
|
68
|
+
process_name = Skein::Support.process_name
|
69
|
+
|
70
|
+
assert(process_name)
|
71
|
+
|
72
|
+
assert(%w[ test_skein_support rake_test_loader ].include?(process_name))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_pid
|
76
|
+
process_id = Skein::Support.process_id
|
77
|
+
|
78
|
+
assert(process_id)
|
79
|
+
assert(process_id.is_a?(Integer))
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_arrayify
|
83
|
+
assert_mapping(
|
84
|
+
[ :test ] => [ :test ],
|
85
|
+
:test => [ :test ],
|
86
|
+
true => [ true ],
|
87
|
+
0 => [ 0 ],
|
88
|
+
[ 0 ] => [ 0 ],
|
89
|
+
[ nil ] => [ nil ],
|
90
|
+
nil => nil
|
91
|
+
) do |value|
|
92
|
+
Skein::Support.arrayify(value)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|