statsd-instrument 2.3.2 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
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