bunny-mock 1.1.0 → 1.2.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/.editorconfig +12 -0
- data/.rubocop.yml +9 -0
- data/.rubocop_todo.yml +65 -0
- data/.travis.yml +6 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +1 -11
- data/README.md +61 -88
- data/Rakefile +29 -0
- data/UPGRADING.md +12 -0
- data/bunny-mock.gemspec +19 -16
- data/lib/bunny-mock.rb +30 -29
- data/lib/bunny_mock/channel.rb +275 -274
- data/lib/bunny_mock/exchange.rb +258 -267
- data/lib/bunny_mock/exchanges/direct.rb +20 -19
- data/lib/bunny_mock/exchanges/fanout.rb +20 -23
- data/lib/bunny_mock/exchanges/headers.rb +27 -26
- data/lib/bunny_mock/exchanges/topic.rb +45 -49
- data/lib/bunny_mock/queue.rb +210 -209
- data/lib/bunny_mock/session.rb +171 -151
- data/lib/bunny_mock/version.rb +3 -2
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/bunny_mock/exchange_spec.rb +10 -10
- data/spec/unit/bunny_mock/queue_spec.rb +7 -7
- data/spec/unit/bunny_mock/session_spec.rb +74 -48
- metadata +86 -14
- data/CHANGELOG +0 -8
- data/lib/bunny_mock/exceptions.rb +0 -16
@@ -1,24 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module BunnyMock
|
2
|
-
|
3
|
-
|
3
|
+
module Exchanges
|
4
|
+
class Direct < BunnyMock::Exchange
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
#
|
7
|
+
# API
|
8
|
+
#
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
##
|
11
|
+
# Deliver a message to route with direct key match
|
12
|
+
#
|
13
|
+
# @param [Object] payload Message content
|
14
|
+
# @param [Hash] opts Message properties
|
15
|
+
# @param [String] key Routing key
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
#
|
19
|
+
def deliver(payload, opts, key)
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
@routes[key].publish payload, opts if @routes[key]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
24
25
|
end
|
@@ -1,28 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module BunnyMock
|
2
|
-
|
3
|
-
|
3
|
+
module Exchanges
|
4
|
+
class Fanout < BunnyMock::Exchange
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
#
|
7
|
+
# API
|
8
|
+
#
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
##
|
11
|
+
# Deliver a message to all routes
|
12
|
+
#
|
13
|
+
# @param [Object] payload Message content
|
14
|
+
# @param [Hash] opts Message properties
|
15
|
+
# @param [String] key Routing key
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
#
|
19
|
+
def deliver(payload, opts, _key)
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
21
|
+
@routes.each_value { |destination| destination.publish(payload, opts) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
28
25
|
end
|
@@ -1,33 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module BunnyMock
|
2
|
-
|
3
|
-
|
3
|
+
module Exchanges
|
4
|
+
class Header < BunnyMock::Exchange
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
# @private
|
7
|
+
# @return [Regexp] Any match
|
8
|
+
ANY = /^any$/i
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
# @private
|
11
|
+
# @return [Regexp] All match
|
12
|
+
ALL = /^all$/i
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
#
|
15
|
+
# API
|
16
|
+
#
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
##
|
19
|
+
# Deliver a message to routes with header matches
|
20
|
+
#
|
21
|
+
# @param [Object] payload Message content
|
22
|
+
# @param [Hash] opts Message properties
|
23
|
+
# @param [String] key Routing key
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
#
|
27
|
+
def deliver(payload, opts, key)
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
# ~: proper headers exchange implementation
|
30
|
+
@routes[key].publish payload, opts if @routes[key]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
33
34
|
end
|
@@ -1,51 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module BunnyMock
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@routes[route].publish payload, opts if route =~ key
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
3
|
+
module Exchanges
|
4
|
+
class Topic < BunnyMock::Exchange
|
5
|
+
|
6
|
+
# @private
|
7
|
+
# @return [String] Multiple subdomain wildcard
|
8
|
+
MULTI_WILDCARD = '#'
|
9
|
+
|
10
|
+
# @private
|
11
|
+
# @return [String] Single subdomain wildcard
|
12
|
+
SINGLE_WILDCARD = '*'
|
13
|
+
|
14
|
+
#
|
15
|
+
# API
|
16
|
+
#
|
17
|
+
|
18
|
+
##
|
19
|
+
# Deliver a message to route with keys matching wildcards
|
20
|
+
#
|
21
|
+
# @param [Object] payload Message content
|
22
|
+
# @param [Hash] opts Message properties
|
23
|
+
# @param [String] key Routing key
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
#
|
27
|
+
def deliver(payload, opts, key)
|
28
|
+
|
29
|
+
# escape periods with backslash for regex
|
30
|
+
key.gsub!('.', '\.')
|
31
|
+
|
32
|
+
# replace single wildcards with regex for a single domain
|
33
|
+
key.gsub!(SINGLE_WILDCARD, '(?:\w+)')
|
34
|
+
|
35
|
+
# replace multi wildcards with regex for many domains separated by '.'
|
36
|
+
key.gsub!(MULTI_WILDCARD, '\w+\.?')
|
37
|
+
|
38
|
+
# turn key into regex
|
39
|
+
key = Regexp.new(key)
|
40
|
+
|
41
|
+
@routes.each do |route, destination|
|
42
|
+
destination.publish(payload, opts) if route =~ key
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
51
47
|
end
|
data/lib/bunny_mock/queue.rb
CHANGED
@@ -1,211 +1,212 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module BunnyMock
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
3
|
+
class Queue
|
4
|
+
|
5
|
+
#
|
6
|
+
# API
|
7
|
+
#
|
8
|
+
|
9
|
+
# @return {BunnyMock::Channel} Channel used by queue
|
10
|
+
attr_reader :channel
|
11
|
+
|
12
|
+
# @return [String] Queue name
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
# @return [Hash] Creation options
|
16
|
+
attr_reader :opts
|
17
|
+
|
18
|
+
##
|
19
|
+
# Create a new [BunnyMock::Queue] instance
|
20
|
+
#
|
21
|
+
# @param [BunnyMock::Channel] channel Channel this queue will use
|
22
|
+
# @param [String] name Name of queue
|
23
|
+
# @param [Hash] opts Creation options
|
24
|
+
#
|
25
|
+
# @see BunnyMock::Channel#queue
|
26
|
+
#
|
27
|
+
def initialize(channel, name = '', opts = {})
|
28
|
+
|
29
|
+
# Store creation information
|
30
|
+
@channel = channel
|
31
|
+
@name = name
|
32
|
+
@opts = opts
|
33
|
+
|
34
|
+
# Store messages
|
35
|
+
@messages = []
|
36
|
+
end
|
37
|
+
|
38
|
+
# @group Bunny API
|
39
|
+
|
40
|
+
##
|
41
|
+
# Publish a message
|
42
|
+
#
|
43
|
+
# @param [Object] payload Message payload
|
44
|
+
# @param [Hash] opts Message properties
|
45
|
+
#
|
46
|
+
# @option opts [String] :routing_key Routing key
|
47
|
+
# @option opts [Boolean] :persistent Should the message be persisted to disk?
|
48
|
+
# @option opts [Boolean] :mandatory Should the message be returned if it cannot be routed to any queue?
|
49
|
+
# @option opts [Integer] :timestamp A timestamp associated with this message
|
50
|
+
# @option opts [Integer] :expiration Expiration time after which the message will be deleted
|
51
|
+
# @option opts [String] :type Message type, e.g. what type of event or command this message represents. Can be any string
|
52
|
+
# @option opts [String] :reply_to Queue name other apps should send the response to
|
53
|
+
# @option opts [String] :content_type Message content type (e.g. application/json)
|
54
|
+
# @option opts [String] :content_encoding Message content encoding (e.g. gzip)
|
55
|
+
# @option opts [String] :correlation_id Message correlated to this one, e.g. what request this message is a reply for
|
56
|
+
# @option opts [Integer] :priority Message priority, 0 to 9. Not used by RabbitMQ, only applications
|
57
|
+
# @option opts [String] :message_id Any message identifier
|
58
|
+
# @option opts [String] :user_id Optional user ID. Verified by RabbitMQ against the actual connection username
|
59
|
+
# @option opts [String] :app_id Optional application ID
|
60
|
+
#
|
61
|
+
# @return [BunnyMock::Queue] self
|
62
|
+
# @see {BunnyMock::Exchange#publish}
|
63
|
+
# @api public
|
64
|
+
#
|
65
|
+
def publish(payload, opts = {})
|
66
|
+
|
67
|
+
check_queue_deleted!
|
68
|
+
|
69
|
+
# add to messages
|
70
|
+
@messages << { message: payload, options: opts }
|
71
|
+
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Bind this queue to an exchange
|
77
|
+
#
|
78
|
+
# @param [BunnyMock::Exchange,String] exchange Exchange to bind to
|
79
|
+
# @param [Hash] opts Binding properties
|
80
|
+
#
|
81
|
+
# @option opts [String] :routing_key Custom routing key
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
#
|
85
|
+
def bind(exchange, opts = {})
|
86
|
+
|
87
|
+
check_queue_deleted!
|
88
|
+
|
89
|
+
if exchange.respond_to?(:add_route)
|
90
|
+
|
91
|
+
# we can do the binding ourselves
|
92
|
+
exchange.add_route opts.fetch(:routing_key, @name), self
|
93
|
+
|
94
|
+
else
|
95
|
+
|
96
|
+
# we need the channel to lookup the exchange
|
97
|
+
@channel.queue_bind self, opts.fetch(:routing_key, @name), exchange
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Unbind this queue from an exchange
|
103
|
+
#
|
104
|
+
# @param [BunnyMock::Exchange,String] exchange Exchange to unbind from
|
105
|
+
# @param [Hash] opts Binding properties
|
106
|
+
#
|
107
|
+
# @option opts [String] :routing_key Custom routing key
|
108
|
+
#
|
109
|
+
# @api public
|
110
|
+
#
|
111
|
+
def unbind(exchange, opts = {})
|
112
|
+
|
113
|
+
check_queue_deleted!
|
114
|
+
|
115
|
+
if exchange.respond_to?(:remove_route)
|
116
|
+
|
117
|
+
# we can do the unbinding ourselves
|
118
|
+
exchange.remove_route opts.fetch(:routing_key, @name)
|
119
|
+
|
120
|
+
else
|
121
|
+
|
122
|
+
# we need the channel to lookup the exchange
|
123
|
+
@channel.queue_unbind opts.fetch(:routing_key, @name), exchange
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# @endgroup
|
128
|
+
|
129
|
+
##
|
130
|
+
# Check if this queue is bound to the exchange
|
131
|
+
#
|
132
|
+
# @param [BunnyMock::Exchange,String] exchange Exchange to test
|
133
|
+
# @param [Hash] opts Binding properties
|
134
|
+
#
|
135
|
+
# @option opts [String] :routing_key Routing key from binding
|
136
|
+
#
|
137
|
+
# @return [Boolean] true if this queue is bound to the given exchange, false otherwise
|
138
|
+
# @api public
|
139
|
+
#
|
140
|
+
def bound_to?(exchange, opts = {})
|
141
|
+
|
142
|
+
check_queue_deleted!
|
143
|
+
|
144
|
+
if exchange.respond_to?(:routes_to?)
|
145
|
+
|
146
|
+
# we can do the check ourselves
|
147
|
+
exchange.routes_to? opts.fetch(:routing_key, @name)
|
148
|
+
|
149
|
+
else
|
150
|
+
|
151
|
+
# we need the channel to lookup the exchange
|
152
|
+
@channel.xchg_routes_to? opts.fetch(:routing_key, @name), exchange
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# Count of messages in queue
|
158
|
+
#
|
159
|
+
# @return [Integer] Number of messages in queue
|
160
|
+
# @api public
|
161
|
+
#
|
162
|
+
def message_count
|
163
|
+
@messages.count
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Get oldest message in queue
|
168
|
+
#
|
169
|
+
# @return [Hash] Message data
|
170
|
+
# @api public
|
171
|
+
#
|
172
|
+
def pop
|
173
|
+
@messages.shift
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# Clear all messages in queue
|
178
|
+
#
|
179
|
+
# @api public
|
180
|
+
#
|
181
|
+
def purge
|
182
|
+
@messages = []
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Get all messages in queue
|
187
|
+
#
|
188
|
+
# @return [Array] All messages
|
189
|
+
# @api public
|
190
|
+
#
|
191
|
+
def all
|
192
|
+
@messages
|
193
|
+
end
|
194
|
+
|
195
|
+
##
|
196
|
+
# Deletes this queue
|
197
|
+
#
|
198
|
+
# @api public
|
199
|
+
#
|
200
|
+
def delete
|
201
|
+
|
202
|
+
@channel.deregister_queue self
|
203
|
+
|
204
|
+
@deleted = true
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
def check_queue_deleted!
|
209
|
+
raise 'Queue has been deleted' if @deleted
|
210
|
+
end
|
211
|
+
end
|
211
212
|
end
|