rabbit_feed 0.3.1
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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/Brewfile +4 -0
- data/DEVELOPING.md +140 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +121 -0
- data/LICENSE.txt +9 -0
- data/README.md +304 -0
- data/Rakefile +30 -0
- data/bin/bundle +3 -0
- data/bin/rabbit_feed +11 -0
- data/example/non_rails_app/.rspec +1 -0
- data/example/non_rails_app/Gemfile +7 -0
- data/example/non_rails_app/Gemfile.lock +56 -0
- data/example/non_rails_app/Rakefile +5 -0
- data/example/non_rails_app/bin/benchmark +63 -0
- data/example/non_rails_app/bin/bundle +3 -0
- data/example/non_rails_app/config/rabbit_feed.yml +8 -0
- data/example/non_rails_app/lib/non_rails_app.rb +32 -0
- data/example/non_rails_app/lib/non_rails_app/event_handler.rb +10 -0
- data/example/non_rails_app/log/.keep +0 -0
- data/example/non_rails_app/spec/lib/non_rails_app/event_handler_spec.rb +14 -0
- data/example/non_rails_app/spec/lib/non_rails_app/event_routing_spec.rb +14 -0
- data/example/non_rails_app/spec/spec_helper.rb +31 -0
- data/example/non_rails_app/tmp/pids/.keep +0 -0
- data/example/rails_app/.gitignore +17 -0
- data/example/rails_app/.node-version +1 -0
- data/example/rails_app/.rspec +1 -0
- data/example/rails_app/Gemfile +36 -0
- data/example/rails_app/Gemfile.lock +173 -0
- data/example/rails_app/README.rdoc +28 -0
- data/example/rails_app/Rakefile +6 -0
- data/example/rails_app/app/assets/images/.keep +0 -0
- data/example/rails_app/app/assets/javascripts/application.js +16 -0
- data/example/rails_app/app/assets/javascripts/beavers.js.coffee +3 -0
- data/example/rails_app/app/assets/stylesheets/application.css +15 -0
- data/example/rails_app/app/assets/stylesheets/beavers.css.scss +3 -0
- data/example/rails_app/app/assets/stylesheets/scaffolds.css.scss +69 -0
- data/example/rails_app/app/controllers/application_controller.rb +5 -0
- data/example/rails_app/app/controllers/beavers_controller.rb +81 -0
- data/example/rails_app/app/controllers/concerns/.keep +0 -0
- data/example/rails_app/app/helpers/application_helper.rb +2 -0
- data/example/rails_app/app/helpers/beavers_helper.rb +2 -0
- data/example/rails_app/app/mailers/.keep +0 -0
- data/example/rails_app/app/models/.keep +0 -0
- data/example/rails_app/app/models/beaver.rb +2 -0
- data/example/rails_app/app/models/concerns/.keep +0 -0
- data/example/rails_app/app/views/beavers/_form.html.erb +21 -0
- data/example/rails_app/app/views/beavers/edit.html.erb +6 -0
- data/example/rails_app/app/views/beavers/index.html.erb +25 -0
- data/example/rails_app/app/views/beavers/index.json.jbuilder +4 -0
- data/example/rails_app/app/views/beavers/new.html.erb +5 -0
- data/example/rails_app/app/views/beavers/show.html.erb +9 -0
- data/example/rails_app/app/views/beavers/show.json.jbuilder +1 -0
- data/example/rails_app/app/views/layouts/application.html.erb +14 -0
- data/example/rails_app/bin/bundle +3 -0
- data/example/rails_app/bin/rails +4 -0
- data/example/rails_app/bin/rake +4 -0
- data/example/rails_app/config.ru +4 -0
- data/example/rails_app/config/application.rb +25 -0
- data/example/rails_app/config/boot.rb +4 -0
- data/example/rails_app/config/database.yml +22 -0
- data/example/rails_app/config/environment.rb +5 -0
- data/example/rails_app/config/environments/development.rb +83 -0
- data/example/rails_app/config/environments/test.rb +39 -0
- data/example/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/example/rails_app/config/initializers/cookies_serializer.rb +3 -0
- data/example/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/example/rails_app/config/initializers/inflections.rb +16 -0
- data/example/rails_app/config/initializers/mime_types.rb +4 -0
- data/example/rails_app/config/initializers/rabbit_feed.rb +43 -0
- data/example/rails_app/config/initializers/session_store.rb +3 -0
- data/example/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/example/rails_app/config/locales/en.yml +23 -0
- data/example/rails_app/config/rabbit_feed.yml +8 -0
- data/example/rails_app/config/routes.rb +58 -0
- data/example/rails_app/config/secrets.yml +18 -0
- data/example/rails_app/config/unicorn.rb +4 -0
- data/example/rails_app/db/migrate/20140424102400_create_beavers.rb +9 -0
- data/example/rails_app/db/schema.rb +22 -0
- data/example/rails_app/db/seeds.rb +7 -0
- data/example/rails_app/lib/assets/.keep +0 -0
- data/example/rails_app/lib/event_handler.rb +7 -0
- data/example/rails_app/lib/tasks/.keep +0 -0
- data/example/rails_app/log/.keep +0 -0
- data/example/rails_app/public/404.html +67 -0
- data/example/rails_app/public/422.html +67 -0
- data/example/rails_app/public/500.html +66 -0
- data/example/rails_app/public/favicon.ico +0 -0
- data/example/rails_app/public/robots.txt +5 -0
- data/example/rails_app/spec/controllers/beavers_controller_spec.rb +32 -0
- data/example/rails_app/spec/event_routing_spec.rb +15 -0
- data/example/rails_app/spec/spec_helper.rb +51 -0
- data/example/rails_app/test/controllers/.keep +0 -0
- data/example/rails_app/test/controllers/beavers_controller_test.rb +49 -0
- data/example/rails_app/test/fixtures/.keep +0 -0
- data/example/rails_app/test/fixtures/beavers.yml +7 -0
- data/example/rails_app/test/helpers/.keep +0 -0
- data/example/rails_app/test/helpers/beavers_helper_test.rb +4 -0
- data/example/rails_app/test/integration/.keep +0 -0
- data/example/rails_app/test/mailers/.keep +0 -0
- data/example/rails_app/test/models/.keep +0 -0
- data/example/rails_app/test/models/beaver_test.rb +7 -0
- data/example/rails_app/test/test_helper.rb +13 -0
- data/example/rails_app/tmp/pids/.keep +0 -0
- data/example/rails_app/vendor/assets/javascripts/.keep +0 -0
- data/example/rails_app/vendor/assets/stylesheets/.keep +0 -0
- data/lib/dsl.rb +9 -0
- data/lib/rabbit_feed.rb +41 -0
- data/lib/rabbit_feed/client.rb +181 -0
- data/lib/rabbit_feed/configuration.rb +50 -0
- data/lib/rabbit_feed/connection_concern.rb +95 -0
- data/lib/rabbit_feed/consumer.rb +14 -0
- data/lib/rabbit_feed/consumer_connection.rb +108 -0
- data/lib/rabbit_feed/event.rb +43 -0
- data/lib/rabbit_feed/event_definitions.rb +98 -0
- data/lib/rabbit_feed/event_routing.rb +90 -0
- data/lib/rabbit_feed/producer.rb +47 -0
- data/lib/rabbit_feed/producer_connection.rb +65 -0
- data/lib/rabbit_feed/testing_support/rspec_matchers/publish_event.rb +90 -0
- data/lib/rabbit_feed/testing_support/testing_helpers.rb +16 -0
- data/lib/rabbit_feed/version.rb +3 -0
- data/logo.png +0 -0
- data/rabbit_feed.gemspec +35 -0
- data/run_benchmark +35 -0
- data/run_example +62 -0
- data/run_recovery_test +26 -0
- data/spec/features/connectivity.feature +13 -0
- data/spec/features/step_definitions/connectivity_steps.rb +96 -0
- data/spec/fixtures/configuration.yml +14 -0
- data/spec/lib/rabbit_feed/client_spec.rb +116 -0
- data/spec/lib/rabbit_feed/configuration_spec.rb +121 -0
- data/spec/lib/rabbit_feed/connection_concern_spec.rb +116 -0
- data/spec/lib/rabbit_feed/consumer_connection_spec.rb +85 -0
- data/spec/lib/rabbit_feed/event_definitions_spec.rb +139 -0
- data/spec/lib/rabbit_feed/event_routing_spec.rb +121 -0
- data/spec/lib/rabbit_feed/event_spec.rb +33 -0
- data/spec/lib/rabbit_feed/producer_connection_spec.rb +72 -0
- data/spec/lib/rabbit_feed/producer_spec.rb +57 -0
- data/spec/lib/rabbit_feed/testing_support/rspec_matchers/publish_event_spec.rb +60 -0
- data/spec/lib/rabbit_feed/testing_support/testing_helper_spec.rb +34 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/support/shared_examples_for_connections.rb +40 -0
- metadata +305 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module RabbitFeed
|
|
4
|
+
describe EventDefinitions do
|
|
5
|
+
before do
|
|
6
|
+
EventDefinitions do
|
|
7
|
+
define_event('customer_purchases_policy', version: '1.0.0') do
|
|
8
|
+
defined_as do
|
|
9
|
+
'The definition of a purchase'
|
|
10
|
+
end
|
|
11
|
+
payload_contains do
|
|
12
|
+
field('customer_id', type: 'string', definition: 'The definition of the customer id')
|
|
13
|
+
field('policy_id', type: 'string', definition: 'The definition of the policy id')
|
|
14
|
+
field('price', type: 'string', definition: 'The definition of the price')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
subject { RabbitFeed::Producer.event_definitions['customer_purchases_policy'] }
|
|
20
|
+
|
|
21
|
+
it { should_not be_nil }
|
|
22
|
+
it { should be_valid }
|
|
23
|
+
its(:name) { should eq 'customer_purchases_policy' }
|
|
24
|
+
|
|
25
|
+
describe EventDefinitions::Event do
|
|
26
|
+
let(:name) { 'event_name' }
|
|
27
|
+
let(:version) { '1.0.0' }
|
|
28
|
+
let(:definition) { 'event definition' }
|
|
29
|
+
subject do
|
|
30
|
+
(EventDefinitions::Event.new name, version).tap do |event|
|
|
31
|
+
event.defined_as do
|
|
32
|
+
definition
|
|
33
|
+
end
|
|
34
|
+
event.payload_contains do
|
|
35
|
+
field 'field', { type: 'string', definition: 'field definition' }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it { should be_valid }
|
|
41
|
+
its(:fields) { should_not be_empty }
|
|
42
|
+
its(:schema) { should be_a Avro::Schema }
|
|
43
|
+
its(:payload){ should =~ [
|
|
44
|
+
{name: 'application', type: 'string', doc: 'The name of the application that created the event'},
|
|
45
|
+
{name: 'host', type: 'string', doc: 'The hostname of the server on which the event was created'},
|
|
46
|
+
{name: 'environment', type: 'string', doc: 'The environment in which the event was created'},
|
|
47
|
+
{name: 'version', type: 'string', doc: 'The version of the event'},
|
|
48
|
+
{name: 'created_at_utc', type: 'string', doc: 'The UTC time that the event was created'},
|
|
49
|
+
{name: 'field', type: 'string', doc: 'field definition'},
|
|
50
|
+
{name: 'name', type: 'string', doc: 'The name of the event'}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
context 'when the name is nil' do
|
|
55
|
+
let(:name) {}
|
|
56
|
+
|
|
57
|
+
it { should_not be_valid }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'when the version is nil' do
|
|
61
|
+
let(:version) {}
|
|
62
|
+
|
|
63
|
+
it { should_not be_valid }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'when the version is malformed' do
|
|
67
|
+
let(:version) { '1.a' }
|
|
68
|
+
|
|
69
|
+
it { should_not be_valid }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context 'when the definition is nil' do
|
|
73
|
+
let(:definition) {}
|
|
74
|
+
|
|
75
|
+
it { should_not be_valid }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context 'when the event is not a valid avro schema' do
|
|
79
|
+
before { subject.fields << (EventDefinitions::Field.new 'junk', 'junk', 'junk') }
|
|
80
|
+
|
|
81
|
+
it { should_not be_valid }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe EventDefinitions::Field do
|
|
86
|
+
let(:name) { 'event_name' }
|
|
87
|
+
let(:type) { 'string' }
|
|
88
|
+
let(:definition) { 'event definition' }
|
|
89
|
+
subject{ EventDefinitions::Field.new name, type, definition }
|
|
90
|
+
|
|
91
|
+
it { should be_valid }
|
|
92
|
+
its(:schema) { should eq({ name: name, type: type, doc: definition }) }
|
|
93
|
+
|
|
94
|
+
context 'when the name is nil' do
|
|
95
|
+
let(:name) {}
|
|
96
|
+
|
|
97
|
+
it 'raises a configuration error' do
|
|
98
|
+
expect{ subject }.to raise_error ConfigurationError
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context 'when the type is nil' do
|
|
103
|
+
let(:type) {}
|
|
104
|
+
|
|
105
|
+
it 'raises a configuration error' do
|
|
106
|
+
expect{ subject }.to raise_error ConfigurationError
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context 'when the definition is nil' do
|
|
111
|
+
let(:definition) {}
|
|
112
|
+
|
|
113
|
+
it 'raises a configuration error' do
|
|
114
|
+
expect{ subject }.to raise_error ConfigurationError
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
context 'testing cumulative definitions' do
|
|
120
|
+
before do
|
|
121
|
+
EventDefinitions do
|
|
122
|
+
define_event('plumber_fixes_tap', version: '1.0.0') do
|
|
123
|
+
defined_as do
|
|
124
|
+
'What a plumber does'
|
|
125
|
+
end
|
|
126
|
+
payload_contains do
|
|
127
|
+
field('plumber_name', type: 'string', definition: 'The name of the plumber')
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'applies event definitions in a cumulative manner' do
|
|
134
|
+
expect(RabbitFeed::Producer.event_definitions['customer_purchases_policy']).to be_present
|
|
135
|
+
expect(RabbitFeed::Producer.event_definitions['plumber_fixes_tap']).to be_present
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module RabbitFeed
|
|
4
|
+
describe EventRouting do
|
|
5
|
+
before do
|
|
6
|
+
EventRouting do
|
|
7
|
+
accept_from('dummy_1') do
|
|
8
|
+
event('event_1') do |event|
|
|
9
|
+
event.payload
|
|
10
|
+
end
|
|
11
|
+
event('event_2') do |event|
|
|
12
|
+
event.payload
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
accept_from('dummy_2') do
|
|
16
|
+
event('event_3') do |event|
|
|
17
|
+
event.payload
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'should create routing keys for the specified routes' do
|
|
24
|
+
|
|
25
|
+
RabbitFeed::Consumer.event_routing.accepted_routes.should =~ %w{
|
|
26
|
+
test.dummy_1.event_1
|
|
27
|
+
test.dummy_1.event_2
|
|
28
|
+
test.dummy_2.event_3
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'routes the event to the correct action' do
|
|
33
|
+
events = [
|
|
34
|
+
double(:event, application: 'dummy_1', name: 'event_1', payload: 1),
|
|
35
|
+
double(:event, application: 'dummy_1', name: 'event_2', payload: 2),
|
|
36
|
+
double(:event, application: 'dummy_2', name: 'event_3', payload: 3),
|
|
37
|
+
]
|
|
38
|
+
events.each do |event|
|
|
39
|
+
(RabbitFeed::Consumer.event_routing.handle_event event).should eq event.payload
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'raises a routing error when the event cannot be routed' do
|
|
44
|
+
events = [
|
|
45
|
+
double(:event, application: 'dummy_9', name: 'event_1', payload: 1),
|
|
46
|
+
double(:event, application: 'dummy_1', name: 'event_9', payload: 3),
|
|
47
|
+
]
|
|
48
|
+
events.each do |event|
|
|
49
|
+
expect{ RabbitFeed::Consumer.event_routing.handle_event event }.to raise_error RoutingError
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe EventRouting::Application do
|
|
54
|
+
let(:name) { 'name' }
|
|
55
|
+
subject{ EventRouting::Application.new name }
|
|
56
|
+
|
|
57
|
+
it { should be_valid }
|
|
58
|
+
|
|
59
|
+
context 'when the name is nil' do
|
|
60
|
+
let(:name) {}
|
|
61
|
+
|
|
62
|
+
it 'raises a configuration error' do
|
|
63
|
+
expect{ subject }.to raise_error ConfigurationError
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe EventRouting::Event do
|
|
69
|
+
let(:name) { 'name' }
|
|
70
|
+
let(:block) { Proc.new{|event|} }
|
|
71
|
+
subject{ EventRouting::Event.new name, block }
|
|
72
|
+
|
|
73
|
+
it { should be_valid }
|
|
74
|
+
|
|
75
|
+
context 'when the name is nil' do
|
|
76
|
+
let(:name) {}
|
|
77
|
+
|
|
78
|
+
it 'raises a configuration error' do
|
|
79
|
+
expect{ subject }.to raise_error ConfigurationError
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context 'when no action is provided' do
|
|
84
|
+
let(:block) {}
|
|
85
|
+
|
|
86
|
+
it 'raises a configuration error' do
|
|
87
|
+
expect{ subject }.to raise_error ConfigurationError
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context 'when the event is not provided to the event action' do
|
|
92
|
+
let(:block) { Proc.new{} }
|
|
93
|
+
|
|
94
|
+
it 'raises a configuration error' do
|
|
95
|
+
expect{ subject }.to raise_error ConfigurationError
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context 'testing cumulative routing definitions' do
|
|
101
|
+
before do
|
|
102
|
+
EventRouting do
|
|
103
|
+
accept_from('dummy_3') do
|
|
104
|
+
event('event_4') do |event|
|
|
105
|
+
event.payload
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'applies routing definitions in a cumulative manner' do
|
|
112
|
+
RabbitFeed::Consumer.event_routing.accepted_routes.should =~ %w{
|
|
113
|
+
test.dummy_1.event_1
|
|
114
|
+
test.dummy_1.event_2
|
|
115
|
+
test.dummy_2.event_3
|
|
116
|
+
test.dummy_3.event_4
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module RabbitFeed
|
|
4
|
+
describe Event do
|
|
5
|
+
let(:schema) { double(:schema) }
|
|
6
|
+
let(:payload) { { 'customer_id' => '123' } }
|
|
7
|
+
|
|
8
|
+
subject { described_class.new schema, payload }
|
|
9
|
+
|
|
10
|
+
describe '.new' do
|
|
11
|
+
|
|
12
|
+
it { should be_valid }
|
|
13
|
+
its(:schema) { should eq schema }
|
|
14
|
+
its(:payload) { should eq({ 'customer_id' => '123' }) }
|
|
15
|
+
|
|
16
|
+
context 'when schema is nil' do
|
|
17
|
+
let(:schema) {}
|
|
18
|
+
|
|
19
|
+
it 'should raise an error' do
|
|
20
|
+
expect{ subject }.to raise_error Error
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'when payload is nil' do
|
|
25
|
+
let(:payload) {}
|
|
26
|
+
|
|
27
|
+
it 'should raise an error' do
|
|
28
|
+
expect{ subject }.to raise_error Error
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module RabbitFeed
|
|
4
|
+
describe ProducerConnection do
|
|
5
|
+
let(:bunny_exchange) { double(:bunny_exchange, on_return: nil, publish: nil) }
|
|
6
|
+
let(:bunny_channel) { double(:bunny_channel, exchange: bunny_exchange, id: 1) }
|
|
7
|
+
let(:bunny_connection) { double(:bunny_connection, start: nil, closed?: false, close: nil, create_channel: bunny_channel) }
|
|
8
|
+
before do
|
|
9
|
+
allow(Bunny).to receive(:new).and_return(bunny_connection)
|
|
10
|
+
end
|
|
11
|
+
subject do
|
|
12
|
+
described_class.new bunny_channel
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe '#new' do
|
|
16
|
+
it 'sets up returned message handling' do
|
|
17
|
+
expect(described_class).to receive(:handle_returned_message).with('return_info', 'content')
|
|
18
|
+
expect(bunny_exchange).to receive(:on_return).and_yield('return_info', 'properties', 'content')
|
|
19
|
+
subject
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'assigns the exchange' do
|
|
23
|
+
expect(subject.exchange).to eq bunny_exchange
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '#handle_returned_message' do
|
|
28
|
+
|
|
29
|
+
context 'when Airbrake is defined' do
|
|
30
|
+
before do
|
|
31
|
+
stub_const('Airbrake', double(:airbrake, configuration: airbrake_configuration))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'and the Airbrake configuration is public' do
|
|
35
|
+
let(:airbrake_configuration) { double(:airbrake_configuration, public?: true) }
|
|
36
|
+
|
|
37
|
+
it 'notifies Airbrake of the return' do
|
|
38
|
+
expect(Airbrake).to receive(:notify_or_ignore).with(an_instance_of ReturnedMessageError)
|
|
39
|
+
described_class.handle_returned_message 1, 2
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe '#connection_options' do
|
|
46
|
+
|
|
47
|
+
it 'does not use a threaded connection' do
|
|
48
|
+
expect(described_class.connection_options).to include(threaded: false)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe '#publish' do
|
|
53
|
+
let(:message) { 'the message' }
|
|
54
|
+
let(:options) { {routing_key: 'routing_key'} }
|
|
55
|
+
|
|
56
|
+
it 'publishes the message as mandatory and persistent' do
|
|
57
|
+
expect(bunny_exchange).to receive(:publish).with(message, { persistent: true, mandatory: true, routing_key: 'routing_key' })
|
|
58
|
+
described_class.publish message, options
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'retries on closed connections' do
|
|
62
|
+
expect(described_class).to receive(:retry_on_closed_connection).and_call_original
|
|
63
|
+
described_class.publish message, options
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'retries on exception' do
|
|
67
|
+
expect(described_class).to receive(:retry_on_exception).twice.and_call_original
|
|
68
|
+
described_class.publish message, options
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module RabbitFeed
|
|
4
|
+
describe Producer do
|
|
5
|
+
describe '.publish' do
|
|
6
|
+
let(:event_name) { 'event_name' }
|
|
7
|
+
before do
|
|
8
|
+
RabbitFeed::Producer.stub!
|
|
9
|
+
EventDefinitions do
|
|
10
|
+
define_event('event_name', version: '1.0.0') do
|
|
11
|
+
defined_as do
|
|
12
|
+
'The definition of the event'
|
|
13
|
+
end
|
|
14
|
+
payload_contains do
|
|
15
|
+
field('field', type: 'string', definition: 'The definition of the field')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
subject{ RabbitFeed::Producer.publish_event event_name, { 'field' => 'value' } }
|
|
21
|
+
|
|
22
|
+
context 'when event definitions are not set' do
|
|
23
|
+
before{ RabbitFeed::Producer.event_definitions = nil }
|
|
24
|
+
|
|
25
|
+
it 'raises an error' do
|
|
26
|
+
expect{ subject }.to raise_error Error
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context 'when no event definition is found' do
|
|
31
|
+
let(:event_name) { 'different event name' }
|
|
32
|
+
|
|
33
|
+
it 'raises an error' do
|
|
34
|
+
expect{ subject }.to raise_error Error
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns the event' do
|
|
39
|
+
expect(subject).to be_a Event
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'serializes the event and provides message metadata' do
|
|
43
|
+
Timecop.freeze do
|
|
44
|
+
expect(ProducerConnection).to receive(:publish).with(
|
|
45
|
+
an_instance_of(String),
|
|
46
|
+
{
|
|
47
|
+
routing_key: 'test.rabbit_feed.event_name',
|
|
48
|
+
type: 'event_name',
|
|
49
|
+
app_id: 'rabbit_feed',
|
|
50
|
+
timestamp: Time.now.utc.to_i,
|
|
51
|
+
})
|
|
52
|
+
subject
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module RabbitFeed
|
|
4
|
+
module TestingSupport
|
|
5
|
+
module RSpecMatchers
|
|
6
|
+
describe PublishEvent do
|
|
7
|
+
let(:event_name) { 'test_event' }
|
|
8
|
+
let(:event_payload) { {'field' => 'value'} }
|
|
9
|
+
before do
|
|
10
|
+
EventDefinitions do
|
|
11
|
+
define_event('test_event', version: '1.0.0') do
|
|
12
|
+
defined_as do
|
|
13
|
+
'The definition of a test event'
|
|
14
|
+
end
|
|
15
|
+
field('field', type: 'string', definition: 'field definition')
|
|
16
|
+
end
|
|
17
|
+
define_event('different name', version: '1.0.0') do
|
|
18
|
+
defined_as do
|
|
19
|
+
'The definition of a test event with a different name'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'when the expectation is met' do
|
|
26
|
+
|
|
27
|
+
it 'validates' do
|
|
28
|
+
expect {
|
|
29
|
+
RabbitFeed::Producer.publish_event event_name, event_payload
|
|
30
|
+
}.to publish_event(event_name, event_payload)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'validates the negation' do
|
|
34
|
+
expect {
|
|
35
|
+
RabbitFeed::Producer.publish_event 'different name', {}
|
|
36
|
+
}.to_not publish_event(event_name, {})
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'traps exceptions' do
|
|
40
|
+
expect {
|
|
41
|
+
raise 'this hurts me more than it hurts you'
|
|
42
|
+
}.to_not publish_event(event_name, {})
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'validates the event name' do
|
|
47
|
+
matcher = described_class.new(event_name, {})
|
|
48
|
+
block = Proc.new { RabbitFeed::Producer.publish_event 'different name', {} }
|
|
49
|
+
(matcher.matches? block).should be_false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'validates the event payload' do
|
|
53
|
+
matcher = described_class.new(event_name, event_payload)
|
|
54
|
+
block = Proc.new { RabbitFeed::Producer.publish_event event_name, {'field' => 'different value'} }
|
|
55
|
+
(matcher.matches? block).should be_false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|