ffi-rzmq 0.6.0 → 0.7.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/.bnsignore +22 -0
- data/History.txt +36 -0
- data/README.rdoc +18 -22
- data/Rakefile +22 -5
- data/examples/local_lat_poll.rb +54 -0
- data/ffi-rzmq.gemspec +9 -9
- data/lib/ffi-rzmq/context.rb +1 -1
- data/lib/ffi-rzmq/poll.rb +7 -1
- data/lib/ffi-rzmq/socket.rb +75 -21
- data/lib/ffi-rzmq/wrapper.rb +8 -6
- data/lib/ffi-rzmq/zmq.rb +27 -1
- data/spec/context_spec.rb +7 -34
- data/spec/pushpull_spec.rb +16 -19
- data/spec/reqrep_spec.rb +5 -0
- data/spec/socket_spec.rb +249 -109
- data/spec/spec_helper.rb +3 -13
- data/version.txt +1 -1
- metadata +10 -10
- data/.gitignore +0 -2
- data/examples/xreqxrep_poll.rb +0 -82
data/lib/ffi-rzmq/wrapper.rb
CHANGED
@@ -5,11 +5,11 @@ module LibC
|
|
5
5
|
# figures out the correct libc for each platform including Windows
|
6
6
|
library = ffi_lib(FFI::Library::LIBC).first
|
7
7
|
|
8
|
+
# Size_t not working properly on Windows
|
9
|
+
find_type(:size_t) rescue typedef(:ulong, :size_t)
|
10
|
+
|
8
11
|
# memory allocators
|
9
12
|
attach_function :malloc, [:size_t], :pointer
|
10
|
-
attach_function :calloc, [:size_t], :pointer
|
11
|
-
attach_function :valloc, [:size_t], :pointer
|
12
|
-
attach_function :realloc, [:pointer, :size_t], :pointer
|
13
13
|
attach_function :free, [:pointer], :void
|
14
14
|
|
15
15
|
# get a pointer to the free function; used for ZMQ::Message deallocation
|
@@ -17,17 +17,17 @@ module LibC
|
|
17
17
|
|
18
18
|
# memory movers
|
19
19
|
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
|
20
|
-
attach_function :bcopy, [:pointer, :pointer, :size_t], :void
|
21
|
-
|
22
20
|
end # module LibC
|
23
21
|
|
24
22
|
module LibZMQ
|
25
23
|
extend FFI::Library
|
26
|
-
LINUX = ["libzmq", "/usr/local/lib/libzmq", "/opt/local/lib/libzmq"]
|
24
|
+
LINUX = ["libzmq", "/usr/local/lib/libzmq", "/usr/local/lib/libzmq.so", "/opt/local/lib/libzmq"]
|
27
25
|
OSX = ["libzmq", "/usr/local/lib/libzmq", "/opt/local/lib/libzmq"]
|
28
26
|
WINDOWS = []
|
29
27
|
ffi_lib(LINUX + OSX + WINDOWS)
|
30
28
|
|
29
|
+
# Size_t not working properly on Windows
|
30
|
+
find_type(:size_t) rescue typedef(:ulong, :size_t)
|
31
31
|
|
32
32
|
# Misc
|
33
33
|
attach_function :zmq_version, [:pointer, :pointer, :pointer], :void
|
@@ -66,6 +66,8 @@ module LibZMQ
|
|
66
66
|
# thread within the lib may try to call back into the ruby runtime. Failure to
|
67
67
|
# release the GIL will result in a hang; the hint *may* allow things to run
|
68
68
|
# smoothly for Ruby runtimes hampered by a GIL.
|
69
|
+
#
|
70
|
+
# This is really only honored by the MRI implementation.
|
69
71
|
attach_function :zmq_setsockopt, [:pointer, :int, :pointer, :int], :int
|
70
72
|
attach_function :zmq_getsockopt, [:pointer, :int, :pointer, :pointer], :int
|
71
73
|
attach_function :zmq_bind, [:pointer, :string], :int
|
data/lib/ffi-rzmq/zmq.rb
CHANGED
@@ -37,6 +37,13 @@ module ZMQ
|
|
37
37
|
SNDBUF = 11
|
38
38
|
RCVBUF = 12
|
39
39
|
RCVMORE = 13
|
40
|
+
FD = 14
|
41
|
+
EVENTS = 15
|
42
|
+
TYPE = 16
|
43
|
+
LINGER = 17
|
44
|
+
RECONNECT_IVL = 18
|
45
|
+
BACKLOG = 19
|
46
|
+
RECOVERY_IVL_MSEC = 20
|
40
47
|
|
41
48
|
# Send/recv options
|
42
49
|
NOBLOCK = 1
|
@@ -98,13 +105,32 @@ module ZMQ
|
|
98
105
|
# Returns an array of the form [major, minor, patch] to represent the
|
99
106
|
# version of libzmq.
|
100
107
|
#
|
101
|
-
|
108
|
+
# Class method! Invoke as: ZMQ::Util.version
|
109
|
+
#
|
110
|
+
def self.version
|
102
111
|
major = FFI::MemoryPointer.new :int
|
103
112
|
minor = FFI::MemoryPointer.new :int
|
104
113
|
patch = FFI::MemoryPointer.new :int
|
105
114
|
LibZMQ.zmq_version major, minor, patch
|
106
115
|
[major.read_int, minor.read_int, patch.read_int]
|
107
116
|
end
|
117
|
+
|
118
|
+
# Compares the 0mq library API version to a minimal version tuple. Returns
|
119
|
+
# true if it meets the minimum requirement, false otherwise.
|
120
|
+
#
|
121
|
+
# Takes a +tuple+ with 3 elements corresponding to the major, minor and patch
|
122
|
+
# version levels.
|
123
|
+
#
|
124
|
+
# e.g. Util.minimum_api?([2, 1, 0])
|
125
|
+
#
|
126
|
+
def self.minimum_api? tuple
|
127
|
+
api_version = Util.version
|
128
|
+
|
129
|
+
# call #to_i to convert nil entries to 0 so the comparison is valid
|
130
|
+
tuple[0].to_i >= api_version[0] &&
|
131
|
+
tuple[1].to_i >= api_version[1] &&
|
132
|
+
tuple[2].to_i >= api_version[2]
|
133
|
+
end
|
108
134
|
|
109
135
|
|
110
136
|
private
|
data/spec/context_spec.rb
CHANGED
@@ -23,17 +23,17 @@ module ZMQ
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should set the :pointer accessor to non-nil" do
|
26
|
-
ctx =
|
26
|
+
ctx = spec_ctx
|
27
27
|
ctx.pointer.should_not be_nil
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should set the :context accessor to non-nil" do
|
31
|
-
ctx =
|
31
|
+
ctx = spec_ctx
|
32
32
|
ctx.context.should_not be_nil
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should set the :pointer and :context accessors to the same value" do
|
36
|
-
ctx =
|
36
|
+
ctx = spec_ctx
|
37
37
|
ctx.pointer.should == ctx.context
|
38
38
|
end
|
39
39
|
|
@@ -46,13 +46,13 @@ module ZMQ
|
|
46
46
|
|
47
47
|
context "when terminating" do
|
48
48
|
it "should call zmq_term to terminate the library's context" do
|
49
|
-
ctx = Context.new
|
49
|
+
ctx = Context.new # can't use a shared context here because we are terminating it!
|
50
50
|
LibZMQ.should_receive(:zmq_term).with(ctx.pointer).and_return(0)
|
51
51
|
ctx.terminate
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should raise a ZMQ::ContextError exception when it fails" do
|
55
|
-
ctx = Context.new
|
55
|
+
ctx = Context.new # can't use a shared context here because we are terminating it!
|
56
56
|
LibZMQ.stub(:zmq_term => 1)
|
57
57
|
lambda { ctx.terminate }.should raise_error(ZMQ::ContextError)
|
58
58
|
end
|
@@ -61,44 +61,17 @@ module ZMQ
|
|
61
61
|
|
62
62
|
context "when allocating a socket" do
|
63
63
|
it "should return a ZMQ::Socket" do
|
64
|
-
ctx =
|
64
|
+
ctx = spec_ctx
|
65
65
|
ctx.socket(ZMQ::REQ).should be_kind_of(ZMQ::Socket)
|
66
66
|
end
|
67
67
|
|
68
68
|
it "should raise a ZMQ::SocketError exception when allocation fails" do
|
69
|
-
ctx =
|
69
|
+
ctx = spec_ctx
|
70
70
|
Socket.stub(:new => nil)
|
71
71
|
lambda { ctx.socket(ZMQ::REQ) }.should raise_error(ZMQ::SocketError)
|
72
72
|
end
|
73
73
|
end # context socket
|
74
74
|
|
75
|
-
|
76
|
-
# context "when allocating a device" do
|
77
|
-
# let(:ctx) { Context.new 1 }
|
78
|
-
# let(:sock1) { ctx.socket ZMQ::REQ }
|
79
|
-
# let(:sock2) { ctx.socket ZMQ::REP }
|
80
|
-
#
|
81
|
-
# it "should return a ZMQ::Forwarder" do
|
82
|
-
# device = ctx.device ZMQ::FORWARDER, sock1, sock2
|
83
|
-
# device.should be_kind_of(ZMQ::Forwarder)
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# it "should return a ZMQ::Queue" do
|
87
|
-
# device = ctx.device ZMQ::QUEUE, sock1, sock2
|
88
|
-
# device.should be_kind_of(ZMQ::Queue)
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
# it "should return a ZMQ::Streamer" do
|
92
|
-
# device = ctx.device ZMQ::STREAMER, sock1, sock2
|
93
|
-
# device.should be_kind_of(ZMQ::Streamer)
|
94
|
-
# end
|
95
|
-
#
|
96
|
-
# it "should raise an exception when the requested device is unknown" do
|
97
|
-
# lambda { ctx.device(-1, sock1, sock2) }.should raise_error(ZMQ::DeviceError)
|
98
|
-
# end
|
99
|
-
# end # context device
|
100
|
-
|
101
|
-
|
102
75
|
end # describe Context
|
103
76
|
|
104
77
|
|
data/spec/pushpull_spec.rb
CHANGED
@@ -10,14 +10,19 @@ module ZMQ
|
|
10
10
|
|
11
11
|
before(:each) do
|
12
12
|
$stdout.flush
|
13
|
-
@context = ZMQ::Context.new
|
13
|
+
@context = ZMQ::Context.new
|
14
14
|
@push = @context.socket ZMQ::PUSH
|
15
15
|
@pull = @context.socket ZMQ::PULL
|
16
16
|
@link = "tcp://127.0.0.1:#{random_port}"
|
17
17
|
@pull.connect @link
|
18
18
|
@push.bind @link
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
|
+
after(:each) do
|
22
|
+
@push.close
|
23
|
+
@pull.close
|
24
|
+
end
|
25
|
+
|
21
26
|
it "should receive an exact copy of the sent message using Message objects directly on one pull socket" do
|
22
27
|
@push.send_string string
|
23
28
|
received = @pull.recv_string
|
@@ -34,32 +39,24 @@ module ZMQ
|
|
34
39
|
received_message.copy_out_string.should == string
|
35
40
|
end
|
36
41
|
|
37
|
-
it "should receive an exact string copy of the message sent when sending in non-blocking mode and using Message objects directly" do
|
38
|
-
sent_message = Message.new string
|
39
|
-
received_message = Message.new
|
40
|
-
|
41
|
-
@push.send sent_message, ZMQ::NOBLOCK
|
42
|
-
sleep 0.1 # give it time for delivery
|
43
|
-
@pull.recv received_message, ZMQ::NOBLOCK
|
44
|
-
received_message.copy_out_string.should == string
|
45
|
-
end
|
46
|
-
|
47
42
|
it "should receive a single message for each message sent on each socket listening, when an equal number pulls to messages" do
|
48
43
|
received = []
|
49
44
|
threads = []
|
50
45
|
count = 4
|
46
|
+
@pull.close # close this one since we aren't going to use it below and we don't want it to receive a message
|
51
47
|
|
52
|
-
count.times
|
53
|
-
threads << Thread.new
|
48
|
+
count.times do
|
49
|
+
threads << Thread.new do
|
54
50
|
pull = @context.socket ZMQ::PULL
|
55
|
-
pull.connect @link
|
51
|
+
rc = pull.connect @link
|
56
52
|
received << pull.recv_string
|
57
53
|
pull.close
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
count.times { @push.send_string(string); sleep 0.001 }
|
54
|
+
end
|
55
|
+
sleep 0.001 # give each thread time to spin up
|
56
|
+
end
|
62
57
|
|
58
|
+
count.times { @push.send_string(string) }
|
59
|
+
|
63
60
|
threads.each {|t| t.join}
|
64
61
|
|
65
62
|
received.find_all {|r| r == string}.length.should == count
|
data/spec/reqrep_spec.rb
CHANGED
data/spec/socket_spec.rb
CHANGED
@@ -7,105 +7,94 @@ module ZMQ
|
|
7
7
|
describe Socket do
|
8
8
|
|
9
9
|
context "when initializing" do
|
10
|
+
before(:all) { @ctx = Context.new }
|
11
|
+
after(:all) { @ctx.terminate }
|
10
12
|
|
11
|
-
let(:ctx) { Context.new 1 }
|
12
13
|
|
13
14
|
it "should raise an error for a nil context" do
|
14
15
|
lambda { Socket.new(FFI::Pointer::NULL, ZMQ::REQ) }.should raise_exception(ZMQ::ContextError)
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
lambda { Socket.new(ctx.pointer, ZMQ::REQ) }.should_not raise_error
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should not raise an error for a ZMQ::REP socket type" do
|
22
|
-
lambda { Socket.new(ctx.pointer, ZMQ::REP) }.should_not raise_error
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should not raise an error for a ZMQ::PUB socket type" do
|
26
|
-
lambda { Socket.new(ctx.pointer, ZMQ::PUB) }.should_not raise_error
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should not raise an error for a ZMQ::SUB socket type" do
|
30
|
-
lambda { Socket.new(ctx.pointer, ZMQ::SUB) }.should_not raise_error
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should not raise an error for a ZMQ::PAIR socket type" do
|
34
|
-
lambda { Socket.new(ctx.pointer, ZMQ::PAIR) }.should_not raise_error
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should not raise an error for a ZMQ::XREQ socket type" do
|
38
|
-
lambda { Socket.new(ctx.pointer, ZMQ::XREQ) }.should_not raise_error
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should not raise an error for a ZMQ::XREP socket type" do
|
42
|
-
lambda { Socket.new(ctx.pointer, ZMQ::XREP) }.should_not raise_error
|
43
|
-
end
|
18
|
+
[ZMQ::REQ, ZMQ::REP, ZMQ::XREQ, ZMQ::XREP, ZMQ::PUB, ZMQ::SUB, ZMQ::PUSH, ZMQ::PULL, ZMQ::PAIR].each do |socket_type|
|
44
19
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should raise an error for an unknown socket type" do
|
54
|
-
lambda { Socket.new(ctx.pointer, 80) }.should raise_exception(ZMQ::SocketError)
|
55
|
-
end
|
20
|
+
it "should not raise an error for a #{ZMQ::SocketTypeNameMap[socket_type]} socket type" do
|
21
|
+
sock = nil
|
22
|
+
lambda { sock = Socket.new(@ctx.pointer, socket_type) }.should_not raise_error
|
23
|
+
sock.close
|
24
|
+
end
|
25
|
+
end # each socket_type
|
56
26
|
|
57
27
|
it "should set the :socket accessor to the raw socket allocated by libzmq" do
|
58
|
-
socket = mock('socket')
|
28
|
+
socket = mock('socket')
|
59
29
|
socket.stub!(:null? => false)
|
60
30
|
LibZMQ.should_receive(:zmq_socket).and_return(socket)
|
61
31
|
|
62
|
-
sock = Socket.new(ctx.pointer, ZMQ::REQ)
|
32
|
+
sock = Socket.new(@ctx.pointer, ZMQ::REQ)
|
63
33
|
sock.socket.should == socket
|
64
34
|
end
|
65
35
|
|
66
36
|
it "should define a finalizer on this object" do
|
67
|
-
|
68
|
-
|
69
|
-
|
37
|
+
ObjectSpace.should_receive(:define_finalizer).at_least(1)
|
38
|
+
sock = Socket.new(@ctx.pointer, ZMQ::REQ)
|
39
|
+
sock.close
|
70
40
|
end
|
71
41
|
end # context initializing
|
42
|
+
|
43
|
+
|
44
|
+
context "calling close" do
|
45
|
+
before(:all) { @ctx = Context.new }
|
46
|
+
after(:all) { @ctx.terminate }
|
47
|
+
|
48
|
+
it "should call LibZMQ.close only once" do
|
49
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
50
|
+
raw_socket = sock.socket
|
51
|
+
|
52
|
+
LibZMQ.should_receive(:close).with(raw_socket)
|
53
|
+
sock.close
|
54
|
+
sock.close
|
55
|
+
LibZMQ.close raw_socket # *really close it otherwise the context will block indefinitely
|
56
|
+
end
|
57
|
+
end # context calling close
|
72
58
|
|
73
59
|
|
74
60
|
context "identity=" do
|
61
|
+
before(:all) { @ctx = Context.new }
|
62
|
+
after(:all) { @ctx.terminate }
|
63
|
+
|
75
64
|
it "should raise an exception for identities in excess of 255 bytes" do
|
76
|
-
|
77
|
-
sock = Socket.new ctx.pointer, ZMQ::REQ
|
65
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
78
66
|
|
79
67
|
lambda { sock.identity = ('a' * 256) }.should raise_exception(ZMQ::SocketError)
|
68
|
+
sock.close
|
80
69
|
end
|
81
70
|
|
82
71
|
it "should raise an exception for identities of length 0" do
|
83
|
-
|
84
|
-
sock = Socket.new ctx.pointer, ZMQ::REQ
|
72
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
85
73
|
|
86
74
|
lambda { sock.identity = '' }.should raise_exception(ZMQ::SocketError)
|
75
|
+
sock.close
|
87
76
|
end
|
88
77
|
|
89
78
|
it "should NOT raise an exception for identities of 1 byte" do
|
90
|
-
|
91
|
-
sock = Socket.new ctx.pointer, ZMQ::REQ
|
79
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
92
80
|
|
93
81
|
lambda { sock.identity = 'a' }.should_not raise_exception(ZMQ::SocketError)
|
82
|
+
sock.close
|
94
83
|
end
|
95
84
|
|
96
85
|
it "should NOT raise an exception for identities of 255 bytes" do
|
97
|
-
|
98
|
-
sock = Socket.new ctx.pointer, ZMQ::REQ
|
86
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
99
87
|
|
100
88
|
lambda { sock.identity = ('a' * 255) }.should_not raise_exception(ZMQ::SocketError)
|
89
|
+
sock.close
|
101
90
|
end
|
102
91
|
|
103
92
|
it "should convert numeric identities to strings" do
|
104
|
-
|
105
|
-
sock = Socket.new ctx.pointer, ZMQ::REQ
|
93
|
+
sock = Socket.new @ctx.pointer, ZMQ::REQ
|
106
94
|
|
107
95
|
sock.identity = 7
|
108
96
|
sock.identity.should == '7'
|
97
|
+
sock.close
|
109
98
|
end
|
110
99
|
end # context identity=
|
111
100
|
|
@@ -113,9 +102,15 @@ module ZMQ
|
|
113
102
|
[ZMQ::REQ, ZMQ::REP, ZMQ::XREQ, ZMQ::XREP, ZMQ::PUB, ZMQ::SUB, ZMQ::PUSH, ZMQ::PULL, ZMQ::PAIR].each do |socket_type|
|
114
103
|
|
115
104
|
context "#setsockopt for a #{ZMQ::SocketTypeNameMap[socket_type]} socket" do
|
105
|
+
before(:all) { @ctx = Context.new }
|
106
|
+
after(:all) { @ctx.terminate }
|
107
|
+
|
116
108
|
let(:socket) do
|
117
|
-
ctx
|
118
|
-
|
109
|
+
Socket.new @ctx.pointer, socket_type
|
110
|
+
end
|
111
|
+
|
112
|
+
after(:each) do
|
113
|
+
socket.close
|
119
114
|
end
|
120
115
|
|
121
116
|
|
@@ -139,10 +134,10 @@ module ZMQ
|
|
139
134
|
lambda { socket.setsockopt(ZMQ::UNSUBSCRIBE, "topic.string") }.should_not raise_error(SocketError)
|
140
135
|
end
|
141
136
|
|
142
|
-
it "should raise a ZMQ::SocketError given a topic string that was never subscribed" do
|
143
|
-
socket.setsockopt ZMQ::SUBSCRIBE, "topic.string"
|
144
|
-
lambda { socket.setsockopt(ZMQ::UNSUBSCRIBE, "unknown") }.should raise_error(SocketError)
|
145
|
-
end
|
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
|
146
141
|
else
|
147
142
|
it "should raise a ZMQ::SocketError" do
|
148
143
|
lambda { socket.setsockopt(ZMQ::UNSUBSCRIBE, "topic.string") }.should raise_error(SocketError)
|
@@ -166,18 +161,18 @@ module ZMQ
|
|
166
161
|
end # context using option ZMQ::HWM
|
167
162
|
|
168
163
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
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
|
181
176
|
|
182
177
|
|
183
178
|
context "using option ZMQ::AFFINITY" do
|
@@ -193,52 +188,53 @@ module ZMQ
|
|
193
188
|
socket.getsockopt(ZMQ::AFFINITY).should == affinity.abs
|
194
189
|
end
|
195
190
|
end # context using option ZMQ::AFFINITY
|
196
|
-
|
197
|
-
|
191
|
+
|
192
|
+
|
198
193
|
context "using option ZMQ::IDENTITY" do
|
199
194
|
it "should set the identity given any string under 255 characters" do
|
195
|
+
length = 4
|
200
196
|
(1..255).each do |length|
|
201
197
|
identity = 'a' * length
|
202
198
|
socket.setsockopt ZMQ::IDENTITY, identity
|
203
199
|
socket.getsockopt(ZMQ::IDENTITY).should == identity
|
204
200
|
end
|
205
201
|
end
|
206
|
-
|
202
|
+
|
207
203
|
it "should raise a SocketError given a string 256 characters or longer" do
|
208
204
|
identity = 'a' * 256
|
209
205
|
lambda { socket.setsockopt(ZMQ::IDENTITY, identity) }.should raise_error(SocketError)
|
210
206
|
end
|
211
207
|
end # context using option ZMQ::IDENTITY
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
208
|
+
|
209
|
+
|
210
|
+
context "using option ZMQ::RATE" do
|
211
|
+
it "should set the multicast send rate given a positive value" do
|
212
|
+
rate = 200
|
213
|
+
socket.setsockopt ZMQ::RATE, rate
|
214
|
+
socket.getsockopt(ZMQ::RATE).should == rate
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should raise a SocketError given a negative value" do
|
218
|
+
rate = -200
|
219
|
+
lambda { socket.setsockopt ZMQ::RATE, rate }.should raise_error(SocketError)
|
220
|
+
end
|
221
|
+
end # context using option ZMQ::RATE
|
222
|
+
|
223
|
+
|
224
|
+
context "using option ZMQ::RECOVERY_IVL" do
|
225
|
+
it "should set the multicast recovery buffer measured in seconds given a positive value" do
|
226
|
+
rate = 200
|
227
|
+
socket.setsockopt ZMQ::RECOVERY_IVL, rate
|
228
|
+
socket.getsockopt(ZMQ::RECOVERY_IVL).should == rate
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should raise a SocketError given a negative value" do
|
232
|
+
rate = -200
|
233
|
+
lambda { socket.setsockopt ZMQ::RECOVERY_IVL, rate }.should raise_error(SocketError)
|
234
|
+
end
|
235
|
+
end # context using option ZMQ::RECOVERY_IVL
|
236
|
+
|
237
|
+
|
242
238
|
context "using option ZMQ::MCAST_LOOP" do
|
243
239
|
it "should enable the multicast loopback given a true value" do
|
244
240
|
socket.setsockopt ZMQ::MCAST_LOOP, true
|
@@ -250,8 +246,8 @@ module ZMQ
|
|
250
246
|
socket.getsockopt(ZMQ::MCAST_LOOP).should be_false
|
251
247
|
end
|
252
248
|
end # context using option ZMQ::MCAST_LOOP
|
253
|
-
|
254
|
-
|
249
|
+
|
250
|
+
|
255
251
|
context "using option ZMQ::SNDBUF" do
|
256
252
|
it "should set the OS send buffer given a positive value" do
|
257
253
|
size = 100
|
@@ -265,8 +261,8 @@ module ZMQ
|
|
265
261
|
socket.getsockopt(ZMQ::SNDBUF).should == size.abs
|
266
262
|
end
|
267
263
|
end # context using option ZMQ::SNDBUF
|
268
|
-
|
269
|
-
|
264
|
+
|
265
|
+
|
270
266
|
context "using option ZMQ::RCVBUF" do
|
271
267
|
it "should set the OS receive buffer given a positive value" do
|
272
268
|
size = 100
|
@@ -280,11 +276,155 @@ module ZMQ
|
|
280
276
|
socket.getsockopt(ZMQ::RCVBUF).should == size.abs
|
281
277
|
end
|
282
278
|
end # context using option ZMQ::RCVBUF
|
279
|
+
|
280
|
+
|
281
|
+
context "using option ZMQ::LINGER" do
|
282
|
+
it "should set the socket message linger option measured in milliseconds given a positive value" do
|
283
|
+
value = 200
|
284
|
+
socket.setsockopt ZMQ::LINGER, value
|
285
|
+
socket.getsockopt(ZMQ::LINGER).should == value
|
286
|
+
end
|
287
|
+
|
288
|
+
it "should set the socket message linger option to 0 for dropping packets" do
|
289
|
+
value = 0
|
290
|
+
socket.setsockopt ZMQ::LINGER, value
|
291
|
+
socket.getsockopt(ZMQ::LINGER).should == value
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should default to a value of -1" do
|
295
|
+
value = -1
|
296
|
+
socket.getsockopt(ZMQ::LINGER).should == value
|
297
|
+
end
|
298
|
+
end # context using option ZMQ::LINGER
|
299
|
+
|
300
|
+
|
301
|
+
context "using option ZMQ::RECONNECT_IVL" do
|
302
|
+
it "should set the time interval for reconnecting disconnected sockets measured in milliseconds given a positive value" do
|
303
|
+
value = 200
|
304
|
+
socket.setsockopt ZMQ::RECONNECT_IVL, value
|
305
|
+
socket.getsockopt(ZMQ::RECONNECT_IVL).should == value
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should default to a value of 100" do
|
309
|
+
value = 100
|
310
|
+
socket.getsockopt(ZMQ::RECONNECT_IVL).should == value
|
311
|
+
end
|
312
|
+
end # context using option ZMQ::RECONNECT_IVL
|
313
|
+
|
314
|
+
|
315
|
+
context "using option ZMQ::BACKLOG" do
|
316
|
+
it "should set the maximum number of pending socket connections given a positive value" do
|
317
|
+
value = 200
|
318
|
+
socket.setsockopt ZMQ::BACKLOG, value
|
319
|
+
socket.getsockopt(ZMQ::BACKLOG).should == value
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should default to a value of 100" do
|
323
|
+
value = 100
|
324
|
+
socket.getsockopt(ZMQ::BACKLOG).should == value
|
325
|
+
end
|
326
|
+
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
|
283
341
|
end # context #setsockopt
|
284
342
|
|
343
|
+
|
344
|
+
context "#getsockopt for a #{ZMQ::SocketTypeNameMap[socket_type]} socket" do
|
345
|
+
before(:all) { @ctx = Context.new }
|
346
|
+
after(:all) { @ctx.terminate }
|
347
|
+
|
348
|
+
let(:socket) do
|
349
|
+
Socket.new @ctx.pointer, socket_type
|
350
|
+
end
|
351
|
+
|
352
|
+
after(:each) do
|
353
|
+
socket.close
|
354
|
+
end
|
355
|
+
|
356
|
+
context "using option ZMQ::FD" do
|
357
|
+
it "should return an FD as a positive integer" do
|
358
|
+
socket.getsockopt(ZMQ::FD).should be_a(Fixnum)
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should return a valid FD" do
|
362
|
+
# Use FFI to wrap the C library function +getsockopt+ so that we can execute it
|
363
|
+
# on the 0mq file descriptor. If it returns 0, then it succeeded and the FD
|
364
|
+
# is valid!
|
365
|
+
module LibSocket
|
366
|
+
extend FFI::Library
|
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
|
+
# these 2 hex constants were taken from OSX; may differ on other platforms
|
373
|
+
so_rcvbuf = 0x1002
|
374
|
+
sol_socket = 0xffff
|
375
|
+
socklen_size = FFI::MemoryPointer.new :uint32
|
376
|
+
socklen_size.write_int 8
|
377
|
+
rcvbuf = FFI::MemoryPointer.new :int64
|
378
|
+
fd = socket.getsockopt(ZMQ::FD)
|
379
|
+
|
380
|
+
LibSocket.getsockopt(fd, sol_socket, so_rcvbuf, rcvbuf, socklen_size).should be_zero
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
context "using option ZMQ::EVENTS" do
|
385
|
+
it "should return a mask of events as a Fixnum" do
|
386
|
+
socket.getsockopt(ZMQ::EVENTS).should be_a(Fixnum)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end # context #getsockopt
|
390
|
+
|
285
391
|
end # each socket_type
|
286
392
|
|
287
393
|
|
394
|
+
describe "Events mapping to POLLIN and POLLOUT" do
|
395
|
+
include APIHelper
|
396
|
+
|
397
|
+
before(:all) do
|
398
|
+
@ctx = Context.new
|
399
|
+
addr = "tcp://127.0.0.1:#{random_port}"
|
400
|
+
|
401
|
+
@sub = @ctx.socket ZMQ::SUB
|
402
|
+
@sub.setsockopt ZMQ::SUBSCRIBE, ''
|
403
|
+
|
404
|
+
@pub = @ctx.socket ZMQ::PUB
|
405
|
+
@pub.connect addr
|
406
|
+
|
407
|
+
@sub.bind addr
|
408
|
+
|
409
|
+
@pub.send_string('test')
|
410
|
+
sleep 0.1
|
411
|
+
end
|
412
|
+
after(:all) do
|
413
|
+
@sub.close
|
414
|
+
@pub.close
|
415
|
+
# must call close on *every* socket before calling terminate otherwise it blocks indefinitely
|
416
|
+
@ctx.terminate
|
417
|
+
end
|
418
|
+
|
419
|
+
it "should have only POLLIN set for a sub socket that received a message" do
|
420
|
+
#@sub.getsockopt(ZMQ::EVENTS).should == ZMQ::POLLIN
|
421
|
+
end
|
422
|
+
|
423
|
+
it "should have only POLLOUT set for a sub socket that received a message" do
|
424
|
+
#@pub.getsockopt(ZMQ::EVENTS).should == ZMQ::POLLOUT
|
425
|
+
end
|
426
|
+
end # describe 'events mapping to pollin and pollout'
|
427
|
+
|
288
428
|
end # describe Socket
|
289
429
|
|
290
430
|
|