evrone-common-amqp 0.0.1

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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +6 -0
  9. data/bin/amqp_consumers +12 -0
  10. data/evrone-common-amqp.gemspec +30 -0
  11. data/lib/evrone/common/amqp.rb +68 -0
  12. data/lib/evrone/common/amqp/cli.rb +88 -0
  13. data/lib/evrone/common/amqp/config.rb +74 -0
  14. data/lib/evrone/common/amqp/consumer.rb +70 -0
  15. data/lib/evrone/common/amqp/consumer/ack.rb +19 -0
  16. data/lib/evrone/common/amqp/consumer/configuration.rb +93 -0
  17. data/lib/evrone/common/amqp/consumer/publish.rb +32 -0
  18. data/lib/evrone/common/amqp/consumer/subscribe.rb +67 -0
  19. data/lib/evrone/common/amqp/formatter.rb +109 -0
  20. data/lib/evrone/common/amqp/mixins/logger.rb +17 -0
  21. data/lib/evrone/common/amqp/mixins/with_middleware.rb +16 -0
  22. data/lib/evrone/common/amqp/session.rb +154 -0
  23. data/lib/evrone/common/amqp/supervisor/threaded.rb +170 -0
  24. data/lib/evrone/common/amqp/testing.rb +46 -0
  25. data/lib/evrone/common/amqp/version.rb +7 -0
  26. data/spec/integration/multi_threaded_spec.rb +83 -0
  27. data/spec/integration/threaded_supervisor_spec.rb +85 -0
  28. data/spec/lib/amqp/consumer_spec.rb +281 -0
  29. data/spec/lib/amqp/formatter_spec.rb +47 -0
  30. data/spec/lib/amqp/mixins/with_middleware_spec.rb +32 -0
  31. data/spec/lib/amqp/session_spec.rb +144 -0
  32. data/spec/lib/amqp/supervisor/threaded_spec.rb +123 -0
  33. data/spec/lib/amqp_spec.rb +9 -0
  34. data/spec/spec_helper.rb +13 -0
  35. data/spec/support/amqp.rb +15 -0
  36. data/spec/support/ignore_me_error.rb +1 -0
  37. metadata +175 -0
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ class FormatterConsumerTest
5
+ include Evrone::Common::AMQP::Consumer
6
+
7
+ model Hash
8
+ end
9
+
10
+ describe Evrone::Common::AMQP::Formatter do
11
+ let(:consumer) { FormatterConsumerTest.new }
12
+ subject { described_class }
13
+
14
+ context "pack" do
15
+ let(:body) { { "a" => 1, "b" => 2 } }
16
+
17
+ it "should pack message" do
18
+ expect(subject.pack 'application/json', body).to eq body.to_json
19
+ expect(subject.pack :foo, body).to be_nil
20
+ end
21
+
22
+ end
23
+
24
+ context "unpack" do
25
+ let(:body) { { "a" => 1, "b" => 2 } }
26
+
27
+ before do
28
+ mock(Hash).from_json(body.to_json) { body }
29
+ end
30
+
31
+ it "should unpack message" do
32
+ expect(subject.unpack 'application/json', Hash, body.to_json).to eq body
33
+ expect(subject.unpack :foo, Hash, body.to_json).to be_nil
34
+ end
35
+
36
+ end
37
+
38
+ context "lookup" do
39
+
40
+ it "should find format by content type" do
41
+ expect(subject.lookup('application/json').content_type).to eq 'application/json'
42
+ expect(subject.lookup(:foo)).to be_nil
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::Common::AMQP::WithMiddleware do
4
+ let(:object) { Object.new.extend described_class }
5
+
6
+ Foo = Struct.new(:app, :id) do
7
+ def call(env)
8
+ env << "called"
9
+ app.call env
10
+ end
11
+ end
12
+
13
+ before { Evrone::Common::AMQP.config.reset! }
14
+ after { Evrone::Common::AMQP.config.reset! }
15
+
16
+ context 'with_middleware' do
17
+ it "should be successfull" do
18
+ Evrone::Common::AMQP.configure do |c|
19
+ c.publishing do
20
+ use Foo, :id
21
+ end
22
+ end
23
+
24
+ collected = ""
25
+ object.with_middleware(:publishing, "") do |env|
26
+ collected << env
27
+ end
28
+ expect(collected).to eq 'called'
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+ require 'timeout'
3
+ require 'thread'
4
+
5
+ describe Evrone::Common::AMQP::Session do
6
+ let(:sess) { described_class.new }
7
+ let(:queue_name) { 'foo' }
8
+ let(:exch_name) { 'bar' }
9
+
10
+ subject { sess }
11
+
12
+ before { sess.open }
13
+ after { sess.close }
14
+
15
+ context "open" do
16
+ its("conn.status") { should eq :open }
17
+ its(:open?) { should be }
18
+ end
19
+
20
+ context "should reuse connection" do
21
+ before do
22
+ @id = sess.conn.object_id
23
+ end
24
+ its("conn.object_id") { should eq @id }
25
+ end
26
+
27
+ context "should reuse channel" do
28
+ before do
29
+ @id = sess.channel.id
30
+ end
31
+ its("channel.id") { should eq @id }
32
+ end
33
+
34
+ it 'channel by default should eq connection default channel' do
35
+ expect(sess.channel.id).to eq sess.conn.default_channel.id
36
+ end
37
+
38
+ context "with_channel" do
39
+ before do
40
+ @default = sess.channel.id
41
+ end
42
+
43
+ it "should create and close a new channel" do
44
+ sess.with_channel do
45
+ expect(sess.channel.id).to_not eq @default
46
+ end
47
+ expect(sess.channel.id).to eq @default
48
+ end
49
+ end
50
+
51
+ context "close" do
52
+ it "should close connection" do
53
+ expect{ sess.close }.to change{ sess.open? }.from(true).to(nil)
54
+ end
55
+ end
56
+
57
+ context "declare_exchange" do
58
+ let(:options) {{}}
59
+ let(:exch) { sess.declare_exchange exch_name, options }
60
+ subject { exch }
61
+
62
+ after { delete_exchange exch }
63
+
64
+ it{ should be }
65
+
66
+ context "by default" do
67
+ its(:name) { should eq exch_name }
68
+ its(:type) { should eq :topic }
69
+ its(:durable?) { should be_true }
70
+ its(:auto_delete?) { should be_false }
71
+ its("channel.id") { should eq sess.channel.id }
72
+ end
73
+
74
+ context "when exchange name is nil should use default_exchange_name" do
75
+ let(:exch) { sess.declare_exchange nil, options }
76
+ its(:name) { should eq 'amq.topic' }
77
+ end
78
+
79
+ context "when pass durable: false" do
80
+ let(:options) { { durable: false } }
81
+ its(:durable?) { should be_false }
82
+ end
83
+
84
+ context "when pass auto_delete: true" do
85
+ let(:options) { { auto_delete: true } }
86
+ its(:auto_delete?) { should be_true }
87
+ end
88
+
89
+ context "when pass type: :fanout" do
90
+ let(:options) { { type: :fanout } }
91
+ its(:type) { should eq :fanout }
92
+ end
93
+
94
+ context "when pass :channel" do
95
+ let(:ch) { sess.conn.create_channel }
96
+ let(:options) { { channel: ch } }
97
+ its("channel.id") { should eq ch.id }
98
+ end
99
+ end
100
+
101
+ context "declare_queue" do
102
+ let(:options) {{}}
103
+ let(:queue) { sess.declare_queue queue_name, options }
104
+ subject { queue }
105
+
106
+ after { delete_queue queue }
107
+
108
+ it{ should be }
109
+
110
+ context "by default" do
111
+ its(:name) { should eq queue_name }
112
+ its(:durable?) { should be_true }
113
+ its(:auto_delete?) { should be_false }
114
+ its(:exclusive?) { should be_false }
115
+ its("channel.id") { should eq sess.channel.id }
116
+ end
117
+
118
+ context 'when queue name is nil should use generated name' do
119
+ let(:queue) { sess.declare_queue nil, options }
120
+ its(:name) { should match(/amq\.gen/) }
121
+ end
122
+
123
+ context "when pass durable: false" do
124
+ let(:options) { { durable: false } }
125
+ its(:durable?) { should be_false }
126
+ end
127
+
128
+ context "when pass auto_delete: true" do
129
+ let(:options) { { auto_delete: true } }
130
+ its(:auto_delete?) { should be_true }
131
+ end
132
+
133
+ context "when pass exclusive: true" do
134
+ let(:options) { { exclusive: true } }
135
+ its(:exclusive?) { should be_true }
136
+ end
137
+
138
+ context "when pass :channel" do
139
+ let(:ch) { sess.conn.create_channel }
140
+ let(:options) { { channel: ch } }
141
+ its("channel.id") { should eq ch.id }
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+ require 'timeout'
3
+
4
+ describe Evrone::Common::AMQP::Supervisor::Threaded, jruby: true do
5
+ let(:supervisor) { described_class.new }
6
+ let(:runner) {
7
+ Struct.new(:timeout, :error) do
8
+ def run
9
+ sleep timeout
10
+ raise IgnoreMeError if error
11
+ end
12
+ end
13
+ }
14
+
15
+ after { Evrone::Common::AMQP.config.reset! }
16
+ before { Evrone::Common::AMQP.config.reset! }
17
+
18
+ it { should be }
19
+
20
+ it "should add a new task" do
21
+ expect{
22
+ supervisor.add runner.new(1, false), :run, 1
23
+ }.to change { supervisor.size }.from(0).to(1)
24
+ end
25
+
26
+ context "run" do
27
+ let(:mutex) { Mutex.new }
28
+ let(:collected) { [] }
29
+ let(:len) { 1 }
30
+ let(:runner) {
31
+ Proc.new do
32
+ id = Thread.current[:consumer_id]
33
+ mutex.synchronize do
34
+ collected.push id
35
+ end
36
+ sleep 1
37
+ end
38
+ }
39
+
40
+ before do
41
+ len.times {|n| supervisor.add runner, :call, n + 1 }
42
+ expect(supervisor.size).to eq len
43
+ end
44
+
45
+ context "start one task" do
46
+ it "should be" do
47
+ timeout 2 do
48
+ th = supervisor.run_async
49
+ sleep 0.2
50
+ supervisor.shutdown
51
+ timeout(10) { th.join }
52
+ expect(collected).to eq [1]
53
+ end
54
+ end
55
+ end
56
+
57
+ context "start 5 tasks" do
58
+ let(:len) { 5 }
59
+
60
+ it "should be", slow: true do
61
+ timeout 10 do
62
+ th = supervisor.run_async
63
+ sleep 0.2
64
+ supervisor.shutdown
65
+ timeout(10) { th.join }
66
+ expect(collected.sort).to eq [1,2,3,4,5]
67
+ end
68
+ end
69
+ end
70
+
71
+ context "restart broken tasks" do
72
+ let(:len) { 2 }
73
+ let(:runner) {
74
+ Proc.new do
75
+ sleep 0.1
76
+ id = Thread.current[:consumer_id]
77
+ mutex.synchronize do
78
+ collected.push id
79
+ end
80
+ raise IgnoreMeError
81
+ end
82
+ }
83
+ it "should be" do
84
+ timeout 10 do
85
+ th = supervisor.run_async
86
+ sleep 2.2
87
+ supervisor.shutdown
88
+ timeout(10) { th.join }
89
+ while !collected.empty?
90
+ first, second = collected.shift, collected.shift
91
+ expect([first,second].sort).to eq [1,2]
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ context "raise when attemts limit reached" do
98
+ let(:runner) {
99
+ Proc.new do
100
+ raise IgnoreMeError
101
+ end
102
+ }
103
+
104
+ it "should be" do
105
+ Evrone::Common::AMQP.configure do |c|
106
+ c.spawn_attempts = 1
107
+ end
108
+ th = supervisor.run_async
109
+ timeout 10 do
110
+ expect {
111
+ th.join
112
+ }.to raise_error(Evrone::Common::AMQP::Supervisor::Threaded::SpawnAttemptsLimitReached)
113
+ end
114
+ end
115
+ end
116
+
117
+ def timeout(val, &block)
118
+ Timeout.timeout(val, &block)
119
+ end
120
+ end
121
+
122
+ end
123
+
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evrone::Common::AMQP do
4
+ let(:amqp) { described_class }
5
+ subject { amqp }
6
+
7
+ its(:config) { should be }
8
+ its(:session) { should be }
9
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path '../../lib/evrone/common/amqp', __FILE__
2
+
3
+ require 'rspec/autorun'
4
+
5
+ Dir[File.expand_path("../..", __FILE__) + "/spec/support/**.rb"].each {|f| require f}
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_with :rr
9
+
10
+ config.after(:suite) do
11
+ Evrone::Common::AMQP.close
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ def delete_queue(q)
2
+ Evrone::Common::AMQP.logger.info "[AMQP] delete queue #{q.inspect[0..30]}"
3
+ if q
4
+ q.purge
5
+ q.delete if_unused: false, if_empty: false
6
+ end
7
+ true
8
+ end
9
+
10
+ def delete_exchange(x)
11
+ Evrone::Common::AMQP.logger.info "[AMQP] delete exchnage #{x.inspect[0..30]}"
12
+ x.delete if x
13
+ true
14
+ end
15
+
@@ -0,0 +1 @@
1
+ class IgnoreMeError < Exception ; end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evrone-common-amqp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dmitry Galinsky
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bunny
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0.pre3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0.pre3
27
+ - !ruby/object:Gem::Dependency
28
+ name: evrone-common-rack-builder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: ' Common amqp code '
98
+ email:
99
+ - dima.exe@gmail.com
100
+ executables:
101
+ - amqp_consumers
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - .gitignore
106
+ - .rspec
107
+ - .travis.yml
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/amqp_consumers
113
+ - evrone-common-amqp.gemspec
114
+ - lib/evrone/common/amqp.rb
115
+ - lib/evrone/common/amqp/cli.rb
116
+ - lib/evrone/common/amqp/config.rb
117
+ - lib/evrone/common/amqp/consumer.rb
118
+ - lib/evrone/common/amqp/consumer/ack.rb
119
+ - lib/evrone/common/amqp/consumer/configuration.rb
120
+ - lib/evrone/common/amqp/consumer/publish.rb
121
+ - lib/evrone/common/amqp/consumer/subscribe.rb
122
+ - lib/evrone/common/amqp/formatter.rb
123
+ - lib/evrone/common/amqp/mixins/logger.rb
124
+ - lib/evrone/common/amqp/mixins/with_middleware.rb
125
+ - lib/evrone/common/amqp/session.rb
126
+ - lib/evrone/common/amqp/supervisor/threaded.rb
127
+ - lib/evrone/common/amqp/testing.rb
128
+ - lib/evrone/common/amqp/version.rb
129
+ - spec/integration/multi_threaded_spec.rb
130
+ - spec/integration/threaded_supervisor_spec.rb
131
+ - spec/lib/amqp/consumer_spec.rb
132
+ - spec/lib/amqp/formatter_spec.rb
133
+ - spec/lib/amqp/mixins/with_middleware_spec.rb
134
+ - spec/lib/amqp/session_spec.rb
135
+ - spec/lib/amqp/supervisor/threaded_spec.rb
136
+ - spec/lib/amqp_spec.rb
137
+ - spec/spec_helper.rb
138
+ - spec/support/amqp.rb
139
+ - spec/support/ignore_me_error.rb
140
+ homepage: ''
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: 1.9.3
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.0.2
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: Common amqp code
164
+ test_files:
165
+ - spec/integration/multi_threaded_spec.rb
166
+ - spec/integration/threaded_supervisor_spec.rb
167
+ - spec/lib/amqp/consumer_spec.rb
168
+ - spec/lib/amqp/formatter_spec.rb
169
+ - spec/lib/amqp/mixins/with_middleware_spec.rb
170
+ - spec/lib/amqp/session_spec.rb
171
+ - spec/lib/amqp/supervisor/threaded_spec.rb
172
+ - spec/lib/amqp_spec.rb
173
+ - spec/spec_helper.rb
174
+ - spec/support/amqp.rb
175
+ - spec/support/ignore_me_error.rb