qubole-statsd-instrument 2.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +89 -0
- data/CONTRIBUTING.md +34 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +319 -0
- data/Rakefile +10 -0
- data/lib/statsd/instrument/assertions.rb +88 -0
- data/lib/statsd/instrument/backend.rb +17 -0
- data/lib/statsd/instrument/backends/capture_backend.rb +29 -0
- data/lib/statsd/instrument/backends/logger_backend.rb +20 -0
- data/lib/statsd/instrument/backends/null_backend.rb +7 -0
- data/lib/statsd/instrument/backends/udp_backend.rb +106 -0
- data/lib/statsd/instrument/environment.rb +54 -0
- data/lib/statsd/instrument/helpers.rb +14 -0
- data/lib/statsd/instrument/matchers.rb +96 -0
- data/lib/statsd/instrument/metric.rb +117 -0
- data/lib/statsd/instrument/metric_expectation.rb +67 -0
- data/lib/statsd/instrument/railtie.rb +14 -0
- data/lib/statsd/instrument/version.rb +5 -0
- data/lib/statsd/instrument.rb +407 -0
- data/lib/statsd-instrument.rb +1 -0
- data/shipit.rubygems.yml +1 -0
- data/statsd-instrument.gemspec +27 -0
- data/test/assertions_test.rb +329 -0
- data/test/benchmark/tags.rb +34 -0
- data/test/capture_backend_test.rb +24 -0
- data/test/environment_test.rb +46 -0
- data/test/helpers_test.rb +24 -0
- data/test/integration_test.rb +20 -0
- data/test/logger_backend_test.rb +20 -0
- data/test/matchers_test.rb +102 -0
- data/test/metric_test.rb +45 -0
- data/test/statsd_instrumentation_test.rb +328 -0
- data/test/statsd_test.rb +136 -0
- data/test/test_helper.rb +10 -0
- data/test/udp_backend_test.rb +167 -0
- 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
|
data/test/statsd_test.rb
ADDED
@@ -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
|
data/test/test_helper.rb
ADDED
@@ -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
|