ffi-rzmq 0.5.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.
@@ -0,0 +1,147 @@
1
+
2
+ module ZMQ
3
+
4
+ # Socket types
5
+ PAIR = 0
6
+ PUB = 1
7
+ SUB = 2
8
+ REQ = 3
9
+ REP = 4
10
+ XREQ = 5
11
+ XREP = 6
12
+ UPSTREAM = 7
13
+ DOWNSTREAM = 8
14
+
15
+ # Socket options
16
+ HWM = 1
17
+ SWAP = 3
18
+ AFFINITY = 4
19
+ IDENTITY = 5
20
+ SUBSCRIBE = 6
21
+ UNSUBSCRIBE = 7
22
+ RATE = 8
23
+ RECOVERY_IVL = 9
24
+ MCAST_LOOP = 10
25
+ SNDBUF = 11
26
+ RCVBUF = 12
27
+ RCVMORE = 13
28
+
29
+ # Send/recv options
30
+ NOBLOCK = 1
31
+ SNDMORE = 2
32
+
33
+ # I/O multiplexing
34
+
35
+ POLL = 1
36
+ POLLIN = 1
37
+ POLLOUT = 2
38
+ POLLERR = 4
39
+
40
+ # Socket errors
41
+ EAGAIN = Errno::EAGAIN::Errno
42
+ EINVAL = Errno::EINVAL::Errno
43
+ ENOMEM = Errno::ENOMEM::Errno
44
+ ENODEV = Errno::ENODEV::Errno
45
+ EFAULT = Errno::EFAULT::Errno
46
+
47
+ # ZMQ errors
48
+ HAUSNUMERO = 156384712
49
+ EMTHREAD = (HAUSNUMERO + 50)
50
+ EFSM = (HAUSNUMERO + 51)
51
+ ENOCOMPATPROTO = (HAUSNUMERO + 52)
52
+ ETERM = (HAUSNUMERO + 53)
53
+
54
+ # Rescue unknown constants and use the ZeroMQ defined values
55
+ # Usually only happens on Windows though some don't resolve on
56
+ # OSX too (ENOTSUP)
57
+ ENOTSUP = Errno::ENOTSUP::Errno rescue (HAUSNUMERO + 1)
58
+ EPROTONOSUPPORT = Errno::EPROTONOSUPPORT::Errno rescue (HAUSNUMERO + 2)
59
+ ENOBUFS = Errno::ENOBUFS::Errno rescue (HAUSNUMERO + 3)
60
+ ENETDOWN = Errno::ENETDOWN::Errno rescue (HAUSNUMERO + 4)
61
+ EADDRINUSE = Errno::EADDRINUSE::Errno rescue (HAUSNUMERO + 5)
62
+ EADDRNOTAVAIL = Errno::EADDRNOTAVAIL::Errno rescue (HAUSNUMERO + 6)
63
+ ECONNREFUSED = Errno::ECONNREFUSED::Errno rescue (HAUSNUMERO + 7)
64
+ EINPROGRESS = Errno::EINPROGRESS::Errno rescue (HAUSNUMERO + 8)
65
+
66
+
67
+
68
+ # These methods don't belong to any specific context. They get included
69
+ # in the #Context, #Socket and #Poller classes.
70
+ #
71
+ module Util
72
+
73
+ # Returns the +errno+ as set by the libzmq library.
74
+ #
75
+ def errno
76
+ LibZMQ.zmq_errno
77
+ end
78
+
79
+ # Returns a string corresponding to the currently set #errno. These
80
+ # error strings are defined by libzmq.
81
+ #
82
+ def error_string
83
+ LibZMQ.zmq_strerror(errno).read_string
84
+ end
85
+
86
+ # Returns an array of the form [major, minor, patch] to represent the
87
+ # version of libzmq.
88
+ #
89
+ def version
90
+ major = FFI::MemoryPointer.new :int
91
+ minor = FFI::MemoryPointer.new :int
92
+ patch = FFI::MemoryPointer.new :int
93
+ LibZMQ.zmq_version major, minor, patch
94
+ [major.read_int, minor.read_int, patch.read_int]
95
+ end
96
+
97
+
98
+ private
99
+
100
+ # :doc:
101
+ # Called by most library methods to verify there were no errors during
102
+ # operation. If any are found, raise the appropriate #ZeroMQError.
103
+ #
104
+ # When no error is found, this method returns +true+ which is behavior
105
+ # used internally by #send and #recv.
106
+ #
107
+ def error_check source, result_code
108
+ unless result_code.zero?
109
+ raise_error source, result_code
110
+ end
111
+
112
+ # used by Socket::send/recv, ignored by others
113
+ true
114
+ end
115
+
116
+ # :doc:
117
+ # Only called on sockets in non-blocking mode.
118
+ #
119
+ # Checks the #errno and +result_code+ values for a failed non-blocking
120
+ # send/recv. True only when #errno is EGAIN and +result_code+ is non-zero.
121
+ #
122
+ def error_check_nonblock result_code
123
+ queue_operation = eagain? && !result_code.zero? ? false : true
124
+ queue_operation
125
+ end
126
+
127
+ def raise_error source, result_code
128
+ case source
129
+ when ZMQ_SOCKET_STR, ZMQ_SETSOCKOPT_STR, ZMQ_GETSOCKOPT_STR, ZMQ_BIND_STR, ZMQ_CONNECT_STR, ZMQ_SEND_STR, ZMQ_RECV_STR
130
+ raise SocketError.new source, result_code, errno, error_string
131
+ when ZMQ_INIT_STR, ZMQ_TERM_STR
132
+ raise ContextError.new source, result_code, errno, error_string
133
+ when ZMQ_POLL_STR
134
+ raise PollError.new source, result_code, errno, error_string
135
+ else
136
+ raise ZeroMQError.new source, result_code, -1,
137
+ "Source [#{source}] does not match any zmq_* strings, rc [#{result_code}], errno [#{errno}], error_string [#{error_string}]"
138
+ end
139
+ end
140
+
141
+ def eagain?
142
+ EAGAIN == errno
143
+ end
144
+
145
+ end # module Util
146
+
147
+ end # module ZMQ
@@ -0,0 +1,96 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ module ZMQ
5
+
6
+
7
+ describe Context do
8
+
9
+ context "when initializing" do
10
+ include APIHelper
11
+
12
+ it "should raise an error for negative io threads" do
13
+ lambda { Context.new(-1) }.should raise_exception(ZMQ::ContextError)
14
+ end
15
+
16
+ it "should set the :pointer accessor to non-nil" do
17
+ ctx = Context.new 1
18
+ ctx.pointer.should_not be_nil
19
+ end
20
+
21
+ it "should set the :context accessor to non-nil" do
22
+ ctx = Context.new 1
23
+ ctx.context.should_not be_nil
24
+ end
25
+
26
+ it "should set the :pointer and :context accessors to the same value" do
27
+ ctx = Context.new 1
28
+ ctx.pointer.should == ctx.context
29
+ end
30
+
31
+ it "should define a finalizer on this object" do
32
+ ObjectSpace.should_receive(:define_finalizer)
33
+ ctx = Context.new 1
34
+ end
35
+ end # context initializing
36
+
37
+
38
+ context "when terminating" do
39
+ it "should call zmq_term to terminate the library's context" do
40
+ ctx = Context.new 1
41
+ LibZMQ.should_receive(:zmq_term).with(ctx.pointer).and_return(0)
42
+ ctx.terminate
43
+ end
44
+
45
+ it "should raise an exception when it fails" do
46
+ ctx = Context.new 1
47
+ LibZMQ.stub(:zmq_term => 1)
48
+ lambda { ctx.terminate }.should raise_error(ZMQ::ContextError)
49
+ end
50
+ end # context terminate
51
+
52
+
53
+ context "when allocating a socket" do
54
+ it "should return a ZMQ::Socket" do
55
+ ctx = Context.new 1
56
+ ctx.socket(ZMQ::REQ).should be_kind_of(ZMQ::Socket)
57
+ end
58
+
59
+ it "should raise an exception when allocation fails" do
60
+ ctx = Context.new 1
61
+ Socket.stub(:new => nil)
62
+ lambda { ctx.socket(ZMQ::REQ) }.should raise_error(ZMQ::SocketError)
63
+ end
64
+ end # context socket
65
+
66
+
67
+ # context "when allocating a device" do
68
+ # let(:ctx) { Context.new 1 }
69
+ # let(:sock1) { ctx.socket ZMQ::REQ }
70
+ # let(:sock2) { ctx.socket ZMQ::REP }
71
+ #
72
+ # it "should return a ZMQ::Forwarder" do
73
+ # device = ctx.device ZMQ::FORWARDER, sock1, sock2
74
+ # device.should be_kind_of(ZMQ::Forwarder)
75
+ # end
76
+ #
77
+ # it "should return a ZMQ::Queue" do
78
+ # device = ctx.device ZMQ::QUEUE, sock1, sock2
79
+ # device.should be_kind_of(ZMQ::Queue)
80
+ # end
81
+ #
82
+ # it "should return a ZMQ::Streamer" do
83
+ # device = ctx.device ZMQ::STREAMER, sock1, sock2
84
+ # device.should be_kind_of(ZMQ::Streamer)
85
+ # end
86
+ #
87
+ # it "should raise an exception when the requested device is unknown" do
88
+ # lambda { ctx.device(-1, sock1, sock2) }.should raise_error(ZMQ::DeviceError)
89
+ # end
90
+ # end # context device
91
+
92
+
93
+ end # describe Context
94
+
95
+
96
+ end # module ZMQ
@@ -0,0 +1,56 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ module ZMQ
5
+
6
+
7
+ describe Context do
8
+
9
+ context "when running ping pong" do
10
+ include APIHelper
11
+
12
+ let(:string) { "booga-booga" }
13
+
14
+ before(:each) do
15
+ context = ZMQ::Context.new 1
16
+ @ping = context.socket ZMQ::REQ
17
+ @pong = context.socket ZMQ::REP
18
+ link = "tcp://127.0.0.1:#{random_port}"
19
+ @pong.bind link
20
+ @ping.connect link
21
+ end
22
+
23
+ it "should receive an exact string copy of the string message sent" do
24
+ @ping.send_string string
25
+ received_message = @pong.recv_string
26
+
27
+ received_message.should == string
28
+ end
29
+
30
+ it "should receive an exact copy of the sent message using Message objects directly" do
31
+ sent_message = Message.new string
32
+ received_message = Message.new
33
+
34
+ @ping.send sent_message
35
+ @pong.recv received_message
36
+
37
+ received_message.copy_out_string.should == string
38
+ end
39
+
40
+ it "should receive an exact copy of the sent message using Message objects directly in non-blocking mode" do
41
+ sent_message = Message.new string
42
+ received_message = Message.new
43
+
44
+ @ping.send sent_message, ZMQ::NOBLOCK
45
+ sleep 0.001 # give it time for delivery
46
+ @pong.recv received_message, ZMQ::NOBLOCK
47
+
48
+ received_message.copy_out_string.should == string
49
+ end
50
+ end # context ping-pong
51
+
52
+
53
+ end # describe
54
+
55
+
56
+ end # module ZMQ
@@ -0,0 +1,111 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ module ZMQ
5
+
6
+
7
+ describe Socket do
8
+
9
+ context "when initializing" do
10
+
11
+ let(:ctx) { Context.new 1 }
12
+
13
+ it "should raise an error for a nil context" do
14
+ lambda { Socket.new(FFI::Pointer::NULL, ZMQ::REQ) }.should raise_exception(ZMQ::ContextError)
15
+ end
16
+
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
44
+
45
+ it "should not raise an error for a ZMQ::DOWNSTREAM socket type" do
46
+ lambda { Socket.new(ctx.pointer, ZMQ::DOWNSTREAM) }.should_not raise_error
47
+ end
48
+
49
+ it "should not raise an error for a ZMQ::UPSTREAM socket type" do
50
+ lambda { Socket.new(ctx.pointer, ZMQ::UPSTREAM) }.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
56
+
57
+ it "should set the :socket accessor to non-nil" do
58
+ sock = Socket.new(Context.new(1).pointer, ZMQ::REQ)
59
+ sock.socket.should_not be_nil
60
+ end
61
+
62
+ it "should define a finalizer on this object" do
63
+ ObjectSpace.should_receive(:define_finalizer)
64
+ ctx = Context.new 1
65
+ end
66
+ end # context initializing
67
+
68
+
69
+ context "identity=" do
70
+ it "should raise an exception for identities in excess of 255 bytes" do
71
+ ctx = Context.new 1
72
+ sock = Socket.new ctx.pointer, ZMQ::REQ
73
+
74
+ lambda { sock.identity = ('a' * 256) }.should raise_exception(ZMQ::SocketError)
75
+ end
76
+
77
+ it "should raise an exception for identities of length 0" do
78
+ ctx = Context.new 1
79
+ sock = Socket.new ctx.pointer, ZMQ::REQ
80
+
81
+ lambda { sock.identity = '' }.should raise_exception(ZMQ::SocketError)
82
+ end
83
+
84
+ it "should NOT raise an exception for identities of 1 byte" do
85
+ ctx = Context.new 1
86
+ sock = Socket.new ctx.pointer, ZMQ::REQ
87
+
88
+ lambda { sock.identity = 'a' }.should_not raise_exception(ZMQ::SocketError)
89
+ end
90
+
91
+ it "should NOT raise an exception for identities of 255 bytes" do
92
+ ctx = Context.new 1
93
+ sock = Socket.new ctx.pointer, ZMQ::REQ
94
+
95
+ lambda { sock.identity = ('a' * 255) }.should_not raise_exception(ZMQ::SocketError)
96
+ end
97
+
98
+ it "should convert numeric identities to strings" do
99
+ ctx = Context.new 1
100
+ sock = Socket.new ctx.pointer, ZMQ::REQ
101
+
102
+ sock.identity = 7
103
+ sock.identity.should == '7'
104
+ end
105
+ end # context identity=
106
+
107
+
108
+ end # describe Socket
109
+
110
+
111
+ end # module ZMQ
@@ -0,0 +1,38 @@
1
+ # To run these specs using rake, make sure the 'bones' and 'bones-extras'
2
+ # gems are installed. Then execute 'rake spec' from the main directory
3
+ # to run all specs.
4
+
5
+ require File.expand_path(
6
+ File.join(File.dirname(__FILE__), %w[.. lib ffi-rzmq]))
7
+
8
+ # turns off all warnings; added so I don't have to see the warnings
9
+ # for included libraries like FFI.
10
+ $VERBOSE = false
11
+
12
+ Spec::Runner.configure do |config|
13
+ # == Mock Framework
14
+ #
15
+ # RSpec uses it's own mocking framework by default. If you prefer to
16
+ # use mocha, flexmock or RR, uncomment the appropriate line:
17
+ #
18
+ # config.mock_with :mocha
19
+ # config.mock_with :flexmock
20
+ # config.mock_with :rr
21
+ end
22
+
23
+ module APIHelper
24
+ def stub_libzmq
25
+ @err_str_mock = mock("error string")
26
+
27
+ LibZMQ.stub!(
28
+ :zmq_init => 0,
29
+ :zmq_errno => 0,
30
+ :zmq_sterror => @err_str_mock
31
+ )
32
+ end
33
+
34
+ # generate a random port between 10_000 and 65534
35
+ def random_port
36
+ rand(55534) + 10_000
37
+ end
38
+ end