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.
- checksums.yaml +4 -4
- data/.gitignore +20 -0
- data/.hound.yml +2 -0
- data/.rubocop.yml +50 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +363 -0
- data/Gemfile +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +32 -3
- data/Rakefile +38 -0
- data/dispatch-rider.gemspec +46 -0
- data/lib/dispatch-rider/notification_services/aws_sns.rb +9 -0
- data/lib/dispatch-rider/version.rb +1 -1
- data/spec/fixtures/handlers/another_test_handler.rb +2 -0
- data/spec/fixtures/handlers/test_handler.rb +2 -0
- data/spec/lib/dispatch-rider/airbrake_error_handler_spec.rb +16 -0
- data/spec/lib/dispatch-rider/callbacks/access_spec.rb +62 -0
- data/spec/lib/dispatch-rider/callbacks/storage_spec.rb +43 -0
- data/spec/lib/dispatch-rider/configuration_spec.rb +74 -0
- data/spec/lib/dispatch-rider/default_error_handler_spec.rb +14 -0
- data/spec/lib/dispatch-rider/demultiplexer_spec.rb +117 -0
- data/spec/lib/dispatch-rider/dispatcher_spec.rb +69 -0
- data/spec/lib/dispatch-rider/handlers/base_spec.rb +81 -0
- data/spec/lib/dispatch-rider/handlers/inheritance_tracking_spec.rb +27 -0
- data/spec/lib/dispatch-rider/message_spec.rb +59 -0
- data/spec/lib/dispatch-rider/notification_services/aws_sns_spec.rb +28 -0
- data/spec/lib/dispatch-rider/notification_services/base_spec.rb +65 -0
- data/spec/lib/dispatch-rider/notification_services/file_system/channel_spec.rb +28 -0
- data/spec/lib/dispatch-rider/notification_services/file_system/notifier_spec.rb +14 -0
- data/spec/lib/dispatch-rider/notification_services/file_system_spec.rb +23 -0
- data/spec/lib/dispatch-rider/notification_services_spec.rb +4 -0
- data/spec/lib/dispatch-rider/publisher/base_spec.rb +79 -0
- data/spec/lib/dispatch-rider/publisher/configuration/destination_spec.rb +100 -0
- data/spec/lib/dispatch-rider/publisher/configuration/notification_service_spec.rb +53 -0
- data/spec/lib/dispatch-rider/publisher/configuration_reader_spec.rb +129 -0
- data/spec/lib/dispatch-rider/publisher/configuration_spec.rb +149 -0
- data/spec/lib/dispatch-rider/publisher/configuration_support_spec.rb +89 -0
- data/spec/lib/dispatch-rider/publisher_spec.rb +123 -0
- data/spec/lib/dispatch-rider/queue_services/aws_sqs_spec.rb +193 -0
- data/spec/lib/dispatch-rider/queue_services/base_spec.rb +147 -0
- data/spec/lib/dispatch-rider/queue_services/file_system_spec.rb +88 -0
- data/spec/lib/dispatch-rider/queue_services/received_message_spec.rb +23 -0
- data/spec/lib/dispatch-rider/queue_services/simple_spec.rb +63 -0
- data/spec/lib/dispatch-rider/queue_services_spec.rb +6 -0
- data/spec/lib/dispatch-rider/registrars/base_spec.rb +68 -0
- data/spec/lib/dispatch-rider/registrars/file_system_channel_spec.rb +12 -0
- data/spec/lib/dispatch-rider/registrars/handler_spec.rb +16 -0
- data/spec/lib/dispatch-rider/registrars/notification_service_spec.rb +13 -0
- data/spec/lib/dispatch-rider/registrars/publishing_destination_spec.rb +11 -0
- data/spec/lib/dispatch-rider/registrars/queue_service_spec.rb +13 -0
- data/spec/lib/dispatch-rider/registrars/sns_channel_spec.rb +14 -0
- data/spec/lib/dispatch-rider/registrars_spec.rb +4 -0
- data/spec/lib/dispatch-rider/runner_spec.rb +25 -0
- data/spec/lib/dispatch-rider/subscriber_spec.rb +140 -0
- data/spec/lib/dispatch-rider_spec.rb +27 -0
- data/spec/spec_helper.rb +21 -0
- 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,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
|