statsd-instrument 2.3.2 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/workflows/benchmark.yml +32 -0
  4. data/.github/workflows/ci.yml +47 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml +1027 -0
  7. data/.rubocop.yml +50 -0
  8. data/.yardopts +5 -0
  9. data/CHANGELOG.md +288 -2
  10. data/CONTRIBUTING.md +28 -6
  11. data/Gemfile +5 -0
  12. data/README.md +54 -46
  13. data/Rakefile +4 -2
  14. data/benchmark/README.md +29 -0
  15. data/benchmark/datagram-client +41 -0
  16. data/benchmark/send-metrics-to-dev-null-log +47 -0
  17. data/benchmark/send-metrics-to-local-udp-receiver +57 -0
  18. data/lib/statsd/instrument/assertions.rb +179 -30
  19. data/lib/statsd/instrument/backend.rb +3 -2
  20. data/lib/statsd/instrument/backends/capture_backend.rb +4 -1
  21. data/lib/statsd/instrument/backends/logger_backend.rb +3 -3
  22. data/lib/statsd/instrument/backends/null_backend.rb +2 -0
  23. data/lib/statsd/instrument/backends/udp_backend.rb +39 -45
  24. data/lib/statsd/instrument/capture_sink.rb +27 -0
  25. data/lib/statsd/instrument/client.rb +313 -0
  26. data/lib/statsd/instrument/datagram.rb +75 -0
  27. data/lib/statsd/instrument/datagram_builder.rb +101 -0
  28. data/lib/statsd/instrument/dogstatsd_datagram_builder.rb +71 -0
  29. data/lib/statsd/instrument/environment.rb +108 -29
  30. data/lib/statsd/instrument/helpers.rb +16 -8
  31. data/lib/statsd/instrument/log_sink.rb +24 -0
  32. data/lib/statsd/instrument/matchers.rb +14 -11
  33. data/lib/statsd/instrument/metric.rb +72 -45
  34. data/lib/statsd/instrument/metric_expectation.rb +32 -18
  35. data/lib/statsd/instrument/null_sink.rb +13 -0
  36. data/lib/statsd/instrument/railtie.rb +2 -1
  37. data/lib/statsd/instrument/rubocop/measure_as_dist_argument.rb +39 -0
  38. data/lib/statsd/instrument/rubocop/metaprogramming_positional_arguments.rb +42 -0
  39. data/lib/statsd/instrument/rubocop/metric_prefix_argument.rb +37 -0
  40. data/lib/statsd/instrument/rubocop/metric_return_value.rb +32 -0
  41. data/lib/statsd/instrument/rubocop/metric_value_keyword_argument.rb +36 -0
  42. data/lib/statsd/instrument/rubocop/positional_arguments.rb +99 -0
  43. data/lib/statsd/instrument/rubocop/splat_arguments.rb +31 -0
  44. data/lib/statsd/instrument/rubocop.rb +64 -0
  45. data/lib/statsd/instrument/statsd_datagram_builder.rb +14 -0
  46. data/lib/statsd/instrument/strict.rb +235 -0
  47. data/lib/statsd/instrument/udp_sink.rb +62 -0
  48. data/lib/statsd/instrument/version.rb +3 -1
  49. data/lib/statsd/instrument.rb +340 -163
  50. data/lib/statsd-instrument.rb +2 -0
  51. data/statsd-instrument.gemspec +13 -10
  52. data/test/assertions_test.rb +167 -156
  53. data/test/benchmark/clock_gettime.rb +27 -0
  54. data/test/benchmark/default_tags.rb +47 -0
  55. data/test/benchmark/metrics.rb +9 -8
  56. data/test/benchmark/tags.rb +5 -3
  57. data/test/capture_backend_test.rb +4 -2
  58. data/test/capture_sink_test.rb +44 -0
  59. data/test/client_test.rb +164 -0
  60. data/test/compatibility/dogstatsd_datagram_compatibility_test.rb +162 -0
  61. data/test/datagram_builder_test.rb +120 -0
  62. data/test/deprecations_test.rb +132 -0
  63. data/test/dogstatsd_datagram_builder_test.rb +32 -0
  64. data/test/environment_test.rb +75 -8
  65. data/test/helpers/rubocop_helper.rb +47 -0
  66. data/test/helpers_test.rb +2 -1
  67. data/test/integration_test.rb +31 -7
  68. data/test/log_sink_test.rb +37 -0
  69. data/test/logger_backend_test.rb +10 -8
  70. data/test/matchers_test.rb +42 -28
  71. data/test/metric_test.rb +18 -22
  72. data/test/null_sink_test.rb +13 -0
  73. data/test/rubocop/measure_as_dist_argument_test.rb +44 -0
  74. data/test/rubocop/metaprogramming_positional_arguments_test.rb +58 -0
  75. data/test/rubocop/metric_prefix_argument_test.rb +38 -0
  76. data/test/rubocop/metric_return_value_test.rb +78 -0
  77. data/test/rubocop/metric_value_keyword_argument_test.rb +39 -0
  78. data/test/rubocop/positional_arguments_test.rb +110 -0
  79. data/test/rubocop/splat_arguments_test.rb +27 -0
  80. data/test/statsd_datagram_builder_test.rb +22 -0
  81. data/test/statsd_instrumentation_test.rb +109 -100
  82. data/test/statsd_test.rb +113 -79
  83. data/test/test_helper.rb +12 -1
  84. data/test/udp_backend_test.rb +38 -36
  85. data/test/udp_sink_test.rb +85 -0
  86. metadata +85 -5
  87. data/.travis.yml +0 -12
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ require 'statsd/instrument/client'
6
+
7
+ class DogStatsDDatagramBuilderTest < Minitest::Test
8
+ def setup
9
+ @datagram_builder = StatsD::Instrument::DogStatsDDatagramBuilder.new
10
+ end
11
+
12
+ def test_raises_on_unsupported_metrics
13
+ assert_raises(NotImplementedError) { @datagram_builder.kv('foo', 10, nil, nil) }
14
+ end
15
+
16
+ def test_service_check
17
+ assert_equal '_sc|service|0', @datagram_builder._sc('service', :ok)
18
+ datagram = @datagram_builder._sc('service', :warning, timestamp: Time.parse('2019-09-30T04:22:12Z'),
19
+ hostname: 'localhost', tags: { foo: 'bar|baz' }, message: 'blah')
20
+ assert_equal "_sc|service|1|h:localhost|d:1569817332|#foo:barbaz|m:blah", datagram
21
+ end
22
+
23
+ def test_event
24
+ assert_equal '_e{5,5}:hello|world', @datagram_builder._e('hello', "world")
25
+
26
+ datagram = @datagram_builder._e("testing", "with\nnewline", timestamp: Time.parse('2019-09-30T04:22:12Z'),
27
+ hostname: 'localhost', aggregation_key: 'my-key', priority: 'low', source_type_name: 'source',
28
+ alert_type: 'success', tags: { foo: 'bar|baz' })
29
+ assert_equal '_e{7,13}:testing|with\\nnewline|h:localhost|d:1569817332|k:my-key|' \
30
+ 'p:low|s:source|t:success|#foo:barbaz', datagram
31
+ end
32
+ end
@@ -1,30 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  module Rails; end
4
6
 
5
7
  class EnvironmentTest < Minitest::Test
6
-
7
8
  def setup
8
9
  ENV['STATSD_ADDR'] = nil
9
10
  ENV['IMPLEMENTATION'] = nil
10
11
  end
11
12
 
12
- def test_uses_logger_in_development_environment
13
+ def test_default_backend_uses_logger_in_development_environment
13
14
  StatsD::Instrument::Environment.stubs(:environment).returns('development')
14
15
  assert_instance_of StatsD::Instrument::Backends::LoggerBackend, StatsD::Instrument::Environment.default_backend
15
16
  end
16
17
 
17
- def test_uses_null_backend_in_test_environment
18
+ def test_default_backend_uses_null_backend_in_test_environment
18
19
  StatsD::Instrument::Environment.stubs(:environment).returns('test')
19
20
  assert_instance_of StatsD::Instrument::Backends::NullBackend, StatsD::Instrument::Environment.default_backend
20
21
  end
21
22
 
22
- def test_uses_udp_backend_in_production_environment
23
+ def test_default_backend_uses_udp_backend_in_production_environment
23
24
  StatsD::Instrument::Environment.stubs(:environment).returns('production')
24
25
  assert_instance_of StatsD::Instrument::Backends::UDPBackend, StatsD::Instrument::Environment.default_backend
25
26
  end
26
27
 
27
- def test_uses_environment_variables_in_production_environment
28
+ def test_default_backend_uses_environment_variables_in_production_environment
28
29
  StatsD::Instrument::Environment.stubs(:environment).returns('production')
29
30
  ENV['STATSD_ADDR'] = '127.0.0.1:1234'
30
31
  ENV['STATSD_IMPLEMENTATION'] = 'datadog'
@@ -35,12 +36,78 @@ class EnvironmentTest < Minitest::Test
35
36
  assert_equal :datadog, backend.implementation
36
37
  end
37
38
 
38
- def test_uses_env_when_rails_does_not_respond_to_env
39
- assert_equal ENV['ENV'], StatsD::Instrument::Environment.environment
39
+ def test_environment_prefers_statsd_env_if_available
40
+ env = StatsD::Instrument::Environment.new(
41
+ 'STATSD_ENV' => 'set_from_STATSD_ENV',
42
+ 'RACK_ENV' => 'set_from_RACK_ENV',
43
+ 'ENV' => 'set_from_ENV',
44
+ )
45
+ assert_equal 'set_from_STATSD_ENV', env.environment
40
46
  end
41
47
 
42
- def test_uses_rails_env_when_rails_is_available
48
+ def test_environment_uses_env_when_rails_does_not_respond_to_env_and_statsd_env_is_not_set
49
+ env = StatsD::Instrument::Environment.new(
50
+ 'ENV' => 'set_from_ENV',
51
+ )
52
+ assert_equal 'set_from_ENV', env.environment
53
+ end
54
+
55
+ def test_environment_uses_rails_env_when_rails_is_available
43
56
  Rails.stubs(:env).returns('production')
44
57
  assert_equal 'production', StatsD::Instrument::Environment.environment
45
58
  end
59
+
60
+ def test_environment_defaults_to_development
61
+ env = StatsD::Instrument::Environment.new({})
62
+ assert_equal 'development', env.environment
63
+ end
64
+
65
+ def test_default_client_uses_log_sink_in_development_environment
66
+ env = StatsD::Instrument::Environment.new('STATSD_ENV' => 'development')
67
+ assert_kind_of StatsD::Instrument::LogSink, env.default_client.sink
68
+ end
69
+
70
+ def test_default_client_uses_null_sink_in_test_environment
71
+ env = StatsD::Instrument::Environment.new('STATSD_ENV' => 'test')
72
+ assert_kind_of StatsD::Instrument::NullSink, env.default_client.sink
73
+ end
74
+
75
+ def test_default_client_uses_udp_sink_in_staging_environment
76
+ env = StatsD::Instrument::Environment.new('STATSD_ENV' => 'staging')
77
+ assert_kind_of StatsD::Instrument::UDPSink, env.default_client.sink
78
+ end
79
+
80
+ def test_default_client_uses_udp_sink_in_production_environment
81
+ env = StatsD::Instrument::Environment.new('STATSD_ENV' => 'production')
82
+ assert_kind_of StatsD::Instrument::UDPSink, env.default_client.sink
83
+ end
84
+
85
+ def test_default_client_respects_statsd_environment_variables
86
+ env = StatsD::Instrument::Environment.new(
87
+ 'STATSD_ENV' => 'production',
88
+ 'STATSD_IMPLEMENTATION' => 'datadog',
89
+ 'STATSD_ADDR' => 'foo:8125',
90
+ 'STATSD_SAMPLE_RATE' => "0.1",
91
+ 'STATSD_PREFIX' => "foo",
92
+ 'STATSD_DEFAULT_TAGS' => "foo,bar:baz",
93
+ )
94
+
95
+ assert_equal StatsD::Instrument::DogStatsDDatagramBuilder, env.default_client.datagram_builder_class
96
+ assert_equal 'foo', env.default_client.sink.host
97
+ assert_equal 8125, env.default_client.sink.port
98
+ assert_equal 0.1, env.default_client.default_sample_rate
99
+ assert_equal "foo", env.default_client.prefix
100
+ assert_equal ["foo", "bar:baz"], env.default_client.default_tags
101
+ end
102
+
103
+ def test_default_client_has_sensible_defaults
104
+ env = StatsD::Instrument::Environment.new('STATSD_ENV' => 'production')
105
+
106
+ assert_equal StatsD::Instrument::StatsDDatagramBuilder, env.default_client.datagram_builder_class
107
+ assert_equal 'localhost', env.default_client.sink.host
108
+ assert_equal 8125, env.default_client.sink.port
109
+ assert_equal 1.0, env.default_client.default_sample_rate
110
+ assert_nil env.default_client.prefix
111
+ assert_nil env.default_client.default_tags
112
+ end
46
113
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RubocopHelper
6
+ attr_accessor :cop
7
+
8
+ private
9
+
10
+ def assert_no_offenses(source)
11
+ investigate(RuboCop::ProcessedSource.new(source, 2.3, nil))
12
+ assert_predicate cop.offenses, :empty?, "Did not expect Rubocop to find offenses"
13
+ end
14
+
15
+ def assert_offense(source)
16
+ investigate(RuboCop::ProcessedSource.new(source, 2.3, nil))
17
+ refute_predicate cop.offenses, :empty?, "Expected Rubocop to find offenses"
18
+ end
19
+
20
+ def assert_no_autocorrect(source)
21
+ corrected = autocorrect_source(source)
22
+ assert_equal source, corrected
23
+ end
24
+
25
+ def autocorrect_source(source)
26
+ RuboCop::Formatter::DisabledConfigFormatter.config_to_allow_offenses = {}
27
+ RuboCop::Formatter::DisabledConfigFormatter.detected_styles = {}
28
+ cop.instance_variable_get(:@options)[:auto_correct] = true
29
+
30
+ processed_source = RuboCop::ProcessedSource.new(source, 2.3, nil)
31
+ investigate(processed_source)
32
+
33
+ corrector = RuboCop::Cop::Corrector.new(processed_source.buffer, cop.corrections)
34
+ corrector.rewrite
35
+ end
36
+
37
+ def investigate(processed_source)
38
+ forces = RuboCop::Cop::Force.all.each_with_object([]) do |klass, instances|
39
+ next unless cop.join_force?(klass)
40
+ instances << klass.new([cop])
41
+ end
42
+
43
+ commissioner = RuboCop::Cop::Commissioner.new([cop], forces, raise_error: true)
44
+ commissioner.investigate(processed_source)
45
+ commissioner
46
+ end
47
+ end
data/test/helpers_test.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class HelpersTest < Minitest::Test
@@ -21,4 +23,3 @@ class HelpersTest < Minitest::Test
21
23
  assert_equal 12, metrics[1].value
22
24
  end
23
25
  end
24
-
@@ -1,20 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class IntegrationTest < Minitest::Test
4
-
5
6
  def setup
6
- @old_backend, StatsD.backend = StatsD.backend, StatsD::Instrument::Backends::UDPBackend.new("localhost:31798")
7
+ @server = UDPSocket.new
8
+ @server.bind('localhost', 0)
9
+ port = @server.addr[1]
10
+
11
+ @old_backend = StatsD.backend
12
+ StatsD.backend = StatsD::Instrument::Backends::UDPBackend.new("localhost:#{port}")
7
13
  end
8
-
14
+
9
15
  def teardown
16
+ @server.close
10
17
  StatsD.backend = @old_backend
11
18
  end
12
19
 
13
20
  def test_live_local_udp_socket
14
- server = UDPSocket.new
15
- server.bind('localhost', 31798)
16
-
17
21
  StatsD.increment('counter')
18
- assert_equal "counter:1|c", server.recvfrom(100).first
22
+ assert_equal "counter:1|c", @server.recvfrom(100).first
23
+ end
24
+
25
+ def test_synchronize_in_exit_handler_handles_thread_error_and_exits_cleanly
26
+ pid = fork do
27
+ Signal.trap('TERM') do
28
+ StatsD.increment('exiting')
29
+ Process.exit!(0)
30
+ end
31
+
32
+ sleep 100
33
+ end
34
+
35
+ Process.kill('TERM', pid)
36
+ _, exit_status = Process.waitpid2(pid)
37
+
38
+ assert_equal 0, exit_status, "The foked process did not exit cleanly"
39
+ assert_equal "exiting:1|c", @server.recvfrom_nonblock(100).first
40
+
41
+ rescue NotImplementedError
42
+ pass("Fork is not implemented on #{RUBY_PLATFORM}")
19
43
  end
20
44
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ require 'statsd/instrument/client'
6
+
7
+ class LogSinktest < Minitest::Test
8
+ def test_log_sink
9
+ logger = Logger.new(log = StringIO.new)
10
+ logger.formatter = proc do |severity, _datetime, _progname, msg|
11
+ "#{severity}: #{msg}\n"
12
+ end
13
+
14
+ log_sink = StatsD::Instrument::LogSink.new(logger)
15
+ log_sink << 'foo:1|c' << 'bar:1|c'
16
+
17
+ assert_equal <<~LOG, log.string
18
+ DEBUG: [StatsD] foo:1|c
19
+ DEBUG: [StatsD] bar:1|c
20
+ LOG
21
+ end
22
+
23
+ def test_log_sink_chomps_trailing_newlines
24
+ logger = Logger.new(log = StringIO.new)
25
+ logger.formatter = proc do |severity, _datetime, _progname, msg|
26
+ "#{severity}: #{msg}\n"
27
+ end
28
+
29
+ log_sink = StatsD::Instrument::LogSink.new(logger)
30
+ log_sink << "foo:1|c\n" << "bar:1|c\n"
31
+
32
+ assert_equal <<~LOG, log.string
33
+ DEBUG: [StatsD] foo:1|c
34
+ DEBUG: [StatsD] bar:1|c
35
+ LOG
36
+ end
37
+ end
@@ -1,20 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class LoggerBackendTest < Minitest::Test
4
6
  def setup
5
7
  logger = Logger.new(@io = StringIO.new)
6
- logger.formatter = lambda { |_,_,_, msg| "#{msg}\n" }
8
+ logger.formatter = lambda { |_, _, _, msg| "#{msg}\n" }
7
9
  @backend = StatsD::Instrument::Backends::LoggerBackend.new(logger)
8
- @metric1 = StatsD::Instrument::Metric::new(type: :c, name: 'mock.counter', tags: { a: 'b', c: 'd'})
9
- @metric2 = StatsD::Instrument::Metric::new(type: :ms, name: 'mock.measure', value: 123, sample_rate: 0.3)
10
+ @metric1 = StatsD::Instrument::Metric.new(type: :c, name: 'mock.counter', tags: { a: 'b', c: 'd' })
11
+ @metric2 = StatsD::Instrument::Metric.new(type: :ms, name: 'mock.measure', value: 123, sample_rate: 0.3)
10
12
  end
11
13
 
12
14
  def test_logs_metrics
13
15
  @backend.collect_metric(@metric1)
14
- assert_equal @io.string, "[StatsD] increment mock.counter:1 #a:b #c:d\n"
15
- @io.string = ""
16
-
17
16
  @backend.collect_metric(@metric2)
18
- assert_equal @io.string, "[StatsD] measure mock.measure:123 @0.3\n"
17
+ assert_equal <<~LOG, @io.string
18
+ [StatsD] increment mock.counter:1 #a:b #c:d
19
+ [StatsD] measure mock.measure:123 @0.3
20
+ LOG
19
21
  end
20
- end
22
+ end
@@ -1,13 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'statsd/instrument/matchers'
3
5
 
4
6
  class MatchersTest < Minitest::Test
5
7
  def test_statsd_increment_matched
6
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', {}).matches? lambda { StatsD.increment('counter') }
8
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', {})
9
+ .matches?(lambda { StatsD.increment('counter') })
7
10
  end
8
11
 
9
12
  def test_statsd_increment_not_matched
10
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', {}).matches? lambda { StatsD.increment('not_counter') }
13
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', {})
14
+ .matches?(lambda { StatsD.increment('not_counter') })
11
15
  end
12
16
 
13
17
  def test_statsd_increment_compound_matched
@@ -31,72 +35,82 @@ class MatchersTest < Minitest::Test
31
35
  end
32
36
 
33
37
  def test_statsd_increment_with_times_matched
34
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 1).matches? lambda { StatsD.increment('counter') }
38
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 1)
39
+ .matches?(lambda { StatsD.increment('counter') })
35
40
  end
36
41
 
37
42
  def test_statsd_increment_with_times_not_matched
38
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2).matches? lambda { StatsD.increment('counter', times: 3) }
43
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2)
44
+ .matches? lambda { 3.times { StatsD.increment('counter') } }
39
45
  end
40
46
 
41
47
  def test_statsd_increment_with_sample_rate_matched
42
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: 0.5).matches? lambda { StatsD.increment('counter', sample_rate: 0.5) }
48
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: 0.5)
49
+ .matches?(lambda { StatsD.increment('counter', sample_rate: 0.5) })
43
50
  end
44
51
 
45
52
  def test_statsd_increment_with_sample_rate_not_matched
46
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: 0.5).matches? lambda { StatsD.increment('counter', sample_rate: 0.7) }
53
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: 0.5)
54
+ .matches?(lambda { StatsD.increment('counter', sample_rate: 0.7) })
47
55
  end
48
56
 
49
57
  def test_statsd_increment_with_value_matched
50
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches? lambda { StatsD.increment('counter') }
58
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1)
59
+ .matches?(lambda { StatsD.increment('counter') })
51
60
  end
52
61
 
53
62
  def test_statsd_increment_with_value_matched_when_multiple_metrics
54
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches? lambda {
55
- StatsD.increment('counter', value: 2)
56
- StatsD.increment('counter', value: 1)
57
- }
63
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches?(lambda {
64
+ StatsD.increment('counter', 2)
65
+ StatsD.increment('counter', 1)
66
+ })
58
67
  end
59
68
 
60
69
  def test_statsd_increment_with_value_not_matched_when_multiple_metrics
61
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches? lambda {
62
- StatsD.increment('counter', value: 2)
63
- StatsD.increment('counter', value: 3)
64
- }
70
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 1).matches?(lambda {
71
+ StatsD.increment('counter', 2)
72
+ StatsD.increment('counter', 3)
73
+ })
65
74
  end
66
75
 
67
76
  def test_statsd_increment_with_value_not_matched
68
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 3).matches? lambda { StatsD.increment('counter') }
77
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', value: 3)
78
+ .matches?(lambda { StatsD.increment('counter') })
69
79
  end
70
80
 
71
81
  def test_statsd_increment_with_tags_matched
72
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['a', 'b']).matches? lambda { StatsD.increment('counter', tags: ['a', 'b']) }
82
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['a', 'b'])
83
+ .matches?(lambda { StatsD.increment('counter', tags: ['a', 'b']) })
73
84
  end
74
85
 
75
86
  def test_statsd_increment_with_tags_not_matched
76
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['a', 'b']).matches? lambda { StatsD.increment('counter', tags: ['c']) }
87
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', tags: ['a', 'b'])
88
+ .matches?(lambda { StatsD.increment('counter', tags: ['c']) })
77
89
  end
78
90
 
79
91
  def test_statsd_increment_with_times_and_value_matched
80
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2, value: 1).matches? lambda {
81
- StatsD.increment('counter', value: 1)
82
- StatsD.increment('counter', value: 1)
83
- }
92
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2, value: 1).matches?(lambda {
93
+ StatsD.increment('counter', 1)
94
+ StatsD.increment('counter', 1)
95
+ })
84
96
  end
85
97
 
86
98
  def test_statsd_increment_with_times_and_value_not_matched
87
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2, value: 1).matches? lambda {
88
- StatsD.increment('counter', value: 1)
89
- StatsD.increment('counter', value: 2)
90
- }
99
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', times: 2, value: 1).matches?(lambda {
100
+ StatsD.increment('counter', 1)
101
+ StatsD.increment('counter', 2)
102
+ })
91
103
  end
92
104
 
93
105
  def test_statsd_increment_with_sample_rate_and_argument_matcher_matched
94
106
  between_matcher = RSpec::Matchers::BuiltIn::BeBetween.new(0.4, 0.6).inclusive
95
- assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: between_matcher).matches? lambda { StatsD.increment('counter', sample_rate: 0.5) }
107
+ assert StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: between_matcher)
108
+ .matches?(lambda { StatsD.increment('counter', sample_rate: 0.5) })
96
109
  end
97
110
 
98
111
  def test_statsd_increment_with_sample_rate_and_argument_matcher_not_matched
99
112
  between_matcher = RSpec::Matchers::BuiltIn::BeBetween.new(0.4, 0.6).inclusive
100
- refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: between_matcher).matches? lambda { StatsD.increment('counter', sample_rate: 0.7) }
113
+ refute StatsD::Instrument::Matchers::Increment.new(:c, 'counter', sample_rate: between_matcher)
114
+ .matches?(lambda { StatsD.increment('counter', sample_rate: 0.7) })
101
115
  end
102
116
  end
data/test/metric_test.rb CHANGED
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class MetricTest < Minitest::Test
4
-
5
6
  def test_required_arguments
6
7
  assert_raises(ArgumentError) { StatsD::Instrument::Metric.new(type: :c) }
7
8
  assert_raises(ArgumentError) { StatsD::Instrument::Metric.new(name: 'test') }
@@ -15,37 +16,32 @@ class MetricTest < Minitest::Test
15
16
  assert m.tags.nil?
16
17
  end
17
18
 
18
- def test_name_prefix
19
- StatsD.stubs(:prefix).returns('prefix')
20
- m = StatsD::Instrument::Metric.new(type: :c, name: 'counter')
21
- assert_equal 'prefix.counter', m.name
22
-
23
- m = StatsD::Instrument::Metric.new(type: :c, name: 'counter', no_prefix: true)
24
- assert_equal 'counter', m.name
25
-
26
- m = StatsD::Instrument::Metric.new(type: :c, name: 'counter', prefix: "foobar")
27
- assert_equal 'foobar.counter', m.name
28
-
29
- m = StatsD::Instrument::Metric.new(type: :c, name: 'counter', prefix: "foobar", no_prefix: true)
30
- assert_equal 'counter', m.name
31
- end
32
-
33
19
  def test_bad_metric_name
34
- m = StatsD::Instrument::Metric.new(type: :c, name: 'my:metric', no_prefix: true)
20
+ m = StatsD::Instrument::Metric.new(type: :c, name: 'my:metric')
35
21
  assert_equal 'my_metric', m.name
36
- m = StatsD::Instrument::Metric.new(type: :c, name: 'my|metric', no_prefix: true)
22
+ m = StatsD::Instrument::Metric.new(type: :c, name: 'my|metric')
37
23
  assert_equal 'my_metric', m.name
38
- m = StatsD::Instrument::Metric.new(type: :c, name: 'my@metric', no_prefix: true)
24
+ m = StatsD::Instrument::Metric.new(type: :c, name: 'my@metric')
39
25
  assert_equal 'my_metric', m.name
40
26
  end
41
27
 
42
28
  def test_handle_bad_tags
43
29
  assert_equal ['ignored'], StatsD::Instrument::Metric.normalize_tags(['igno|red'])
44
- assert_equal ['lol::class:omg::lol'], StatsD::Instrument::Metric.normalize_tags({ :"lol::class" => "omg::lol" })
30
+ assert_equal ['lol::class:omg::lol'], StatsD::Instrument::Metric.normalize_tags("lol::class" => "omg::lol")
45
31
  end
46
32
 
47
33
  def test_rewrite_tags_provided_as_hash
48
- assert_equal ['tag:value'], StatsD::Instrument::Metric.normalize_tags(:tag => 'value')
49
- assert_equal ['tag:value', 'tag2:value2'], StatsD::Instrument::Metric.normalize_tags(:tag => 'value', :tag2 => 'value2')
34
+ assert_equal ['tag:value'], StatsD::Instrument::Metric.normalize_tags(tag: 'value')
35
+ assert_equal ['tag1:v1', 'tag2:v2'], StatsD::Instrument::Metric.normalize_tags(tag1: 'v1', tag2: 'v2')
36
+ end
37
+
38
+ def test_default_tags
39
+ StatsD.stubs(:default_tags).returns(['default_tag:default_value'])
40
+ m = StatsD::Instrument::Metric.new(type: :c, name: 'counter', tags: { tag: 'value' })
41
+ assert_equal ['tag:value', 'default_tag:default_value'], m.tags
42
+
43
+ StatsD.stubs(:default_tags).returns(['tag:value'])
44
+ m = StatsD::Instrument::Metric.new(type: :c, name: 'counter', tags: { tag: 'value' })
45
+ assert_equal ['tag:value', 'tag:value'], m.tags # we don't care about duplicates
50
46
  end
51
47
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ require 'statsd/instrument/client'
6
+
7
+ class NullSinktest < Minitest::Test
8
+ def test_null_sink
9
+ null_sink = StatsD::Instrument::NullSink.new
10
+ null_sink << 'foo:1|c' << 'bar:1|c'
11
+ pass # We don't have anything to assert, except that no exception was raised
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'statsd/instrument/rubocop'
5
+
6
+ module Rubocop
7
+ class MeasureAsDistArgumentTest < Minitest::Test
8
+ include RubocopHelper
9
+
10
+ def setup
11
+ @cop = RuboCop::Cop::StatsD::MeasureAsDistArgument.new
12
+ end
13
+
14
+ def test_ok_for_metric_method_without_as_dist_argument
15
+ assert_no_offenses("StatsD.measure('foo', 123)")
16
+ assert_no_offenses("StatsD.measure('foo', 123, sample_rate: 3)")
17
+ assert_no_offenses("StatsD.measure('foo') {}")
18
+ end
19
+
20
+ def test_ok_for_other_metric_methods
21
+ assert_no_offenses("StatsD.increment('foo', as_dist: true)")
22
+ end
23
+
24
+ def test_ok_for_metaprogramming_method_without_as_dist_argument
25
+ assert_no_offenses("statsd_measure(:method, 'metric_name', sample_rate: 1) {}")
26
+ end
27
+
28
+ def test_ok_for_other_metaprogramming_methods
29
+ assert_no_offenses("statsd_distribution(:method, 'metric_name', as_dist: true) {}")
30
+ end
31
+
32
+ def test_offense_when_using_as_dist_with_measure_metric_method
33
+ assert_offense("StatsD.measure('foo', 123, sample_rate: 1, as_dist: true, tags: ['foo'])")
34
+ assert_offense("StatsD.measure('foo', 123, as_dist: false)")
35
+ assert_offense("StatsD.measure('foo', as_dist: true, &block)")
36
+ assert_offense("StatsD.measure('foo', as_dist: true) { } ")
37
+ end
38
+
39
+ def test_offense_when_using_as_dist_with_measure_metaprogramming_method
40
+ assert_offense("statsd_measure(:method, 'foo', as_dist: true, &block)")
41
+ assert_offense("statsd_measure(:method, 'foo', as_dist: false) { } ")
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'statsd/instrument/rubocop'
5
+
6
+ module Rubocop
7
+ class MetaprogrammingPositionalArgumentsTest < Minitest::Test
8
+ include RubocopHelper
9
+
10
+ def setup
11
+ @cop = RuboCop::Cop::StatsD::MetaprogrammingPositionalArguments.new
12
+ end
13
+
14
+ def test_ok_with_two_arguments
15
+ assert_no_offenses("ClassName.statsd_count_if(:method, 'metric') { foo }")
16
+ assert_no_offenses("ClassName.statsd_measure :method, 'metric'")
17
+ assert_no_offenses(<<~RUBY)
18
+ class Foo
19
+ statsd_count :method, 'metric'
20
+ end
21
+ RUBY
22
+ end
23
+
24
+ def test_ok_with_keyword_arguments_and_blocks
25
+ assert_no_offenses("ClassName.statsd_measure :method, 'metric', foo: 'bar'")
26
+ assert_no_offenses("ClassName.statsd_count_success(:method, 'metric', **kwargs)")
27
+ assert_no_offenses("ClassName.statsd_measure(:method, 'metric', foo: 'bar', &block)")
28
+ assert_no_offenses(<<~RUBY)
29
+ class Foo
30
+ statsd_count_if(:method, 'metric', foo: 'bar', baz: 'quc') do |result|
31
+ result == 'ok'
32
+ end
33
+ end
34
+ RUBY
35
+ end
36
+
37
+ def test_offense_with_positional_arguments
38
+ assert_offense("ClassName.statsd_measure(:method, 'metric', 1)")
39
+ assert_offense("ClassName.statsd_measure(:method, 'metric', 1, ['tag'])")
40
+ assert_offense("ClassName.statsd_measure(:method, 'metric', 1, tag: 'value')")
41
+ assert_offense(<<~RUBY)
42
+ class Foo
43
+ extend StatsD::Instrument
44
+ statsd_measure(:method, 'metric', 1)
45
+ end
46
+ RUBY
47
+ end
48
+
49
+ def test_offense_with_splat
50
+ assert_offense("ClassName.statsd_measure(:method, 'metric', *options)")
51
+ end
52
+
53
+ def test_offense_with_constant_or_method_as_third_argument
54
+ assert_offense("ClassName.statsd_measure(:method, 'metric', SAMPLE_RATE_CONSTANT)")
55
+ assert_offense("ClassName.statsd_measure(:method, 'metric', method_returning_a_hash)")
56
+ end
57
+ end
58
+ end