qubole-statsd-instrument 2.1.4

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +12 -0
  4. data/CHANGELOG.md +89 -0
  5. data/CONTRIBUTING.md +34 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +20 -0
  8. data/README.md +319 -0
  9. data/Rakefile +10 -0
  10. data/lib/statsd/instrument/assertions.rb +88 -0
  11. data/lib/statsd/instrument/backend.rb +17 -0
  12. data/lib/statsd/instrument/backends/capture_backend.rb +29 -0
  13. data/lib/statsd/instrument/backends/logger_backend.rb +20 -0
  14. data/lib/statsd/instrument/backends/null_backend.rb +7 -0
  15. data/lib/statsd/instrument/backends/udp_backend.rb +106 -0
  16. data/lib/statsd/instrument/environment.rb +54 -0
  17. data/lib/statsd/instrument/helpers.rb +14 -0
  18. data/lib/statsd/instrument/matchers.rb +96 -0
  19. data/lib/statsd/instrument/metric.rb +117 -0
  20. data/lib/statsd/instrument/metric_expectation.rb +67 -0
  21. data/lib/statsd/instrument/railtie.rb +14 -0
  22. data/lib/statsd/instrument/version.rb +5 -0
  23. data/lib/statsd/instrument.rb +407 -0
  24. data/lib/statsd-instrument.rb +1 -0
  25. data/shipit.rubygems.yml +1 -0
  26. data/statsd-instrument.gemspec +27 -0
  27. data/test/assertions_test.rb +329 -0
  28. data/test/benchmark/tags.rb +34 -0
  29. data/test/capture_backend_test.rb +24 -0
  30. data/test/environment_test.rb +46 -0
  31. data/test/helpers_test.rb +24 -0
  32. data/test/integration_test.rb +20 -0
  33. data/test/logger_backend_test.rb +20 -0
  34. data/test/matchers_test.rb +102 -0
  35. data/test/metric_test.rb +45 -0
  36. data/test/statsd_instrumentation_test.rb +328 -0
  37. data/test/statsd_test.rb +136 -0
  38. data/test/test_helper.rb +10 -0
  39. data/test/udp_backend_test.rb +167 -0
  40. metadata +182 -0
@@ -0,0 +1,328 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveMerchant; end
4
+ class ActiveMerchant::Base
5
+ def ssl_post(arg)
6
+ if arg
7
+ 'OK'
8
+ else
9
+ raise 'Not OK'
10
+ end
11
+ end
12
+
13
+ def post_with_block(&block)
14
+ yield if block_given?
15
+ end
16
+ end
17
+
18
+ class ActiveMerchant::Gateway < ActiveMerchant::Base
19
+ def purchase(arg)
20
+ ssl_post(arg)
21
+ true
22
+ rescue
23
+ false
24
+ end
25
+
26
+ def self.sync
27
+ true
28
+ end
29
+
30
+ def self.singleton_class
31
+ class << self; self; end
32
+ end
33
+ end
34
+
35
+ class ActiveMerchant::UniqueGateway < ActiveMerchant::Base
36
+ def ssl_post(arg)
37
+ {:success => arg}
38
+ end
39
+
40
+ def purchase(arg)
41
+ ssl_post(arg)
42
+ end
43
+ end
44
+
45
+ class GatewaySubClass < ActiveMerchant::Gateway
46
+ end
47
+
48
+ class InstrumentedClass
49
+ extend StatsD::Instrument
50
+
51
+ def public_and_instrumented
52
+ end
53
+ statsd_count :public_and_instrumented, 'InstrumentedClass.public_and_instrumented'
54
+
55
+ protected
56
+
57
+ def protected_and_instrumented
58
+ end
59
+ statsd_count :protected_and_instrumented, 'InstrumentedClass.protected_and_instrumented'
60
+
61
+ private
62
+
63
+ def private_and_instrumented
64
+ end
65
+ statsd_count :private_and_instrumented, 'InstrumentedClass.private_and_instrumented'
66
+ end
67
+
68
+ ActiveMerchant::Base.extend StatsD::Instrument
69
+
70
+ class StatsDInstrumentationTest < Minitest::Test
71
+ include StatsD::Instrument::Assertions
72
+
73
+ def test_statsd_count_if
74
+ ActiveMerchant::Gateway.statsd_count_if :ssl_post, 'ActiveMerchant.Gateway.if'
75
+
76
+ assert_statsd_increment('ActiveMerchant.Gateway.if') do
77
+ ActiveMerchant::Gateway.new.purchase(true)
78
+ ActiveMerchant::Gateway.new.purchase(false)
79
+ end
80
+ ensure
81
+ ActiveMerchant::Gateway.statsd_remove_count_if :ssl_post, 'ActiveMerchant.Gateway.if'
82
+ end
83
+
84
+ def test_statsd_count_if_with_method_receiving_block
85
+ ActiveMerchant::Base.statsd_count_if :post_with_block, 'ActiveMerchant.Base.post_with_block' do |result|
86
+ result == 'true'
87
+ end
88
+
89
+ assert_statsd_increment('ActiveMerchant.Base.post_with_block') do
90
+ assert_equal 'true', ActiveMerchant::Base.new.post_with_block { 'true' }
91
+ assert_equal 'false', ActiveMerchant::Base.new.post_with_block { 'false' }
92
+ end
93
+ ensure
94
+ ActiveMerchant::Base.statsd_remove_count_if :post_with_block, 'ActiveMerchant.Base.post_with_block'
95
+ end
96
+
97
+ def test_statsd_count_if_with_block
98
+ ActiveMerchant::UniqueGateway.statsd_count_if :ssl_post, 'ActiveMerchant.Gateway.block' do |result|
99
+ result[:success]
100
+ end
101
+
102
+ assert_statsd_increment('ActiveMerchant.Gateway.block', times: 1) do
103
+ ActiveMerchant::UniqueGateway.new.purchase(true)
104
+ ActiveMerchant::UniqueGateway.new.purchase(false)
105
+ end
106
+ ensure
107
+ ActiveMerchant::UniqueGateway.statsd_remove_count_if :ssl_post, 'ActiveMerchant.Gateway.block'
108
+ end
109
+
110
+ def test_statsd_count_success
111
+ ActiveMerchant::Gateway.statsd_count_success :ssl_post, 'ActiveMerchant.Gateway', 0.5
112
+
113
+ assert_statsd_increment('ActiveMerchant.Gateway.success', sample_rate: 0.5, times: 1) do
114
+ ActiveMerchant::Gateway.new.purchase(true)
115
+ ActiveMerchant::Gateway.new.purchase(false)
116
+ end
117
+
118
+ assert_statsd_increment('ActiveMerchant.Gateway.failure', sample_rate: 0.5, times: 1) do
119
+ ActiveMerchant::Gateway.new.purchase(false)
120
+ ActiveMerchant::Gateway.new.purchase(true)
121
+ end
122
+ ensure
123
+ ActiveMerchant::Gateway.statsd_remove_count_success :ssl_post, 'ActiveMerchant.Gateway'
124
+ end
125
+
126
+ def test_statsd_count_success_with_method_receiving_block
127
+ ActiveMerchant::Base.statsd_count_success :post_with_block, 'ActiveMerchant.Base.post_with_block' do |result|
128
+ result == 'successful'
129
+ end
130
+
131
+ assert_statsd_increment('ActiveMerchant.Base.post_with_block.success', times: 1) do
132
+ assert_equal 'successful', ActiveMerchant::Base.new.post_with_block { 'successful' }
133
+ assert_equal 'not so successful', ActiveMerchant::Base.new.post_with_block { 'not so successful' }
134
+ end
135
+
136
+ assert_statsd_increment('ActiveMerchant.Base.post_with_block.failure', times: 1) do
137
+ assert_equal 'successful', ActiveMerchant::Base.new.post_with_block { 'successful' }
138
+ assert_equal 'not so successful', ActiveMerchant::Base.new.post_with_block { 'not so successful' }
139
+ end
140
+ ensure
141
+ ActiveMerchant::Base.statsd_remove_count_success :post_with_block, 'ActiveMerchant.Base.post_with_block'
142
+ end
143
+
144
+ def test_statsd_count_success_with_block
145
+ ActiveMerchant::UniqueGateway.statsd_count_success :ssl_post, 'ActiveMerchant.Gateway' do |result|
146
+ result[:success]
147
+ end
148
+
149
+ assert_statsd_increment('ActiveMerchant.Gateway.success') do
150
+ ActiveMerchant::UniqueGateway.new.purchase(true)
151
+ end
152
+
153
+ assert_statsd_increment('ActiveMerchant.Gateway.failure') do
154
+ ActiveMerchant::UniqueGateway.new.purchase(false)
155
+ end
156
+ ensure
157
+ ActiveMerchant::UniqueGateway.statsd_remove_count_success :ssl_post, 'ActiveMerchant.Gateway'
158
+ end
159
+
160
+ def test_statsd_count
161
+ ActiveMerchant::Gateway.statsd_count :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
162
+
163
+ assert_statsd_increment('ActiveMerchant.Gateway.ssl_post') do
164
+ ActiveMerchant::Gateway.new.purchase(true)
165
+ end
166
+ ensure
167
+ ActiveMerchant::Gateway.statsd_remove_count :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
168
+ end
169
+
170
+ def test_statsd_count_with_name_as_lambda
171
+ metric_namer = lambda { |object, args| object.class.to_s.downcase + ".insert." + args.first.to_s }
172
+ ActiveMerchant::Gateway.statsd_count(:ssl_post, metric_namer)
173
+
174
+ assert_statsd_increment('gatewaysubclass.insert.true') do
175
+ GatewaySubClass.new.purchase(true)
176
+ end
177
+ ensure
178
+ ActiveMerchant::Gateway.statsd_remove_count(:ssl_post, metric_namer)
179
+ end
180
+
181
+ def test_statsd_count_with_method_receiving_block
182
+ ActiveMerchant::Base.statsd_count :post_with_block, 'ActiveMerchant.Base.post_with_block'
183
+
184
+ assert_statsd_increment('ActiveMerchant.Base.post_with_block') do
185
+ assert_equal 'block called', ActiveMerchant::Base.new.post_with_block { 'block called' }
186
+ end
187
+ ensure
188
+ ActiveMerchant::Base.statsd_remove_count :post_with_block, 'ActiveMerchant.Base.post_with_block'
189
+ end
190
+
191
+ def test_statsd_measure
192
+ ActiveMerchant::UniqueGateway.statsd_measure :ssl_post, 'ActiveMerchant.Gateway.ssl_post', sample_rate: 0.3
193
+
194
+ assert_statsd_measure('ActiveMerchant.Gateway.ssl_post', sample_rate: 0.3) do
195
+ ActiveMerchant::UniqueGateway.new.purchase(true)
196
+ end
197
+ ensure
198
+ ActiveMerchant::UniqueGateway.statsd_remove_measure :ssl_post, 'ActiveMerchant.Gateway.ssl_post'
199
+ end
200
+
201
+ def test_statsd_measure_uses_normalized_metric_name
202
+ ActiveMerchant::UniqueGateway.statsd_measure :ssl_post, 'ActiveMerchant::Gateway.ssl_post'
203
+
204
+ assert_statsd_measure('ActiveMerchant.Gateway.ssl_post') do
205
+ ActiveMerchant::UniqueGateway.new.purchase(true)
206
+ end
207
+ ensure
208
+ ActiveMerchant::UniqueGateway.statsd_remove_measure :ssl_post, 'ActiveMerchant::Gateway.ssl_post'
209
+ end
210
+
211
+ def test_statsd_measure_yells_without_block
212
+ err = assert_raises(ArgumentError) do
213
+ assert_statsd_measure('ActiveMerchant.Gateway.ssl_post')
214
+ end
215
+ assert_equal "block must be given", err.to_s
216
+ end
217
+
218
+ def test_statsd_measure_with_method_receiving_block
219
+ ActiveMerchant::Base.statsd_measure :post_with_block, 'ActiveMerchant.Base.post_with_block'
220
+
221
+ assert_statsd_measure('ActiveMerchant.Base.post_with_block') do
222
+ assert_equal 'block called', ActiveMerchant::Base.new.post_with_block { 'block called' }
223
+ end
224
+ ensure
225
+ ActiveMerchant::Base.statsd_remove_measure :post_with_block, 'ActiveMerchant.Base.post_with_block'
226
+ end
227
+
228
+ def test_instrumenting_class_method
229
+ ActiveMerchant::Gateway.singleton_class.extend StatsD::Instrument
230
+ ActiveMerchant::Gateway.singleton_class.statsd_count :sync, 'ActiveMerchant.Gateway.sync'
231
+
232
+ assert_statsd_increment('ActiveMerchant.Gateway.sync') do
233
+ ActiveMerchant::Gateway.sync
234
+ end
235
+ ensure
236
+ ActiveMerchant::Gateway.singleton_class.statsd_remove_count :sync, 'ActiveMerchant.Gateway.sync'
237
+ end
238
+
239
+ def test_statsd_count_with_tags
240
+ ActiveMerchant::Gateway.singleton_class.extend StatsD::Instrument
241
+ ActiveMerchant::Gateway.singleton_class.statsd_count :sync, 'ActiveMerchant.Gateway.sync', tags: { key: 'value' }
242
+
243
+ assert_statsd_increment('ActiveMerchant.Gateway.sync', tags: ['key:value']) do
244
+ ActiveMerchant::Gateway.sync
245
+ end
246
+ ensure
247
+ ActiveMerchant::Gateway.singleton_class.statsd_remove_count :sync, 'ActiveMerchant.Gateway.sync'
248
+ end
249
+
250
+ def test_statsd_doesnt_change_method_scope_of_public_method
251
+ assert_scope InstrumentedClass, :public_and_instrumented, :public
252
+
253
+ assert_statsd_increment('InstrumentedClass.public_and_instrumented') do
254
+ InstrumentedClass.new.send(:public_and_instrumented)
255
+ end
256
+ end
257
+
258
+ def test_statsd_doesnt_change_method_scope_of_protected_method
259
+ assert_scope InstrumentedClass, :protected_and_instrumented, :protected
260
+
261
+ assert_statsd_increment('InstrumentedClass.protected_and_instrumented') do
262
+ InstrumentedClass.new.send(:protected_and_instrumented)
263
+ end
264
+ end
265
+
266
+ def test_statsd_doesnt_change_method_scope_of_private_method
267
+ assert_scope InstrumentedClass, :private_and_instrumented, :private
268
+
269
+ assert_statsd_increment('InstrumentedClass.private_and_instrumented') do
270
+ InstrumentedClass.new.send(:private_and_instrumented)
271
+ end
272
+ end
273
+
274
+ def test_statsd_doesnt_change_method_scope_on_removal_of_public_method
275
+ assert_scope InstrumentedClass, :public_and_instrumented, :public
276
+ InstrumentedClass.statsd_remove_count :public_and_instrumented, 'InstrumentedClass.public_and_instrumented'
277
+ assert_scope InstrumentedClass, :public_and_instrumented, :public
278
+
279
+ InstrumentedClass.statsd_count :public_and_instrumented, 'InstrumentedClass.public_and_instrumented'
280
+ end
281
+
282
+ def test_statsd_doesnt_change_method_scope_on_removal_of_protected_method
283
+ assert_scope InstrumentedClass, :protected_and_instrumented, :protected
284
+ InstrumentedClass.statsd_remove_count :protected_and_instrumented, 'InstrumentedClass.protected_and_instrumented'
285
+ assert_scope InstrumentedClass, :protected_and_instrumented, :protected
286
+
287
+ InstrumentedClass.statsd_count :protected_and_instrumented, 'InstrumentedClass.protected_and_instrumented'
288
+ end
289
+
290
+ def test_statsd_doesnt_change_method_scope_on_removal_of_private_method
291
+ assert_scope InstrumentedClass, :private_and_instrumented, :private
292
+ InstrumentedClass.statsd_remove_count :private_and_instrumented, 'InstrumentedClass.private_and_instrumented'
293
+ assert_scope InstrumentedClass, :private_and_instrumented, :private
294
+
295
+ InstrumentedClass.statsd_count :private_and_instrumented, 'InstrumentedClass.private_and_instrumented'
296
+ end
297
+
298
+ def test_statsd_works_with_prepended_modules
299
+ mod = Module.new do
300
+ define_method(:foo) { super() }
301
+ end
302
+ klass = Class.new do
303
+ prepend mod
304
+ extend StatsD::Instrument
305
+ define_method(:foo) {}
306
+ statsd_count :foo, "foo"
307
+ end
308
+
309
+ assert_statsd_increment("foo") do
310
+ klass.new.foo
311
+ end
312
+ end
313
+
314
+ private
315
+
316
+ def assert_scope(klass, method, expected_scope)
317
+ method_scope = case
318
+ when klass.private_method_defined?(method)
319
+ :private
320
+ when klass.protected_method_defined?(method)
321
+ :protected
322
+ else
323
+ :public
324
+ end
325
+
326
+ assert_equal method_scope, expected_scope, "Expected method to be #{expected_scope}"
327
+ end
328
+ end
@@ -0,0 +1,136 @@
1
+ require 'test_helper'
2
+
3
+ class StatsDTest < Minitest::Test
4
+ include StatsD::Instrument::Assertions
5
+
6
+ def test_statsd_passed_collections_to_backend
7
+ StatsD.backend.expects(:collect_metric).with(instance_of(StatsD::Instrument::Metric))
8
+ StatsD.increment('test')
9
+ end
10
+
11
+ def test_statsd_measure_with_explicit_value
12
+ result = nil
13
+ metric = capture_statsd_call { result = StatsD.measure('values.foobar', 42) }
14
+ assert_equal metric, result
15
+ assert_equal 'values.foobar', metric.name
16
+ assert_equal 42, metric.value
17
+ assert_equal :ms, metric.type
18
+ end
19
+
20
+ def test_statsd_measure_with_explicit_value_as_keyword_argument
21
+ result = nil
22
+ metric = capture_statsd_call { result = StatsD.measure('values.foobar', value: 42) }
23
+ assert_equal metric, result
24
+ assert_equal 'values.foobar', metric.name
25
+ assert_equal 42, metric.value
26
+ assert_equal :ms, metric.type
27
+ end
28
+
29
+ def test_statsd_measure_without_value_or_block
30
+ assert_raises(ArgumentError) { StatsD.measure('values.foobar', tags: 123) }
31
+ end
32
+
33
+ def test_statsd_measure_with_explicit_value_and_sample_rate
34
+ metric = capture_statsd_call { StatsD.measure('values.foobar', 42, :sample_rate => 0.1) }
35
+ assert_equal 0.1, metric.sample_rate
36
+ end
37
+
38
+ def test_statsd_measure_with_benchmarked_block_duration
39
+ StatsD::Instrument.stubs(:duration).returns(1.12)
40
+ metric = capture_statsd_call do
41
+ StatsD.measure('values.foobar') { 'foo' }
42
+ end
43
+ assert_equal 1120.0, metric.value
44
+ end
45
+
46
+ def test_statsd_measure_returns_return_value_of_block
47
+ return_value = StatsD.measure('values.foobar') { 'sarah' }
48
+ assert_equal 'sarah', return_value
49
+ end
50
+
51
+ def test_statsd_increment
52
+ result = nil
53
+ metric = capture_statsd_call { result = StatsD.increment('values.foobar', 3) }
54
+ assert_equal metric, result
55
+ assert_equal :c, metric.type
56
+ assert_equal 'values.foobar', metric.name
57
+ assert_equal 3, metric.value
58
+ end
59
+
60
+ def test_statsd_increment_with_hash_argument
61
+ metric = capture_statsd_call { StatsD.increment('values.foobar', :tags => ['test']) }
62
+ assert_equal StatsD.default_sample_rate, metric.sample_rate
63
+ assert_equal ['test'], metric.tags
64
+ assert_equal 1, metric.value
65
+ end
66
+
67
+ def test_statsd_increment_with_value_as_keyword_argument
68
+ metric = capture_statsd_call { StatsD.increment('values.foobar', :value => 2) }
69
+ assert_equal StatsD.default_sample_rate, metric.sample_rate
70
+ assert_equal 2, metric.value
71
+ end
72
+
73
+ def test_statsd_increment_with_multiple_arguments
74
+ metric = capture_statsd_call { StatsD.increment('values.foobar', 12, nil, ['test']) }
75
+ assert_equal StatsD.default_sample_rate, metric.sample_rate
76
+ assert_equal ['test'], metric.tags
77
+ assert_equal 12, metric.value
78
+ end
79
+
80
+ def test_statsd_gauge
81
+ result = nil
82
+ metric = capture_statsd_call { result = StatsD.gauge('values.foobar', 12) }
83
+ assert_equal metric, result
84
+ assert_equal :g, metric.type
85
+ assert_equal 'values.foobar', metric.name
86
+ assert_equal 12, metric.value
87
+ end
88
+
89
+ def test_statsd_gauge_with_keyword_argument
90
+ result = nil
91
+ metric = capture_statsd_call { result = StatsD.gauge('values.foobar', value: 13) }
92
+ assert_equal metric, result
93
+ assert_equal :g, metric.type
94
+ assert_equal 'values.foobar', metric.name
95
+ assert_equal 13, metric.value
96
+ end
97
+
98
+ def test_statsd_gauge_without_value
99
+ assert_raises(ArgumentError) { StatsD.gauge('values.foobar', tags: 123) }
100
+ end
101
+
102
+ def test_statsd_set
103
+ result = nil
104
+ metric = capture_statsd_call { result = StatsD.set('values.foobar', 'unique_identifier') }
105
+ assert_equal metric, result
106
+ assert_equal :s, metric.type
107
+ assert_equal 'values.foobar', metric.name
108
+ assert_equal 'unique_identifier', metric.value
109
+ end
110
+
111
+ def test_statsd_histogram
112
+ result = nil
113
+ metric = capture_statsd_call { result = StatsD.histogram('values.foobar', 42) }
114
+ assert_equal metric, result
115
+ assert_equal :h, metric.type
116
+ assert_equal 'values.foobar', metric.name
117
+ assert_equal 42, metric.value
118
+ end
119
+
120
+ def test_statsd_key_value
121
+ result = nil
122
+ metric = capture_statsd_call { result = StatsD.key_value('values.foobar', 42) }
123
+ assert_equal metric, result
124
+ assert_equal :kv, metric.type
125
+ assert_equal 'values.foobar', metric.name
126
+ assert_equal 42, metric.value
127
+ end
128
+
129
+ protected
130
+
131
+ def capture_statsd_call(&block)
132
+ metrics = capture_statsd_calls(&block)
133
+ assert_equal 1, metrics.length
134
+ metrics.first
135
+ end
136
+ end
@@ -0,0 +1,10 @@
1
+ ENV['ENV'] = 'test'
2
+
3
+ require 'minitest/autorun'
4
+ require 'minitest/pride'
5
+ require 'mocha/setup'
6
+ require 'set'
7
+ require 'logger'
8
+ require 'statsd-instrument'
9
+
10
+ StatsD.logger = Logger.new('/dev/null')
@@ -0,0 +1,167 @@
1
+ require 'test_helper'
2
+
3
+ class UDPBackendTest < Minitest::Test
4
+ def setup
5
+ StatsD.stubs(:backend).returns(@backend = StatsD::Instrument::Backends::UDPBackend.new)
6
+ @backend.stubs(:rand).returns(0.0)
7
+
8
+ UDPSocket.stubs(:new).returns(@socket = mock('socket'))
9
+ @socket.stubs(:connect)
10
+ @socket.stubs(:send).returns(1)
11
+
12
+ StatsD.stubs(:logger).returns(@logger = mock('logger'))
13
+ end
14
+
15
+ def test_changing_host_or_port_should_create_new_socket
16
+ @socket.expects(:connect).with('localhost', 1234).once
17
+ @socket.expects(:connect).with('localhost', 2345).once
18
+ @socket.expects(:connect).with('127.0.0.1', 2345).once
19
+
20
+ @backend.server = "localhost:1234"
21
+ @backend.socket
22
+
23
+ @backend.port = 2345
24
+ @backend.socket
25
+
26
+ @backend.host = '127.0.0.1'
27
+ @backend.socket
28
+ end
29
+
30
+ def test_collect_respects_sampling_rate
31
+ @socket.expects(:send).once.returns(1)
32
+ metric = StatsD::Instrument::Metric.new(type: :c, name: 'test', sample_rate: 0.5)
33
+
34
+ @backend.stubs(:rand).returns(0.4)
35
+ @backend.collect_metric(metric)
36
+
37
+ @backend.stubs(:rand).returns(0.6)
38
+ @backend.collect_metric(metric)
39
+ end
40
+
41
+ def test_support_counter_syntax
42
+ @backend.expects(:write_packet).with('counter:1|c').once
43
+ StatsD.increment('counter', sample_rate: 1.0)
44
+
45
+ @backend.expects(:write_packet).with('counter:1|c|@0.5').once
46
+ StatsD.increment('counter', sample_rate: 0.5)
47
+ end
48
+
49
+ def test_supports_gauge_syntax
50
+ @backend.expects(:write_packet).with('fooy:1.23|g')
51
+ StatsD.gauge('fooy', 1.23)
52
+
53
+ @backend.expects(:write_packet).with('fooy:42|g|@0.01')
54
+ StatsD.gauge('fooy', 42, sample_rate: 0.01)
55
+ end
56
+
57
+ def test_supports_set_syntax
58
+ @backend.expects(:write_packet).with('unique:10.0.0.10|s')
59
+ StatsD.set('unique', '10.0.0.10')
60
+
61
+ @backend.expects(:write_packet).with('unique:10.0.0.10|s|@0.01')
62
+ StatsD.set('unique', '10.0.0.10', sample_rate: 0.01)
63
+ end
64
+
65
+ def test_support_measure_syntax
66
+ @backend.expects(:write_packet).with('duration:1.23|ms')
67
+ StatsD.measure('duration', 1.23)
68
+
69
+ @backend.expects(:write_packet).with('duration:0.42|ms|@0.01')
70
+ StatsD.measure('duration', 0.42, sample_rate: 0.01)
71
+ end
72
+
73
+ def test_histogram_syntax_on_datadog
74
+ @backend.implementation = :datadog
75
+ @backend.expects(:write_packet).with('fooh:42.4|h')
76
+ StatsD.histogram('fooh', 42.4)
77
+ end
78
+
79
+ def test_histogram_warns_if_not_using_datadog
80
+ @backend.implementation = :other
81
+ @backend.expects(:write_packet).never
82
+ @logger.expects(:warn)
83
+ StatsD.histogram('fooh', 42.4)
84
+ end
85
+
86
+ def test_supports_key_value_syntax_on_statsite
87
+ @backend.implementation = :statsite
88
+ @backend.expects(:write_packet).with("fooy:42|kv\n")
89
+ StatsD.key_value('fooy', 42)
90
+ end
91
+
92
+ def test_supports_key_value_with_timestamp_on_statsite
93
+ @backend.implementation = :statsite
94
+ @backend.expects(:write_packet).with("fooy:42|kv|@123456\n")
95
+ StatsD.key_value('fooy', 42, 123456)
96
+ end
97
+
98
+ def test_warn_when_using_key_value_and_not_on_statsite
99
+ @backend.implementation = :other
100
+ @backend.expects(:write_packet).never
101
+ @logger.expects(:warn)
102
+ StatsD.key_value('fookv', 3.33)
103
+ end
104
+
105
+ def test_support_tags_syntax_on_datadog
106
+ @backend.implementation = :datadog
107
+ @backend.expects(:write_packet).with("fooc:3|c|#topic:foo,bar")
108
+ StatsD.increment('fooc', 3, tags: ['topic:foo', 'bar'])
109
+ end
110
+
111
+ def test_support_tags_syntax_on_collectd
112
+ @backend.implementation = :collectd
113
+ @backend.expects(:write_packet).with("[topic=foo,bar]fooc:3|g")
114
+ StatsD.gauge('fooc', 3, tags: ['topic:foo','bar'])
115
+ end
116
+
117
+ def test_warn_when_using_tags_and_not_on_datadog
118
+ @backend.implementation = :other
119
+ @backend.expects(:write_packet).with("fooc:1|c")
120
+ @logger.expects(:warn)
121
+ StatsD.increment('fooc', tags: ['ignored'])
122
+ end
123
+
124
+ def test_socket_error_should_not_raise_but_log
125
+ @socket.stubs(:connect).raises(SocketError)
126
+ @logger.expects(:error)
127
+ StatsD.increment('fail')
128
+ end
129
+
130
+ def test_system_call_error_should_not_raise_but_log
131
+ @socket.stubs(:send).raises(Errno::ETIMEDOUT)
132
+ @logger.expects(:error)
133
+ StatsD.increment('fail')
134
+ end
135
+
136
+ def test_io_error_should_not_raise_but_log
137
+ @socket.stubs(:send).raises(IOError)
138
+ @logger.expects(:error)
139
+ StatsD.increment('fail')
140
+ end
141
+
142
+ def test_synchronize_in_exit_handler_handles_thread_error_and_exits_cleanly
143
+ pid = fork do
144
+ Signal.trap('TERM') do
145
+ $sent_packet = false
146
+
147
+ class << @backend.socket
148
+ def send(command, *args)
149
+ $sent_packet = true if command == 'exiting:1|c'
150
+ command.length
151
+ end
152
+ end
153
+
154
+ StatsD.increment('exiting')
155
+ Process.exit!($sent_packet)
156
+ end
157
+
158
+ sleep 100
159
+ end
160
+
161
+ Process.kill('TERM', pid)
162
+ Process.waitpid(pid)
163
+
164
+ assert $?.success?, 'socket did not write on exit'
165
+ end
166
+
167
+ end