msgr 1.2.0 → 1.3.0

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 (65) 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 +11 -1
  9. data/Gemfile +8 -15
  10. data/README.md +8 -20
  11. data/Rakefile +5 -5
  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.rb +1 -0
  18. data/lib/msgr/binding.rb +13 -8
  19. data/lib/msgr/channel.rb +5 -3
  20. data/lib/msgr/cli.rb +18 -11
  21. data/lib/msgr/client.rb +17 -20
  22. data/lib/msgr/connection.rb +13 -1
  23. data/lib/msgr/consumer.rb +2 -3
  24. data/lib/msgr/dispatcher.rb +7 -9
  25. data/lib/msgr/logging.rb +2 -0
  26. data/lib/msgr/message.rb +1 -2
  27. data/lib/msgr/railtie.rb +14 -69
  28. data/lib/msgr/route.rb +1 -4
  29. data/lib/msgr/routes.rb +2 -0
  30. data/lib/msgr/tasks/msgr/drain.rake +11 -0
  31. data/lib/msgr/test_pool.rb +1 -3
  32. data/lib/msgr/version.rb +1 -1
  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/integration/dummy/Rakefile +1 -1
  37. data/spec/{msgr/support/.keep → integration/dummy/app/assets/config/manifest.js} +0 -0
  38. data/spec/integration/dummy/bin/bundle +1 -1
  39. data/spec/integration/dummy/bin/rails +1 -1
  40. data/spec/integration/dummy/config/application.rb +1 -1
  41. data/spec/integration/dummy/config/boot.rb +2 -2
  42. data/spec/integration/dummy/config/environment.rb +1 -1
  43. data/spec/integration/dummy/config/rabbitmq.yml +1 -1
  44. data/spec/integration/msgr/dispatcher_spec.rb +28 -12
  45. data/spec/integration/msgr/railtie_spec.rb +10 -120
  46. data/spec/integration/spec_helper.rb +2 -3
  47. data/spec/integration/{msgr_spec.rb → test_controller_spec.rb} +1 -1
  48. data/spec/unit/msgr/client_spec.rb +88 -0
  49. data/spec/{msgr → unit}/msgr/connection_spec.rb +1 -1
  50. data/spec/{msgr → unit}/msgr/consumer_spec.rb +0 -0
  51. data/spec/unit/msgr/dispatcher_spec.rb +45 -0
  52. data/spec/{msgr → unit}/msgr/route_spec.rb +15 -14
  53. data/spec/{msgr → unit}/msgr/routes_spec.rb +32 -35
  54. data/spec/{msgr → unit}/msgr_spec.rb +25 -16
  55. data/spec/{msgr → unit}/spec_helper.rb +1 -1
  56. data/spec/unit/support/.keep +0 -0
  57. metadata +37 -33
  58. data/gemfiles/Gemfile.rails-4-2 +0 -7
  59. data/gemfiles/Gemfile.rails-5-0 +0 -7
  60. data/gemfiles/Gemfile.rails-5-1 +0 -7
  61. data/gemfiles/Gemfile.rails-5-2 +0 -7
  62. data/gemfiles/Gemfile.rails-master +0 -14
  63. data/spec/msgr/msgr/client_spec.rb +0 -60
  64. data/spec/msgr/msgr/dispatcher_spec.rb +0 -44
  65. data/spec/support/setup.rb +0 -29
@@ -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]
@@ -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)
@@ -3,7 +3,7 @@
3
3
  module Msgr
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 2
6
+ MINOR = 3
7
7
  PATCH = 0
8
8
  STAGE = nil
9
9
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.')
@@ -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}"
@@ -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
@@ -6,139 +6,29 @@ describe Msgr::Railtie do
6
6
  describe 'configuration options' do
7
7
  let(:config) { Rails.configuration }
8
8
 
9
- it 'should have `msgr` key' do
9
+ it 'has `msgr` key' do
10
10
  expect(config).to respond_to :msgr
11
11
  end
12
12
  end
13
13
 
14
- describe '#parse_config' do
15
- let(:settings) { {} }
16
- let(:action) { described_class.parse_config settings }
17
- subject { action }
18
-
19
- context 'with incorrect settings' do
20
- subject { -> { action } }
21
-
22
- context 'with config without url' do
23
- let(:settings) { {'test' => {hans: 'otto'}} }
24
-
25
- it { should raise_error 'Could not load rabbitmq environment config: URI missing.' }
26
- end
27
-
28
- context 'with invalid autostart value' do
29
- let(:settings) { {'test' => {uri: 'hans', autostart: 'unvalid'}} }
30
-
31
- it { should raise_error 'Invalid value for rabbitmq config autostart: "unvalid"' }
32
- end
33
-
34
- context 'with invalid checkcredentials value' do
35
- let(:settings) { {'test' => {uri: 'hans', checkcredentials: 'unvalid'}} }
36
-
37
- it { should raise_error 'Invalid value for rabbitmq config checkcredentials: "unvalid"' }
38
- end
39
-
40
- context 'with invalid raise_exceptions value' do
41
- let(:settings) { {'test' => {uri: 'franz', raise_exceptions: 'unvalid'}} }
42
-
43
- it { should raise_error 'Invalid value for rabbitmq config raise_exceptions: "unvalid"' }
44
- end
45
- end
46
-
47
- context 'without set routes file' do
48
- let(:settings) { {'test' => {uri: 'test'}} }
49
-
50
- context '[:routing_file]' do
51
- subject { super()[:routing_file] }
52
- it { should eq Rails.root.join('config/msgr.rb').to_s }
53
- end
54
- end
55
-
56
- context 'with set routes file' do
57
- let(:settings) { {'test' => {uri: 'test', 'routing_file' => 'my fancy file'}} }
58
-
59
- context '[:routing_file]' do
60
- subject { super()[:routing_file] }
61
- it { should eq 'my fancy file' }
62
- end
63
- end
64
-
65
- context 'with uri as symbol' do
66
- let(:settings) { {'test' => {uri: 'hans'}} }
67
-
68
- context '[:uri]' do
69
- subject { super()[:uri] }
70
- it { should eq 'hans' }
71
- end
72
- end
73
-
74
- context 'with uri as string' do
75
- let(:settings) { {'test' => {'uri' => 'hans'}} }
76
-
77
- context '[:uri]' do
78
- subject { super()[:uri] }
79
- it { should eq 'hans' }
80
- end
81
- end
82
-
83
- context 'without raise_exceptions config' do
84
- let(:settings) { {'test' => {'uri' => 'hans'}, 'development' => {'uri' => 'hans_dev'}} }
85
-
86
- describe '[:raise_exceptions]' do
87
- subject { super()[:raise_exceptions] }
88
- it { should eq false }
89
- end
90
- end
91
- end
92
-
93
14
  describe '#load' do
94
- let(:config) do
95
- cfg = ActiveSupport::OrderedOptions.new
96
- cfg.rabbitmq_config = Rails.root.join 'config', 'rabbitmq.yml'
97
- cfg
98
- end
99
-
100
- context 'with autostart is true' do
101
- it 'should not start Msgr' do
102
- expect(Msgr).to receive(:start)
103
- expect(Msgr::Railtie).to receive(:load_config).and_return('test' => {uri: 'test', autostart: true})
104
- Msgr::Railtie.load config
105
- end
106
- end
107
-
108
- context 'without autostart value' do
109
- it 'should not start Msgr' do
110
- expect(Msgr).to_not receive(:start)
111
- expect(Msgr::Railtie).to receive(:load_config).and_return('test' => {uri: 'test'})
112
- Msgr::Railtie.load config
113
- end
15
+ before do
16
+ allow(Msgr).to receive(:start)
17
+ allow(Msgr.client).to receive(:connect)
114
18
  end
115
19
 
116
20
  context 'without checkcredentials value' do
117
- it 'should connect to rabbitmq directly to check credentials' do
118
- expect_any_instance_of(Msgr::Client).to receive(:connect)
119
- expect(Msgr::Railtie).to receive(:load_config).and_return('test' => {uri: 'test'})
120
- Msgr::Railtie.load config
21
+ it 'connects to rabbitmq directly to check credentials' do
22
+ described_class.load({})
23
+ expect(Msgr.client).to have_received(:connect)
121
24
  end
122
25
  end
123
26
 
124
27
  context 'with checkcredentials is false' do
125
- it 'should connect to rabbitmq directly to check credentials' do
126
- expect_any_instance_of(Msgr::Client).to_not receive(:connect)
127
- expect(Msgr::Railtie).to receive(:load_config).and_return('test' => {uri: 'test', checkcredentials: false})
128
- Msgr::Railtie.load config
28
+ it 'connects to rabbitmq directly to check credentials' do
29
+ described_class.load({checkcredentials: false})
30
+ expect(Msgr.client).not_to have_received(:connect)
129
31
  end
130
32
  end
131
33
  end
132
-
133
- # describe '#load_config'
134
- # let(:options) { {} }
135
-
136
- # subject { Msgr::Railtie.load_config options }
137
-
138
- # if Rails::Application.methods.include(:config_for)
139
- # it 'should use config_for' do
140
-
141
- # end
142
- # end
143
- # end
144
34
  end
@@ -10,15 +10,14 @@ Coveralls.wear! do
10
10
  add_filter 'spec'
11
11
  end
12
12
 
13
- #
14
13
  ENV['RAILS_ENV'] ||= 'test'
15
14
  ENV['RAILS_GROUPS'] = ['rails', ENV['RAILS_GROUPS']].reject(&:nil?).join(',')
16
- require File.expand_path('../dummy/config/environment', __FILE__)
15
+ require File.expand_path('dummy/config/environment', __dir__)
17
16
  require 'rspec/rails'
18
17
 
19
18
  # Requires supporting ruby files with custom matchers and macros, etc,
20
19
  # in spec/support/ and its subdirectories.
21
- Dir[File.expand_path('../support/**/*.rb', __FILE__)].each {|f| require f }
20
+ Dir[File.expand_path('support/**/*.rb', __dir__)].sort.each {|f| require f }
22
21
 
23
22
  # Checks for pending migrations before tests are run.
24
23
  # If you are not using ActiveRecord, you can remove this line.
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe TestController, type: :request do
6
- it 'should send messages on :index' do
6
+ it 'sends messages on :index' do
7
7
  get '/'
8
8
  end
9
9
  end