statsd-ruby-tcp 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ class Statsd
2
+ # = MonotonicTime: a helper for getting monotonic time
3
+ #
4
+ # @example
5
+ # MonotonicTime.time_in_ms #=> 287138801.144576
6
+
7
+ # MonotonicTime guarantees that the time is strictly linearly
8
+ # increasing (unlike realtime).
9
+ # @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
10
+ module MonotonicTime
11
+ class << self
12
+ # @return [Integer] current monotonic time in milliseconds
13
+ def time_in_ms
14
+ time_in_nanoseconds / (10.0 ** 6)
15
+ end
16
+
17
+ private
18
+
19
+ if defined?(Process::CLOCK_MONOTONIC)
20
+ def time_in_nanoseconds
21
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
22
+ end
23
+ elsif RUBY_ENGINE == 'jruby'
24
+ def time_in_nanoseconds
25
+ java.lang.System.nanoTime
26
+ end
27
+ else
28
+ def time_in_nanoseconds
29
+ t = Time.now
30
+ t.to_i * (10 ** 9) + t.nsec
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ require 'minitest/autorun'
7
+ require 'statsd'
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,593 @@
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', 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', 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, 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, 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, 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', 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, 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, 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
+ assert_nil @statsd.timing('foobar', 500, 0.5)
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, 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
+ assert_nil @statsd.postfix
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, 1)
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, 1)
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, 1)
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', 1)
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
+ assert_nil @statsd.increment('foobar')
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 default batch byte size of nil" do
363
+ assert_nil @statsd.batch_byte_size
364
+ end
365
+
366
+ it "should have a default flush interval of nil" do
367
+ assert_nil @statsd.flush_interval
368
+ end
369
+
370
+ it "should have a modifiable batch size" do
371
+ @statsd.batch_size = 7
372
+ @statsd.batch_size.must_equal 7
373
+ @statsd.batch do |b|
374
+ b.batch_size.must_equal 7
375
+ end
376
+
377
+ @statsd.batch_size = nil
378
+ @statsd.batch_byte_size = 1472
379
+ @statsd.batch do |b|
380
+ assert_nil b.batch_size
381
+ b.batch_byte_size.must_equal 1472
382
+ end
383
+
384
+ end
385
+
386
+ it 'should have a modifiable flush interval' do
387
+ @statsd.flush_interval = 1
388
+ @statsd.flush_interval.must_equal 1
389
+ @statsd.batch do |b|
390
+ b.flush_interval.must_equal 1
391
+ end
392
+ end
393
+
394
+ it "should flush the batch at the batch size or at the end of the block" do
395
+ @statsd.batch do |b|
396
+ b.batch_size = 3
397
+
398
+ # The first three should flush, the next two will be flushed when the
399
+ # block is done.
400
+ 5.times { b.increment('foobar') }
401
+
402
+ @socket.recv.must_equal [(["foobar:1|c"] * 3).join("\n")]
403
+ end
404
+
405
+ @socket.recv.must_equal [(["foobar:1|c"] * 2).join("\n")]
406
+ end
407
+
408
+ it "should flush based on batch byte size" do
409
+ @statsd.batch do |b|
410
+ b.batch_size = nil
411
+ b.batch_byte_size = 22
412
+
413
+ # The first two should flush, the last will be flushed when the
414
+ # block is done.
415
+ 3.times { b.increment('foobar') }
416
+
417
+ @socket.recv.must_equal [(["foobar:1|c"] * 2).join("\n")]
418
+ end
419
+
420
+ @socket.recv.must_equal ["foobar:1|c"]
421
+ end
422
+
423
+ it "should flush immediately when the queue is exactly a batch size" do
424
+ @statsd.batch do |b|
425
+ b.batch_size = nil
426
+ b.batch_byte_size = 21
427
+
428
+ # The first two should flush together
429
+ 2.times { b.increment('foobar') }
430
+
431
+ @socket.recv.must_equal [(["foobar:1|c"] * 2).join("\n")]
432
+ end
433
+ end
434
+
435
+ it "should flush when the interval has passed" do
436
+ @statsd.batch do |b|
437
+ b.batch_size = nil
438
+ b.flush_interval = 0.01
439
+
440
+ # The first two should flush, the last will be flushed when the
441
+ # block is done.
442
+ 2.times { b.increment('foobar') }
443
+ sleep(0.03)
444
+ b.increment('foobar')
445
+
446
+ @socket.recv.must_equal [(["foobar:1|c"] * 2).join("\n")]
447
+ end
448
+
449
+ @socket.recv.must_equal ["foobar:1|c"]
450
+ end
451
+
452
+ it "should not flush to the socket if the backlog is empty" do
453
+ batch = Statsd::Batch.new(@statsd)
454
+ batch.flush
455
+ @socket.recv.must_be :nil?
456
+
457
+ batch.increment 'foobar'
458
+ batch.flush
459
+ @socket.recv.must_equal %w[foobar:1|c]
460
+ end
461
+
462
+ it "should support setting namespace for the underlying instance" do
463
+ batch = Statsd::Batch.new(@statsd)
464
+ batch.namespace = 'ns'
465
+ @statsd.namespace.must_equal 'ns'
466
+ end
467
+
468
+ it "should support setting host for the underlying instance" do
469
+ batch = Statsd::Batch.new(@statsd)
470
+ batch.host = '1.2.3.4'
471
+ @statsd.host.must_equal '1.2.3.4'
472
+ end
473
+
474
+ it "should support setting port for the underlying instance" do
475
+ batch = Statsd::Batch.new(@statsd)
476
+ batch.port = 42
477
+ @statsd.port.must_equal 42
478
+ end
479
+
480
+ end
481
+
482
+ describe "#connect" do
483
+ it "should reconnect" do
484
+ c = $connect_count
485
+ @statsd.connect
486
+ ($connect_count - c).must_equal 1
487
+ end
488
+ end
489
+
490
+ end
491
+
492
+ describe Statsd do
493
+ describe "with a real UDP socket" do
494
+ it "should actually send stuff over the socket" do
495
+ family = Addrinfo.udp(UDPSocket.getaddress('localhost'), 0).afamily
496
+ begin
497
+ socket = UDPSocket.new family
498
+ host, port = 'localhost', 0
499
+ socket.bind(host, port)
500
+ port = socket.addr[1]
501
+
502
+ statsd = Statsd.new(host, port)
503
+ statsd.increment('foobar')
504
+ message = socket.recvfrom(16).first
505
+ message.must_equal 'foobar:1|c'
506
+ ensure
507
+ socket.close
508
+ end
509
+ end
510
+
511
+ it "should send stuff over an IPv4 socket" do
512
+ begin
513
+ socket = UDPSocket.new Socket::AF_INET
514
+ host, port = '127.0.0.1', 0
515
+ socket.bind(host, port)
516
+ port = socket.addr[1]
517
+
518
+ statsd = Statsd.new(host, port)
519
+ statsd.increment('foobar')
520
+ message = socket.recvfrom(16).first
521
+ message.must_equal 'foobar:1|c'
522
+ ensure
523
+ socket.close
524
+ end
525
+ end
526
+
527
+ it "should send stuff over an IPv6 socket" do
528
+ begin
529
+ socket = UDPSocket.new Socket::AF_INET6
530
+ host, port = '::1', 0
531
+ socket.bind(host, port)
532
+ port = socket.addr[1]
533
+
534
+ statsd = Statsd.new(host, port)
535
+ statsd.increment('foobar')
536
+ message = socket.recvfrom(16).first
537
+ message.must_equal 'foobar:1|c'
538
+ ensure
539
+ socket.close
540
+ end
541
+ end
542
+ end
543
+
544
+ describe "supports TCP sockets" do
545
+ it "should connect to and send stats over TCPv4" do
546
+ begin
547
+ host, port = '127.0.0.1', 0
548
+ server = TCPServer.new host, port
549
+ port = server.addr[1]
550
+
551
+ socket = nil
552
+ Thread.new { socket = server.accept }
553
+
554
+ statsd = Statsd.new(host, port, :tcp)
555
+ statsd.increment('foobar')
556
+
557
+ Timeout.timeout(5) do
558
+ Thread.pass while socket == nil
559
+ end
560
+
561
+ message = socket.recvfrom(16).first
562
+ message.must_equal "foobar:1|c\n"
563
+ ensure
564
+ socket.close if socket
565
+ server.close
566
+ end
567
+ end
568
+
569
+ it "should connect to and send stats over TCPv6" do
570
+ begin
571
+ host, port = '::1', 0
572
+ server = TCPServer.new host, port
573
+ port = server.addr[1]
574
+
575
+ socket = nil
576
+ Thread.new { socket = server.accept }
577
+
578
+ statsd = Statsd.new(host, port, :tcp)
579
+ statsd.increment('foobar')
580
+
581
+ Timeout.timeout(5) do
582
+ Thread.pass while socket == nil
583
+ end
584
+
585
+ message = socket.recvfrom(16).first
586
+ message.must_equal "foobar:1|c\n"
587
+ ensure
588
+ socket.close if socket
589
+ server.close
590
+ end
591
+ end
592
+ end
593
+ end