riemann-client 1.0.1 → 1.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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/ci.yml +8 -7
- data/.github/workflows/codeql-analysis.yml +72 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +20 -2
- data/Rakefile +1 -1
- data/SECURITY.md +42 -0
- data/lib/riemann/client/tcp_socket.rb +1 -1
- data/lib/riemann/client.rb +32 -12
- data/lib/riemann/version.rb +1 -1
- data/riemann-client.gemspec +2 -1
- data/spec/client_spec.rb +66 -0
- data/spec/shared_examples.rb +531 -0
- data/spec/spec_helper.rb +38 -0
- metadata +32 -10
- data/spec/client.rb +0 -384
data/spec/client.rb
DELETED
@@ -1,384 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# How to run the bacon tests:
|
5
|
-
# 1. Start Riemann using the config from riemann.config
|
6
|
-
# 2. $ bundle exec bacon spec/client.rb
|
7
|
-
|
8
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'riemann'))
|
9
|
-
require 'riemann/client'
|
10
|
-
require 'bacon'
|
11
|
-
require 'set'
|
12
|
-
require 'timecop'
|
13
|
-
|
14
|
-
Bacon.summary_on_exit
|
15
|
-
|
16
|
-
include Riemann # rubocop:disable Style/MixinUsage
|
17
|
-
|
18
|
-
INACTIVITY_TIME = 5
|
19
|
-
|
20
|
-
def wait_for(&block)
|
21
|
-
tries = 0
|
22
|
-
while tries < 30
|
23
|
-
tries += 1
|
24
|
-
begin
|
25
|
-
res = block.call
|
26
|
-
return res if res
|
27
|
-
rescue NoMethodError
|
28
|
-
# If a query returns no result (#query retruns nil or #[] returns []),
|
29
|
-
# calling #first on it will raise a NoMethodError. We can ignore it for
|
30
|
-
# these tests.
|
31
|
-
end
|
32
|
-
sleep(0.1)
|
33
|
-
end
|
34
|
-
|
35
|
-
raise 'wait_for condition never realized'
|
36
|
-
end
|
37
|
-
|
38
|
-
def roundtrip_metric(metric)
|
39
|
-
@client_with_transport << {
|
40
|
-
service: 'metric-test',
|
41
|
-
metric: metric
|
42
|
-
}
|
43
|
-
|
44
|
-
wait_for { @client["service = \"metric-test\" and metric = #{metric}"].first }
|
45
|
-
.metric.should.equal metric
|
46
|
-
end
|
47
|
-
|
48
|
-
def truthy
|
49
|
-
->(obj) { !(obj.nil? || obj == false) }
|
50
|
-
end
|
51
|
-
|
52
|
-
def falsey
|
53
|
-
->(obj) { obj.nil? || obj == false }
|
54
|
-
end
|
55
|
-
|
56
|
-
shared 'a riemann client' do
|
57
|
-
should 'yield itself to given block' do
|
58
|
-
client = nil
|
59
|
-
Client.new(host: 'localhost', port: 5555) do |c|
|
60
|
-
client = c
|
61
|
-
end
|
62
|
-
client.should.be.is_a?(Client)
|
63
|
-
client.should.not.be.connected
|
64
|
-
end
|
65
|
-
|
66
|
-
should 'close sockets if given a block that raises' do
|
67
|
-
client = nil
|
68
|
-
begin
|
69
|
-
Client.new(host: 'localhost', port: 5555) do |c|
|
70
|
-
client = c
|
71
|
-
raise 'The Boom'
|
72
|
-
end
|
73
|
-
rescue StandardError
|
74
|
-
# swallow the exception
|
75
|
-
end
|
76
|
-
client.should.be.is_a?(Client)
|
77
|
-
client.should.not.be.connected
|
78
|
-
end
|
79
|
-
|
80
|
-
should 'be connected after sending' do
|
81
|
-
@client_with_transport.connected?.should.be falsey
|
82
|
-
@client.connected?.should.be falsey
|
83
|
-
@client_with_transport << { state: 'ok', service: 'connected check' }
|
84
|
-
@client_with_transport.connected?.should.be truthy
|
85
|
-
# NOTE: only single transport connected at this point, @client.connected? is still false until all transports used
|
86
|
-
end
|
87
|
-
|
88
|
-
should 'send longs' do
|
89
|
-
roundtrip_metric(0)
|
90
|
-
roundtrip_metric(-3)
|
91
|
-
roundtrip_metric(5)
|
92
|
-
roundtrip_metric(-(2**63))
|
93
|
-
roundtrip_metric(2**63 - 1)
|
94
|
-
end
|
95
|
-
|
96
|
-
should 'send doubles' do
|
97
|
-
roundtrip_metric 0.0
|
98
|
-
roundtrip_metric 12.0
|
99
|
-
roundtrip_metric 1.2300000190734863
|
100
|
-
end
|
101
|
-
|
102
|
-
should 'send custom attributes' do
|
103
|
-
event = Event.new(
|
104
|
-
service: 'custom',
|
105
|
-
state: 'ok',
|
106
|
-
cats: 'meow',
|
107
|
-
env: 'prod'
|
108
|
-
)
|
109
|
-
event[:sneak] = 'attack'
|
110
|
-
@client_with_transport << event
|
111
|
-
event2 = wait_for { @client['service = "custom"'].first }
|
112
|
-
event2.service.should.equal 'custom'
|
113
|
-
event2.state.should.equal 'ok'
|
114
|
-
event2[:cats].should.equal 'meow'
|
115
|
-
event2[:env].should.equal 'prod'
|
116
|
-
event2[:sneak].should.equal 'attack'
|
117
|
-
end
|
118
|
-
|
119
|
-
should 'send a state with a time' do
|
120
|
-
Timecop.freeze do
|
121
|
-
t = (Time.now - 10).to_i
|
122
|
-
@client_with_transport << {
|
123
|
-
state: 'ok',
|
124
|
-
service: 'test',
|
125
|
-
time: t
|
126
|
-
}
|
127
|
-
wait_for { @client.query('service = "test"').events.first.time == t }
|
128
|
-
e = @client.query('service = "test"').events.first
|
129
|
-
e.time.should.equal t
|
130
|
-
e.time_micros.should.equal t * 1_000_000
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
should 'send a state with a time_micros' do
|
135
|
-
Timecop.freeze do
|
136
|
-
t = ((Time.now - 10).to_f * 1_000_000).to_i
|
137
|
-
@client_with_transport << {
|
138
|
-
state: 'ok',
|
139
|
-
service: 'test',
|
140
|
-
time_micros: t
|
141
|
-
}
|
142
|
-
wait_for { @client.query('service = "test"').events.first.time_micros == t }
|
143
|
-
e = @client.query('service = "test"').events.first
|
144
|
-
e.time.should.equal (Time.now - 10).to_i
|
145
|
-
e.time_micros.should.equal t
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
should 'send a state without time nor time_micros' do
|
150
|
-
time_before = (Time.now.to_f * 1_000_000).to_i
|
151
|
-
@client_with_transport << {
|
152
|
-
state: 'ok',
|
153
|
-
service: 'timeless test'
|
154
|
-
}
|
155
|
-
wait_for { @client.query('service = "timeless test"').events.first.time_micros >= time_before }
|
156
|
-
e = @client.query('service = "timeless test"').events.first
|
157
|
-
time_after = (Time.now.to_f * 1_000_000).to_i
|
158
|
-
|
159
|
-
[time_before, e.time_micros, time_after].sort.should.equal([time_before, e.time_micros, time_after])
|
160
|
-
end
|
161
|
-
|
162
|
-
should 'query states' do
|
163
|
-
@client_with_transport << { state: 'critical', service: '1' }
|
164
|
-
@client_with_transport << { state: 'warning', service: '2' }
|
165
|
-
@client_with_transport << { state: 'critical', service: '3' }
|
166
|
-
wait_for { @client.query('service = "3"').events.first }
|
167
|
-
@client.query.events
|
168
|
-
.map(&:service).to_set.should.superset %w[1 2 3].to_set
|
169
|
-
@client.query('state = "critical" and (service = "1" or service = "2" or service = "3")').events
|
170
|
-
.map(&:service).to_set.should.equal %w[1 3].to_set
|
171
|
-
end
|
172
|
-
|
173
|
-
it '[]' do
|
174
|
-
# @client['state = "critical"'].should == []
|
175
|
-
@client_with_transport << { state: 'critical' }
|
176
|
-
wait_for { @client['state = "critical"'].first }.state.should.equal 'critical'
|
177
|
-
end
|
178
|
-
|
179
|
-
should 'query quickly' do
|
180
|
-
t1 = Time.now
|
181
|
-
total = 1000
|
182
|
-
total.times do |_i|
|
183
|
-
@client.query('state = "critical"')
|
184
|
-
end
|
185
|
-
t2 = Time.now
|
186
|
-
|
187
|
-
rate = total / (t2 - t1)
|
188
|
-
puts "\n #{format('%.2f', rate)} queries/sec (#{format('%.2f', (1000 / rate))}ms per query)"
|
189
|
-
rate.should > 100
|
190
|
-
end
|
191
|
-
|
192
|
-
should 'be threadsafe' do
|
193
|
-
concurrency = 10
|
194
|
-
per_thread = 200
|
195
|
-
total = concurrency * per_thread
|
196
|
-
|
197
|
-
t1 = Time.now
|
198
|
-
(0...concurrency).map do |_i|
|
199
|
-
Thread.new do
|
200
|
-
per_thread.times do
|
201
|
-
@client_with_transport.<<({
|
202
|
-
state: 'ok',
|
203
|
-
service: 'test',
|
204
|
-
description: 'desc',
|
205
|
-
metric_f: 1.0
|
206
|
-
})
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end.each(&:join)
|
210
|
-
t2 = Time.now
|
211
|
-
|
212
|
-
rate = total / (t2 - t1)
|
213
|
-
puts "\n #{format('%.2f', rate)} inserts/sec (#{format('%.2f', (1000 / rate))}ms per insert)"
|
214
|
-
rate.should > @expected_rate
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
describe 'Riemann::Client (TLS transport)' do
|
219
|
-
before do
|
220
|
-
@client = Client.new(host: 'localhost', port: 5554, ssl: true,
|
221
|
-
key_file: '/etc/riemann/riemann_server.pkcs8',
|
222
|
-
cert_file: '/etc/riemann/riemann_server.crt',
|
223
|
-
ca_file: '/etc/riemann/riemann_server.crt',
|
224
|
-
ssl_verify: true)
|
225
|
-
@client_with_transport = @client.tcp
|
226
|
-
@expected_rate = 100
|
227
|
-
end
|
228
|
-
behaves_like 'a riemann client'
|
229
|
-
|
230
|
-
should 'send a state' do
|
231
|
-
res = @client_with_transport << {
|
232
|
-
state: 'ok',
|
233
|
-
service: 'test',
|
234
|
-
description: 'desc',
|
235
|
-
metric_f: 1.0
|
236
|
-
}
|
237
|
-
|
238
|
-
res.ok.should.be truthy
|
239
|
-
wait_for { @client['service = "test"'].first }.state.should.equal 'ok'
|
240
|
-
end
|
241
|
-
|
242
|
-
should 'survive inactivity' do
|
243
|
-
@client_with_transport.<<({
|
244
|
-
state: 'warning',
|
245
|
-
service: 'survive TCP inactivity'
|
246
|
-
})
|
247
|
-
wait_for { @client['service = "survive TCP inactivity"'].first.state == 'warning' }
|
248
|
-
|
249
|
-
sleep INACTIVITY_TIME
|
250
|
-
|
251
|
-
@client_with_transport.<<({
|
252
|
-
state: 'ok',
|
253
|
-
service: 'survive TCP inactivity'
|
254
|
-
}).ok.should.be truthy
|
255
|
-
wait_for { @client['service = "survive TCP inactivity"'].first.state == 'ok' }
|
256
|
-
end
|
257
|
-
|
258
|
-
should 'survive local close' do
|
259
|
-
@client_with_transport.<<({
|
260
|
-
state: 'warning',
|
261
|
-
service: 'survive TCP local close'
|
262
|
-
}).ok.should.be truthy
|
263
|
-
wait_for { @client['service = "survive TCP local close"'].first.state == 'warning' }
|
264
|
-
|
265
|
-
@client.close
|
266
|
-
|
267
|
-
@client_with_transport.<<({
|
268
|
-
state: 'ok',
|
269
|
-
service: 'survive TCP local close'
|
270
|
-
}).ok.should.be truthy
|
271
|
-
wait_for { @client['service = "survive TCP local close"'].first.state == 'ok' }
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
describe 'Riemann::Client (TCP transport)' do
|
276
|
-
before do
|
277
|
-
@client = Client.new(host: 'localhost', port: 5555)
|
278
|
-
@client_with_transport = @client.tcp
|
279
|
-
@expected_rate = 100
|
280
|
-
end
|
281
|
-
behaves_like 'a riemann client'
|
282
|
-
|
283
|
-
should 'send a state' do
|
284
|
-
res = @client_with_transport << {
|
285
|
-
state: 'ok',
|
286
|
-
service: 'test',
|
287
|
-
description: 'desc',
|
288
|
-
metric_f: 1.0
|
289
|
-
}
|
290
|
-
|
291
|
-
res.ok.should.be truthy
|
292
|
-
wait_for { @client['service = "test"'].first }.state.should.equal 'ok'
|
293
|
-
end
|
294
|
-
|
295
|
-
should 'survive inactivity' do
|
296
|
-
@client_with_transport.<<({
|
297
|
-
state: 'warning',
|
298
|
-
service: 'survive TCP inactivity'
|
299
|
-
})
|
300
|
-
wait_for { @client['service = "survive TCP inactivity"'].first.state == 'warning' }
|
301
|
-
|
302
|
-
sleep INACTIVITY_TIME
|
303
|
-
|
304
|
-
@client_with_transport.<<({
|
305
|
-
state: 'ok',
|
306
|
-
service: 'survive TCP inactivity'
|
307
|
-
}).ok.should.be truthy
|
308
|
-
wait_for { @client['service = "survive TCP inactivity"'].first.state == 'ok' }
|
309
|
-
end
|
310
|
-
|
311
|
-
should 'survive local close' do
|
312
|
-
@client_with_transport.<<({
|
313
|
-
state: 'warning',
|
314
|
-
service: 'survive TCP local close'
|
315
|
-
}).ok.should.be truthy
|
316
|
-
wait_for { @client['service = "survive TCP local close"'].first.state == 'warning' }
|
317
|
-
|
318
|
-
@client.close
|
319
|
-
|
320
|
-
@client_with_transport.<<({
|
321
|
-
state: 'ok',
|
322
|
-
service: 'survive TCP local close'
|
323
|
-
}).ok.should.be truthy
|
324
|
-
wait_for { @client['service = "survive TCP local close"'].first.state == 'ok' }
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
describe 'Riemann::Client (UDP transport)' do
|
329
|
-
before do
|
330
|
-
@client = Client.new(host: 'localhost', port: 5555)
|
331
|
-
@client_with_transport = @client.udp
|
332
|
-
@expected_rate = 1000
|
333
|
-
end
|
334
|
-
behaves_like 'a riemann client'
|
335
|
-
|
336
|
-
should 'send a state' do
|
337
|
-
res = @client_with_transport << {
|
338
|
-
state: 'ok',
|
339
|
-
service: 'test',
|
340
|
-
description: 'desc',
|
341
|
-
metric_f: 1.0
|
342
|
-
}
|
343
|
-
|
344
|
-
res.should.be.nil
|
345
|
-
wait_for { @client['service = "test"'].first }.state.should.equal 'ok'
|
346
|
-
end
|
347
|
-
|
348
|
-
should 'survive inactivity' do
|
349
|
-
@client_with_transport.<<({
|
350
|
-
state: 'warning',
|
351
|
-
service: 'survive UDP inactivity'
|
352
|
-
}).should.be.nil
|
353
|
-
wait_for { @client['service = "survive UDP inactivity"'].first.state == 'warning' }
|
354
|
-
|
355
|
-
sleep INACTIVITY_TIME
|
356
|
-
|
357
|
-
@client_with_transport.<<({
|
358
|
-
state: 'ok',
|
359
|
-
service: 'survive UDP inactivity'
|
360
|
-
}).should.be.nil
|
361
|
-
wait_for { @client['service = "survive UDP inactivity"'].first.state == 'ok' }
|
362
|
-
end
|
363
|
-
|
364
|
-
should 'survive local close' do
|
365
|
-
@client_with_transport.<<({
|
366
|
-
state: 'warning',
|
367
|
-
service: 'survive UDP local close'
|
368
|
-
}).should.be.nil
|
369
|
-
wait_for { @client['service = "survive UDP local close"'].first.state == 'warning' }
|
370
|
-
|
371
|
-
@client.close
|
372
|
-
|
373
|
-
@client_with_transport.<<({
|
374
|
-
state: 'ok',
|
375
|
-
service: 'survive UDP local close'
|
376
|
-
}).should.be.nil
|
377
|
-
wait_for { @client['service = "survive UDP local close"'].first.state == 'ok' }
|
378
|
-
end
|
379
|
-
|
380
|
-
should 'raise Riemann::Client::Unsupported exception on query' do
|
381
|
-
should.raise(Riemann::Client::Unsupported) { @client_with_transport['service = "test"'] }
|
382
|
-
should.raise(Riemann::Client::Unsupported) { @client_with_transport.query('service = "test"') }
|
383
|
-
end
|
384
|
-
end
|