symphony 0.3.0.pre20140327204419
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.simplecov +9 -0
- data/ChangeLog +508 -0
- data/History.rdoc +15 -0
- data/Manifest.txt +30 -0
- data/README.rdoc +89 -0
- data/Rakefile +77 -0
- data/TODO.md +5 -0
- data/USAGE.rdoc +381 -0
- data/bin/symphony +8 -0
- data/bin/symphony-task +10 -0
- data/etc/config.yml.example +9 -0
- data/lib/symphony/daemon.rb +372 -0
- data/lib/symphony/metrics.rb +84 -0
- data/lib/symphony/mixins.rb +75 -0
- data/lib/symphony/queue.rb +313 -0
- data/lib/symphony/routing.rb +98 -0
- data/lib/symphony/signal_handling.rb +107 -0
- data/lib/symphony/task.rb +407 -0
- data/lib/symphony/tasks/auditor.rb +51 -0
- data/lib/symphony/tasks/failure_logger.rb +106 -0
- data/lib/symphony/tasks/pinger.rb +64 -0
- data/lib/symphony/tasks/simulator.rb +57 -0
- data/lib/symphony/tasks/ssh.rb +126 -0
- data/lib/symphony/tasks/sshscript.rb +168 -0
- data/lib/symphony.rb +56 -0
- data/spec/helpers.rb +36 -0
- data/spec/symphony/mixins_spec.rb +78 -0
- data/spec/symphony/queue_spec.rb +368 -0
- data/spec/symphony/task_spec.rb +147 -0
- data/spec/symphony_spec.rb +14 -0
- data.tar.gz.sig +0 -0
- metadata +332 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,368 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../helpers'
|
4
|
+
|
5
|
+
require 'symphony/queue'
|
6
|
+
|
7
|
+
describe Symphony::Queue do
|
8
|
+
|
9
|
+
|
10
|
+
before( :each ) do
|
11
|
+
described_class.configure( broker_uri: 'amqp://example.com/%2Ftesty' )
|
12
|
+
described_class.reset
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
it_should_behave_like "an object with Configurability"
|
17
|
+
|
18
|
+
|
19
|
+
it "can build a Hash of AMQP options from its configuration" do
|
20
|
+
expect( described_class.amqp_session_options ).to include({
|
21
|
+
heartbeat: :server,
|
22
|
+
logger: Loggability[ Symphony ],
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
it "can use the Bunny-style configuration Hash" do
|
28
|
+
described_class.configure( host: 'spimethorpe.com', port: 23456 )
|
29
|
+
expect( described_class.amqp_session_options ).to include({
|
30
|
+
host: 'spimethorpe.com',
|
31
|
+
port: 23456,
|
32
|
+
heartbeat: :server,
|
33
|
+
logger: Loggability[ Symphony ],
|
34
|
+
})
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
it "assumes Bunny-style configuration Hash if no broker uri is configured" do
|
39
|
+
described_class.configure( host: 'spimethorpe.com', port: 23456 )
|
40
|
+
described_class.broker_uri = nil
|
41
|
+
|
42
|
+
expect( Bunny ).to receive( :new ).
|
43
|
+
with( described_class.amqp_session_options )
|
44
|
+
|
45
|
+
described_class.amqp_session
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
context "bunny interaction" do
|
50
|
+
|
51
|
+
|
52
|
+
it "can build a new Bunny session using the loaded configuration" do
|
53
|
+
clowney = double( "Bunny session" )
|
54
|
+
expect( Bunny::Session ).to receive( :new ).
|
55
|
+
with( described_class.broker_uri, described_class.amqp_session_options ).
|
56
|
+
and_return( clowney )
|
57
|
+
|
58
|
+
expect( described_class.amqp_session ).to be( clowney )
|
59
|
+
end
|
60
|
+
|
61
|
+
it "doesn't recreate the bunny session across multiple calls" do
|
62
|
+
bunny = double( "Bunny session" )
|
63
|
+
expect( Bunny::Session ).to receive( :new ).
|
64
|
+
once.
|
65
|
+
with( described_class.broker_uri, described_class.amqp_session_options ).
|
66
|
+
and_return( bunny )
|
67
|
+
|
68
|
+
expect( described_class.amqp_session ).to be( bunny )
|
69
|
+
expect( described_class.amqp_session ).to be( bunny )
|
70
|
+
end
|
71
|
+
|
72
|
+
it "can open a channel on the Bunny session" do
|
73
|
+
bunny = double( "Bunny session" )
|
74
|
+
channel = double( "Bunny channel" )
|
75
|
+
expect( Bunny ).to receive( :new ).
|
76
|
+
with( described_class.broker_uri, described_class.amqp_session_options ).
|
77
|
+
and_return( bunny )
|
78
|
+
expect( bunny ).to receive( :start )
|
79
|
+
expect( bunny ).to receive( :create_channel ).and_return( channel )
|
80
|
+
|
81
|
+
expect( described_class.amqp_channel ).to be( channel )
|
82
|
+
end
|
83
|
+
|
84
|
+
it "can fetch the configured exchange" do
|
85
|
+
bunny = double( "Bunny session" )
|
86
|
+
channel = double( "Bunny channel" )
|
87
|
+
exchange = double( "Symphony exchange" )
|
88
|
+
expect( Bunny ).to receive( :new ).
|
89
|
+
with( described_class.broker_uri, described_class.amqp_session_options ).
|
90
|
+
and_return( bunny )
|
91
|
+
expect( bunny ).to receive( :start )
|
92
|
+
expect( bunny ).to receive( :create_channel ).and_return( channel )
|
93
|
+
expect( channel ).to receive( :topic ).with( described_class.exchange, passive: true ).
|
94
|
+
and_return( exchange )
|
95
|
+
|
96
|
+
expect( described_class.amqp_exchange ).to be( exchange )
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
context "instance" do
|
102
|
+
|
103
|
+
let( :queue ) { described_class.for_task(testing_task_class) }
|
104
|
+
|
105
|
+
let( :testing_task_class ) { Class.new(Symphony::Task) }
|
106
|
+
let( :session ) { double("Bunny session", :start => true ) }
|
107
|
+
|
108
|
+
before( :each ) do
|
109
|
+
allow( Bunny ).to receive( :new ).and_return( session )
|
110
|
+
described_class.amqp[:exchange] = double( "AMQP exchange", name: 'the_exchange' )
|
111
|
+
described_class.amqp[:channel] = double( "AMQP channel" )
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
it "creates an auto-deleted queue for the task if one doesn't already exist" do
|
116
|
+
testing_task_class.subscribe_to( 'floppy.rabbit.#' )
|
117
|
+
expect( described_class.amqp_channel ).to receive( :queue ).
|
118
|
+
with( queue.name, passive: true ).
|
119
|
+
and_raise( Bunny::NotFound.new("no such queue", described_class.amqp_channel, true) )
|
120
|
+
expect( described_class.amqp_channel ).to receive( :open? ).
|
121
|
+
and_return( false )
|
122
|
+
|
123
|
+
# Channel is reset after queue creation fails
|
124
|
+
new_channel = double( "New AMQP channel" )
|
125
|
+
amqp_queue = double( "AMQP queue" )
|
126
|
+
allow( described_class.amqp_session ).to receive( :create_channel ).
|
127
|
+
and_return( new_channel )
|
128
|
+
expect( new_channel ).to receive( :prefetch ).
|
129
|
+
with( Symphony::Queue::DEFAULT_PREFETCH )
|
130
|
+
expect( new_channel ).to receive( :queue ).
|
131
|
+
with( queue.name, auto_delete: true ).
|
132
|
+
and_return( amqp_queue )
|
133
|
+
expect( amqp_queue ).to receive( :bind ).
|
134
|
+
with( described_class.amqp_exchange, routing_key: 'floppy.rabbit.#' )
|
135
|
+
|
136
|
+
expect( queue.create_amqp_queue ).to be( amqp_queue )
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
it "re-uses the existing queue on the broker if it already exists" do
|
141
|
+
amqp_queue = double( "AMQP queue" )
|
142
|
+
expect( described_class.amqp_channel ).to receive( :queue ).
|
143
|
+
with( queue.name, passive: true ).
|
144
|
+
and_return( amqp_queue )
|
145
|
+
expect( described_class.amqp_channel ).to receive( :prefetch ).
|
146
|
+
with( Symphony::Queue::DEFAULT_PREFETCH )
|
147
|
+
|
148
|
+
expect( queue.create_amqp_queue ).to be( amqp_queue )
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
it "subscribes to the message queue with a configured consumer to wait for messages" do
|
153
|
+
amqp_queue = double( "AMQP queue", channel: described_class.amqp_channel )
|
154
|
+
consumer = double( "Bunny consumer", channel: described_class.amqp_channel )
|
155
|
+
|
156
|
+
expect( described_class.amqp_channel ).to receive( :queue ).
|
157
|
+
with( testing_task_class.queue_name, passive: true ).
|
158
|
+
and_return( amqp_queue )
|
159
|
+
expect( described_class.amqp_channel ).to receive( :prefetch ).
|
160
|
+
with( Symphony::Queue::DEFAULT_PREFETCH )
|
161
|
+
|
162
|
+
expect( Bunny::Consumer ).to receive( :new ).
|
163
|
+
with( described_class.amqp_channel, amqp_queue, queue.consumer_tag, false ).
|
164
|
+
and_return( consumer )
|
165
|
+
|
166
|
+
# Set up an artificial method to call the delivery callback that we can later
|
167
|
+
# call ourselves
|
168
|
+
expect( consumer ).to receive( :on_delivery ) do |&block|
|
169
|
+
allow( consumer ).to receive( :deliver ) do
|
170
|
+
delivery_info = double("delivery info", delivery_tag: 'mirrors!!!!' )
|
171
|
+
properties = {:content_type => 'application/json'}
|
172
|
+
payload = '{"some": "stuff"}'
|
173
|
+
block.call( delivery_info, properties, payload )
|
174
|
+
end
|
175
|
+
end
|
176
|
+
expect( consumer ).to receive( :on_cancellation )
|
177
|
+
|
178
|
+
# When the queue subscription happens, call the hook we set up above to simulate
|
179
|
+
# the delivery of AMQP messages
|
180
|
+
expect( amqp_queue ).to receive( :subscribe_with ) do |*args|
|
181
|
+
expect( args.first ).to be( consumer )
|
182
|
+
expect( args.last ).to eq({ block: true })
|
183
|
+
5.times { consumer.deliver }
|
184
|
+
end
|
185
|
+
|
186
|
+
expect( described_class.amqp_channel ).to receive( :acknowledge ).
|
187
|
+
with( 'mirrors!!!!' ).
|
188
|
+
exactly( 5 ).times
|
189
|
+
expect( described_class.amqp_channel ).to receive( :close )
|
190
|
+
expect( session ).to receive( :closed? ).and_return( false ).exactly( 5 ).times
|
191
|
+
expect( session ).to receive( :close )
|
192
|
+
|
193
|
+
count = 0
|
194
|
+
queue.wait_for_message { count += 1 }
|
195
|
+
expect( count ).to eq( 5 )
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
it "raises if wait_for_message is called without a block" do
|
200
|
+
expect { queue.wait_for_message }.to raise_error( LocalJumpError, /no work/i )
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
it "sets up the queue and consumer to only run once if waiting in one-shot mode" do
|
205
|
+
amqp_queue = double( "AMQP queue", channel: described_class.amqp_channel )
|
206
|
+
consumer = double( "Bunny consumer", channel: described_class.amqp_channel )
|
207
|
+
|
208
|
+
expect( described_class.amqp_channel ).to receive( :queue ).
|
209
|
+
with( testing_task_class.queue_name, passive: true ).
|
210
|
+
and_return( amqp_queue )
|
211
|
+
expect( described_class.amqp_channel ).to receive( :prefetch ).with( 1 )
|
212
|
+
|
213
|
+
expect( Bunny::Consumer ).to receive( :new ).
|
214
|
+
with( described_class.amqp_channel, amqp_queue, queue.consumer_tag, false ).
|
215
|
+
and_return( consumer )
|
216
|
+
|
217
|
+
expect( consumer ).to receive( :on_delivery ) do |&block|
|
218
|
+
allow( consumer ).to receive( :deliver ) do
|
219
|
+
delivery_info = double("delivery info", delivery_tag: 'mirrors!!!!' )
|
220
|
+
properties = {:content_type => 'application/json'}
|
221
|
+
payload = '{"some": "stuff"}'
|
222
|
+
block.call( delivery_info, properties, payload )
|
223
|
+
end
|
224
|
+
end
|
225
|
+
expect( consumer ).to receive( :on_cancellation )
|
226
|
+
|
227
|
+
expect( amqp_queue ).to receive( :subscribe_with ) do |*args|
|
228
|
+
expect( args.first ).to be( consumer )
|
229
|
+
expect( args.last ).to eq({ block: true })
|
230
|
+
consumer.deliver
|
231
|
+
end
|
232
|
+
expect( described_class.amqp_channel ).to receive( :acknowledge ).
|
233
|
+
with( 'mirrors!!!!' ).once
|
234
|
+
expect( described_class.amqp_channel ).to receive( :close )
|
235
|
+
expect( session ).to receive( :closed? ).and_return( false ).once
|
236
|
+
expect( session ).to receive( :close )
|
237
|
+
expect( consumer ).to receive( :cancel )
|
238
|
+
|
239
|
+
count = 0
|
240
|
+
queue.wait_for_message( true ) { count += 1 }
|
241
|
+
expect( count ).to eq( 1 )
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
it "shuts down the consumer if the queues it's consuming from is deleted on the server" do
|
246
|
+
amqp_queue = double( "AMQP queue", channel: described_class.amqp_channel )
|
247
|
+
consumer = double( "Bunny consumer", channel: described_class.amqp_channel )
|
248
|
+
|
249
|
+
expect( described_class.amqp_channel ).to receive( :queue ).
|
250
|
+
with( testing_task_class.queue_name, passive: true ).
|
251
|
+
and_return( amqp_queue )
|
252
|
+
expect( described_class.amqp_channel ).to receive( :prefetch ).
|
253
|
+
with( Symphony::Queue::DEFAULT_PREFETCH )
|
254
|
+
|
255
|
+
expect( Bunny::Consumer ).to receive( :new ).
|
256
|
+
with( described_class.amqp_channel, amqp_queue, queue.consumer_tag, false ).
|
257
|
+
and_return( consumer )
|
258
|
+
|
259
|
+
expect( consumer ).to receive( :on_delivery )
|
260
|
+
expect( consumer ).to receive( :on_cancellation ) do |&block|
|
261
|
+
allow( consumer ).to receive( :server_cancel ) do
|
262
|
+
block.call
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
expect( amqp_queue ).to receive( :subscribe_with ) do |*|
|
267
|
+
consumer.server_cancel
|
268
|
+
end
|
269
|
+
expect( described_class.amqp_channel ).to receive( :close )
|
270
|
+
expect( session ).to receive( :close )
|
271
|
+
expect( consumer ).to receive( :cancel )
|
272
|
+
|
273
|
+
queue.wait_for_message {}
|
274
|
+
expect( queue ).to be_shutting_down()
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
it "creates a consumer with acknowledgements enabled if it has acknowledgements enabled" do
|
279
|
+
amqp_channel = double( "AMQP channel" )
|
280
|
+
amqp_queue = double( "AMQP queue", channel: amqp_channel )
|
281
|
+
consumer = double( "Bunny consumer" )
|
282
|
+
|
283
|
+
# Ackmode argument is actually 'no_ack'
|
284
|
+
expect( Bunny::Consumer ).to receive( :new ).
|
285
|
+
with( amqp_channel, amqp_queue, queue.consumer_tag, false ).
|
286
|
+
and_return( consumer )
|
287
|
+
expect( consumer ).to receive( :on_delivery )
|
288
|
+
expect( consumer ).to receive( :on_cancellation )
|
289
|
+
|
290
|
+
expect( queue.create_consumer(amqp_queue) ).to be( consumer )
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
it "creates a consumer with acknowledgements disabled if it has acknowledgements disabled" do
|
295
|
+
amqp_channel = double( "AMQP channel" )
|
296
|
+
amqp_queue = double( "AMQP queue", channel: amqp_channel )
|
297
|
+
consumer = double( "Bunny consumer" )
|
298
|
+
|
299
|
+
# Ackmode argument is actually 'no_ack'
|
300
|
+
queue.instance_variable_set( :@acknowledge, false )
|
301
|
+
expect( Bunny::Consumer ).to receive( :new ).
|
302
|
+
with( amqp_channel, amqp_queue, queue.consumer_tag, true ).
|
303
|
+
and_return( consumer )
|
304
|
+
expect( consumer ).to receive( :on_delivery )
|
305
|
+
expect( consumer ).to receive( :on_cancellation )
|
306
|
+
|
307
|
+
expect( queue.create_consumer(amqp_queue) ).to be( consumer )
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
it "it acknowledges the message if acknowledgements are set and the task returns a true value" do
|
312
|
+
channel = double( "amqp channel" )
|
313
|
+
queue.consumer = double( "bunny consumer", channel: channel )
|
314
|
+
delivery_info = double( "delivery info", delivery_tag: 128 )
|
315
|
+
|
316
|
+
expect( channel ).to receive( :acknowledge ).with( delivery_info.delivery_tag )
|
317
|
+
|
318
|
+
queue.handle_message( delivery_info, {content_type: 'text/plain'}, :payload ) do |*|
|
319
|
+
true
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
|
324
|
+
it "re-raises AMQP errors raised while handling a message" do
|
325
|
+
channel = double( "amqp channel" )
|
326
|
+
queue.consumer = double( "bunny consumer", channel: channel )
|
327
|
+
delivery_info = double( "delivery info", delivery_tag: 128 )
|
328
|
+
|
329
|
+
expect( channel ).to_not receive( :acknowledge )
|
330
|
+
|
331
|
+
expect {
|
332
|
+
queue.handle_message( delivery_info, {content_type: 'text/plain'}, :payload ) do |*|
|
333
|
+
raise Bunny::Exception, 'something bad!'
|
334
|
+
end
|
335
|
+
}.to raise_error( Bunny::Exception, 'something bad!' )
|
336
|
+
end
|
337
|
+
|
338
|
+
|
339
|
+
it "it rejects the message if acknowledgements are set and the task returns a false value" do
|
340
|
+
channel = double( "amqp channel" )
|
341
|
+
queue.consumer = double( "bunny consumer", channel: channel )
|
342
|
+
delivery_info = double( "delivery info", delivery_tag: 128 )
|
343
|
+
|
344
|
+
expect( channel ).to receive( :reject ).with( delivery_info.delivery_tag, true )
|
345
|
+
|
346
|
+
queue.handle_message( delivery_info, {content_type: 'text/plain'}, :payload ) do |*|
|
347
|
+
false
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
|
352
|
+
it "it permanently rejects the message if acknowledgements are set and the task raises" do
|
353
|
+
channel = double( "amqp channel" )
|
354
|
+
queue.consumer = double( "bunny consumer", channel: channel )
|
355
|
+
delivery_info = double( "delivery info", delivery_tag: 128 )
|
356
|
+
|
357
|
+
expect( channel ).to receive( :reject ).with( delivery_info.delivery_tag, false )
|
358
|
+
|
359
|
+
queue.handle_message( delivery_info, {content_type: 'text/plain'}, :payload ) do |*|
|
360
|
+
raise "Uh-oh!"
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
|
365
|
+
end
|
366
|
+
|
367
|
+
end
|
368
|
+
|
@@ -0,0 +1,147 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../helpers'
|
4
|
+
|
5
|
+
require 'symphony/task'
|
6
|
+
|
7
|
+
describe Symphony::Task do
|
8
|
+
|
9
|
+
before( :all ) do
|
10
|
+
Symphony::Queue.configure
|
11
|
+
end
|
12
|
+
|
13
|
+
before( :each ) do
|
14
|
+
Symphony::Queue.reset
|
15
|
+
allow( Bunny ).to receive( :new ).and_return( amqp_session )
|
16
|
+
end
|
17
|
+
|
18
|
+
after( :each ) do
|
19
|
+
# reset signal handlers
|
20
|
+
Symphony::Task::SIGNALS.each do |sig|
|
21
|
+
Signal.trap( sig, :DFL )
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
let( :amqp_session ) { double('amqp_session') }
|
27
|
+
let( :channel ) { double('amqp channel') }
|
28
|
+
let( :consumer ) { double('bunny consumer', channel: channel) }
|
29
|
+
|
30
|
+
|
31
|
+
it "cancels the AMQP consumer when it receives a TERM signal" do
|
32
|
+
queue = described_class.queue
|
33
|
+
queue.consumer = consumer
|
34
|
+
task = described_class.new( queue )
|
35
|
+
|
36
|
+
expect( queue.consumer ).to receive( :cancel )
|
37
|
+
|
38
|
+
task.handle_signal( :TERM )
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
it "cancels the AMQP consumer when it receives an INT signal" do
|
43
|
+
queue = described_class.queue
|
44
|
+
queue.consumer = consumer
|
45
|
+
task = described_class.new( queue )
|
46
|
+
|
47
|
+
expect( queue.consumer ).to receive( :cancel )
|
48
|
+
|
49
|
+
task.handle_signal( :INT )
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
it "closes the AMQP session when it receives a second TERM signal" do
|
54
|
+
queue = described_class.queue
|
55
|
+
queue.consumer = consumer
|
56
|
+
task = described_class.new( queue )
|
57
|
+
task.shutting_down = true
|
58
|
+
|
59
|
+
expect( queue.consumer.channel ).to receive( :close )
|
60
|
+
|
61
|
+
task.handle_signal( :TERM )
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
context "a concrete subclass" do
|
66
|
+
|
67
|
+
before( :each ) do
|
68
|
+
@task_class = Class.new( described_class ) do
|
69
|
+
def self::name; 'ACME::TestingTask'; end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
it "raises an exception if run without specifying any subscriptions" do
|
75
|
+
expect { @task_class.run }.to raise_error( ScriptError, /no subscriptions/i )
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
it "can set an explicit queue name" do
|
80
|
+
@task_class.queue_name( 'happy.fun.queue' )
|
81
|
+
expect( @task_class.queue_name ).to eq( 'happy.fun.queue' )
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
it "can retry on timeout instead of rejecting" do
|
86
|
+
@task_class.timeout_action( :retry )
|
87
|
+
expect( @task_class.timeout_action ).to eq( :retry )
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
it "provides a default name for its queue based on its name" do
|
92
|
+
expect( @task_class.queue_name ).to eq( 'acme.testingtask' )
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
it "can declare a pattern to use when subscribing" do
|
97
|
+
@task_class.subscribe_to( 'foo.test' )
|
98
|
+
expect( @task_class.routing_keys ).to include( 'foo.test' )
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
it "has acknowledgements enabled by default" do
|
103
|
+
expect( @task_class.acknowledge ).to eq( true )
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
it "can enable acknowledgements" do
|
108
|
+
@task_class.acknowledge( true )
|
109
|
+
expect( @task_class.acknowledge ).to eq( true )
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
it "can disable acknowledgements" do
|
114
|
+
@task_class.acknowledge( false )
|
115
|
+
expect( @task_class.acknowledge ).to eq( false )
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
it "can set a timeout" do
|
120
|
+
@task_class.timeout( 10 )
|
121
|
+
expect( @task_class.timeout ).to eq( 10 )
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
it "can declare a one-shot work model" do
|
126
|
+
@task_class.work_model( :oneshot )
|
127
|
+
expect( @task_class.work_model ).to eq( :oneshot )
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
it "can declare a long-lived work model" do
|
132
|
+
@task_class.work_model( :longlived )
|
133
|
+
expect( @task_class.work_model ).to eq( :longlived )
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
it "raises an error if an invalid work model is declared " do
|
138
|
+
expect {
|
139
|
+
@task_class.work_model( :lazy )
|
140
|
+
}.to raise_error( /unknown work_model/i )
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
data.tar.gz.sig
ADDED
Binary file
|