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.
@@ -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