newrelic_rpm 3.5.6.48.beta → 3.5.6.55

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.gitignore +1 -0
  3. data/CHANGELOG +52 -0
  4. data/gem-public_cert.pem +20 -0
  5. data/lib/new_relic/agent.rb +3 -0
  6. data/lib/new_relic/agent/agent.rb +21 -14
  7. data/lib/new_relic/agent/agent_logger.rb +9 -1
  8. data/lib/new_relic/agent/configuration/defaults.rb +3 -3
  9. data/lib/new_relic/agent/configuration/mask_defaults.rb +1 -0
  10. data/lib/new_relic/agent/error_collector.rb +11 -2
  11. data/lib/new_relic/agent/instrumentation/browser_monitoring_timings.rb +2 -2
  12. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +1 -1
  13. data/lib/new_relic/agent/instrumentation/sinatra.rb +10 -2
  14. data/lib/new_relic/agent/new_relic_service.rb +90 -10
  15. data/lib/new_relic/agent/pipe_service.rb +9 -0
  16. data/lib/new_relic/agent/sql_sampler.rb +10 -3
  17. data/lib/new_relic/agent/thread_profiler.rb +20 -7
  18. data/lib/new_relic/coerce.rb +37 -0
  19. data/lib/new_relic/commands/deployments.rb +1 -1
  20. data/lib/new_relic/control/frameworks/rails.rb +12 -2
  21. data/lib/new_relic/control/frameworks/rails3.rb +2 -11
  22. data/lib/new_relic/control/instance_methods.rb +10 -6
  23. data/lib/new_relic/control/server_methods.rb +5 -37
  24. data/lib/new_relic/local_environment.rb +1 -1
  25. data/lib/new_relic/metric_data.rb +13 -2
  26. data/lib/new_relic/noticed_error.rb +8 -1
  27. data/lib/new_relic/transaction_sample.rb +12 -3
  28. data/lib/new_relic/transaction_sample/segment.rb +6 -3
  29. data/newrelic.yml +6 -19
  30. data/newrelic_rpm.gemspec +7 -0
  31. data/test/multiverse/lib/multiverse/environment.rb +1 -1
  32. data/test/multiverse/suites/agent_only/logging_test.rb +19 -0
  33. data/test/multiverse/suites/agent_only/ssl_test.rb +22 -0
  34. data/test/multiverse/suites/rails/config/newrelic.yml +3 -136
  35. data/test/multiverse/suites/rails/error_tracing_test.rb +39 -21
  36. data/test/multiverse/suites/rails/gc_instrumentation_test.rb +26 -24
  37. data/test/multiverse/suites/resque/Rakefile +6 -0
  38. data/test/multiverse/suites/resque/instrumentation_test.rb +18 -5
  39. data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +38 -0
  40. data/test/multiverse/suites/sinatra/sinatra_test.rb +17 -0
  41. data/test/new_relic/agent/agent/connect_test.rb +7 -26
  42. data/test/new_relic/agent/agent_test.rb +27 -31
  43. data/test/new_relic/agent/browser_monitoring_test.rb +1 -1
  44. data/test/new_relic/agent/error_collector_test.rb +16 -0
  45. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +1 -1
  46. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +1 -0
  47. data/test/new_relic/agent/new_relic_service_test.rb +95 -2
  48. data/test/new_relic/agent/pipe_channel_manager_test.rb +3 -3
  49. data/test/new_relic/agent/pipe_service_test.rb +21 -1
  50. data/test/new_relic/agent/rpm_agent_test.rb +1 -1
  51. data/test/new_relic/agent/sql_sampler_test.rb +20 -0
  52. data/test/new_relic/agent/thread_profiler_test.rb +53 -8
  53. data/test/new_relic/agent/worker_loop_test.rb +4 -8
  54. data/test/new_relic/agent_test.rb +1 -2
  55. data/test/new_relic/coerce_test.rb +65 -0
  56. data/test/new_relic/command/deployments_test.rb +1 -1
  57. data/test/new_relic/control_test.rb +19 -44
  58. data/test/new_relic/fake_collector.rb +3 -2
  59. data/test/new_relic/local_environment_test.rb +1 -1
  60. data/test/new_relic/metric_data_test.rb +29 -0
  61. data/test/new_relic/noticed_error_test.rb +8 -0
  62. data/test/new_relic/transaction_sample/segment_test.rb +7 -0
  63. data/test/new_relic/transaction_sample_test.rb +36 -8
  64. data/test/test_contexts.rb +1 -1
  65. data/test/test_helper.rb +21 -2
  66. data/ui/helpers/google_pie_chart.rb +1 -0
  67. metadata +68 -10
  68. metadata.gz.sig +0 -0
  69. data/test/new_relic/fake_service.rb +0 -53
@@ -0,0 +1,38 @@
1
+ class SinatraErrorTracingTestApp < Sinatra::Base
2
+ configure do
3
+ set :show_exceptions, false
4
+ end
5
+
6
+ get '/will_boom' do
7
+ raise 'Boom!'
8
+ end
9
+
10
+ error do
11
+ 'We are sorry'
12
+ end
13
+ end
14
+
15
+ class SinatraErrorTracingTest < Test::Unit::TestCase
16
+ include Rack::Test::Methods
17
+ include ::NewRelic::Agent::Instrumentation::Sinatra
18
+
19
+ def app
20
+ SinatraErrorTracingTestApp
21
+ end
22
+
23
+ def setup
24
+ ::NewRelic::Agent.manual_start
25
+ @error_collector = ::NewRelic::Agent.instance.error_collector
26
+
27
+ assert(@error_collector.enabled?,
28
+ 'error collector should be enabled')
29
+ end
30
+
31
+ def test_traps_errors
32
+ get '/will_boom'
33
+ assert_equal 500, last_response.status
34
+ assert_equal 'We are sorry', last_response.body
35
+
36
+ assert_equal(1, @error_collector.errors.size)
37
+ end
38
+ end
@@ -8,6 +8,9 @@ class SinatraRouteTestApp < Sinatra::Base
8
8
  halt 404 unless boolean
9
9
  end
10
10
  end
11
+
12
+ # treat errors like production for testing purposes
13
+ set :show_exceptions, false
11
14
  end
12
15
 
13
16
  get '/user/login' do
@@ -18,6 +21,11 @@ class SinatraRouteTestApp < Sinatra::Base
18
21
  get '/user/:id', :my_condition => false do |id|
19
22
  "Welcome #{id}"
20
23
  end
24
+
25
+ get '/error' do
26
+ raise "Uh-oh"
27
+ end
28
+
21
29
  end
22
30
 
23
31
  class SinatraTest < Test::Unit::TestCase
@@ -32,6 +40,10 @@ class SinatraTest < Test::Unit::TestCase
32
40
  ::NewRelic::Agent.manual_start
33
41
  end
34
42
 
43
+ def teardown
44
+ ::NewRelic::Agent.agent.error_collector.harvest_errors([])
45
+ end
46
+
35
47
  # https://support.newrelic.com/tickets/24779
36
48
  def test_lower_priority_route_conditions_arent_applied_to_higher_priority_routes
37
49
  get '/user/login'
@@ -52,4 +64,9 @@ class SinatraTest < Test::Unit::TestCase
52
64
  assert metric_names.include?("WebFrontend/WebServer/all")
53
65
  assert ::NewRelic::Agent.agent.stats_engine.get_stats("WebFrontend/WebServer/all")
54
66
  end
67
+
68
+ def test_shown_errors_get_caught
69
+ get '/error'
70
+ assert_equal 1, ::NewRelic::Agent.agent.error_collector.errors.size
71
+ end
55
72
  end
@@ -183,9 +183,8 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
183
183
 
184
184
  def test_connect_to_server_gets_config_from_collector
185
185
  NewRelic::Agent.manual_start
186
- service = NewRelic::FakeService.new
187
- NewRelic::Agent::Agent.instance.service = service
188
- service.mock['connect'] = {'agent_run_id' => 23, 'config' => 'a lot'}
186
+ NewRelic::Agent::Agent.instance.service = default_service(
187
+ :connect => {'agent_run_id' => 23, 'config' => 'a lot'})
189
188
 
190
189
  response = NewRelic::Agent.agent.connect_to_server
191
190
 
@@ -217,13 +216,11 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
217
216
 
218
217
  def test_logging_collector_messages
219
218
  NewRelic::Agent.manual_start
220
- service = NewRelic::FakeService.new
221
- NewRelic::Agent::Agent.instance.service = service
222
- service.mock['connect'] = {
223
- 'agent_run_id' => 23, 'config' => 'a lot',
224
- 'messages' => [{ 'message' => 'beep boop', 'level' => 'INFO' },
225
- { 'message' => 'ha cha cha', 'level' => 'WARN' }]
226
- }
219
+ NewRelic::Agent::Agent.instance.service = default_service(
220
+ :connect => {
221
+ 'messages' => [{ 'message' => 'beep boop', 'level' => 'INFO' },
222
+ { 'message' => 'ha cha cha', 'level' => 'WARN' }]
223
+ })
227
224
 
228
225
  expects_logging(:info, 'beep boop')
229
226
  expects_logging(:warn, 'ha cha cha')
@@ -238,22 +235,6 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
238
235
  assert_equal 'blah', @service.agent_id
239
236
  end
240
237
 
241
- # no idea why this test leaks in Rails 2.0
242
- # will be moved to a multiverse test eventually anyway
243
- if !Rails::VERSION::STRING =~ /2\.0.*/
244
- def test_set_apdex_t_from_server
245
- service = NewRelic::FakeService.new
246
- NewRelic::Agent::Agent.instance.service = service
247
- service.mock['connect'] = { 'apdex_t' => 0.5 }
248
- with_config(:sync_startup => true, :monitor_mode => true,
249
- :license_key => 'a' * 40) do
250
- NewRelic::Agent.manual_start
251
- assert_equal 0.5, NewRelic::Agent.config[:apdex_t]
252
- NewRelic::Agent.shutdown
253
- end
254
- end
255
- end
256
-
257
238
  private
258
239
 
259
240
  def mocked_control
@@ -8,23 +8,13 @@ module NewRelic
8
8
  def setup
9
9
  super
10
10
  @agent = NewRelic::Agent::Agent.new
11
- @agent.service = NewRelic::FakeService.new
11
+ @agent.service = default_service
12
12
  end
13
13
 
14
14
  #
15
15
  # Helpers
16
16
  #
17
17
 
18
- def with_config( options )
19
- config_source = NewRelic::Agent::Configuration::ManualSource.new( options )
20
- NewRelic::Agent.config.apply_config( config_source )
21
-
22
- yield
23
-
24
- ensure
25
- NewRelic::Agent.config.remove_config( config_source ) if config_source
26
- end
27
-
28
18
  def with_profile(opts)
29
19
  profile = NewRelic::Agent::ThreadProfile.new(-1, 0, 0, true)
30
20
  profile.aggregate(["chunky.rb:42:in `bacon'"], profile.traces[:other])
@@ -60,8 +50,13 @@ module NewRelic
60
50
  end
61
51
 
62
52
  def test_transmit_data_should_transmit
53
+ @agent.service.expects(:metric_data).at_least_once
54
+ @agent.instance_eval { transmit_data }
55
+ end
56
+
57
+ def test_transmit_data_should_use_one_http_handle_per_harvest
58
+ @agent.service.expects(:session).once
63
59
  @agent.instance_eval { transmit_data }
64
- assert @agent.service.agent_data.any?
65
60
  end
66
61
 
67
62
  def test_transmit_data_should_close_explain_db_connections
@@ -105,27 +100,20 @@ module NewRelic
105
100
 
106
101
  def test_harvest_and_send_thread_profile
107
102
  profile = with_profile(:finished => true)
103
+ @agent.service.expects(:profile_data).with(any_parameters)
108
104
  @agent.send(:harvest_and_send_thread_profile, false)
109
-
110
- assert_equal([profile],
111
- @agent.service.agent_data \
112
- .find{|data| data.action == :profile_data}.params)
113
105
  end
114
106
 
115
107
  def test_harvest_and_send_thread_profile_when_not_finished
116
108
  with_profile(:finished => false)
109
+ @agent.service.expects(:profile_data).never
117
110
  @agent.send(:harvest_and_send_thread_profile, false)
118
-
119
- assert_nil @agent.service.agent_data.find{|data| data.action == :profile_data}
120
111
  end
121
112
 
122
113
  def test_harvest_and_send_thread_profile_when_not_finished_but_disconnecting
123
114
  profile = with_profile(:finished => false)
115
+ @agent.service.expects(:profile_data).with(any_parameters)
124
116
  @agent.send(:harvest_and_send_thread_profile, true)
125
-
126
- assert_equal([profile],
127
- @agent.service.agent_data \
128
- .find{|data| data.action == :profile_data}.params)
129
117
  end
130
118
 
131
119
  def test_harvest_timeslice_data
@@ -158,8 +146,8 @@ module NewRelic
158
146
  end
159
147
 
160
148
  def test_check_for_agent_commands
149
+ @agent.service.expects(:get_agent_commands).returns([]).once
161
150
  @agent.send :check_for_agent_commands
162
- assert_equal(1, @agent.service.calls_for(:get_agent_commands).size)
163
151
  end
164
152
 
165
153
  def test_merge_data_from_empty
@@ -218,18 +206,26 @@ module NewRelic
218
206
  assert_equal(1, @agent.unsent_timeslice_data, "should have the key from above")
219
207
  end
220
208
 
221
- def test_merge_data_from_all_three_empty
222
- unsent_timeslice_data = mock('unsent timeslice data')
223
- unsent_errors = mock('unsent errors')
209
+ def test_merge_data_traces
224
210
  unsent_traces = mock('unsent traces')
225
211
  @agent.instance_eval {
226
- @unsent_errors = unsent_errors
227
- @unsent_timeslice_data = unsent_timeslice_data
228
212
  @traces = unsent_traces
229
213
  }
230
214
  unsent_traces.expects(:+).with([1,2,3])
231
- unsent_errors.expects(:+).with([4,5,6])
232
- @agent.merge_data_from([{}, [1,2,3], [4,5,6]])
215
+ @agent.merge_data_from([{}, [1,2,3], []])
216
+ end
217
+
218
+ def test_merge_data_from_abides_by_error_queue_limit
219
+ errors = []
220
+ 40.times { |i| errors << Exception.new("boo #{i}") }
221
+
222
+ @agent.merge_data_from([{}, [], errors])
223
+
224
+ assert_equal 20, @agent.error_collector.errors.length
225
+
226
+ # This method should NOT increment error counts, since that has already
227
+ # been counted in the child
228
+ assert_equal 0, NewRelic::Agent.get_stats("Errors/all").call_count
233
229
  end
234
230
 
235
231
  def test_fill_metric_id_cache_from_collect_response
@@ -275,7 +271,7 @@ module NewRelic
275
271
  end
276
272
 
277
273
  def test_connect_does_not_retry_on_license_error
278
- @agent.service.stubs(:connect).raises(NewRelic::Agent::LicenseException)
274
+ @agent.service.expects(:connect).raises(NewRelic::Agent::LicenseException)
279
275
  @agent.send(:connect)
280
276
  assert(@agent.disconnected?)
281
277
  end
@@ -373,7 +373,7 @@ var e=document.createElement("script");'
373
373
  end
374
374
 
375
375
  def test_place_beacon_payload_head_when_given_mobile_request_header
376
- Time.stubs(:now).returns(6)
376
+ Time.stubs(:now).returns(Time.at(6))
377
377
  response = mobile_transaction
378
378
  txn_name = obfuscate(NewRelic::Agent.instance.beacon_configuration,
379
379
  browser_monitoring_transaction_name)
@@ -186,7 +186,23 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
186
186
  end
187
187
  end
188
188
 
189
+ def test_increments_count_on_errors
190
+ expects_error_count_increase(1) do
191
+ @error_collector.notice_error(StandardError.new("Boo"))
192
+ end
193
+ end
194
+
189
195
  private
196
+
197
+ def expects_error_count_increase(increase)
198
+ count = get_error_stats
199
+ yield
200
+ assert_equal increase, get_error_stats - count
201
+ end
202
+
203
+ def get_error_stats
204
+ NewRelic::Agent.get_stats("Errors/all").call_count
205
+ end
190
206
 
191
207
  def wrapped_filter_proc
192
208
  Proc.new do |e|
@@ -4,7 +4,7 @@ module NewRelic::Agent::Instrumentation
4
4
  class BrowserMonitoringTimingsTest < Test::Unit::TestCase
5
5
 
6
6
  def setup
7
- Time.stubs(:now).returns(2000)
7
+ Time.stubs(:now).returns(Time.at(2000))
8
8
  @transaction = stub(
9
9
  :transaction_name => "Name",
10
10
  :start_time => 0
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_contexts'))
2
3
 
3
4
  class NewRelic::Agent::Instrumentation::TaskInstrumentationTest < Test::Unit::TestCase
4
5
  include NewRelic::Agent::Instrumentation::ControllerInstrumentation
@@ -1,6 +1,62 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
2
2
  require 'new_relic/agent/thread_profiler'
3
3
 
4
+ # Tests of HTTP Keep Alive implementation that require a different setup and
5
+ # set of mocks.
6
+ class NewRelicServiceKeepAliveTest < Test::Unit::TestCase
7
+ def setup
8
+ @server = NewRelic::Control::Server.new('somewhere.example.com',
9
+ 30303, '10.10.10.10')
10
+ @service = NewRelic::Agent::NewRelicService.new('license-key', @server)
11
+ end
12
+
13
+ def stub_net_http_handle(overrides = {})
14
+ stub('http_handle', :start => true, :finish => true, :address => '10.10.10.10', :port => 30303)
15
+ end
16
+
17
+ def test_session_block_reuses_http_handle
18
+ handle1 = stub_net_http_handle
19
+ handle2 = stub_net_http_handle
20
+ @service.stubs(:create_http_connection).returns(handle1, handle2)
21
+
22
+ block_ran = false
23
+ @service.session do
24
+ block_ran = true
25
+ assert(@service.http_connection)
26
+
27
+ # check we get the same object back each time we call http_connection in the block
28
+ assert_equal(@service.http_connection.object_id, handle1.object_id)
29
+ assert_equal(@service.http_connection.object_id, handle1.object_id)
30
+ end
31
+ assert(block_ran)
32
+ end
33
+
34
+ def test_multiple_http_handles_are_used_outside_session_block
35
+ handle1 = stub_net_http_handle
36
+ handle2 = stub_net_http_handle
37
+ @service.stubs(:create_http_connection).returns(handle1, handle2)
38
+ assert_equal(@service.http_connection.object_id, handle1.object_id)
39
+ assert_equal(@service.http_connection.object_id, handle2.object_id)
40
+ end
41
+
42
+
43
+ def test_session_starts_and_finishes_http_session
44
+ handle1 = stub_net_http_handle
45
+ handle1.expects(:start).once
46
+ handle1.expects(:finish).once
47
+ @service.stubs(:create_http_connection).returns(handle1)
48
+
49
+ block_ran = false
50
+ @service.session do
51
+ block_ran = true
52
+ # mocks expect #start and #finish to be called. This is how Net::HTTP
53
+ # implements keep alive
54
+ end
55
+ assert(block_ran)
56
+ end
57
+
58
+ end
59
+
4
60
  class NewRelicServiceTest < Test::Unit::TestCase
5
61
  def initialize(*_)
6
62
  [ :HTTPSuccess,
@@ -27,7 +83,7 @@ class NewRelicServiceTest < Test::Unit::TestCase
27
83
  30303, '10.10.10.10')
28
84
  @service = NewRelic::Agent::NewRelicService.new('license-key', @server)
29
85
  @http_handle = HTTPHandle.new
30
- NewRelic::Control.instance.stubs(:http_connection).returns(@http_handle)
86
+ @service.stubs(:create_http_connection).returns(@http_handle)
31
87
 
32
88
  @http_handle.respond_to(:get_redirect_host, 'localhost')
33
89
  connect_response = {
@@ -43,6 +99,43 @@ class NewRelicServiceTest < Test::Unit::TestCase
43
99
  end
44
100
  end
45
101
 
102
+ def test_cert_file_path
103
+ assert @service.cert_file_path
104
+ assert_equal File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'cert', 'cacert.pem')), @service.cert_file_path
105
+ end
106
+
107
+ # This test does not actually use the ruby agent in any way - it's
108
+ # testing that the CA file we ship actually validates our server's
109
+ # certificate. It's used for customers who enable verify_certificate
110
+ def test_cert_file
111
+ require 'socket'
112
+ require 'openssl'
113
+
114
+ s = TCPSocket.new 'collector.newrelic.com', 443
115
+ ctx = OpenSSL::SSL::SSLContext.new
116
+ ctx.ca_file = @service.cert_file_path
117
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
118
+ s = OpenSSL::SSL::SSLSocket.new s, ctx
119
+ s.connect
120
+ # should not raise an error
121
+ end
122
+
123
+ # see above, but for staging, as well. This allows us to test new
124
+ # certificates in a non-customer-facing place before setting them
125
+ # live.
126
+ def test_staging_cert_file
127
+ require 'socket'
128
+ require 'openssl'
129
+
130
+ s = TCPSocket.new 'staging-collector.newrelic.com', 443
131
+ ctx = OpenSSL::SSL::SSLContext.new
132
+ ctx.ca_file = @service.cert_file_path
133
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
134
+ s = OpenSSL::SSL::SSLSocket.new s, ctx
135
+ s.connect
136
+ # should not raise an error
137
+ end
138
+
46
139
  def test_initialize_uses_correct_license_key_settings
47
140
  with_config(:license_key => 'abcde') do
48
141
  service = NewRelic::Agent::NewRelicService.new
@@ -65,7 +158,7 @@ class NewRelicServiceTest < Test::Unit::TestCase
65
158
  def test_connect_resets_cached_ip_address
66
159
  assert_equal '10.10.10.10', @service.collector.ip
67
160
  @service.connect
68
- assert_nil @service.collector.ip # 'localhost' resolves to nil
161
+ assert_equal 'localhost', @service.collector.ip # 'localhost' resolves to nil
69
162
  end
70
163
 
71
164
  def test_connect_uses_proxy_collector_if_no_redirect_host
@@ -77,9 +77,9 @@ class NewRelic::Agent::PipeChannelManagerTest < Test::Unit::TestCase
77
77
  sampler.notice_error(Exception.new("message"), :uri => '/myurl/',
78
78
  :metric => 'path', :referer => 'test_referer',
79
79
  :request_params => {:x => 'y'})
80
- NewRelic::Agent.agent.merge_data_from([nil, nil, [sampler.errors]])
80
+ NewRelic::Agent.agent.merge_data_from([nil, nil, sampler.errors])
81
81
 
82
- assert_equal(1, NewRelic::Agent.agent.unsent_errors_size)
82
+ assert_equal(1, NewRelic::Agent.agent.error_collector.errors.size)
83
83
 
84
84
  listener = start_listener_with_pipe(668)
85
85
 
@@ -94,7 +94,7 @@ class NewRelic::Agent::PipeChannelManagerTest < Test::Unit::TestCase
94
94
  Process.wait(pid)
95
95
  listener.stop
96
96
 
97
- assert_equal(2, NewRelic::Agent.agent.unsent_errors_size)
97
+ assert_equal(2, NewRelic::Agent.agent.error_collector.errors.size)
98
98
  end
99
99
 
100
100
  def test_close_pipe_on_EOF_string