rbzmq 0.1.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,14 @@
1
+ module RbZMQ
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+ STAGE = nil
7
+
8
+ STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.').freeze
9
+
10
+ def self.to_s
11
+ STRING
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rbzmq/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rbzmq'
8
+ spec.version = RbZMQ::VERSION
9
+ spec.authors = ['Jan Graichen']
10
+ spec.email = ['jg@altimos.de']
11
+ spec.summary = %q{An opinionated ruby library wrapping ffi-rzmq for more rubish flair.}
12
+ spec.description = %q{An opinionated ruby library wrapping ffi-rzmq for more rubish flair.}
13
+ spec.homepage = 'https://github.com/jgraichen/rbzmq'
14
+ spec.license = 'LGPLv3'
15
+
16
+ spec.files = Dir['**/*'].grep(%r{^((bin|lib|test|spec|features)/|.*\.gemspec|.*LICENSE.*|.*README.*|.*CHANGELOG.*)})
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'ffi-rzmq', '~> 2.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.5'
24
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe RbZMQ::Poller do
4
+ let!(:poller) { RbZMQ::Poller.new }
5
+ let!(:receiver) do
6
+ RbZMQ::Socket.new(ZMQ::PULL).tap{|s| s.bind 'inproc://test' }
7
+ end
8
+ let!(:sender) do
9
+ RbZMQ::Socket.new(ZMQ::PUSH).tap{|s| s.connect 'inproc://test' }
10
+ end
11
+ let(:delta) { 0.01 }
12
+ after { receiver.close! }
13
+ after { sender.close! }
14
+
15
+ describe '#register' do
16
+ let(:action) { -> { poller.register(receiver, ZMQ::POLLIN) } }
17
+ subject { action }
18
+
19
+ it { should change(poller, :size).from(0).to(1) }
20
+ end
21
+
22
+ describe '#deregister' do
23
+ let(:action) { -> { poller.deregister(receiver, ZMQ::POLLIN) } }
24
+ subject { action }
25
+
26
+ context 'with all events removed' do
27
+ before { poller.register(receiver, ZMQ::POLLIN) }
28
+ it { should change(poller, :size).from(1).to(0) }
29
+ end
30
+
31
+ context 'with events leaving' do
32
+ before { poller.register(receiver, ZMQ::POLLIN | ZMQ::POLLOUT) }
33
+ it { should_not change(poller, :size) }
34
+ it { expect(subject.call).to eq ZMQ::POLLOUT }
35
+ end
36
+ end
37
+
38
+ describe '#poll' do
39
+ let!(:start_time) { Time.now.to_f }
40
+ let(:end_time) { Time.now.to_f }
41
+
42
+ context 'without any registered' do
43
+ it 'should not block' do
44
+ poller.poll(1_000)
45
+ expect(end_time).to be_within(delta).of(start_time)
46
+ end
47
+ end
48
+
49
+ context 'with registered ZMQ socket' do
50
+ before { poller.register(receiver, ZMQ::POLLIN) }
51
+
52
+ it 'should timeout without event' do
53
+ poller.poll(100)
54
+ expect(end_time).to be > (start_time + 0.1)
55
+ end
56
+
57
+ it 'should interrupt on event' do
58
+ Thread.new do
59
+ sleep 0.1
60
+ sender.send 'MSG'
61
+ end
62
+ poller.poll(1_000)
63
+ expect(receiver.recv.to_s).to eq 'MSG'
64
+ expect(end_time).to be < (start_time + 1.0)
65
+ end
66
+ end
67
+
68
+ context 'with registered IO' do
69
+ let(:pipe) { IO.pipe }
70
+ let(:reader) { pipe[0] }
71
+ let(:writer) { pipe[1] }
72
+ before { poller.register(reader, ZMQ::POLLIN) }
73
+
74
+ it 'should timeout without event' do
75
+ ret = poller.poll(100)
76
+ expect(ret).to be_a Enumerator
77
+ expect(ret).to have(0).items
78
+ expect(end_time).to be > (start_time + 0.1)
79
+ end
80
+
81
+ it 'should interrupt on event' do
82
+ Thread.new do
83
+ sleep 0.1
84
+ writer.write 'MSG'
85
+ writer.close
86
+ end
87
+ ret = poller.poll(1_000)
88
+ expect(end_time).to be < (start_time + 1.0)
89
+ expect(ret).to be_a Enumerator
90
+ expect(ret).to have(1).item
91
+ expect(reader.read_nonblock(4096)).to eq 'MSG'
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe RbZMQ::Socket do
4
+ let!(:server) do
5
+ described_class.new(ZMQ::PULL).tap{|s| s.bind 'inproc://test' }
6
+ end
7
+ after { server.close! }
8
+
9
+ let!(:socket) { described_class.new(ZMQ::PUSH) }
10
+ after { socket.close! }
11
+
12
+ describe 'recv' do
13
+ describe 'timeout' do
14
+ before do
15
+ socket.connect 'inproc://test'
16
+ end
17
+
18
+ it 'should poll messages' do
19
+ Thread.new do
20
+ sleep 0.2
21
+ socket.send 'TEST'
22
+ end
23
+
24
+ start = Time.now
25
+ str = server.recv(timeout: 1000).to_s
26
+
27
+ expect(Time.now - start).to be < 1
28
+ expect(str).to eq 'TEST'
29
+ end
30
+
31
+ it 'should raise error when timeout is reached' do
32
+ start = Time.now
33
+
34
+ expect{ server.recv(timeout: 1000).to_s }.to raise_error Errno::EAGAIN
35
+
36
+ expect(Time.now - start).to be_within(0.1).of(1)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,255 @@
1
+ require 'spec_helper'
2
+
3
+ describe RbZMQ::Socket do
4
+ let(:socket) { RbZMQ::Socket.new ZMQ::ROUTER }
5
+
6
+ describe '#initialize' do
7
+ let(:opts) { Hash.new }
8
+ let(:socket) { RbZMQ::Socket.new ZMQ::ROUTER, opts }
9
+
10
+ context 'opts: ctx' do
11
+ let(:opts) { {ctx: ctx} }
12
+
13
+ context 'with valid ctx' do
14
+ subject { socket }
15
+
16
+ context 'with ZMQ::Context' do
17
+ let(:ctx) { ZMQ::Context.new }
18
+ it { expect(socket.zmq_ctx).to eq ctx.pointer }
19
+ end
20
+
21
+ context 'with RbZMQ::Context' do
22
+ let(:ctx) { RbZMQ::Context.new }
23
+ it { expect(socket.zmq_ctx).to eq ctx.pointer }
24
+ end
25
+ end
26
+
27
+ context 'with invalid object' do
28
+ subject { ->{ socket } }
29
+
30
+ context 'with String' do
31
+ let(:ctx) { '' }
32
+ it { should raise_error ArgumentError }
33
+ end
34
+ end
35
+ end
36
+
37
+ context 'with ZMQ raising an error' do
38
+ let(:zmq_err) { ZMQ::ZeroMQError.new('zmq_source', 42, 21, 'abc MSG') }
39
+ before do
40
+ expect(ZMQ::Socket).to receive(:new).and_raise zmq_err
41
+ end
42
+
43
+ subject do
44
+ begin
45
+ socket
46
+ rescue => err
47
+ err
48
+ end
49
+ end
50
+
51
+ it { should be_a RbZMQ::ZMQError }
52
+ its(:rc) { should eq 42 }
53
+ its(:result_code) { should eq 42 }
54
+ its(:errno) { should eq 21 }
55
+ its(:error_code) { should eq 21 }
56
+ its(:message) { should eq 'abc MSG' }
57
+ its(:to_s) { should eq '[ERRNO 21, RC 42] abc MSG' }
58
+ end
59
+ end
60
+
61
+ describe '#close' do
62
+ subject { socket.close }
63
+
64
+ it 'should successfully call #close on ZMQ socket' do
65
+ expect(socket.zmq_socket).to receive(:close).and_return(0)
66
+ expect(subject).to eq true
67
+ end
68
+
69
+ it 'should return false on failure' do
70
+ expect(socket.zmq_socket).to receive(:close).and_return(-1)
71
+ should eq false
72
+ end
73
+ end
74
+
75
+ describe '#close!' do
76
+ subject { socket.close! }
77
+
78
+ it 'should successfully call #close on ZMQ socket' do
79
+ expect(socket.zmq_socket).to receive(:close)
80
+ expect(subject).to eq true
81
+ end
82
+
83
+ it 'should raise error on failure' do
84
+ expect(socket.zmq_socket).to receive(:close).and_return(-1)
85
+ expect { subject }.to raise_error RbZMQ::ZMQError
86
+ end
87
+ end
88
+
89
+ describe '#bind' do
90
+ subject { socket.bind 'tcp://127.0.0.1:5555' }
91
+
92
+ it 'should successfully call #bind on ZMQ socket' do
93
+ expect(socket.zmq_socket).to receive(:bind)
94
+ .with('tcp://127.0.0.1:5555').and_return(0)
95
+ expect(subject).to eq socket
96
+ end
97
+
98
+ it 'should raise error on failure' do
99
+ expect(socket.zmq_socket).to receive(:bind).and_return(-1)
100
+ expect { subject }.to raise_error RbZMQ::ZMQError
101
+ end
102
+ end
103
+
104
+ describe '#connect' do
105
+ subject { socket.connect 'tcp://127.0.0.1:5555' }
106
+
107
+ it 'should successfully call #connect on ZMQ socket' do
108
+ expect(socket.zmq_socket).to receive(:connect)
109
+ .with('tcp://127.0.0.1:5555').and_return(0)
110
+ expect(subject).to eq socket
111
+ end
112
+
113
+ it 'should raise error on failure' do
114
+ expect(socket.zmq_socket).to receive(:connect).and_return(-1)
115
+ expect { subject }.to raise_error RbZMQ::ZMQError
116
+ end
117
+ end
118
+
119
+ describe '#send' do
120
+ context 'with single message' do
121
+ let(:dup) { double('ZMQMSG') }
122
+ let(:msg) { RbZMQ::Message.new }
123
+ let(:args) { [msg, 42] }
124
+ subject { socket.send(*args) }
125
+ before { allow(msg).to receive(:to_zmq).and_return(dup) }
126
+
127
+ it 'should successfully call #sendmsg on ZMQ socket' do
128
+ expect(socket.zmq_socket).to receive(:sendmsg)
129
+ .with(dup, 42).and_return(0)
130
+ expect(subject).to eq socket
131
+ end
132
+
133
+ it 'should raise error on failure' do
134
+ expect(socket.zmq_socket).to receive(:sendmsg).and_return(-1)
135
+ expect { subject }.to raise_error RbZMQ::ZMQError
136
+ end
137
+
138
+ context 'with :block option' do
139
+ let(:args) { [msg, {block: false}] }
140
+
141
+ it 'should set ZMQ::DONTWAIT flag' do
142
+ expect(socket.zmq_socket).to receive(:sendmsg)
143
+ .with(dup, ZMQ::DONTWAIT).and_return(0)
144
+ expect(subject).to eq socket
145
+ end
146
+ end
147
+
148
+ context 'with :more option' do
149
+ let(:args) { [msg, {more: true}] }
150
+
151
+ it 'should set ZMQ::SNDMORE flag' do
152
+ expect(socket.zmq_socket).to receive(:sendmsg)
153
+ .with(dup, ZMQ::SNDMORE).and_return(0)
154
+ expect(subject).to eq socket
155
+ end
156
+ end
157
+ end
158
+
159
+ context 'with multiple messages' do
160
+ let(:dup1) { double('msg1') }
161
+ let(:dup2) { double('msg2') }
162
+ let(:msg1) { RbZMQ::Message.new }
163
+ let(:msg2) { RbZMQ::Message.new }
164
+ let(:args) { [[msg1, msg2]] }
165
+ subject { socket.send(*args) }
166
+ before { allow(msg1).to receive(:to_zmq).and_return(dup1) }
167
+ before { allow(msg2).to receive(:to_zmq).and_return(dup2) }
168
+
169
+ it 'should successfully call #sendmsg on ZMQ socket' do
170
+ expect(socket.zmq_socket).to receive(:sendmsg)
171
+ .with(dup1, ZMQ::SNDMORE).ordered.and_return(0)
172
+ expect(socket.zmq_socket).to receive(:sendmsg)
173
+ .with(dup2, 0).ordered.and_return(0)
174
+ expect(subject).to eq socket
175
+ end
176
+
177
+ it 'should raise error on failure' do
178
+ expect(socket.zmq_socket).to receive(:sendmsg)
179
+ .with(dup1, ZMQ::SNDMORE).ordered.and_return(-1)
180
+ expect { subject }.to raise_error RbZMQ::ZMQError
181
+ end
182
+
183
+ context 'with :block option' do
184
+ let(:args) { super() + [{block: false}] }
185
+
186
+ it 'should successfully call #sendmsg on ZMQ socket' do
187
+ expect(socket.zmq_socket).to receive(:sendmsg)
188
+ .with(dup1, ZMQ::SNDMORE | ZMQ::DONTWAIT).ordered.and_return(0)
189
+ expect(socket.zmq_socket).to receive(:sendmsg)
190
+ .with(dup2, ZMQ::DONTWAIT).ordered.and_return(0)
191
+ expect(subject).to eq socket
192
+ end
193
+ end
194
+
195
+ context 'with :more option' do
196
+ let(:args) { super() + [{more: true}] }
197
+
198
+ it 'should successfully call #sendmsg on ZMQ socket' do
199
+ expect(socket.zmq_socket).to receive(:sendmsg)
200
+ .with(dup1, ZMQ::SNDMORE).ordered.and_return(0)
201
+ expect(socket.zmq_socket).to receive(:sendmsg)
202
+ .with(dup2, ZMQ::SNDMORE).ordered.and_return(0)
203
+ expect(subject).to eq socket
204
+ end
205
+ end
206
+ end
207
+
208
+ context 'with single string' do
209
+ subject { socket.send 'abc', 42 }
210
+
211
+ it 'should successfully call #send_string on ZMQ socket' do
212
+ expect(socket.zmq_socket).to receive(:sendmsg)
213
+ .with(kind_of(ZMQ::Message), 42).and_return(0)
214
+ expect(subject).to eq socket
215
+ end
216
+
217
+ it 'should raise error on failure' do
218
+ expect(socket.zmq_socket).to receive(:sendmsg).and_return(-1)
219
+ expect { subject }.to raise_error RbZMQ::ZMQError
220
+ end
221
+ end
222
+
223
+ context 'with multiple strings' do
224
+ subject { socket.send %w(abc cde), 0 }
225
+
226
+ it 'should successfully call #send_strings on ZMQ socket' do
227
+ expect(socket.zmq_socket).to receive(:sendmsg).ordered
228
+ .with(kind_of(ZMQ::Message), ZMQ::SNDMORE).and_return(0)
229
+ expect(socket.zmq_socket).to receive(:sendmsg).ordered
230
+ .with(kind_of(ZMQ::Message), 0).and_return(0)
231
+ expect(subject).to eq socket
232
+ end
233
+
234
+ it 'should raise error on failure' do
235
+ expect(socket.zmq_socket).to receive(:sendmsg).and_return(-1)
236
+ expect { subject }.to raise_error RbZMQ::ZMQError
237
+ end
238
+ end
239
+ end
240
+
241
+ describe '#setsockopt' do
242
+ subject { socket.setsockopt(ZMQ::SUBSCRIBE, 'ABC') }
243
+
244
+ it 'should call #setsockopt on ZMQ socket' do
245
+ expect(socket.zmq_socket).to receive(:setsockopt)
246
+ .with(ZMQ::SUBSCRIBE, 'ABC').and_return(0)
247
+ expect(subject).to eq true
248
+ end
249
+
250
+ it 'should return false on failure' do
251
+ expect(socket.zmq_socket).to receive(:setsockopt).and_return(-1)
252
+ expect(subject).to eq false
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << File.expand_path("../../../lib", __FILE__)
2
+
3
+ require "rbzmq"
4
+
5
+ socket = RbZMQ::Socket.new ZMQ::ROUTER
@@ -0,0 +1,27 @@
1
+ require 'bundler'
2
+ Bundler.require :default, :test
3
+
4
+ if ENV['CI'] || (defined?(:RUBY_ENGINE) && RUBY_ENGINE != 'rbx')
5
+ require 'coveralls'
6
+ Coveralls.wear! do
7
+ add_filter 'spec'
8
+ end
9
+ end
10
+
11
+ require 'rbzmq'
12
+
13
+ Dir[File.expand_path('spec/support/**/*.rb')].each {|f| require f}
14
+
15
+ RSpec.configure do |config|
16
+ config.order = 'random'
17
+
18
+ config.around do |example|
19
+ begin
20
+ Timeout.timeout(30) do
21
+ example.call
22
+ end
23
+ rescue
24
+ raise Timeout::Error.new 'Spec exceeded maximum execution time'
25
+ end
26
+ end
27
+ end