mercury_amqp 0.1.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 +7 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/Gemfile +5 -0
- data/README.md +85 -0
- data/Rakefile +9 -0
- data/lib/mercury/cps/methods.rb +23 -0
- data/lib/mercury/cps/seq.rb +23 -0
- data/lib/mercury/cps/seq_with_let.rb +67 -0
- data/lib/mercury/cps.rb +97 -0
- data/lib/mercury/fake/domain.rb +9 -0
- data/lib/mercury/fake/metadata.rb +24 -0
- data/lib/mercury/fake/queue.rb +80 -0
- data/lib/mercury/fake/queued_message.rb +17 -0
- data/lib/mercury/fake/subscriber.rb +13 -0
- data/lib/mercury/fake.rb +104 -0
- data/lib/mercury/mercury.rb +186 -0
- data/lib/mercury/monadic.rb +41 -0
- data/lib/mercury/received_message.rb +30 -0
- data/lib/mercury/sync.rb +20 -0
- data/lib/mercury/test_utils.rb +59 -0
- data/lib/mercury/utils.rb +9 -0
- data/lib/mercury/version.rb +3 -0
- data/lib/mercury/wire_serializer.rb +54 -0
- data/lib/mercury.rb +1 -0
- data/mercury_amqp.gemspec +33 -0
- data/spec/lib/mercury/cps_spec.rb +225 -0
- data/spec/lib/mercury/mercury_spec.rb +87 -0
- data/spec/lib/mercury/monadic_spec.rb +313 -0
- data/spec/lib/mercury/sync_spec.rb +33 -0
- data/spec/lib/mercury/utils_spec.rb +17 -0
- data/spec/lib/mercury/wire_serializer_spec.rb +29 -0
- data/spec/spec_helper.rb +39 -0
- metadata +238 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mercury'
|
3
|
+
|
4
|
+
describe Mercury do
|
5
|
+
include MercuryFakeSpec
|
6
|
+
|
7
|
+
# These tests just cover the basics. Most of the testing is
|
8
|
+
# done in the Mercury::Monadic spec for convenience.
|
9
|
+
|
10
|
+
let!(:sent) { { 'a' => 1 } }
|
11
|
+
let!(:source) { 'test-exchange' }
|
12
|
+
let!(:queue) { 'test-queue' }
|
13
|
+
|
14
|
+
describe '::open' do
|
15
|
+
it 'opens a mercury instance' do
|
16
|
+
em do
|
17
|
+
Mercury.open do |m|
|
18
|
+
expect(m).to be_a Mercury
|
19
|
+
m.close do
|
20
|
+
done
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#close' do
|
28
|
+
itt 'closes the connection' do
|
29
|
+
em do
|
30
|
+
Mercury.open do |m|
|
31
|
+
m.close do
|
32
|
+
expect { m.publish(queue, {'a' => 1}) }.to raise_error /connection is closed/
|
33
|
+
done
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#start_listener' do
|
41
|
+
itt 'listens for messages' do
|
42
|
+
with_mercury do |m|
|
43
|
+
received = []
|
44
|
+
m.start_listener(source, received.method(:push)) do
|
45
|
+
m.publish(source, sent) do
|
46
|
+
em_wait_until(proc{received.any?}) do
|
47
|
+
expect(received.size).to eql 1
|
48
|
+
expect(received[0].content).to eql sent
|
49
|
+
m.close do
|
50
|
+
done
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#start_worker' do
|
60
|
+
itt 'listens for messages' do
|
61
|
+
with_mercury do |m|
|
62
|
+
received = []
|
63
|
+
m.start_worker(queue, source, received.method(:push)) do
|
64
|
+
m.publish(source, sent) do
|
65
|
+
em_wait_until(proc{received.any?}) do
|
66
|
+
expect(received.size).to eql 1
|
67
|
+
expect(received[0].content).to eql sent
|
68
|
+
m.close do
|
69
|
+
done
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def with_mercury(&block)
|
79
|
+
sources = [source]
|
80
|
+
queues = [queue]
|
81
|
+
em { delete_sources_and_queues_cps(sources, queues).run{done} }
|
82
|
+
em { Mercury.open(&block) }
|
83
|
+
em { delete_sources_and_queues_cps(sources, queues).run{done} }
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,313 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'mercury'
|
4
|
+
require 'mercury/monadic'
|
5
|
+
|
6
|
+
describe Mercury::Monadic do
|
7
|
+
include Cps::Methods
|
8
|
+
include MercuryFakeSpec
|
9
|
+
|
10
|
+
let!(:source1) { 'test-exchange1' }
|
11
|
+
let!(:source2) { 'test-exchange2' }
|
12
|
+
let!(:source) { source1 }
|
13
|
+
let!(:queue1) { 'test-queue1' }
|
14
|
+
let!(:queue2) { 'test-queue2' }
|
15
|
+
let!(:queue) { queue1 }
|
16
|
+
let!(:worker) { queue }
|
17
|
+
let!(:tag1) { 'tag1' }
|
18
|
+
let!(:tag2) { 'tag2' }
|
19
|
+
let!(:tag) { tag1 }
|
20
|
+
let!(:msg1) { {'a' => 1} }
|
21
|
+
let!(:msg2) { {'b' => 2} }
|
22
|
+
let!(:msg3) { {'c' => 3} }
|
23
|
+
let!(:msg4) { {'d' => 4} }
|
24
|
+
let!(:msg) { msg1 }
|
25
|
+
let!(:long_enough_to_receive_any_messages) { 0.5 } # seconds
|
26
|
+
|
27
|
+
# Sending an receiving are complementary operations. You can't test
|
28
|
+
# one without testing the other. Consequently, these tests verify
|
29
|
+
# system behavior rather than method contracts.
|
30
|
+
|
31
|
+
itt 'sends and receives messages' do
|
32
|
+
test_with_mercury do |m|
|
33
|
+
msgs = []
|
34
|
+
seql do
|
35
|
+
and_then { m.start_listener(source1, &msgs.method(:push)) }
|
36
|
+
and_then { m.publish(source1, msg1) }
|
37
|
+
and_then { m.publish(source2, msg2) } # different source
|
38
|
+
and_then { m.publish(source1, msg3) }
|
39
|
+
and_then { wait_until { msgs.size == 2 } }
|
40
|
+
and_lift do
|
41
|
+
msgs.each { |msg| expect(msg).to be_a Mercury::ReceivedMessage }
|
42
|
+
expect(msgs[0].content).to eql(msg1)
|
43
|
+
expect(msgs[1].content).to eql(msg3)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
itt 'sends and receives tagged messages' do
|
50
|
+
test_with_mercury do |m|
|
51
|
+
msgs = []
|
52
|
+
seql do
|
53
|
+
and_then { m.start_listener(source, tag_filter: tag1, &msgs.method(:push)) }
|
54
|
+
and_then { m.publish(source, msg1, tag: tag1) }
|
55
|
+
and_then { m.publish(source, msg2, tag: tag2) } # different tag
|
56
|
+
and_then { m.publish(source, msg3, tag: tag1) }
|
57
|
+
and_then { wait_until { msgs.size == 2 } }
|
58
|
+
and_lift do
|
59
|
+
expect(msgs[0].content).to eql(msg1)
|
60
|
+
expect(msgs[0].tag).to eql(tag1)
|
61
|
+
expect(msgs[1].content).to eql(msg3)
|
62
|
+
expect(msgs[1].tag).to eql(tag1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
itt 'uses AMQP-style tag filters' do
|
69
|
+
test_with_mercury do |m|
|
70
|
+
successes = []
|
71
|
+
failures = []
|
72
|
+
bars = []
|
73
|
+
everything = []
|
74
|
+
seql do
|
75
|
+
and_then { m.start_listener(source, tag_filter: '*.success', &successes.method(:push)) }
|
76
|
+
and_then { m.start_listener(source, tag_filter: '*.failure', &failures.method(:push)) }
|
77
|
+
and_then { m.start_listener(source, tag_filter: 'bar.*', &bars.method(:push)) }
|
78
|
+
and_then { m.start_listener(source, tag_filter: '#', &everything.method(:push)) }
|
79
|
+
and_then { m.publish(source, msg1, tag: 'foo.success') }
|
80
|
+
and_then { m.publish(source, msg2, tag: 'foo.failure') }
|
81
|
+
and_then { m.publish(source, msg3, tag: 'bar.success') }
|
82
|
+
and_then { m.publish(source, msg4, tag: 'bar.failure') }
|
83
|
+
and_then { wait_until { successes.size == 2 && failures.size == 2 && bars.size == 2 && everything.size == 4 } }
|
84
|
+
and_lift do
|
85
|
+
expect(successes[0].content).to eql(msg1)
|
86
|
+
expect(successes[1].content).to eql(msg3)
|
87
|
+
expect(failures[0].content).to eql(msg2)
|
88
|
+
expect(failures[1].content).to eql(msg4)
|
89
|
+
expect(bars[0].content).to eql(msg3)
|
90
|
+
expect(bars[1].content).to eql(msg4)
|
91
|
+
expect(everything[0].content).to eql(msg1)
|
92
|
+
expect(everything[1].content).to eql(msg2)
|
93
|
+
expect(everything[2].content).to eql(msg3)
|
94
|
+
expect(everything[3].content).to eql(msg4)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
itt 'workers share a queue' do
|
101
|
+
test_with_mercury do |m|
|
102
|
+
seql do
|
103
|
+
let(:m2) { Mercury::Monadic.open }
|
104
|
+
work1 = []
|
105
|
+
work2 = []
|
106
|
+
and_then { m.start_worker(worker, source, &push_and_ack(work1)) }
|
107
|
+
and_then { m2.start_worker(worker, source, &push_and_ack(work2)) }
|
108
|
+
and_then { m.publish(source, msg1) }
|
109
|
+
and_then { m.publish(source, msg2) }
|
110
|
+
and_then { wait_until { work1.size + work2.size == 2 } }
|
111
|
+
and_lift { expect((work1 + work2).map(&:content).uniq.size).to eql 2 }
|
112
|
+
and_then { m2.close }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
itt 'workers can specify tag filters' do
|
118
|
+
test_with_mercury do |m|
|
119
|
+
seql do
|
120
|
+
let(:m2) { Mercury::Monadic.open }
|
121
|
+
work1 = []
|
122
|
+
work2 = []
|
123
|
+
and_then { m.start_worker(worker, source, tag_filter: 'success', &push_and_ack(work1)) }
|
124
|
+
and_then { m2.start_worker(worker, source, tag_filter: 'failure', &push_and_ack(work2)) }
|
125
|
+
and_then { m.publish(source, msg1, tag: 'success') }
|
126
|
+
and_then { m.publish(source, msg2, tag: 'failure') }
|
127
|
+
and_then { wait_until { work1.size == 1 && work2.size == 1 } }
|
128
|
+
and_lift do
|
129
|
+
expect(work1[0].content).to eql msg1
|
130
|
+
expect(work2[0].content).to eql msg2
|
131
|
+
end
|
132
|
+
and_then { m2.close }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def push_and_ack(array)
|
138
|
+
proc do |msg|
|
139
|
+
array.push(msg)
|
140
|
+
msg.ack
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
itt 'a worker must ack before receiving another message' do
|
145
|
+
test_with_mercury do |m|
|
146
|
+
msgs = []
|
147
|
+
seql do
|
148
|
+
and_then { m.start_worker(worker, source, &msgs.method(:push)) }
|
149
|
+
and_then { m.publish(source, msg1) }
|
150
|
+
and_then { m.publish(source, msg2) }
|
151
|
+
and_then { wait_for(long_enough_to_receive_any_messages) }
|
152
|
+
and_lift { expect(msgs.size).to eql 1 }
|
153
|
+
and_lift { msgs[0].ack }
|
154
|
+
and_then { wait_until { msgs.size == 2 } }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
itt 'rejected messages are not requeued' do
|
160
|
+
test_with_mercury do |m|
|
161
|
+
msgs = []
|
162
|
+
seql do
|
163
|
+
and_then { m.start_worker(worker, source, &msgs.method(:push)) }
|
164
|
+
and_then { m.publish(source, msg) }
|
165
|
+
and_then { wait_until { msgs.size == 1 } }
|
166
|
+
and_lift { msgs[0].reject }
|
167
|
+
and_then { wait_for(long_enough_to_receive_any_messages) }
|
168
|
+
and_lift { expect(msgs.size).to eql 1}
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
itt 'nacked messages are requeued' do
|
174
|
+
test_with_mercury do |m|
|
175
|
+
msgs = []
|
176
|
+
seql do
|
177
|
+
and_then { m.start_worker(worker, source, &msgs.method(:push)) }
|
178
|
+
and_then { m.publish(source, msg) }
|
179
|
+
and_then { wait_until { msgs.size == 1 } }
|
180
|
+
and_lift { msgs[0].nack }
|
181
|
+
and_then { wait_until { msgs.size == 2} }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'unacked messages are requeued (client failure)' do
|
187
|
+
test_with_mercury do |m|
|
188
|
+
msgs = []
|
189
|
+
seql do
|
190
|
+
and_then { m.start_worker(worker, source, &msgs.method(:push)) }
|
191
|
+
and_then { m.publish(source, msg) }
|
192
|
+
and_then { wait_until { msgs.size == 1 } }
|
193
|
+
and_then { m.close }
|
194
|
+
let(:m2) { Mercury::Monadic.open }
|
195
|
+
and_then { m2.start_worker(worker, source, &msgs.method(:push)) }
|
196
|
+
and_then { wait_until { msgs.size == 2 } }
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'raises when an error occurs' do
|
202
|
+
# verify it registers a handler
|
203
|
+
expect_any_instance_of(AMQP::Channel).to receive(:on_error) {|&b| @handler = b}
|
204
|
+
|
205
|
+
# verify the handler raises an error
|
206
|
+
expect do
|
207
|
+
em do
|
208
|
+
Mercury.open do
|
209
|
+
ch = double
|
210
|
+
info = double(reply_code: 'code', reply_text: 'text')
|
211
|
+
@handler.call(ch, info)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end.to raise_error 'An error occurred: code - text'
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '#delete_source' do
|
218
|
+
itt 'deletes the source if it exists' do
|
219
|
+
test_with_mercury do |m|
|
220
|
+
seql do
|
221
|
+
and_then { m.start_listener(source) }
|
222
|
+
let(:r1) { m.source_exists?(source) }
|
223
|
+
and_lift { expect(r1).to be true }
|
224
|
+
and_then { m.delete_source(source) }
|
225
|
+
let(:r2) { m.source_exists?(source) }
|
226
|
+
and_lift { expect(r2).to be false }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
itt 'does nothing if the source does not exist' do
|
231
|
+
test_with_mercury do |m|
|
232
|
+
seql do
|
233
|
+
and_then { m.delete_source(source) }
|
234
|
+
let(:r) { m.source_exists?(source) }
|
235
|
+
and_lift { expect(r).to be false }
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe '#delete_work_queue' do
|
242
|
+
itt 'deletes the queue if it exists' do
|
243
|
+
test_with_mercury do |m|
|
244
|
+
seql do
|
245
|
+
and_then { m.start_worker(queue, source) }
|
246
|
+
let(:r1) { m.queue_exists?(queue) }
|
247
|
+
and_lift { expect(r1).to be true }
|
248
|
+
and_then { m.delete_work_queue(queue) }
|
249
|
+
let(:r2) { m.queue_exists?(queue) }
|
250
|
+
and_lift { expect(r2).to be false }
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
itt 'does nothing if the queue does not exist' do
|
255
|
+
test_with_mercury do |m|
|
256
|
+
seql do
|
257
|
+
and_then { m.delete_work_queue(queue) }
|
258
|
+
let(:r) { m.queue_exists?(queue) }
|
259
|
+
and_lift { expect(r).to be false }
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe '#source_exists?' do
|
266
|
+
itt 'returns false when the source does not exist' do
|
267
|
+
test_with_mercury do |m|
|
268
|
+
m.source_exists?('asdf').
|
269
|
+
and_lift { |result| expect(result).to be false }
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'returns true when the source exists' do
|
274
|
+
test_with_mercury do |m|
|
275
|
+
m.source_exists?('amq.direct').
|
276
|
+
and_lift { |result| expect(result).to be true }
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe '#queue_exists?' do
|
282
|
+
itt 'returns false when the queue does not exist' do
|
283
|
+
test_with_mercury do |m|
|
284
|
+
m.queue_exists?('asdf').
|
285
|
+
and_lift { |result| expect(result).to be false }
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
itt 'returns true when the source exists' do
|
290
|
+
test_with_mercury do |m|
|
291
|
+
m.start_worker(queue1, source1, proc{}).
|
292
|
+
and_then { m.queue_exists?(queue1) }.
|
293
|
+
and_lift { |result| expect(result).to be true }
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
describe '#open' do
|
299
|
+
it 'relays args to Mercury.open' do
|
300
|
+
logger = double
|
301
|
+
expect(Mercury).to receive(:open).with(logger: logger, host: 'asdf')
|
302
|
+
Mercury::Monadic.open(logger: logger, host: 'asdf').run
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# the block must return a Cps
|
307
|
+
def test_with_mercury(&block)
|
308
|
+
sources = [source1, source2]
|
309
|
+
queues = [queue1, queue2]
|
310
|
+
test_with_mercury_cps(sources, queues, &block)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mercury/sync'
|
3
|
+
require 'mercury/monadic'
|
4
|
+
|
5
|
+
describe Mercury::Sync do
|
6
|
+
include Cps::Methods
|
7
|
+
let!(:source) { 'test-exchange1' }
|
8
|
+
let!(:queue) { 'test-queue1' }
|
9
|
+
describe '::publish' do
|
10
|
+
it 'publishes synchronously' do
|
11
|
+
sent = {'a' => 1}
|
12
|
+
received = []
|
13
|
+
test_with_mercury do |m|
|
14
|
+
seql do
|
15
|
+
and_then { m.start_listener(source, received.method(:push)) }
|
16
|
+
and_lift { Mercury::Sync.publish(source, sent) }
|
17
|
+
and_then { wait_until { received.any? } }
|
18
|
+
and_lift do
|
19
|
+
expect(received.size).to eql 1
|
20
|
+
expect(received[0].content).to eql sent
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# the block must return a Cps
|
28
|
+
def test_with_mercury(&block)
|
29
|
+
sources = [source]
|
30
|
+
queues = [queue]
|
31
|
+
test_with_mercury_cps(sources, queues, &block)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mercury/utils'
|
3
|
+
|
4
|
+
describe Utils do
|
5
|
+
describe '::unsplat' do
|
6
|
+
it 'allows args to be provided in splatted form' do
|
7
|
+
expect(Utils.unsplat([])).to eql []
|
8
|
+
expect(Utils.unsplat([1])).to eql [1]
|
9
|
+
expect(Utils.unsplat([1, 2])).to eql [1, 2]
|
10
|
+
end
|
11
|
+
it 'allows args to be provided as an array' do
|
12
|
+
expect(Utils.unsplat([[]])).to eql []
|
13
|
+
expect(Utils.unsplat([[1]])).to eql [1]
|
14
|
+
expect(Utils.unsplat([[1, 2]])).to eql [1, 2]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mercury/wire_serializer'
|
3
|
+
|
4
|
+
describe Mercury::WireSerializer do
|
5
|
+
subject {Mercury::WireSerializer.new}
|
6
|
+
describe '#write' do
|
7
|
+
it 'writes a string hash as JSON' do
|
8
|
+
expect(subject.write({'a' => 1})).to eql '{"a":1}'
|
9
|
+
end
|
10
|
+
it 'writes a symbol hash as JSON' do
|
11
|
+
expect(subject.write({a: 1})).to eql '{"a":1}'
|
12
|
+
end
|
13
|
+
it 'writes a struct as JSON' do
|
14
|
+
Foo = Struct.new(:a)
|
15
|
+
expect(subject.write(Foo.new(1))).to eql '{"a":1}'
|
16
|
+
end
|
17
|
+
it 'writes a string literally' do
|
18
|
+
expect(subject.write('asdf')).to eql 'asdf'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
describe '#read' do
|
22
|
+
it 'reads JSON as a string hash' do
|
23
|
+
expect(subject.read('{"a":1}')).to eql('a' => 1)
|
24
|
+
end
|
25
|
+
it 'reads unparseable JSON as a string' do
|
26
|
+
expect(subject.read('asdf')).to eql 'asdf'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'mercury/test_utils'
|
3
|
+
require 'mercury/fake'
|
4
|
+
include Mercury::TestUtils
|
5
|
+
|
6
|
+
# the block must return a Cps
|
7
|
+
def test_with_mercury_cps(sources, queues, &block)
|
8
|
+
em do
|
9
|
+
seql do
|
10
|
+
let(:m) { Mercury::Monadic.open }
|
11
|
+
and_then { delete_sources_and_queues_cps(sources, queues) }
|
12
|
+
and_then { block.call(m) }
|
13
|
+
and_then { delete_sources_and_queues_cps(sources, queues) }
|
14
|
+
and_then { m.close }
|
15
|
+
and_lift { done }
|
16
|
+
end.run
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module MercuryFakeSpec
|
21
|
+
def self.included(base)
|
22
|
+
base.extend(ClassMethods)
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
# runs a test once with real mercury and once with Mercury::Fake
|
27
|
+
def itt(name, &block)
|
28
|
+
it(name, &block)
|
29
|
+
context 'with Mercury::Fake' do
|
30
|
+
before :each do
|
31
|
+
allow(Mercury).to receive(:open) do |&k|
|
32
|
+
EM.next_tick { k.call(Mercury::Fake.new) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
it(name, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|