newrelic_rpm 3.7.0.174.beta → 3.7.0.177
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +27 -4
- data/bin/nrdebug +10 -4
- data/lib/new_relic/agent.rb +33 -11
- data/lib/new_relic/agent/agent.rb +83 -120
- data/lib/new_relic/agent/agent_logger.rb +28 -16
- data/lib/new_relic/agent/audit_logger.rb +3 -4
- data/lib/new_relic/agent/autostart.rb +20 -8
- data/lib/new_relic/agent/commands/agent_command_router.rb +26 -17
- data/lib/new_relic/agent/commands/thread_profiler_session.rb +2 -2
- data/lib/new_relic/agent/configuration/default_source.rb +146 -59
- data/lib/new_relic/agent/configuration/manager.rb +3 -3
- data/lib/new_relic/agent/cross_app_monitor.rb +15 -40
- data/lib/new_relic/agent/cross_app_tracing.rb +20 -12
- data/lib/new_relic/agent/database.rb +24 -0
- data/lib/new_relic/agent/error_collector.rb +6 -2
- data/lib/new_relic/agent/instrumentation/merb/controller.rb +3 -1
- data/lib/new_relic/agent/javascript_instrumentor.rb +187 -0
- data/lib/new_relic/agent/new_relic_service.rb +30 -22
- data/lib/new_relic/agent/obfuscator.rb +48 -0
- data/lib/new_relic/agent/request_sampler.rb +5 -13
- data/lib/new_relic/agent/shim_agent.rb +1 -0
- data/lib/new_relic/agent/sql_sampler.rb +15 -5
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +9 -4
- data/lib/new_relic/agent/transaction.rb +0 -1
- data/lib/new_relic/agent/transaction_sampler.rb +28 -16
- data/lib/new_relic/agent/transaction_state.rb +9 -0
- data/lib/new_relic/agent/transaction_timings.rb +5 -1
- data/lib/new_relic/agent/worker_loop.rb +0 -10
- data/lib/new_relic/cli/deployments.rb +1 -1
- data/lib/new_relic/control/instance_methods.rb +1 -1
- data/lib/new_relic/helper.rb +3 -1
- data/lib/new_relic/rack/browser_monitoring.rb +1 -2
- data/lib/new_relic/transaction_sample.rb +11 -13
- data/lib/newrelic_rpm.rb +1 -0
- data/test/agent_helper.rb +20 -5
- data/test/environments/lib/environments/runner.rb +1 -0
- data/test/helpers/file_searching.rb +28 -0
- data/test/multiverse/lib/multiverse/suite.rb +36 -19
- data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +49 -0
- data/test/multiverse/suites/agent_only/http_response_code_test.rb +2 -2
- data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +4 -2
- data/test/multiverse/suites/agent_only/service_timeout_test.rb +1 -1
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +7 -4
- data/test/multiverse/suites/agent_only/thread_profiling_test.rb +2 -1
- data/test/multiverse/suites/rails/error_tracing_test.rb +34 -4
- data/test/multiverse/suites/rails/ignore_test.rb +1 -1
- data/test/multiverse/suites/rails/request_statistics_test.rb +1 -3
- data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +10 -7
- data/test/multiverse/suites/sinatra/ignoring_test.rb +1 -1
- data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -1
- data/test/new_relic/agent/agent_logger_test.rb +108 -114
- data/test/new_relic/agent/agent_test.rb +139 -21
- data/test/new_relic/agent/audit_logger_test.rb +22 -20
- data/test/new_relic/agent/autostart_test.rb +3 -2
- data/test/new_relic/agent/commands/agent_command_router_test.rb +51 -32
- data/test/new_relic/agent/configuration/default_source_test.rb +8 -2
- data/test/new_relic/agent/configuration/manager_test.rb +5 -1
- data/test/new_relic/agent/configuration/orphan_configuration_test.rb +57 -0
- data/test/new_relic/agent/cross_app_monitor_test.rb +10 -26
- data/test/new_relic/agent/database_test.rb +32 -0
- data/test/new_relic/agent/error_collector_test.rb +33 -16
- data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +88 -71
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -2
- data/test/new_relic/agent/javascript_instrumentor_test.rb +341 -0
- data/test/new_relic/agent/memcache_instrumentation_test.rb +91 -89
- data/test/new_relic/agent/method_tracer_test.rb +1 -1
- data/test/new_relic/agent/obfuscator_test.rb +77 -0
- data/test/new_relic/agent/pipe_channel_manager_test.rb +5 -5
- data/test/new_relic/agent/pipe_service_test.rb +1 -1
- data/test/new_relic/agent/request_sampler_test.rb +21 -11
- data/test/new_relic/agent/sql_sampler_test.rb +52 -8
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +6 -6
- data/test/new_relic/agent/stats_engine_test.rb +18 -2
- data/test/new_relic/agent/transaction_sampler_test.rb +98 -53
- data/test/new_relic/agent/transaction_state_test.rb +44 -0
- data/test/new_relic/agent/transaction_test.rb +1 -1
- data/test/new_relic/agent/transaction_timings_test.rb +15 -5
- data/test/new_relic/agent/worker_loop_test.rb +0 -9
- data/test/new_relic/agent_test.rb +9 -21
- data/test/new_relic/data_container_tests.rb +72 -0
- data/test/new_relic/fake_collector.rb +69 -20
- data/test/new_relic/http_client_test_cases.rb +17 -2
- data/test/new_relic/license_test.rb +6 -15
- data/test/new_relic/multiverse_helpers.rb +2 -3
- data/test/new_relic/rack/browser_monitoring_test.rb +15 -37
- data/test/new_relic/transaction_sample_test.rb +92 -62
- data/test/performance/suites/rum_autoinsertion.rb +0 -3
- data/test/rum/x_ua_meta_tag_spaces_around_equals.result.html +10 -0
- data/test/rum/x_ua_meta_tag_spaces_around_equals.source.html +10 -0
- data/test/test_helper.rb +9 -5
- metadata +29 -11
- metadata.gz.sig +0 -0
- data/lib/new_relic/agent/beacon_configuration.rb +0 -37
- data/lib/new_relic/agent/browser_monitoring.rb +0 -257
- data/test/new_relic/agent/beacon_configuration_test.rb +0 -44
- data/test/new_relic/agent/browser_monitoring_test.rb +0 -474
@@ -3,6 +3,7 @@
|
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
4
|
|
5
5
|
require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
|
6
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','data_container_tests'))
|
6
7
|
require 'new_relic/agent/internal_agent_error'
|
7
8
|
|
8
9
|
class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
@@ -13,7 +14,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
13
14
|
@error_collector = NewRelic::Agent::ErrorCollector.new
|
14
15
|
@error_collector.stubs(:enabled).returns(true)
|
15
16
|
|
16
|
-
NewRelic::Agent.instance.stats_engine.
|
17
|
+
NewRelic::Agent.instance.stats_engine.reset!
|
17
18
|
end
|
18
19
|
|
19
20
|
def teardown
|
@@ -21,15 +22,31 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
21
22
|
NewRelic::Agent.config.remove_config(@test_config)
|
22
23
|
end
|
23
24
|
|
25
|
+
# Helpers for DataContainerTests
|
26
|
+
|
27
|
+
def create_container
|
28
|
+
NewRelic::Agent::ErrorCollector.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def populate_container(collector, n)
|
32
|
+
n.times do |i|
|
33
|
+
collector.notice_error('yay errors', :metric => 'path')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
include NewRelic::DataContainerTests
|
38
|
+
|
39
|
+
# Tests
|
40
|
+
|
24
41
|
def test_empty
|
25
|
-
@error_collector.
|
42
|
+
@error_collector.harvest!
|
26
43
|
@error_collector.notice_error(nil, :metric=> 'path', :request_params => {:x => 'y'})
|
27
|
-
errors = @error_collector.
|
44
|
+
errors = @error_collector.harvest!
|
28
45
|
|
29
46
|
assert_equal 0, errors.length
|
30
47
|
|
31
48
|
@error_collector.notice_error('Some error message', :metric=> 'path', :request_params => {:x => 'y'})
|
32
|
-
errors = @error_collector.
|
49
|
+
errors = @error_collector.harvest!
|
33
50
|
|
34
51
|
err = errors.first
|
35
52
|
assert_equal 'Some error message', err.message
|
@@ -44,7 +61,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
44
61
|
def test_simple
|
45
62
|
@error_collector.notice_error(StandardError.new("message"), :uri => '/myurl/', :metric => 'path', :referer => 'test_referer', :request_params => {:x => 'y'})
|
46
63
|
|
47
|
-
errors = @error_collector.
|
64
|
+
errors = @error_collector.harvest!
|
48
65
|
|
49
66
|
assert_equal errors.length, 1
|
50
67
|
|
@@ -59,7 +76,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
59
76
|
|
60
77
|
# the collector should now return an empty array since nothing
|
61
78
|
# has been added since its last harvest
|
62
|
-
errors = @error_collector.
|
79
|
+
errors = @error_collector.harvest!
|
63
80
|
assert errors.length == 0
|
64
81
|
end
|
65
82
|
|
@@ -68,7 +85,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
68
85
|
#still 1 byte / char.
|
69
86
|
@error_collector.notice_error(StandardError.new("1234567890" * 500), :uri => '/myurl/', :metric => 'path', :request_params => {:x => 'y'})
|
70
87
|
|
71
|
-
errors = @error_collector.
|
88
|
+
errors = @error_collector.harvest!
|
72
89
|
|
73
90
|
assert_equal errors.length, 1
|
74
91
|
|
@@ -80,14 +97,14 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
80
97
|
def test_collect_failover
|
81
98
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'first', :request_params => {:x => 'y'})
|
82
99
|
|
83
|
-
errors = @error_collector.
|
100
|
+
errors = @error_collector.harvest!
|
84
101
|
|
85
102
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'second', :request_params => {:x => 'y'})
|
86
103
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'path', :request_params => {:x => 'y'})
|
87
104
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'last', :request_params => {:x => 'y'})
|
88
105
|
|
89
106
|
@error_collector.merge!(errors)
|
90
|
-
errors = @error_collector.
|
107
|
+
errors = @error_collector.harvest!
|
91
108
|
|
92
109
|
assert_equal 4, errors.length
|
93
110
|
assert_equal_unordered(%w(first second path last), errors.map { |e| e.path })
|
@@ -95,7 +112,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
95
112
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'first', :request_params => {:x => 'y'})
|
96
113
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'last', :request_params => {:x => 'y'})
|
97
114
|
|
98
|
-
errors = @error_collector.
|
115
|
+
errors = @error_collector.harvest!
|
99
116
|
assert_equal 2, errors.length
|
100
117
|
assert_equal 'first', errors.first.path
|
101
118
|
assert_equal 'last', errors.last.path
|
@@ -111,7 +128,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
111
128
|
end
|
112
129
|
end
|
113
130
|
|
114
|
-
errors = @error_collector.
|
131
|
+
errors = @error_collector.harvest!
|
115
132
|
assert errors.length == max_q_length
|
116
133
|
errors.each_index do |i|
|
117
134
|
err = errors.shift
|
@@ -138,7 +155,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
138
155
|
types.each do |test|
|
139
156
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'path',
|
140
157
|
:request_params => {:x => test[0]})
|
141
|
-
assert_equal test[1], @error_collector.
|
158
|
+
assert_equal test[1], @error_collector.harvest![0].params[:request_params][:x]
|
142
159
|
end
|
143
160
|
end
|
144
161
|
|
@@ -148,7 +165,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
148
165
|
|
149
166
|
@error_collector.notice_error(IOError.new("message"), :metric => 'path', :request_params => {:x => 'y'})
|
150
167
|
|
151
|
-
errors = @error_collector.
|
168
|
+
errors = @error_collector.harvest!
|
152
169
|
|
153
170
|
assert_equal 0, errors.length
|
154
171
|
end
|
@@ -159,7 +176,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
159
176
|
NewRelic::Agent.config.apply_config(:'error_collector.ignore_errors' => "IOError")
|
160
177
|
@error_collector.notice_error(IOError.new("message"))
|
161
178
|
|
162
|
-
errors = @error_collector.
|
179
|
+
errors = @error_collector.harvest!
|
163
180
|
|
164
181
|
assert_equal 1, errors.length
|
165
182
|
|
@@ -171,7 +188,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
171
188
|
@error_collector.notice_error(IOError.new("message"), :metric => 'path', :request_params => {:x => 'y'})
|
172
189
|
@error_collector.notice_error(StandardError.new("message"), :metric => 'path', :request_params => {:x => 'y'})
|
173
190
|
|
174
|
-
errors = @error_collector.
|
191
|
+
errors = @error_collector.harvest!
|
175
192
|
|
176
193
|
assert_equal 1, errors.length
|
177
194
|
end
|
@@ -181,7 +198,7 @@ class NewRelic::Agent::ErrorCollectorTest < Test::Unit::TestCase
|
|
181
198
|
@error_collector.notice_error(StandardError.new("YO SQL BAD: serect * flom test where foo = 'bar'"))
|
182
199
|
@error_collector.notice_error(StandardError.new("YO SQL BAD: serect * flom test where foo in (1,2,3,4,5)"))
|
183
200
|
|
184
|
-
errors = @error_collector.
|
201
|
+
errors = @error_collector.harvest!
|
185
202
|
|
186
203
|
assert_equal(NewRelic::NoticedError::STRIPPED_EXCEPTION_REPLACEMENT_MESSAGE, errors[0].message)
|
187
204
|
assert_equal(NewRelic::NoticedError::STRIPPED_EXCEPTION_REPLACEMENT_MESSAGE, errors[1].message)
|
@@ -372,102 +372,119 @@ class NewRelic::Agent::Instrumentation::ActiveRecordInstrumentationTest < Test::
|
|
372
372
|
end
|
373
373
|
|
374
374
|
def test_prepare_to_send
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
375
|
+
with_config(:'transaction_tracer.explain_enabled' => true,
|
376
|
+
:'transaction_tracer.explain_threshold' => 0.0) do
|
377
|
+
perform_action_with_newrelic_trace :name => 'bogosity' do
|
378
|
+
ActiveRecordFixtures::Order.add_delay
|
379
|
+
all_finder(ActiveRecordFixtures::Order)
|
380
|
+
end
|
381
|
+
sample = NewRelic::Agent.instance.transaction_sampler.last_sample
|
382
|
+
assert_not_nil sample
|
383
|
+
|
384
|
+
includes_gc = false
|
385
|
+
sample.each_segment {|s| includes_gc ||= s.metric_name =~ /GC/ }
|
386
|
+
|
387
|
+
sql_segment = last_segment(sample)
|
388
|
+
assert_not_nil sql_segment, sample.to_s
|
389
|
+
assert_match /^SELECT /, sql_segment.params[:sql]
|
390
|
+
assert sql_segment.duration > 0.0, "Segment duration must be greater than zero."
|
391
|
+
sample = sample.prepare_to_send!
|
392
|
+
sql_segment = last_segment(sample)
|
393
|
+
assert_match /^SELECT /, sql_segment.params[:sql]
|
394
|
+
explanations = sql_segment.params[:explain_plan]
|
395
|
+
if (isMysql? || isPostgres?) && !NewRelic::LanguageSupport.using_engine?('jruby')
|
396
|
+
assert_not_nil explanations, "No explains in segment: #{sql_segment}"
|
397
|
+
assert_equal(2, explanations.size,
|
398
|
+
"No explains in segment: #{sql_segment}")
|
399
|
+
end
|
397
400
|
end
|
398
401
|
end
|
399
402
|
|
400
403
|
def test_transaction_mysql
|
401
404
|
return unless isMysql? && !defined?(JRuby)
|
402
405
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
ActiveRecordFixtures
|
407
|
-
|
408
|
-
|
406
|
+
with_config(:record_sql => :obfuscated,
|
407
|
+
:'transaction_tracer.explain_enabled' => true,
|
408
|
+
:'transaction_tracer.explain_threshold' => 0.0) do
|
409
|
+
ActiveRecordFixtures.setup
|
410
|
+
sample = NewRelic::Agent.instance.transaction_sampler.reset!
|
411
|
+
perform_action_with_newrelic_trace :name => 'bogosity' do
|
412
|
+
ActiveRecordFixtures::Order.add_delay
|
413
|
+
all_finder(ActiveRecordFixtures::Order)
|
414
|
+
end
|
409
415
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
+
sample = NewRelic::Agent.instance.transaction_sampler.last_sample
|
417
|
+
sample = sample.prepare_to_send!
|
418
|
+
segment = last_segment(sample)
|
419
|
+
explanation = segment.params[:explain_plan]
|
420
|
+
assert_not_nil explanation, "No explains in segment: #{segment}"
|
421
|
+
assert_equal 2, explanation.size,"No explains in segment: #{segment}"
|
416
422
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
423
|
+
assert_equal 10, explanation[0].size
|
424
|
+
['id', 'select_type', 'table'].each do |c|
|
425
|
+
assert explanation[0].include?(c)
|
426
|
+
end
|
427
|
+
['1', 'SIMPLE', ActiveRecordFixtures::Order.table_name].each do |c|
|
428
|
+
assert explanation[1][0].include?(c)
|
429
|
+
end
|
424
430
|
|
425
|
-
|
426
|
-
|
431
|
+
s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
|
432
|
+
assert_equal 1, s.call_count
|
433
|
+
end
|
427
434
|
end
|
428
435
|
|
429
436
|
def test_transaction_postgres
|
430
437
|
return unless isPostgres?
|
431
|
-
# note that our current test builds do not use postgres, this is
|
432
|
-
# here strictly for troubleshooting, not CI builds
|
433
|
-
sample = NewRelic::Agent.instance.transaction_sampler.reset!
|
434
|
-
perform_action_with_newrelic_trace :name => 'bogosity' do
|
435
|
-
ActiveRecordFixtures::Order.add_delay
|
436
|
-
all_finder(ActiveRecordFixtures::Order)
|
437
|
-
end
|
438
438
|
|
439
|
-
|
439
|
+
with_config(:record_sql => :obfuscated,
|
440
|
+
:'transaction_tracer.explain_enabled' => true,
|
441
|
+
:'transaction_tracer.explain_threshold' => 0.0) do
|
442
|
+
# note that our current test builds do not use postgres, this is
|
443
|
+
# here strictly for troubleshooting, not CI builds
|
444
|
+
sample = NewRelic::Agent.instance.transaction_sampler.reset!
|
445
|
+
perform_action_with_newrelic_trace :name => 'bogosity' do
|
446
|
+
ActiveRecordFixtures::Order.add_delay
|
447
|
+
all_finder(ActiveRecordFixtures::Order)
|
448
|
+
end
|
449
|
+
|
450
|
+
sample = NewRelic::Agent.instance.transaction_sampler.last_sample
|
440
451
|
|
441
|
-
|
442
|
-
|
443
|
-
|
452
|
+
sample = sample.prepare_to_send!
|
453
|
+
segment = last_segment(sample)
|
454
|
+
explanations = segment.params[:explain_plan]
|
444
455
|
|
445
|
-
|
446
|
-
|
447
|
-
|
456
|
+
assert_not_nil explanations, "No explains in segment: #{segment}"
|
457
|
+
assert_equal 1, explanations.size,"No explains in segment: #{segment}"
|
458
|
+
assert_equal 1, explanations.first.size
|
448
459
|
|
449
|
-
|
450
|
-
|
460
|
+
assert_equal("Explain Plan", explanations[0][0])
|
461
|
+
assert_match /Seq Scan on test_data/, explanations[0][1].join(";")
|
451
462
|
|
452
|
-
|
453
|
-
|
463
|
+
s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
|
464
|
+
assert_equal 1, s.call_count
|
465
|
+
end
|
454
466
|
end
|
455
467
|
|
456
468
|
def test_transaction_other
|
457
469
|
return if isMysql? || isPostgres?
|
458
|
-
sample = NewRelic::Agent.instance.transaction_sampler.reset!
|
459
|
-
perform_action_with_newrelic_trace :name => 'bogosity' do
|
460
|
-
ActiveRecordFixtures::Order.add_delay
|
461
|
-
all_finder(ActiveRecordFixtures::Order)
|
462
|
-
end
|
463
470
|
|
464
|
-
|
471
|
+
with_config(:record_sql => :obfuscated,
|
472
|
+
:'transaction_tracer.explain_enabled' => true,
|
473
|
+
:'transaction_tracer.explain_threshold' => 0.0) do
|
474
|
+
sample = NewRelic::Agent.instance.transaction_sampler.reset!
|
475
|
+
perform_action_with_newrelic_trace :name => 'bogosity' do
|
476
|
+
ActiveRecordFixtures::Order.add_delay
|
477
|
+
all_finder(ActiveRecordFixtures::Order)
|
478
|
+
end
|
465
479
|
|
466
|
-
|
467
|
-
segment = last_segment(sample)
|
480
|
+
sample = NewRelic::Agent.instance.transaction_sampler.last_sample
|
468
481
|
|
469
|
-
|
470
|
-
|
482
|
+
sample = sample.prepare_to_send!
|
483
|
+
segment = last_segment(sample)
|
484
|
+
|
485
|
+
s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
|
486
|
+
assert_equal 1, s.call_count
|
487
|
+
end
|
471
488
|
end
|
472
489
|
|
473
490
|
# These are only valid for rails 2.1 and later
|
@@ -147,9 +147,9 @@ class NewRelic::Agent::Instrumentation::TaskInstrumentationTest < Test::Unit::Te
|
|
147
147
|
end
|
148
148
|
|
149
149
|
def test_error_collector_captures_custom_params
|
150
|
-
@agent.error_collector.
|
150
|
+
@agent.error_collector.harvest!
|
151
151
|
run_task_exception rescue nil
|
152
|
-
errors = @agent.error_collector.
|
152
|
+
errors = @agent.error_collector.harvest!
|
153
153
|
|
154
154
|
assert_equal(1, errors.size)
|
155
155
|
error = errors.first
|
@@ -0,0 +1,341 @@
|
|
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/javascript_instrumentor"
|
7
|
+
require "base64"
|
8
|
+
|
9
|
+
class NewRelic::Agent::JavascriptInstrumentorTest < Test::Unit::TestCase
|
10
|
+
attr_reader :instrumentor
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@config = {
|
14
|
+
:application_id => '5, 6', # collector can return app multiple ids
|
15
|
+
:beacon => 'beacon',
|
16
|
+
:browser_key => 'browserKey',
|
17
|
+
:js_agent_loader => 'loader',
|
18
|
+
:license_key => "\0", # no-op obfuscation key
|
19
|
+
:'rum.enabled' => true
|
20
|
+
}
|
21
|
+
NewRelic::Agent.config.apply_config(@config)
|
22
|
+
|
23
|
+
events = stub(:subscribe => nil)
|
24
|
+
@instrumentor = NewRelic::Agent::JavascriptInstrumentor.new(events)
|
25
|
+
|
26
|
+
# By default we expect our transaction to have a start time
|
27
|
+
# All sorts of basics don't output without this setup initially
|
28
|
+
NewRelic::Agent::TransactionState.reset(nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
def teardown
|
32
|
+
NewRelic::Agent::TransactionState.clear
|
33
|
+
NewRelic::Agent.config.remove_config(@config)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_js_errors_beta_default_gets_default_loader
|
37
|
+
assert_equal "rum", NewRelic::Agent.config[:'browser_monitoring.loader']
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_js_errors_beta_gets_full_loader
|
41
|
+
with_config(:js_errors_beta => true) do
|
42
|
+
assert_equal "full", NewRelic::Agent.config[:'browser_monitoring.loader']
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_js_errors_beta_off_gets_default_loader
|
47
|
+
with_config(:js_errors_beta => false) do
|
48
|
+
assert_equal "rum", NewRelic::Agent.config[:'browser_monitoring.loader']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_auto_instrumentation_config_defaults_to_enabled
|
53
|
+
assert NewRelic::Agent.config[:'browser_monitoring.auto_instrument']
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_start_time_reset_each_request_when_auto_instrument_is_disabled
|
57
|
+
controller = Object.new
|
58
|
+
def controller.perform_action_without_newrelic_trace(method, options={});
|
59
|
+
# noop; instrument me
|
60
|
+
end
|
61
|
+
def controller.newrelic_metric_path; "foo"; end
|
62
|
+
controller.extend ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
63
|
+
|
64
|
+
with_config(:'browser_monitoring.auto_instrument' => false) do
|
65
|
+
controller.perform_action_with_newrelic_trace(:index)
|
66
|
+
first_request_start_time = instrumentor.current_transaction.start_time
|
67
|
+
|
68
|
+
controller.perform_action_with_newrelic_trace(:index)
|
69
|
+
second_request_start_time = instrumentor.current_transaction.start_time
|
70
|
+
|
71
|
+
# assert that these aren't the same time object
|
72
|
+
# the start time should be reinitialized each request to the controller
|
73
|
+
assert !(first_request_start_time.equal? second_request_start_time)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_browser_timing_header_outside_transaction
|
78
|
+
assert_equal "", instrumentor.browser_timing_header
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_browser_timing_scripts_with_rum_enabled_false
|
82
|
+
in_transaction do
|
83
|
+
with_config(:'rum.enabled' => false) do
|
84
|
+
assert_equal "", instrumentor.browser_timing_header
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_browser_timing_header_disable_transaction_tracing
|
90
|
+
in_transaction do
|
91
|
+
NewRelic::Agent.disable_transaction_tracing do
|
92
|
+
assert_equal "", instrumentor.browser_timing_header
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_browser_timing_header_disable_all_tracing
|
98
|
+
in_transaction do
|
99
|
+
NewRelic::Agent.disable_all_tracing do
|
100
|
+
assert_equal "", instrumentor.browser_timing_header
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_browser_timing_header_without_loader
|
106
|
+
in_transaction do
|
107
|
+
with_config(:js_agent_loader => '') do
|
108
|
+
assert_equal "", instrumentor.browser_timing_header
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_browser_timing_header_without_beacon
|
114
|
+
in_transaction do
|
115
|
+
with_config(:beacon => '') do
|
116
|
+
assert_equal "", instrumentor.browser_timing_header
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_browser_timing_header_without_browser_key
|
122
|
+
in_transaction do
|
123
|
+
with_config(:browser_key => '') do
|
124
|
+
assert_equal "", instrumentor.browser_timing_header
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_browser_timing_header_with_ignored_enduser
|
130
|
+
in_transaction do
|
131
|
+
NewRelic::Agent::TransactionState.get.request_ignore_enduser = true
|
132
|
+
assert_equal "", instrumentor.browser_timing_header
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_browser_timing_header_with_default_settings
|
137
|
+
in_transaction do
|
138
|
+
header = instrumentor.browser_timing_header
|
139
|
+
assert_has_js_agent_loader(header)
|
140
|
+
assert_has_text(BEGINNING_OF_FOOTER, header)
|
141
|
+
assert_has_text(END_OF_FOOTER, header)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_data_for_js_agent_extra_parameter
|
146
|
+
in_transaction do
|
147
|
+
with_config(CAPTURE_ATTRIBUTES_PAGE_EVENTS => true) do
|
148
|
+
NewRelic::Agent.add_custom_parameters({:boo => "hoo"})
|
149
|
+
assert_equal({:boo => "hoo"}, instrumentor.data_for_js_agent_extra_parameter)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_data_for_js_agent_extra_parameter_outside_transaction
|
155
|
+
with_config(CAPTURE_ATTRIBUTES_PAGE_EVENTS => true) do
|
156
|
+
NewRelic::Agent.add_custom_parameters({:boo => "hoo"})
|
157
|
+
assert_empty instrumentor.data_for_js_agent_extra_parameter
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_format
|
162
|
+
assert_formatted({:a => "1", "b" => 2}, "a=1", "b=#2")
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_format_extra_data_escaping
|
166
|
+
assert_formatted({"semi;colon" => "gets;escaped"}, "semi:colon=gets:escaped")
|
167
|
+
assert_formatted({"equal=key" => "equal=value"}, "equal-key=equal-value")
|
168
|
+
assert_formatted({'"quoted"' => '"marks"'}, %Q['quoted'='marks'])
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_format_extra_data_disallowed_types
|
172
|
+
assert_formatted_empty({"nested" => { "hashes?" => "nope" }})
|
173
|
+
assert_formatted_empty({"lists" => ["are", "they", "allowed?", "nope"]})
|
174
|
+
end
|
175
|
+
|
176
|
+
def assert_formatted(data, *expected)
|
177
|
+
result = instrumentor.format_extra_data(data).split(";")
|
178
|
+
expected.each do |expect|
|
179
|
+
assert_includes(result, expect)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def assert_formatted_empty(data)
|
184
|
+
result = instrumentor.format_extra_data(data)
|
185
|
+
assert_equal("", result)
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_config_data_for_js_agent
|
189
|
+
freeze_time
|
190
|
+
in_transaction do
|
191
|
+
with_config(CAPTURE_ATTRIBUTES_PAGE_EVENTS => true) do
|
192
|
+
NewRelic::Agent.set_user_attributes(:user => "user")
|
193
|
+
|
194
|
+
txn = NewRelic::Agent::Transaction.current
|
195
|
+
txn.stubs(:queue_time).returns(0)
|
196
|
+
txn.stubs(:start_time).returns(Time.now - 10)
|
197
|
+
txn.name = 'most recent transaction'
|
198
|
+
|
199
|
+
state = NewRelic::Agent::TransactionState.get
|
200
|
+
state.request_token = '0123456789ABCDEF'
|
201
|
+
state.request_guid = 'ABC'
|
202
|
+
|
203
|
+
data = instrumentor.data_for_js_agent
|
204
|
+
expected = {
|
205
|
+
"beacon" => "beacon",
|
206
|
+
"errorBeacon" => "",
|
207
|
+
"licenseKey" => "browserKey",
|
208
|
+
"applicationID" => "5, 6",
|
209
|
+
"transactionName" => pack("most recent transaction"),
|
210
|
+
"queueTime" => 0,
|
211
|
+
"applicationTime" => 10000,
|
212
|
+
"ttGuid" => "ABC",
|
213
|
+
"agentToken" => "0123456789ABCDEF",
|
214
|
+
"agent" => "",
|
215
|
+
"extra" => pack("user=user")
|
216
|
+
}
|
217
|
+
|
218
|
+
assert_equal(expected, data)
|
219
|
+
|
220
|
+
js = instrumentor.browser_timing_config
|
221
|
+
expected.each do |key, value|
|
222
|
+
assert_match(/"#{key.to_s}":#{formatted_for_matching(value)}/, js)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_ssl_for_http_not_included_by_default
|
229
|
+
data = instrumentor.data_for_js_agent
|
230
|
+
assert_false data.include?("sslForHttp")
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_ssl_for_http_enabled
|
234
|
+
with_config(:'browser_monitoring.ssl_for_http' => true) do
|
235
|
+
data = instrumentor.data_for_js_agent
|
236
|
+
assert data["sslForHttp"]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_ssl_for_http_disabled
|
241
|
+
with_config(:'browser_monitoring.ssl_for_http' => false) do
|
242
|
+
data = instrumentor.data_for_js_agent
|
243
|
+
assert_false data["sslForHttp"]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
ANALYTICS_ENABLED = :'analytics_events.enabled'
|
248
|
+
CAPTURE_ATTRIBUTES_PAGE_EVENTS = :'capture_attributes.page_view_events'
|
249
|
+
|
250
|
+
def test_data_for_js_agent_doesnt_pick_up_extras_by_default
|
251
|
+
in_transaction do
|
252
|
+
NewRelic::Agent.add_custom_parameters({:boo => "hoo"})
|
253
|
+
assert_extra_data_is("")
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_data_for_js_agent_picks_up_extras_when_configured
|
258
|
+
in_transaction do
|
259
|
+
with_config(ANALYTICS_ENABLED => true,
|
260
|
+
CAPTURE_ATTRIBUTES_PAGE_EVENTS => true) do
|
261
|
+
NewRelic::Agent.add_custom_parameters({:boo => "hoo"})
|
262
|
+
assert_extra_data_is("boo=hoo")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_data_for_js_agent_ignores_extras_if_no_analytics
|
268
|
+
in_transaction do
|
269
|
+
with_config(ANALYTICS_ENABLED => false,
|
270
|
+
CAPTURE_ATTRIBUTES_PAGE_EVENTS => true) do
|
271
|
+
NewRelic::Agent.add_custom_parameters({:boo => "hoo"})
|
272
|
+
assert_extra_data_is("")
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_data_for_js_agent_ignores_extras_if_not_allowed_in_page
|
278
|
+
in_transaction do
|
279
|
+
with_config(ANALYTICS_ENABLED => true,
|
280
|
+
CAPTURE_ATTRIBUTES_PAGE_EVENTS => false) do
|
281
|
+
NewRelic::Agent.add_custom_parameters({:boo => "hoo"})
|
282
|
+
assert_extra_data_is("")
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def test_html_safe_if_needed_unsafed
|
288
|
+
string = mock('string')
|
289
|
+
# here to handle 1.9 encoding - we stub this out because it should
|
290
|
+
# be handled automatically and is outside the scope of this test
|
291
|
+
string.stubs(:respond_to?).with(:encoding).returns(false)
|
292
|
+
string.expects(:respond_to?).with(:html_safe).returns(false)
|
293
|
+
assert_equal(string, instrumentor.html_safe_if_needed(string))
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_html_safe_if_needed_safed
|
297
|
+
string = mock('string')
|
298
|
+
string.expects(:respond_to?).with(:html_safe).returns(true)
|
299
|
+
string.expects(:html_safe).returns(string)
|
300
|
+
# here to handle 1.9 encoding - we stub this out because it should
|
301
|
+
# be handled automatically and is outside the scope of this test
|
302
|
+
string.stubs(:respond_to?).with(:encoding).returns(false)
|
303
|
+
assert_equal(string, instrumentor.html_safe_if_needed(string))
|
304
|
+
end
|
305
|
+
|
306
|
+
# Helpers
|
307
|
+
|
308
|
+
BEGINNING_OF_FOOTER = '<script type="text/javascript">window.NREUM||(NREUM={});NREUM.info='
|
309
|
+
END_OF_FOOTER = '}</script>'
|
310
|
+
|
311
|
+
def assert_has_js_agent_loader(header)
|
312
|
+
assert_match(%Q[\n<script type=\"text/javascript\">loader</script>],
|
313
|
+
header,
|
314
|
+
"expected new JS agent loader 'loader' but saw '#{header}'")
|
315
|
+
end
|
316
|
+
|
317
|
+
def assert_has_text(snippet, footer)
|
318
|
+
assert(footer.include?(snippet), "Expected footer to include snippet: #{snippet}, but instead was #{footer}")
|
319
|
+
end
|
320
|
+
|
321
|
+
def assert_extra_data_is(expected)
|
322
|
+
data = instrumentor.data_for_js_agent
|
323
|
+
assert_equal pack(expected), data["extra"]
|
324
|
+
end
|
325
|
+
|
326
|
+
def pack(text)
|
327
|
+
[text].pack("m0").gsub("\n", "")
|
328
|
+
end
|
329
|
+
|
330
|
+
def formatted_for_matching(value)
|
331
|
+
case value
|
332
|
+
when String
|
333
|
+
%Q["#{value}"]
|
334
|
+
when NilClass
|
335
|
+
"null"
|
336
|
+
else
|
337
|
+
value
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|