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
@@ -7,11 +7,11 @@ require 'base64'
7
7
  require 'thread'
8
8
  require 'timeout'
9
9
  require 'zlib'
10
+ require 'new_relic/agent/threading/backtrace_service'
10
11
  require 'new_relic/agent/threading/threaded_test_case'
11
- require 'new_relic/agent/commands/thread_profiler'
12
- #require 'test/new_relic/agent/commands/agent_command_test'
12
+ require 'new_relic/agent/commands/thread_profiler_session'
13
13
 
14
- module ThreadProfilerTestHelpers
14
+ module ThreadProfilerSessionTestHelpers
15
15
  START = {
16
16
  "profile_id" => 42,
17
17
  "sample_period" => 0.02,
@@ -43,17 +43,18 @@ module ThreadProfilerTestHelpers
43
43
  end
44
44
  end
45
45
 
46
- if !NewRelic::Agent::Commands::ThreadProfiler.is_supported?
46
+ if !NewRelic::Agent::Threading::BacktraceService.is_supported?
47
47
 
48
48
  class ThreadProfilerUnsupportedTest < Test::Unit::TestCase
49
- include ThreadProfilerTestHelpers
49
+ include ThreadProfilerSessionTestHelpers
50
50
 
51
51
  def setup
52
- @profiler = NewRelic::Agent::Commands::ThreadProfiler.new
52
+ backtrace_service = NewRelic::Agent::Threading::BacktraceService.new
53
+ @profiler = NewRelic::Agent::Commands::ThreadProfilerSession.new(backtrace_service)
53
54
  end
54
55
 
55
56
  def test_thread_profiling_isnt_supported
56
- assert_equal false, NewRelic::Agent::Commands::ThreadProfiler.is_supported?
57
+ assert_equal false, NewRelic::Agent::Threading::BacktraceService.is_supported?
57
58
  end
58
59
 
59
60
  def test_stop_is_safe_when_not_supported
@@ -75,20 +76,28 @@ else
75
76
 
76
77
  require 'json'
77
78
 
78
- class ThreadProfilerTest < ThreadedTestCase
79
- include ThreadProfilerTestHelpers
79
+ class ThreadProfilerSessionTest < Test::Unit::TestCase
80
+ include ThreadedTestCase
81
+ include ThreadProfilerSessionTestHelpers
80
82
 
81
83
  def setup
82
- super
83
- @profiler = NewRelic::Agent::Commands::ThreadProfiler.new
84
+ setup_fake_threads
85
+ backtrace_service = NewRelic::Agent::Threading::BacktraceService.new
86
+ backtrace_service.worker_loop.stubs(:run).returns(nil)
87
+ @profiler = NewRelic::Agent::Commands::ThreadProfilerSession.new(backtrace_service)
88
+ end
89
+
90
+ def teardown
91
+ NewRelic::Agent.instance.stats_engine.clear_stats
92
+ teardown_fake_threads
84
93
  end
85
94
 
86
95
  def test_is_supported
87
- assert NewRelic::Agent::Commands::ThreadProfiler.is_supported?
96
+ assert NewRelic::Agent::Threading::BacktraceService.is_supported?
88
97
  end
89
98
 
90
99
  def test_is_not_running
91
- assert !@profiler.running?
100
+ assert_false @profiler.running?
92
101
  end
93
102
 
94
103
  def test_is_running
@@ -96,8 +105,17 @@ else
96
105
  assert @profiler.running?
97
106
  end
98
107
 
99
- def test_is_not_finished_if_no_profile_started
100
- assert !@profiler.finished?
108
+ def test_is_not_ready_to_harvest_if_no_profile_started
109
+ assert_false @profiler.ready_to_harvest?
110
+ end
111
+
112
+ def test_is_ready_to_harvest_if_duration_has_elapsed
113
+ freeze_time
114
+ @profiler.start(start_command)
115
+ assert_false @profiler.ready_to_harvest?
116
+
117
+ advance_time(0.026)
118
+ assert @profiler.ready_to_harvest?
101
119
  end
102
120
 
103
121
  def test_can_stop_a_running_profile
@@ -105,8 +123,8 @@ else
105
123
  assert @profiler.running?
106
124
 
107
125
  @profiler.stop(true)
126
+ assert_false @profiler.running?
108
127
 
109
- assert @profiler.finished?
110
128
  assert_not_nil @profiler.harvest
111
129
  end
112
130
 
@@ -129,12 +147,21 @@ else
129
147
  assert_equal true, @profiler.running?
130
148
  end
131
149
 
150
+ def test_config_can_disable_running
151
+ with_config(:'thread_profiler.enabled' => false) do
152
+ assert_raise NewRelic::Agent::Commands::AgentCommandRouter::AgentCommandError do
153
+ @profiler.handle_start_command(start_command)
154
+ end
155
+ assert_false @profiler.running?
156
+ end
157
+ end
158
+
132
159
  def test_handle_stop_command
133
160
  @profiler.start(start_command)
134
161
  assert @profiler.running?
135
162
 
136
163
  @profiler.handle_stop_command(stop_command)
137
- assert_equal true, @profiler.finished?
164
+ assert_false @profiler.running?
138
165
  end
139
166
 
140
167
  def test_handle_stop_command_and_discard
@@ -165,12 +192,24 @@ else
165
192
  end
166
193
  end
167
194
 
195
+ def test_harvested_profile_doesnt_still_report_as_ready_to_harvest
196
+ freeze_time
197
+ @profiler.handle_start_command(start_command)
198
+
199
+ advance_time(1.0)
200
+ @profiler.stop(true)
201
+ assert @profiler.ready_to_harvest?
202
+
203
+ @profiler.harvest
204
+ assert_false @profiler.ready_to_harvest?
205
+ end
206
+
168
207
  def test_command_attributes_passed_along
169
208
  @profiler.handle_start_command(start_command)
209
+ @profiler.handle_stop_command(stop_command)
170
210
  profile = @profiler.harvest
171
211
  assert_equal 42, profile.profile_id
172
- assert_equal 0.02, profile.interval
173
- assert_equal false, profile.profile_agent_code
212
+ assert_equal 0.02, profile.requested_period
174
213
  end
175
214
 
176
215
  end
@@ -0,0 +1,332 @@
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
+ require 'new_relic/agent/commands/xray_session_collection'
7
+
8
+ module NewRelic::Agent::Commands
9
+ class XraySessionCollectionTest < Test::Unit::TestCase
10
+
11
+ attr_reader :sessions, :service
12
+
13
+ FIRST_ID = 123
14
+ FIRST_NAME = "Next Session"
15
+ FIRST_TRANSACTION_NAME = "Controller/blogs/index"
16
+ FIRST_REQUESTED_TRACE_COUNT = 10
17
+ FIRST_DURATION = 600
18
+ FIRST_SAMPLE_PERIOD = 0.2
19
+ FIRST_RUN_PROFILER = true
20
+
21
+ FIRST_METADATA = {
22
+ "x_ray_id" => FIRST_ID,
23
+ "xray_session_name" => FIRST_NAME,
24
+ "key_transaction_name" => FIRST_TRANSACTION_NAME,
25
+ "requested_trace_count" => FIRST_REQUESTED_TRACE_COUNT,
26
+ "duration" => FIRST_DURATION,
27
+ "sample_period" => FIRST_SAMPLE_PERIOD,
28
+ "run_profiler" => FIRST_RUN_PROFILER,
29
+ }
30
+
31
+ SECOND_ID = 42
32
+ SECOND_TRANSACTION_NAME = "Controller/blogs/show"
33
+
34
+ SECOND_METADATA = {
35
+ "x_ray_id" => SECOND_ID,
36
+ "key_transaction_name" => SECOND_TRANSACTION_NAME,
37
+ "duration" => 0.0,
38
+ "run_profiler" => true
39
+ }
40
+
41
+ ANOTHER_ID_FOR_SECOND = 666
42
+ ANOTHER_FOR_SECOND_METADATA = {
43
+ "x_ray_id" => ANOTHER_ID_FOR_SECOND,
44
+ "key_transaction_name" => SECOND_TRANSACTION_NAME,
45
+ "duration" => 0.0,
46
+ "run_profiler" => true
47
+ }
48
+
49
+ def setup
50
+ @new_relic_service = stub
51
+ NewRelic::Agent.instance.stubs(:service).returns(@new_relic_service)
52
+
53
+ @backtrace_service = NewRelic::Agent::Threading::BacktraceService.new
54
+ @backtrace_service.worker_loop.stubs(:run)
55
+
56
+ @event_listener = NewRelic::Agent::EventListener.new
57
+
58
+ @sessions = NewRelic::Agent::Commands::XraySessionCollection.new(@backtrace_service, @event_listener)
59
+
60
+ @new_relic_service.stubs(:get_xray_metadata).with([FIRST_ID]).returns([FIRST_METADATA])
61
+ @new_relic_service.stubs(:get_xray_metadata).with([SECOND_ID]).returns([SECOND_METADATA])
62
+ @new_relic_service.stubs(:get_xray_metadata).with([FIRST_ID, SECOND_ID]).returns([FIRST_METADATA, SECOND_METADATA])
63
+ @new_relic_service.stubs(:get_xray_metadata).with([ANOTHER_ID_FOR_SECOND]).returns([ANOTHER_FOR_SECOND_METADATA])
64
+ end
65
+
66
+ def teardown
67
+ @backtrace_service.worker_thread.join if @backtrace_service.worker_thread
68
+ NewRelic::Agent.instance.stats_engine.clear_stats
69
+ end
70
+
71
+ def test_can_add_sessions
72
+ handle_command_for(FIRST_ID, SECOND_ID)
73
+
74
+ assert sessions.include?(FIRST_ID)
75
+ assert sessions.include?(SECOND_ID)
76
+
77
+ assert_metrics_recorded({
78
+ "Supportability/XraySessions/Starts" => { :call_count => 2 }})
79
+ end
80
+
81
+ def test_can_disable_from_config
82
+ with_config(:'xray_session.enabled' => false) do
83
+ handle_command_for(FIRST_ID, SECOND_ID)
84
+
85
+ assert_false sessions.include?(FIRST_ID)
86
+ assert_false sessions.include?(SECOND_ID)
87
+ end
88
+ end
89
+
90
+ def test_adding_sessions_registers_them_as_thread_profiling_clients
91
+ xray_id = 333
92
+ xray_metadata = {
93
+ 'x_ray_id' => xray_id,
94
+ 'run_profiler' => true,
95
+ 'key_transaction_name' => 'foo'
96
+ }
97
+ @new_relic_service.stubs(:get_xray_metadata).with([xray_id]).returns([xray_metadata])
98
+
99
+ @backtrace_service.expects(:subscribe).with('foo', xray_metadata)
100
+ handle_command_for(xray_id)
101
+ end
102
+
103
+ def test_adding_sessions_does_not_register_them_as_thread_profiling_clients_unless_run_profiler_set
104
+ xray_id = 333
105
+ xray_metadata = {
106
+ 'x_ray_id' => xray_id,
107
+ 'run_profiler' => false,
108
+ 'key_transaction_name' => 'foo'
109
+ }
110
+ @new_relic_service.stubs(:get_xray_metadata).with([xray_id]).returns([xray_metadata])
111
+
112
+ @backtrace_service.expects(:subscribe).never
113
+ handle_command_for(xray_id)
114
+ end
115
+
116
+ def test_removing_sessions_unsubscribes_from_backtrace_service
117
+ xray_id = 333
118
+ xray_metadata = {
119
+ 'x_ray_id' => xray_id,
120
+ 'run_profiler' => true,
121
+ 'key_transaction_name' => 'foo'
122
+ }
123
+ @new_relic_service.stubs(:get_xray_metadata).with([xray_id]).returns([xray_metadata])
124
+ handle_command_for(xray_id)
125
+
126
+ @backtrace_service.expects(:unsubscribe).with('foo')
127
+ @sessions.handle_active_xray_sessions(create_agent_command('xray_ids' => []))
128
+ end
129
+
130
+ def test_creates_a_session_from_collector_metadata
131
+ handle_command_for(FIRST_ID)
132
+
133
+ session = sessions[FIRST_ID]
134
+ assert_equal FIRST_ID, session.id
135
+ assert_equal FIRST_NAME, session.xray_session_name
136
+ assert_equal FIRST_REQUESTED_TRACE_COUNT, session.requested_trace_count
137
+ assert_equal FIRST_DURATION, session.duration
138
+ assert_equal FIRST_SAMPLE_PERIOD, session.sample_period
139
+ assert_equal FIRST_RUN_PROFILER, session.run_profiler?
140
+ assert_equal FIRST_TRANSACTION_NAME, session.key_transaction_name
141
+ assert_equal true, session.active?
142
+ end
143
+
144
+ def test_defaults_out_properties_for_session_missing_metadata
145
+ handle_command_for(SECOND_ID)
146
+
147
+ session = sessions[SECOND_ID]
148
+ assert_not_nil session.xray_session_name
149
+ assert_not_nil session.requested_trace_count
150
+ assert_not_nil session.duration
151
+ assert_not_nil session.sample_period
152
+ assert_not_nil session.run_profiler?
153
+ assert_not_nil session.key_transaction_name
154
+ assert_not_nil session.active?
155
+ end
156
+
157
+ def test_doesnt_recall_metadata_for_already_active_sessions
158
+ # unstub fails on certain mocha/rails versions (rails23 env)
159
+ # replace the service instead to let us expect to never get the call...
160
+ @new_relic_service = stub
161
+ NewRelic::Agent.instance.stubs(:service).returns(@new_relic_service)
162
+ @new_relic_service.stubs(:get_xray_metadata).with([FIRST_ID]).returns([FIRST_METADATA])
163
+ @new_relic_service.stubs(:get_xray_metadata).with([SECOND_ID]).returns([SECOND_METADATA])
164
+
165
+ @new_relic_service.expects(:get_xray_metadata).with([FIRST_ID, SECOND_ID]).never
166
+
167
+ handle_command_for(FIRST_ID)
168
+ handle_command_for(FIRST_ID, SECOND_ID)
169
+
170
+ assert sessions.include?(FIRST_ID)
171
+ assert sessions.include?(SECOND_ID)
172
+ end
173
+
174
+ def test_adding_doesnt_replace_session_object
175
+ handle_command_for(FIRST_ID)
176
+ expected = sessions[FIRST_ID]
177
+
178
+ handle_command_for(FIRST_ID)
179
+ result = sessions[FIRST_ID]
180
+
181
+ assert_equal expected, result
182
+ end
183
+
184
+ def test_can_access_session
185
+ handle_command_for(FIRST_ID)
186
+
187
+ session = sessions[FIRST_ID]
188
+ assert_equal FIRST_ID, session.id
189
+ end
190
+
191
+ def test_can_find_session_id_by_transaction_name
192
+ handle_command_for(FIRST_ID)
193
+
194
+ result = sessions.session_id_for_transaction_name(FIRST_TRANSACTION_NAME)
195
+ assert_equal(FIRST_ID, result)
196
+ end
197
+
198
+ def test_can_find_session_id_by_missing_transaction_name
199
+ result = sessions.session_id_for_transaction_name("MISSING")
200
+ assert_nil result
201
+ end
202
+
203
+ def test_adding_a_session_actives_it
204
+ handle_command_for(FIRST_ID)
205
+
206
+ session = sessions[FIRST_ID]
207
+ assert_equal true, session.active?
208
+ end
209
+
210
+ def test_removes_inactive_sessions
211
+ handle_command_for(FIRST_ID, SECOND_ID)
212
+ handle_command_for(FIRST_ID)
213
+
214
+ assert_equal true, sessions.include?(FIRST_ID)
215
+ assert_equal false, sessions.include?(SECOND_ID)
216
+
217
+ assert_metrics_recorded(["Supportability/XraySessions/Stops"])
218
+ end
219
+
220
+ def test_removing_inactive_sessions_deactivates_them
221
+ handle_command_for(FIRST_ID)
222
+ session = sessions[FIRST_ID]
223
+
224
+ handle_command_for(*[])
225
+
226
+ assert_equal false, session.active?
227
+ end
228
+
229
+ def test_before_harvest_event_prunes_finished_sessions
230
+ freeze_time
231
+
232
+ handle_command_for(SECOND_ID)
233
+ assert sessions.include?(SECOND_ID)
234
+
235
+ advance_time(1.0)
236
+ @event_listener.notify(:before_harvest)
237
+
238
+ assert_false sessions.include?(SECOND_ID)
239
+ end
240
+
241
+ if NewRelic::Agent::Threading::BacktraceService.is_supported?
242
+
243
+ def test_harvest_thread_profiles_pulls_data_from_backtrace_service
244
+ handle_command_for(FIRST_ID, SECOND_ID)
245
+
246
+ profile0 = stub('profile0', :empty? => false)
247
+ profile1 = stub('profile1', :empty? => false)
248
+
249
+ @backtrace_service.expects(:harvest).with(FIRST_TRANSACTION_NAME).returns(profile0)
250
+ @backtrace_service.expects(:harvest).with(SECOND_TRANSACTION_NAME).returns(profile1)
251
+
252
+ profiles = @sessions.harvest_thread_profiles
253
+ assert_equal_unordered([profile0, profile1], profiles)
254
+ end
255
+
256
+ def test_harvest_thread_profiles_doesnt_return_empty_profiles
257
+ handle_command_for(FIRST_ID, SECOND_ID)
258
+
259
+ profile0 = stub('profile0', :empty? => true)
260
+ profile1 = stub('profile1', :empty? => false)
261
+
262
+ @backtrace_service.stubs(:harvest).with(FIRST_TRANSACTION_NAME).returns(profile0)
263
+ @backtrace_service.stubs(:harvest).with(SECOND_TRANSACTION_NAME).returns(profile1)
264
+
265
+ profiles = @sessions.harvest_thread_profiles
266
+ assert_equal_unordered([profile1], profiles)
267
+ end
268
+
269
+ def test_starting_and_stopping_for_same_transaction_in_one_call
270
+ # Don't run an actual thread--our shutdown on SECOND_ID leaves a thread
271
+ # that potentially tromples on other tests
272
+ @backtrace_service.stubs(:start)
273
+
274
+ handle_command_for(SECOND_ID)
275
+ assert_equal true, sessions.include?(SECOND_ID)
276
+ assert_not_nil @backtrace_service.profiles[SECOND_TRANSACTION_NAME]
277
+
278
+ handle_command_for(ANOTHER_ID_FOR_SECOND)
279
+ assert_equal false, sessions.include?(SECOND_ID)
280
+ assert_equal true, sessions.include?(ANOTHER_ID_FOR_SECOND)
281
+ assert_not_nil @backtrace_service.profiles[SECOND_TRANSACTION_NAME]
282
+ end
283
+
284
+ def test_concurrency_on_access_to_sessions
285
+ # Our usage in this test will spin up tons of threads when we pound
286
+ # the commands. Since we are only checking locking around @sessions,
287
+ # don't let the backtrace service spin up threads...
288
+ @backtrace_service.stubs(:subscribe)
289
+
290
+ harvest_thread = Thread.new do
291
+ Thread.current.abort_on_exception = true
292
+ 500.times do
293
+ handle_command_for(FIRST_ID)
294
+ handle_command_for()
295
+ end
296
+ end
297
+
298
+ 500.times do
299
+ sessions.session_id_for_transaction_name(FIRST_TRANSACTION_NAME)
300
+ end
301
+
302
+ harvest_thread.join
303
+ assert_nil @backtrace_service.worker_thread
304
+ end
305
+
306
+ else
307
+
308
+ def test_harvest_is_empty_if_not_supported
309
+ handle_command_for(FIRST_ID, SECOND_ID)
310
+
311
+ @backtrace_service.expects(:harvest).never
312
+
313
+ profiles = @sessions.harvest_thread_profiles
314
+ assert_equal([], profiles)
315
+ end
316
+
317
+ end
318
+
319
+
320
+ # Helpers
321
+
322
+ def handle_command_for(*session_ids)
323
+ command = command_for(*session_ids)
324
+ sessions.handle_active_xray_sessions(command)
325
+ end
326
+
327
+ def command_for(*session_ids)
328
+ command = create_agent_command({ "xray_ids" => session_ids})
329
+ end
330
+
331
+ end
332
+ end