newrelic_rpm 3.3.5 → 3.4.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of newrelic_rpm might be problematic. Click here for more details.

Files changed (41) hide show
  1. data/CHANGELOG +8 -5
  2. data/lib/new_relic/agent.rb +11 -3
  3. data/lib/new_relic/agent/agent.rb +68 -223
  4. data/lib/new_relic/agent/error_collector.rb +1 -1
  5. data/lib/new_relic/agent/instrumentation/resque.rb +80 -0
  6. data/lib/new_relic/agent/instrumentation/sinatra.rb +2 -0
  7. data/lib/new_relic/agent/new_relic_service.rb +221 -0
  8. data/lib/new_relic/agent/pipe_channel_manager.rb +151 -0
  9. data/lib/new_relic/agent/pipe_service.rb +57 -0
  10. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +4 -34
  11. data/lib/new_relic/agent/sql_sampler.rb +1 -5
  12. data/lib/new_relic/agent/stats_engine/transactions.rb +2 -2
  13. data/lib/new_relic/agent/transaction_sampler.rb +0 -2
  14. data/lib/new_relic/control/configuration.rb +1 -1
  15. data/lib/new_relic/control/instance_methods.rb +2 -1
  16. data/lib/new_relic/language_support.rb +26 -0
  17. data/lib/new_relic/transaction_sample.rb +2 -6
  18. data/lib/new_relic/version.rb +3 -3
  19. data/newrelic_rpm.gemspec +16 -5
  20. data/test/new_relic/agent/agent/connect_test.rb +39 -23
  21. data/test/new_relic/agent/agent_test.rb +25 -4
  22. data/test/new_relic/agent/database_test.rb +12 -0
  23. data/test/new_relic/agent/new_relic_service_test.rb +151 -0
  24. data/test/new_relic/agent/pipe_channel_manager_test.rb +114 -0
  25. data/test/new_relic/agent/pipe_service_test.rb +113 -0
  26. data/test/new_relic/agent/rpm_agent_test.rb +3 -30
  27. data/test/new_relic/agent/transaction_sample_builder_test.rb +0 -1
  28. data/test/new_relic/agent/transaction_sampler_test.rb +6 -6
  29. data/test/new_relic/agent/worker_loop_test.rb +2 -2
  30. data/test/new_relic/agent_test.rb +73 -3
  31. data/test/new_relic/control/configuration_test.rb +0 -7
  32. data/test/new_relic/control_test.rb +3 -3
  33. data/test/new_relic/delayed_job_injection_test.rb +6 -1
  34. data/test/new_relic/fake_collector.rb +210 -0
  35. data/test/new_relic/fake_service.rb +44 -0
  36. data/test/script/ci.sh +6 -6
  37. data/test/script/ci_agent-tests_runner.sh +82 -0
  38. data/test/script/ci_multiverse_runner.sh +35 -0
  39. data/test/test_contexts.rb +1 -0
  40. data/test/test_helper.rb +3 -1
  41. metadata +359 -324
@@ -146,4 +146,16 @@ class NewRelic::Agent::DatabaseTest < Test::Unit::TestCase
146
146
 
147
147
  NewRelic::Agent::Database::Obfuscator.instance.reset
148
148
  end
149
+
150
+ def test_close_connections_closes_all_held_db_connections
151
+ foo_connection = mock('foo connection')
152
+ bar_connection = mock('bar connection')
153
+ NewRelic::Agent::Database::ConnectionManager.instance.instance_eval do
154
+ @connections = { :foo => foo_connection, :bar => bar_connection }
155
+ end
156
+ foo_connection.expects(:disconnect!)
157
+ bar_connection.expects(:disconnect!)
158
+
159
+ NewRelic::Agent::Database.close_connections
160
+ end
149
161
  end
@@ -0,0 +1,151 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
2
+
3
+ class NewRelicServiceTest < Test::Unit::TestCase
4
+ def setup
5
+ @server = NewRelic::Control::Server.new('127.0.0.1', 30303)
6
+ @service = NewRelic::Agent::NewRelicService.new('license-key', @server)
7
+ @http_handle = HTTPHandle.new
8
+ NewRelic::Control.instance.stubs(:http_connection).returns(@http_handle)
9
+ @http_handle.respond_to(:get_redirect_host, 'localhost')
10
+ connect_response = {
11
+ 'config' => 'some config directives',
12
+ 'agent_run_id' => 1
13
+ }
14
+ @http_handle.respond_to(:connect, connect_response)
15
+ end
16
+
17
+ def test_connect_sets_agent_id_and_config_data
18
+ response = @service.connect
19
+ assert_equal 1, response['agent_run_id']
20
+ assert_equal 'some config directives', response['config']
21
+ end
22
+
23
+ def test_connect_sets_redirect_host
24
+ assert_equal '127.0.0.1', @service.collector.name
25
+ @service.connect
26
+ assert_equal 'localhost', @service.collector.name
27
+ end
28
+
29
+ def test_connect_uses_proxy_collector_if_no_redirect_host
30
+ @http_handle.reset
31
+ @http_handle.respond_to(:get_redirect_host, nil)
32
+ @http_handle.respond_to(:connect, {'agent_run_id' => 1})
33
+
34
+ @service.connect
35
+ assert_equal '127.0.0.1', @service.collector.name
36
+ end
37
+
38
+ def test_connect_sets_agent_id
39
+ @http_handle.reset
40
+ @http_handle.respond_to(:get_redirect_host, 'localhost')
41
+ @http_handle.respond_to(:connect, {'agent_run_id' => 666})
42
+
43
+ @service.connect
44
+ assert_equal 666, @service.agent_id
45
+ end
46
+
47
+ def test_get_redirect_host
48
+ host = @service.get_redirect_host
49
+ assert_equal 'localhost', host
50
+ end
51
+
52
+ def test_shutdown
53
+ @service.agent_id = 666
54
+ @http_handle.respond_to(:shutdown, 'shut this bird down')
55
+ response = @service.shutdown(Time.now)
56
+ assert_equal 'shut this bird down', response
57
+ end
58
+
59
+ def test_should_not_shutdown_if_never_connected
60
+ @http_handle.respond_to(:shutdown, 'shut this bird down')
61
+ response = @service.shutdown(Time.now)
62
+ assert_nil response
63
+ end
64
+
65
+ def test_metric_data
66
+ @http_handle.respond_to(:metric_data, 'met rick date uhhh')
67
+ response = @service.metric_data(Time.now - 60, Time.now, {})
68
+ assert_equal 'met rick date uhhh', response
69
+ end
70
+
71
+ def test_error_data
72
+ @http_handle.respond_to(:error_data, 'too human')
73
+ response = @service.error_data([])
74
+ assert_equal 'too human', response
75
+ end
76
+
77
+ def test_transaction_sample_data
78
+ @http_handle.respond_to(:transaction_sample_data, 'MPC1000')
79
+ response = @service.transaction_sample_data([])
80
+ assert_equal 'MPC1000', response
81
+ end
82
+
83
+ def test_sql_trace_data
84
+ @http_handle.respond_to(:sql_trace_data, 'explain this')
85
+ response = @service.sql_trace_data([])
86
+ assert_equal 'explain this', response
87
+ end
88
+
89
+ def test_request_timeout
90
+ NewRelic::Control.instance['timeout'] = 600
91
+ service = NewRelic::Agent::NewRelicService.new('abcdef', @server)
92
+ assert_equal 600, service.request_timeout
93
+ end
94
+
95
+ def test_should_throw_received_errors
96
+ assert_raise NewRelic::Agent::ServerConnectionException do
97
+ @service.send(:invoke_remote, :bogus_method)
98
+ end
99
+ end
100
+
101
+ class HTTPHandle
102
+ attr_accessor :read_timeout, :route_table
103
+
104
+ def initialize
105
+ reset
106
+ end
107
+
108
+ def respond_to(method, payload)
109
+ register(HTTPResponse.new(Marshal.dump(payload))) do |request|
110
+ request.path.include?(method.to_s)
111
+ end
112
+ end
113
+
114
+ def register(response, &block)
115
+ @route_table[block] = response
116
+ end
117
+
118
+ def request(*args)
119
+ @route_table.each_pair do |condition, response|
120
+ if condition.call(args[0])
121
+ return response
122
+ end
123
+ end
124
+ HTTPFailure.new('not found', 404)
125
+ end
126
+
127
+ def reset
128
+ @route_table = {}
129
+ end
130
+ end
131
+
132
+ module HTTPResponseMock
133
+ attr_accessor :code, :body, :message, :headers
134
+
135
+ def initialize(body, code=200, message='OK')
136
+ @code = code
137
+ @body = body
138
+ @message = message
139
+ @headers = {}
140
+ end
141
+
142
+ def [](key)
143
+ @headers[key]
144
+ end
145
+ end
146
+
147
+ HTTPResponse = Class.new(Net::HTTPOK)
148
+ HTTPResponse.class_eval { include HTTPResponseMock }
149
+ HTTPFailure = Class.new(Net::HTTPError)
150
+ HTTPFailure.class_eval { include HTTPResponseMock }
151
+ end
@@ -0,0 +1,114 @@
1
+ require 'timeout'
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
3
+ require 'new_relic/agent/pipe_channel_manager'
4
+
5
+ class NewRelic::Agent::PipeChannelManagerTest < Test::Unit::TestCase
6
+ def setup
7
+ NewRelic::Agent::PipeChannelManager.listener.close_all_pipes
8
+ NewRelic::Agent.manual_start
9
+ end
10
+
11
+ def teardown
12
+ NewRelic::Agent::PipeChannelManager.listener.stop
13
+ NewRelic::Agent.shutdown
14
+ end
15
+
16
+ def test_registering_a_pipe
17
+ NewRelic::Agent::PipeChannelManager.listener.wake.in.expects(:<<).with('.')
18
+ NewRelic::Agent::PipeChannelManager.register_report_channel(1)
19
+ pipe = NewRelic::Agent::PipeChannelManager.channels[1]
20
+
21
+ assert pipe.out.kind_of?(IO)
22
+ assert pipe.in.kind_of?(IO)
23
+
24
+ NewRelic::Agent::PipeChannelManager.listener.close_all_pipes
25
+ end
26
+
27
+ if NewRelic::LanguageSupport.can_fork? && !NewRelic::LanguageSupport.using_version?('1.9.1')
28
+ def test_listener_merges_timeslice_metrics
29
+ metric = 'Custom/test/method'
30
+ engine = NewRelic::Agent.agent.stats_engine
31
+ engine.get_stats_no_scope(metric).record_data_point(1.0)
32
+
33
+ listener = start_listener_with_pipe(666)
34
+
35
+ pid = Process.fork do
36
+ NewRelic::Agent.after_fork
37
+ new_engine = NewRelic::Agent::StatsEngine.new
38
+ new_engine.get_stats_no_scope(metric).record_data_point(2.0)
39
+ listener.pipes[666].write(:stats => new_engine.harvest_timeslice_data({}, {}))
40
+ end
41
+ Process.wait(pid)
42
+ listener.stop
43
+
44
+ assert_equal(3.0, engine.lookup_stats(metric).total_call_time)
45
+ end
46
+
47
+ def test_listener_merges_transaction_traces
48
+ sampler = NewRelic::Agent.agent.transaction_sampler
49
+ TransactionSampleTestHelper.run_sample_trace_on(sampler)
50
+ NewRelic::Agent.agent.merge_data_from([nil, [sampler.samples], nil])
51
+
52
+ assert_equal(1, NewRelic::Agent.agent.unsent_traces_size)
53
+
54
+ listener = start_listener_with_pipe(667)
55
+
56
+ pid = Process.fork do
57
+ NewRelic::Agent.after_fork
58
+ new_sampler = NewRelic::Agent::TransactionSampler.new
59
+ sample = TransactionSampleTestHelper.run_sample_trace_on(new_sampler)
60
+ new_sampler.store_force_persist(sample)
61
+ listener.pipes[667].write(:transaction_traces => new_sampler.harvest([], 0))
62
+ end
63
+ Process.wait(pid)
64
+ listener.stop
65
+
66
+ assert_equal(2, NewRelic::Agent.agent.unsent_traces_size)
67
+ end
68
+
69
+ def test_listener_merges_error_traces
70
+ sampler = NewRelic::Agent.agent.error_collector
71
+ sampler.notice_error(Exception.new("message"), :uri => '/myurl/',
72
+ :metric => 'path', :referer => 'test_referer',
73
+ :request_params => {:x => 'y'})
74
+ NewRelic::Agent.agent.merge_data_from([nil, nil, [sampler.errors]])
75
+
76
+ assert_equal(1, NewRelic::Agent.agent.unsent_errors_size)
77
+
78
+ listener = start_listener_with_pipe(668)
79
+
80
+ pid = Process.fork do
81
+ NewRelic::Agent.after_fork
82
+ new_sampler = NewRelic::Agent::ErrorCollector.new
83
+ new_sampler.notice_error(Exception.new("new message"), :uri => '/myurl/',
84
+ :metric => 'path', :referer => 'test_referer',
85
+ :request_params => {:x => 'y'})
86
+ listener.pipes[668].write(:error_traces => new_sampler.harvest_errors([]))
87
+ end
88
+ Process.wait(pid)
89
+ listener.stop
90
+
91
+ assert_equal(2, NewRelic::Agent.agent.unsent_errors_size)
92
+ end
93
+
94
+ def test_close_pipe_on_EOF_string
95
+ listener = start_listener_with_pipe(669)
96
+
97
+ pid = Process.fork do
98
+ listener.pipes[669].write('EOF')
99
+ end
100
+ Process.wait(pid)
101
+ listener.stop
102
+
103
+ assert(!NewRelic::Agent::PipeChannelManager.channels[669] ||
104
+ NewRelic::Agent::PipeChannelManager.channels[669].closed?)
105
+ end
106
+ end
107
+
108
+ def start_listener_with_pipe(pipe_id)
109
+ listener = NewRelic::Agent::PipeChannelManager.listener
110
+ listener.start
111
+ listener.register_pipe(pipe_id)
112
+ listener
113
+ end
114
+ end
@@ -0,0 +1,113 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
2
+
3
+ class PipeServiceTest < Test::Unit::TestCase
4
+ def setup
5
+ NewRelic::Agent::PipeChannelManager.listener.stop
6
+ NewRelic::Agent::PipeChannelManager.register_report_channel(:pipe_service_test)
7
+ @service = NewRelic::Agent::PipeService.new(:pipe_service_test)
8
+ end
9
+
10
+ def test_constructor
11
+ assert_equal :pipe_service_test, @service.channel_id
12
+ end
13
+
14
+ def test_connect_returns_nil
15
+ assert_nil @service.connect({})
16
+ end
17
+
18
+ if NewRelic::LanguageSupport.can_fork? &&
19
+ !NewRelic::LanguageSupport.using_version?('1.9.1')
20
+
21
+ def test_metric_data
22
+ received_data = data_from_forked_process do
23
+ metric_data0 = generate_metric_data('Custom/something')
24
+ @service.metric_data(0.0, 0.1, metric_data0)
25
+ end
26
+
27
+ assert_equal 'Custom/something', received_data[:stats].keys.sort[0].name
28
+ end
29
+
30
+ def test_transaction_sample_data
31
+ received_data = data_from_forked_process do
32
+ @service.transaction_sample_data(['txn'])
33
+ end
34
+
35
+ assert_equal ['txn'], received_data[:transaction_traces]
36
+ end
37
+
38
+ def test_error_data
39
+ received_data = data_from_forked_process do
40
+ @service.error_data(['err'])
41
+ end
42
+ assert_equal ['err'], received_data[:error_traces]
43
+ end
44
+
45
+ def test_sql_trace_data
46
+ received_data = data_from_forked_process do
47
+ @service.sql_trace_data(['sql'])
48
+ end
49
+ assert_equal ['sql'], received_data[:sql_traces]
50
+ end
51
+
52
+ def test_multiple_writes_to_pipe
53
+ pid = Process.fork do
54
+ metric_data0 = generate_metric_data('Custom/something')
55
+ @service.metric_data(0.0, 0.1, metric_data0)
56
+ @service.transaction_sample_data(['txn0'])
57
+ @service.error_data(['err0'])
58
+ @service.sql_trace_data(['sql0'])
59
+ @service.shutdown(Time.now)
60
+ end
61
+ Process.wait(pid)
62
+
63
+ received_data = read_from_pipe
64
+
65
+ assert_equal 'Custom/something', received_data[:stats].keys.sort[0].name
66
+ assert_equal ['txn0'], received_data[:transaction_traces]
67
+ assert_equal ['err0'], received_data[:error_traces].sort
68
+ end
69
+
70
+ def test_shutdown_sends_EOF
71
+ received_data = data_from_forked_process do
72
+ @service.shutdown(Time.now)
73
+ end
74
+ assert_equal 'EOF', received_data[:EOF]
75
+ end
76
+
77
+ def test_shutdown_closes_pipe
78
+ data_from_forked_process do
79
+ @service.shutdown(Time.now)
80
+ assert NewRelic::Agent::PipeChannelManager \
81
+ .channels[:pipe_service_test].closed?
82
+ end
83
+ end
84
+ end
85
+
86
+ def generate_metric_data(metric_name, data=1.0)
87
+ engine = NewRelic::Agent::StatsEngine.new
88
+ engine.get_stats_no_scope(metric_name).record_data_point(data)
89
+ engine.harvest_timeslice_data({}, {}).values
90
+ end
91
+
92
+ def read_from_pipe
93
+ pipe = NewRelic::Agent::PipeChannelManager.channels[:pipe_service_test]
94
+ pipe.in.close
95
+ data = {}
96
+ while payload = pipe.out.gets("\n\n")
97
+ got = Marshal.load(payload)
98
+ if got == 'EOF'
99
+ got = {:EOF => 'EOF'}
100
+ end
101
+ data.merge!(got)
102
+ end
103
+ data
104
+ end
105
+
106
+ def data_from_forked_process
107
+ pid = Process.fork do
108
+ yield
109
+ end
110
+ Process.wait(pid)
111
+ read_from_pipe
112
+ end
113
+ end
@@ -83,7 +83,9 @@ class NewRelic::Agent::RpmAgentTest < Test::Unit::TestCase # ActiveSupport::Test
83
83
  should "send_timeslice_data" do
84
84
  # this test fails due to a rubinius bug
85
85
  return if NewRelic::LanguageSupport.using_engine?('rbx')
86
- @agent.expects(:invoke_remote).returns({NewRelic::MetricSpec.new("/A/b/c") => 1, NewRelic::MetricSpec.new("/A/b/c", "/X") => 2, NewRelic::MetricSpec.new("/A/b/d") => 3 }.to_a)
86
+ @agent.service.expects(:metric_data).returns({ NewRelic::MetricSpec.new("/A/b/c") => 1,
87
+ NewRelic::MetricSpec.new("/A/b/c", "/X") => 2,
88
+ NewRelic::MetricSpec.new("/A/b/d") => 3 }.to_a)
87
89
  @agent.send :harvest_and_send_timeslice_data
88
90
  assert_equal 3, @agent.metric_ids.size
89
91
  assert_equal 3, @agent.metric_ids[NewRelic::MetricSpec.new("/A/b/d") ], @agent.metric_ids.inspect
@@ -106,34 +108,6 @@ class NewRelic::Agent::RpmAgentTest < Test::Unit::TestCase # ActiveSupport::Test
106
108
  assert_match /\d\.\d+\.\d+/, NewRelic::VERSION::STRING
107
109
  end
108
110
 
109
- should "invoke_remote__ignore_non_200_results" do
110
- NewRelic::Agent::Agent.class_eval do
111
- public :invoke_remote
112
- end
113
- response_mock = mock()
114
- Net::HTTP.any_instance.stubs(:request).returns(response_mock)
115
- response_mock.stubs(:message).returns("bogus error")
116
-
117
- for code in %w[500 504 400 302 503] do
118
- assert_raise NewRelic::Agent::ServerConnectionException, "Ignore #{code}" do
119
- response_mock.stubs(:code).returns(code)
120
- NewRelic::Agent.agent.invoke_remote :get_data_report_period, 0
121
- end
122
- end
123
- end
124
- should "invoke_remote__throw_other_errors" do
125
- NewRelic::Agent::Agent.class_eval do
126
- public :invoke_remote
127
- end
128
- response_mock = Net::HTTPSuccess.new nil, nil, nil
129
- response_mock.stubs(:body).returns("")
130
- Marshal.stubs(:load).raises(RuntimeError, "marshal issue")
131
- Net::HTTP.any_instance.stubs(:request).returns(response_mock)
132
- assert_raise RuntimeError do
133
- NewRelic::Agent.agent.invoke_remote :get_data_report_period, 0xFEFE
134
- end
135
- end
136
-
137
111
  context "with transaction api" do
138
112
  should "reject empty arguments" do
139
113
  assert_raises RuntimeError do
@@ -143,7 +117,6 @@ class NewRelic::Agent::RpmAgentTest < Test::Unit::TestCase # ActiveSupport::Test
143
117
  should "record a transaction" do
144
118
  NewRelic::Agent.record_transaction 0.5, 'uri' => "/users/create?foo=bar"
145
119
  end
146
-
147
120
  end
148
121
  end
149
122
  end