ffi-rzmq 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|