action_subscriber 1.0.3-java

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 (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +5 -0
  5. data/LICENSE +20 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +122 -0
  8. data/Rakefile +8 -0
  9. data/action_subscriber.gemspec +38 -0
  10. data/examples/at_least_once.rb +17 -0
  11. data/examples/at_most_once.rb +15 -0
  12. data/examples/basic_subscriber.rb +30 -0
  13. data/examples/message_acknowledgement.rb +19 -0
  14. data/lib/action_subscriber.rb +93 -0
  15. data/lib/action_subscriber/base.rb +83 -0
  16. data/lib/action_subscriber/bunny/subscriber.rb +57 -0
  17. data/lib/action_subscriber/configuration.rb +68 -0
  18. data/lib/action_subscriber/default_routing.rb +26 -0
  19. data/lib/action_subscriber/dsl.rb +83 -0
  20. data/lib/action_subscriber/march_hare/subscriber.rb +60 -0
  21. data/lib/action_subscriber/middleware.rb +18 -0
  22. data/lib/action_subscriber/middleware/active_record/connection_management.rb +17 -0
  23. data/lib/action_subscriber/middleware/active_record/query_cache.rb +29 -0
  24. data/lib/action_subscriber/middleware/decoder.rb +33 -0
  25. data/lib/action_subscriber/middleware/env.rb +65 -0
  26. data/lib/action_subscriber/middleware/error_handler.rb +16 -0
  27. data/lib/action_subscriber/middleware/router.rb +17 -0
  28. data/lib/action_subscriber/middleware/runner.rb +16 -0
  29. data/lib/action_subscriber/rabbit_connection.rb +40 -0
  30. data/lib/action_subscriber/railtie.rb +13 -0
  31. data/lib/action_subscriber/rspec.rb +91 -0
  32. data/lib/action_subscriber/subscribable.rb +118 -0
  33. data/lib/action_subscriber/threadpool.rb +29 -0
  34. data/lib/action_subscriber/version.rb +3 -0
  35. data/spec/integration/basic_subscriber_spec.rb +42 -0
  36. data/spec/lib/action_subscriber/base_spec.rb +18 -0
  37. data/spec/lib/action_subscriber/configuration_spec.rb +32 -0
  38. data/spec/lib/action_subscriber/dsl_spec.rb +143 -0
  39. data/spec/lib/action_subscriber/middleware/active_record/connection_management_spec.rb +17 -0
  40. data/spec/lib/action_subscriber/middleware/active_record/query_cache_spec.rb +49 -0
  41. data/spec/lib/action_subscriber/middleware/decoder_spec.rb +31 -0
  42. data/spec/lib/action_subscriber/middleware/env_spec.rb +60 -0
  43. data/spec/lib/action_subscriber/middleware/error_handler_spec.rb +35 -0
  44. data/spec/lib/action_subscriber/middleware/router_spec.rb +24 -0
  45. data/spec/lib/action_subscriber/middleware/runner_spec.rb +6 -0
  46. data/spec/lib/action_subscriber/subscribable_spec.rb +128 -0
  47. data/spec/lib/action_subscriber/threadpool_spec.rb +35 -0
  48. data/spec/spec_helper.rb +26 -0
  49. data/spec/support/user_subscriber.rb +6 -0
  50. metadata +255 -0
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::ActionSubscriber::DSL do
4
+ let(:subscriber) { Object.new }
5
+ before { subscriber.extend(::ActionSubscriber::DSL) }
6
+
7
+ describe "acknowledging messages" do
8
+ context "when manual_acknowledgement! is set" do
9
+ before { subscriber.manual_acknowledgement! }
10
+
11
+ it "acknowledges messages" do
12
+ expect(subscriber.acknowledge_messages?).to eq(true)
13
+ end
14
+
15
+ it "returns expected queue subscription options" do
16
+ expect(subscriber.queue_subscription_options).to eq( :manual_ack => true )
17
+ end
18
+
19
+ it "does not acknowledge messages after processing them" do
20
+ expect(subscriber.acknowledge_messages_after_processing?).to eq(false)
21
+ end
22
+
23
+ it "does not acknowledge messages before processing them" do
24
+ expect(subscriber.acknowledge_messages_before_processing?).to eq(false)
25
+ end
26
+ end
27
+
28
+ context "when at_most_once! is set" do
29
+ before { subscriber.at_most_once! }
30
+
31
+ it "acknowledges messages" do
32
+ expect(subscriber.acknowledge_messages?).to eq(true)
33
+ end
34
+
35
+ it "acknowledges messages before processing them" do
36
+ expect(subscriber.acknowledge_messages_before_processing?).to eq(true)
37
+ end
38
+
39
+ it "does not acknowledge messages after processing them" do
40
+ expect(subscriber.acknowledge_messages_after_processing?).to eq(false)
41
+ end
42
+ end
43
+
44
+ context "when at_least_once! is set" do
45
+ before { subscriber.at_least_once! }
46
+
47
+ it "acknowledges messages" do
48
+ expect(subscriber.acknowledge_messages?).to eq(true)
49
+ end
50
+
51
+ it "does not acknowledge messages before processing them" do
52
+ expect(subscriber.acknowledge_messages_before_processing?).to eq(false)
53
+ end
54
+
55
+ it "acknowledges messages after processing them" do
56
+ expect(subscriber.acknowledge_messages_after_processing?).to eq(true)
57
+ end
58
+ end
59
+
60
+ context "when no_acknowledgement! is set" do
61
+ before { subscriber.no_acknowledgement! }
62
+
63
+ it "does not acknowledge messages" do
64
+ expect(subscriber.acknowledge_messages?).to eq(false)
65
+ end
66
+
67
+ it "does not acknowledge messages after processing them" do
68
+ expect(subscriber.acknowledge_messages_after_processing?).to eq(false)
69
+ end
70
+
71
+ it "does not acknowledge messages before processing them" do
72
+ expect(subscriber.acknowledge_messages_before_processing?).to eq(false)
73
+ end
74
+ end
75
+
76
+ context "default" do
77
+ it "does not acknowledge messages" do
78
+ expect(subscriber.acknowledge_messages?).to eq(false)
79
+ end
80
+
81
+ it "does not acknowledge messages after processing them" do
82
+ expect(subscriber.acknowledge_messages_after_processing?).to eq(false)
83
+ end
84
+
85
+ it "does not acknowledge messages before processing them" do
86
+ expect(subscriber.acknowledge_messages_before_processing?).to eq(false)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "exchange_names" do
92
+ context "when exchange names are set" do
93
+ before { subscriber.exchange_names :foo, :bar }
94
+
95
+ it "returns an array of exchange names" do
96
+ expect(subscriber.exchange_names).to eq(["foo", "bar"])
97
+ end
98
+ end
99
+
100
+ context "when exchange names are not set" do
101
+ before { subscriber.instance_variable_set(:@_exchange_names, nil) }
102
+
103
+ it "returns the default exchange" do
104
+ expect(subscriber.exchange_names).to eq(["events"])
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "queue_for" do
110
+ before { subscriber.queue_for(:created, "my_app.app.user.created") }
111
+
112
+ it "adds the method and queue name to the queue names collection" do
113
+ expect(subscriber.queue_names).to eq({:created => "my_app.app.user.created" })
114
+ end
115
+ end
116
+
117
+ describe "remote_application_name" do
118
+ context "when remote appliation name is set" do
119
+ before { subscriber.remote_application_name "app" }
120
+
121
+ it "returns the remote application name" do
122
+ expect(subscriber.remote_application_name).to eq("app")
123
+ end
124
+ end
125
+
126
+ context "when remote application name is not set" do
127
+ before { subscriber.instance_variable_set(:@_remote_application_name, nil) }
128
+
129
+ it "returns nil" do
130
+ expect(subscriber.remote_application_name).to be_nil
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "routing_key_for" do
136
+ before { subscriber.routing_key_for(:created, "app.user.created") }
137
+
138
+ it "adds the method name to the routing key names collection" do
139
+ expect(subscriber.routing_key_names).to eq({:created => "app.user.created"})
140
+ end
141
+ end
142
+
143
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'action_subscriber/middleware/active_record/connection_management'
3
+
4
+ describe ActionSubscriber::Middleware::ActiveRecord::ConnectionManagement do
5
+ include_context 'action subscriber middleware env'
6
+
7
+ before { allow(ActiveRecord::Base).to receive(:clear_active_connections!) }
8
+
9
+ subject { described_class.new(app) }
10
+
11
+ it_behaves_like 'an action subscriber middleware'
12
+
13
+ it "clears active connections" do
14
+ expect(ActiveRecord::Base).to receive(:clear_active_connections!)
15
+ subject.call(env)
16
+ end
17
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'action_subscriber/middleware/active_record/query_cache'
3
+
4
+ describe ActionSubscriber::Middleware::ActiveRecord::QueryCache do
5
+ include_context 'action subscriber middleware env'
6
+
7
+ let(:connection) { double(:connection, :query_cache_enabled => true) }
8
+
9
+ before do
10
+ allow(connection).to receive(:clear_query_cache)
11
+ allow(connection).to receive(:disable_query_cache!)
12
+ allow(connection).to receive(:enable_query_cache!)
13
+
14
+ allow(ActiveRecord::Base).to receive(:connection).and_return(connection)
15
+ allow(ActiveRecord::Base).to receive(:connection_id)
16
+ end
17
+
18
+ subject { described_class.new(app) }
19
+
20
+ it_behaves_like 'an action subscriber middleware'
21
+
22
+ it "enables the query cache" do
23
+ expect(connection).to receive(:enable_query_cache!)
24
+ subject.call(env)
25
+ end
26
+
27
+ it "clears the query cache" do
28
+ expect(connection).to receive(:clear_query_cache)
29
+ subject.call(env)
30
+ end
31
+
32
+ context "when the query cache is already enabled" do
33
+ before { allow(connection).to receive(:query_cache_enabled).and_return(true) }
34
+
35
+ it "does not disable the query cache" do
36
+ expect(connection).to_not receive(:disable_query_cache!)
37
+ subject.call(env)
38
+ end
39
+ end
40
+
41
+ context "when the query cache is not already enabled" do
42
+ before { allow(connection).to receive(:query_cache_enabled).and_return(false) }
43
+
44
+ it "does disable the query cache" do
45
+ expect(connection).to receive(:disable_query_cache!)
46
+ subject.call(env)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActionSubscriber::Middleware::Decoder do
4
+ include_context 'action subscriber middleware env'
5
+
6
+ subject { described_class.new(app) }
7
+
8
+ it_behaves_like 'an action subscriber middleware'
9
+
10
+ let(:env) { ActionSubscriber::Middleware::Env.new(UserSubscriber, encoded_payload, message_properties) }
11
+ let(:encoded_payload) { JSON.generate(payload) }
12
+ let(:payload) { {"ohai" => "GUYZ"} }
13
+
14
+ context "when the content type has an associated decoder" do
15
+ before { message_properties[:content_type] = "application/json"}
16
+
17
+ it "decodes the payload" do
18
+ subject.call(env)
19
+ expect(env.payload).to eq(payload)
20
+ end
21
+ end
22
+
23
+ context "when the content type does not have an associated decoder" do
24
+ before { message_properties[:content_type] = "application/foo"}
25
+
26
+ it "uses the payload as-is" do
27
+ subject.call(env)
28
+ expect(env.payload).to eq(encoded_payload)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActionSubscriber::Middleware::Env do
4
+ let(:channel) { double("channel") }
5
+ let(:encoded_payload) { 'encoded_payload' }
6
+ let(:properties){ {
7
+ :channel => channel,
8
+ :content_type => "application/json",
9
+ :delivery_tag => "XYZ",
10
+ :encoded_payload => encoded_payload,
11
+ :exchange => "events",
12
+ :message_id => "MSG-1234",
13
+ :routing_key => "amigo.user.created",
14
+ } }
15
+ let(:subscriber) { UserSubscriber }
16
+
17
+ subject { described_class.new(subscriber, encoded_payload, properties) }
18
+
19
+ specify { expect(subject.action).to eq("created") }
20
+ specify { expect(subject.content_type).to eq(properties[:content_type]) }
21
+ specify { expect(subject.exchange).to eq(properties[:exchange]) }
22
+ specify { expect(subject.message_id).to eq(properties[:message_id]) }
23
+ specify { expect(subject.routing_key).to eq(properties[:routing_key]) }
24
+
25
+ describe "#acknowledge" do
26
+ it "sends an acknowledgement to rabbitmq" do
27
+ expect(channel).to receive(:ack).with(properties[:delivery_tag], false)
28
+ subject.acknowledge
29
+ end
30
+ end
31
+
32
+ describe "#reject" do
33
+ it "sends an rejection to rabbitmq" do
34
+ expect(channel).to receive(:reject).with(properties[:delivery_tag], true)
35
+ subject.reject
36
+ end
37
+ end
38
+
39
+ describe "#to_hash" do
40
+ it "includes the action" do
41
+ expect(subject.to_hash).to have_key(:action)
42
+ end
43
+
44
+ it "includes the content_type" do
45
+ expect(subject.to_hash).to have_key(:content_type)
46
+ end
47
+
48
+ it "includes the exchange" do
49
+ expect(subject.to_hash).to have_key(:exchange)
50
+ end
51
+
52
+ it "includes the routing_key" do
53
+ expect(subject.to_hash).to have_key(:routing_key)
54
+ end
55
+
56
+ it "includes the payload" do
57
+ expect(subject.to_hash).to have_key(:payload)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'action_subscriber/middleware/error_handler'
3
+
4
+ describe ActionSubscriber::Middleware::ErrorHandler do
5
+ include_context 'action subscriber middleware env'
6
+
7
+ subject { described_class.new(app) }
8
+
9
+ it_behaves_like 'an action subscriber middleware'
10
+
11
+ let(:error) { ::RuntimeError.new("Boom!") }
12
+
13
+ context "when an exception occurs" do
14
+ before { allow(app).to receive(:call).and_raise(error) }
15
+
16
+ it "calls the exception handler" do
17
+ handler = ::ActionSubscriber.configuration.error_handler
18
+ expect(handler).to receive(:call).with(error, env.to_h)
19
+
20
+ subject.call(env)
21
+ end
22
+
23
+ context "when the subscriber was expecting to acknowledge the message" do
24
+ before { allow(env.subscriber).to receive(:acknowledge_messages_after_processing?).and_return(true) }
25
+
26
+ it "calls the exception handler and rejects the message" do
27
+ handler = ::ActionSubscriber.configuration.error_handler
28
+ expect(handler).to receive(:call).with(error, env.to_h)
29
+ expect(env).to receive(:reject).with(no_args)
30
+
31
+ subject.call(env)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActionSubscriber::Middleware::Router do
4
+ include_context 'action subscriber middleware env'
5
+
6
+ subject { described_class.new(app) }
7
+
8
+ it "routes the event to the proper action" do
9
+ allow_any_instance_of(env.subscriber).to receive(env.action)
10
+ subject.call(env)
11
+ end
12
+
13
+ it "acknowledges messages after processing if the subscriber flag is set" do
14
+ allow(env.subscriber).to receive(:acknowledge_messages_after_processing?).and_return(true)
15
+ expect(env).to receive(:acknowledge)
16
+ subject.call(env)
17
+ end
18
+
19
+ it "acknowledges messages before processing if the subscriber flag is set" do
20
+ allow(env.subscriber).to receive(:acknowledge_messages_before_processing?).and_return(true)
21
+ expect(env).to receive(:acknowledge)
22
+ subject.call(env)
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActionSubscriber::Middleware::Runner do
4
+ # TODO: Figure out at way to test this...
5
+ it "adds the router to the top of the stack"
6
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ TestSubscriber = Class.new(ActionSubscriber::Base) do
4
+ def updated
5
+ end
6
+
7
+ def updated_low
8
+ end
9
+ end
10
+ TestSubscriber.remote_application_name :bob
11
+
12
+ describe ActionSubscriber::Subscribable do
13
+ describe "allow_low_priority_methods?" do
14
+ after do
15
+ ::ActionSubscriber.configure { |config| config.allow_low_priority_methods = false }
16
+ end
17
+
18
+ it "when the configuration is false is is false" do
19
+ ::ActionSubscriber.configure { |config| config.allow_low_priority_methods = false }
20
+ expect(TestSubscriber.allow_low_priority_methods?).to eq(false)
21
+ end
22
+
23
+ it "when the configuration is true it is true" do
24
+ ::ActionSubscriber.configure { |config| config.allow_low_priority_methods = true }
25
+ expect(TestSubscriber.allow_low_priority_methods?).to eq(true)
26
+ end
27
+ end
28
+
29
+ describe "filter_low_priority_methods" do
30
+ context "when allow_low_priority_methods? is false" do
31
+ before { allow(TestSubscriber).to receive(:allow_low_priority_methods?).and_return(false) }
32
+
33
+ it "removes low priority methods" do
34
+ filtered_methods = TestSubscriber.filter_low_priority_methods([:updated, :updated_low])
35
+ expect(filtered_methods).to eq([:updated])
36
+ end
37
+ end
38
+
39
+ context "when allow_low_priority_methods? is true" do
40
+ before { allow(TestSubscriber).to receive(:allow_low_priority_methods?).and_return(true) }
41
+
42
+ it "allows low priority methods" do
43
+ filtered_methods = TestSubscriber.filter_low_priority_methods([:updated, :updated_low])
44
+ expect(filtered_methods).to eq([:updated, :updated_low])
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "generate_queue_name" do
50
+ it "returns a queue name" do
51
+ queue_name = TestSubscriber.generate_queue_name(:created)
52
+ expect(queue_name).to eq("alice.bob.test.created")
53
+ end
54
+ end
55
+
56
+ describe "generate_routing_key_name" do
57
+ it "returns a routing key name" do
58
+ routing_key_name = TestSubscriber.generate_routing_key_name(:created)
59
+ expect(routing_key_name).to eq("bob.test.created")
60
+ end
61
+ end
62
+
63
+ describe "local_application_name" do
64
+ it "returns the local application name" do
65
+ expect(TestSubscriber.local_application_name).to eq("alice")
66
+ end
67
+ end
68
+
69
+ describe "queue_name_for_method" do
70
+ before { TestSubscriber.instance_variable_set(:@_queue_names, nil) }
71
+
72
+ context "when the queue is already registered" do
73
+ it "returns the registered queue" do
74
+ TestSubscriber.queue_for(:created, "foo.bar")
75
+ queue_name = TestSubscriber.queue_name_for_method(:created)
76
+ expect(queue_name).to eq("foo.bar")
77
+ end
78
+ end
79
+
80
+ context "when the queue is not registered" do
81
+ it "generates a queue name" do
82
+ queue_name = TestSubscriber.queue_name_for_method(:created)
83
+ expect(queue_name).to eq("alice.bob.test.created")
84
+ end
85
+
86
+ it "registers the generated queue" do
87
+ queue_name = TestSubscriber.queue_name_for_method(:created)
88
+ expect(TestSubscriber.queue_names).to eq({:created =>"alice.bob.test.created"})
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "resource_name" do
94
+ it "returns the resource name" do
95
+ expect(TestSubscriber.resource_name).to eq("test")
96
+ end
97
+ end
98
+
99
+ describe "routing_key_name_for_method" do
100
+ before { TestSubscriber.instance_variable_set(:@_routing_key_names, nil) }
101
+
102
+ context "when the routing key is already registered" do
103
+ it "returns the registered routing key" do
104
+ TestSubscriber.routing_key_for(:created, "bar.foo")
105
+ routing_key_name = TestSubscriber.routing_key_name_for_method(:created)
106
+ expect(routing_key_name).to eq("bar.foo")
107
+ end
108
+ end
109
+
110
+ context "when the routing key is not registered" do
111
+ it "generates a routing key name" do
112
+ routing_key_name = TestSubscriber.routing_key_name_for_method(:created)
113
+ expect(routing_key_name).to eq("bob.test.created")
114
+ end
115
+
116
+ it "registers the generated routing key" do
117
+ routing_key_name = TestSubscriber.routing_key_name_for_method(:created)
118
+ expect(TestSubscriber.routing_key_names).to eq({:created => "bob.test.created"})
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "subscribable methods" do
124
+ it "returns the subscribable methods" do
125
+ expect(TestSubscriber.subscribable_methods).to eq([:updated])
126
+ end
127
+ end
128
+ end