newrelic_rpm 3.6.7.159 → 3.6.8.164

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/CHANGELOG +14 -0
  2. data/lib/new_relic/agent/agent.rb +38 -35
  3. data/lib/new_relic/agent/agent_logger.rb +6 -47
  4. data/lib/new_relic/agent/beacon_configuration.rb +10 -4
  5. data/lib/new_relic/agent/browser_monitoring.rb +39 -33
  6. data/lib/new_relic/agent/commands/agent_command.rb +4 -4
  7. data/lib/new_relic/agent/commands/agent_command_router.rb +72 -10
  8. data/lib/new_relic/agent/commands/thread_profiler_session.rb +110 -0
  9. data/lib/new_relic/agent/commands/xray_session.rb +55 -0
  10. data/lib/new_relic/agent/commands/xray_session_collection.rb +158 -0
  11. data/lib/new_relic/agent/configuration/default_source.rb +61 -24
  12. data/lib/new_relic/agent/configuration/mask_defaults.rb +2 -2
  13. data/lib/new_relic/agent/configuration/server_source.rb +1 -1
  14. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +2 -0
  15. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -10
  16. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +10 -11
  17. data/lib/new_relic/agent/memory_logger.rb +52 -0
  18. data/lib/new_relic/agent/new_relic_service.rb +4 -0
  19. data/lib/new_relic/agent/request_sampler.rb +32 -13
  20. data/lib/new_relic/agent/samplers/cpu_sampler.rb +6 -3
  21. data/lib/new_relic/agent/threading/agent_thread.rb +2 -1
  22. data/lib/new_relic/agent/threading/backtrace_node.rb +80 -27
  23. data/lib/new_relic/agent/threading/backtrace_service.rb +264 -0
  24. data/lib/new_relic/agent/threading/thread_profile.rb +79 -118
  25. data/lib/new_relic/agent/transaction/developer_mode_sample_buffer.rb +56 -0
  26. data/lib/new_relic/agent/transaction/force_persist_sample_buffer.rb +25 -0
  27. data/lib/new_relic/agent/transaction/slowest_sample_buffer.rb +25 -0
  28. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +86 -0
  29. data/lib/new_relic/agent/transaction/xray_sample_buffer.rb +64 -0
  30. data/lib/new_relic/agent/transaction.rb +25 -4
  31. data/lib/new_relic/agent/transaction_sample_builder.rb +6 -10
  32. data/lib/new_relic/agent/transaction_sampler.rb +47 -202
  33. data/lib/new_relic/agent/worker_loop.rb +47 -39
  34. data/lib/new_relic/agent.rb +1 -1
  35. data/lib/new_relic/build.rb +2 -2
  36. data/lib/new_relic/coerce.rb +8 -0
  37. data/lib/new_relic/control/instance_methods.rb +1 -0
  38. data/lib/new_relic/rack/browser_monitoring.rb +15 -1
  39. data/lib/new_relic/rack/developer_mode.rb +1 -1
  40. data/lib/new_relic/transaction_sample.rb +20 -5
  41. data/lib/new_relic/version.rb +1 -1
  42. data/newrelic.yml +4 -6
  43. data/newrelic_rpm.gemspec +1 -1
  44. data/test/agent_helper.rb +11 -0
  45. data/test/environments/lib/environments/runner.rb +5 -1
  46. data/test/environments/rails21/Gemfile +2 -2
  47. data/test/environments/rails22/Gemfile +2 -2
  48. data/test/environments/rails23/Gemfile +2 -2
  49. data/test/environments/rails31/Gemfile +2 -2
  50. data/test/environments/rails32/Gemfile +2 -2
  51. data/test/multiverse/suites/agent_only/marshaling_test.rb +1 -1
  52. data/test/multiverse/suites/agent_only/testing_app.rb +6 -0
  53. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +5 -5
  54. data/test/multiverse/suites/agent_only/xray_sessions_test.rb +163 -0
  55. data/test/multiverse/suites/rails/request_statistics_test.rb +2 -2
  56. data/test/multiverse/suites/rails/view_instrumentation_test.rb +20 -21
  57. data/test/new_relic/agent/agent/connect_test.rb +0 -10
  58. data/test/new_relic/agent/agent_test.rb +27 -44
  59. data/test/new_relic/agent/browser_monitoring_test.rb +0 -52
  60. data/test/new_relic/agent/commands/agent_command_router_test.rb +150 -12
  61. data/test/new_relic/agent/commands/{thread_profiler_test.rb → thread_profiler_session_test.rb} +58 -19
  62. data/test/new_relic/agent/commands/xray_session_collection_test.rb +332 -0
  63. data/test/new_relic/agent/commands/xray_session_test.rb +42 -0
  64. data/test/new_relic/agent/configuration/manager_test.rb +2 -1
  65. data/test/new_relic/agent/configuration/server_source_test.rb +10 -10
  66. data/test/new_relic/agent/cpu_sampler_test.rb +50 -0
  67. data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +31 -0
  68. data/test/new_relic/agent/instrumentation/queue_time_test.rb +0 -1
  69. data/test/new_relic/agent/instrumentation/sequel_test.rb +1 -1
  70. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +0 -1
  71. data/test/new_relic/agent/memory_logger_test.rb +53 -0
  72. data/test/new_relic/agent/new_relic_service_test.rb +1 -1
  73. data/test/new_relic/agent/pipe_channel_manager_test.rb +4 -5
  74. data/test/new_relic/agent/request_sampler_test.rb +70 -20
  75. data/test/new_relic/agent/rules_engine_test.rb +6 -0
  76. data/test/new_relic/agent/threading/agent_thread_test.rb +2 -2
  77. data/test/new_relic/agent/threading/backtrace_node_test.rb +110 -17
  78. data/test/new_relic/agent/threading/backtrace_service_test.rb +567 -0
  79. data/test/new_relic/agent/threading/fake_thread.rb +4 -0
  80. data/test/new_relic/agent/threading/thread_profile_test.rb +141 -217
  81. data/test/new_relic/agent/threading/threaded_test_case.rb +3 -8
  82. data/test/new_relic/agent/transaction/developer_mode_sample_buffer_test.rb +69 -0
  83. data/test/new_relic/agent/transaction/force_persist_sample_buffer_test.rb +52 -0
  84. data/test/new_relic/agent/transaction/slowest_sample_buffer_test.rb +67 -0
  85. data/test/new_relic/agent/transaction/xray_sample_buffer_test.rb +71 -0
  86. data/test/new_relic/agent/transaction_sampler_test.rb +171 -307
  87. data/test/new_relic/agent/transaction_test.rb +33 -5
  88. data/test/new_relic/agent/worker_loop_test.rb +33 -11
  89. data/test/new_relic/coerce_test.rb +13 -0
  90. data/test/new_relic/fake_collector.rb +26 -3
  91. data/test/new_relic/multiverse_helpers.rb +2 -0
  92. data/test/new_relic/rack/browser_monitoring_test.rb +12 -0
  93. data/test/new_relic/rack/developer_mode_test.rb +2 -2
  94. data/test/new_relic/transaction_sample_test.rb +19 -2
  95. data/test/performance/lib/performance/console_reporter.rb +1 -1
  96. data/test/performance/lib/performance/test_case.rb +7 -3
  97. data/test/performance/script/runner +3 -0
  98. data/test/performance/suites/thread_profiling.rb +83 -0
  99. data/test/test_helper.rb +2 -2
  100. data.tar.gz.sig +0 -0
  101. metadata +32 -32
  102. metadata.gz.sig +1 -1
  103. data/lib/new_relic/agent/commands/thread_profiler.rb +0 -80
@@ -4,23 +4,19 @@
4
4
 
5
5
  require 'new_relic/agent/threading/fake_thread'
6
6
 
7
- class ThreadedTestCase < Test::Unit::TestCase
8
- def setup
7
+ module ThreadedTestCase
8
+ def setup_fake_threads
9
9
  @original_thread_class = NewRelic::Agent::Threading::AgentThread
10
10
  swap_thread_class(FakeThread)
11
11
  end
12
12
 
13
- def teardown
13
+ def teardown_fake_threads
14
14
  swap_thread_class(@original_thread_class)
15
15
  @original_thread_class = nil
16
16
 
17
17
  FakeThread.list.clear
18
18
  end
19
19
 
20
- def default_test
21
- # no-op to keep quiet....
22
- end
23
-
24
20
  private
25
21
 
26
22
  def swap_thread_class(klass)
@@ -30,4 +26,3 @@ class ThreadedTestCase < Test::Unit::TestCase
30
26
  NewRelic::Agent::Threading.const_set("AgentThread", klass)
31
27
  end
32
28
  end
33
-
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','test_helper'))
6
+
7
+ class NewRelic::Agent::Transaction
8
+ class DeveloperModeSampleBufferTest < Test::Unit::TestCase
9
+ def setup
10
+ @buffer = DeveloperModeSampleBuffer.new
11
+ end
12
+
13
+ def test_store_sample_for_developer_mode_in_dev_mode
14
+ with_config(:developer_mode => true) do
15
+ sample = stub
16
+ @buffer.store(sample)
17
+ assert_equal([sample], @buffer.samples)
18
+ end
19
+ end
20
+
21
+ def test_store_sample_for_developer_mode_not_in_dev_mode
22
+ with_config(:developer_mode => false) do
23
+ @buffer.store(stub)
24
+ assert(@buffer.samples.empty?)
25
+ end
26
+ end
27
+
28
+ def test_stores_up_to_truncate_max
29
+ sample = stub
30
+ @buffer.max_samples.times { @buffer.store(sample) }
31
+
32
+ assert_equal(Array.new(@buffer.max_samples, sample), @buffer.samples)
33
+ end
34
+
35
+ def test_stores_and_truncates
36
+ sample = stub
37
+ (@buffer.max_samples * 2).times { @buffer.store(sample) }
38
+
39
+ assert_equal(Array.new(@buffer.max_samples, sample), @buffer.samples)
40
+ end
41
+
42
+ def test_visit_segment_takes_backtraces_in_dev_mode
43
+ with_config(:developer_mode => true) do
44
+ segment = {}
45
+ @buffer.visit_segment(segment)
46
+ assert segment[:backtrace].any? {|trace_line| trace_line.include?(__FILE__)}
47
+ end
48
+ end
49
+
50
+ def test_visit_segment_takes_backtraces_not_in_dev_mode
51
+ with_config(:developer_mode => false) do
52
+ segment = {}
53
+ @buffer.visit_segment(segment)
54
+ assert_nil segment[:backtrace]
55
+ end
56
+ end
57
+
58
+ def test_visit_segment_safe_against_nils
59
+ with_config(:developer_mode => true) do
60
+ @buffer.visit_segment(nil)
61
+ end
62
+ end
63
+
64
+ def test_doesnt_store_previous
65
+ @buffer.store_previous([stub])
66
+ assert @buffer.samples.empty?
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','test_helper'))
6
+
7
+ class NewRelic::Agent::Transaction
8
+ class ForcePersistSampleBufferTest < Test::Unit::TestCase
9
+ def setup
10
+ @buffer = ForcePersistSampleBuffer.new
11
+ end
12
+
13
+ def test_stores_forced_sample
14
+ sample = stub(:force_persist => true)
15
+ @buffer.store(sample)
16
+
17
+ assert_equal([sample], @buffer.samples)
18
+ end
19
+
20
+ def test_does_not_store_forced_sample
21
+ sample = stub(:force_persist => false)
22
+ @buffer.store(sample)
23
+
24
+ assert(@buffer.samples.empty?)
25
+ end
26
+
27
+ def test_harvest_samples
28
+ sample = stub(:force_persist => true)
29
+ @buffer.store(sample)
30
+
31
+ result = @buffer.harvest_samples
32
+
33
+ assert_equal([sample], result)
34
+ end
35
+
36
+ def test_harvest_samples_resets
37
+ sample = stub(:force_persist => true)
38
+ @buffer.store(sample)
39
+
40
+ @buffer.harvest_samples
41
+
42
+ assert(@buffer.samples.empty?)
43
+ end
44
+
45
+ def test_intermediate_storage_keeps_N_longest_samples
46
+ samples = (1..100).map { |i| stub(i.to_s, :force_persist => true, :duration => i) }
47
+ samples.each {|s| @buffer.store(s)}
48
+
49
+ assert_equal(samples.last(@buffer.max_samples), @buffer.samples)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','test_helper'))
6
+
7
+ class NewRelic::Agent::Transaction
8
+ class SlowestSampleBufferTest < Test::Unit::TestCase
9
+ def setup
10
+ @buffer = SlowestSampleBuffer.new
11
+ end
12
+
13
+ def test_store_sample
14
+ sample = stub(:duration => 2.0, :threshold => 1.0)
15
+ @buffer.store(sample)
16
+ assert_equal([sample], @buffer.samples)
17
+ end
18
+
19
+ def test_store_new_is_slowest
20
+ old_sample = stub(:duration => 3.0, :threshold => 1.0)
21
+ new_sample = stub(:duration => 4.0, :threshold => 1.0)
22
+
23
+ @buffer.store(old_sample)
24
+ @buffer.store(new_sample)
25
+
26
+ assert_equal([new_sample], @buffer.samples)
27
+ end
28
+
29
+ def test_store_new_is_faster
30
+ old_sample = stub(:duration => 4.0, :threshold => 1.0)
31
+ new_sample = stub(:duration => 3.0, :threshold => 1.0)
32
+
33
+ @buffer.store(old_sample)
34
+ @buffer.store(new_sample)
35
+
36
+ assert_equal([old_sample], @buffer.samples)
37
+ end
38
+
39
+ def test_store_does_not_store_if_faster_than_threshold
40
+ old_sample = stub('old', :duration => 1.0, :threshold => 0.5)
41
+ new_sample = stub('new', :duration => 2.0, :threshold => 4.0)
42
+
43
+ @buffer.store(old_sample)
44
+ @buffer.store(new_sample)
45
+
46
+ assert_equal([old_sample], @buffer.samples)
47
+ end
48
+
49
+ def test_harvest_samples
50
+ sample = stub(:duration => 1.0, :threshold => 1.0)
51
+ @buffer.store(sample)
52
+
53
+ harvested = @buffer.harvest_samples
54
+
55
+ assert_equal([sample], harvested)
56
+ end
57
+
58
+ def test_harvest_samples_resets
59
+ sample = stub(:duration => 1.0, :threshold => 1.0)
60
+ @buffer.store(sample)
61
+
62
+ @buffer.harvest_samples
63
+
64
+ assert(@buffer.samples.empty?)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under New Relic's license terms.
3
+ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
+
5
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','test_helper'))
6
+
7
+ class NewRelic::Agent::Transaction
8
+ class XraySampleBufferTest < Test::Unit::TestCase
9
+
10
+ XRAY_SESSION_ID = 123
11
+ MATCHING_TRANSACTION = "Matching/transaction/name"
12
+
13
+ def setup
14
+ @xray_session_collection = stub
15
+ @xray_session_collection.stubs(:session_id_for_transaction_name).with(any_parameters).returns(nil)
16
+ @xray_session_collection.stubs(:session_id_for_transaction_name).with(MATCHING_TRANSACTION).returns(XRAY_SESSION_ID)
17
+
18
+ @buffer = XraySampleBuffer.new
19
+ @buffer.xray_session_collection = @xray_session_collection
20
+ end
21
+
22
+ def test_doesnt_store_if_not_matching_transaction
23
+ sample = sample_with(:transaction_name => "Meaningless/transaction/name")
24
+ @buffer.store(sample)
25
+
26
+ assert @buffer.samples.empty?
27
+ end
28
+
29
+ def test_stores_if_matching_transaction
30
+ sample = sample_with(:transaction_name => MATCHING_TRANSACTION)
31
+ @buffer.store(sample)
32
+
33
+ assert_equal([sample], @buffer.samples)
34
+ end
35
+
36
+ def test_stores_and_marks_xray_session_id
37
+ sample = sample_with(:transaction_name => MATCHING_TRANSACTION)
38
+ @buffer.store(sample)
39
+
40
+ assert_equal(XRAY_SESSION_ID, sample.xray_session_id)
41
+ end
42
+
43
+ def test_limits_xray_traces
44
+ tons_o_samples = max_samples * 2
45
+ samples = (0..tons_o_samples).map do |i|
46
+ sample = sample_with(:transaction_name => MATCHING_TRANSACTION)
47
+ @buffer.store(sample)
48
+ sample
49
+ end
50
+
51
+ assert_equal(samples.first(max_samples), @buffer.samples)
52
+ end
53
+
54
+ def test_can_disable_via_config
55
+ with_config(:'xray_session.allow_traces' => false) do
56
+ assert_false @buffer.enabled?
57
+ end
58
+ end
59
+
60
+ def max_samples
61
+ NewRelic::Agent.config[:'xray_session.max_samples']
62
+ end
63
+
64
+ def sample_with(opts={})
65
+ sample = NewRelic::TransactionSample.new
66
+ sample.transaction_name = opts[:transaction_name]
67
+ sample
68
+ end
69
+
70
+ end
71
+ end
@@ -45,47 +45,6 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
45
45
  NewRelic::Agent.instance.instance_variable_set(:@transaction_sampler, @old_sampler)
46
46
  end
47
47
 
48
- def test_initialize
49
- defaults = {
50
- :samples => [],
51
- :harvest_count => 0,
52
- :max_samples => 100,
53
- :random_sample => nil,
54
- }
55
- defaults.each do |variable, default_value|
56
- assert_equal(default_value, @sampler.instance_variable_get('@' + variable.to_s))
57
- end
58
-
59
- lock = @sampler.instance_variable_get('@samples_lock')
60
- assert(lock.is_a?(Mutex), "Samples lock should be a mutex, is: #{lock.inspect}")
61
- end
62
-
63
- def test_current_sample_id_default
64
- builder = mock('builder')
65
- builder.expects(:sample_id).returns(11111)
66
- @sampler.expects(:builder).returns(builder)
67
- assert_equal(11111, @sampler.current_sample_id)
68
- end
69
-
70
- def test_current_sample_id_no_builder
71
- @sampler.expects(:builder).returns(nil)
72
- assert_equal(nil, @sampler.current_sample_id)
73
- end
74
-
75
- def test_sampling_rate_equals_default
76
- @sampler.sampling_rate = 1
77
- assert_equal(1, @sampler.instance_variable_get('@sampling_rate'))
78
- # rand(1) is always zero, so we can be sure here
79
- assert_equal(0, @sampler.instance_variable_get('@harvest_count'))
80
- end
81
-
82
- def test_sampling_rate_equals_with_a_float
83
- @sampler.sampling_rate = 5.5
84
- assert_equal(5, @sampler.instance_variable_get('@sampling_rate'))
85
- harvest_count = @sampler.instance_variable_get('@harvest_count')
86
- assert((0..4).include?(harvest_count), "should be in the range 0..4")
87
- end
88
-
89
48
  def test_notice_first_scope_push_default
90
49
  @sampler.expects(:start_builder).with(100.0)
91
50
  @sampler.notice_first_scope_push(Time.at(100))
@@ -113,38 +72,16 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
113
72
  end
114
73
  end
115
74
 
116
- def test_notice_push_scope_in_dev_mode
117
- builder = mock('builder')
118
- builder.expects(:trace_entry).with(100.0)
119
- @sampler.expects(:builder).returns(builder).twice
120
- @sampler.expects(:capture_segment_trace)
121
-
122
- @sampler.notice_push_scope(Time.at(100))
123
- end
124
-
125
- def test_scope_depth_no_builder
126
- @sampler.expects(:builder).returns(nil)
127
- assert_equal(0, @sampler.scope_depth, "should default to zero with no builder")
128
- end
129
-
130
- def test_scope_depth_with_builder
131
- builder = mock('builder')
132
- builder.expects(:scope_depth).returns('scope_depth')
133
- @sampler.expects(:builder).returns(builder).twice
134
-
135
- assert_equal('scope_depth', @sampler.scope_depth, "should delegate scope depth to the builder")
136
- end
137
-
138
75
  def test_notice_pop_scope_no_builder
139
76
  @sampler.expects(:builder).returns(nil)
140
77
  assert_equal(nil, @sampler.notice_pop_scope('a scope', Time.at(100)))
141
78
  end
142
79
 
143
- def test_notice_pop_scope_with_frozen_sample
80
+ def test_notice_pop_scope_with_finished_sample
144
81
  builder = mock('builder')
145
82
  sample = mock('sample')
146
83
  builder.expects(:sample).returns(sample)
147
- sample.expects(:frozen?).returns(true)
84
+ sample.expects(:finished).returns(true)
148
85
  @sampler.expects(:builder).returns(builder).twice
149
86
 
150
87
  assert_raise(RuntimeError) do
@@ -157,7 +94,7 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
157
94
  builder.expects(:trace_exit).with('a scope', 100.0)
158
95
  sample = mock('sample')
159
96
  builder.expects(:sample).returns(sample)
160
- sample.expects(:frozen?).returns(false)
97
+ sample.expects(:finished).returns(false)
161
98
  @sampler.expects(:builder).returns(builder).times(3)
162
99
 
163
100
  @sampler.notice_pop_scope('a scope', Time.at(100))
@@ -205,111 +142,6 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
205
142
  assert_equal(sample, @sampler.instance_variable_get('@last_sample'))
206
143
  end
207
144
 
208
- def test_store_random_sample_no_random_sampling
209
- with_config(:'transaction_tracer.random_sample' => false) do
210
- assert_equal(nil, @sampler.instance_variable_get('@random_sample'))
211
- @sampler.store_random_sample(mock('sample'))
212
- assert_equal(nil, @sampler.instance_variable_get('@random_sample'))
213
- end
214
- end
215
-
216
- def test_store_random_sample_random_sampling
217
- with_config(:'transaction_tracer.random_sample' => true) do
218
- sample = mock('sample')
219
- assert_equal(nil, @sampler.instance_variable_get('@random_sample'))
220
- @sampler.store_random_sample(sample)
221
- assert_equal(sample, @sampler.instance_variable_get('@random_sample'))
222
- end
223
- end
224
-
225
- def test_store_sample_for_developer_mode_in_dev_mode
226
- sample = mock('sample')
227
- @sampler.expects(:truncate_samples)
228
- @sampler.store_sample_for_developer_mode(sample)
229
- assert_equal([sample], @sampler.instance_variable_get('@samples'))
230
- end
231
-
232
- def test_store_sample_for_developer_mode_no_dev
233
- with_config(:developer_mode => false) do
234
- sample = mock('sample')
235
- @sampler.store_sample_for_developer_mode(sample)
236
- assert_equal([], @sampler.instance_variable_get('@samples'))
237
- end
238
- end
239
-
240
- def test_store_slowest_sample_new_is_slowest
241
- old_sample = stub('old_sample', :duration => 3.0, :threshold => 1.0)
242
- new_sample = stub('new_sample', :duration => 4.0, :threshold => 1.0)
243
- @sampler.instance_eval { @slowest_sample = old_sample }
244
-
245
- @sampler.store_slowest_sample(new_sample)
246
-
247
- assert_equal(new_sample, @sampler.instance_variable_get('@slowest_sample'))
248
- end
249
-
250
- def test_store_slowest_sample_not_slowest
251
- old_sample = mock('old_sample')
252
- new_sample = mock('new_sample')
253
- @sampler.instance_eval { @slowest_sample = old_sample }
254
- @sampler.expects(:slowest_sample?).with(old_sample, new_sample).returns(false)
255
-
256
- @sampler.store_slowest_sample(new_sample)
257
-
258
- assert_equal(old_sample, @sampler.instance_variable_get('@slowest_sample'))
259
- end
260
-
261
- def test_store_slowest_sample_does_not_store_if_faster_than_threshold
262
- old_sample = stub('old_sample', :duration => 1.0, :threshold => 0.5)
263
- new_sample = stub('new_sample', :duration => 2.0, :threshold => 4.0)
264
- @sampler.instance_eval { @slowest_sample = old_sample }
265
- @sampler.store_slowest_sample(new_sample)
266
-
267
- assert_equal(old_sample, @sampler.instance_variable_get('@slowest_sample'))
268
- end
269
-
270
- def test_slowest_sample_no_sample
271
- old_sample = nil
272
- new_sample = mock('new_sample')
273
- assert_equal(true, @sampler.slowest_sample?(old_sample, new_sample))
274
- end
275
-
276
- def test_slowest_sample_faster_sample
277
- old_sample = mock('old_sample')
278
- new_sample = mock('new_sample')
279
- old_sample.expects(:duration).returns(1.0)
280
- new_sample.expects(:duration).returns(0.5)
281
- assert_equal(false, @sampler.slowest_sample?(old_sample, new_sample))
282
- end
283
-
284
- def test_slowest_sample_slower_sample
285
- old_sample = mock('old_sample')
286
- new_sample = mock('new_sample')
287
- old_sample.expects(:duration).returns(0.5)
288
- new_sample.expects(:duration).returns(1.0)
289
- assert_equal(true, @sampler.slowest_sample?(old_sample, new_sample))
290
- end
291
-
292
- def test_truncate_samples_no_samples
293
- @sampler.instance_eval { @max_samples = 10 }
294
- @sampler.instance_eval { @samples = [] }
295
- @sampler.truncate_samples
296
- assert_equal([], @sampler.instance_variable_get('@samples'))
297
- end
298
-
299
- def test_truncate_samples_equal_samples
300
- @sampler.instance_eval { @max_samples = 2 }
301
- @sampler.instance_eval { @samples = [1, 2] }
302
- @sampler.truncate_samples
303
- assert_equal([1, 2], @sampler.instance_variable_get('@samples'))
304
- end
305
-
306
- def test_truncate_samples_extra_samples
307
- @sampler.instance_eval { @max_samples = 2 }
308
- @sampler.instance_eval { @samples = [1, 2, 3] }
309
- @sampler.truncate_samples
310
- assert_equal([2, 3], @sampler.instance_variable_get('@samples'))
311
- end
312
-
313
145
  def test_ignore_transaction_no_builder
314
146
  @sampler.expects(:builder).returns(nil).once
315
147
  @sampler.ignore_transaction
@@ -446,154 +278,166 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
446
278
  def test_harvest_defaults
447
279
  # making sure the sampler clears out the old samples
448
280
  @sampler.instance_eval do
449
- @slowest_sample = 'a sample'
450
- @random_sample = 'a sample'
451
281
  @last_sample = 'a sample'
452
282
  end
453
283
 
454
- @sampler.expects(:add_samples_to).with([]).returns([])
284
+ @sampler.expects(:choose_samples).with([]).returns([])
455
285
 
456
286
  assert_equal([], @sampler.harvest)
457
287
 
458
288
  # make sure the samples have been cleared
459
- assert_equal(nil, @sampler.instance_variable_get('@slowest_sample'))
460
- assert_equal(nil, @sampler.instance_variable_get('@random_sample'))
461
289
  assert_equal(nil, @sampler.instance_variable_get('@last_sample'))
462
290
  end
463
291
 
464
292
  def test_harvest_with_previous_samples
465
293
  with_config(:'transaction_tracer.limit_segments' => 2000) do
466
294
  sample = mock('sample')
467
- @sampler.expects(:add_samples_to).with([sample]).returns([sample])
295
+ @sampler.expects(:choose_samples).with([sample]).returns([sample])
468
296
  assert_equal([sample], @sampler.harvest([sample]))
469
297
  end
470
298
  end
471
299
 
472
- def test_add_random_sample_to_not_random_sampling
473
- @sampler.instance_eval { @random_sampling = false }
474
- result = []
475
- @sampler.add_random_sample_to(result)
476
- assert_equal([], result, "should not add anything to the array if we are not random sampling")
300
+ def test_harvest_no_data
301
+ previous = []
302
+ assert_equal([], @sampler.harvest(previous))
477
303
  end
478
304
 
479
- def test_add_random_sample_to_no_random_sample
480
- @sampler.instance_eval { @random_sampling = true }
481
- @sampler.instance_eval {
482
- @harvest_count = 1
483
- @sampling_rate = 2
484
- @random_sample = nil
485
- }
486
- result = []
487
- @sampler.add_random_sample_to(result)
488
- assert_equal([], result, "should not add sample to the array when it is nil")
305
+ def test_add_samples_holds_onto_previous_result
306
+ sample = sample_with(:duration => 1)
307
+ previous = [sample]
308
+ assert_equal([sample], @sampler.harvest(previous))
489
309
  end
490
310
 
491
- def test_add_random_sample_to_not_active
492
- @sampler.instance_eval { @random_sampling = true }
493
- sample = mock('sample')
494
- @sampler.instance_eval {
495
- @harvest_count = 4
496
- @sampling_rate = 40 # 4 % 40 = 4, so the sample should not be added
497
- @random_sample = sample
498
- }
499
- result = []
500
- @sampler.add_random_sample_to(result)
501
- assert_equal([], result, "should not add samples to the array when harvest count is not moduli sampling rate")
311
+ def test_add_samples_avoids_dups_from_previous
312
+ sample = sample_with(:duration => 1)
313
+ previous = [sample, sample]
314
+ assert_equal([sample], @sampler.harvest(previous))
502
315
  end
503
316
 
504
- def test_add_random_sample_to_activated
505
- with_config(:'transaction_tracer.random_sample' => true, :sample_rate => 1) do
506
- sample = mock('sample')
507
- @sampler.instance_eval {
508
- @harvest_count = 3
509
- @random_sample = sample
510
- }
511
- result = []
512
- @sampler.add_random_sample_to(result)
513
- assert_equal([sample], result, "should add the random sample to the array")
514
- end
317
+ def test_harvest_avoids_dups_from_harvested_samples
318
+ sample = sample_with(:duration => 2.5, :force_persist => false)
319
+ @sampler.store_sample(sample)
320
+ @sampler.store_sample(sample)
321
+
322
+ assert_equal([sample], @sampler.harvest([]))
515
323
  end
516
324
 
517
- def test_add_random_sample_to_sampling_rate_zero
518
- @sampler.instance_eval { @random_sampling = true }
519
- sample = mock('sample')
520
- @sampler.instance_eval {
521
- @harvest_count = 3
522
- @sampling_rate = 0
523
- @random_sample = sample
524
- }
525
- result = []
526
- @sampler.add_random_sample_to(result)
527
- assert_equal([], result, "should not add the sample to the array")
325
+ def test_add_samples_avoids_dups_from_forced
326
+ sample = sample_with(:duration => 1, :force_persist => true)
327
+ previous = [sample, sample]
328
+ assert_equal([sample], @sampler.harvest(previous))
528
329
  end
529
330
 
530
- def test_add_samples_to_no_data
531
- result = []
532
- @sampler.instance_eval { @slowest_sample = nil }
533
- @sampler.expects(:add_random_sample_to).with([])
534
- assert_equal([], @sampler.add_samples_to(result))
331
+ def test_harvest_adding_slowest
332
+ sample = sample_with(:duration => 2.5, :force_persist => false)
333
+ @sampler.store_sample(sample)
334
+
335
+ assert_equal([sample], @sampler.harvest([]))
535
336
  end
536
337
 
537
- def test_add_samples_to_one_result
538
- sample = mock('sample')
539
- sample.expects(:duration).returns(1).at_least_once
540
- sample.stubs(:force_persist).returns(false)
541
- result = [sample]
542
- @sampler.instance_eval { @slowest_sample = nil }
543
- @sampler.expects(:add_random_sample_to).with([sample])
544
- assert_equal([sample], @sampler.add_samples_to(result))
338
+ def test_harvest_new_slower_sample_replaces_older
339
+ faster_sample = sample_with(:duration => 5.0)
340
+ previous = [faster_sample]
341
+
342
+ slower_sample = sample_with(:duration => 10.0)
343
+ @sampler.store_sample(slower_sample)
344
+
345
+ assert_equal([slower_sample], @sampler.harvest(previous))
545
346
  end
546
347
 
547
- def test_add_samples_to_adding_slowest
548
- sample = mock('sample')
549
- sample.expects(:duration).returns(2.5).at_least_once
550
- result = []
551
- @sampler.instance_variable_set(:@slowest_sample, sample)
552
- @sampler.expects(:add_random_sample_to).with([sample])
553
- with_config(:'transaction_tracer.transaction_threshold' => 2) do
554
- assert_equal([sample], @sampler.add_samples_to(result))
555
- end
348
+ def test_harvest_keep_older_slower_sample
349
+ faster_sample = sample_with(:duration => 5.0)
350
+ @sampler.store_sample(faster_sample)
351
+
352
+ slower_sample = sample_with(:duration => 10.0)
353
+ previous = [slower_sample]
354
+
355
+ assert_equal([slower_sample], @sampler.harvest(previous))
556
356
  end
557
357
 
558
- def test_add_samples_to_two_sample_enter_one_sample_leave
559
- slower_sample = mock('slower')
560
- slower_sample.expects(:duration).returns(10.0).at_least_once
561
- faster_sample = mock('faster')
562
- faster_sample.expects(:duration).returns(5.0).at_least_once
563
- faster_sample.stubs(:force_persist).returns(false)
564
- result = [faster_sample]
565
- @sampler.instance_eval { @slowest_sample = slower_sample }
566
- @sampler.expects(:add_random_sample_to).with([slower_sample])
567
- assert_equal([slower_sample], @sampler.add_samples_to(result))
358
+ def test_harvest_keep_force_persist_in_previous_results
359
+ unforced_sample = sample_with(:duration => 10, :force_persist => false)
360
+ forced_sample = sample_with(:duration => 1, :force_persist => true)
361
+
362
+ result = @sampler.harvest([unforced_sample, forced_sample])
363
+
364
+ assert_includes(result, unforced_sample)
365
+ assert_includes(result, forced_sample)
568
366
  end
569
367
 
570
- def test_add_samples_to_keep_older_slower_sample
571
- slower_sample = mock('slower')
572
- slower_sample.expects(:duration).returns(10.0).at_least_once
573
- slower_sample.stubs(:force_persist).returns(false)
368
+ def test_harvest_keeps_force_persist_in_new_results
369
+ forced_sample = sample_with(:duration => 1, :force_persist => true)
370
+ @sampler.store_sample(forced_sample)
371
+
372
+ unforced_sample = sample_with(:duration => 10, :force_persist => false)
373
+ @sampler.store_sample(unforced_sample)
374
+
375
+ result = @sampler.harvest([])
574
376
 
575
- faster_sample = mock('faster')
576
- faster_sample.expects(:duration).returns(5.0).at_least_once
577
- result = [slower_sample]
578
- @sampler.instance_eval { @slowest_sample = faster_sample }
579
- @sampler.expects(:add_random_sample_to).with([slower_sample])
580
- assert_equal([slower_sample], @sampler.add_samples_to(result))
377
+ assert_includes(result, unforced_sample)
378
+ assert_includes(result, forced_sample)
581
379
  end
582
380
 
583
- def test_keep_force_persist
584
- sample1 = mock('regular')
585
- sample1.stubs(:duration).returns(10)
586
- sample1.stubs(:force_persist).returns(false)
381
+ def test_harvest_keeps_forced_from_new_and_previous_results
382
+ new_forced = sample_with(:duration => 1, :force_persist => true)
383
+ @sampler.store_sample(new_forced)
587
384
 
588
- sample2 = mock('force_persist')
589
- sample2.stubs(:duration).returns(1)
590
- sample2.stubs(:force_persist).returns(true)
385
+ old_forced = sample_with(:duration => 1, :force_persist => true)
591
386
 
592
- result = @sampler.add_samples_to([sample1,sample2])
387
+ result = @sampler.harvest([old_forced])
593
388
 
594
- assert_equal 2, result.length
595
- assert_equal sample1, result[0]
596
- assert_equal sample2, result[1]
389
+ assert_includes(result, new_forced)
390
+ assert_includes(result, old_forced)
391
+ end
392
+
393
+ FORCE_PERSIST_MAX = NewRelic::Agent::Transaction::ForcePersistSampleBuffer::MAX_SAMPLES
394
+ SLOWEST_SAMPLE_MAX = NewRelic::Agent::Transaction::SlowestSampleBuffer::MAX_SAMPLES
395
+ XRAY_SAMPLE_MAX = NewRelic::Agent.config[:'xray_session.max_samples']
396
+
397
+ def test_harvest_respects_limits_from_previous
398
+ slowest = sample_with(:duration => 10.0)
399
+ previous = [slowest]
400
+
401
+ forced_samples = generate_samples(100, :force_persist => true)
402
+ previous.concat(forced_samples)
403
+
404
+ xray_samples = generate_samples(100, :transaction_name => "Active/xray")
405
+ previous.concat(xray_samples)
406
+
407
+ result = nil
408
+ with_active_xray_session("Active/xray") do
409
+ result = @sampler.harvest(previous)
410
+ end
411
+
412
+ expected = [slowest]
413
+ expected = expected.concat(forced_samples.last(FORCE_PERSIST_MAX))
414
+ expected = expected.concat(xray_samples.first(XRAY_SAMPLE_MAX))
415
+
416
+ assert_equal_unordered(expected, result)
417
+ end
418
+
419
+ def test_harvest_respects_limits_from_current_traces
420
+ slowest = sample_with(:duration => 10.0)
421
+ @sampler.store_sample(slowest)
422
+
423
+ forced_samples = generate_samples(100, :force_persist => true)
424
+ forced_samples.each do |forced|
425
+ @sampler.store_sample(forced)
426
+ end
427
+
428
+ xray_samples = generate_samples(100, :transaction_name => "Active/xray")
429
+ with_active_xray_session("Active/xray") do
430
+ xray_samples.each do |xrayed|
431
+ @sampler.store_sample(xrayed)
432
+ end
433
+ end
434
+
435
+ result = @sampler.harvest([])
436
+
437
+ expected = [slowest]
438
+ expected = expected.concat(forced_samples.last(FORCE_PERSIST_MAX))
439
+ expected = expected.concat(xray_samples.first(XRAY_SAMPLE_MAX))
440
+ assert_equal_unordered(expected, result)
597
441
  end
598
442
 
599
443
  def test_start_builder_default
@@ -639,21 +483,9 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
639
483
  # unit tests per se - some overlap with the tests above, but
640
484
  # generally usefully so
641
485
 
642
- def test_multiple_samples
643
- run_sample_trace
644
- run_sample_trace
645
- run_sample_trace
646
- run_sample_trace
647
-
648
- samples = @sampler.samples
649
- assert_equal 4, samples.length
650
- assert_equal "a", samples.first.root_segment.called_segments[0].metric_name
651
- assert_equal "a", samples.last.root_segment.called_segments[0].metric_name
652
- end
653
486
 
654
487
  def test_sample_tree
655
488
  with_config(:'transaction_tracer.transaction_threshold' => 0.0) do
656
- assert_equal 0, @sampler.scope_depth
657
489
  @sampler.notice_first_scope_push Time.now.to_f
658
490
  @sampler.notice_transaction(nil, {})
659
491
  @sampler.notice_push_scope
@@ -678,7 +510,6 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
678
510
  # These are effectively Garbage Collects, detected each time GC.time is
679
511
  # called by the transaction sampler. One time value in seconds for each call.
680
512
  MockGCStats.mock_values = [0,0,0,1,0,0,1,0,0,0,0,0,0,0,0]
681
- assert_equal 0, @sampler.scope_depth
682
513
 
683
514
  with_config(:'transaction_tracer.transaction_threshold' => 0.0) do
684
515
  @sampler.notice_first_scope_push Time.now.to_f
@@ -703,13 +534,6 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
703
534
  MockGCStats.mock_values = []
704
535
  end
705
536
 
706
- def test_sample_id
707
- run_sample_trace do
708
- assert((@sampler.current_sample_id && @sampler.current_sample_id != 0), @sampler.current_sample_id.to_s + ' should not be zero')
709
- end
710
- end
711
-
712
-
713
537
  # NB this test occasionally fails due to a GC during one of the
714
538
  # sample traces, for example. It's unfortunate, but we can't
715
539
  # reliably turn off GC on all versions of ruby under test
@@ -729,12 +553,12 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
729
553
 
730
554
  # 1 second duration
731
555
  run_sample_trace(0,1)
732
- not_as_slow = @sampler.harvest(slowest)[0]
556
+ not_as_slow = @sampler.harvest([slowest])[0]
733
557
  assert((not_as_slow == slowest), "Should re-harvest the same transaction since it should be slower than the new transaction - expected #{slowest.inspect} but got #{not_as_slow.inspect}")
734
558
 
735
559
  run_sample_trace(0,10)
736
560
 
737
- new_slowest = @sampler.harvest(slowest)[0]
561
+ new_slowest = @sampler.harvest([slowest])[0]
738
562
  assert((new_slowest != slowest), "Should not harvest the same trace since the new one should be slower")
739
563
  assert_equal(new_slowest.duration.round, 10, "Slowest duration must be = 10, but was: #{new_slowest.duration.inspect}")
740
564
  end
@@ -770,17 +594,16 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
770
594
 
771
595
  def test_sample_with_parallel_paths
772
596
  with_config(:'transaction_tracer.transaction_threshold' => 0.0) do
773
- assert_equal 0, @sampler.scope_depth
774
597
  @sampler.notice_first_scope_push Time.now.to_f
775
598
  @sampler.notice_transaction(nil, {})
776
599
  @sampler.notice_push_scope
777
600
 
778
- assert_equal 1, @sampler.scope_depth
601
+ assert_equal 1, @sampler.builder.scope_depth
779
602
 
780
603
  @sampler.notice_pop_scope "a"
781
604
  @sampler.notice_scope_empty(@txn)
782
605
 
783
- assert_equal 0, @sampler.scope_depth
606
+ assert_nil @sampler.builder
784
607
 
785
608
  @sampler.notice_first_scope_push Time.now.to_f
786
609
  @sampler.notice_transaction(nil, {})
@@ -788,9 +611,9 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
788
611
  @sampler.notice_pop_scope "a"
789
612
  @sampler.notice_scope_empty(@txn)
790
613
 
791
- assert_equal 0, @sampler.scope_depth
792
- sample = @sampler.harvest(nil).first
793
- assert_equal "ROOT{a}", sample.to_s_compact
614
+ assert_nil @sampler.builder
615
+
616
+ assert_equal "ROOT{a}", @sampler.last_sample.to_s_compact
794
617
  end
795
618
  end
796
619
 
@@ -913,7 +736,7 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
913
736
  @sampler.notice_pop_scope "a11"
914
737
  @sampler.notice_pop_scope "a1"
915
738
  end
916
- assert_equal 3, @sampler.samples[0].count_segments
739
+ assert_equal 3, @sampler.last_sample.count_segments
917
740
  end
918
741
  end
919
742
 
@@ -995,6 +818,47 @@ class NewRelic::Agent::TransactionSamplerTest < Test::Unit::TestCase
995
818
 
996
819
  private
997
820
 
821
+ SAMPLE_DEFAULTS = {
822
+ :threshold => 1.0,
823
+ :force_persist => false,
824
+ :transaction_name => nil
825
+ }
826
+
827
+ def sample_with(incoming_opts = {})
828
+ opts = SAMPLE_DEFAULTS.dup
829
+ opts.merge!(incoming_opts)
830
+
831
+ sample = NewRelic::TransactionSample.new
832
+ sample.threshold = opts[:threshold]
833
+ sample.force_persist = opts[:force_persist]
834
+ sample.transaction_name = opts[:transaction_name]
835
+ sample.stubs(:duration).returns(opts[:duration])
836
+ sample
837
+ end
838
+
839
+ def generate_samples(count, opts = {})
840
+ (1..count).map do |millis|
841
+ sample_with(opts.merge(:duration => (millis / 1000.0)))
842
+ end
843
+ end
844
+
845
+ def with_active_xray_session(name)
846
+ xray_session_id = 1234
847
+ xray_session = NewRelic::Agent::Commands::XraySession.new({
848
+ "x_ray_id" => xray_session_id,
849
+ "key_transaction_name" => name,
850
+ "run_profiler" => false
851
+ })
852
+
853
+ xray_session_collection = NewRelic::Agent.instance.agent_command_router.xray_session_collection
854
+ xray_session_collection.send(:add_session, xray_session)
855
+ @sampler.xray_sample_buffer.xray_session_collection = xray_session_collection
856
+
857
+ yield
858
+ ensure
859
+ xray_session_collection.send(:remove_session_by_id, xray_session_id)
860
+ end
861
+
998
862
  def run_long_sample_trace(n)
999
863
  @sampler.notice_transaction(nil, {})
1000
864
  @sampler.notice_first_scope_push(Time.now.to_f)