marquise 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/marquise.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+ require 'git-version-bump'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "marquise"
6
+
7
+ s.version = GVB.version
8
+ s.date = GVB.date
9
+
10
+ s.platform = Gem::Platform::RUBY
11
+
12
+ s.homepage = "https://github.com/mpalmer/marquise-ruby"
13
+ s.summary = "Ruby bindings for the marquise data-point transport "+
14
+ "for Vaultaire"
15
+ s.authors = ["Matt Palmer"]
16
+
17
+ s.extra_rdoc_files = ["README.md"]
18
+ s.files = `git ls-files`.split("\n")
19
+
20
+ s.add_runtime_dependency 'ffi', '~> 1.9'
21
+ s.add_runtime_dependency 'ffi_dry'
22
+ s.add_runtime_dependency 'git-version-bump', '~> 0.7'
23
+
24
+ s.add_development_dependency 'rspec', "~> 2.14"
25
+ s.add_development_dependency 'rake'
26
+ s.add_development_dependency 'bundler'
27
+ s.add_development_dependency 'rdoc'
28
+ s.add_development_dependency 'guard-spork'
29
+ s.add_development_dependency 'guard-rspec'
30
+ s.add_development_dependency 'rb-inotify', '~> 0.9'
31
+ s.add_development_dependency 'plymouth'
32
+ s.add_development_dependency 'pry-debugger'
33
+ end
@@ -0,0 +1,274 @@
1
+ require_relative './spec_helper'
2
+
3
+ require 'marquise'
4
+
5
+ describe Marquise do
6
+ describe ".new" do
7
+ it "bombs out without an argument" do
8
+ expect { Marquise.new }.to raise_error
9
+ end
10
+
11
+ it "returns a Marquise instance when given a zmq URL" do
12
+ expect(Marquise.new('tcp://localhost:4567')).to be_a(Marquise)
13
+ end
14
+
15
+ it "calls marquise_consumer_new with a zmq URL" do
16
+ Marquise::FFI.
17
+ should_receive(:marquise_consumer_new).
18
+ with('tcp://localhost:4567', 5).
19
+ and_return('19')
20
+
21
+ Marquise.new('tcp://localhost:4567')
22
+ end
23
+
24
+ it "raises RuntimeError if marquise_consumer_new returns nil" do
25
+ Marquise::FFI.
26
+ should_receive(:marquise_consumer_new).
27
+ with('tcp://localhost:4567', 5).
28
+ and_return(nil)
29
+
30
+ expect { Marquise.new('tcp://localhost:4567') }.
31
+ to raise_error(RuntimeError, "libmarquise failed; check syslog (no, seriously)")
32
+ end
33
+
34
+ it "passes non-default batch_period if given" do
35
+ Marquise::FFI.
36
+ should_receive(:marquise_consumer_new).
37
+ with('tcp://localhost:4567', 0.05).
38
+ and_return('38')
39
+
40
+ Marquise.new('tcp://localhost:4567', 0.05)
41
+ end
42
+
43
+ it "defines a finalizer to call marquise_consumer_shutdown" do
44
+ Marquise::FFI.
45
+ should_receive(:marquise_consumer_new).
46
+ with('tcp://localhost:4567', 5).
47
+ and_return('xyzzy')
48
+ ObjectSpace.
49
+ should_receive(:define_finalizer).
50
+ with(instance_of(Marquise), mock_janitor = double('janitor'))
51
+ Marquise::Janitor.
52
+ should_receive(:new).
53
+ with('xyzzy', {}).
54
+ and_return(mock_janitor)
55
+
56
+ x = Marquise.new('tcp://localhost:4567')
57
+ end
58
+ end
59
+
60
+ describe ".open" do
61
+ it "bombs out without an argument" do
62
+ expect { Marquise.open }.to raise_error
63
+ end
64
+
65
+ it "returns a Marquise instance when given a zmq URL" do
66
+ expect(Marquise.open('tcp://localhost:4567')).to be_a(Marquise)
67
+ end
68
+
69
+ it "calls marquise_consumer_new with a zmq URL" do
70
+ Marquise::FFI.
71
+ should_receive(:marquise_consumer_new).
72
+ with('tcp://localhost:4567', 5).
73
+ and_return('81')
74
+
75
+ Marquise.open('tcp://localhost:4567')
76
+ end
77
+
78
+ it "raises RuntimeError if marquise_consumer_new returns nil" do
79
+ Marquise::FFI.
80
+ should_receive(:marquise_consumer_new).
81
+ with('tcp://localhost:4567', 5).
82
+ and_return(nil)
83
+
84
+ expect { Marquise.open('tcp://localhost:4567') }.
85
+ to raise_error(RuntimeError, "libmarquise failed; check syslog (no, seriously)")
86
+ end
87
+
88
+ it "passes non-default batch_period if given" do
89
+ Marquise::FFI.
90
+ should_receive(:marquise_consumer_new).
91
+ with('tcp://localhost:4567', 0.05).
92
+ and_return('100')
93
+
94
+ Marquise.open('tcp://localhost:4567', 0.05)
95
+ end
96
+
97
+ it "bombs out with a block but without an argument" do
98
+ expect { Marquise.open() { |x| puts x } }.to raise_error
99
+ end
100
+
101
+ it "yields a Marquise instance when given a block" do
102
+ expect do |b|
103
+ Marquise.open('tcp://localhost:4567', &b)
104
+ end.to yield_with_args(Marquise)
105
+ end
106
+ end
107
+
108
+ describe "#connect" do
109
+ it "calls marquise_connect" do
110
+ Marquise::FFI.
111
+ should_receive(:marquise_consumer_new).
112
+ with('tcp://localhost:4567', 5).
113
+ and_return('118')
114
+ Marquise::FFI.
115
+ should_receive(:marquise_connect).
116
+ with('118').
117
+ and_return('122')
118
+
119
+ x = Marquise.open('tcp://localhost:4567').connect
120
+ # This is just cheating... avoid possibly sending insane data
121
+ # to libmarquise via calling close functions on GC
122
+ ObjectSpace.undefine_finalizer(x)
123
+ end
124
+
125
+ it "calls marquise_connect only once per thread" do
126
+ Marquise::FFI.
127
+ should_receive(:marquise_consumer_new).
128
+ with('tcp://localhost:4567', 5).
129
+ and_return('118')
130
+ Marquise::FFI.
131
+ should_receive(:marquise_connect).
132
+ with('118').
133
+ and_return('122')
134
+
135
+ x = Marquise.open('tcp://localhost:4567')
136
+ # This is just cheating... avoid possibly sending insane data
137
+ # to libmarquise via calling close functions on GC
138
+ ObjectSpace.undefine_finalizer(x)
139
+
140
+ 10.times { x.connect }
141
+ end
142
+
143
+ it "barfs if marquise_connect fails" do
144
+ Marquise::FFI.
145
+ should_receive(:marquise_consumer_new).
146
+ with('tcp://localhost:4567', 5).
147
+ and_return('134')
148
+ Marquise::FFI.
149
+ should_receive(:marquise_connect).
150
+ with('134').
151
+ and_return(nil)
152
+
153
+ x = Marquise.open('tcp://localhost:4567')
154
+ # This is just cheating... avoid possibly sending insane data
155
+ # to libmarquise via calling close functions on GC
156
+ ObjectSpace.undefine_finalizer(x)
157
+
158
+ expect { x.connect }.
159
+ to raise_error(
160
+ RuntimeError,
161
+ "marquise_connect() failed... consult syslog (no, seriously)"
162
+ )
163
+ end
164
+
165
+ it "creates separate connections for each thread" do
166
+ Marquise::FFI.
167
+ should_receive(:marquise_consumer_new).
168
+ with('tcp://localhost:4567', 5).
169
+ and_return('156')
170
+ Marquise::FFI.
171
+ should_receive(:marquise_connect).
172
+ twice.
173
+ with('156').
174
+ and_return('161.1', '161.2')
175
+
176
+ x = Marquise.open('tcp://localhost:4567')
177
+ # This is just cheating... avoid possibly sending insane data
178
+ # to libmarquise via calling close functions on GC
179
+ ObjectSpace.undefine_finalizer(x)
180
+
181
+ th1 = Thread.new { 10.times { x.connect } }
182
+ th2 = Thread.new { 10.times { x.connect } }
183
+
184
+ th1.join
185
+ th2.join
186
+
187
+ # Digging inside the object... how naughty...
188
+ conns = x.instance_variable_get(:@connections)
189
+
190
+ expect(conns[th1]).to_not eq(conns[th2])
191
+ end
192
+ end
193
+
194
+ describe "#close" do
195
+ it "calls marquise_consumer_shutdown" do
196
+ Marquise::FFI.
197
+ should_receive(:marquise_consumer_new).
198
+ with('tcp://localhost:4567', 5).
199
+ and_return('121')
200
+ Marquise::FFI.
201
+ should_receive(:marquise_consumer_shutdown).
202
+ with('121')
203
+
204
+ Marquise.open('tcp://localhost:4567').close
205
+ end
206
+
207
+ it "doesn't call marquise_consumer_shutdown more than once" do
208
+ Marquise::FFI.
209
+ should_receive(:marquise_consumer_new).
210
+ with('tcp://localhost:4567', 5).
211
+ and_return('131')
212
+ Marquise::FFI.
213
+ should_receive(:marquise_consumer_shutdown).
214
+ with('131')
215
+
216
+ x = Marquise.open('tcp://localhost:4567').close
217
+
218
+ # Creating a huge chunk of junk memory and then releasing it should
219
+ # cause the GC to cleanup everything, running all finalizers
220
+ x = 'x' * 100_000_000
221
+ x = nil
222
+ GC.start
223
+ end
224
+
225
+ it "calls marquise_close on the connection" do
226
+ Marquise::FFI.
227
+ should_receive(:marquise_consumer_new).
228
+ with('tcp://localhost:4567', 5).
229
+ and_return('148')
230
+ Marquise::FFI.
231
+ should_receive(:marquise_consumer_shutdown).
232
+ with('148')
233
+ Marquise::FFI.
234
+ should_receive(:marquise_connect).
235
+ with('148').
236
+ and_return('155')
237
+ Marquise::FFI.
238
+ should_receive(:marquise_close).
239
+ with('155')
240
+
241
+ x = Marquise.open('tcp://localhost:4567')
242
+ x.connect
243
+ x.close
244
+ end
245
+
246
+ it "calls marquise_close on all connections" do
247
+ Marquise::FFI.
248
+ should_receive(:marquise_consumer_new).
249
+ with('tcp://localhost:4567', 5).
250
+ and_return('255')
251
+ Marquise::FFI.
252
+ should_receive(:marquise_consumer_shutdown).
253
+ with('255')
254
+ Marquise::FFI.
255
+ should_receive(:marquise_connect).
256
+ with('255').
257
+ twice.
258
+ and_return('263.1', '263.2')
259
+ Marquise::FFI.
260
+ should_receive(:marquise_close).
261
+ with('263.1')
262
+ Marquise::FFI.
263
+ should_receive(:marquise_close).
264
+ with('263.2')
265
+
266
+ x = Marquise.open('tcp://localhost:4567')
267
+
268
+ Thread.new { x.connect }.join
269
+ Thread.new { x.connect }.join
270
+
271
+ x.close
272
+ end
273
+ end
274
+ end
@@ -0,0 +1,183 @@
1
+ require_relative './spec_helper'
2
+ require 'marquise'
3
+
4
+ describe Marquise do
5
+ describe "#tell" do
6
+ let(:marquise) do
7
+ Marquise::FFI.
8
+ should_receive(:marquise_consumer_new).
9
+ with('tcp://localhost:4567', 5).
10
+ and_return('#tell')
11
+ Marquise::FFI.
12
+ should_receive(:marquise_connect).
13
+ with('#tell').
14
+ and_return('#tellconn')
15
+
16
+ x = Marquise.new('tcp://localhost:4567')
17
+ # Neuter the Marquise
18
+ ObjectSpace.undefine_finalizer(x)
19
+
20
+ x
21
+ end
22
+
23
+ describe "(binary)" do
24
+ it "sends a simple binary" do
25
+ Marquise::FFI.stub(:send) do |*args|
26
+ expect(args).to be_an(Array)
27
+ expect(args.length).to eq(8)
28
+
29
+ method, conn, src_f, src_v, src_c, data, len, tstamp = args
30
+
31
+ expect(method).to eq(:marquise_send_binary)
32
+ expect(conn).to eq('#tellconn')
33
+
34
+ expect(tstamp).
35
+ to be_within(1_000_000_000).
36
+ of(Time.now.to_f * 1_000_000_000)
37
+
38
+ expect(src_c).to eq(0)
39
+ expect(src_f).to be(nil)
40
+ expect(src_v).to be(nil)
41
+
42
+ expect(len).to eq("hello world".length)
43
+ expect(data).to eq("hello world")
44
+
45
+ 0
46
+ end
47
+
48
+ marquise.tell "hello world".encode('ASCII-8BIT')
49
+ end
50
+
51
+ it "sends a non-UTF-8 string as binary" do
52
+ Marquise::FFI.stub(:send) do |*args|
53
+ expect(args).to be_an(Array)
54
+ expect(args.length).to eq(8)
55
+
56
+ method, conn, src_f, src_v, src_c, data, len, tstamp = args
57
+
58
+ expect(method).to eq(:marquise_send_binary)
59
+ expect(conn).to eq('#tellconn')
60
+
61
+ expect(tstamp).
62
+ to be_within(1_000_000_000).
63
+ of(Time.now.to_f * 1_000_000_000)
64
+
65
+ expect(src_c).to eq(0)
66
+ expect(src_f).to be(nil)
67
+ expect(src_v).to be(nil)
68
+
69
+ expect(len).to eq(1)
70
+ expect(data).to eq("\xC0")
71
+
72
+ 0
73
+ end
74
+
75
+ marquise.tell "\xC0"
76
+ end
77
+
78
+ it "sends binary and a timestamp" do
79
+ t = Time.now - 86400
80
+
81
+ Marquise::FFI.stub(:send) do |*args|
82
+ expect(args).to be_an(Array)
83
+ expect(args.length).to eq(8)
84
+
85
+ method, conn, src_f, src_v, src_c, data, len, tstamp = args
86
+
87
+ expect(method).to eq(:marquise_send_binary)
88
+ expect(conn).to eq('#tellconn')
89
+
90
+ expect(tstamp).to eq(t.to_f * 1_000_000_000)
91
+
92
+ expect(src_c).to eq(0)
93
+ expect(src_f).to be(nil)
94
+ expect(src_v).to be(nil)
95
+
96
+ expect(len).to eq("hello world".length)
97
+ expect(data).to eq("hello world")
98
+
99
+ 0
100
+ end
101
+
102
+ marquise.tell "hello world".encode('ASCII-8BIT'), t
103
+ end
104
+
105
+ it "sends binary and tags" do
106
+ Marquise::FFI.stub(:send) do |*args|
107
+ expect(args).to be_an(Array)
108
+ expect(args.length).to eq(8)
109
+
110
+ method, conn, src_f, src_v, src_c, data, len, tstamp = args
111
+
112
+ expect(method).to eq(:marquise_send_binary)
113
+ expect(conn).to eq('#tellconn')
114
+
115
+ expect(tstamp).
116
+ to be_within(1_000_000_000).
117
+ of(Time.now.to_f * 1_000_000_000)
118
+
119
+ expect(src_c).to eq(2)
120
+
121
+ expect(src_f).to be_a(FFI::MemoryPointer)
122
+ expect(src_f.size).to eq(3*src_f.type_size)
123
+ expect(src_f[0].read_pointer.read_string).to eq('foo')
124
+ expect(src_f[1].read_pointer.read_string).to eq('answer')
125
+ expect(src_f[2].read_pointer.address).to eq(0)
126
+
127
+ expect(src_v).to be_a(FFI::MemoryPointer)
128
+ expect(src_v.size).to eq(3*src_f.type_size)
129
+ expect(src_v[0].read_pointer.read_string).to eq('bar')
130
+ expect(src_v[1].read_pointer.read_string).to eq('42')
131
+ expect(src_v[2].read_pointer.address).to eq(0)
132
+
133
+ expect(len).to eq("hello world".length)
134
+ expect(data).to eq("hello world")
135
+
136
+ 0
137
+ end
138
+
139
+ marquise.tell "hello world".encode('ASCII-8BIT'),
140
+ :foo => 'bar', 'answer' => 42
141
+ end
142
+
143
+ it "sends binary, timestamp and source" do
144
+ t = Time.now + 86400
145
+
146
+ Marquise::FFI.stub(:send) do |*args|
147
+ expect(args).to be_an(Array)
148
+ expect(args.length).to eq(8)
149
+
150
+ method, conn, src_f, src_v, src_c, data, len, tstamp = args
151
+
152
+ expect(method).to eq(:marquise_send_binary)
153
+ expect(conn).to eq('#tellconn')
154
+
155
+ expect(tstamp).to eq(t.to_f * 1_000_000_000)
156
+
157
+ expect(src_c).to eq(2)
158
+
159
+ expect(src_f).to be_a(FFI::MemoryPointer)
160
+ expect(src_f.size).to eq(3*src_f.type_size)
161
+ expect(src_f[0].read_pointer.read_string).to eq('foo')
162
+ expect(src_f[1].read_pointer.read_string).to eq('answer')
163
+ expect(src_f[2].read_pointer.address).to eq(0)
164
+
165
+ expect(src_v).to be_a(FFI::MemoryPointer)
166
+ expect(src_v.size).to eq(3*src_f.type_size)
167
+ expect(src_v[0].read_pointer.read_string).to eq('bar')
168
+ expect(src_v[1].read_pointer.read_string).to eq('42')
169
+ expect(src_v[2].read_pointer.address).to eq(0)
170
+
171
+ expect(len).to eq("hello world".length)
172
+ expect(data).to eq("hello world")
173
+
174
+ 0
175
+ end
176
+
177
+ marquise.tell "hello world".encode('ASCII-8BIT'),
178
+ t,
179
+ :foo => 'bar', 'answer' => 42
180
+ end
181
+ end
182
+ end
183
+ end