em-zmq-tp10 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ module EventMachine
2
+ module Protocols
3
+ module Zmq2
4
+ VERSION = '0.1.7'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ require 'em/protocols/zmq2'
2
+ EventMachine::Protocols::ZmqTP10 = EventMachine::Protocols::Zmq2
data/tests/helper.rb ADDED
@@ -0,0 +1,102 @@
1
+ require 'ffi-rzmq'
2
+ module Native
3
+ extend self
4
+ ZBIND_ADDR = 'tcp://127.0.0.1:7890'
5
+ ZCONNECT_ADDR = 'tcp://127.0.0.1:7891'
6
+
7
+ def native_context
8
+ @zctx = ZMQ::Context.new
9
+ end
10
+
11
+ def with_context
12
+ native_context
13
+ yield
14
+ ensure
15
+ close_context
16
+ end
17
+
18
+ def close_context
19
+ @zctx.terminate
20
+ end
21
+
22
+ def setup_pair(kind)
23
+ kind_n = ZMQ.const_get(kind)
24
+ @zbind = @zctx.socket(kind_n)
25
+ @zbind.identity = "BIND_#{kind}"
26
+ @zbind.bind(ZBIND_ADDR)
27
+ @zconnect = @zctx.socket(kind_n)
28
+ @zconnect.identity = "CONNECT_#{kind}"
29
+ @zconnect.connect(ZCONNECT_ADDR)
30
+ [@zbind, @zconnect]
31
+ end
32
+
33
+ def with_socket_pair(kind)
34
+ with_context do
35
+ begin
36
+ yield setup_pair(kind)
37
+ ensure
38
+ close_pair
39
+ end
40
+ end
41
+ end
42
+
43
+ def close_pair
44
+ @zbind.setsockopt(ZMQ::LINGER, 0)
45
+ @zconnect.setsockopt(ZMQ::LINGER, 0)
46
+ @zbind.close
47
+ @zconnect.close
48
+ end
49
+
50
+ def setup_socket(kind)
51
+ kind_n = ZMQ.const_get(kind)
52
+ @zbind = @zctx.socket(kind_n)
53
+ @zbind.identity = "BIND_#{kind}"
54
+ @zbind.bind(ZBIND_ADDR)
55
+ @zbind
56
+ end
57
+
58
+ def with_socket(kind)
59
+ with_context do
60
+ begin
61
+ yield setup_socket(kind)
62
+ ensure
63
+ close_socket
64
+ end
65
+ end
66
+ end
67
+
68
+ def close_socket
69
+ @zbind.setsockopt(ZMQ::LINGER, 0)
70
+ @zbind.close
71
+ end
72
+ end
73
+
74
+ module DeferredMixin
75
+ def initialize(opts={})
76
+ super(opts)
77
+ @connected = opts[:connected]
78
+ @finished = opts[:finished]
79
+ end
80
+
81
+ attr_writer :connected, :finished
82
+
83
+ def peer_free(peer_ident, connection)
84
+ super
85
+ if @connected && @free_peers.size == 2
86
+ @connected, connected = nil, @connected
87
+ connected.succeed
88
+ end
89
+ end
90
+ end
91
+
92
+ module IncomingMixin
93
+ attr :incoming_queue
94
+ def initialize(opts={})
95
+ super
96
+ @incoming_queue = []
97
+ end
98
+
99
+ def receive_message(message)
100
+ @incoming_queue << message
101
+ end
102
+ end
data/tests/run_all.rb ADDED
@@ -0,0 +1,3 @@
1
+ %w{req router dealer rep}.each do |what|
2
+ require File.expand_path("../test_#{what}.rb", __FILE__)
3
+ end
@@ -0,0 +1,237 @@
1
+ require 'eventmachine'
2
+ require 'minitest/autorun'
3
+ require File.expand_path('../helper.rb', __FILE__)
4
+
5
+ require 'em/protocols/zmq2/dealer'
6
+
7
+ describe 'Dealer' do
8
+
9
+ let(:connected) do
10
+ EM::DefaultDeferrable.new
11
+ end
12
+
13
+ describe EM::Protocols::Zmq2::PreDealer do
14
+ class MyPreDealer < EM::Protocols::Zmq2::PreDealer
15
+
16
+ attr :incoming_queue
17
+ def initialize(opts={})
18
+ super(opts)
19
+ @connected = opts[:connected]
20
+ @incoming_queue = []
21
+ end
22
+ def peer_free(peer_ident, connection)
23
+ super
24
+ @connected.succeed if @free_peers.size == 2
25
+ end
26
+ def receive_message(message)
27
+ @incoming_queue << message
28
+ end
29
+ end
30
+
31
+ attr :dealer
32
+ before do
33
+ @dealer = MyPreDealer.new(identity: 'MyDealer', connected: connected)
34
+ @dealer.connect(Native::ZBIND_ADDR)
35
+ @dealer.bind(Native::ZCONNECT_ADDR)
36
+ end
37
+
38
+ let(:messages) do
39
+ 64.times.map{|n| ['', 'hello', 'world', n.to_s]}
40
+ end
41
+
42
+ it "should be able to send message" do
43
+ results = []
44
+ Native.with_socket_pair('ROUTER') do |zbind, zconnect|
45
+ EM.run {
46
+ connected.callback {
47
+ messages.each{|message|
48
+ dealer.send_message(message).must_equal true
49
+ }
50
+ dealer.close do
51
+ EM.next_tick{ EM.stop }
52
+ end
53
+ }
54
+ }
55
+ result = []
56
+ while zbind.recv_strings(result, ZMQ::NOBLOCK) != -1
57
+ result.shift.must_equal 'MyDealer'
58
+ results << result
59
+ result = []
60
+ end
61
+ results.size.must_be :>, 0
62
+ results.size.must_be :<, messages.size
63
+ while zconnect.recv_strings(result, ZMQ::NOBLOCK) != -1
64
+ result.shift.must_equal 'MyDealer'
65
+ results << result
66
+ result = []
67
+ end
68
+ end
69
+ (messages - results).must_be_empty
70
+ (results - messages).must_be_empty
71
+ end
72
+
73
+ it "should be able to receive messages" do
74
+ Native.with_socket_pair('ROUTER') do |zbind, zconnect|
75
+ EM.run {
76
+ connected.callback {
77
+ messages[0...(messages.size/2)].each{|message|
78
+ zbind.send_strings ['MyDealer', *message]
79
+ }
80
+ messages[(messages.size/2)..-1].each{|message|
81
+ zconnect.send_strings ['MyDealer', *message]
82
+ }
83
+ }
84
+ cb = proc do
85
+ if dealer.incoming_queue.size < messages.size
86
+ EM.add_timer(0.5, cb)
87
+ else
88
+ EM.next_tick{ EM.stop }
89
+ end
90
+ end
91
+ cb.call
92
+ }
93
+ end
94
+ dealer.incoming_queue.size.must_equal messages.size
95
+ (dealer.incoming_queue - messages).must_be_empty
96
+ (messages - dealer.incoming_queue).must_be_empty
97
+ end
98
+ end
99
+
100
+ describe EM::Protocols::Zmq2::Dealer do
101
+ class MyDealer < EM::Protocols::Zmq2::Dealer
102
+ attr :incoming_queue, :canceled_messages
103
+ def initialize(opts={})
104
+ super(opts)
105
+ @connected = opts[:connected]
106
+ @incoming_queue = []
107
+ @canceled_messages = []
108
+ end
109
+ def peer_free(peer_ident, connection)
110
+ super
111
+ @connected.succeed if @free_peers.size == 2
112
+ end
113
+ def receive_message(message)
114
+ @incoming_queue << message
115
+ end
116
+ def cancel_message(message)
117
+ @canceled_messages << message
118
+ end
119
+ end
120
+
121
+ attr :dealer
122
+ before do
123
+ @dealer = MyDealer.new(identity: 'MyDealer', connected: connected)
124
+ @dealer.connect(Native::ZBIND_ADDR)
125
+ @dealer.bind(Native::ZCONNECT_ADDR)
126
+ end
127
+
128
+ let(:messages) do
129
+ 10000.times.map{|n| ['', 'hello', 'world', n.to_s]}
130
+ end
131
+
132
+ class RouteCollector
133
+ attr :res_a, :res_b
134
+ def initialize(till)
135
+ @till = till
136
+ @res_a, @res_b = [], []
137
+ end
138
+ def full?
139
+ @res_a.size + @res_b.size >= @till
140
+ end
141
+ def full_res
142
+ @res_a + @res_b
143
+ end
144
+ def set_sockets(zbind, zconnect)
145
+ @zbind = zbind
146
+ @zconnect = zconnect
147
+ end
148
+ def thread
149
+ Thread.new do
150
+ result = []
151
+ until full?
152
+ while @zbind.recv_strings(result, ZMQ::NOBLOCK) != -1
153
+ result.shift.must_equal 'MyDealer'
154
+ @res_a << result
155
+ result = []
156
+ end
157
+ while @zconnect.recv_strings(result, ZMQ::NOBLOCK) != -1
158
+ result.shift.must_equal 'MyDealer'
159
+ @res_b << result
160
+ result = []
161
+ end
162
+ sleep(0.01)
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ it "should be able to send a lot of messages" do
169
+ collector = RouteCollector.new(messages.size)
170
+ Native.with_socket_pair('ROUTER') do |zbind, zconnect|
171
+ collector.set_sockets zbind, zconnect
172
+ thrd = collector.thread
173
+ EM.run {
174
+ connected.callback {
175
+ messages.each{|message|
176
+ dealer.send_message(message)
177
+ }
178
+ dealer.close do
179
+ EM.next_tick{ EM.stop }
180
+ end
181
+ }
182
+ }
183
+ thrd.join
184
+ end
185
+ collector.full?.must_equal true
186
+ collector.res_a.size.must_be :>, 0
187
+ collector.res_a.size.must_be :<, messages.size
188
+ (messages - collector.full_res).must_be_empty
189
+ (collector.full_res - messages).must_be_empty
190
+ end
191
+
192
+ it "should be closed after writting" do
193
+ collector = RouteCollector.new(messages.size)
194
+ Native.with_socket_pair('ROUTER') do |zbind, zconnect|
195
+ collector.set_sockets zbind, zconnect
196
+ thrd = collector.thread
197
+ EM.run {
198
+ connected.callback {
199
+ messages.each{|message|
200
+ dealer.send_message(message)
201
+ }
202
+ dealer.close do
203
+ EM.next_tick{ EM.stop }
204
+ end
205
+ }
206
+ }
207
+ thrd.join
208
+ end
209
+ collector.full?.must_equal true
210
+ collector.res_a.size.must_be :>, 0
211
+ collector.res_a.size.must_be :<, messages.size
212
+ (messages - collector.full_res).must_be_empty
213
+ (collector.full_res - messages).must_be_empty
214
+ end
215
+
216
+ it "should not accept message on low hwm with strategy :drop_last" do
217
+ dealer.hwm = 1
218
+ dealer.hwm_strategy = :drop_last
219
+ EM.run {
220
+ dealer.send_message(['hi', 'ho1']).must_equal true
221
+ dealer.send_message(['hi', 'ho2']).wont_equal true
222
+ EM.stop
223
+ }
224
+ end
225
+
226
+ it "should cancel earlier message on low hwm with strategy :drop_first" do
227
+ dealer.hwm = 1
228
+ dealer.hwm_strategy = :drop_first
229
+ EM.run {
230
+ dealer.send_message(['hi', 'ho1']).must_equal true
231
+ dealer.send_message(['hi', 'ho2']).must_equal true
232
+ EM.stop
233
+ }
234
+ dealer.canceled_messages.must_equal [['hi', 'ho1']]
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,113 @@
1
+ require 'eventmachine'
2
+ require 'minitest/autorun'
3
+ require File.expand_path('../helper.rb', __FILE__)
4
+
5
+ require 'em/protocols/zmq2'
6
+
7
+ describe 'InProc' do
8
+ let(:connected) do
9
+ EM::DefaultDeferrable.new
10
+ end
11
+
12
+ class IPDealer < EM::Protocols::Zmq2::Dealer
13
+ include DeferredMixin
14
+ include IncomingMixin
15
+ def peers
16
+ @peers
17
+ end
18
+ end
19
+
20
+ let(:messages) do
21
+ 1000.times.map{|i| ['hi', i.to_s]}
22
+ end
23
+
24
+ let(:fan) do
25
+ IPDealer.new(connected: connected, identity: 'fan')
26
+ end
27
+
28
+ let(:sinks) do
29
+ 2.times.map{|i| IPDealer.new(identity: "sink.#{i}") }
30
+ end
31
+
32
+ def run_test
33
+ EM.run {
34
+ connected.callback do
35
+ fan.peers['sink.0'].wont_be_nil
36
+ fan.peers['sink.1'].wont_be_nil
37
+ sinks.each{|sink| sink.peers['fan'].wont_be_nil}
38
+ messages.each{|message| fan.send_message(message)}
39
+ fan.close do
40
+ EM.next_tick{ EM.stop }
41
+ end
42
+ end
43
+ }
44
+ sinks.each do |sink|
45
+ sink.incoming_queue.size.must_be :>, 0
46
+ sink.incoming_queue.size.must_be :<, messages.size
47
+ end
48
+ incomings = sinks.map(&:incoming_queue).flatten(1)
49
+ (incomings - messages).must_be_empty
50
+ (messages - incomings).must_be_empty
51
+ end
52
+
53
+ it "should send messages to several connected socket" do
54
+ sinks.each{|sink| sink.connect 'inproc://fan'}
55
+ fan.bind 'inproc://fan'
56
+ run_test
57
+ end
58
+
59
+ it "should send messages to several binded sockets" do
60
+ sinks.each{|sink|
61
+ bind_point = "inproc://#{sink.identity}"
62
+ sink.bind bind_point
63
+ fan.connect bind_point
64
+ }
65
+ run_test
66
+ end
67
+
68
+ it "should send messages to inproc and tcp" do
69
+ sinks[0].bind 'tcp://127.0.0.1:9876'
70
+ fan.connect 'tcp://127.0.0.1:9876'
71
+ sinks[1].bind 'inproc://sink.1'
72
+ fan.connect 'inproc://sink.1'
73
+ run_test
74
+ end
75
+
76
+ if RUBY_PLATFORM !~ /window/
77
+ it "should send messages to inproc and tcp" do
78
+ sinks[0].bind 'ipc://falcon'
79
+ fan.connect 'ipc://falcon'
80
+ sinks[1].bind 'inproc://sink.1'
81
+ fan.connect 'inproc://sink.1'
82
+ run_test
83
+ end
84
+ end
85
+
86
+ class IPPub < EM::Protocols::Zmq2::Pub
87
+ include DeferredMixin
88
+ include IncomingMixin
89
+ end
90
+ class IPSub < EM::Protocols::Zmq2::Sub
91
+ include DeferredMixin
92
+ include IncomingMixin
93
+ end
94
+ it "should pub messages to inproc and tcp sub" do
95
+ pub = IPPub.new(identity: 'pub', connected: connected)
96
+ subs = 2.times.map{ sub = IPSub.new(subscribe: 'hi') }
97
+ subs[0].bind 'tcp://127.0.0.1:9876'
98
+ pub.connect 'tcp://127.0.0.1:9876'
99
+ subs[1].bind 'inproc://sink.1'
100
+ pub.connect 'inproc://sink.1'
101
+ EM.run {
102
+ connected.callback {
103
+ messages.each{|message| pub.send_message(message)}
104
+ pub.close do
105
+ EM.next_tick{ EM.stop }
106
+ end
107
+ }
108
+ }
109
+ subs.each {|sub|
110
+ sub.incoming_queue.must_equal messages
111
+ }
112
+ end
113
+ end