batsir 0.1.0 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.travis.yml +9 -1
  2. data/CHANGES.md +54 -0
  3. data/Gemfile +7 -10
  4. data/README.md +49 -5
  5. data/Rakefile +23 -16
  6. data/batsir.gemspec +43 -15
  7. data/lib/batsir/acceptors/acceptor.rb +31 -5
  8. data/lib/batsir/acceptors/amqp_acceptor.rb +36 -8
  9. data/lib/batsir/amqp.rb +35 -7
  10. data/lib/batsir/amqp_consumer.rb +8 -0
  11. data/lib/batsir/compiler/stage_worker_compiler.rb +86 -0
  12. data/lib/batsir/config.rb +208 -24
  13. data/lib/batsir/dsl/conditional_notifier_declaration.rb +31 -0
  14. data/lib/batsir/dsl/dsl_mappings.rb +27 -2
  15. data/lib/batsir/errors.rb +18 -0
  16. data/lib/batsir/filter.rb +5 -0
  17. data/lib/batsir/log.rb +7 -0
  18. data/lib/batsir/logger.rb +37 -0
  19. data/lib/batsir/logo.rb +3 -8
  20. data/lib/batsir/notifiers/amqp_notifier.rb +14 -4
  21. data/lib/batsir/notifiers/conditional_notifier.rb +29 -0
  22. data/lib/batsir/notifiers/notifier.rb +6 -5
  23. data/lib/batsir/registry.rb +6 -2
  24. data/lib/batsir/stage.rb +9 -4
  25. data/lib/batsir/stage_worker.rb +3 -56
  26. data/lib/batsir/strategies/retry_strategy.rb +35 -0
  27. data/lib/batsir/strategies/strategy.rb +20 -0
  28. data/lib/batsir/transformers/field_transformer.rb +2 -3
  29. data/lib/batsir/transformers/json_input_transformer.rb +6 -2
  30. data/lib/batsir/transformers/json_output_transformer.rb +6 -2
  31. data/lib/batsir/transformers/transformer.rb +5 -1
  32. data/lib/batsir/version.rb +10 -0
  33. data/lib/batsir.rb +31 -13
  34. data/spec/batsir/acceptors/acceptor_spec.rb +7 -78
  35. data/spec/batsir/acceptors/amqp_acceptor_spec.rb +55 -66
  36. data/spec/batsir/acceptors/shared_examples.rb +102 -0
  37. data/spec/batsir/amqp_spec.rb +58 -0
  38. data/spec/batsir/chain_spec.rb +4 -4
  39. data/spec/batsir/config_spec.rb +97 -0
  40. data/spec/batsir/dsl/chain_mapping_spec.rb +5 -6
  41. data/spec/batsir/dsl/conditional_notifier_mapping_spec.rb +80 -0
  42. data/spec/batsir/dsl/stage_mapping_spec.rb +38 -20
  43. data/spec/batsir/filter_queue_spec.rb +9 -15
  44. data/spec/batsir/filter_spec.rb +4 -5
  45. data/spec/batsir/log_spec.rb +10 -0
  46. data/spec/batsir/logger_spec.rb +46 -0
  47. data/spec/batsir/notifiers/amqp_notifier_spec.rb +43 -22
  48. data/spec/batsir/notifiers/conditional_notifier_spec.rb +62 -0
  49. data/spec/batsir/notifiers/notifier_spec.rb +4 -66
  50. data/spec/batsir/notifiers/shared_examples.rb +100 -0
  51. data/spec/batsir/registry_spec.rb +48 -0
  52. data/spec/batsir/stage_spec.rb +91 -85
  53. data/spec/batsir/stage_worker_spec.rb +13 -13
  54. data/spec/batsir/strategies/retry_strategy_spec.rb +58 -0
  55. data/spec/batsir/strategies/strategy_spec.rb +28 -0
  56. data/spec/batsir/support/bunny_mocks.rb +78 -5
  57. data/spec/batsir/transformers/field_transformer_spec.rb +22 -22
  58. data/spec/batsir/transformers/json_input_transformer_spec.rb +8 -3
  59. data/spec/batsir/transformers/json_output_transformer_spec.rb +2 -2
  60. data/spec/batsir/transformers/transformer_spec.rb +18 -4
  61. data/spec/spec_helper.rb +6 -2
  62. metadata +78 -23
  63. data/VERSION +0 -1
@@ -1,51 +1,58 @@
1
1
  require File.join( File.dirname(__FILE__), "..", "..", "spec_helper" )
2
+ require File.join( File.dirname(__FILE__), 'shared_examples')
2
3
 
3
4
  describe Batsir::Notifiers::AMQPNotifier do
4
5
  let(:notifier_class){
5
6
  Batsir::Notifiers::AMQPNotifier
6
- }
7
+ }
7
8
 
8
- context "With respect to setting options" do
9
- it "should be a Batsir::Notifiers::Notifier" do
9
+ def new_notifier(options = {})
10
+ notifier_class.new(options)
11
+ end
12
+
13
+ it_should_behave_like "a notifier", Batsir::Notifiers::AMQPNotifier
14
+
15
+ context "with respect to setting options" do
16
+ it "is a Batsir::Notifiers::Notifier" do
10
17
  notifier_class.ancestors.should include Batsir::Notifiers::Notifier
11
18
  end
12
19
 
13
- it "should be possible to set the queue on which to listen" do
20
+ it "can set the queue on which to listen" do
14
21
  notifier = notifier_class.new(:queue => :queue)
15
22
  notifier.queue.should == :queue
16
23
  end
17
24
 
18
- it "should be possible to set the host of the amqp broker" do
25
+ it "can set the host of the amqp broker" do
19
26
  notifier = notifier_class.new(:host => 'localhost')
20
27
  notifier.host.should == 'localhost'
21
28
  end
22
29
 
23
- it "should be possible to set the port of the amqp broker" do
30
+ it "can set the port of the amqp broker" do
24
31
  notifier = notifier_class.new(:port => 1234)
25
32
  notifier.port.should == 1234
26
33
  end
27
34
 
28
- it "should be possible to set the username with which to connect to the broker" do
35
+ it "can set the username with which to connect to the broker" do
29
36
  notifier = notifier_class.new(:username => 'some_user')
30
37
  notifier.username.should == 'some_user'
31
38
  end
32
39
 
33
- it "should be possible to set the password with which to connect to the broker" do
40
+ it "can set the password with which to connect to the broker" do
34
41
  notifier = notifier_class.new(:password => 'password')
35
42
  notifier.password.should == 'password'
36
43
  end
37
44
 
38
- it "should be possible to set the vhost to use on the broker" do
45
+ it "can set the vhost to use on the broker" do
39
46
  notifier = notifier_class.new(:vhost => '/blah')
40
47
  notifier.vhost.should == '/blah'
41
48
  end
42
49
 
43
- it "should be possible to set the exchange to use on the broker" do
50
+ it "can set the exchange to use on the broker" do
44
51
  notifier = notifier_class.new(:exchange => 'amq.direct')
45
52
  notifier.exchange.should == 'amq.direct'
46
53
  end
47
54
 
48
- it "should default to amqp://guest:guest@localhost:5672/ with direct exchange on vhost ''" do
55
+ it "defaults to amqp://guest:guest@localhost:5672/ with direct exchange on vhost ''" do
49
56
  notifier = notifier_class.new(:queue => :somequeue)
50
57
  notifier.queue.should == :somequeue
51
58
  notifier.host.should == 'localhost'
@@ -57,54 +64,62 @@ describe Batsir::Notifiers::AMQPNotifier do
57
64
  end
58
65
  end
59
66
 
60
- context "With respect to notifying" do
61
- def new_notifier(options = {})
62
- notifier_class.new(options)
67
+ context "with respect to notifying" do
68
+ before :each do
69
+ Batsir::Registry.reset
70
+ end
71
+
72
+ it 'has an #execute method' do
73
+ notifier_class.instance_methods.map{|m| m.to_s}.should include "execute"
63
74
  end
64
75
 
65
- it "should connect to the configured host" do
76
+ it 'has a #handle_error method' do
77
+ notifier_class.instance_methods.map{|m| m.to_s}.should include "handle_error"
78
+ end
79
+
80
+ it "connects to the configured host" do
66
81
  notifier = new_notifier(:host => 'somehost')
67
82
  notifier.execute({})
68
83
  instance = Bunny.instance
69
84
  instance.options[:host].should == 'somehost'
70
85
  end
71
86
 
72
- it "should connect to the configured port" do
87
+ it "connects to the configured port" do
73
88
  notifier = new_notifier(:port => 1234)
74
89
  notifier.execute({})
75
90
  instance = Bunny.instance
76
91
  instance.options[:port].should == 1234
77
92
  end
78
93
 
79
- it "should connect with the configured username" do
94
+ it "connects with the configured username" do
80
95
  notifier = new_notifier(:username => 'user')
81
96
  notifier.execute({})
82
97
  instance = Bunny.instance
83
- instance.options[:user].should == 'user'
98
+ instance.user.should == 'user'
84
99
  end
85
100
 
86
- it "should connect with the configured password" do
101
+ it "connects with the configured password" do
87
102
  notifier = new_notifier(:password => 'pass')
88
103
  notifier.execute({})
89
104
  instance = Bunny.instance
90
105
  instance.options[:pass].should == 'pass'
91
106
  end
92
107
 
93
- it "should connect to the configured vhost" do
108
+ it "connects to the configured vhost" do
94
109
  notifier = new_notifier(:vhost => '/vhost')
95
110
  notifier.execute({})
96
111
  instance = Bunny.instance
97
112
  instance.options[:vhost].should == '/vhost'
98
113
  end
99
114
 
100
- it "should declare the configured exchange" do
115
+ it "declares the configured exchange" do
101
116
  notifier = new_notifier(:exchange => 'some_exchange')
102
117
  notifier.execute({})
103
118
  instance = Bunny.instance
104
119
  instance.exchange.name.should == 'some_exchange'
105
120
  end
106
121
 
107
- it "should bind the configured exchange to the queue and publish the message with the queue set as routing key" do
122
+ it "binds the configured exchange to the queue and publish the message with the queue set as routing key" do
108
123
  notifier = new_notifier(:exchange => 'some_exchange', :queue => :queue)
109
124
  notifier.execute({})
110
125
  instance = Bunny.instance
@@ -112,6 +127,12 @@ describe Batsir::Notifiers::AMQPNotifier do
112
127
  instance.exchange.message.should == {}
113
128
  instance.exchange.key.should == :queue
114
129
  end
130
+ end
115
131
 
132
+ context "with respect to error handling" do
133
+ it 'uses a strategy object to resolve notification errors' do
134
+ notifier = new_notifier(:exchange => 'some_exchange', :queue => :queue)
135
+ notifier.error_strategy.should be_a Batsir::Strategies::RetryStrategy
136
+ end
116
137
  end
117
138
  end
@@ -0,0 +1,62 @@
1
+ require File.join( File.dirname(__FILE__), "..", "..", "spec_helper" )
2
+ require File.join( File.dirname(__FILE__), 'shared_examples')
3
+
4
+ describe Batsir::Notifiers::ConditionalNotifier do
5
+
6
+ it_should_behave_like "a notifier", Batsir::Notifiers::ConditionalNotifier
7
+
8
+ true_block = ::Proc.new { |message| true }
9
+
10
+ let(:notifier){ Batsir::Notifiers::Notifier }
11
+
12
+ it "can add notifiers" do
13
+ subject.notifiers.size.should == 0
14
+ subject.add_notifier( true_block, notifier)
15
+ subject.notifiers.size.should == 1
16
+ end
17
+
18
+ it "stores notifier conditions" do
19
+ subject.add_notifier(true_block, notifier)
20
+
21
+ notifier_condition = subject.notifiers.first
22
+ notifier_condition.should be_a Batsir::Notifiers::ConditionalNotifier::NotifierCondition
23
+ notifier_condition.condition.should == true_block
24
+ notifier_condition.notifier.should == notifier
25
+ end
26
+
27
+ it "stores optional options for the notifier" do
28
+ subject.add_notifier( true_block, notifier, :some => :extra, :options => :foryou)
29
+
30
+ notifier_condition = subject.notifiers.first
31
+ notifier_condition.options.size.should == 2
32
+ notifier_condition.options.should have_key :some
33
+ notifier_condition.options.should have_key :options
34
+ end
35
+
36
+ context "sending messages" do
37
+ class FakeNotifier < Batsir::Notifiers::Notifier; end
38
+
39
+ it "executes notifiers if condition is true" do
40
+
41
+ notifier_class = FakeNotifier
42
+ notifier_class.any_instance.stub(:execute)
43
+ notifier_class.any_instance.should_receive(:execute)
44
+
45
+ conditional = Batsir::Notifiers::ConditionalNotifier.new
46
+ conditional.add_notifier( true_block, notifier_class.new({}) )
47
+ conditional.execute("some message")
48
+ end
49
+
50
+ it "does not execute when condition is false" do
51
+ false_block = lambda {|message| false}
52
+
53
+ notifier_class = FakeNotifier
54
+ notifier_class.any_instance.stub(:execute)
55
+ notifier_class.any_instance.should_not_receive(:execute)
56
+
57
+ conditional = Batsir::Notifiers::ConditionalNotifier.new
58
+ conditional.add_notifier( false_block, notifier_class.new({}) )
59
+ conditional.execute("some message")
60
+ end
61
+ end
62
+ end
@@ -1,73 +1,11 @@
1
1
  require File.join( File.dirname(__FILE__), "..", "..", "spec_helper" )
2
+ require File.join( File.dirname(__FILE__), 'shared_examples')
2
3
 
3
4
  describe Batsir::Notifiers::Notifier do
4
- let( :notifier_class ) do
5
- Batsir::Notifiers::Notifier
6
- end
7
-
8
- it "should have a transformer_queue" do
9
- notifier = notifier_class.new
10
- notifier.transformer_queue.should_not be_nil
11
- end
12
-
13
- it "should initially have an empty transformer_queue" do
14
- notifier = notifier_class.new
15
- notifier.transformer_queue.should_not be_nil
16
- notifier.transformer_queue.should be_empty
17
- end
18
-
19
- it "should be possible to add a transformer to the transformer_queue" do
20
- transformer = :transformer
21
-
22
- notifier = notifier_class.new
23
- notifier.add_transformer transformer
24
-
25
- notifier.transformer_queue.should_not be_empty
26
- notifier.transformer_queue.size.should == 1
27
- notifier.transformer_queue.first.should == :transformer
28
- end
29
-
30
- it "should be possible to add a transformer multiple times" do
31
- transformer = :transformer
32
5
 
33
- notifier = notifier_class.new
34
- notifier.add_transformer transformer
35
- notifier.add_transformer transformer
36
-
37
- notifier.transformer_queue.should_not be_empty
38
- notifier.transformer_queue.size.should == 2
39
- end
40
-
41
- it "should create a FieldTransformer when the 'fields' option is given during initialization" do
42
- fields = {:foo => :bar}
43
- notifier = notifier_class.new(:fields => fields)
44
- notifier.transformer_queue.should_not be_empty
45
- notifier.transformer_queue.first.class.should == Batsir::Transformers::FieldTransformer
46
- notifier.transformer_queue.first.fields.should == fields
47
- end
48
-
49
- it "should call #transform when #notify is called" do
50
- notifier = notifier_class.new
51
- notifier.should_receive(:transform).with({})
52
- notifier.notify({})
53
- end
54
-
55
- it "should call #transform on all transformers when #transform is called" do
56
- class MockTransformer < Batsir::Transformers::Transformer
57
- end
58
-
59
- notifier = notifier_class.new
60
- transformer = MockTransformer.new
61
- notifier.add_transformer transformer
62
- notifier.transformer_queue.size.should == 1
63
-
64
- transformer.should_receive(:transform).with({})
65
- notifier.notify({})
66
- end
6
+ it_should_behave_like "a notifier", Batsir::Notifiers::Notifier
67
7
 
68
- it "should call #execute when #notify is called" do
69
- notifier = notifier_class.new
70
- notifier.should_receive(:execute)
71
- notifier.notify({})
8
+ it 'raises an error when the #execute method is not implemented' do
9
+ lambda{ subject.notify({})}.should raise_error NotImplementedError
72
10
  end
73
11
  end
@@ -0,0 +1,100 @@
1
+ shared_examples_for "a notifier" do |notifier_class|
2
+ before :each do
3
+ subject{notifier_class.new}
4
+ end
5
+
6
+ context 'transformers' do
7
+ it "has a transformer_queue" do
8
+ subject.transformer_queue.should_not be_nil
9
+ end
10
+
11
+ it "initially has an empty transformer_queue" do
12
+ subject.transformer_queue.should_not be_nil
13
+ subject.transformer_queue.should be_empty
14
+ end
15
+
16
+ it "can add a transformer to the transformer_queue" do
17
+ transformer = :transformer
18
+
19
+ subject.add_transformer transformer
20
+
21
+ subject.transformer_queue.should_not be_empty
22
+ subject.transformer_queue.size.should == 1
23
+ subject.transformer_queue.first.should == :transformer
24
+ end
25
+
26
+ it "can add a transformer multiple times" do
27
+ transformer = :transformer
28
+
29
+ subject.add_transformer transformer
30
+ subject.add_transformer transformer
31
+
32
+ subject.transformer_queue.should_not be_empty
33
+ subject.transformer_queue.size.should == 2
34
+ end
35
+
36
+ it "creates a FieldTransformer when the 'fields' option is given during initialization" do
37
+ fields = {:foo => :bar}
38
+ subject = notifier_class.new(:fields => fields)
39
+ subject.transformer_queue.should_not be_empty
40
+ subject.transformer_queue.first.class.should == Batsir::Transformers::FieldTransformer
41
+ subject.transformer_queue.first.fields.should == fields
42
+ end
43
+ end
44
+
45
+ context 'methods calls' do
46
+ it "has an #execute method" do
47
+ notifier_class.instance_methods.map{|m| m.to_s}.should include "execute"
48
+ end
49
+
50
+
51
+ it "calls #transform when #notify is called" do
52
+ subject.stub(:execute)
53
+ subject.should_receive(:transform).with({})
54
+ subject.notify({})
55
+ end
56
+
57
+ it "calls #transform on all transformers when #transform is called" do
58
+ class MockTransformer < Batsir::Transformers::Transformer
59
+ end
60
+
61
+ subject.stub(:execute)
62
+ transformer = MockTransformer.new
63
+ subject.add_transformer transformer
64
+ subject.transformer_queue.size.should == 1
65
+
66
+ transformer.should_receive(:transform).with({})
67
+ subject.notify({})
68
+ end
69
+
70
+ it "calls #execute when #notify is called" do
71
+ subject.stub(:execute)
72
+ subject.should_receive(:execute)
73
+ subject.notify({})
74
+ end
75
+ end
76
+
77
+ context 'message unmodified' do
78
+ it 'has no transformers' do
79
+ message = {'test_id' => 123}
80
+ subject.add_transformer(Batsir::Transformers::JSONOutputTransformer.new)
81
+ begin
82
+ subject.notify(message).should == {'test_id' => 123}
83
+ rescue NotImplementedError => e
84
+ end
85
+ message.should == {'test_id' => 123}
86
+ end
87
+
88
+ it 'has a FieldTransformer' do
89
+ fields = {:foo => 'bar', 'test_id' => 'test'}
90
+ message = {'test_id' => 123}
91
+ subject = notifier_class.new(:fields => fields)
92
+ subject.add_transformer(Batsir::Transformers::JSONOutputTransformer.new)
93
+ begin
94
+ subject.notify(message).should == {'test_id' => 123}
95
+ rescue NotImplementedError => e
96
+ end
97
+ message.should == {'test_id' => 123}
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,48 @@
1
+ require File.join( File.dirname(__FILE__), "..", "spec_helper" )
2
+
3
+ describe Batsir::Registry do
4
+
5
+ before :all do
6
+ @class = Batsir::Registry
7
+ end
8
+
9
+ before :each do
10
+ @class.reset
11
+ end
12
+
13
+ it "outputs the whole registry" do
14
+ @class.registry.should == {}
15
+ end
16
+
17
+ it "registers a value" do
18
+ @class.register(:foo, :bar)
19
+ @class.registry.keys.size.should == 1
20
+ @class.registry.keys.should include :foo
21
+ @class.registry.values.size.should == 1
22
+ @class.registry.values.should include :bar
23
+ end
24
+
25
+ it "is able to retrieve a registered variable" do
26
+ @class.register('test', 'value')
27
+ @class.get('test').should == 'value'
28
+ end
29
+
30
+ it "returns nil when the requested key is not found" do
31
+ @class.get('foobar').should be_nil
32
+ end
33
+
34
+ context "resetting" do
35
+ it "is possible" do
36
+ @class.register('foo', 'bar')
37
+ @class.registry.should == {'foo' => 'bar'}
38
+ @class.reset
39
+ @class.registry.should == {}
40
+ end
41
+
42
+ it "returns its new state" do
43
+ @class.register('foo', 'bar')
44
+ result = @class.reset
45
+ result.should == {}
46
+ end
47
+ end
48
+ end