rbzmq 0.1.0

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