em-zmq-tp10 0.1.7
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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +237 -0
- data/Rakefile +9 -0
- data/em-zmq-tp10.gemspec +23 -0
- data/lib/em-zmq-tp10.rb +1 -0
- data/lib/em/protocols/zmq2.rb +25 -0
- data/lib/em/protocols/zmq2/connection.rb +37 -0
- data/lib/em/protocols/zmq2/dealer.rb +133 -0
- data/lib/em/protocols/zmq2/inproc.rb +147 -0
- data/lib/em/protocols/zmq2/pub_sub.rb +102 -0
- data/lib/em/protocols/zmq2/queue_per_peer.rb +57 -0
- data/lib/em/protocols/zmq2/rep.rb +64 -0
- data/lib/em/protocols/zmq2/req.rb +325 -0
- data/lib/em/protocols/zmq2/router.rb +69 -0
- data/lib/em/protocols/zmq2/socket.rb +236 -0
- data/lib/em/protocols/zmq2/socket_connection.rb +151 -0
- data/lib/em/protocols/zmq2/version.rb +7 -0
- data/lib/em/protocols/zmq_tp10.rb +2 -0
- data/tests/helper.rb +102 -0
- data/tests/run_all.rb +3 -0
- data/tests/test_dealer.rb +237 -0
- data/tests/test_inproc.rb +113 -0
- data/tests/test_pub_sub.rb +271 -0
- data/tests/test_reconnect.rb +64 -0
- data/tests/test_rep.rb +117 -0
- data/tests/test_req.rb +229 -0
- data/tests/test_router.rb +221 -0
- metadata +108 -0
@@ -0,0 +1,271 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require File.expand_path('../helper.rb', __FILE__)
|
4
|
+
|
5
|
+
require 'em/protocols/zmq2/pub_sub'
|
6
|
+
|
7
|
+
describe 'Sub' do
|
8
|
+
let(:connected) do
|
9
|
+
EM::DefaultDeferrable.new
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:finished) do
|
13
|
+
EM::DefaultDeferrable.new
|
14
|
+
end
|
15
|
+
|
16
|
+
describe EM::Protocols::Zmq2::Sub do
|
17
|
+
class MySub < EM::Protocols::Zmq2::Sub
|
18
|
+
attr :incoming_queue
|
19
|
+
def initialize(connected, finished, opts={})
|
20
|
+
super opts
|
21
|
+
@connected = connected
|
22
|
+
@finished = finished
|
23
|
+
@incoming_queue = []
|
24
|
+
@to_catch = 2
|
25
|
+
end
|
26
|
+
def peer_free(peer, connection)
|
27
|
+
super
|
28
|
+
@connected.succeed if @peers.size == 2
|
29
|
+
end
|
30
|
+
def receive_message(message)
|
31
|
+
@incoming_queue << message
|
32
|
+
if message.last == 'xxx'
|
33
|
+
@to_catch -= 1
|
34
|
+
@finished.succeed if @to_catch == 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr :sub
|
40
|
+
before do
|
41
|
+
@sub = MySub.new(connected, finished, subscribe: 'mess')
|
42
|
+
@sub.connect(Native::ZBIND_ADDR)
|
43
|
+
@sub.bind(Native::ZCONNECT_ADDR)
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:messages_a) do
|
47
|
+
1000.times.map{|n| ['mess_a', n.to_s]} << ['mess_a', 'xxx']
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:messages_b) do
|
51
|
+
1000.times.map{|n| ['mess_b', n.to_s]} << ['mess_b', 'xxx']
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should accept messages" do
|
55
|
+
Native.with_socket_pair('PUB') do |zbind, zconnect|
|
56
|
+
thrd1, thrd2 = nil
|
57
|
+
EM.run do
|
58
|
+
connected.callback do
|
59
|
+
thrd1 = Thread.new do
|
60
|
+
messages_a.each do |message|
|
61
|
+
zbind.send_strings(message)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
thrd2 = Thread.new do
|
65
|
+
messages_b.each do |message|
|
66
|
+
zconnect.send_strings(message)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
finished.callback do
|
71
|
+
EM.next_tick{ EM.stop }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
thrd1.join
|
75
|
+
thrd2.join
|
76
|
+
end
|
77
|
+
(sub.incoming_queue - messages_a - messages_b).must_be_empty
|
78
|
+
(messages_a - sub.incoming_queue).must_be_empty
|
79
|
+
(messages_b - sub.incoming_queue).must_be_empty
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe EM::Protocols::Zmq2::PrePub do
|
84
|
+
class MyPrePub < EM::Protocols::Zmq2::PrePub
|
85
|
+
def initialize(connected, opts={})
|
86
|
+
super opts
|
87
|
+
@connected = connected
|
88
|
+
end
|
89
|
+
def peer_free(peer, connection)
|
90
|
+
super
|
91
|
+
@connected.succeed if @peers.size == 2
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
attr :pub
|
96
|
+
before do
|
97
|
+
@pub = MyPrePub.new(connected)
|
98
|
+
@pub.connect(Native::ZBIND_ADDR)
|
99
|
+
@pub.bind(Native::ZCONNECT_ADDR)
|
100
|
+
end
|
101
|
+
|
102
|
+
let(:messages) {
|
103
|
+
100.times.map{|n| ['mess_a', n.to_s]} << ['mess_a', 'xxx']
|
104
|
+
}
|
105
|
+
|
106
|
+
it "should send messages" do
|
107
|
+
results = []
|
108
|
+
Native.with_socket_pair('SUB') do |zbind, zconnect|
|
109
|
+
zbind.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
110
|
+
zconnect.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
111
|
+
thrds = [zbind, zconnect].map{|z| Thread.new do
|
112
|
+
res = []
|
113
|
+
while true
|
114
|
+
recv = []
|
115
|
+
z.recv_strings recv
|
116
|
+
res << recv
|
117
|
+
break if recv.last == 'xxx'
|
118
|
+
end
|
119
|
+
res
|
120
|
+
end}
|
121
|
+
EM.run do
|
122
|
+
connected.callback do
|
123
|
+
messages.each do |message|
|
124
|
+
pub.send_message message
|
125
|
+
end
|
126
|
+
pub.close do
|
127
|
+
EM.next_tick do EM.stop end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
results = thrds.map(&:value)
|
132
|
+
end
|
133
|
+
results[0].must_equal messages
|
134
|
+
results[1].must_equal messages
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe EM::Protocols::Zmq2::Pub do
|
139
|
+
class MyPub < EM::Protocols::Zmq2::Pub
|
140
|
+
def initialize(connected, opts={})
|
141
|
+
super opts
|
142
|
+
@connected = connected
|
143
|
+
end
|
144
|
+
def peer_free(peer, connection)
|
145
|
+
super
|
146
|
+
@connected.succeed if @peers.size == 2
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
attr :pub
|
151
|
+
before do
|
152
|
+
@pub = MyPub.new(connected)
|
153
|
+
@pub.connect(Native::ZBIND_ADDR)
|
154
|
+
@pub.bind(Native::ZCONNECT_ADDR)
|
155
|
+
end
|
156
|
+
|
157
|
+
let(:messages) {
|
158
|
+
500.times.map{|n| ['mess_a', n.to_s]} << ['mess_a', 'xxx']
|
159
|
+
}
|
160
|
+
|
161
|
+
it "should send a lot of messages" do
|
162
|
+
results = []
|
163
|
+
Native.with_socket_pair('SUB') do |zbind, zconnect|
|
164
|
+
zbind.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
165
|
+
zconnect.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
166
|
+
thrds = [zbind, zconnect].map{|z| Thread.new do
|
167
|
+
res = []
|
168
|
+
while true
|
169
|
+
recv = []
|
170
|
+
z.recv_strings recv
|
171
|
+
res << recv
|
172
|
+
#p [z.object_id, *recv]
|
173
|
+
break if recv.last == 'xxx'
|
174
|
+
end
|
175
|
+
res
|
176
|
+
end}
|
177
|
+
EM.run do
|
178
|
+
connected.callback do
|
179
|
+
messages.each do |message|
|
180
|
+
pub.send_message message
|
181
|
+
end
|
182
|
+
pub.close do
|
183
|
+
EM.next_tick do EM.stop end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
results = thrds.map(&:value)
|
188
|
+
end
|
189
|
+
results[0].must_equal messages
|
190
|
+
results[1].must_equal messages
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should not accept message when hwm is low and strategy is :drop_last" do
|
194
|
+
pub.hwm = 1
|
195
|
+
pub.hwm_strategy = :drop_last
|
196
|
+
results = nil
|
197
|
+
EM.run do
|
198
|
+
EM.defer proc{
|
199
|
+
Native.with_socket_pair('SUB') do |zbind, zconnect|
|
200
|
+
sleep 0.2
|
201
|
+
end
|
202
|
+
}, proc {
|
203
|
+
pub.send_message(messages[0]).must_equal true
|
204
|
+
pub.send_message(messages[1]).must_equal false
|
205
|
+
connected.instance_variable_set(:@deferred_status, nil)
|
206
|
+
connected.callback do
|
207
|
+
pub.send_message(messages.last).must_equal true
|
208
|
+
end
|
209
|
+
EM.defer proc{
|
210
|
+
Native.with_socket_pair('SUB') do |zbind, zconnect|
|
211
|
+
zbind.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
212
|
+
zconnect.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
213
|
+
results = [zbind, zconnect].map{|z| Thread.new do
|
214
|
+
res = []
|
215
|
+
2.times do
|
216
|
+
recv = []
|
217
|
+
z.recv_strings recv
|
218
|
+
res << recv
|
219
|
+
end
|
220
|
+
res
|
221
|
+
end}.map(&:value)
|
222
|
+
end
|
223
|
+
}, proc{
|
224
|
+
EM.next_tick{ EM.stop }
|
225
|
+
}
|
226
|
+
}
|
227
|
+
end
|
228
|
+
results[0].must_equal [messages.first, messages.last]
|
229
|
+
results[1].must_equal [messages.first, messages.last]
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should drop first message when hwm is low and strategy is :drop_first" do
|
233
|
+
pub.hwm = 1
|
234
|
+
pub.hwm_strategy = :drop_first
|
235
|
+
results = nil
|
236
|
+
EM.run do
|
237
|
+
EM.defer proc{
|
238
|
+
Native.with_socket_pair('SUB') do |zbind, zconnect|
|
239
|
+
sleep 0.2
|
240
|
+
end
|
241
|
+
}, proc {
|
242
|
+
pub.send_message(messages[0]).must_equal true
|
243
|
+
pub.send_message(messages[1]).must_equal true
|
244
|
+
connected.instance_variable_set(:@deferred_status, nil)
|
245
|
+
connected.callback do
|
246
|
+
pub.send_message(messages.last).must_equal true
|
247
|
+
end
|
248
|
+
EM.defer proc{
|
249
|
+
Native.with_socket_pair('SUB') do |zbind, zconnect|
|
250
|
+
zbind.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
251
|
+
zconnect.setsockopt(ZMQ::SUBSCRIBE, 'mess')
|
252
|
+
results = [zbind, zconnect].map{|z| Thread.new do
|
253
|
+
res = []
|
254
|
+
2.times do
|
255
|
+
recv = []
|
256
|
+
z.recv_strings recv
|
257
|
+
res << recv
|
258
|
+
end
|
259
|
+
res
|
260
|
+
end}.map(&:value)
|
261
|
+
end
|
262
|
+
}, proc{
|
263
|
+
EM.next_tick{ EM.stop }
|
264
|
+
}
|
265
|
+
}
|
266
|
+
end
|
267
|
+
results[0].must_equal [messages[1], messages.last]
|
268
|
+
results[1].must_equal [messages[1], messages.last]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require File.expand_path('../helper.rb', __FILE__)
|
4
|
+
|
5
|
+
require 'em/protocols/zmq2/socket'
|
6
|
+
|
7
|
+
describe EM::Protocols::Zmq2::Socket do
|
8
|
+
class MSocket < EM::Protocols::Zmq2::Socket
|
9
|
+
include DeferredMixin
|
10
|
+
end
|
11
|
+
let(:connected){ EM::DefaultDeferrable.new }
|
12
|
+
let(:fan) { MSocket.new(connected: connected) }
|
13
|
+
let(:sink) { MSocket.new() }
|
14
|
+
|
15
|
+
it 'should connect after timeout to tcp' do
|
16
|
+
were_connected = false
|
17
|
+
EM.run {
|
18
|
+
connected.callback {
|
19
|
+
were_connected = true
|
20
|
+
EM.next_tick { EM.stop }
|
21
|
+
}
|
22
|
+
fan.connect(Native::ZBIND_ADDR)
|
23
|
+
fan.connect(Native::ZCONNECT_ADDR)
|
24
|
+
EM.add_timer(0.1) do
|
25
|
+
sink.bind(Native::ZBIND_ADDR)
|
26
|
+
sink.bind(Native::ZCONNECT_ADDR)
|
27
|
+
EM.add_timer(0.1) do
|
28
|
+
EM.next_tick { EM.stop }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
}
|
32
|
+
were_connected.must_equal true
|
33
|
+
end
|
34
|
+
|
35
|
+
unless RUBY_PLATFORM =~ /windows|mingw|mswin/
|
36
|
+
it 'should connect after timeout to ipc' do
|
37
|
+
socket1 = File.expand_path("../test1.sock", __FILE__)
|
38
|
+
socket2 = File.expand_path("../test2.sock", __FILE__)
|
39
|
+
File.unlink(socket1) rescue nil
|
40
|
+
File.unlink(socket2) rescue nil
|
41
|
+
|
42
|
+
were_connected = false
|
43
|
+
EM.run {
|
44
|
+
connected.callback {
|
45
|
+
were_connected = true
|
46
|
+
EM.next_tick { EM.stop }
|
47
|
+
}
|
48
|
+
fan.connect('ipc://'+socket1)
|
49
|
+
fan.connect('ipc://'+socket2)
|
50
|
+
EM.add_timer(0.1) do
|
51
|
+
sink.bind('ipc://'+socket1)
|
52
|
+
sink.bind('ipc://'+socket2)
|
53
|
+
EM.add_timer(0.1) do
|
54
|
+
EM.next_tick { EM.stop }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
}
|
58
|
+
were_connected.must_equal true
|
59
|
+
|
60
|
+
File.unlink(socket1) rescue nil
|
61
|
+
File.unlink(socket2) rescue nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/tests/test_rep.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require File.expand_path('../helper.rb', __FILE__)
|
4
|
+
|
5
|
+
require 'em/protocols/zmq2/rep'
|
6
|
+
|
7
|
+
describe 'Rep' do
|
8
|
+
let(:connected) do
|
9
|
+
EM::DefaultDeferrable.new
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:finished) do
|
13
|
+
EM::DefaultDeferrable.new
|
14
|
+
end
|
15
|
+
|
16
|
+
module MyRepMixin
|
17
|
+
attr :incoming_queue
|
18
|
+
def initialize(connected, finished, opts={})
|
19
|
+
super opts
|
20
|
+
@connected = connected
|
21
|
+
@finished = finished
|
22
|
+
@incoming_queue = []
|
23
|
+
end
|
24
|
+
def peer_free(peer_identity, connection)
|
25
|
+
super
|
26
|
+
@connected.succeed
|
27
|
+
end
|
28
|
+
def receive_request(message, envelope)
|
29
|
+
message.first.must_equal 'hello'
|
30
|
+
envelope.first.must_be :start_with?, 'BIND_'
|
31
|
+
send_reply(['world', *message[1..-1]], envelope)
|
32
|
+
@finished.succeed if message.last == 'xxx'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe EM::Protocols::Zmq2::PreRep do
|
37
|
+
class MyPreRep < EM::Protocols::Zmq2::PreRep
|
38
|
+
include MyRepMixin
|
39
|
+
end
|
40
|
+
|
41
|
+
attr :req
|
42
|
+
before do
|
43
|
+
@req = MyPreRep.new(connected, finished, identity: 'REP')
|
44
|
+
@req.connect(Native::ZBIND_ADDR)
|
45
|
+
end
|
46
|
+
|
47
|
+
let(:messages){
|
48
|
+
300.times.map{|i| ['hello', i.to_s]} << ['hello', 'xxx']
|
49
|
+
}
|
50
|
+
|
51
|
+
it 'should make replies' do
|
52
|
+
replies = []
|
53
|
+
Native.with_socket('REQ') do |zreq|
|
54
|
+
thrd = Thread.new do
|
55
|
+
messages.each do |message|
|
56
|
+
zreq.send_strings message
|
57
|
+
reply = []
|
58
|
+
zreq.recv_strings reply
|
59
|
+
replies << reply
|
60
|
+
end
|
61
|
+
end
|
62
|
+
EM.run {
|
63
|
+
finished.callback {
|
64
|
+
req.close do
|
65
|
+
EM.next_tick{ EM.stop }
|
66
|
+
end
|
67
|
+
}
|
68
|
+
}
|
69
|
+
thrd.join
|
70
|
+
end
|
71
|
+
replies.all?{|reply| reply.first == 'world'}.must_equal true
|
72
|
+
replies.map{|reply| ['hello', *reply[1..-1]]}.must_equal messages
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe EM::Protocols::Zmq2::Rep do
|
77
|
+
class MyRep < EM::Protocols::Zmq2::Rep
|
78
|
+
include MyRepMixin
|
79
|
+
end
|
80
|
+
|
81
|
+
attr :req
|
82
|
+
before do
|
83
|
+
@req = MyRep.new(connected, finished, identity: 'REP')
|
84
|
+
@req.connect(Native::ZBIND_ADDR)
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:messages){
|
88
|
+
5000.times.map{|i| ['hello', i.to_s]} << ['hello', 'xxx']
|
89
|
+
}
|
90
|
+
|
91
|
+
it 'should make a lot of replies' do
|
92
|
+
replies = []
|
93
|
+
Native.with_socket('DEALER') do |zreq|
|
94
|
+
thrd = Thread.new do
|
95
|
+
messages.each do |message|
|
96
|
+
zreq.send_strings ['', *message]
|
97
|
+
end
|
98
|
+
messages.size.times do
|
99
|
+
reply = []
|
100
|
+
zreq.recv_strings reply
|
101
|
+
replies << reply[1..-1]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
EM.run {
|
105
|
+
finished.callback {
|
106
|
+
req.close do
|
107
|
+
EM.next_tick{ EM.stop }
|
108
|
+
end
|
109
|
+
}
|
110
|
+
}
|
111
|
+
thrd.join
|
112
|
+
end
|
113
|
+
replies.all?{|reply| reply.first == 'world'}.must_equal true
|
114
|
+
replies.map{|reply| ['hello', *reply[1..-1]]}.must_equal messages
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|