msgr 1.1.0.1.b306 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +8 -0
  3. data/.github/workflows/build.yml +52 -0
  4. data/.github/workflows/lint.yml +20 -0
  5. data/.rubocop.yml +9 -48
  6. data/.travis.yml +21 -35
  7. data/Appraisals +18 -0
  8. data/CHANGELOG.md +34 -11
  9. data/Gemfile +9 -15
  10. data/README.md +8 -20
  11. data/Rakefile +10 -6
  12. data/bin/msgr +1 -0
  13. data/gemfiles/rails_5.2.gemfile +14 -0
  14. data/gemfiles/rails_6.0.gemfile +14 -0
  15. data/gemfiles/rails_6.1.gemfile +14 -0
  16. data/gemfiles/rails_master.gemfile +14 -0
  17. data/lib/msgr/binding.rb +13 -8
  18. data/lib/msgr/channel.rb +5 -3
  19. data/lib/msgr/cli.rb +18 -11
  20. data/lib/msgr/client.rb +25 -23
  21. data/lib/msgr/connection.rb +13 -1
  22. data/lib/msgr/consumer.rb +2 -3
  23. data/lib/msgr/dispatcher.rb +7 -9
  24. data/lib/msgr/logging.rb +2 -0
  25. data/lib/msgr/message.rb +1 -2
  26. data/lib/msgr/railtie.rb +14 -75
  27. data/lib/msgr/route.rb +1 -4
  28. data/lib/msgr/routes.rb +2 -0
  29. data/lib/msgr/tasks/msgr/drain.rake +11 -0
  30. data/lib/msgr/test_pool.rb +1 -3
  31. data/lib/msgr/version.rb +2 -2
  32. data/lib/msgr.rb +1 -0
  33. data/msgr.gemspec +2 -6
  34. data/scripts/simple_test.rb +2 -3
  35. data/spec/fixtures/{msgr-routes-test-1.rb → msgr_routes_test_1.rb} +0 -0
  36. data/spec/fixtures/msgr_routes_test_drain.rb +5 -0
  37. data/spec/integration/dummy/Rakefile +1 -1
  38. data/spec/{msgr/support/.keep → integration/dummy/app/assets/config/manifest.js} +0 -0
  39. data/spec/integration/dummy/bin/bundle +1 -1
  40. data/spec/integration/dummy/bin/rails +1 -1
  41. data/spec/integration/dummy/config/application.rb +1 -1
  42. data/spec/integration/dummy/config/boot.rb +2 -2
  43. data/spec/integration/dummy/config/environment.rb +1 -1
  44. data/spec/integration/dummy/config/rabbitmq.yml +1 -1
  45. data/spec/integration/msgr/dispatcher_spec.rb +28 -12
  46. data/spec/integration/msgr/railtie_spec.rb +10 -120
  47. data/spec/integration/spec_helper.rb +2 -3
  48. data/spec/integration/{msgr_spec.rb → test_controller_spec.rb} +1 -1
  49. data/spec/unit/msgr/client_spec.rb +83 -0
  50. data/spec/{msgr → unit}/msgr/connection_spec.rb +1 -1
  51. data/spec/{msgr → unit}/msgr/consumer_spec.rb +0 -0
  52. data/spec/unit/msgr/dispatcher_spec.rb +45 -0
  53. data/spec/{msgr → unit}/msgr/route_spec.rb +15 -14
  54. data/spec/{msgr → unit}/msgr/routes_spec.rb +32 -35
  55. data/spec/{msgr → unit}/msgr_spec.rb +25 -16
  56. data/spec/{msgr → unit}/spec_helper.rb +1 -1
  57. data/spec/unit/support/.keep +0 -0
  58. metadata +41 -36
  59. data/gemfiles/Gemfile.rails-4-2 +0 -7
  60. data/gemfiles/Gemfile.rails-5-0 +0 -7
  61. data/gemfiles/Gemfile.rails-5-1 +0 -7
  62. data/gemfiles/Gemfile.rails-5-2 +0 -7
  63. data/gemfiles/Gemfile.rails-master +0 -14
  64. data/spec/msgr/msgr/client_spec.rb +0 -60
  65. data/spec/msgr/msgr/dispatcher_spec.rb +0 -44
  66. data/spec/support/setup.rb +0 -29
data/lib/msgr/client.rb CHANGED
@@ -2,15 +2,14 @@
2
2
 
3
3
  require 'uri'
4
4
  require 'cgi'
5
+ require 'json'
5
6
 
6
7
  module Msgr
7
- # rubocop:disable Metrics/ClassLength
8
8
  class Client
9
9
  include Logging
10
10
 
11
11
  attr_reader :config
12
12
 
13
- # rubocop:disable MethodLength
14
13
  def initialize(config = {})
15
14
  @config = {
16
15
  host: '127.0.0.1',
@@ -18,21 +17,16 @@ module Msgr
18
17
  max: 2
19
18
  }
20
19
 
21
- @config.merge! parse(config.delete(:uri)) if config.key?(:uri)
20
+ @config.merge! parse(config.delete(:uri)) if config[:uri]
22
21
  @config.merge! config.symbolize_keys
23
22
 
24
23
  @mutex = ::Mutex.new
25
- @routes = Routes.new
24
+ @routes = load_routes
26
25
  @pid ||= ::Process.pid
27
26
 
28
27
  log(:debug) { "Created new client on process ##{@pid}..." }
29
28
  end
30
- # rubocop:enable all
31
29
 
32
- # rubocop:disable AbcSize
33
- # rubocop:disable MethodLength
34
- # rubocop:disable PerceivedComplexity
35
- # rubocop:disable CyclomaticComplexity
36
30
  def uri
37
31
  @uri = begin
38
32
  uri = ::URI.parse('amqp://localhost')
@@ -50,7 +44,6 @@ module Msgr
50
44
  uri
51
45
  end
52
46
  end
53
- # rubocop:enable all
54
47
 
55
48
  def running?
56
49
  mutex.synchronize do
@@ -59,7 +52,6 @@ module Msgr
59
52
  end
60
53
  end
61
54
 
62
- # rubocop:disable AbcSize
63
55
  def start
64
56
  mutex.synchronize do
65
57
  check_process!
@@ -67,12 +59,9 @@ module Msgr
67
59
 
68
60
  log(:debug) { "Start on #{uri}..." }
69
61
 
70
- @routes << config[:routing_file] if config[:routing_file].present?
71
- @routes.reload
72
62
  connection.bind(@routes)
73
63
  end
74
64
  end
75
- # rubocop:enable all
76
65
 
77
66
  def connect
78
67
  mutex.synchronize do
@@ -85,7 +74,6 @@ module Msgr
85
74
  end
86
75
  end
87
76
 
88
- # rubocop:disable AbcSize
89
77
  def stop(opts = {})
90
78
  mutex.synchronize do
91
79
  check_process!
@@ -100,7 +88,6 @@ module Msgr
100
88
  reset
101
89
  end
102
90
  end
103
- # rubocop:enable all
104
91
 
105
92
  def purge(release: false)
106
93
  mutex.synchronize do
@@ -112,6 +99,15 @@ module Msgr
112
99
  end
113
100
  end
114
101
 
102
+ ##
103
+ # Purge all queues known to Msgr, if they exist.
104
+ #
105
+ def drain
106
+ @routes.each do |route|
107
+ connection.purge_queue(route.name)
108
+ end
109
+ end
110
+
115
111
  def publish(payload, opts = {})
116
112
  mutex.synchronize do
117
113
  check_process!
@@ -149,6 +145,7 @@ module Msgr
149
145
 
150
146
  def check_process!
151
147
  return if ::Process.pid == @pid
148
+
152
149
  log(:warn) do
153
150
  "Fork detected. Reset internal state. (Old PID: #{@pid} / " \
154
151
  "New PID: #{::Process.pid}"
@@ -178,22 +175,27 @@ module Msgr
178
175
  @dispatcher = nil
179
176
  end
180
177
 
181
- # rubocop:disable AbcSize
182
178
  def parse(uri)
183
179
  # Legacy parsing of URI configuration; does not follow usual
184
180
  # AMQP vhost encoding but used regular URL path
185
181
  uri = ::URI.parse(uri)
186
182
 
187
183
  config = {}
188
- config[:user] ||= uri.user if uri.user
189
- config[:pass] ||= uri.password if uri.password
190
- config[:host] ||= uri.host if uri.host
191
- config[:port] ||= uri.port if uri.port
192
- config[:vhost] ||= uri.path unless uri.path.empty?
184
+ config[:user] ||= uri.user if uri.user
185
+ config[:pass] ||= uri.password if uri.password
186
+ config[:host] ||= uri.host if uri.host
187
+ config[:port] ||= uri.port if uri.port
188
+ config[:vhost] ||= uri.path unless uri.path.empty?
193
189
  config[:ssl] ||= uri.scheme.casecmp('amqps').zero?
194
190
 
195
191
  config
196
192
  end
197
- # rubocop:enable all
193
+
194
+ def load_routes
195
+ Routes.new.tap do |routes|
196
+ routes << config[:routing_file] if config[:routing_file].present?
197
+ routes.reload
198
+ end
199
+ end
198
200
  end
199
201
  end
@@ -3,7 +3,6 @@
3
3
  require 'bunny'
4
4
 
5
5
  module Msgr
6
- # rubocop:disable Metrics/ClassLength
7
6
  class Connection
8
7
  include Logging
9
8
 
@@ -49,6 +48,7 @@ module Msgr
49
48
 
50
49
  def release
51
50
  return if bindings.empty?
51
+
52
52
  log(:debug) { "Release bindings (#{bindings.size})..." }
53
53
 
54
54
  bindings.each(&:release)
@@ -56,6 +56,7 @@ module Msgr
56
56
 
57
57
  def delete
58
58
  return if bindings.empty?
59
+
59
60
  log(:debug) { "Delete bindings (#{bindings.size})..." }
60
61
 
61
62
  bindings.each(&:delete)
@@ -63,11 +64,22 @@ module Msgr
63
64
 
64
65
  def purge(**kwargs)
65
66
  return if bindings.empty?
67
+
66
68
  log(:debug) { "Purge bindings (#{bindings.size})..." }
67
69
 
68
70
  bindings.each {|b| b.purge(**kwargs) }
69
71
  end
70
72
 
73
+ def purge_queue(name)
74
+ # Creating the queue in passive mode ensures that queues that do not exist
75
+ # won't be created just to purge them.
76
+ # That requires creating a new channel every time, as exceptions (on
77
+ # missing queues) invalidate the channel.
78
+ channel.queue(name, passive: true).purge
79
+ rescue Bunny::NotFound
80
+ nil
81
+ end
82
+
71
83
  def bindings
72
84
  @bindings ||= []
73
85
  end
data/lib/msgr/consumer.rb CHANGED
@@ -5,6 +5,7 @@ module Msgr
5
5
  include Logging
6
6
 
7
7
  attr_reader :message
8
+
8
9
  delegate :payload, to: :@message
9
10
  delegate :action, to: :'@message.route'
10
11
  delegate :consumer, to: :'@message.consumer'
@@ -14,9 +15,7 @@ module Msgr
14
15
  @auto_ack || @auto_ack.nil?
15
16
  end
16
17
 
17
- def auto_ack=(val)
18
- @auto_ack = val
19
- end
18
+ attr_writer :auto_ack
20
19
  end
21
20
 
22
21
  def dispatch(message)
@@ -27,9 +27,6 @@ module Msgr
27
27
  end
28
28
  end
29
29
 
30
- # rubocop:disable Metrics/AbcSize
31
- # rubocop:disable Metrics/MethodLength
32
- # rubocop:disable Metrics/CyclomaticComplexity
33
30
  def dispatch(message)
34
31
  consumer_class = Object.const_get message.route.consumer
35
32
 
@@ -37,17 +34,18 @@ module Msgr
37
34
 
38
35
  consumer_class.new.dispatch message
39
36
 
40
- # Acknowledge message unless it is already acknowledged or auto_ack is disabled.
41
- message.ack unless message.acked? or not consumer_class.auto_ack?
42
- rescue => error
37
+ # Acknowledge message only if it is not already acknowledged and auto
38
+ # acknowledgment is enabled.
39
+ message.ack unless message.acked? || !consumer_class.auto_ack?
40
+ rescue StandardError => e
43
41
  message.nack unless message.acked?
44
42
 
45
43
  log(:error) do
46
- "Dispatcher error: #{error.class.name}: #{error}\n" +
47
- error.backtrace.join("\n")
44
+ "Dispatcher error: #{e.class.name}: #{e}\n" +
45
+ e.backtrace.join("\n")
48
46
  end
49
47
 
50
- raise error if config[:raise_exceptions]
48
+ raise e if config[:raise_exceptions]
51
49
  ensure
52
50
  if defined?(ActiveRecord) &&
53
51
  ActiveRecord::Base.connection_pool.active_connection?
data/lib/msgr/logging.rb CHANGED
@@ -3,7 +3,9 @@
3
3
  module Msgr
4
4
  module Logging
5
5
  def log(level)
6
+ # rubocop:disable Style/SafeNavigation - Msgr.logger can be false
6
7
  Msgr.logger.send(level) { "#{log_name} #{yield}" } if Msgr.logger
8
+ # rubocop:enable all
7
9
  end
8
10
 
9
11
  def log_name
data/lib/msgr/message.rb CHANGED
@@ -11,8 +11,7 @@ module Msgr
11
11
  @payload = payload
12
12
  @route = route
13
13
 
14
- # rubocop:disable Style/GuardClause
15
- if content_type == 'application/json'
14
+ if content_type == 'application/json' # rubocop:disable Style/GuardClause
16
15
  @payload = JSON.parse(payload)
17
16
  @payload.symbolize_keys! if @payload.respond_to? :symbolize_keys!
18
17
  end
data/lib/msgr/railtie.rb CHANGED
@@ -4,92 +4,31 @@ module Msgr
4
4
  class Railtie < ::Rails::Railtie
5
5
  config.msgr = ActiveSupport::OrderedOptions.new
6
6
 
7
- if File.exist?("#{Rails.root}/app/consumers")
8
- config.autoload_paths << File.expand_path("#{Rails.root}/app/consumers")
9
- end
10
-
11
7
  initializer 'msgr.logger' do |app|
12
8
  app.config.msgr.logger ||= Rails.logger
13
9
  end
14
10
 
15
- # Start msgr
16
11
  initializer 'msgr.start' do
17
12
  config.after_initialize do |app|
18
13
  Msgr.logger = app.config.msgr.logger
19
-
20
- self.class.load app.config.msgr
14
+ self.class.load(app.config_for(:rabbitmq).symbolize_keys)
21
15
  end
22
16
  end
23
17
 
24
- class << self
25
- def load(rails_config)
26
- cfg = parse_config load_config rails_config
27
- return unless cfg # no config given -> does not load Msgr
28
-
29
- Msgr.config = cfg
30
- Msgr.client.connect if cfg[:checkcredentials]
31
- Msgr.start if cfg[:autostart]
32
- end
33
-
34
- def parse_config(cfg)
35
- unless cfg.is_a? Hash
36
- Rails.logger.warn '[Msgr] Could not load rabbitmq config: Config must be a Hash'
37
- return nil
38
- end
39
-
40
- unless cfg[Rails.env].is_a?(Hash)
41
- Rails.logger.warn "Could not load rabbitmq config for environment \"#{Rails.env}\": is not a Hash"
42
- return nil
43
- end
44
-
45
- cfg = HashWithIndifferentAccess.new cfg[Rails.env]
46
- unless cfg[:uri]
47
- raise ArgumentError.new('Could not load rabbitmq environment config: URI missing.')
48
- end
49
-
50
- case cfg[:autostart]
51
- when true, 'true', 'enabled'
52
- cfg[:autostart] = true
53
- when false, 'false', 'disabled', nil
54
- cfg[:autostart] = false
55
- else
56
- raise ArgumentError.new("Invalid value for rabbitmq config autostart: \"#{cfg[:autostart]}\"")
57
- end
58
-
59
- case cfg[:checkcredentials]
60
- when true, 'true', 'enabled', nil
61
- cfg[:checkcredentials] = true
62
- when false, 'false', 'disabled'
63
- cfg[:checkcredentials] = false
64
- else
65
- raise ArgumentError.new("Invalid value for rabbitmq config checkcredentials: \"#{cfg[:checkcredentials]}\"")
66
- end
67
-
68
- case cfg[:raise_exceptions]
69
- when true, 'true', 'enabled'
70
- cfg[:raise_exceptions] = true
71
- when false, 'false', 'disabled', nil
72
- cfg[:raise_exceptions] = false
73
- else
74
- raise ArgumentError.new("Invalid value for rabbitmq config raise_exceptions: \"#{cfg[:raise_exceptions]}\"")
75
- end
76
-
77
- cfg[:routing_file] ||= Rails.root.join('config/msgr.rb').to_s
78
- cfg
79
- end
80
-
81
- def load_config(options)
82
- if options.rabbitmq_config || !Rails.application.respond_to?(:config_for)
83
- load_file options.rabbitmq_config || Rails.root.join('config', 'rabbitmq.yml')
84
- else
85
- conf = Rails.application.config_for :rabbitmq
86
-
87
- {Rails.env.to_s => conf}
88
- end
89
- end
18
+ rake_tasks do
19
+ load File.expand_path('tasks/msgr/drain.rake', __dir__)
20
+ end
90
21
 
91
- def load_file(path)
92
- YAML.safe_load ERB.new(File.read(path)).result
22
+ class << self
23
+ def load(config)
24
+ # Set defaults
25
+ config.reverse_merge!(
26
+ checkcredentials: true,
27
+ routing_file: Rails.root.join('config/msgr.rb').to_s
28
+ )
29
+
30
+ Msgr.config = config
31
+ Msgr.client.connect if config.fetch(:checkcredentials)
93
32
  end
94
33
  end
95
34
  end
data/lib/msgr/route.rb CHANGED
@@ -4,10 +4,7 @@ module Msgr
4
4
  class Route
5
5
  attr_reader :consumer, :action, :opts
6
6
 
7
- MATCH_REGEXP = /\A(?<consumer>\w+)#(?<action>\w+)\z/
8
-
9
- # rubocop:disable Metrics/AbcSize
10
- # rubocop:disable Metrics/MethodLength
7
+ MATCH_REGEXP = /\A(?<consumer>\w+)#(?<action>\w+)\z/.freeze
11
8
  def initialize(key, opts = {})
12
9
  @opts = opts
13
10
  raise ArgumentError.new 'Missing `to` options.' unless @opts[:to]
data/lib/msgr/routes.rb CHANGED
@@ -3,7 +3,9 @@
3
3
  module Msgr
4
4
  class Routes
5
5
  include Logging
6
+
6
7
  attr_reader :routes
8
+
7
9
  delegate :each, :empty?, :size, :any?, to: :@routes
8
10
 
9
11
  def initialize
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :msgr do
4
+ desc 'Drain all known queues'
5
+ task drain: :environment do
6
+ client = Msgr.client
7
+
8
+ client.connect
9
+ client.drain
10
+ end
11
+ end
@@ -31,8 +31,6 @@ module Msgr
31
31
 
32
32
  private
33
33
 
34
- # rubocop:disable Metrics/AbcSize
35
- # rubocop:disable Metrics/MethodLength
36
34
  def ns_run(count: 1, timeout: 5)
37
35
  received = 0
38
36
 
@@ -59,7 +57,7 @@ module Msgr
59
57
 
60
58
  class << self
61
59
  def new(*args)
62
- @instance ||= super(*args)
60
+ @instance ||= super(*args) # rubocop:disable Naming/MemoizedInstanceVariableName
63
61
  end
64
62
 
65
63
  def run(*args)
data/lib/msgr/version.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  module Msgr
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 1
7
- PATCH = 0
6
+ MINOR = 3
7
+ PATCH = 2
8
8
  STAGE = nil
9
9
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.')
10
10
 
data/lib/msgr.rb CHANGED
@@ -26,6 +26,7 @@ require 'msgr/railtie' if defined? Rails
26
26
  module Msgr
27
27
  class << self
28
28
  attr_writer :client, :config
29
+
29
30
  delegate :publish, to: :client
30
31
 
31
32
  def config
data/msgr.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  require 'msgr/version'
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.name = 'msgr'
10
10
  spec.version = Msgr::VERSION
11
11
  spec.authors = ['Jan Graichen']
12
- spec.email = ['jg@altimos.de']
12
+ spec.email = ['jgraichen@altimos.de']
13
13
  spec.description = 'Msgr: Rails-like Messaging Framework'
14
14
  spec.summary = 'Msgr: Rails-like Messaging Framework'
15
15
  spec.homepage = 'https://github.com/jgraichen/msgr'
@@ -24,8 +24,4 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'bunny', '>= 1.4', '< 3.0'
25
25
 
26
26
  spec.add_development_dependency 'bundler'
27
-
28
- if ENV['TRAVIS_BUILD_NUMBER']
29
- spec.version = "#{spec.version}.1.b#{ENV['TRAVIS_BUILD_NUMBER']}"
30
- end
31
27
  end
@@ -19,7 +19,6 @@ class TestConsumer < Msgr::Consumer
19
19
  end
20
20
  end
21
21
 
22
- #
23
22
  class NullPool
24
23
  def initialize(*); end
25
24
 
@@ -45,9 +44,9 @@ end
45
44
 
46
45
  begin
47
46
  sleep
48
- rescue Interrupt
47
+ rescue Interrupt # rubocop:disable Lint/SuppressedException
49
48
  ensure
50
49
  @client.stop timeout: 10, delete: true
51
50
  end
52
51
 
53
- $stderr.puts "COUNTER: #{@counter}"
52
+ warn "COUNTER: #{@counter}"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ route 'abc', to: 'consumer1#action1'
4
+ route 'def', to: 'consumer1#action2'
5
+ route 'ghi', to: 'consumer2#action1'
@@ -3,6 +3,6 @@
3
3
  # Add your own tasks in files placed in lib/tasks ending in .rake,
4
4
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
5
5
 
6
- require File.expand_path('../config/application', __FILE__)
6
+ require File.expand_path('config/application', __dir__)
7
7
 
8
8
  Dummy::Application.load_tasks
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
4
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
5
5
  load Gem.bin_path('bundler', 'bundle')
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- APP_PATH = File.expand_path('../../config/application', __FILE__)
4
+ APP_PATH = File.expand_path('../config/application', __dir__)
5
5
  require_relative '../config/boot'
6
6
  require 'rails/commands'
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path('../boot', __FILE__)
3
+ require File.expand_path('boot', __dir__)
4
4
 
5
5
  require 'rails/all'
6
6
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Set up gems listed in the Gemfile.
4
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
4
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
5
5
 
6
6
  require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
7
- $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
7
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Load the Rails application.
4
- require File.expand_path('../application', __FILE__)
4
+ require File.expand_path('application', __dir__)
5
5
 
6
6
  # Initialize the Rails application.
7
7
  Dummy::Application.initialize!
@@ -1,5 +1,5 @@
1
1
  common: &common
2
- uri: amqp://localhost/
2
+ uri: <%= ENV.fetch("AMQP_SERVER", "amqp://localhost/") %>
3
3
 
4
4
  test:
5
5
  <<: *common
@@ -4,7 +4,19 @@ require 'spec_helper'
4
4
 
5
5
  class DispatcherTestConsumer < Msgr::Consumer
6
6
  def index
7
- puts "<<< #{payload}"
7
+ self.class.called!
8
+ end
9
+
10
+ class << self
11
+ def calls
12
+ @calls ||= 0
13
+ end
14
+
15
+ attr_writer :calls
16
+
17
+ def called!
18
+ self.calls += 1
19
+ end
8
20
  end
9
21
  end
10
22
 
@@ -19,55 +31,59 @@ describe Msgr::Dispatcher do
19
31
  let(:config) { {max: 1} }
20
32
  let(:consumer) { 'DispatcherTestConsumer' }
21
33
  let(:route) do
22
- double(:route).tap do |t|
34
+ instance_double('Msgr::Route').tap do |t|
23
35
  allow(t).to receive(:consumer).and_return consumer
24
36
  allow(t).to receive(:action).and_return 'index'
25
37
  end
26
38
  end
27
39
  let(:channel) do
28
- double(:channel).tap do |c|
40
+ instance_double('Msgr::Channel').tap do |c|
29
41
  allow(c).to receive(:ack)
30
42
  end
31
43
  end
32
44
  let(:delivery_info) do
33
- double(:delivery_info).tap do |ti|
45
+ instance_double('Bunny::DeliveryInfo').tap do |ti|
34
46
  allow(ti).to receive(:delivery_tag).and_return(3)
35
47
  end
36
48
  end
37
49
  let(:payload) { {} }
38
50
  let(:metadata) do
39
- double(:metadata).tap do |metadata|
51
+ instance_double('Bunny::MessageProperties').tap do |metadata|
40
52
  allow(metadata).to receive(:content_type).and_return('text/plain')
41
53
  end
42
54
  end
43
55
  let(:message) { Msgr::Message.new channel, delivery_info, metadata, payload, route }
44
56
  let(:action) { -> { dispatcher.call message } }
45
57
 
46
- it 'should consume message' do
47
- expect_any_instance_of(DispatcherTestConsumer).to receive(:index)
48
- dispatcher.call message
58
+ it 'consumes message' do
59
+ expect do
60
+ dispatcher.call message
61
+ end.to change(DispatcherTestConsumer, :calls).by(1)
49
62
  end
50
63
 
51
64
  context 'with not acknowledged message' do
52
- before { dispatcher.call message }
53
65
  subject { message }
54
- it { should be_acked }
66
+
67
+ before { dispatcher.call message }
68
+
69
+ it { is_expected.to be_acked }
55
70
  end
56
71
 
57
72
  describe 'exception swallowing' do
58
73
  let(:consumer) { 'DispatcherRaiseConsumer' }
74
+
59
75
  before do
60
76
  allow(message).to receive(:nack)
61
77
  end
62
78
 
63
- it 'should swallow exceptions by default' do
79
+ it 'swallows exceptions by default' do
64
80
  expect { dispatcher.call(message) }.not_to raise_error
65
81
  end
66
82
 
67
83
  context 'with raise_exceptions configuration option and a synchronous pool' do
68
84
  let(:config) { super().merge(raise_exceptions: true) }
69
85
 
70
- it 'should raise the exception' do
86
+ it 'raises the exception' do
71
87
  expect { dispatcher.call(message) }.to raise_error(ArgumentError)
72
88
  end
73
89
  end