ffi-rzmq 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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