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.
@@ -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
- def version
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 = Context.new 1
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 = Context.new 1
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 = Context.new 1
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 1
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 1
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 = Context.new 1
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 = Context.new 1
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
 
@@ -10,14 +10,19 @@ module ZMQ
10
10
 
11
11
  before(:each) do
12
12
  $stdout.flush
13
- @context = ZMQ::Context.new 1
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
@@ -19,6 +19,11 @@ module ZMQ
19
19
  @pong.bind link
20
20
  @ping.connect link
21
21
  end
22
+
23
+ after(:each) do
24
+ @ping.close
25
+ @pong.close
26
+ end
22
27
 
23
28
  it "should receive an exact string copy of the string message sent" do
24
29
  @ping.send_string string
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
- it "should not raise an error for a ZMQ::REQ socket type" do
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
- it "should not raise an error for a ZMQ::PUSH socket type" do
46
- lambda { Socket.new(ctx.pointer, ZMQ::PUSH) }.should_not raise_error
47
- end
48
-
49
- it "should not raise an error for a ZMQ::PULL socket type" do
50
- lambda { Socket.new(ctx.pointer, ZMQ::PULL) }.should_not raise_error
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')#.as_null_object
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
- pending # need to wait for 0mq 2.1 or later to fix this
68
- ObjectSpace.should_receive(:define_finalizer)
69
- ctx = Context.new 1
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
- ctx = Context.new 1
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
- ctx = Context.new 1
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
- ctx = Context.new 1
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
- ctx = Context.new 1
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
- ctx = Context.new 1
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 = Context.new
118
- Socket.new ctx.pointer, socket_type
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
- # context "using option ZMQ::SWAP" do
170
- # it "should set the swap value given a positive value" do
171
- # swap = 10_000
172
- # socket.setsockopt ZMQ::SWAP, swap
173
- # socket.getsockopt(ZMQ::SWAP).should == swap
174
- # end
175
- #
176
- # it "should raise a SocketError given a negative value" do
177
- # swap = -10_000
178
- # lambda { socket.setsockopt(ZMQ::SWAP, swap) }.should raise_error(SocketError)
179
- # end
180
- # end # context using option ZMQ::SWP
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
- # context "using option ZMQ::RATE" do
215
- # it "should set the multicast send rate given a positive value" do
216
- # rate = 200
217
- # socket.setsockopt ZMQ::RATE, rate
218
- # socket.getsockopt(ZMQ::RATE).should == rate
219
- # end
220
- #
221
- # it "should raise a SocketError given a negative value" do
222
- # rate = -200
223
- # lambda { socket.setsockopt ZMQ::RATE, rate }.should raise_error(SocketError)
224
- # end
225
- # end # context using option ZMQ::RATE
226
- #
227
- #
228
- # context "using option ZMQ::RECOVERY_IVL" do
229
- # it "should set the multicast recovery buffer measured in seconds given a positive value" do
230
- # rate = 200
231
- # socket.setsockopt ZMQ::RECOVERY_IVL, rate
232
- # socket.getsockopt(ZMQ::RECOVERY_IVL).should == rate
233
- # end
234
- #
235
- # it "should raise a SocketError given a negative value" do
236
- # rate = -200
237
- # lambda { socket.setsockopt ZMQ::RECOVERY_IVL, rate }.should raise_error(SocketError)
238
- # end
239
- # end # context using option ZMQ::RECOVERY_IVL
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