skein 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +69 -0
  4. data/README.md +57 -0
  5. data/RELEASES.md +4 -0
  6. data/Rakefile +30 -0
  7. data/VERSION +1 -0
  8. data/bin/skein +186 -0
  9. data/config/.gitignore +3 -0
  10. data/config/skein.yml.example +11 -0
  11. data/lib/skein.rb +24 -0
  12. data/lib/skein/client.rb +51 -0
  13. data/lib/skein/client/publisher.rb +14 -0
  14. data/lib/skein/client/rpc.rb +96 -0
  15. data/lib/skein/client/subscriber.rb +25 -0
  16. data/lib/skein/client/worker.rb +51 -0
  17. data/lib/skein/config.rb +87 -0
  18. data/lib/skein/connected.rb +52 -0
  19. data/lib/skein/context.rb +38 -0
  20. data/lib/skein/handler.rb +86 -0
  21. data/lib/skein/handler/async.rb +9 -0
  22. data/lib/skein/handler/threaded.rb +7 -0
  23. data/lib/skein/rabbitmq.rb +44 -0
  24. data/lib/skein/reporter.rb +11 -0
  25. data/lib/skein/rpc.rb +24 -0
  26. data/lib/skein/rpc/base.rb +23 -0
  27. data/lib/skein/rpc/error.rb +34 -0
  28. data/lib/skein/rpc/notification.rb +2 -0
  29. data/lib/skein/rpc/request.rb +62 -0
  30. data/lib/skein/rpc/response.rb +38 -0
  31. data/lib/skein/support.rb +67 -0
  32. data/skein.gemspec +95 -0
  33. data/test/data/sample_config.yml +13 -0
  34. data/test/helper.rb +42 -0
  35. data/test/script/em_example +28 -0
  36. data/test/unit/test_skein_client.rb +18 -0
  37. data/test/unit/test_skein_client_publisher.rb +10 -0
  38. data/test/unit/test_skein_client_subscriber.rb +41 -0
  39. data/test/unit/test_skein_client_worker.rb +61 -0
  40. data/test/unit/test_skein_config.rb +33 -0
  41. data/test/unit/test_skein_context.rb +44 -0
  42. data/test/unit/test_skein_rabbitmq.rb +14 -0
  43. data/test/unit/test_skein_reporter.rb +4 -0
  44. data/test/unit/test_skein_rpc_error.rb +10 -0
  45. data/test/unit/test_skein_rpc_request.rb +93 -0
  46. data/test/unit/test_skein_support.rb +95 -0
  47. 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,10 @@
1
+ require_relative '../helper'
2
+
3
+ class TestSkeinPublisher < Test::Unit::TestCase
4
+ def test_defaults
5
+ publisher = Skein::Client::Publisher.new('test_name')
6
+
7
+ ensure
8
+ publisher and publisher.close
9
+ end
10
+ 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,14 @@
1
+ require_relative '../helper'
2
+
3
+ class TestSkeinRabbitMQ < Test::Unit::TestCase
4
+ def test_can_connect
5
+ rmq = Skein::RabbitMQ.connect
6
+
7
+ assert rmq
8
+
9
+ assert rmq.respond_to?(:create_channel)
10
+
11
+ ensure
12
+ rmq and rmq.close
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ require_relative '../helper'
2
+
3
+ class TestSkeinReporter < Test::Unit::TestCase
4
+ end
@@ -0,0 +1,10 @@
1
+ require_relative '../helper'
2
+
3
+ class TestSkeinRPCError < Test::Unit::TestCase
4
+ def test_default
5
+ error = Skein::RPC::Error.new
6
+
7
+ assert_equal nil, error.id
8
+ assert_equal nil, error.error
9
+ end
10
+ 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