proletariat 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +12 -0
- data/README.md +1 -2
- data/lib/proletariat/concurrency/actor.rb +71 -0
- data/lib/proletariat/concurrency/supervisor.rb +31 -0
- data/lib/proletariat/configuration.rb +131 -0
- data/lib/proletariat/cucumber.rb +6 -2
- data/lib/proletariat/manager.rb +20 -66
- data/lib/proletariat/publisher.rb +27 -51
- data/lib/proletariat/queue_config.rb +1 -5
- data/lib/proletariat/runner.rb +10 -106
- data/lib/proletariat/subscriber.rb +6 -8
- data/lib/proletariat/testing/expectation_guarantor.rb +5 -9
- data/lib/proletariat/testing.rb +1 -1
- data/lib/proletariat/util/worker_description_parser.rb +37 -0
- data/lib/proletariat/version.rb +1 -1
- data/lib/proletariat/worker.rb +17 -41
- data/lib/proletariat.rb +24 -51
- data/spec/lib/configuration_spec.rb +85 -0
- data/spec/lib/proletariat_spec.rb +5 -4
- data/spec/lib/publisher_spec.rb +36 -0
- data/spec/lib/queue_config_spec.rb +12 -0
- data/spec/lib/testing/expectation_guarantor_spec.rb +55 -0
- data/spec/lib/testing/expectation_spec.rb +15 -0
- data/spec/lib/util/worker_description_parser_spec.rb +42 -0
- data/spec/lib/worker_spec.rb +83 -0
- metadata +34 -25
@@ -8,19 +8,17 @@ module Proletariat
|
|
8
8
|
|
9
9
|
# Public: Creates a new Subscriber instance.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
14
|
-
def initialize(connection, listener, queue_config)
|
15
|
-
@connection = connection
|
11
|
+
# listener - Object to delegate new messages to.
|
12
|
+
# queue_config - A QueueConfig value object.
|
13
|
+
def initialize(listener, queue_config)
|
16
14
|
@listener = listener
|
17
15
|
@queue_config = queue_config
|
18
16
|
|
19
|
-
@channel =
|
17
|
+
@channel = Proletariat.connection.create_channel
|
20
18
|
|
21
|
-
@channel.prefetch
|
19
|
+
@channel.prefetch Proletariat.worker_threads
|
22
20
|
|
23
|
-
@exchange = @channel.topic
|
21
|
+
@exchange = @channel.topic Proletariat.exchange_name, durable: true
|
24
22
|
@bunny_queue = @channel.queue queue_config.queue_name,
|
25
23
|
durable: true,
|
26
24
|
auto_delete: queue_config.auto_delete
|
@@ -19,7 +19,6 @@ module Proletariat
|
|
19
19
|
# block - The block of code within which the expectations should
|
20
20
|
# be satisfied.
|
21
21
|
def initialize(expectations, &block)
|
22
|
-
@connection = Proletariat.runner.connection
|
23
22
|
@counters = []
|
24
23
|
@subscribers = []
|
25
24
|
|
@@ -27,7 +26,7 @@ module Proletariat
|
|
27
26
|
queue_config = generate_queue_config_for_topic(expectation.topics)
|
28
27
|
counter = MessageCounter.new(expectation.quantity)
|
29
28
|
counters << counter
|
30
|
-
subscribers << Subscriber.new(
|
29
|
+
subscribers << Subscriber.new(counter, queue_config)
|
31
30
|
end
|
32
31
|
|
33
32
|
@block = block
|
@@ -40,7 +39,7 @@ module Proletariat
|
|
40
39
|
def guarantee
|
41
40
|
run_subscribers
|
42
41
|
|
43
|
-
block.call
|
42
|
+
block.call if block
|
44
43
|
|
45
44
|
timer = 0.0
|
46
45
|
|
@@ -61,9 +60,6 @@ module Proletariat
|
|
61
60
|
# satisfied.
|
62
61
|
attr_reader :block
|
63
62
|
|
64
|
-
# Internal: Returns an open Bunny::Session object.
|
65
|
-
attr_reader :connection
|
66
|
-
|
67
63
|
# Internal: Returns an array of MessageCounter instances.
|
68
64
|
attr_reader :counters
|
69
65
|
|
@@ -71,7 +67,7 @@ module Proletariat
|
|
71
67
|
attr_reader :subscribers
|
72
68
|
|
73
69
|
def generate_queue_config_for_topic(topics)
|
74
|
-
QueueConfig.new('',
|
70
|
+
QueueConfig.new('', topics, true)
|
75
71
|
end
|
76
72
|
|
77
73
|
# Internal: Checks each counter to ensure expected messages have arrived.
|
@@ -107,8 +103,8 @@ module Proletariat
|
|
107
103
|
# Public: Creates a new MessageCounter instance.
|
108
104
|
#
|
109
105
|
# expected - The number of messages expected.
|
110
|
-
def initialize(expected)
|
111
|
-
@count =
|
106
|
+
def initialize(expected, count = 0)
|
107
|
+
@count = count
|
112
108
|
@expected = expected
|
113
109
|
end
|
114
110
|
|
data/lib/proletariat/testing.rb
CHANGED
@@ -4,7 +4,7 @@ require 'proletariat/testing/fixnum_extension'
|
|
4
4
|
|
5
5
|
module Proletariat
|
6
6
|
# Public: Mixin to aid solve test synchronization issues while still running
|
7
|
-
# Proletariat the same way you would in production
|
7
|
+
# Proletariat the same way you would in production.
|
8
8
|
module Testing
|
9
9
|
# Public: Builds an Expectation instance which listens for a single message
|
10
10
|
# on any topic.
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Proletariat
|
2
|
+
# Internal: Helper utility to parse and constantize strings into arrays of
|
3
|
+
# Worker classes.
|
4
|
+
module WorkerDescriptionParser
|
5
|
+
# Public: Parse given string into array of Worker classes.
|
6
|
+
#
|
7
|
+
# description - String to be parsed. Should contain comma-separated class
|
8
|
+
# names.
|
9
|
+
#
|
10
|
+
# Examples
|
11
|
+
#
|
12
|
+
# WorkerDescriptionParser.parse('FirstWorker,SecondWorker')
|
13
|
+
# # => [FirstWorker, SecondWorker]
|
14
|
+
#
|
15
|
+
# Returns an Array of Worker classes.
|
16
|
+
def self.parse(description)
|
17
|
+
description.split(',').map(&:strip).map do |string|
|
18
|
+
constantize string
|
19
|
+
end.compact
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Intenal: Performs constantizing of worker names into Classes.
|
25
|
+
#
|
26
|
+
# name - The name to be constantized.
|
27
|
+
#
|
28
|
+
# Returns the Worker class if valid.
|
29
|
+
# Returns the nil if Worker class cannot be found.
|
30
|
+
def self.constantize(name)
|
31
|
+
name.split('::').reduce(Object) { |a, e| a.const_get(e) }
|
32
|
+
rescue NameError => e
|
33
|
+
Proletariat.logger.warn "Missing worker class: #{e.name}"
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/proletariat/version.rb
CHANGED
data/lib/proletariat/worker.rb
CHANGED
@@ -1,48 +1,39 @@
|
|
1
|
+
require 'proletariat/concerns/logging'
|
2
|
+
|
1
3
|
module Proletariat
|
2
|
-
# Public: Handles messages
|
4
|
+
# Public: Handles messages for Background processing. Subclasses should
|
3
5
|
# overwrite the #work method.
|
4
|
-
class Worker
|
6
|
+
class Worker
|
5
7
|
include Concerns::Logging
|
6
8
|
|
7
|
-
#
|
8
|
-
# messages. Overridden in this subclass to call the #work method
|
9
|
-
# with the given message.
|
10
|
-
#
|
11
|
-
# message - The incoming message.
|
9
|
+
# Public: Logs the 'online' status of the worker.
|
12
10
|
#
|
13
11
|
# Returns nil.
|
14
|
-
def
|
15
|
-
|
12
|
+
def started
|
13
|
+
log_info 'Now online'
|
14
|
+
|
15
|
+
nil
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
# in this subclass to log the status of the worker.
|
18
|
+
# Public: Logs the 'offline' status of the worker.
|
20
19
|
#
|
21
20
|
# Returns nil.
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
log_info 'Now online'
|
21
|
+
def stopped
|
22
|
+
log_info 'Now offline'
|
26
23
|
|
27
24
|
nil
|
28
25
|
end
|
29
26
|
|
30
|
-
#
|
31
|
-
# in this subclass to log the status of the worker.
|
27
|
+
# Public: Logs the 'shutting down' status of the worker.
|
32
28
|
#
|
33
29
|
# Returns nil.
|
34
|
-
def
|
30
|
+
def stopping
|
35
31
|
log_info 'Attempting graceful shutdown.'
|
36
|
-
wait_for_work_queue unless queue.empty?
|
37
|
-
|
38
|
-
super
|
39
|
-
|
40
|
-
log_info 'Now offline'
|
41
32
|
|
42
33
|
nil
|
43
34
|
end
|
44
35
|
|
45
|
-
# Public: Handles
|
36
|
+
# Public: Handles an incoming message to perform background work.
|
46
37
|
#
|
47
38
|
# message - The incoming message.
|
48
39
|
#
|
@@ -51,8 +42,6 @@ module Proletariat
|
|
51
42
|
fail NotImplementedError
|
52
43
|
end
|
53
44
|
|
54
|
-
protected
|
55
|
-
|
56
45
|
# Public: Helper method to ease accessing the logger from within #work.
|
57
46
|
# Sends #info to logger if message provided.
|
58
47
|
#
|
@@ -90,19 +79,6 @@ module Proletariat
|
|
90
79
|
nil
|
91
80
|
end
|
92
81
|
|
93
|
-
private
|
94
|
-
|
95
|
-
# Internal: Blocks until each message has been handled by #work.
|
96
|
-
#
|
97
|
-
# Returns nil.
|
98
|
-
def wait_for_work_queue
|
99
|
-
log_info 'Waiting for work queue to drain.'
|
100
|
-
|
101
|
-
work(*queue.pop.message) until queue.empty?
|
102
|
-
|
103
|
-
nil
|
104
|
-
end
|
105
|
-
|
106
82
|
# Internal: Class methods on Worker to provide configuration DSL.
|
107
83
|
module ConfigurationMethods
|
108
84
|
# Public: A configuration method for adding a routing key to be used when
|
@@ -111,8 +87,8 @@ module Proletariat
|
|
111
87
|
# routing_key - A routing key for queue-binding as a String.
|
112
88
|
#
|
113
89
|
# Returns nil.
|
114
|
-
def listen_on(
|
115
|
-
routing_keys
|
90
|
+
def listen_on(*new_routing_keys)
|
91
|
+
routing_keys.concat new_routing_keys
|
116
92
|
|
117
93
|
nil
|
118
94
|
end
|
data/lib/proletariat.rb
CHANGED
@@ -5,8 +5,12 @@ require 'bunny'
|
|
5
5
|
require 'logger'
|
6
6
|
require 'forwardable'
|
7
7
|
|
8
|
-
require 'proletariat/
|
8
|
+
require 'proletariat/concurrency/actor'
|
9
|
+
require 'proletariat/concurrency/supervisor'
|
9
10
|
|
11
|
+
require 'proletariat/util/worker_description_parser'
|
12
|
+
|
13
|
+
require 'proletariat/configuration'
|
10
14
|
require 'proletariat/manager'
|
11
15
|
require 'proletariat/publisher'
|
12
16
|
require 'proletariat/queue_config'
|
@@ -15,73 +19,42 @@ require 'proletariat/subscriber'
|
|
15
19
|
require 'proletariat/worker'
|
16
20
|
|
17
21
|
# Public: Creates the Proletariat namespace and holds a process-wide Runner
|
18
|
-
# instance as well as
|
22
|
+
# instance as well as access to the configuration attributes.
|
19
23
|
module Proletariat
|
20
|
-
# Public: The default name used for the RabbitMQ topic exchange.
|
21
|
-
DEFAULT_EXCHANGE_NAME = 'proletariat'
|
22
|
-
|
23
24
|
class << self
|
24
25
|
extend Forwardable
|
25
26
|
|
26
27
|
# Public: Delegate lifecycle calls to the process-wide Runner.
|
27
28
|
def_delegators :runner, :run, :run!, :stop, :running?, :publish, :purge
|
28
29
|
|
29
|
-
# Public: Allows
|
30
|
+
# Public: Allows configuration of Proletariat via given block.
|
30
31
|
#
|
31
|
-
#
|
32
|
-
attr_writer :logger
|
33
|
-
|
34
|
-
# Public: Sets the process-wide Runner to an instance initialized with a
|
35
|
-
# given hash of options.
|
32
|
+
# block - Block containing configuration calls.
|
36
33
|
#
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
# String.
|
41
|
-
# :logger - An object which fulfills the role of a
|
42
|
-
# Logger.
|
43
|
-
# :publisher_threads - The size of the publisher thread pool.
|
44
|
-
# :supervisor - A Supervisor instance.
|
45
|
-
# :worker_classes - An Array of Worker subclasses.
|
46
|
-
# :worker_threads - The size of the worker thread pool.
|
47
|
-
def configure(options = {})
|
48
|
-
self.logger = options.fetch(:logger, default_logger)
|
34
|
+
# Returns nil.
|
35
|
+
def configure(&block)
|
36
|
+
config.configure_with_block(&block)
|
49
37
|
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
# Internal: The logger used if no other is specified via .configure.
|
54
|
-
#
|
55
|
-
# Returns a Logger which logs to STDOUT.
|
56
|
-
def default_logger
|
57
|
-
Logger.new(STDOUT)
|
38
|
+
nil
|
58
39
|
end
|
59
40
|
|
60
|
-
|
61
|
-
|
62
|
-
# Returns a Hash of options.
|
63
|
-
def defaults
|
64
|
-
{
|
65
|
-
worker_classes: workers_from_env || []
|
66
|
-
}
|
41
|
+
def runner
|
42
|
+
@runner ||= Runner.new
|
67
43
|
end
|
68
44
|
|
69
|
-
def
|
70
|
-
|
45
|
+
def method_missing(method_sym, *arguments, &block)
|
46
|
+
if config.respond_to? method_sym
|
47
|
+
config.send method_sym
|
48
|
+
else
|
49
|
+
super
|
50
|
+
end
|
71
51
|
end
|
72
52
|
|
73
|
-
|
74
|
-
@runner ||= Runner.new(defaults)
|
75
|
-
end
|
53
|
+
private
|
76
54
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
string
|
81
|
-
.split('::')
|
82
|
-
.reduce(Object) { |a, e| a.const_get(e) }
|
83
|
-
end
|
84
|
-
end
|
55
|
+
# Internal: Global configuration object.
|
56
|
+
def config
|
57
|
+
@config ||= Configuration.new
|
85
58
|
end
|
86
59
|
end
|
87
60
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'proletariat'
|
2
|
+
|
3
|
+
FirstWorker = Class.new
|
4
|
+
SecondWorker = Class.new
|
5
|
+
|
6
|
+
module Proletariat
|
7
|
+
describe Configuration do
|
8
|
+
describe '#configure_with_block' do
|
9
|
+
it 'should allow configuration via `config.[attribute]=`' do
|
10
|
+
configuration = Configuration.new
|
11
|
+
expect(configuration).to receive(:connection=).with('new connection')
|
12
|
+
configuration.configure_with_block do
|
13
|
+
config.connection = 'new connection'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#connection' do
|
19
|
+
let(:new_session) { double.as_null_object }
|
20
|
+
|
21
|
+
before do
|
22
|
+
stub_const 'Bunny', double(new: new_session)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should default to a creating a new bunny session' do
|
26
|
+
expect(Bunny).to receive(:new)
|
27
|
+
Configuration.new.connection
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should open any new bunny sessions' do
|
31
|
+
expect(new_session).to receive(:start)
|
32
|
+
Configuration.new.connection
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#exchange_name' do
|
37
|
+
it 'should default to proletariat' do
|
38
|
+
expect(Configuration.new.exchange_name).to eq 'proletariat'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#logger' do
|
43
|
+
it 'should default to STDOUT' do
|
44
|
+
expect(Logger).to receive(:new).with(STDOUT)
|
45
|
+
Configuration.new.logger
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#publisher_threads' do
|
50
|
+
it 'should default to 2' do
|
51
|
+
expect(Configuration.new.publisher_threads).to eq 2
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#worker_classes' do
|
56
|
+
context 'WORKERS env variable is set' do
|
57
|
+
before do
|
58
|
+
ENV['WORKERS'] = 'FirstWorker,SecondWorker'
|
59
|
+
end
|
60
|
+
|
61
|
+
after do
|
62
|
+
ENV['WORKERS'] = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should default to workers in env variable' do
|
66
|
+
expect(Configuration.new.worker_classes).to \
|
67
|
+
eq [FirstWorker, SecondWorker]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'WORKERS env variable is not set' do
|
72
|
+
it 'should default to an empty array' do
|
73
|
+
expect(Configuration.new.worker_classes).to \
|
74
|
+
eq []
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#worker_threads' do
|
80
|
+
it 'should default to 3' do
|
81
|
+
expect(Configuration.new.worker_threads).to eq 3
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -40,10 +40,11 @@ end
|
|
40
40
|
|
41
41
|
describe Proletariat do
|
42
42
|
it 'should roughly work' do
|
43
|
-
Proletariat.configure
|
44
|
-
logger
|
45
|
-
worker_classes
|
46
|
-
|
43
|
+
Proletariat.configure do
|
44
|
+
config.logger = Logger.new('/dev/null')
|
45
|
+
config.worker_classes = [PingWorker, PongWorker]
|
46
|
+
end
|
47
|
+
|
47
48
|
Proletariat.run!
|
48
49
|
sleep 2
|
49
50
|
Proletariat.publish 'ping', ''
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'proletariat/publisher'
|
2
|
+
|
3
|
+
module Proletariat
|
4
|
+
describe Publisher do
|
5
|
+
let(:connection) { double.as_null_object }
|
6
|
+
let(:exchange_name) { 'great-exchange' }
|
7
|
+
let(:logger) { double }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(Proletariat).to receive(:connection).and_return(connection)
|
11
|
+
allow(Proletariat).to receive(:exchange_name).and_return(exchange_name)
|
12
|
+
allow(Proletariat).to receive(:logger).and_return(logger)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#started' do
|
16
|
+
it 'should log status' do
|
17
|
+
expect(logger).to receive(:info).with /online/
|
18
|
+
Publisher.new.started
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#stopped' do
|
23
|
+
it 'should log status' do
|
24
|
+
expect(logger).to receive(:info).with /offline/
|
25
|
+
Publisher.new.stopped
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#stopping' do
|
30
|
+
it 'should log status' do
|
31
|
+
expect(logger).to receive(:info).with /graceful shutdown/
|
32
|
+
Publisher.new.stopping
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'proletariat/queue_config'
|
2
|
+
|
3
|
+
module Proletariat
|
4
|
+
describe QueueConfig do
|
5
|
+
describe '#queue_name' do
|
6
|
+
it 'should return an underscored version of the worker name' do
|
7
|
+
queue_config = QueueConfig.new('ExampleWorker', ['lolcats'], false)
|
8
|
+
expect(queue_config.queue_name).to eq 'example_worker'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'proletariat/testing/expectation_guarantor'
|
2
|
+
|
3
|
+
module Proletariat
|
4
|
+
module Testing
|
5
|
+
describe ExpectationGuarantor::MessageCounter do
|
6
|
+
describe '#expected_messages_received?' do
|
7
|
+
context 'count is equal or greater than expected' do
|
8
|
+
it 'should return true' do
|
9
|
+
counter = ExpectationGuarantor::MessageCounter.new(1, 3)
|
10
|
+
expect(counter.expected_messages_received?).to be_truthy
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'count is less than expected' do
|
15
|
+
it 'should return false' do
|
16
|
+
counter = ExpectationGuarantor::MessageCounter.new(5, 3)
|
17
|
+
expect(counter.expected_messages_received?).to be_falsey
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#post?' do
|
23
|
+
class FakeBlockTaker
|
24
|
+
attr_reader :block
|
25
|
+
|
26
|
+
def initialize(&block)
|
27
|
+
@block = block
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
before do
|
32
|
+
stub_const 'Concurrent::Future', FakeBlockTaker
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should increment the count' do
|
36
|
+
counter = ExpectationGuarantor::MessageCounter.new(1)
|
37
|
+
counter.post?('message')
|
38
|
+
expect(counter.expected_messages_received?).to be_truthy
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should return a future containing :ok' do
|
42
|
+
counter = ExpectationGuarantor::MessageCounter.new(1)
|
43
|
+
expect(Concurrent::Future).to receive(:new)
|
44
|
+
counter.post?('message')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should ensure the returned future contains :ok' do
|
48
|
+
counter = ExpectationGuarantor::MessageCounter.new(1)
|
49
|
+
future = counter.post?('message')
|
50
|
+
expect(future.block.call).to eq :ok
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'proletariat/testing/expectation'
|
2
|
+
|
3
|
+
module Proletariat
|
4
|
+
module Testing
|
5
|
+
describe Expectation do
|
6
|
+
describe '#on_topic' do
|
7
|
+
it 'should return a new expectation with given topic' do
|
8
|
+
expectation = Expectation.new([], 2)
|
9
|
+
expect(expectation.on_topic('lolcats', 'dogs').topics).to \
|
10
|
+
eq %w(lolcats dogs)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'proletariat/util/worker_description_parser'
|
2
|
+
|
3
|
+
FakeWorker = Class.new
|
4
|
+
AnotherFakeWorker = Class.new
|
5
|
+
|
6
|
+
module Proletariat
|
7
|
+
describe WorkerDescriptionParser do
|
8
|
+
describe '.parse' do
|
9
|
+
let(:logger) { double.as_null_object }
|
10
|
+
|
11
|
+
before do
|
12
|
+
stub_const 'Proletariat', double(logger: logger)
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'worker classes exist' do
|
16
|
+
it 'should return the worker classes' do
|
17
|
+
parsed = WorkerDescriptionParser.parse 'FakeWorker,AnotherFakeWorker'
|
18
|
+
expect(parsed).to eq [FakeWorker, AnotherFakeWorker]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'worker classes do not exist' do
|
23
|
+
it 'should return an empty array' do
|
24
|
+
parsed = WorkerDescriptionParser.parse('NonexistantWorker')
|
25
|
+
expect(parsed).to eq []
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should log a warning for the missing class' do
|
29
|
+
expect(logger).to receive(:warn).with(/Missing worker class/)
|
30
|
+
WorkerDescriptionParser.parse('NonexistantWorker')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'some worker classes exist' do
|
35
|
+
it 'should return only the existing classes' do
|
36
|
+
parsed = WorkerDescriptionParser.parse 'FakeWorker,NonexistantWorker'
|
37
|
+
expect(parsed).to eq [FakeWorker]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|