msgr 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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