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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/LICENSE +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +122 -0
- data/Rakefile +8 -0
- data/action_subscriber.gemspec +38 -0
- data/examples/at_least_once.rb +17 -0
- data/examples/at_most_once.rb +15 -0
- data/examples/basic_subscriber.rb +30 -0
- data/examples/message_acknowledgement.rb +19 -0
- data/lib/action_subscriber.rb +93 -0
- data/lib/action_subscriber/base.rb +83 -0
- data/lib/action_subscriber/bunny/subscriber.rb +57 -0
- data/lib/action_subscriber/configuration.rb +68 -0
- data/lib/action_subscriber/default_routing.rb +26 -0
- data/lib/action_subscriber/dsl.rb +83 -0
- data/lib/action_subscriber/march_hare/subscriber.rb +60 -0
- data/lib/action_subscriber/middleware.rb +18 -0
- data/lib/action_subscriber/middleware/active_record/connection_management.rb +17 -0
- data/lib/action_subscriber/middleware/active_record/query_cache.rb +29 -0
- data/lib/action_subscriber/middleware/decoder.rb +33 -0
- data/lib/action_subscriber/middleware/env.rb +65 -0
- data/lib/action_subscriber/middleware/error_handler.rb +16 -0
- data/lib/action_subscriber/middleware/router.rb +17 -0
- data/lib/action_subscriber/middleware/runner.rb +16 -0
- data/lib/action_subscriber/rabbit_connection.rb +40 -0
- data/lib/action_subscriber/railtie.rb +13 -0
- data/lib/action_subscriber/rspec.rb +91 -0
- data/lib/action_subscriber/subscribable.rb +118 -0
- data/lib/action_subscriber/threadpool.rb +29 -0
- data/lib/action_subscriber/version.rb +3 -0
- data/spec/integration/basic_subscriber_spec.rb +42 -0
- data/spec/lib/action_subscriber/base_spec.rb +18 -0
- data/spec/lib/action_subscriber/configuration_spec.rb +32 -0
- data/spec/lib/action_subscriber/dsl_spec.rb +143 -0
- data/spec/lib/action_subscriber/middleware/active_record/connection_management_spec.rb +17 -0
- data/spec/lib/action_subscriber/middleware/active_record/query_cache_spec.rb +49 -0
- data/spec/lib/action_subscriber/middleware/decoder_spec.rb +31 -0
- data/spec/lib/action_subscriber/middleware/env_spec.rb +60 -0
- data/spec/lib/action_subscriber/middleware/error_handler_spec.rb +35 -0
- data/spec/lib/action_subscriber/middleware/router_spec.rb +24 -0
- data/spec/lib/action_subscriber/middleware/runner_spec.rb +6 -0
- data/spec/lib/action_subscriber/subscribable_spec.rb +128 -0
- data/spec/lib/action_subscriber/threadpool_spec.rb +35 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/user_subscriber.rb +6 -0
- metadata +255 -0
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module ActionSubscriber
         | 
| 2 | 
            +
              module Middleware
         | 
| 3 | 
            +
                class ErrorHandler
         | 
| 4 | 
            +
                  def initialize(app)
         | 
| 5 | 
            +
                    @app = app
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def call(env)
         | 
| 9 | 
            +
                    @app.call(env)
         | 
| 10 | 
            +
                  rescue => error
         | 
| 11 | 
            +
                    env.reject if env.subscriber.acknowledge_messages_after_processing?
         | 
| 12 | 
            +
                    ::ActionSubscriber.configuration.error_handler.call(error, env.to_h)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module ActionSubscriber
         | 
| 2 | 
            +
              module Middleware
         | 
| 3 | 
            +
                class Router
         | 
| 4 | 
            +
                  def initialize(app)
         | 
| 5 | 
            +
                    @app = app
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def call(env)
         | 
| 9 | 
            +
                    subscriber = env.subscriber.new(env)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    env.acknowledge if env.subscriber.acknowledge_messages_before_processing?
         | 
| 12 | 
            +
                    subscriber.public_send(env.action)
         | 
| 13 | 
            +
                    env.acknowledge if env.subscriber.acknowledge_messages_after_processing?
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            require 'middleware/runner'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ActionSubscriber
         | 
| 4 | 
            +
              module Middleware
         | 
| 5 | 
            +
                class Runner < ::Middleware::Runner
         | 
| 6 | 
            +
                  # Override the default middleware runner so we can ensure that the
         | 
| 7 | 
            +
                  # router is the last thing called in the stack.
         | 
| 8 | 
            +
                  #
         | 
| 9 | 
            +
                  def initialize(stack)
         | 
| 10 | 
            +
                    stack << ::ActionSubscriber::Middleware::Router
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    super(stack)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'thread'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ActionSubscriber
         | 
| 4 | 
            +
              module RabbitConnection
         | 
| 5 | 
            +
                CONNECTION_MUTEX = ::Mutex.new
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.connect!
         | 
| 8 | 
            +
                  CONNECTION_MUTEX.synchronize do
         | 
| 9 | 
            +
                    return @connection if @connection
         | 
| 10 | 
            +
                    if ::RUBY_PLATFORM == "java"
         | 
| 11 | 
            +
                      @connection = ::MarchHare.connect(connection_options)
         | 
| 12 | 
            +
                    else
         | 
| 13 | 
            +
                      @connection = ::Bunny.new(connection_options)
         | 
| 14 | 
            +
                      @connection.start
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                    @connection
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def self.connected?
         | 
| 21 | 
            +
                  connection && connection.connected?
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def self.connection
         | 
| 25 | 
            +
                  connect!
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def self.connection_options
         | 
| 29 | 
            +
                  {
         | 
| 30 | 
            +
                    :heartbeat                     => ::ActionSubscriber.configuration.heartbeat,
         | 
| 31 | 
            +
                    :hosts                         => ::ActionSubscriber.configuration.hosts,
         | 
| 32 | 
            +
                    :port                          => ::ActionSubscriber.configuration.port,
         | 
| 33 | 
            +
                    :continuation_timeout          => ::ActionSubscriber.configuration.timeout * 1_000.0, #convert sec to ms
         | 
| 34 | 
            +
                    :automatically_recover         => true,
         | 
| 35 | 
            +
                    :network_recovery_interval     => 1,
         | 
| 36 | 
            +
                    :recover_from_connection_close => true,
         | 
| 37 | 
            +
                  }
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            module ActionSubscriber
         | 
| 2 | 
            +
              class Railtie < ::Rails::Railtie
         | 
| 3 | 
            +
                config.action_subscriber = ::ActionSubscriber.config
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                ::ActiveSupport.on_load(:active_record) do
         | 
| 6 | 
            +
                  require "action_subscriber/middleware/active_record/connection_management"
         | 
| 7 | 
            +
                  require "action_subscriber/middleware/active_record/query_cache"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  ::ActionSubscriber.config.middleware.use ::ActionSubscriber::Middleware::ActiveRecord::ConnectionManagement
         | 
| 10 | 
            +
                  ::ActionSubscriber.config.middleware.use ::ActionSubscriber::Middleware::ActiveRecord::QueryCache
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            require 'rspec'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ActionSubscriber
         | 
| 4 | 
            +
              module RSpec
         | 
| 5 | 
            +
                class FakeChannel # A class that quacks like a RabbitMQ Channel
         | 
| 6 | 
            +
                  def ack(delivery_tag, acknowledge_multiple)
         | 
| 7 | 
            +
                    true
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def reject(delivery_tag, requeue_message)
         | 
| 11 | 
            +
                    true
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                PROPERTIES_DEFAULTS = {
         | 
| 16 | 
            +
                  :channel => FakeChannel.new,
         | 
| 17 | 
            +
                  :content_type => "text/plain",
         | 
| 18 | 
            +
                  :delivery_tag => "XYZ",
         | 
| 19 | 
            +
                  :exchange => "events",
         | 
| 20 | 
            +
                  :message_id => "MSG-123",
         | 
| 21 | 
            +
                  :routing_key => "amigo.user.created",
         | 
| 22 | 
            +
                }.freeze
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                # Create a new subscriber instance. Available options are:
         | 
| 25 | 
            +
                #
         | 
| 26 | 
            +
                #  * :acknowledger - the object that should receive ack/reject calls for this message (only useful for testing manual acknowledgment)
         | 
| 27 | 
            +
                #  * :content_type - defaults to text/plain
         | 
| 28 | 
            +
                #  * :encoded_payload - the encoded payload object to pass into the instance.
         | 
| 29 | 
            +
                #  * :exchange - defaults to "events"
         | 
| 30 | 
            +
                #  * :message_id - defaults to "MSG-123"
         | 
| 31 | 
            +
                #  * :payload - the payload object to pass to the instance.
         | 
| 32 | 
            +
                #  * :routing_key - defaults to amigo.user.created
         | 
| 33 | 
            +
                #  * :subscriber - the class constant corresponding to the subscriber. `described_class` is the default.
         | 
| 34 | 
            +
                #
         | 
| 35 | 
            +
                # Example
         | 
| 36 | 
            +
                #
         | 
| 37 | 
            +
                #   describe UserSubscriber do
         | 
| 38 | 
            +
                #     subject { mock_subscriber(:payload => proto) }
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                #     it 'logs the user create event' do
         | 
| 41 | 
            +
                #       SomeLogger.should_receive(:log)
         | 
| 42 | 
            +
                #       subject.created
         | 
| 43 | 
            +
                #     end
         | 
| 44 | 
            +
                #   end
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                def mock_subscriber(opts = {})
         | 
| 47 | 
            +
                  encoded_payload = opts.fetch(:encoded_payload) { double('encoded payload').as_null_object }
         | 
| 48 | 
            +
                  subscriber_class = opts.fetch(:subscriber) { described_class }
         | 
| 49 | 
            +
                  properties = PROPERTIES_DEFAULTS.merge(opts.slice(:channel,
         | 
| 50 | 
            +
                                                                    :content_type,
         | 
| 51 | 
            +
                                                                    :delivery_tag,
         | 
| 52 | 
            +
                                                                    :exchange,
         | 
| 53 | 
            +
                                                                    :message_id,
         | 
| 54 | 
            +
                                                                    :routing_key))
         | 
| 55 | 
            +
             | 
| 56 | 
            +
             | 
| 57 | 
            +
                  env = ActionSubscriber::Middleware::Env.new(subscriber_class, encoded_payload, properties)
         | 
| 58 | 
            +
                  env.payload = opts.fetch(:payload) { double('payload').as_null_object }
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  return subscriber_class.new(env)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            ::RSpec.configure do |config|
         | 
| 66 | 
            +
              config.include ActionSubscriber::RSpec
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              shared_context 'action subscriber middleware env' do
         | 
| 69 | 
            +
                let(:app) { Proc.new { |inner_env| inner_env } }
         | 
| 70 | 
            +
                let(:env) { ActionSubscriber::Middleware::Env.new(UserSubscriber, 'encoded payload', message_properties) }
         | 
| 71 | 
            +
                let(:message_properties) {{
         | 
| 72 | 
            +
                  :channel => ::ActionSubscriber::RSpec::FakeChannel.new,
         | 
| 73 | 
            +
                  :content_type => "text/plain",
         | 
| 74 | 
            +
                  :delivery_tag => "XYZ",
         | 
| 75 | 
            +
                  :exchange => "events",
         | 
| 76 | 
            +
                  :message_id => "MSG-123",
         | 
| 77 | 
            +
                  :routing_key => "amigo.user.created",
         | 
| 78 | 
            +
                }}
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
              shared_examples_for 'an action subscriber middleware' do
         | 
| 82 | 
            +
                include_context 'action subscriber middleware env'
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                subject { described_class.new(app) }
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                it "calls the stack" do
         | 
| 87 | 
            +
                  expect(app).to receive(:call).with(env)
         | 
| 88 | 
            +
                  subject.call(env)
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
            end
         | 
| @@ -0,0 +1,118 @@ | |
| 1 | 
            +
            module ActionSubscriber
         | 
| 2 | 
            +
              module Subscribable
         | 
| 3 | 
            +
                def allow_low_priority_methods?
         | 
| 4 | 
            +
                  !!(::ActionSubscriber.configuration.allow_low_priority_methods)
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def filter_low_priority_methods(methods)
         | 
| 8 | 
            +
                  if allow_low_priority_methods?
         | 
| 9 | 
            +
                    return methods
         | 
| 10 | 
            +
                  else
         | 
| 11 | 
            +
                    return methods - methods.grep(/_low/)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def generate_queue_name(method_name)
         | 
| 16 | 
            +
                  [
         | 
| 17 | 
            +
                    local_application_name,
         | 
| 18 | 
            +
                    remote_application_name,
         | 
| 19 | 
            +
                    resource_name,
         | 
| 20 | 
            +
                    method_name
         | 
| 21 | 
            +
                  ].compact.join('.')
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def generate_routing_key_name(method_name)
         | 
| 25 | 
            +
                  [
         | 
| 26 | 
            +
                    remote_application_name,
         | 
| 27 | 
            +
                    resource_name,
         | 
| 28 | 
            +
                    method_name
         | 
| 29 | 
            +
                  ].compact.join('.')
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def local_application_name(reload = false)
         | 
| 33 | 
            +
                  if reload || @_local_application_name.nil?
         | 
| 34 | 
            +
                    @_local_application_name = case
         | 
| 35 | 
            +
                                          when ENV['APP_NAME'] then
         | 
| 36 | 
            +
                                            ENV['APP_NAME'].to_s.dup
         | 
| 37 | 
            +
                                          when defined?(::Rails) then
         | 
| 38 | 
            +
                                            ::Rails.application.class.parent_name.dup
         | 
| 39 | 
            +
                                          else
         | 
| 40 | 
            +
                                            raise "Define an application name (ENV['APP_NAME'])"
         | 
| 41 | 
            +
                                          end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    @_local_application_name.downcase!
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  @_local_application_name
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def inspect
         | 
| 50 | 
            +
                  inspection_string = "#{self.name}\n"
         | 
| 51 | 
            +
                  exchange_names.each do |exchange_name|
         | 
| 52 | 
            +
                    inspection_string << "  -- exchange: #{exchange_name}\n"
         | 
| 53 | 
            +
                    subscribable_methods.each do |method|
         | 
| 54 | 
            +
                      inspection_string << "    -- method: #{method}\n"
         | 
| 55 | 
            +
                      inspection_string << "      -- queue:       #{queue_names[method]}\n"
         | 
| 56 | 
            +
                      inspection_string << "      -- routing_key: #{routing_key_names[method]}\n"
         | 
| 57 | 
            +
                      inspection_string << "\n"
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                  return inspection_string
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                # Build the `queue` for a given method.
         | 
| 64 | 
            +
                #
         | 
| 65 | 
            +
                # If the queue name is not set, the queue name is
         | 
| 66 | 
            +
                #   "local.remote.resoure.action"
         | 
| 67 | 
            +
                #
         | 
| 68 | 
            +
                # Example
         | 
| 69 | 
            +
                #   "bob.alice.user.created"
         | 
| 70 | 
            +
                #
         | 
| 71 | 
            +
                def queue_name_for_method(method_name)
         | 
| 72 | 
            +
                  return queue_names[method_name] if queue_names[method_name]
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  queue_name = generate_queue_name(method_name)
         | 
| 75 | 
            +
                  queue_for(method_name, queue_name)
         | 
| 76 | 
            +
                  return queue_name
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                # The name of the resource respresented by this subscriber.
         | 
| 80 | 
            +
                # If the class name were `UserSubscriber` the resource_name would be `user`.
         | 
| 81 | 
            +
                #
         | 
| 82 | 
            +
                def resource_name
         | 
| 83 | 
            +
                  @_resource_name ||= self.name.underscore.gsub(/_subscriber/, '').to_s
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                # Build the `routing_key` for a given method.
         | 
| 87 | 
            +
                #
         | 
| 88 | 
            +
                # If the routing_key name is not set, the routing_key name is
         | 
| 89 | 
            +
                #   "remote.resoure.action"
         | 
| 90 | 
            +
                #
         | 
| 91 | 
            +
                # Example
         | 
| 92 | 
            +
                #   "amigo.user.created"
         | 
| 93 | 
            +
                #
         | 
| 94 | 
            +
                def routing_key_name_for_method(method_name)
         | 
| 95 | 
            +
                  return routing_key_names[method_name] if routing_key_names[method_name]
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  routing_key_name = generate_routing_key_name(method_name)
         | 
| 98 | 
            +
                  routing_key_for(method_name, routing_key_name)
         | 
| 99 | 
            +
                  return routing_key_name
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                def subscribable_methods
         | 
| 103 | 
            +
                  return @_subscribable_methods if @_subscribable_methods
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  methods = instance_methods
         | 
| 106 | 
            +
                  methods -= ::Object.instance_methods
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  self.included_modules.each do |mod|
         | 
| 109 | 
            +
                    methods -= mod.instance_methods
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  @_subscribable_methods = filter_low_priority_methods(methods)
         | 
| 113 | 
            +
                  @_subscribable_methods.sort!
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  return @_subscribable_methods
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
              end
         | 
| 118 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module ActionSubscriber
         | 
| 2 | 
            +
              class Threadpool
         | 
| 3 | 
            +
                ##
         | 
| 4 | 
            +
                # Class Methods
         | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                def self.busy?
         | 
| 7 | 
            +
                  (pool.pool_size == pool.busy_size)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def self.perform_async(*args)
         | 
| 11 | 
            +
                  self.pool.async.perform(*args)
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def self.pool
         | 
| 15 | 
            +
                  @pool ||= ::Lifeguard::InfiniteThreadpool.new(
         | 
| 16 | 
            +
                    :pool_size => ::ActionSubscriber.config.threadpool_size
         | 
| 17 | 
            +
                  )
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def self.ready?
         | 
| 21 | 
            +
                  !busy?
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def self.ready_size
         | 
| 25 | 
            +
                  ready_size = pool.pool_size - pool.busy_size
         | 
| 26 | 
            +
                  return ready_size >= 0 ? ready_size : 0
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class BasicPushSubscriber < ActionSubscriber::Base
         | 
| 4 | 
            +
              BOOKED_MESSAGES = []
         | 
| 5 | 
            +
              CANCELLED_MESSAGES = []
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              publisher :greg
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              # queue => alice.greg.basic_push.booked
         | 
| 10 | 
            +
              # routing_key => greg.basic_push.booked
         | 
| 11 | 
            +
              def booked
         | 
| 12 | 
            +
                BOOKED_MESSAGES << payload
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              queue_for :cancelled, "basic.cancelled"
         | 
| 16 | 
            +
              routing_key_for :cancelled, "basic.cancelled"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def cancelled
         | 
| 19 | 
            +
                CANCELLED_MESSAGES << payload
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            describe "A Basic Subscriber using Push API", :integration => true do
         | 
| 24 | 
            +
              let(:connection) { subscriber.connection }
         | 
| 25 | 
            +
              let(:subscriber) { BasicPushSubscriber }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              it "messages are routed to the right place" do
         | 
| 28 | 
            +
                ::ActionSubscriber.start_queues
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                channel = connection.create_channel
         | 
| 31 | 
            +
                exchange = channel.topic("events")
         | 
| 32 | 
            +
                exchange.publish("Ohai Booked", :routing_key => "greg.basic_push.booked")
         | 
| 33 | 
            +
                exchange.publish("Ohai Cancelled", :routing_key => "basic.cancelled")
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                ::ActionSubscriber.auto_pop!
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                expect(subscriber::BOOKED_MESSAGES).to eq(["Ohai Booked"])
         | 
| 38 | 
            +
                expect(subscriber::CANCELLED_MESSAGES).to eq(["Ohai Cancelled"])
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                connection.close
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestObject < ActionSubscriber::Base
         | 
| 4 | 
            +
              exchange :events
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def created
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            describe ActionSubscriber::Base do
         | 
| 11 | 
            +
              describe "inherited" do
         | 
| 12 | 
            +
                context "when a class has inherited from action subscriber base" do
         | 
| 13 | 
            +
                  it "adds the class to the intherited classes collection" do
         | 
| 14 | 
            +
                    expect(described_class.inherited_classes).to include(TestObject)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe ::ActionSubscriber::Configuration do
         | 
| 4 | 
            +
              describe "default values" do
         | 
| 5 | 
            +
                specify { expect(subject.allow_low_priority_methods).to eq(false) }
         | 
| 6 | 
            +
                specify { expect(subject.default_exchange).to eq("events") }
         | 
| 7 | 
            +
                specify { expect(subject.host).to eq("localhost") }
         | 
| 8 | 
            +
                specify { expect(subject.port).to eq(5672) }
         | 
| 9 | 
            +
                specify { expect(subject.threadpool_size).to eq(8) }
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              describe "add_decoder" do
         | 
| 13 | 
            +
                it "add the decoder to the registry" do
         | 
| 14 | 
            +
                  subject.add_decoder({"application/protobuf" => lambda { |payload| "foo"} })
         | 
| 15 | 
            +
                  expect(subject.decoder).to include("application/protobuf")
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                it 'raises an error when decoder does not have arity of 1' do
         | 
| 19 | 
            +
                  expect {
         | 
| 20 | 
            +
                    subject.add_decoder("foo" => lambda { |*args|  })
         | 
| 21 | 
            +
                  }.to raise_error(/The foo decoder was given with arity of -1/)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  expect {
         | 
| 24 | 
            +
                    subject.add_decoder("foo" => lambda {  })
         | 
| 25 | 
            +
                  }.to raise_error(/The foo decoder was given with arity of 0/)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  expect {
         | 
| 28 | 
            +
                    subject.add_decoder("foo" => lambda { |a,b| })
         | 
| 29 | 
            +
                  }.to raise_error(/The foo decoder was given with arity of 2/)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         |