ffi-rzmq 0.8.2 → 0.9.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.
- data/AUTHORS.txt +1 -0
- data/History.txt +35 -0
- data/README.rdoc +48 -15
- data/Rakefile +7 -2
- data/examples/README.rdoc +21 -76
- data/examples/{local_lat.rb → v2api/local_lat.rb} +27 -12
- data/examples/v2api/local_lat_poll.rb +66 -0
- data/examples/{local_throughput.rb → v2api/local_throughput.rb} +24 -9
- data/examples/v2api/publish_subscribe.rb +82 -0
- data/examples/{remote_lat.rb → v2api/remote_lat.rb} +26 -8
- data/examples/v2api/remote_throughput.rb +39 -0
- data/examples/v2api/reqrep_poll.rb +62 -0
- data/examples/v2api/request_response.rb +40 -0
- data/examples/v2api/throughput_measurement.rb +138 -0
- data/examples/v3api/local_lat.rb +59 -0
- data/examples/v3api/local_lat_poll.rb +66 -0
- data/examples/v3api/local_throughput.rb +65 -0
- data/examples/v3api/publish_subscribe.rb +82 -0
- data/examples/v3api/remote_lat.rb +71 -0
- data/examples/v3api/remote_throughput.rb +47 -0
- data/examples/v3api/reqrep_poll.rb +62 -0
- data/examples/v3api/request_response.rb +40 -0
- data/examples/v3api/throughput_measurement.rb +166 -0
- data/ext/README +5 -0
- data/ffi-rzmq.gemspec +4 -4
- data/lib/ffi-rzmq.rb +4 -1
- data/lib/ffi-rzmq/constants.rb +178 -0
- data/lib/ffi-rzmq/context.rb +61 -45
- data/lib/ffi-rzmq/device.rb +22 -9
- data/lib/ffi-rzmq/exceptions.rb +0 -98
- data/lib/ffi-rzmq/libc.rb +19 -0
- data/lib/ffi-rzmq/libzmq.rb +188 -0
- data/lib/ffi-rzmq/message.rb +33 -40
- data/lib/ffi-rzmq/poll.rb +49 -52
- data/lib/ffi-rzmq/socket.rb +902 -392
- data/lib/ffi-rzmq/util.rb +101 -0
- data/spec/context_spec.rb +47 -21
- data/spec/device_spec.rb +78 -58
- data/spec/message_spec.rb +90 -12
- data/spec/multipart_spec.rb +162 -0
- data/spec/nonblocking_recv_spec.rb +325 -0
- data/spec/pushpull_spec.rb +95 -34
- data/spec/reqrep_spec.rb +55 -20
- data/spec/socket_spec.rb +353 -204
- data/spec/spec_helper.rb +46 -3
- data/version.txt +1 -1
- metadata +91 -66
- data/examples/local_lat_poll.rb +0 -54
- data/examples/local_lat_zerocopy.rb +0 -24
- data/examples/publish_subscribe.rb +0 -52
- data/examples/remote_lat_zerocopy.rb +0 -35
- data/examples/remote_throughput.rb +0 -27
- data/examples/reqrep_poll.rb +0 -49
- data/examples/request_response.rb +0 -23
- data/lib/ffi-rzmq/wrapper.rb +0 -121
- data/lib/ffi-rzmq/zmq.rb +0 -198
data/spec/pushpull_spec.rb
CHANGED
@@ -13,55 +13,116 @@ module ZMQ
|
|
13
13
|
@context = ZMQ::Context.new
|
14
14
|
@push = @context.socket ZMQ::PUSH
|
15
15
|
@pull = @context.socket ZMQ::PULL
|
16
|
-
@
|
17
|
-
@pull.
|
16
|
+
@push.setsockopt ZMQ::LINGER, 0
|
17
|
+
@pull.setsockopt ZMQ::LINGER, 0
|
18
|
+
port = connect_to_random_tcp_port(@pull)
|
19
|
+
@link = "tcp://127.0.0.1:#{port}"
|
18
20
|
@push.bind @link
|
19
21
|
end
|
20
|
-
|
22
|
+
|
21
23
|
after(:each) do
|
22
24
|
@push.close
|
23
25
|
@pull.close
|
26
|
+
@context.terminate
|
24
27
|
end
|
25
|
-
|
28
|
+
|
26
29
|
it "should receive an exact copy of the sent message using Message objects directly on one pull socket" do
|
27
30
|
@push.send_string string
|
28
|
-
received =
|
31
|
+
received = ''
|
32
|
+
rc = @pull.recv_string received
|
29
33
|
received.should == string
|
30
34
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
|
36
|
+
if version2?
|
37
|
+
it "should receive an exact string copy of the message sent when receiving in non-blocking mode and using Message objects directly" do
|
38
|
+
sent_message = Message.new string
|
39
|
+
received_message = Message.new
|
40
|
+
|
41
|
+
rc = @push.send sent_message
|
42
|
+
rc.should == 0
|
43
|
+
sleep 0.1 # give it time for delivery
|
44
|
+
rc = @pull.recv received_message, ZMQ::NOBLOCK
|
45
|
+
received_message.copy_out_string.should == string
|
46
|
+
end
|
47
|
+
|
48
|
+
else
|
49
|
+
|
50
|
+
it "should receive an exact string copy of the message sent when receiving in non-blocking mode and using Message objects directly" do
|
51
|
+
sent_message = Message.new string
|
52
|
+
received_message = Message.new
|
53
|
+
|
54
|
+
rc = @push.sendmsg sent_message
|
55
|
+
rc.should == string.size
|
56
|
+
sleep 0.1 # give it time for delivery
|
57
|
+
rc = @pull.recvmsg received_message, ZMQ::DONTWAIT
|
58
|
+
rc.should == string.size
|
59
|
+
received_message.copy_out_string.should == string
|
60
|
+
end
|
40
61
|
end
|
41
62
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
|
64
|
+
if version2?
|
65
|
+
|
66
|
+
it "should receive a single message for each message sent on each socket listening, when an equal number pulls to messages" do
|
67
|
+
received = []
|
68
|
+
threads = []
|
69
|
+
count = 4
|
70
|
+
@pull.close # close this one since we aren't going to use it below and we don't want it to receive a message
|
71
|
+
|
72
|
+
count.times do |i|
|
73
|
+
threads << Thread.new do
|
74
|
+
pull = @context.socket ZMQ::PULL
|
75
|
+
rc = pull.setsockopt ZMQ::LINGER, 0
|
76
|
+
rc = pull.connect @link
|
77
|
+
rc.should == 0
|
78
|
+
buffer = ''
|
79
|
+
rc = pull.recv_string buffer
|
80
|
+
rc.should == 0
|
81
|
+
received << buffer
|
82
|
+
pull.close
|
83
|
+
end
|
84
|
+
sleep 0.01 # give each thread time to spin up
|
54
85
|
end
|
55
|
-
|
86
|
+
|
87
|
+
count.times { @push.send_string(string) }
|
88
|
+
|
89
|
+
threads.each {|t| t.join}
|
90
|
+
|
91
|
+
received.find_all {|r| r == string}.length.should == count
|
56
92
|
end
|
57
|
-
|
58
|
-
count.times { @push.send_string(string) }
|
59
93
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
94
|
+
else # version3 or 4
|
95
|
+
|
96
|
+
it "should receive a single message for each message sent on each socket listening, when an equal number pulls to messages" do
|
97
|
+
received = []
|
98
|
+
threads = []
|
99
|
+
count = 4
|
100
|
+
@pull.close # close this one since we aren't going to use it below and we don't want it to receive a message
|
101
|
+
|
102
|
+
count.times do |i|
|
103
|
+
threads << Thread.new do
|
104
|
+
pull = @context.socket ZMQ::PULL
|
105
|
+
rc = pull.setsockopt ZMQ::LINGER, 0
|
106
|
+
rc = pull.connect @link
|
107
|
+
rc.should == 0
|
108
|
+
buffer = ''
|
109
|
+
rc = pull.recv_string buffer
|
110
|
+
rc.should == string.size
|
111
|
+
received << buffer
|
112
|
+
pull.close
|
113
|
+
end
|
114
|
+
sleep 0.01 # give each thread time to spin up
|
115
|
+
end
|
116
|
+
|
117
|
+
count.times { @push.send_string(string) }
|
118
|
+
|
119
|
+
threads.each {|t| t.join}
|
120
|
+
|
121
|
+
received.find_all {|r| r == string}.length.should == count
|
122
|
+
end
|
123
|
+
|
124
|
+
end # if version...
|
125
|
+
|
65
126
|
end # @context ping-pong
|
66
127
|
end # describe
|
67
128
|
end # module ZMQ
|
data/spec/reqrep_spec.rb
CHANGED
@@ -15,11 +15,10 @@ module ZMQ
|
|
15
15
|
context = ZMQ::Context.new 1
|
16
16
|
@ping = context.socket ZMQ::REQ
|
17
17
|
@pong = context.socket ZMQ::REP
|
18
|
-
|
19
|
-
@
|
20
|
-
@ping.connect link
|
18
|
+
port = bind_to_random_tcp_port(@pong)
|
19
|
+
@ping.connect "tcp://127.0.0.1:#{port}"
|
21
20
|
end
|
22
|
-
|
21
|
+
|
23
22
|
after(:each) do
|
24
23
|
@ping.close
|
25
24
|
@pong.close
|
@@ -27,31 +26,67 @@ module ZMQ
|
|
27
26
|
|
28
27
|
it "should receive an exact string copy of the string message sent" do
|
29
28
|
@ping.send_string string
|
30
|
-
received_message =
|
29
|
+
received_message = ''
|
30
|
+
rc = @pong.recv_string received_message
|
31
31
|
|
32
32
|
received_message.should == string
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
if version2?
|
36
|
+
it "should receive an exact copy of the sent message using Message objects directly" do
|
37
|
+
sent_message = Message.new string
|
38
|
+
received_message = Message.new
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
rc = @ping.send sent_message
|
41
|
+
rc.should == 0
|
42
|
+
rc = @pong.recv received_message
|
43
|
+
rc.should == 0
|
41
44
|
|
42
|
-
|
43
|
-
|
45
|
+
received_message.copy_out_string.should == string
|
46
|
+
end
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
+
it "should receive an exact copy of the sent message using Message objects directly in non-blocking mode" do
|
49
|
+
sent_message = Message.new string
|
50
|
+
received_message = Message.new
|
48
51
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
rc = @ping.send sent_message, ZMQ::NOBLOCK
|
53
|
+
rc.should == 0
|
54
|
+
sleep 0.1 # give it time for delivery
|
55
|
+
rc = @pong.recv received_message, ZMQ::NOBLOCK
|
56
|
+
rc.should == 0
|
57
|
+
|
58
|
+
received_message.copy_out_string.should == string
|
59
|
+
end
|
60
|
+
|
61
|
+
else # version3 or 4
|
62
|
+
|
63
|
+
it "should receive an exact copy of the sent message using Message objects directly" do
|
64
|
+
sent_message = Message.new string
|
65
|
+
received_message = Message.new
|
66
|
+
|
67
|
+
rc = @ping.sendmsg sent_message
|
68
|
+
rc.should == string.size
|
69
|
+
rc = @pong.recvmsg received_message
|
70
|
+
rc.should == string.size
|
71
|
+
|
72
|
+
received_message.copy_out_string.should == string
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should receive an exact copy of the sent message using Message objects directly in non-blocking mode" do
|
76
|
+
sent_message = Message.new string
|
77
|
+
received_message = Message.new
|
78
|
+
|
79
|
+
rc = @ping.sendmsg sent_message, ZMQ::DONTWAIT
|
80
|
+
rc.should == string.size
|
81
|
+
sleep 0.001 # give it time for delivery
|
82
|
+
rc = @pong.recvmsg received_message, ZMQ::DONTWAIT
|
83
|
+
rc.should == string.size
|
84
|
+
|
85
|
+
received_message.copy_out_string.should == string
|
86
|
+
end
|
87
|
+
|
88
|
+
end # if version...
|
52
89
|
|
53
|
-
received_message.copy_out_string.should == string
|
54
|
-
end
|
55
90
|
end # context ping-pong
|
56
91
|
|
57
92
|
|
data/spec/socket_spec.rb
CHANGED
@@ -6,6 +6,14 @@ module ZMQ
|
|
6
6
|
|
7
7
|
describe Socket do
|
8
8
|
|
9
|
+
socket_types = if LibZMQ.version2?
|
10
|
+
[ZMQ::REQ, ZMQ::REP, ZMQ::DEALER, ZMQ::ROUTER, ZMQ::PUB, ZMQ::SUB, ZMQ::PUSH, ZMQ::PULL, ZMQ::PAIR]
|
11
|
+
elsif LibZMQ.version3?
|
12
|
+
[ZMQ::REQ, ZMQ::REP, ZMQ::DEALER, ZMQ::ROUTER, ZMQ::PUB, ZMQ::SUB, ZMQ::PUSH, ZMQ::PULL, ZMQ::PAIR, ZMQ::XPUB, ZMQ::XSUB]
|
13
|
+
elsif LibZMQ.version4?
|
14
|
+
[ZMQ::REQ, ZMQ::REP, ZMQ::ROUTER, ZMQ::PUB, ZMQ::SUB, ZMQ::PUSH, ZMQ::PULL, ZMQ::PAIR, ZMQ::XPUB, ZMQ::XSUB]
|
15
|
+
end
|
16
|
+
|
9
17
|
context "when initializing" do
|
10
18
|
before(:all) { @ctx = Context.new }
|
11
19
|
after(:all) { @ctx.terminate }
|
@@ -15,9 +23,24 @@ module ZMQ
|
|
15
23
|
lambda { Socket.new(FFI::Pointer.new(0), ZMQ::REQ) }.should raise_exception(ZMQ::ContextError)
|
16
24
|
end
|
17
25
|
|
18
|
-
|
26
|
+
it "works with a Context#pointer as the context_ptr" do
|
27
|
+
lambda do
|
28
|
+
s = Socket.new(@ctx.pointer, ZMQ::REQ)
|
29
|
+
s.close
|
30
|
+
end.should_not raise_exception(ZMQ::ContextError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "works with a Context instance as the context_ptr" do
|
34
|
+
lambda do
|
35
|
+
s = Socket.new(@ctx, ZMQ::SUB)
|
36
|
+
s.close
|
37
|
+
end.should_not raise_exception(ZMQ::ContextError)
|
38
|
+
end
|
39
|
+
|
19
40
|
|
20
|
-
|
41
|
+
socket_types.each do |socket_type|
|
42
|
+
|
43
|
+
it "should not raise an error for a [#{ZMQ::SocketTypeNameMap[socket_type]}] socket type" do
|
21
44
|
sock = nil
|
22
45
|
lambda { sock = Socket.new(@ctx.pointer, socket_type) }.should_not raise_error
|
23
46
|
sock.close
|
@@ -39,8 +62,8 @@ module ZMQ
|
|
39
62
|
sock.close
|
40
63
|
end
|
41
64
|
end # context initializing
|
42
|
-
|
43
|
-
|
65
|
+
|
66
|
+
|
44
67
|
context "calling close" do
|
45
68
|
before(:all) { @ctx = Context.new }
|
46
69
|
after(:all) { @ctx.terminate }
|
@@ -57,49 +80,57 @@ module ZMQ
|
|
57
80
|
end # context calling close
|
58
81
|
|
59
82
|
|
60
|
-
|
61
|
-
before(:all) { @ctx = Context.new }
|
62
|
-
after(:all) { @ctx.terminate }
|
83
|
+
if version2? || version3?
|
63
84
|
|
64
|
-
|
65
|
-
|
85
|
+
context "identity=" do
|
86
|
+
before(:all) { @ctx = Context.new }
|
87
|
+
after(:all) { @ctx.terminate }
|
66
88
|
|
67
|
-
|
68
|
-
|
69
|
-
end
|
89
|
+
it "fails to set identity for identities in excess of 255 bytes" do
|
90
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
70
91
|
|
71
|
-
|
72
|
-
|
92
|
+
sock.identity = ('a' * 256)
|
93
|
+
sock.identity.should == ''
|
94
|
+
sock.close
|
95
|
+
end
|
73
96
|
|
74
|
-
|
75
|
-
|
76
|
-
end
|
97
|
+
it "fails to set identity for identities of length 0" do
|
98
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
77
99
|
|
78
|
-
|
79
|
-
|
100
|
+
sock.identity = ''
|
101
|
+
sock.identity.should == ''
|
102
|
+
sock.close
|
103
|
+
end
|
80
104
|
|
81
|
-
|
82
|
-
|
83
|
-
end
|
105
|
+
it "sets the identity for identities of 1 byte" do
|
106
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
84
107
|
|
85
|
-
|
86
|
-
|
108
|
+
sock.identity = 'a'
|
109
|
+
sock.identity.should == 'a'
|
110
|
+
sock.close
|
111
|
+
end
|
87
112
|
|
88
|
-
|
89
|
-
|
90
|
-
end
|
113
|
+
it "set the identity identities of 255 bytes" do
|
114
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
91
115
|
|
92
|
-
|
93
|
-
|
116
|
+
sock.identity = ('a' * 255)
|
117
|
+
sock.identity.should == ('a' * 255)
|
118
|
+
sock.close
|
119
|
+
end
|
94
120
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
121
|
+
it "should convert numeric identities to strings" do
|
122
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
123
|
+
|
124
|
+
sock.identity = 7
|
125
|
+
sock.identity.should == '7'
|
126
|
+
sock.close
|
127
|
+
end
|
128
|
+
end # context identity=
|
100
129
|
|
130
|
+
end # version2? || version3?
|
101
131
|
|
102
|
-
|
132
|
+
|
133
|
+
socket_types.each do |socket_type|
|
103
134
|
|
104
135
|
context "#setsockopt for a #{ZMQ::SocketTypeNameMap[socket_type]} socket" do
|
105
136
|
before(:all) { @ctx = Context.new }
|
@@ -114,14 +145,116 @@ module ZMQ
|
|
114
145
|
end
|
115
146
|
|
116
147
|
|
148
|
+
if version2? || version3?
|
149
|
+
|
150
|
+
context "using option ZMQ::IDENTITY" do
|
151
|
+
it "should set the identity given any string under 255 characters" do
|
152
|
+
length = 4
|
153
|
+
(1..255).each do |length|
|
154
|
+
identity = 'a' * length
|
155
|
+
socket.setsockopt ZMQ::IDENTITY, identity
|
156
|
+
|
157
|
+
array = []
|
158
|
+
rc = socket.getsockopt(ZMQ::IDENTITY, array)
|
159
|
+
rc.should == 0
|
160
|
+
array[0].should == identity
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it "returns -1 given a string 256 characters or longer" do
|
165
|
+
identity = 'a' * 256
|
166
|
+
array = []
|
167
|
+
rc = socket.setsockopt(ZMQ::IDENTITY, identity)
|
168
|
+
rc.should == -1
|
169
|
+
end
|
170
|
+
end # context using option ZMQ::IDENTITY
|
171
|
+
|
172
|
+
end # version2? || version3?
|
173
|
+
|
174
|
+
|
175
|
+
if version2?
|
176
|
+
|
177
|
+
context "using option ZMQ::HWM" do
|
178
|
+
it "should set the high water mark given a positive value" do
|
179
|
+
hwm = 4
|
180
|
+
socket.setsockopt ZMQ::HWM, hwm
|
181
|
+
array = []
|
182
|
+
rc = socket.getsockopt(ZMQ::HWM, array)
|
183
|
+
rc.should == 0
|
184
|
+
array[0].should == hwm
|
185
|
+
end
|
186
|
+
end # context using option ZMQ::HWM
|
187
|
+
|
188
|
+
|
189
|
+
context "using option ZMQ::SWAP" do
|
190
|
+
it "should set the swap value given a positive value" do
|
191
|
+
swap = 10_000
|
192
|
+
socket.setsockopt ZMQ::SWAP, swap
|
193
|
+
array = []
|
194
|
+
rc = socket.getsockopt(ZMQ::SWAP, array)
|
195
|
+
rc.should == 0
|
196
|
+
array[0].should == swap
|
197
|
+
end
|
198
|
+
|
199
|
+
it "returns -1 given a negative value" do
|
200
|
+
swap = -10_000
|
201
|
+
rc = socket.setsockopt(ZMQ::SWAP, swap)
|
202
|
+
rc.should == -1
|
203
|
+
end
|
204
|
+
end # context using option ZMQ::SWP
|
205
|
+
|
206
|
+
|
207
|
+
context "using option ZMQ::MCAST_LOOP" do
|
208
|
+
it "should enable the multicast loopback given a 1 (true) value" do
|
209
|
+
socket.setsockopt ZMQ::MCAST_LOOP, 1
|
210
|
+
array = []
|
211
|
+
rc = socket.getsockopt(ZMQ::MCAST_LOOP, array)
|
212
|
+
rc.should == 0
|
213
|
+
array[0].should be_true
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should disable the multicast loopback given a 0 (false) value" do
|
217
|
+
socket.setsockopt ZMQ::MCAST_LOOP, 0
|
218
|
+
array = []
|
219
|
+
rc = socket.getsockopt(ZMQ::MCAST_LOOP, array)
|
220
|
+
rc.should == 0
|
221
|
+
array[0].should be_false
|
222
|
+
end
|
223
|
+
end # context using option ZMQ::MCAST_LOOP
|
224
|
+
|
225
|
+
|
226
|
+
context "using option ZMQ::RECOVERY_IVL_MSEC" do
|
227
|
+
it "should set the time interval for saving messages measured in milliseconds given a positive value" do
|
228
|
+
value = 200
|
229
|
+
socket.setsockopt ZMQ::RECOVERY_IVL_MSEC, value
|
230
|
+
array = []
|
231
|
+
rc = socket.getsockopt(ZMQ::RECOVERY_IVL_MSEC, array)
|
232
|
+
rc.should == 0
|
233
|
+
array[0].should == value
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should default to a value of -1" do
|
237
|
+
value = -1
|
238
|
+
array = []
|
239
|
+
rc = socket.getsockopt(ZMQ::RECOVERY_IVL_MSEC, array)
|
240
|
+
rc.should == 0
|
241
|
+
array[0].should == value
|
242
|
+
end
|
243
|
+
end # context using option ZMQ::RECOVERY_IVL_MSEC
|
244
|
+
|
245
|
+
end # version2?
|
246
|
+
|
247
|
+
|
117
248
|
context "using option ZMQ::SUBSCRIBE" do
|
118
249
|
if ZMQ::SUB == socket_type
|
119
|
-
it "
|
120
|
-
|
250
|
+
it "returns 0 for a SUB socket" do
|
251
|
+
rc = socket.setsockopt(ZMQ::SUBSCRIBE, "topic.string")
|
252
|
+
rc.should == 0
|
121
253
|
end
|
122
254
|
else
|
123
|
-
it "
|
124
|
-
|
255
|
+
it "returns -1 for non-SUB sockets" do
|
256
|
+
rc = socket.setsockopt(ZMQ::SUBSCRIBE, "topic.string")
|
257
|
+
rc.should == -1
|
125
258
|
end
|
126
259
|
end
|
127
260
|
end # context using option ZMQ::SUBSCRIBE
|
@@ -129,94 +262,47 @@ module ZMQ
|
|
129
262
|
|
130
263
|
context "using option ZMQ::UNSUBSCRIBE" do
|
131
264
|
if ZMQ::SUB == socket_type
|
132
|
-
it "
|
265
|
+
it "returns 0 given a topic string that was previously subscribed" do
|
133
266
|
socket.setsockopt ZMQ::SUBSCRIBE, "topic.string"
|
134
|
-
|
267
|
+
rc = socket.setsockopt(ZMQ::UNSUBSCRIBE, "topic.string")
|
268
|
+
rc.should == 0
|
135
269
|
end
|
136
270
|
|
137
|
-
# it "should raise a ZMQ::SocketError given a topic string that was never subscribed" do
|
138
|
-
# socket.setsockopt ZMQ::SUBSCRIBE, "topic.string"
|
139
|
-
# lambda { socket.setsockopt(ZMQ::UNSUBSCRIBE, "unknown") }.should raise_error(SocketError)
|
140
|
-
# end
|
141
271
|
else
|
142
|
-
it "
|
143
|
-
|
272
|
+
it "returns -1 for non-SUB sockets" do
|
273
|
+
rc = socket.setsockopt(ZMQ::UNSUBSCRIBE, "topic.string")
|
274
|
+
rc.should == -1
|
144
275
|
end
|
145
276
|
end
|
146
277
|
end # context using option ZMQ::UNSUBSCRIBE
|
147
278
|
|
148
279
|
|
149
|
-
context "using option ZMQ::HWM" do
|
150
|
-
it "should set the high water mark given a positive value" do
|
151
|
-
hwm = 4
|
152
|
-
socket.setsockopt ZMQ::HWM, hwm
|
153
|
-
socket.getsockopt(ZMQ::HWM).should == hwm
|
154
|
-
end
|
155
|
-
|
156
|
-
it "should convert a negative value to a positive value" do
|
157
|
-
hwm = -4
|
158
|
-
socket.setsockopt ZMQ::HWM, hwm
|
159
|
-
socket.getsockopt(ZMQ::HWM).should == hwm.abs
|
160
|
-
end
|
161
|
-
end # context using option ZMQ::HWM
|
162
|
-
|
163
|
-
|
164
|
-
context "using option ZMQ::SWAP" do
|
165
|
-
it "should set the swap value given a positive value" do
|
166
|
-
swap = 10_000
|
167
|
-
socket.setsockopt ZMQ::SWAP, swap
|
168
|
-
socket.getsockopt(ZMQ::SWAP).should == swap
|
169
|
-
end
|
170
|
-
|
171
|
-
it "should raise a SocketError given a negative value" do
|
172
|
-
swap = -10_000
|
173
|
-
lambda { socket.setsockopt(ZMQ::SWAP, swap) }.should raise_error(SocketError)
|
174
|
-
end
|
175
|
-
end # context using option ZMQ::SWP
|
176
|
-
|
177
|
-
|
178
280
|
context "using option ZMQ::AFFINITY" do
|
179
281
|
it "should set the affinity value given a positive value" do
|
180
282
|
affinity = 3
|
181
283
|
socket.setsockopt ZMQ::AFFINITY, affinity
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
affinity = -3
|
187
|
-
socket.setsockopt ZMQ::AFFINITY, affinity
|
188
|
-
socket.getsockopt(ZMQ::AFFINITY).should == affinity.abs
|
284
|
+
array = []
|
285
|
+
rc = socket.getsockopt(ZMQ::AFFINITY, array)
|
286
|
+
rc.should == 0
|
287
|
+
array[0].should == affinity
|
189
288
|
end
|
190
289
|
end # context using option ZMQ::AFFINITY
|
191
290
|
|
192
291
|
|
193
|
-
context "using option ZMQ::IDENTITY" do
|
194
|
-
it "should set the identity given any string under 255 characters" do
|
195
|
-
length = 4
|
196
|
-
(1..255).each do |length|
|
197
|
-
identity = 'a' * length
|
198
|
-
socket.setsockopt ZMQ::IDENTITY, identity
|
199
|
-
socket.getsockopt(ZMQ::IDENTITY).should == identity
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
it "should raise a SocketError given a string 256 characters or longer" do
|
204
|
-
identity = 'a' * 256
|
205
|
-
lambda { socket.setsockopt(ZMQ::IDENTITY, identity) }.should raise_error(SocketError)
|
206
|
-
end
|
207
|
-
end # context using option ZMQ::IDENTITY
|
208
|
-
|
209
|
-
|
210
292
|
context "using option ZMQ::RATE" do
|
211
293
|
it "should set the multicast send rate given a positive value" do
|
212
294
|
rate = 200
|
213
295
|
socket.setsockopt ZMQ::RATE, rate
|
214
|
-
|
296
|
+
array = []
|
297
|
+
rc = socket.getsockopt(ZMQ::RATE, array)
|
298
|
+
rc.should == 0
|
299
|
+
array[0].should == rate
|
215
300
|
end
|
216
301
|
|
217
|
-
it "
|
302
|
+
it "returns -1 given a negative value" do
|
218
303
|
rate = -200
|
219
|
-
|
304
|
+
rc = socket.setsockopt ZMQ::RATE, rate
|
305
|
+
rc.should == -1
|
220
306
|
end
|
221
307
|
end # context using option ZMQ::RATE
|
222
308
|
|
@@ -225,40 +311,28 @@ module ZMQ
|
|
225
311
|
it "should set the multicast recovery buffer measured in seconds given a positive value" do
|
226
312
|
rate = 200
|
227
313
|
socket.setsockopt ZMQ::RECOVERY_IVL, rate
|
228
|
-
|
314
|
+
array = []
|
315
|
+
rc = socket.getsockopt(ZMQ::RECOVERY_IVL, array)
|
316
|
+
rc.should == 0
|
317
|
+
array[0].should == rate
|
229
318
|
end
|
230
319
|
|
231
|
-
it "
|
320
|
+
it "returns -1 given a negative value" do
|
232
321
|
rate = -200
|
233
|
-
|
322
|
+
rc = socket.setsockopt ZMQ::RECOVERY_IVL, rate
|
323
|
+
rc.should == -1
|
234
324
|
end
|
235
325
|
end # context using option ZMQ::RECOVERY_IVL
|
236
326
|
|
237
327
|
|
238
|
-
context "using option ZMQ::MCAST_LOOP" do
|
239
|
-
it "should enable the multicast loopback given a true value" do
|
240
|
-
socket.setsockopt ZMQ::MCAST_LOOP, true
|
241
|
-
socket.getsockopt(ZMQ::MCAST_LOOP).should be_true
|
242
|
-
end
|
243
|
-
|
244
|
-
it "should disable the multicast loopback given a false value" do
|
245
|
-
socket.setsockopt ZMQ::MCAST_LOOP, false
|
246
|
-
socket.getsockopt(ZMQ::MCAST_LOOP).should be_false
|
247
|
-
end
|
248
|
-
end # context using option ZMQ::MCAST_LOOP
|
249
|
-
|
250
|
-
|
251
328
|
context "using option ZMQ::SNDBUF" do
|
252
329
|
it "should set the OS send buffer given a positive value" do
|
253
330
|
size = 100
|
254
331
|
socket.setsockopt ZMQ::SNDBUF, size
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
size = -100
|
260
|
-
socket.setsockopt ZMQ::SNDBUF, size
|
261
|
-
socket.getsockopt(ZMQ::SNDBUF).should == size.abs
|
332
|
+
array = []
|
333
|
+
rc = socket.getsockopt(ZMQ::SNDBUF, array)
|
334
|
+
rc.should == 0
|
335
|
+
array[0].should == size
|
262
336
|
end
|
263
337
|
end # context using option ZMQ::SNDBUF
|
264
338
|
|
@@ -267,13 +341,10 @@ module ZMQ
|
|
267
341
|
it "should set the OS receive buffer given a positive value" do
|
268
342
|
size = 100
|
269
343
|
socket.setsockopt ZMQ::RCVBUF, size
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
size = -100
|
275
|
-
socket.setsockopt ZMQ::RCVBUF, size
|
276
|
-
socket.getsockopt(ZMQ::RCVBUF).should == size.abs
|
344
|
+
array = []
|
345
|
+
rc = socket.getsockopt(ZMQ::RCVBUF, array)
|
346
|
+
rc.should == 0
|
347
|
+
array[0].should == size
|
277
348
|
end
|
278
349
|
end # context using option ZMQ::RCVBUF
|
279
350
|
|
@@ -282,18 +353,27 @@ module ZMQ
|
|
282
353
|
it "should set the socket message linger option measured in milliseconds given a positive value" do
|
283
354
|
value = 200
|
284
355
|
socket.setsockopt ZMQ::LINGER, value
|
285
|
-
|
356
|
+
array = []
|
357
|
+
rc = socket.getsockopt(ZMQ::LINGER, array)
|
358
|
+
rc.should == 0
|
359
|
+
array[0].should == value
|
286
360
|
end
|
287
361
|
|
288
362
|
it "should set the socket message linger option to 0 for dropping packets" do
|
289
363
|
value = 0
|
290
364
|
socket.setsockopt ZMQ::LINGER, value
|
291
|
-
|
365
|
+
array = []
|
366
|
+
rc = socket.getsockopt(ZMQ::LINGER, array)
|
367
|
+
rc.should == 0
|
368
|
+
array[0].should == value
|
292
369
|
end
|
293
370
|
|
294
371
|
it "should default to a value of -1" do
|
295
372
|
value = -1
|
296
|
-
|
373
|
+
array = []
|
374
|
+
rc = socket.getsockopt(ZMQ::LINGER, array)
|
375
|
+
rc.should == 0
|
376
|
+
array[0].should == value
|
297
377
|
end
|
298
378
|
end # context using option ZMQ::LINGER
|
299
379
|
|
@@ -302,12 +382,18 @@ module ZMQ
|
|
302
382
|
it "should set the time interval for reconnecting disconnected sockets measured in milliseconds given a positive value" do
|
303
383
|
value = 200
|
304
384
|
socket.setsockopt ZMQ::RECONNECT_IVL, value
|
305
|
-
|
385
|
+
array = []
|
386
|
+
rc = socket.getsockopt(ZMQ::RECONNECT_IVL, array)
|
387
|
+
rc.should == 0
|
388
|
+
array[0].should == value
|
306
389
|
end
|
307
390
|
|
308
391
|
it "should default to a value of 100" do
|
309
392
|
value = 100
|
310
|
-
|
393
|
+
array = []
|
394
|
+
rc = socket.getsockopt(ZMQ::RECONNECT_IVL, array)
|
395
|
+
rc.should == 0
|
396
|
+
array[0].should == value
|
311
397
|
end
|
312
398
|
end # context using option ZMQ::RECONNECT_IVL
|
313
399
|
|
@@ -316,28 +402,20 @@ module ZMQ
|
|
316
402
|
it "should set the maximum number of pending socket connections given a positive value" do
|
317
403
|
value = 200
|
318
404
|
socket.setsockopt ZMQ::BACKLOG, value
|
319
|
-
|
405
|
+
array = []
|
406
|
+
rc = socket.getsockopt(ZMQ::BACKLOG, array)
|
407
|
+
rc.should == 0
|
408
|
+
array[0].should == value
|
320
409
|
end
|
321
410
|
|
322
411
|
it "should default to a value of 100" do
|
323
412
|
value = 100
|
324
|
-
|
413
|
+
array = []
|
414
|
+
rc = socket.getsockopt(ZMQ::BACKLOG, array)
|
415
|
+
rc.should == 0
|
416
|
+
array[0].should == value
|
325
417
|
end
|
326
418
|
end # context using option ZMQ::BACKLOG
|
327
|
-
|
328
|
-
|
329
|
-
context "using option ZMQ::RECOVERY_IVL_MSEC" do
|
330
|
-
it "should set the time interval for saving messages measured in milliseconds given a positive value" do
|
331
|
-
value = 200
|
332
|
-
socket.setsockopt ZMQ::RECOVERY_IVL_MSEC, value
|
333
|
-
socket.getsockopt(ZMQ::RECOVERY_IVL_MSEC).should == value
|
334
|
-
end
|
335
|
-
|
336
|
-
it "should default to a value of -1" do
|
337
|
-
value = -1
|
338
|
-
socket.getsockopt(ZMQ::RECOVERY_IVL_MSEC).should == value
|
339
|
-
end
|
340
|
-
end # context using option ZMQ::RECOVERY_IVL_MSEC
|
341
419
|
end # context #setsockopt
|
342
420
|
|
343
421
|
|
@@ -353,48 +431,70 @@ module ZMQ
|
|
353
431
|
socket.close
|
354
432
|
end
|
355
433
|
|
356
|
-
|
357
|
-
|
358
|
-
socket.getsockopt(ZMQ::FD).should be_a(Fixnum)
|
359
|
-
end
|
434
|
+
if RUBY_PLATFORM =~ /linux|darwin/
|
435
|
+
# this spec doesn't work on Windows; hints welcome
|
360
436
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
# figures out the correct libc for each platform including Windows
|
368
|
-
library = ffi_lib(FFI::Library::LIBC).first
|
369
|
-
attach_function :getsockopt, [:int, :int, :int, :pointer, :pointer], :int
|
370
|
-
end # module LibC
|
371
|
-
|
372
|
-
if RUBY_PLATFORM =~ /linux/ || (RUBY_PLATFORM == 'java' && `uname` =~ /linux/i)
|
373
|
-
so_rcvbuf = 8
|
374
|
-
sol_socket = 1
|
375
|
-
else #OSX
|
376
|
-
so_rcvbuf = 0x1002
|
377
|
-
sol_socket = 0xffff
|
437
|
+
context "using option ZMQ::FD" do
|
438
|
+
it "should return an FD as a positive integer" do
|
439
|
+
array = []
|
440
|
+
rc = socket.getsockopt(ZMQ::FD, array)
|
441
|
+
rc.should == 0
|
442
|
+
array[0].should be_a(Fixnum)
|
378
443
|
end
|
379
444
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
445
|
+
it "returns a valid FD that is accepted by the system poll() function" do
|
446
|
+
# Use FFI to wrap the C library function +poll+ so that we can execute it
|
447
|
+
# on the 0mq file descriptor. If it returns 0, then it succeeded and the FD
|
448
|
+
# is valid!
|
449
|
+
module LibSocket
|
450
|
+
extend FFI::Library
|
451
|
+
# figures out the correct libc for each platform including Windows
|
452
|
+
library = ffi_lib(FFI::Library::LIBC).first
|
453
|
+
|
454
|
+
find_type(:nfds_t) rescue typedef(:uint32, :nfds_t)
|
455
|
+
|
456
|
+
attach_function :poll, [:pointer, :nfds_t, :int], :int
|
457
|
+
|
458
|
+
class PollFD < FFI::Struct
|
459
|
+
layout :fd, :int,
|
460
|
+
:events, :short,
|
461
|
+
:revents, :short
|
462
|
+
end
|
463
|
+
end # module LibSocket
|
464
|
+
|
465
|
+
array = []
|
466
|
+
rc = socket.getsockopt(ZMQ::FD, array)
|
467
|
+
rc.should be_zero
|
468
|
+
fd = array[0]
|
469
|
+
|
470
|
+
# setup the BSD poll_fd struct
|
471
|
+
pollfd = LibSocket::PollFD.new
|
472
|
+
pollfd[:fd] = fd
|
473
|
+
pollfd[:events] = 0
|
474
|
+
pollfd[:revents] = 0
|
475
|
+
|
476
|
+
rc = LibSocket.poll(pollfd, 1, 0)
|
477
|
+
rc.should be_zero
|
478
|
+
end
|
386
479
|
end
|
387
|
-
|
480
|
+
|
481
|
+
end # posix platform
|
388
482
|
|
389
483
|
context "using option ZMQ::EVENTS" do
|
390
484
|
it "should return a mask of events as a Fixnum" do
|
391
|
-
|
485
|
+
array = []
|
486
|
+
rc = socket.getsockopt(ZMQ::EVENTS, array)
|
487
|
+
rc.should == 0
|
488
|
+
array[0].should be_a(Fixnum)
|
392
489
|
end
|
393
490
|
end
|
394
491
|
|
395
492
|
context "using option ZMQ::TYPE" do
|
396
493
|
it "should return the socket type" do
|
397
|
-
|
494
|
+
array = []
|
495
|
+
rc = socket.getsockopt(ZMQ::TYPE, array)
|
496
|
+
rc.should == 0
|
497
|
+
array[0].should == socket_type
|
398
498
|
end
|
399
499
|
end
|
400
500
|
end # context #getsockopt
|
@@ -402,38 +502,87 @@ module ZMQ
|
|
402
502
|
end # each socket_type
|
403
503
|
|
404
504
|
|
405
|
-
describe "
|
505
|
+
describe "Mapping socket EVENTS to POLLIN and POLLOUT" do
|
406
506
|
include APIHelper
|
507
|
+
|
508
|
+
shared_examples_for "pubsub sockets where" do
|
509
|
+
it "SUB socket that received a message always has POLLIN set" do
|
510
|
+
events = []
|
511
|
+
rc = @sub.getsockopt(ZMQ::EVENTS, events)
|
512
|
+
rc.should == 0
|
513
|
+
events[0].should == ZMQ::POLLIN
|
514
|
+
end
|
515
|
+
|
516
|
+
it "PUB socket always has POLLOUT set" do
|
517
|
+
events = []
|
518
|
+
rc = @pub.getsockopt(ZMQ::EVENTS, events)
|
519
|
+
rc.should == 0
|
520
|
+
events[0].should == ZMQ::POLLOUT
|
521
|
+
end
|
407
522
|
|
408
|
-
|
409
|
-
|
410
|
-
|
523
|
+
it "PUB socket never has POLLIN set" do
|
524
|
+
events = []
|
525
|
+
rc = @pub.getsockopt(ZMQ::EVENTS, events)
|
526
|
+
rc.should == 0
|
527
|
+
events[0].should_not == ZMQ::POLLIN
|
528
|
+
end
|
411
529
|
|
412
|
-
|
413
|
-
|
530
|
+
it "SUB socket never has POLLOUT set" do
|
531
|
+
events = []
|
532
|
+
rc = @sub.getsockopt(ZMQ::EVENTS, events)
|
533
|
+
rc.should == 0
|
534
|
+
events[0].should_not == ZMQ::POLLOUT
|
535
|
+
end
|
536
|
+
end # shared example for pubsub
|
414
537
|
|
415
|
-
|
416
|
-
@pub.connect addr
|
538
|
+
context "when SUB binds and PUB connects" do
|
417
539
|
|
418
|
-
|
540
|
+
before(:each) do
|
541
|
+
@ctx = Context.new
|
419
542
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
543
|
+
@sub = @ctx.socket ZMQ::SUB
|
544
|
+
rc = @sub.setsockopt ZMQ::SUBSCRIBE, ''
|
545
|
+
|
546
|
+
@pub = @ctx.socket ZMQ::PUB
|
547
|
+
port = bind_to_random_tcp_port(@sub)
|
548
|
+
rc = @pub.connect "tcp://127.0.0.1:#{port}"
|
549
|
+
sleep 0.5
|
550
|
+
|
551
|
+
rc = @pub.send_string('test')
|
552
|
+
sleep 0.2
|
553
|
+
end
|
554
|
+
|
555
|
+
it_behaves_like "pubsub sockets where"
|
556
|
+
end # context SUB binds PUB connects
|
557
|
+
|
558
|
+
context "when SUB connects and PUB binds" do
|
559
|
+
|
560
|
+
before(:each) do
|
561
|
+
@ctx = Context.new
|
562
|
+
|
563
|
+
@sub = @ctx.socket ZMQ::SUB
|
564
|
+
rc = @sub.setsockopt ZMQ::SUBSCRIBE, ''
|
565
|
+
|
566
|
+
@pub = @ctx.socket ZMQ::PUB
|
567
|
+
port = bind_to_random_tcp_port(@pub)
|
568
|
+
rc = @sub.connect "tcp://127.0.0.1:#{port}"
|
569
|
+
sleep 0.5
|
570
|
+
|
571
|
+
rc = @pub.send_string('test')
|
572
|
+
sleep 0.2
|
573
|
+
end
|
574
|
+
|
575
|
+
it_behaves_like "pubsub sockets where"
|
576
|
+
end # context SUB binds PUB connects
|
577
|
+
|
578
|
+
|
579
|
+
after(:each) do
|
424
580
|
@sub.close
|
425
581
|
@pub.close
|
426
582
|
# must call close on *every* socket before calling terminate otherwise it blocks indefinitely
|
427
583
|
@ctx.terminate
|
428
584
|
end
|
429
585
|
|
430
|
-
it "should have only POLLIN set for a sub socket that received a message" do
|
431
|
-
#@sub.getsockopt(ZMQ::EVENTS).should == ZMQ::POLLIN
|
432
|
-
end
|
433
|
-
|
434
|
-
it "should have only POLLOUT set for a sub socket that received a message" do
|
435
|
-
#@pub.getsockopt(ZMQ::EVENTS).should == ZMQ::POLLOUT
|
436
|
-
end
|
437
586
|
end # describe 'events mapping to pollin and pollout'
|
438
587
|
|
439
588
|
end # describe Socket
|