scout_apm 5.3.3 → 5.6.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +30 -0
  3. data/.github/workflows/test.yml +18 -16
  4. data/CHANGELOG.markdown +51 -1
  5. data/README.markdown +5 -1
  6. data/gems/instruments.gemfile +2 -0
  7. data/gems/rails7.gemfile +4 -0
  8. data/gems/sidekiq7.gemfile +3 -0
  9. data/gems/sidekiq8.gemfile +4 -0
  10. data/gems/sqlite3-v2.gemfile +3 -0
  11. data/lib/scout_apm/agent.rb +1 -1
  12. data/lib/scout_apm/agent_context.rb +4 -0
  13. data/lib/scout_apm/app_server_load.rb +1 -1
  14. data/lib/scout_apm/auto_instrument/layer.rb +1 -0
  15. data/lib/scout_apm/auto_instrument/rails.rb +21 -0
  16. data/lib/scout_apm/background_job_integrations/good_job.rb +49 -0
  17. data/lib/scout_apm/background_job_integrations/resque.rb +13 -27
  18. data/lib/scout_apm/background_job_integrations/sidekiq.rb +22 -2
  19. data/lib/scout_apm/background_job_integrations/solid_queue.rb +47 -0
  20. data/lib/scout_apm/config.rb +69 -34
  21. data/lib/scout_apm/environment.rb +2 -0
  22. data/lib/scout_apm/error_service/sidekiq.rb +1 -1
  23. data/lib/scout_apm/git_revision.rb +7 -1
  24. data/lib/scout_apm/instruments/action_view.rb +62 -3
  25. data/lib/scout_apm/instruments/active_record.rb +1 -1
  26. data/lib/scout_apm/instruments/grape.rb +1 -1
  27. data/lib/scout_apm/instruments/mongoid.rb +7 -35
  28. data/lib/scout_apm/instruments/net_http.rb +1 -1
  29. data/lib/scout_apm/instruments/resque.rb +31 -2
  30. data/lib/scout_apm/layer_converters/external_service_converter.rb +1 -1
  31. data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +7 -0
  32. data/lib/scout_apm/sampling.rb +104 -0
  33. data/lib/scout_apm/slow_request_policy.rb +1 -1
  34. data/lib/scout_apm/tracked_request.rb +7 -1
  35. data/lib/scout_apm/utils/installed_gems.rb +2 -1
  36. data/lib/scout_apm/version.rb +1 -1
  37. data/lib/scout_apm.rb +3 -0
  38. data/scout_apm.gemspec +2 -2
  39. data/test/test_helper.rb +61 -0
  40. data/test/unit/auto_instrument/hash_shorthand_controller-instrumented.rb +41 -0
  41. data/test/unit/auto_instrument/hash_shorthand_controller.rb +41 -0
  42. data/test/unit/auto_instrument_test.rb +7 -1
  43. data/test/unit/background_job_integrations/sidekiq_test.rb +13 -3
  44. data/test/unit/config_test.rb +20 -0
  45. data/test/unit/environment_test.rb +0 -28
  46. data/test/unit/git_revision_test.rb +65 -3
  47. data/test/unit/instruments/action_view_test.rb +102 -0
  48. data/test/unit/instruments/active_record_test.rb +30 -0
  49. data/test/unit/instruments/fixtures/test/_test_partial.html.erb +3 -0
  50. data/test/unit/instruments/fixtures/test/_test_partial_collection.html.erb +3 -0
  51. data/test/unit/instruments/fixtures/test_view.html.erb +10 -0
  52. data/test/unit/sampling_test.rb +215 -0
  53. metadata +22 -10
@@ -4,7 +4,7 @@ require 'scout_apm/auto_instrument'
4
4
 
5
5
  class AutoInstrumentTest < Minitest::Test
6
6
  ROOT = File.expand_path("../../", __dir__)
7
-
7
+
8
8
  def source_path(name)
9
9
  File.expand_path("auto_instrument/#{name}.rb", __dir__)
10
10
  end
@@ -38,6 +38,12 @@ class AutoInstrumentTest < Minitest::Test
38
38
  normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("controller")))
39
39
  end
40
40
 
41
+ def test_controller_rewrite_hash_shorthand
42
+ skip if RUBY_VERSION < "3.1"
43
+ assert_equal instrumented_source("hash_shorthand_controller"),
44
+ normalize_backtrace(::ScoutApm::AutoInstrument::Rails.rewrite(source_path("hash_shorthand_controller")))
45
+ end
46
+
41
47
  def test_rescue_from_rewrite
42
48
  # update_instrumented_source("rescue_from")
43
49
 
@@ -18,7 +18,9 @@ class SidekiqTest < Minitest::Test
18
18
  def test_starts_on_startup
19
19
  ::ScoutApm::Agent.any_instance.expects(:start)
20
20
  SidekiqIntegration.new.install
21
- Sidekiq.options[:lifecycle_events][:startup].map(&:call)
21
+ ::Sidekiq.configure_server do |config|
22
+ config[:lifecycle_events][:startup].map(&:call)
23
+ end
22
24
  end
23
25
  end
24
26
 
@@ -100,13 +102,21 @@ class SidekiqTest < Minitest::Test
100
102
  ########################################
101
103
  def test_latency_from_created_at
102
104
  # Created at time 80, but now it is 200. Latency was 120
103
- msg = { 'created_at' => 80 }
105
+ msg = if SidekiqMiddleware.sidekiq_version_8?
106
+ { 'created_at' => 80000 } # milliseconds for Sidekiq 8+
107
+ else
108
+ { 'created_at' => 80 }
109
+ end
104
110
  assert_equal 120, SidekiqMiddleware.new.latency(msg, 200)
105
111
  end
106
112
 
107
113
  def test_latency_from_enqueued_at
108
114
  # Created at time 80, but now it is 200. Latency was 120
109
- msg = { 'enqueued_at' => 80 }
115
+ msg = if SidekiqMiddleware.sidekiq_version_8?
116
+ { 'enqueued_at' => 80000 } # milliseconds for Sidekiq 8+
117
+ else
118
+ { 'enqueued_at' => 80 }
119
+ end
110
120
  assert_equal 120, SidekiqMiddleware.new.latency(msg, 200)
111
121
  end
112
122
 
@@ -72,6 +72,26 @@ class ConfigTest < Minitest::Test
72
72
  assert_equal ["a"], coercion.coerce(["a"])
73
73
  end
74
74
 
75
+ def test_integer_coercion
76
+ coercion = ScoutApm::Config::IntegerCoercion.new
77
+ assert_equal 1, coercion.coerce("1")
78
+ assert_equal 1, coercion.coerce(1)
79
+ assert_equal 0, coercion.coerce("0")
80
+ assert_equal 0, coercion.coerce(0)
81
+ assert_equal 0, coercion.coerce("")
82
+ assert_equal 0, coercion.coerce(nil)
83
+ end
84
+
85
+ def test_nullable_integer_coercion
86
+ coercion = ScoutApm::Config::NullableIntegerCoercion.new
87
+ assert_equal 1, coercion.coerce("1")
88
+ assert_equal 1, coercion.coerce(1)
89
+ assert_equal 0, coercion.coerce("0")
90
+ assert_equal 0, coercion.coerce(0)
91
+ assert_equal 0, coercion.coerce("")
92
+ assert_nil coercion.coerce(nil)
93
+ end
94
+
75
95
  def test_any_keys_found
76
96
  ENV.stubs(:has_key?).returns(nil)
77
97
 
@@ -29,32 +29,4 @@ class EnvironmentTest < Minitest::Test
29
29
  def test_framework_ruby
30
30
  assert_equal :ruby, ScoutApm::Environment.send(:new).framework
31
31
  end
32
-
33
- ############################################################
34
-
35
- def fake_rails(version)
36
- Kernel.const_set("Rails", Module.new)
37
- Kernel.const_set("ActionController", Module.new)
38
- r = Kernel.const_get("Rails")
39
- r.const_set("VERSION", Module.new)
40
- v = r.const_get("VERSION")
41
- v.const_set("MAJOR", version)
42
-
43
- assert_equal version, Rails::VERSION::MAJOR
44
- end
45
-
46
- def clean_fake_rails
47
- Kernel.send(:remove_const, "Rails") if defined?(Kernel::Rails)
48
- Kernel.send(:remove_const, "ActionController") if defined?(Kernel::ActionController)
49
- end
50
-
51
- def fake_sinatra
52
- Kernel.const_set("Sinatra", Module.new)
53
- s = Kernel.const_get("Sinatra")
54
- s.const_set("Base", Module.new)
55
- end
56
-
57
- def clean_fake_sinatra
58
- Kernel.const_unset("Sinatra") if defined?(Kernel::Sinatra)
59
- end
60
32
  end
@@ -3,13 +3,75 @@ require 'test_helper'
3
3
  require 'scout_apm/git_revision'
4
4
 
5
5
  class GitRevisionTest < Minitest::Test
6
- # TODO - other tests that would be nice:
7
- # * ensure we only detect once, on initialize.
8
- # * tests for reading cap files
6
+ def setup
7
+ @env = ENV.to_h
8
+ end
9
+
10
+ def teardown
11
+ ENV.replace(@env)
12
+ end
13
+
14
+ def test_sha_detected_once
15
+ ENV['HEROKU_SLUG_COMMIT'] = 'initial_slug'
16
+ revision = ScoutApm::GitRevision.new(ScoutApm::AgentContext.new)
17
+ assert_equal 'initial_slug', revision.sha
18
+
19
+ ENV['HEROKU_SLUG_COMMIT'] = 'new_slug'
20
+ assert_equal 'initial_slug', revision.sha
21
+ end
22
+
23
+ def test_sha_from_config
24
+ config = make_fake_config('revision_sha' => 'config_sha')
25
+ context = ScoutApm::AgentContext.new().tap { |c| c.config = config }
26
+ revision = ScoutApm::GitRevision.new(context)
27
+
28
+ assert_equal 'config_sha', revision.sha
29
+ end
9
30
 
10
31
  def test_sha_from_heroku
11
32
  ENV['HEROKU_SLUG_COMMIT'] = 'heroku_slug'
12
33
  revision = ScoutApm::GitRevision.new(ScoutApm::AgentContext.new)
13
34
  assert_equal 'heroku_slug', revision.sha
14
35
  end
36
+
37
+ def test_sha_from_capistrano
38
+ Dir.mktmpdir do |dir|
39
+ context = context_with_file_in_root(File.join(dir, 'REVISION'), 'capistrano_sha')
40
+ revision = ScoutApm::GitRevision.new(context)
41
+ assert_equal 'capistrano_sha', revision.sha
42
+ end
43
+ end
44
+
45
+ def test_sha_from_kamal
46
+ ENV['KAMAL_VERSION'] = 'kamal_sha'
47
+ revision = ScoutApm::GitRevision.new(ScoutApm::AgentContext.new)
48
+ assert_equal 'kamal_sha', revision.sha
49
+ end
50
+
51
+
52
+ def test_sha_from_mina
53
+ Dir.mktmpdir do |dir|
54
+ context = context_with_file_in_root(File.join(dir, '.mina_git_revision'), 'mina_sha')
55
+ revision = ScoutApm::GitRevision.new(context)
56
+ assert_equal 'mina_sha', revision.sha
57
+ end
58
+ end
59
+
60
+ def test_sha_from_git
61
+ short_sha = `git rev-parse --short HEAD`.strip
62
+ skip 'git not installed or not in a git repository' if short_sha.empty?
63
+
64
+ revision = ScoutApm::GitRevision.new(ScoutApm::AgentContext.new)
65
+ assert_equal short_sha, revision.sha
66
+ end
67
+
68
+ private
69
+
70
+ def context_with_file_in_root(file_name, contents)
71
+ config = make_fake_config({})
72
+ env = make_fake_environment(root: File.dirname(file_name))
73
+ File.write(file_name, contents)
74
+
75
+ ScoutApm::AgentContext.new().tap { |c| c.config = config; c.environment = env }
76
+ end
15
77
  end
@@ -0,0 +1,102 @@
1
+ # Most of this was taken from Rails:
2
+ # https://github.com/rails/rails/blob/v7.1.3/actionview/test/actionpack/controller/render_test.rb
3
+ # https://github.com/rails/rails/blob/v7.1.3/actionview/test/abstract_unit.rb
4
+
5
+ if (ENV["SCOUT_TEST_FEATURES"] || "").include?("instruments")
6
+ require 'test_helper'
7
+ require 'action_view'
8
+ require 'action_pack'
9
+ require 'action_controller'
10
+
11
+ FIXTURE_LOAD_PATH = File.expand_path("fixtures", __dir__)
12
+
13
+ include ActionView::Context
14
+ include ActionView::Helpers::TagHelper
15
+ include ActionView::Helpers::TextHelper
16
+
17
+ module ActionController
18
+
19
+ class Base
20
+ self.view_paths = FIXTURE_LOAD_PATH
21
+
22
+ def self.test_routes(&block)
23
+ routes = ActionDispatch::Routing::RouteSet.new
24
+ routes.draw(&block)
25
+ include routes.url_helpers
26
+ routes
27
+ end
28
+ end
29
+
30
+ class TestCase
31
+ include ActionDispatch::TestProcess
32
+
33
+ def self.with_routes(&block)
34
+ routes = ActionDispatch::Routing::RouteSet.new
35
+ routes.draw(&block)
36
+ include Module.new {
37
+ define_method(:setup) do
38
+ super()
39
+ @routes = routes
40
+ @controller.singleton_class.include @routes.url_helpers if @controller
41
+ end
42
+ }
43
+ routes
44
+ end
45
+ end
46
+ end
47
+
48
+ class TestController < ActionController::Base
49
+
50
+ def render_test_view
51
+ render template: "test_view"
52
+ end
53
+ end
54
+
55
+ class RenderTest < ActionController::TestCase
56
+
57
+ tests TestController
58
+
59
+ with_routes do
60
+ get :render_test_view, to: "test#render_test_view"
61
+ end
62
+
63
+ def setup
64
+ super
65
+ @controller.logger = ActiveSupport::Logger.new(nil)
66
+ ActionView::Base.logger = ActiveSupport::Logger.new(nil)
67
+
68
+ @request.host = "www.scoutapm.com"
69
+
70
+ @old_view_paths = ActionController::Base.view_paths
71
+ ActionController::Base.view_paths = FIXTURE_LOAD_PATH
72
+ end
73
+
74
+ def teardown
75
+ ActionView::Base.logger = nil
76
+
77
+ ActionController::Base.view_paths = @old_view_paths
78
+ end
79
+
80
+ def test_partial_instrumentation
81
+ recorder = FakeRecorder.new
82
+ agent_context.recorder = recorder
83
+
84
+ instrument = ScoutApm::Instruments::ActionView.new(agent_context)
85
+ instrument.install(prepend: true)
86
+
87
+ get :render_test_view
88
+ assert_response :success
89
+
90
+ root_layer = recorder.requests.first.root_layer
91
+ children = root_layer.children.to_a
92
+ assert_equal 2, children.size
93
+
94
+ partial_layer = children[0]
95
+ collection_layer = children[1]
96
+
97
+ assert_equal "test_view/Rendering", root_layer.name
98
+ assert_equal "test/_test_partial/Rendering", partial_layer.name
99
+ assert_equal "test/_test_partial_collection/Rendering", collection_layer.name
100
+ end
101
+ end
102
+ end
@@ -24,6 +24,36 @@ class ActiveRecordTest < Minitest::Test
24
24
  class User < ActiveRecord::Base
25
25
  end
26
26
 
27
+ class DumbRailsConfig
28
+ def self.after_initialize; end
29
+ end
30
+
31
+ def test_old_rails_initialization
32
+ recorder = FakeRecorder.new
33
+ agent_context.recorder = recorder
34
+ old_rails_version = (1..2).to_a.sample
35
+ fake_rails(old_rails_version)
36
+
37
+ ::Rails.expects(:configuration).never
38
+
39
+ instrument = ScoutApm::Instruments::ActiveRecord.new(agent_context)
40
+ instrument.install(prepend: false)
41
+ clean_fake_rails
42
+ end
43
+
44
+ def test_modern_rails_initialization
45
+ recorder = FakeRecorder.new
46
+ agent_context.recorder = recorder
47
+ modern_rails_version = (3..7).to_a.sample
48
+ fake_rails(modern_rails_version)
49
+
50
+ ::Rails.expects(:configuration).returns(DumbRailsConfig).once
51
+
52
+ instrument = ScoutApm::Instruments::ActiveRecord.new(agent_context)
53
+ instrument.install(prepend: false)
54
+ clean_fake_rails
55
+ end
56
+
27
57
  def test_instrumentation
28
58
  recorder = FakeRecorder.new
29
59
  agent_context.recorder = recorder
@@ -0,0 +1,3 @@
1
+ <div>
2
+ <p><%= message %></p>
3
+ </div>
@@ -0,0 +1,3 @@
1
+ <div>
2
+ <p><%= index %></p>
3
+ </div>
@@ -0,0 +1,10 @@
1
+ <html>
2
+ <head>
3
+ <title>View</title>
4
+ </head>
5
+ <body>
6
+ <h1>View</h1>
7
+ <%= render partial: "test_partial", locals: { message: 'Partial' } %>
8
+ <%= render partial: "test_partial_collection", collection: [1, 2, 3], as: :index %>
9
+ </body>
10
+ </html>
@@ -0,0 +1,215 @@
1
+ require 'test_helper'
2
+
3
+ require 'scout_apm/sampling'
4
+
5
+ class SamplingTest < Minitest::Test
6
+
7
+ def setup
8
+ @global_sample_config = FakeConfigOverlay.new(
9
+ {
10
+ 'sample_rate' => 80,
11
+ }
12
+ )
13
+
14
+ @individual_config = FakeConfigOverlay.new(
15
+ {
16
+ 'sample_endpoints' => ['/foo/bar:100', '/foo:50', '/bar/zap:80'],
17
+ 'ignore_endpoints' => ['/baz'],
18
+ 'sample_jobs' => ['joba:50'],
19
+ 'ignore_jobs' => 'jobb,jobc',
20
+ }
21
+ )
22
+ end
23
+
24
+ def test_individual_sample_to_hash
25
+ sampling = ScoutApm::Sampling.new(@individual_config)
26
+ assert_equal({'/foo/bar' => 100, '/foo' => 50, '/bar/zap' => 80}, sampling.individual_sample_to_hash(@individual_config.value('sample_endpoints')))
27
+
28
+ sampling = ScoutApm::Sampling.new(@global_sample_config)
29
+ assert_nil sampling.individual_sample_to_hash(@global_sample_config.value('sample_endpoints'))
30
+ end
31
+
32
+ def test_uri_ignore
33
+ sampling = ScoutApm::Sampling.new(@individual_config)
34
+ assert_equal true, sampling.ignore_uri?('/baz/bap')
35
+ assert_equal false, sampling.ignore_uri?('/foo/far')
36
+ end
37
+
38
+ def test_uri_sample
39
+ sampling = ScoutApm::Sampling.new(@individual_config)
40
+ rate = sampling.web_sample_rate('/foo/far')
41
+ assert_equal 50, rate
42
+
43
+ rate = sampling.web_sample_rate('/bar')
44
+ assert_nil rate
45
+
46
+ rate = sampling.web_sample_rate('/baz/bap')
47
+ assert_nil rate
48
+
49
+ rate = sampling.web_sample_rate('/foo/bar/baz')
50
+ assert_equal 100, rate
51
+ end
52
+
53
+ def test_job_ignore
54
+ sampling = ScoutApm::Sampling.new(@individual_config)
55
+ assert_equal true, sampling.ignore_job?('jobb')
56
+ assert_equal false, sampling.ignore_job?('joba')
57
+ end
58
+
59
+ def test_job_sample
60
+ sampling = ScoutApm::Sampling.new(@individual_config)
61
+ assert_equal 50, sampling.job_sample_rate('joba')
62
+ assert_nil sampling.job_sample_rate('jobb')
63
+ end
64
+
65
+ def test_sample
66
+ sampling = ScoutApm::Sampling.new(@individual_config)
67
+ sampling.stub(:rand, 0.01) do
68
+ assert_equal(false, sampling.sample?(50))
69
+ end
70
+ sampling.stub(:rand, 0.99) do
71
+ assert_equal(true, sampling.sample?(50))
72
+ end
73
+ end
74
+
75
+ def test_old_ignore
76
+ config = FakeConfigOverlay.new({'ignore' => ['/foo', '/bar']})
77
+ sampling = ScoutApm::Sampling.new(config)
78
+ assert_equal true, sampling.ignore_uri?('/foo')
79
+ assert_equal true, sampling.ignore_uri?('/bar/bap')
80
+ assert_equal false, sampling.ignore_uri?('/baz')
81
+ end
82
+
83
+ def test_web_request_individual_sampling
84
+ sampling = ScoutApm::Sampling.new(@individual_config)
85
+
86
+ # should be ignored
87
+ transaction = FakeTrackedRequest.new_web_request('/baz/bap')
88
+ assert_equal true, sampling.drop_request?(transaction)
89
+
90
+ # should be kept
91
+ transaction = FakeTrackedRequest.new_web_request('/faz/bap')
92
+ assert_equal false, sampling.drop_request?(transaction)
93
+
94
+ transaction = FakeTrackedRequest.new_web_request('/foo/far')
95
+ sampling.stub(:rand, 0.01) do
96
+ assert_equal false, sampling.drop_request?(transaction)
97
+ end
98
+
99
+ # passes individual sample but caught by global rate
100
+ sampling.stub(:rand, 0.99) do
101
+ assert_equal true, sampling.drop_request?(transaction)
102
+ end
103
+ end
104
+
105
+ def test_web_reqeust_general_sampling
106
+ config = FakeConfigOverlay.new(@individual_config.values.merge({'endpoint_sample_rate' => 80}))
107
+ sampling = ScoutApm::Sampling.new(config)
108
+
109
+ transaction = FakeTrackedRequest.new_web_request('/foo/far')
110
+ transaction2 = FakeTrackedRequest.new_web_request('/ooo/oar')
111
+ # /foo/far sampled at 50 specifically, /ooo/oar caught by general endpoint rate of 80
112
+ sampling.stub(:rand, 0.01) do
113
+ assert_equal false, sampling.drop_request?(transaction)
114
+ assert_equal false, sampling.drop_request?(transaction2)
115
+ end
116
+
117
+ sampling.stub(:rand, 0.70) do
118
+ assert_equal true, sampling.drop_request?(transaction)
119
+ assert_equal false, sampling.drop_request?(transaction2)
120
+ end
121
+
122
+ sampling.stub(:rand, 0.99) do
123
+ assert_equal true, sampling.drop_request?(transaction)
124
+ assert_equal true, sampling.drop_request?(transaction2)
125
+ end
126
+ end
127
+
128
+ def test_web_request_with_global_sampling
129
+ config = FakeConfigOverlay.new(@individual_config.values.merge({'sample_rate' => 20}))
130
+ sampling = ScoutApm::Sampling.new(config)
131
+
132
+ # caught by individual rate
133
+ transaction = FakeTrackedRequest.new_web_request('/foo/far')
134
+ sampling.stub(:rand, 0.01) do
135
+ assert_equal false, sampling.drop_request?(transaction)
136
+ end
137
+
138
+ # passes individual rate (50) but caught by global rate (20)
139
+ sampling.stub(:rand, 0.30) do
140
+ assert_equal false, sampling.drop_request?(transaction)
141
+ end
142
+
143
+ # passes individual rate
144
+ sampling.stub(:rand, 0.99) do
145
+ assert_equal true, sampling.drop_request?(transaction)
146
+ end
147
+
148
+ end
149
+
150
+ def test_job_request_individual_sampling
151
+ sampling = ScoutApm::Sampling.new(@individual_config)
152
+
153
+ # should be ignored
154
+ transaction = FakeTrackedRequest.new_job_request('jobb')
155
+ assert_equal true, sampling.drop_request?(transaction)
156
+
157
+ # should be kept
158
+ transaction = FakeTrackedRequest.new_job_request('jobz')
159
+ assert_equal false, sampling.drop_request?(transaction)
160
+
161
+ # should be sampled if rand > 50
162
+ transaction = FakeTrackedRequest.new_job_request('joba')
163
+ sampling.stub(:rand, 0.01) do
164
+ assert_equal false, sampling.drop_request?(transaction)
165
+ end
166
+
167
+ sampling.stub(:rand, 0.99) do
168
+ assert_equal true, sampling.drop_request?(transaction)
169
+ end
170
+ end
171
+
172
+ def test_job_general_sampling
173
+ config = FakeConfigOverlay.new(@individual_config.values.merge({'job_sample_rate' => 80}))
174
+ sampling = ScoutApm::Sampling.new(config)
175
+
176
+ transaction = FakeTrackedRequest.new_job_request('joba')
177
+ transaction2 = FakeTrackedRequest.new_job_request('jobz')
178
+ # joba sampled at 50 specifically, jobz caught by general job rate of 80
179
+ sampling.stub(:rand, 0.01) do
180
+ assert_equal false, sampling.drop_request?(transaction)
181
+ assert_equal false, sampling.drop_request?(transaction2)
182
+ end
183
+
184
+ sampling.stub(:rand, 0.70) do
185
+ assert_equal true, sampling.drop_request?(transaction)
186
+ assert_equal false, sampling.drop_request?(transaction2)
187
+ end
188
+
189
+ sampling.stub(:rand, 0.99) do
190
+ assert_equal true, sampling.drop_request?(transaction)
191
+ assert_equal true, sampling.drop_request?(transaction2)
192
+ end
193
+ end
194
+
195
+ def test_job_request_global_sampling
196
+ config = FakeConfigOverlay.new(@individual_config.values.merge({'sample_rate' => 20}))
197
+ sampling = ScoutApm::Sampling.new(config)
198
+
199
+ # caught by individual rate
200
+ transaction = FakeTrackedRequest.new_job_request('joba')
201
+ sampling.stub(:rand, 0.01) do
202
+ assert_equal false, sampling.drop_request?(transaction)
203
+ end
204
+
205
+ # passes individual rate (50) but caught by global rate (20)
206
+ sampling.stub(:rand, 0.30) do
207
+ assert_equal false, sampling.drop_request?(transaction)
208
+ end
209
+
210
+ # passes individual rate
211
+ sampling.stub(:rand, 0.99) do
212
+ assert_equal true, sampling.drop_request?(transaction)
213
+ end
214
+ end
215
+ end