bunny-mock 1.5.0 → 1.6.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +6 -1
- data/bunny-mock.gemspec +3 -1
- data/lib/bunny-mock.rb +1 -0
- data/lib/bunny_mock/channel.rb +45 -3
- data/lib/bunny_mock/exchanges/topic.rb +2 -2
- data/lib/bunny_mock/get_response.rb +11 -1
- data/lib/bunny_mock/queue.rb +29 -5
- data/lib/bunny_mock/session.rb +2 -2
- data/lib/bunny_mock/version.rb +1 -1
- data/spec/integration/message_acknowledgement_spec.rb +87 -0
- data/spec/unit/bunny_mock/queue_spec.rb +33 -0
- metadata +37 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 884e4998df1d5701f0384a2cb1c009d80ed81b67
|
4
|
+
data.tar.gz: 198414bf1eabff599a44310c514cbfa9ce770b0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 868c41d0849c0ea46f2049b15e6ee9122d662f4953089baefc7e35efc37114baff7ea09c6f66bb322a03252820513115526f27e40e2c71c30f312a9526c34e7a
|
7
|
+
data.tar.gz: ee9f02bc843c883b4df2780a3373219bf283d9780219eccea3edc6e7bcfebca177c53806f6a379dba35469c22d2dfc1dc9dec7a2d8462eb8fbad34cc99d69f26
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,9 +2,14 @@
|
|
2
2
|
|
3
3
|
_Add contribution here_
|
4
4
|
|
5
|
+
## v1.6.0
|
6
|
+
|
7
|
+
* [#27](https://github.com/arempe93/bunny-mock/pull/27): Allow `Session#create_channel` to accept additional args - [@eebs](https://github.com/eebs)
|
8
|
+
* [#20](https://github.com/arempe93/bunny-mock/pull/30): Adds implementation of `ack` and `nack` - [@dwhenry](https://github.com/dwhenry)
|
9
|
+
|
5
10
|
## v1.5.0
|
6
11
|
|
7
|
-
*[#20](https://github.com/arempe93/bunny-mock/pull/20): Adds implementation of `Queue#subscribe` - [@baelter](https://github.com/baelter)
|
12
|
+
* [#20](https://github.com/arempe93/bunny-mock/pull/20): Adds implementation of `Queue#subscribe` - [@baelter](https://github.com/baelter)
|
8
13
|
|
9
14
|
## v1.4.0
|
10
15
|
|
data/bunny-mock.gemspec
CHANGED
@@ -26,9 +26,11 @@ Gem::Specification.new do |s|
|
|
26
26
|
end
|
27
27
|
|
28
28
|
s.add_development_dependency 'rake', '~> 10.5.0'
|
29
|
-
s.add_development_dependency 'rubocop'
|
29
|
+
s.add_development_dependency 'rubocop', '= 0.40.0'
|
30
30
|
s.add_development_dependency 'yard'
|
31
31
|
s.add_development_dependency 'rspec', '~> 3.4.0'
|
32
|
+
s.add_development_dependency 'term-ansicolor', '~> 1.3.0'
|
33
|
+
s.add_development_dependency 'tins', '= 1.6.0'
|
32
34
|
s.add_development_dependency 'coveralls'
|
33
35
|
|
34
36
|
s.files = `git ls-files`.split "\n"
|
data/lib/bunny-mock.rb
CHANGED
data/lib/bunny_mock/channel.rb
CHANGED
@@ -14,6 +14,9 @@ module BunnyMock
|
|
14
14
|
# @return [Symbol] Current channel state
|
15
15
|
attr_reader :status
|
16
16
|
|
17
|
+
# @return [Hash] with details of pending, acked and nacked messaged
|
18
|
+
attr_reader :acknowledged_state
|
19
|
+
|
17
20
|
##
|
18
21
|
# Create a new {BunnyMock::Channel} instance
|
19
22
|
#
|
@@ -32,6 +35,7 @@ module BunnyMock
|
|
32
35
|
# initialize exchange and queue storage
|
33
36
|
@exchanges = {}
|
34
37
|
@queues = {}
|
38
|
+
@acknowledged_state = { pending: {}, acked: {}, nacked: {} }
|
35
39
|
|
36
40
|
# set status to opening
|
37
41
|
@status = :opening
|
@@ -256,13 +260,46 @@ module BunnyMock
|
|
256
260
|
end
|
257
261
|
|
258
262
|
##
|
259
|
-
#
|
263
|
+
# Acknowledge message.
|
264
|
+
#
|
265
|
+
# @param [Integer] delivery_tag Delivery tag to acknowledge
|
266
|
+
# @param [Boolean] multiple (false) Should all unacknowledged messages up to this be acknowleded as well?
|
260
267
|
#
|
261
268
|
# @return nil
|
262
269
|
# @api public
|
263
270
|
#
|
264
|
-
def
|
265
|
-
|
271
|
+
def ack(delivery_tag, multiple = false)
|
272
|
+
if multiple
|
273
|
+
@acknowledged_state[:pending].keys.each do |key|
|
274
|
+
ack(key, false) if key <= delivery_tag
|
275
|
+
end
|
276
|
+
elsif @acknowledged_state[:pending].key?(delivery_tag)
|
277
|
+
update_acknowledgement_state(delivery_tag, :acked)
|
278
|
+
end
|
279
|
+
nil
|
280
|
+
end
|
281
|
+
alias acknowledge ack
|
282
|
+
|
283
|
+
##
|
284
|
+
# Unacknowledge message.
|
285
|
+
#
|
286
|
+
# @param [Integer] delivery_tag Delivery tag to acknowledge
|
287
|
+
# @param [Boolean] multiple (false) Should all unacknowledged messages up to this be rejected as well?
|
288
|
+
# @param [Boolean] requeue (false) Should this message be requeued instead of dropping it?
|
289
|
+
#
|
290
|
+
# @return nil
|
291
|
+
# @api public
|
292
|
+
#
|
293
|
+
def nack(delivery_tag, multiple = false, requeue = false)
|
294
|
+
if multiple
|
295
|
+
@acknowledged_state[:pending].keys.each do |key|
|
296
|
+
nack(key, false, requeue) if key <= delivery_tag
|
297
|
+
end
|
298
|
+
elsif @acknowledged_state[:pending].key?(delivery_tag)
|
299
|
+
delivery, header, body = update_acknowledgement_state(delivery_tag, :nacked)
|
300
|
+
delivery.queue.publish(body, header.to_hash) if requeue
|
301
|
+
end
|
302
|
+
nil
|
266
303
|
end
|
267
304
|
|
268
305
|
##
|
@@ -345,5 +382,10 @@ module BunnyMock
|
|
345
382
|
def xchg_find_or_create(name, opts = {})
|
346
383
|
@connection.find_exchange(name) || Exchange.declare(self, name, opts)
|
347
384
|
end
|
385
|
+
|
386
|
+
# @private
|
387
|
+
def update_acknowledgement_state(delivery_tag, new_state)
|
388
|
+
@acknowledged_state[new_state][delivery_tag] = @acknowledged_state[:pending].delete(delivery_tag)
|
389
|
+
end
|
348
390
|
end
|
349
391
|
end
|
@@ -4,11 +4,11 @@ module BunnyMock
|
|
4
4
|
class Topic < BunnyMock::Exchange
|
5
5
|
# @private
|
6
6
|
# @return [String] Multiple subdomain wildcard
|
7
|
-
MULTI_WILDCARD = '#'
|
7
|
+
MULTI_WILDCARD = '#'.freeze
|
8
8
|
|
9
9
|
# @private
|
10
10
|
# @return [String] Single subdomain wildcard
|
11
|
-
SINGLE_WILDCARD = '*'
|
11
|
+
SINGLE_WILDCARD = '*'.freeze
|
12
12
|
|
13
13
|
#
|
14
14
|
# API
|
@@ -14,11 +14,15 @@ module BunnyMock
|
|
14
14
|
# @return [BunnyMock::Channel] Channel the response is from
|
15
15
|
attr_reader :channel
|
16
16
|
|
17
|
+
# @return [BunnyMock::Queue] Queue the response is from
|
18
|
+
attr_reader :queue
|
19
|
+
|
17
20
|
# @private
|
18
21
|
def initialize(channel, queue, opts = {})
|
19
22
|
@channel = channel
|
23
|
+
@queue = queue
|
20
24
|
@hash = {
|
21
|
-
delivery_tag:
|
25
|
+
delivery_tag: self.class.next_delivery_tag,
|
22
26
|
redelivered: false,
|
23
27
|
exchange: opts.fetch(:exchange, ''),
|
24
28
|
routing_key: opts.fetch(:routing_key, queue.name)
|
@@ -72,5 +76,11 @@ module BunnyMock
|
|
72
76
|
def routing_key
|
73
77
|
@hash[:routing_key]
|
74
78
|
end
|
79
|
+
|
80
|
+
# @return [Integer] incrementing numerically value to support `#ack` with multiple=true
|
81
|
+
def self.next_delivery_tag
|
82
|
+
@delivery_tag ||= 0
|
83
|
+
@delivery_tag += 1
|
84
|
+
end
|
75
85
|
end
|
76
86
|
end
|
data/lib/bunny_mock/queue.rb
CHANGED
@@ -72,14 +72,30 @@ module BunnyMock
|
|
72
72
|
##
|
73
73
|
# Adds a consumer to the queue (subscribes for message deliveries).
|
74
74
|
#
|
75
|
-
#
|
76
|
-
# to the queue
|
75
|
+
# Params are so they can be used when the message is processed. Takes a block which is called when a message
|
76
|
+
# is delivered to the queue
|
77
77
|
#
|
78
78
|
# @api public
|
79
79
|
#
|
80
|
-
def subscribe(*
|
80
|
+
def subscribe(*args, &block)
|
81
81
|
@consumers ||= []
|
82
|
-
@consumers << block
|
82
|
+
@consumers << [block, args]
|
83
|
+
yield_consumers
|
84
|
+
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Adds a specific consumer object to the queue (subscribes for message deliveries).
|
90
|
+
#
|
91
|
+
# @param [#call] consumer A subclass of Bunny::Consumer or any callable object
|
92
|
+
# Secondary params are so they can be used when the message is processed.
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
#
|
96
|
+
def subscribe_with(consumer, *args)
|
97
|
+
@consumers ||= []
|
98
|
+
@consumers << [consumer, args]
|
83
99
|
yield_consumers
|
84
100
|
|
85
101
|
self
|
@@ -241,13 +257,21 @@ module BunnyMock
|
|
241
257
|
# @private
|
242
258
|
def yield_consumers
|
243
259
|
return if @consumers.nil?
|
244
|
-
@consumers.each do |c|
|
260
|
+
@consumers.each do |c, args|
|
245
261
|
# rubocop:disable AssignmentInCondition
|
246
262
|
while message = all.pop
|
247
263
|
response = pop_response(message)
|
264
|
+
store_acknowledgement(response, args)
|
248
265
|
c.call(response)
|
249
266
|
end
|
250
267
|
end
|
251
268
|
end
|
269
|
+
|
270
|
+
def store_acknowledgement(response, args)
|
271
|
+
if args[0].is_a?(Hash) && args[0][:manual_ack]
|
272
|
+
delivery_tag = response[0][:delivery_tag]
|
273
|
+
@channel.acknowledged_state[:pending][delivery_tag] = response
|
274
|
+
end
|
275
|
+
end
|
252
276
|
end
|
253
277
|
end
|
data/lib/bunny_mock/session.rb
CHANGED
@@ -88,9 +88,9 @@ module BunnyMock
|
|
88
88
|
#
|
89
89
|
# @return [BunnyMock::Channel] Channel instance
|
90
90
|
# @api public
|
91
|
-
def create_channel(n = nil, _pool_size = 1)
|
91
|
+
def create_channel(n = nil, _pool_size = 1, *_args)
|
92
92
|
# raise same error as {Bunny::Session#create_channel}
|
93
|
-
raise ArgumentError, 'channel number 0 is reserved in the protocol and cannot be used' if n
|
93
|
+
raise ArgumentError, 'channel number 0 is reserved in the protocol and cannot be used' if n && n.zero?
|
94
94
|
|
95
95
|
# return cached channel if exists
|
96
96
|
return @channels[n] if n && @channels.key?(n)
|
data/lib/bunny_mock/version.rb
CHANGED
@@ -0,0 +1,87 @@
|
|
1
|
+
describe BunnyMock::Channel, 'acknowledgement' do
|
2
|
+
let(:queue) { @channel.queue('test.q') }
|
3
|
+
let(:delivery_tags) { {} }
|
4
|
+
|
5
|
+
context 'when `manual_ack` = true' do
|
6
|
+
before do
|
7
|
+
queue.subscribe(manual_ack: true) do |delivery, _headers, body|
|
8
|
+
delivery_tags[body] = delivery[:delivery_tag]
|
9
|
+
end
|
10
|
+
queue.publish 'Another message on the queue'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should allow messages which have been acked to be identified' do
|
14
|
+
queue.publish 'Message to acknowledge'
|
15
|
+
delivery_tag = delivery_tags['Message to acknowledge']
|
16
|
+
@channel.ack delivery_tag
|
17
|
+
|
18
|
+
expect(@channel.acknowledged_state[:pending]).not_to include(delivery_tag)
|
19
|
+
expect(@channel.acknowledged_state[:acked]).to include(delivery_tag)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should allow messages which have not been acked to be identified' do
|
23
|
+
queue.publish 'Message without acknowledgement'
|
24
|
+
delivery_tag = delivery_tags['Message without acknowledgement']
|
25
|
+
|
26
|
+
expect(@channel.acknowledged_state[:pending]).to include(delivery_tag)
|
27
|
+
expect(@channel.acknowledged_state[:acked]).not_to include(delivery_tag)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should allow messages which have been nacked to be identified' do
|
31
|
+
queue.publish 'Message to nack'
|
32
|
+
delivery_tag = delivery_tags['Message to nack']
|
33
|
+
@channel.nack delivery_tag
|
34
|
+
|
35
|
+
expect(@channel.acknowledged_state[:pending]).not_to include(delivery_tag)
|
36
|
+
expect(@channel.acknowledged_state[:acked]).not_to include(delivery_tag)
|
37
|
+
expect(@channel.acknowledged_state[:nacked]).to include(delivery_tag)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should requeue messages with have been nacked with `requeue` = true' do
|
41
|
+
queue.publish 'Message to nack'
|
42
|
+
delivery_tag = delivery_tags['Message to nack']
|
43
|
+
@channel.nack delivery_tag, false, true
|
44
|
+
new_delivery_tag = delivery_tags['Message to nack']
|
45
|
+
|
46
|
+
expect(@channel.acknowledged_state[:pending]).not_to include(delivery_tag)
|
47
|
+
expect(@channel.acknowledged_state[:acked]).not_to include(delivery_tag)
|
48
|
+
expect(@channel.acknowledged_state[:nacked]).to include(delivery_tag)
|
49
|
+
|
50
|
+
expect(@channel.acknowledged_state[:pending]).to include(new_delivery_tag)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should allow multiple messages to be acked when `multiple` = true' do
|
54
|
+
queue.publish 'Message to be automatically acked'
|
55
|
+
delivery_tag_1 = delivery_tags['Message to be automatically acked']
|
56
|
+
queue.publish 'Message to acked'
|
57
|
+
delivery_tag_2 = delivery_tags['Message to acked']
|
58
|
+
queue.publish 'Message to be left as pending'
|
59
|
+
delivery_tag_3 = delivery_tags['Message to be left as pending']
|
60
|
+
|
61
|
+
@channel.ack delivery_tag_2, true
|
62
|
+
|
63
|
+
expect(@channel.acknowledged_state[:pending]).not_to include(delivery_tag_1)
|
64
|
+
expect(@channel.acknowledged_state[:pending]).not_to include(delivery_tag_2)
|
65
|
+
expect(@channel.acknowledged_state[:pending]).to include(delivery_tag_3)
|
66
|
+
expect(@channel.acknowledged_state[:acked]).to include(delivery_tag_1)
|
67
|
+
expect(@channel.acknowledged_state[:acked]).to include(delivery_tag_2)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should allow multiple messages to be nacked when `multiple` = true' do
|
71
|
+
queue.publish 'Message to be automatically nacked'
|
72
|
+
delivery_tag_1 = delivery_tags['Message to be automatically nacked']
|
73
|
+
queue.publish 'Message to nacked'
|
74
|
+
delivery_tag_2 = delivery_tags['Message to nacked']
|
75
|
+
queue.publish 'Message to be left as pending'
|
76
|
+
delivery_tag_3 = delivery_tags['Message to be left as pending']
|
77
|
+
|
78
|
+
@channel.nack delivery_tag_2, true
|
79
|
+
|
80
|
+
expect(@channel.acknowledged_state[:pending]).not_to include(delivery_tag_1)
|
81
|
+
expect(@channel.acknowledged_state[:pending]).not_to include(delivery_tag_2)
|
82
|
+
expect(@channel.acknowledged_state[:pending]).to include(delivery_tag_3)
|
83
|
+
expect(@channel.acknowledged_state[:nacked]).to include(delivery_tag_1)
|
84
|
+
expect(@channel.acknowledged_state[:nacked]).to include(delivery_tag_2)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -172,6 +172,39 @@ describe BunnyMock::Queue do
|
|
172
172
|
end
|
173
173
|
@queue.publish 'test'
|
174
174
|
end
|
175
|
+
|
176
|
+
it 'should create responses with uniq delivery_tags' do
|
177
|
+
delivery_tags = []
|
178
|
+
@queue.subscribe do |delivery, _headers, _body|
|
179
|
+
delivery_tags << delivery[:delivery_tag]
|
180
|
+
end
|
181
|
+
@queue.publish 'test one'
|
182
|
+
@queue.publish 'test two'
|
183
|
+
|
184
|
+
expect(delivery_tags.uniq.count).to eq(2)
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'when `manual_ack` is set to true' do
|
188
|
+
|
189
|
+
it 'should mark the message as unacknowledged on the channel before processing' do
|
190
|
+
@queue.subscribe(manual_ack: true) do |delivery, _headers, _body|
|
191
|
+
expect(@channel.acknowledged_state[:pending]).to include(delivery[:delivery_tag])
|
192
|
+
end
|
193
|
+
@queue.publish 'test'
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context '#subscribe_with' do
|
199
|
+
|
200
|
+
it 'should consume messages delivered' do
|
201
|
+
consumer = proc do |_delivery, _headers, body|
|
202
|
+
expect(body).to eq('test')
|
203
|
+
end
|
204
|
+
|
205
|
+
@queue.subscribe_with consumer
|
206
|
+
@queue.publish 'test'
|
207
|
+
end
|
175
208
|
end
|
176
209
|
|
177
210
|
context '#purge' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bunny-mock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Rempe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bunny
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 0.40.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 0.40.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: yard
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 3.4.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: term-ansicolor
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.3.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.3.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: tins
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.6.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.6.0
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: coveralls
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,6 +156,7 @@ files:
|
|
128
156
|
- lib/bunny_mock/queue.rb
|
129
157
|
- lib/bunny_mock/session.rb
|
130
158
|
- lib/bunny_mock/version.rb
|
159
|
+
- spec/integration/message_acknowledgement_spec.rb
|
131
160
|
- spec/integration/queue_pop_spec.rb
|
132
161
|
- spec/integration/queue_subscribe_spec.rb
|
133
162
|
- spec/spec_helper.rb
|
@@ -159,11 +188,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
188
|
version: '0'
|
160
189
|
requirements: []
|
161
190
|
rubyforge_project:
|
162
|
-
rubygems_version: 2.
|
191
|
+
rubygems_version: 2.6.4
|
163
192
|
signing_key:
|
164
193
|
specification_version: 4
|
165
194
|
summary: Mocking for the popular Bunny client for RabbitMQ
|
166
195
|
test_files:
|
196
|
+
- spec/integration/message_acknowledgement_spec.rb
|
167
197
|
- spec/integration/queue_pop_spec.rb
|
168
198
|
- spec/integration/queue_subscribe_spec.rb
|
169
199
|
- spec/spec_helper.rb
|