librato-statsd-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new("librato-statsd-ruby", "1.0.0") do |s|
4
+ s.authors = ["Bryan Mikaelian"]
5
+ s.email = 'support@librato.com'
6
+
7
+ s.summary = "A Ruby StatsD client with Librato support"
8
+
9
+ s.homepage = "https://www.librato.com/docs/kb/collect/collection_agents/stastd.html"
10
+ s.licenses = %w[MIT]
11
+
12
+ s.extra_rdoc_files = %w[LICENSE.txt README.md]
13
+
14
+ if $0 =~ /gem/ # If running under rubygems (building), otherwise, just leave
15
+ s.files = `git ls-files`.split($\)
16
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
17
+ end
18
+
19
+ s.add_development_dependency "minitest", ">= 3.2.0"
20
+ s.add_development_dependency "yard"
21
+ s.add_development_dependency "simplecov", ">= 0.6.4"
22
+ s.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,43 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ require 'minitest/autorun'
7
+ require 'librato-statsd-ruby'
8
+ require 'logger'
9
+ require 'timeout'
10
+
11
+ class FakeUDPSocket
12
+ def initialize
13
+ @buffer = []
14
+ end
15
+
16
+ def write(message)
17
+ @buffer.push [message]
18
+ message.length
19
+ end
20
+
21
+ def recv
22
+ @buffer.shift
23
+ end
24
+
25
+ def clear
26
+ @buffer = []
27
+ end
28
+
29
+ def to_s
30
+ inspect
31
+ end
32
+
33
+ def inspect
34
+ "<#{self.class.name}: #{@buffer.inspect}>"
35
+ end
36
+ end
37
+
38
+ class FakeTCPSocket < FakeUDPSocket
39
+ alias_method :readline, :recv
40
+ def write(message)
41
+ @buffer.push message
42
+ end
43
+ end
@@ -0,0 +1,117 @@
1
+ require 'helper'
2
+
3
+ describe Statsd::Admin do
4
+
5
+ before do
6
+ class Statsd::Admin
7
+ o, $VERBOSE = $VERBOSE, nil
8
+ alias connect_old connect
9
+ def connect
10
+ $connect_count ||= 0
11
+ $connect_count += 1
12
+ end
13
+ $VERBOSE = o
14
+ end
15
+ @admin = Statsd::Admin.new('localhost', 1234)
16
+ @socket = @admin.instance_variable_set(:@socket, FakeTCPSocket.new)
17
+ end
18
+
19
+ after do
20
+ class Statsd::Admin
21
+ o, $VERBOSE = $VERBOSE, nil
22
+ alias connect connect_old
23
+ $VERBOSE = o
24
+ end
25
+ end
26
+
27
+ describe "#initialize" do
28
+ it "should set the host and port" do
29
+ @admin.host.must_equal 'localhost'
30
+ @admin.port.must_equal 1234
31
+ end
32
+
33
+ it "should default the host to 127.0.0.1 and port to 8126" do
34
+ statsd = Statsd::Admin.new
35
+ statsd.host.must_equal '127.0.0.1'
36
+ statsd.port.must_equal 8126
37
+ end
38
+ end
39
+
40
+ describe "#host and #port" do
41
+ it "should set host and port" do
42
+ @admin.host = '1.2.3.4'
43
+ @admin.port = 5678
44
+ @admin.host.must_equal '1.2.3.4'
45
+ @admin.port.must_equal 5678
46
+ end
47
+
48
+ it "should not resolve hostnames to IPs" do
49
+ @admin.host = 'localhost'
50
+ @admin.host.must_equal 'localhost'
51
+ end
52
+
53
+ it "should set nil host to default" do
54
+ @admin.host = nil
55
+ @admin.host.must_equal '127.0.0.1'
56
+ end
57
+
58
+ it "should set nil port to default" do
59
+ @admin.port = nil
60
+ @admin.port.must_equal 8126
61
+ end
62
+ end
63
+
64
+ %w(gauges counters timers).each do |action|
65
+ describe "##{action}" do
66
+ it "should send a command and return a Hash" do
67
+ ["{'foo.bar': 0,\n",
68
+ "'foo.baz': 1,\n",
69
+ "'foo.quux': 2 }\n",
70
+ "END\n","\n"].each do |line|
71
+ @socket.write line
72
+ end
73
+ result = @admin.send action.to_sym
74
+ result.must_be_kind_of Hash
75
+ result.size.must_equal 3
76
+ @socket.readline.must_equal "#{action}\n"
77
+ end
78
+ end
79
+
80
+ describe "#del#{action}" do
81
+ it "should send a command and return an Array" do
82
+ ["deleted: foo.bar\n",
83
+ "deleted: foo.baz\n",
84
+ "deleted: foo.quux\n",
85
+ "END\n", "\n"].each do |line|
86
+ @socket.write line
87
+ end
88
+ result = @admin.send "del#{action}", "foo.*"
89
+ result.must_be_kind_of Array
90
+ result.size.must_equal 3
91
+ @socket.readline.must_equal "del#{action} foo.*\n"
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "#stats" do
97
+ it "should send a command and return a Hash" do
98
+ ["whatever: 0\n", "END\n", "\n"].each do |line|
99
+ @socket.write line
100
+ end
101
+ result = @admin.stats
102
+ result.must_be_kind_of Hash
103
+ result["whatever"].must_equal 0
104
+ @socket.readline.must_equal "stats\n"
105
+ end
106
+ end
107
+
108
+ describe "#connect" do
109
+ it "should reconnect" do
110
+ c = $connect_count
111
+ @admin.connect
112
+ ($connect_count - c).must_equal 1
113
+ end
114
+ end
115
+ end
116
+
117
+
@@ -0,0 +1,562 @@
1
+ require 'helper'
2
+
3
+ describe Statsd do
4
+ before do
5
+ class Statsd
6
+ o, $VERBOSE = $VERBOSE, nil
7
+ alias connect_old connect
8
+ def connect
9
+ $connect_count ||= 1
10
+ $connect_count += 1
11
+ end
12
+ $VERBOSE = o
13
+ end
14
+
15
+ @statsd = Statsd.new('localhost', 1234)
16
+ @socket = @statsd.instance_variable_set(:@socket, FakeUDPSocket.new)
17
+ end
18
+
19
+ after do
20
+ class Statsd
21
+ o, $VERBOSE = $VERBOSE, nil
22
+ alias connect connect_old
23
+ $VERBOSE = o
24
+ end
25
+ end
26
+
27
+ describe "#initialize" do
28
+ it "should set the host and port" do
29
+ @statsd.host.must_equal 'localhost'
30
+ @statsd.port.must_equal 1234
31
+ end
32
+
33
+ it "should default the host to 127.0.0.1 and port to 8125" do
34
+ statsd = Statsd.new
35
+ statsd.host.must_equal '127.0.0.1'
36
+ statsd.port.must_equal 8125
37
+ end
38
+
39
+ it "should set delimiter to period by default" do
40
+ @statsd.delimiter.must_equal "."
41
+ end
42
+ end
43
+
44
+ describe "#host and #port" do
45
+ it "should set host and port" do
46
+ @statsd.host = '1.2.3.4'
47
+ @statsd.port = 5678
48
+ @statsd.host.must_equal '1.2.3.4'
49
+ @statsd.port.must_equal 5678
50
+ end
51
+
52
+ it "should not resolve hostnames to IPs" do
53
+ @statsd.host = 'localhost'
54
+ @statsd.host.must_equal 'localhost'
55
+ end
56
+
57
+ it "should set nil host to default" do
58
+ @statsd.host = nil
59
+ @statsd.host.must_equal '127.0.0.1'
60
+ end
61
+
62
+ it "should set nil port to default" do
63
+ @statsd.port = nil
64
+ @statsd.port.must_equal 8125
65
+ end
66
+
67
+ it "should allow an IPv6 address" do
68
+ @statsd.host = '::1'
69
+ @statsd.host.must_equal '::1'
70
+ end
71
+ end
72
+
73
+ describe "#delimiter" do
74
+ it "should set delimiter" do
75
+ @statsd.delimiter = "-"
76
+ @statsd.delimiter.must_equal "-"
77
+ end
78
+
79
+ it "should set default to period if not given a value" do
80
+ @statsd.delimiter = nil
81
+ @statsd.delimiter.must_equal "."
82
+ end
83
+ end
84
+
85
+ describe "#increment" do
86
+ it "should format the message according to the statsd spec" do
87
+ @statsd.increment('foobar')
88
+ @socket.recv.must_equal ['foobar:1|c']
89
+ end
90
+
91
+ describe "with a sample rate" do
92
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
93
+ it "should format the message according to the statsd spec" do
94
+ @statsd.increment('foobar', { sample_rate: 0.5 })
95
+ @socket.recv.must_equal ['foobar:1|c|@0.5']
96
+ end
97
+ end
98
+ end
99
+
100
+ describe "#decrement" do
101
+ it "should format the message according to the statsd spec" do
102
+ @statsd.decrement('foobar')
103
+ @socket.recv.must_equal ['foobar:-1|c']
104
+ end
105
+
106
+ describe "with a sample rate" do
107
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
108
+ it "should format the message according to the statsd spec" do
109
+ @statsd.decrement('foobar', { sample_rate: 0.5 })
110
+ @socket.recv.must_equal ['foobar:-1|c|@0.5']
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "#gauge" do
116
+ it "should send a message with a 'g' type, per the nearbuy fork" do
117
+ @statsd.gauge('begrutten-suffusion', 536)
118
+ @socket.recv.must_equal ['begrutten-suffusion:536|g']
119
+ @statsd.gauge('begrutten-suffusion', -107.3)
120
+ @socket.recv.must_equal ['begrutten-suffusion:-107.3|g']
121
+ end
122
+
123
+ describe "with a sample rate" do
124
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
125
+ it "should format the message according to the statsd spec" do
126
+ @statsd.gauge('begrutten-suffusion', 536, { sample_rate: 0.1 })
127
+ @socket.recv.must_equal ['begrutten-suffusion:536|g|@0.1']
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "#timing" do
133
+ it "should format the message according to the statsd spec" do
134
+ @statsd.timing('foobar', 500)
135
+ @socket.recv.must_equal ['foobar:500|ms']
136
+ end
137
+
138
+ describe "with a sample rate" do
139
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
140
+ it "should format the message according to the statsd spec" do
141
+ @statsd.timing('foobar', 500, { sample_rate: 0.5 })
142
+ @socket.recv.must_equal ['foobar:500|ms|@0.5']
143
+ end
144
+ end
145
+ end
146
+
147
+ describe "#set" do
148
+ it "should format the message according to the statsd spec" do
149
+ @statsd.set('foobar', 765)
150
+ @socket.recv.must_equal ['foobar:765|s']
151
+ end
152
+
153
+ describe "with a sample rate" do
154
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
155
+ it "should format the message according to the statsd spec" do
156
+ @statsd.set('foobar', 500, { sample_rate: 0.5 })
157
+ @socket.recv.must_equal ['foobar:500|s|@0.5']
158
+ end
159
+ end
160
+ end
161
+
162
+ describe "#time" do
163
+ it "should format the message according to the statsd spec" do
164
+ @statsd.time('foobar') { 'test' }
165
+ @socket.recv.must_equal ['foobar:0|ms']
166
+ end
167
+
168
+ it "should return the result of the block" do
169
+ result = @statsd.time('foobar') { 'test' }
170
+ result.must_equal 'test'
171
+ end
172
+
173
+ describe "when given a block with an explicit return" do
174
+ it "should format the message according to the statsd spec" do
175
+ lambda { @statsd.time('foobar') { return 'test' } }.call
176
+ @socket.recv.must_equal ['foobar:0|ms']
177
+ end
178
+
179
+ it "should return the result of the block" do
180
+ result = lambda { @statsd.time('foobar') { return 'test' } }.call
181
+ result.must_equal 'test'
182
+ end
183
+ end
184
+
185
+ describe "with a sample rate" do
186
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
187
+
188
+ it "should format the message according to the statsd spec" do
189
+ @statsd.time('foobar', { sample_rate: 0.5 }) { 'test' }
190
+ @socket.recv.must_equal ['foobar:0|ms|@0.5']
191
+ end
192
+ end
193
+ end
194
+
195
+ describe "#sampled" do
196
+ describe "when the sample rate is 1" do
197
+ before { class << @statsd; def rand; raise end; end }
198
+ it "should send" do
199
+ @statsd.timing('foobar', 500, { sample_rate: 1 })
200
+ @socket.recv.must_equal ['foobar:500|ms']
201
+ end
202
+ end
203
+
204
+ describe "when the sample rate is greater than a random value [0,1]" do
205
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
206
+ it "should send" do
207
+ @statsd.timing('foobar', 500, { sample_rate: 0.5 })
208
+ @socket.recv.must_equal ['foobar:500|ms|@0.5']
209
+ end
210
+ end
211
+
212
+ describe "when the sample rate is less than a random value [0,1]" do
213
+ before { class << @statsd; def rand; 1; end; end } # ensure no delivery
214
+ it "should not send" do
215
+ @statsd.timing('foobar', 500, { sample_rate: 0.5 }).must_equal nil
216
+ end
217
+ end
218
+
219
+ describe "when the sample rate is equal to a random value [0,1]" do
220
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
221
+ it "should send" do
222
+ @statsd.timing('foobar', 500, { sample_rate: 0.5 })
223
+ @socket.recv.must_equal ['foobar:500|ms|@0.5']
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "with namespace" do
229
+ before { @statsd.namespace = 'service' }
230
+
231
+ it "should add namespace to increment" do
232
+ @statsd.increment('foobar')
233
+ @socket.recv.must_equal ['service.foobar:1|c']
234
+ end
235
+
236
+ it "should add namespace to decrement" do
237
+ @statsd.decrement('foobar')
238
+ @socket.recv.must_equal ['service.foobar:-1|c']
239
+ end
240
+
241
+ it "should add namespace to timing" do
242
+ @statsd.timing('foobar', 500)
243
+ @socket.recv.must_equal ['service.foobar:500|ms']
244
+ end
245
+
246
+ it "should add namespace to gauge" do
247
+ @statsd.gauge('foobar', 500)
248
+ @socket.recv.must_equal ['service.foobar:500|g']
249
+ end
250
+ end
251
+
252
+ describe "with postfix" do
253
+ before { @statsd.postfix = 'ip-23-45-56-78' }
254
+
255
+ it "should add postfix to increment" do
256
+ @statsd.increment('foobar')
257
+ @socket.recv.must_equal ['foobar.ip-23-45-56-78:1|c']
258
+ end
259
+
260
+ it "should add postfix to decrement" do
261
+ @statsd.decrement('foobar')
262
+ @socket.recv.must_equal ['foobar.ip-23-45-56-78:-1|c']
263
+ end
264
+
265
+ it "should add namespace to timing" do
266
+ @statsd.timing('foobar', 500)
267
+ @socket.recv.must_equal ['foobar.ip-23-45-56-78:500|ms']
268
+ end
269
+
270
+ it "should add namespace to gauge" do
271
+ @statsd.gauge('foobar', 500)
272
+ @socket.recv.must_equal ['foobar.ip-23-45-56-78:500|g']
273
+ end
274
+ end
275
+
276
+ describe '#postfix=' do
277
+ describe "when nil, false, or empty" do
278
+ it "should set postfix to nil" do
279
+ [nil, false, ''].each do |value|
280
+ @statsd.postfix = 'a postfix'
281
+ @statsd.postfix = value
282
+ @statsd.postfix.must_equal nil
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ describe "with logging" do
289
+ require 'stringio'
290
+ before { Statsd.logger = Logger.new(@log = StringIO.new)}
291
+
292
+ it "should write to the log in debug" do
293
+ Statsd.logger.level = Logger::DEBUG
294
+
295
+ @statsd.increment('foobar')
296
+
297
+ @log.string.must_match "Statsd: foobar:1|c"
298
+ end
299
+
300
+ it "should not write to the log unless debug" do
301
+ Statsd.logger.level = Logger::INFO
302
+
303
+ @statsd.increment('foobar')
304
+
305
+ @log.string.must_be_empty
306
+ end
307
+ end
308
+
309
+ describe "stat names" do
310
+ it "should accept anything as stat" do
311
+ @statsd.increment(Object)
312
+ end
313
+
314
+ it "should replace ruby constant delimeter with graphite package name" do
315
+ class Statsd::SomeClass; end
316
+ @statsd.increment(Statsd::SomeClass)
317
+
318
+ @socket.recv.must_equal ['Statsd.SomeClass:1|c']
319
+ end
320
+
321
+ describe "custom delimiter" do
322
+ before do
323
+ @statsd.delimiter = "-"
324
+ end
325
+
326
+ it "should replace ruby constant delimiter with custom delimiter" do
327
+ class Statsd::SomeOtherClass; end
328
+ @statsd.increment(Statsd::SomeOtherClass)
329
+
330
+ @socket.recv.must_equal ['Statsd-SomeOtherClass:1|c']
331
+ end
332
+ end
333
+
334
+ it "should replace statsd reserved chars in the stat name" do
335
+ @statsd.increment('ray@hostname.blah|blah.blah:blah')
336
+ @socket.recv.must_equal ['ray_hostname.blah_blah.blah_blah:1|c']
337
+ end
338
+ end
339
+
340
+ describe "handling socket errors" do
341
+ before do
342
+ require 'stringio'
343
+ Statsd.logger = Logger.new(@log = StringIO.new)
344
+ @socket.instance_eval { def write(*) raise SocketError end }
345
+ end
346
+
347
+ it "should ignore socket errors" do
348
+ @statsd.increment('foobar').must_equal nil
349
+ end
350
+
351
+ it "should log socket errors" do
352
+ @statsd.increment('foobar')
353
+ @log.string.must_match 'Statsd: SocketError'
354
+ end
355
+ end
356
+
357
+ describe "batching" do
358
+ it "should have a default batch size of 10" do
359
+ @statsd.batch_size.must_equal 10
360
+ end
361
+
362
+ it "should have a modifiable batch size" do
363
+ @statsd.batch_size = 7
364
+ @statsd.batch_size.must_equal 7
365
+ @statsd.batch do |b|
366
+ b.batch_size.must_equal 7
367
+ end
368
+ end
369
+
370
+ it "should flush the batch at the batch size or at the end of the block" do
371
+ @statsd.batch do |b|
372
+ b.batch_size = 3
373
+
374
+ # The first three should flush, the next two will be flushed when the
375
+ # block is done.
376
+ 5.times { b.increment('foobar') }
377
+
378
+ @socket.recv.must_equal [(["foobar:1|c"] * 3).join("\n")]
379
+ end
380
+
381
+ @socket.recv.must_equal [(["foobar:1|c"] * 2).join("\n")]
382
+ end
383
+
384
+ it "should not flush to the socket if the backlog is empty" do
385
+ batch = Statsd::Batch.new(@statsd)
386
+ batch.flush
387
+ @socket.recv.must_be :nil?
388
+
389
+ batch.increment 'foobar'
390
+ batch.flush
391
+ @socket.recv.must_equal %w[foobar:1|c]
392
+ end
393
+
394
+ it "should support setting namespace for the underlying instance" do
395
+ batch = Statsd::Batch.new(@statsd)
396
+ batch.namespace = 'ns'
397
+ @statsd.namespace.must_equal 'ns'
398
+ end
399
+
400
+ it "should support setting host for the underlying instance" do
401
+ batch = Statsd::Batch.new(@statsd)
402
+ batch.host = '1.2.3.4'
403
+ @statsd.host.must_equal '1.2.3.4'
404
+ end
405
+
406
+ it "should support setting port for the underlying instance" do
407
+ batch = Statsd::Batch.new(@statsd)
408
+ batch.port = 42
409
+ @statsd.port.must_equal 42
410
+ end
411
+
412
+ end
413
+
414
+ describe "#connect" do
415
+ it "should reconnect" do
416
+ c = $connect_count
417
+ @statsd.connect
418
+ ($connect_count - c).must_equal 1
419
+ end
420
+ end
421
+
422
+ describe "tags" do
423
+ before { class << @statsd; def rand; 0; end; end } # ensure delivery
424
+
425
+ describe "with counters" do
426
+ it "accepts tags" do
427
+ @statsd.increment('foobar', { tags: { foo: 'bar' }})
428
+ @socket.recv.must_equal ['foobar#foo=bar:1|c']
429
+ end
430
+
431
+ it "accepts tags with sample rate" do
432
+ @statsd.increment('foobar', { sample_rate: 0.5, tags: { foo: 'bar' }})
433
+ @socket.recv.must_equal ['foobar#foo=bar:1|c|@0.5']
434
+ end
435
+ end
436
+
437
+ describe "with timers" do
438
+ it "accepts tags" do
439
+ @statsd.time('foobar', { tags: { foo: 'bar' }}) {}
440
+ @socket.recv.must_equal ['foobar#foo=bar:0|ms']
441
+ end
442
+
443
+ it "accepts tags with sample rate" do
444
+ @statsd.time('foobar', { sample_rate: 0.5, tags: { foo: 'bar' }}) {}
445
+ @socket.recv.must_equal ['foobar#foo=bar:0|ms|@0.5']
446
+ end
447
+ end
448
+
449
+ describe "with postfix" do
450
+ before { @statsd.postfix = 'foo' }
451
+
452
+ it "accepts tags" do
453
+ @statsd.increment('foobar', { tags: { foo: 'bar' }})
454
+ @socket.recv.must_equal ['foobar.foo#foo=bar:1|c']
455
+ end
456
+ end
457
+ end
458
+
459
+ end
460
+
461
+ describe Statsd do
462
+ describe "with a real UDP socket" do
463
+ it "should actually send stuff over the socket" do
464
+ family = Addrinfo.udp(UDPSocket.getaddress('localhost'), 0).afamily
465
+ begin
466
+ socket = UDPSocket.new family
467
+ host, port = 'localhost', 0
468
+ socket.bind(host, port)
469
+ port = socket.addr[1]
470
+
471
+ statsd = Statsd.new(host, port)
472
+ statsd.increment('foobar')
473
+ message = socket.recvfrom(16).first
474
+ message.must_equal 'foobar:1|c'
475
+ ensure
476
+ socket.close
477
+ end
478
+ end
479
+
480
+ it "should send stuff over an IPv4 socket" do
481
+ begin
482
+ socket = UDPSocket.new Socket::AF_INET
483
+ host, port = '127.0.0.1', 0
484
+ socket.bind(host, port)
485
+ port = socket.addr[1]
486
+
487
+ statsd = Statsd.new(host, port)
488
+ statsd.increment('foobar')
489
+ message = socket.recvfrom(16).first
490
+ message.must_equal 'foobar:1|c'
491
+ ensure
492
+ socket.close
493
+ end
494
+ end
495
+
496
+ it "should send stuff over an IPv6 socket" do
497
+ begin
498
+ socket = UDPSocket.new Socket::AF_INET6
499
+ host, port = '::1', 0
500
+ socket.bind(host, port)
501
+ port = socket.addr[1]
502
+
503
+ statsd = Statsd.new(host, port)
504
+ statsd.increment('foobar')
505
+ message = socket.recvfrom(16).first
506
+ message.must_equal 'foobar:1|c'
507
+ ensure
508
+ socket.close
509
+ end
510
+ end
511
+ end
512
+
513
+ describe "supports TCP sockets" do
514
+ it "should connect to and send stats over TCPv4" do
515
+ begin
516
+ host, port = '127.0.0.1', 0
517
+ server = TCPServer.new host, port
518
+ port = server.addr[1]
519
+
520
+ socket = nil
521
+ Thread.new { socket = server.accept }
522
+
523
+ statsd = Statsd.new(host, port, :tcp)
524
+ statsd.increment('foobar')
525
+
526
+ Timeout.timeout(5) do
527
+ Thread.pass while socket == nil
528
+ end
529
+
530
+ message = socket.recvfrom(16).first
531
+ message.must_equal 'foobar:1|c'
532
+ ensure
533
+ socket.close if socket
534
+ server.close
535
+ end
536
+ end
537
+
538
+ it "should connect to and send stats over TCPv6" do
539
+ begin
540
+ host, port = '::1', 0
541
+ server = TCPServer.new host, port
542
+ port = server.addr[1]
543
+
544
+ socket = nil
545
+ Thread.new { socket = server.accept }
546
+
547
+ statsd = Statsd.new(host, port, :tcp)
548
+ statsd.increment('foobar')
549
+
550
+ Timeout.timeout(5) do
551
+ Thread.pass while socket == nil
552
+ end
553
+
554
+ message = socket.recvfrom(16).first
555
+ message.must_equal 'foobar:1|c'
556
+ ensure
557
+ socket.close if socket
558
+ server.close
559
+ end
560
+ end
561
+ end
562
+ end