skein 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.
- 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
|