dispatch-rider 1.4.0 → 1.4.2

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +20 -0
  3. data/.hound.yml +2 -0
  4. data/.rubocop.yml +50 -0
  5. data/.travis.yml +6 -0
  6. data/CHANGELOG.md +363 -0
  7. data/Gemfile +25 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.md +32 -3
  10. data/Rakefile +38 -0
  11. data/dispatch-rider.gemspec +46 -0
  12. data/lib/dispatch-rider/notification_services/aws_sns.rb +9 -0
  13. data/lib/dispatch-rider/version.rb +1 -1
  14. data/spec/fixtures/handlers/another_test_handler.rb +2 -0
  15. data/spec/fixtures/handlers/test_handler.rb +2 -0
  16. data/spec/lib/dispatch-rider/airbrake_error_handler_spec.rb +16 -0
  17. data/spec/lib/dispatch-rider/callbacks/access_spec.rb +62 -0
  18. data/spec/lib/dispatch-rider/callbacks/storage_spec.rb +43 -0
  19. data/spec/lib/dispatch-rider/configuration_spec.rb +74 -0
  20. data/spec/lib/dispatch-rider/default_error_handler_spec.rb +14 -0
  21. data/spec/lib/dispatch-rider/demultiplexer_spec.rb +117 -0
  22. data/spec/lib/dispatch-rider/dispatcher_spec.rb +69 -0
  23. data/spec/lib/dispatch-rider/handlers/base_spec.rb +81 -0
  24. data/spec/lib/dispatch-rider/handlers/inheritance_tracking_spec.rb +27 -0
  25. data/spec/lib/dispatch-rider/message_spec.rb +59 -0
  26. data/spec/lib/dispatch-rider/notification_services/aws_sns_spec.rb +28 -0
  27. data/spec/lib/dispatch-rider/notification_services/base_spec.rb +65 -0
  28. data/spec/lib/dispatch-rider/notification_services/file_system/channel_spec.rb +28 -0
  29. data/spec/lib/dispatch-rider/notification_services/file_system/notifier_spec.rb +14 -0
  30. data/spec/lib/dispatch-rider/notification_services/file_system_spec.rb +23 -0
  31. data/spec/lib/dispatch-rider/notification_services_spec.rb +4 -0
  32. data/spec/lib/dispatch-rider/publisher/base_spec.rb +79 -0
  33. data/spec/lib/dispatch-rider/publisher/configuration/destination_spec.rb +100 -0
  34. data/spec/lib/dispatch-rider/publisher/configuration/notification_service_spec.rb +53 -0
  35. data/spec/lib/dispatch-rider/publisher/configuration_reader_spec.rb +129 -0
  36. data/spec/lib/dispatch-rider/publisher/configuration_spec.rb +149 -0
  37. data/spec/lib/dispatch-rider/publisher/configuration_support_spec.rb +89 -0
  38. data/spec/lib/dispatch-rider/publisher_spec.rb +123 -0
  39. data/spec/lib/dispatch-rider/queue_services/aws_sqs_spec.rb +193 -0
  40. data/spec/lib/dispatch-rider/queue_services/base_spec.rb +147 -0
  41. data/spec/lib/dispatch-rider/queue_services/file_system_spec.rb +88 -0
  42. data/spec/lib/dispatch-rider/queue_services/received_message_spec.rb +23 -0
  43. data/spec/lib/dispatch-rider/queue_services/simple_spec.rb +63 -0
  44. data/spec/lib/dispatch-rider/queue_services_spec.rb +6 -0
  45. data/spec/lib/dispatch-rider/registrars/base_spec.rb +68 -0
  46. data/spec/lib/dispatch-rider/registrars/file_system_channel_spec.rb +12 -0
  47. data/spec/lib/dispatch-rider/registrars/handler_spec.rb +16 -0
  48. data/spec/lib/dispatch-rider/registrars/notification_service_spec.rb +13 -0
  49. data/spec/lib/dispatch-rider/registrars/publishing_destination_spec.rb +11 -0
  50. data/spec/lib/dispatch-rider/registrars/queue_service_spec.rb +13 -0
  51. data/spec/lib/dispatch-rider/registrars/sns_channel_spec.rb +14 -0
  52. data/spec/lib/dispatch-rider/registrars_spec.rb +4 -0
  53. data/spec/lib/dispatch-rider/runner_spec.rb +25 -0
  54. data/spec/lib/dispatch-rider/subscriber_spec.rb +140 -0
  55. data/spec/lib/dispatch-rider_spec.rb +27 -0
  56. data/spec/spec_helper.rb +21 -0
  57. metadata +107 -86
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::Dispatcher, :nodb => true do
4
+ class HandleSomething < DispatchRider::Handlers::Base
5
+ def process(params)
6
+ throw :something if params[:do_throw_something]
7
+ end
8
+ end
9
+
10
+ class HandlerThatReturnsFalse < DispatchRider::Handlers::Base
11
+ def process(params)
12
+ false
13
+ end
14
+ end
15
+
16
+ describe "#dispatch" do
17
+ let(:message){ DispatchRider::Message.new(:subject => "handle_something", :body => { :do_throw_something => true }) }
18
+
19
+ describe "callbacks" do
20
+ let(:dummy) { double(:dummy) }
21
+ let(:storage) { DispatchRider::Callbacks::Storage.new }
22
+ let(:message){ DispatchRider::Message.new(:subject => "handle_something", :body => { :do_throw_something => true }) }
23
+
24
+ before do
25
+ DispatchRider.config.stub(:callbacks) { storage }
26
+ storage.around(:dispatch_message) do |block, message|
27
+ begin
28
+ dummy.before
29
+ dummy.log(message)
30
+ block.call
31
+ ensure
32
+ dummy.after
33
+ end
34
+ end
35
+ subject.register('handle_something')
36
+ end
37
+ example do
38
+ dummy.should_receive(:before).once
39
+ dummy.should_receive(:after).once
40
+ dummy.should_receive(:log).with(message).once
41
+ catch(:something) do
42
+ subject.dispatch(message)
43
+ end
44
+ end
45
+ end
46
+
47
+ context "when the handler provided in the message is present" do
48
+ before :each do
49
+ subject.register('handle_something')
50
+ end
51
+
52
+ it "should process the message" do
53
+ expect { subject.dispatch(message) }.to throw_symbol(:something)
54
+ end
55
+ end
56
+
57
+ context "when the handler returns false" do
58
+ let(:message){ DispatchRider::Message.new(:subject => "handler_that_returns_false", :body => { :do_throw_something => true }) }
59
+
60
+ before :each do
61
+ subject.register('handler_that_returns_false')
62
+ end
63
+
64
+ it "should return true indicating message is good to be removed" do
65
+ expect(subject.dispatch(message)).to be true
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::Handlers::Base do
4
+ class NoProcessImplemented < DispatchRider::Handlers::Base
5
+ end
6
+
7
+ class ProcessImplemented < DispatchRider::Handlers::Base
8
+ def process(options)
9
+ "good job"
10
+ end
11
+ end
12
+
13
+ class ProcessWithImmediateRetry < DispatchRider::Handlers::Base
14
+ def process(options)
15
+ raise "I have failed!"
16
+ end
17
+
18
+ def retry_timeout; :immediate; end
19
+ end
20
+
21
+ class ProcessWithTenSecondRetry < DispatchRider::Handlers::Base
22
+ def process(options)
23
+ raise "I have failed!"
24
+ end
25
+
26
+ def retry_timeout; 10*60; end
27
+ end
28
+
29
+ describe "#do_process" do
30
+ let(:message){ double(:message, subject: 'some_message', body: { 'guid' => DispatchRider::Debug::PUBLISHER_MESSAGE_GUID }) }
31
+
32
+ context "when class doesn't implement process" do
33
+ let(:handler){ NoProcessImplemented.new }
34
+
35
+ example do
36
+ expect {
37
+ handler.do_process(message)
38
+ }.to raise_exception NotImplementedError, "Method 'process' not overridden in subclass!"
39
+ end
40
+ end
41
+
42
+ context "when the class does implement process" do
43
+ let(:handler){ ProcessImplemented.new }
44
+
45
+ example do
46
+ expect {
47
+ handler.do_process(message)
48
+ }.to_not raise_exception
49
+ end
50
+
51
+ example do
52
+ handler.do_process(message).should == "good job"
53
+ end
54
+ end
55
+
56
+ context "when the class wants to immediately retry" do
57
+ let(:handler) { ProcessWithImmediateRetry.new }
58
+
59
+ example do
60
+ message.should_receive(:return_to_queue)
61
+
62
+ expect {
63
+ handler.do_process(message)
64
+ }.to raise_exception "I have failed!"
65
+ end
66
+ end
67
+
68
+ context "when the class wants to retry in 10 seconds" do
69
+ let(:handler) { ProcessWithTenSecondRetry.new }
70
+
71
+ example do
72
+ message.should_receive(:extend_timeout).with(10*60)
73
+
74
+ expect {
75
+ handler.do_process(message)
76
+ }.to raise_exception "I have failed!"
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::Handlers::InheritanceTracking do
4
+
5
+ class InheritanceDummyClass
6
+ extend DispatchRider::Handlers::InheritanceTracking
7
+ end
8
+
9
+ describe ".subclasses" do
10
+ context "when a class inherits from the dummy class" do
11
+ class Blah < InheritanceDummyClass; end
12
+
13
+ example do
14
+ InheritanceDummyClass.subclasses.should include(Blah)
15
+ end
16
+
17
+ context "and another class inherits from the dummy class" do
18
+ class Foo < InheritanceDummyClass; end
19
+
20
+ example do
21
+ InheritanceDummyClass.subclasses.should include(Blah, Foo)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::Message do
4
+ subject(:message) {DispatchRider::Message.new(:subject => 'test', :body => 'test_handler')}
5
+
6
+ describe "#initialize" do
7
+ context "when all the required attributes are passed" do
8
+ context "when the attributes hash has keys as strings" do
9
+ subject(:message) {DispatchRider::Message.new('subject' => 'test', 'body' => 'test_handler')}
10
+
11
+ it "should initiate a new message" do
12
+ message.subject.should eq('test')
13
+ message.body.should eq('test_handler')
14
+ end
15
+ end
16
+
17
+ context "when the attributes hash has keys as symbols" do
18
+ it "should initiate a new message" do
19
+ message.subject.should eq('test')
20
+ message.body.should eq('test_handler')
21
+ end
22
+ end
23
+ end
24
+
25
+ context "when all the required attributes are not passed" do
26
+ it "should raise an exception" do
27
+ expect { DispatchRider::Message.new({}) }.to raise_exception(DispatchRider::RecordInvalid)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#attributes" do
33
+ it "should return the attributes hash of the message" do
34
+ message.attributes.should eq({:subject => 'test', :body => 'test_handler'})
35
+ end
36
+ end
37
+
38
+ describe "#to_json" do
39
+ it "should return the attributes hash in json format" do
40
+ result = JSON.parse(message.to_json)
41
+ result['subject'].should eq('test')
42
+ result['body'].should eq('test_handler')
43
+ end
44
+ end
45
+
46
+ describe "#==" do
47
+ context "when 2 messages have the same attribute values" do
48
+ it "should return true" do
49
+ message.should eq(DispatchRider::Message.new(:subject => 'test', :body => 'test_handler'))
50
+ end
51
+ end
52
+
53
+ context "when 2 messages do not have same attribute values" do
54
+ it "should return false" do
55
+ message.should_not eq(DispatchRider::Message.new(:subject => 'random_test', :body => 'test_handler'))
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::NotificationServices::AwsSns do
4
+ let(:amazon_resource_name){ "arn:aws:sns:us-west-2:123456789012:GeneralTopic" }
5
+
6
+ describe "#notifier_builder" do
7
+ it "returns the notifier builder" do
8
+ subject.notifier_builder.should eq(AWS::SNS)
9
+ end
10
+ end
11
+
12
+ describe "#channel_registrar_builder" do
13
+ it "returns the channel registrar builder" do
14
+ subject.channel_registrar_builder.should eq(DispatchRider::Registrars::SnsChannel)
15
+ end
16
+ end
17
+
18
+ describe "#channel" do
19
+ before { subject.stub(:channel_registrar).and_return(foo: amazon_resource_name) }
20
+
21
+ let(:topics){ double :sns_topics }
22
+ let(:topic){ double :sns_topic }
23
+
24
+ it "returns the channel" do
25
+ subject.channel(:foo).arn.should == amazon_resource_name
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::NotificationServices::Base do
4
+ let :channel do
5
+ channel = OpenStruct.new
6
+ class << channel
7
+ def publish(msg)
8
+ throw :published, JSON.parse(msg)["body"]["bar"]
9
+ end
10
+ end
11
+ channel
12
+ end
13
+
14
+ before :each do
15
+ DispatchRider::NotificationServices::Base.any_instance.stub(:notifier_builder).and_return(OpenStruct)
16
+ DispatchRider::NotificationServices::Base.any_instance.stub(:channel_registrar_builder).and_return(DispatchRider::Registrars::SnsChannel)
17
+ DispatchRider::NotificationServices::Base.any_instance.stub(:channel) do |name|
18
+ subject.notifier.topics[subject.fetch(name)] if name == :foo
19
+ end
20
+ end
21
+
22
+ subject do
23
+ DispatchRider::NotificationServices::Base.new({:topics => {}})
24
+ end
25
+
26
+ describe "#initialize" do
27
+ it "assigns the notifier" do
28
+ subject.notifier.should respond_to(:topics)
29
+ end
30
+
31
+ it "assigns the channel registrar" do
32
+ subject.channel_registrar.store.should be_empty
33
+ end
34
+ end
35
+
36
+ describe "#publish" do
37
+ before :each do
38
+ subject.register(:foo, account: 123, region: "us-east-1", topic: "PlanOfAttack")
39
+ subject.notifier.topics['arn:aws:sns:us-east-1:123:PlanOfAttack'] = channel
40
+ end
41
+
42
+ it "publishes the message to the channels" do
43
+ catch :published do
44
+ subject.publish(:to => :foo, :message => {:subject => :test_handler, :body => {"bar" => "baz"}})
45
+ end.should eq('baz')
46
+ end
47
+ end
48
+
49
+ describe "#channels" do
50
+ before :each do
51
+ subject.register(:foo, account: 123, region: "us-east-1", topic: "PlanOfAttack")
52
+ subject.notifier.topics['arn:aws:sns:us-east-1:123:PlanOfAttack'] = channel
53
+ end
54
+
55
+ it "returns an array of channels" do
56
+ subject.channels(:foo).should eq([channel])
57
+ end
58
+ end
59
+
60
+ describe "#message_builder" do
61
+ it "should return the message builder class" do
62
+ subject.message_builder.should eq(DispatchRider::Message)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::NotificationServices::FileSystem::Channel do
4
+
5
+ let(:path) { File.expand_path("tmp/test/channel") }
6
+ let(:published_message) { File.new(Dir["#{path}/*.ready"].first).read }
7
+
8
+ before { FileUtils.mkdir_p(path) }
9
+ after { FileUtils.rm_rf(path) }
10
+
11
+ subject { described_class.new(path) }
12
+
13
+ describe "#publish" do
14
+ let(:message){ {:subject => "foo", :body => "bar"}.to_json }
15
+
16
+ it "adds a file to the path folder" do
17
+ expect {
18
+ subject.publish(message)
19
+ }.to change { Dir["#{path}/*"].length }.by(1)
20
+ end
21
+
22
+ it "writes the message to the file" do
23
+ subject.publish(message)
24
+
25
+ published_message.should == message
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::NotificationServices::FileSystem::Notifier do
4
+
5
+ subject { described_class.new({}) }
6
+
7
+ describe "#channel" do
8
+ it "returns a channel object" do
9
+ subject.channel("tmp/some/path").should be_a(DispatchRider::NotificationServices::FileSystem::Channel)
10
+ end
11
+ end
12
+
13
+ end
14
+
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::NotificationServices::FileSystem do
4
+
5
+ describe "#notifier_builder" do
6
+ it "returns the notifier builder" do
7
+ subject.notifier_builder.should eq(DispatchRider::NotificationServices::FileSystem::Notifier)
8
+ end
9
+ end
10
+
11
+ describe "#channel_registrar_builder" do
12
+ it "returns the channel registrar builder" do
13
+ subject.channel_registrar_builder.should eq(DispatchRider::Registrars::FileSystemChannel)
14
+ end
15
+ end
16
+
17
+ describe "#channel" do
18
+ it "returns the channel" do
19
+ subject.channel_registrar.register(:foo, :path => "tmp/test/channel")
20
+ subject.channel(:foo).should be_a(DispatchRider::NotificationServices::FileSystem::Channel)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::NotificationServices do
4
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::Publisher::Base do
4
+
5
+ class DummyPublisher < DispatchRider::Publisher::Base
6
+ destinations [:sns_message_queue, :file_system_queue]
7
+ subject "Loud Cheering"
8
+
9
+ def self.publish(cheer)
10
+ new.publish(cheer)
11
+ end
12
+ end
13
+
14
+ class DummyCustomPublisher < DispatchRider::Publisher::Base
15
+ destinations :sqs_message_queue
16
+ subject "Ferocious Tigers!"
17
+
18
+ def self.publish(body, publisher)
19
+ new(publisher).publish(body)
20
+ end
21
+ end
22
+
23
+ describe ".default_publisher" do
24
+ example do
25
+ described_class.default_publisher.should be_a(DispatchRider::Publisher)
26
+ end
27
+ end
28
+
29
+ describe ".publish" do
30
+ context "in the base class" do
31
+ example do
32
+ expect {
33
+ described_class.publish
34
+ }.to raise_error NotImplementedError
35
+ end
36
+ end
37
+
38
+ context "in a derived class with publish implemented" do
39
+ let(:message) do
40
+ {
41
+ destinations: [:sns_message_queue, :file_system_queue],
42
+ message: {
43
+ subject: "Loud Cheering",
44
+ body: {
45
+ "bla" => "WOOOOOOOO!",
46
+ }
47
+ }
48
+ }
49
+ end
50
+
51
+ example do
52
+ DummyPublisher.default_publisher.should_receive(:publish).with(message)
53
+ DummyPublisher.publish({"bla" => "WOOOOOOOO!"})
54
+ end
55
+ end
56
+
57
+ context "in a derived class with publish implemented and a custom publisher" do
58
+ let(:message) do
59
+ {
60
+ destinations: [:sqs_message_queue],
61
+ message: {
62
+ subject: "Ferocious Tigers!",
63
+ body: {
64
+ "bla" => "RAAAAAWWWWW!",
65
+ },
66
+ }
67
+ }
68
+ end
69
+
70
+ let(:publisher) { double(:publisher) }
71
+
72
+ example do
73
+ publisher.should_receive(:publish).with(message)
74
+ DummyCustomPublisher.publish({"bla" => "RAAAAAWWWWW!"}, publisher)
75
+ end
76
+ end
77
+ end
78
+
79
+ end