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.
Files changed (97) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +27 -4
  3. data/bin/nrdebug +10 -4
  4. data/lib/new_relic/agent.rb +33 -11
  5. data/lib/new_relic/agent/agent.rb +83 -120
  6. data/lib/new_relic/agent/agent_logger.rb +28 -16
  7. data/lib/new_relic/agent/audit_logger.rb +3 -4
  8. data/lib/new_relic/agent/autostart.rb +20 -8
  9. data/lib/new_relic/agent/commands/agent_command_router.rb +26 -17
  10. data/lib/new_relic/agent/commands/thread_profiler_session.rb +2 -2
  11. data/lib/new_relic/agent/configuration/default_source.rb +146 -59
  12. data/lib/new_relic/agent/configuration/manager.rb +3 -3
  13. data/lib/new_relic/agent/cross_app_monitor.rb +15 -40
  14. data/lib/new_relic/agent/cross_app_tracing.rb +20 -12
  15. data/lib/new_relic/agent/database.rb +24 -0
  16. data/lib/new_relic/agent/error_collector.rb +6 -2
  17. data/lib/new_relic/agent/instrumentation/merb/controller.rb +3 -1
  18. data/lib/new_relic/agent/javascript_instrumentor.rb +187 -0
  19. data/lib/new_relic/agent/new_relic_service.rb +30 -22
  20. data/lib/new_relic/agent/obfuscator.rb +48 -0
  21. data/lib/new_relic/agent/request_sampler.rb +5 -13
  22. data/lib/new_relic/agent/shim_agent.rb +1 -0
  23. data/lib/new_relic/agent/sql_sampler.rb +15 -5
  24. data/lib/new_relic/agent/stats_engine/metric_stats.rb +9 -4
  25. data/lib/new_relic/agent/transaction.rb +0 -1
  26. data/lib/new_relic/agent/transaction_sampler.rb +28 -16
  27. data/lib/new_relic/agent/transaction_state.rb +9 -0
  28. data/lib/new_relic/agent/transaction_timings.rb +5 -1
  29. data/lib/new_relic/agent/worker_loop.rb +0 -10
  30. data/lib/new_relic/cli/deployments.rb +1 -1
  31. data/lib/new_relic/control/instance_methods.rb +1 -1
  32. data/lib/new_relic/helper.rb +3 -1
  33. data/lib/new_relic/rack/browser_monitoring.rb +1 -2
  34. data/lib/new_relic/transaction_sample.rb +11 -13
  35. data/lib/newrelic_rpm.rb +1 -0
  36. data/test/agent_helper.rb +20 -5
  37. data/test/environments/lib/environments/runner.rb +1 -0
  38. data/test/helpers/file_searching.rb +28 -0
  39. data/test/multiverse/lib/multiverse/suite.rb +36 -19
  40. data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +49 -0
  41. data/test/multiverse/suites/agent_only/http_response_code_test.rb +2 -2
  42. data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +4 -2
  43. data/test/multiverse/suites/agent_only/service_timeout_test.rb +1 -1
  44. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +7 -4
  45. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +2 -1
  46. data/test/multiverse/suites/rails/error_tracing_test.rb +34 -4
  47. data/test/multiverse/suites/rails/ignore_test.rb +1 -1
  48. data/test/multiverse/suites/rails/request_statistics_test.rb +1 -3
  49. data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +10 -7
  50. data/test/multiverse/suites/sinatra/ignoring_test.rb +1 -1
  51. data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -1
  52. data/test/new_relic/agent/agent_logger_test.rb +108 -114
  53. data/test/new_relic/agent/agent_test.rb +139 -21
  54. data/test/new_relic/agent/audit_logger_test.rb +22 -20
  55. data/test/new_relic/agent/autostart_test.rb +3 -2
  56. data/test/new_relic/agent/commands/agent_command_router_test.rb +51 -32
  57. data/test/new_relic/agent/configuration/default_source_test.rb +8 -2
  58. data/test/new_relic/agent/configuration/manager_test.rb +5 -1
  59. data/test/new_relic/agent/configuration/orphan_configuration_test.rb +57 -0
  60. data/test/new_relic/agent/cross_app_monitor_test.rb +10 -26
  61. data/test/new_relic/agent/database_test.rb +32 -0
  62. data/test/new_relic/agent/error_collector_test.rb +33 -16
  63. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +88 -71
  64. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -2
  65. data/test/new_relic/agent/javascript_instrumentor_test.rb +341 -0
  66. data/test/new_relic/agent/memcache_instrumentation_test.rb +91 -89
  67. data/test/new_relic/agent/method_tracer_test.rb +1 -1
  68. data/test/new_relic/agent/obfuscator_test.rb +77 -0
  69. data/test/new_relic/agent/pipe_channel_manager_test.rb +5 -5
  70. data/test/new_relic/agent/pipe_service_test.rb +1 -1
  71. data/test/new_relic/agent/request_sampler_test.rb +21 -11
  72. data/test/new_relic/agent/sql_sampler_test.rb +52 -8
  73. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +6 -6
  74. data/test/new_relic/agent/stats_engine_test.rb +18 -2
  75. data/test/new_relic/agent/transaction_sampler_test.rb +98 -53
  76. data/test/new_relic/agent/transaction_state_test.rb +44 -0
  77. data/test/new_relic/agent/transaction_test.rb +1 -1
  78. data/test/new_relic/agent/transaction_timings_test.rb +15 -5
  79. data/test/new_relic/agent/worker_loop_test.rb +0 -9
  80. data/test/new_relic/agent_test.rb +9 -21
  81. data/test/new_relic/data_container_tests.rb +72 -0
  82. data/test/new_relic/fake_collector.rb +69 -20
  83. data/test/new_relic/http_client_test_cases.rb +17 -2
  84. data/test/new_relic/license_test.rb +6 -15
  85. data/test/new_relic/multiverse_helpers.rb +2 -3
  86. data/test/new_relic/rack/browser_monitoring_test.rb +15 -37
  87. data/test/new_relic/transaction_sample_test.rb +92 -62
  88. data/test/performance/suites/rum_autoinsertion.rb +0 -3
  89. data/test/rum/x_ua_meta_tag_spaces_around_equals.result.html +10 -0
  90. data/test/rum/x_ua_meta_tag_spaces_around_equals.source.html +10 -0
  91. data/test/test_helper.rb +9 -5
  92. metadata +29 -11
  93. metadata.gz.sig +0 -0
  94. data/lib/new_relic/agent/beacon_configuration.rb +0 -37
  95. data/lib/new_relic/agent/browser_monitoring.rb +0 -257
  96. data/test/new_relic/agent/beacon_configuration_test.rb +0 -44
  97. 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.reset_stats
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.harvest_errors
42
+ @error_collector.harvest!
26
43
  @error_collector.notice_error(nil, :metric=> 'path', :request_params => {:x => 'y'})
27
- errors = @error_collector.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors[0].params[:request_params][:x]
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.harvest_errors
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.harvest_errors
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.harvest_errors
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.harvest_errors
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
- perform_action_with_newrelic_trace :name => 'bogosity' do
376
- ActiveRecordFixtures::Order.add_delay
377
- all_finder(ActiveRecordFixtures::Order)
378
- end
379
- sample = NewRelic::Agent.instance.transaction_sampler.last_sample
380
- assert_not_nil sample
381
-
382
- includes_gc = false
383
- sample.each_segment {|s| includes_gc ||= s.metric_name =~ /GC/ }
384
-
385
- sql_segment = last_segment(sample)
386
- assert_not_nil sql_segment, sample.to_s
387
- assert_match /^SELECT /, sql_segment.params[:sql]
388
- assert sql_segment.duration > 0.0, "Segment duration must be greater than zero."
389
- sample = sample.prepare_to_send!(:record_sql => :raw, :explain_sql => 0.0)
390
- sql_segment = last_segment(sample)
391
- assert_match /^SELECT /, sql_segment.params[:sql]
392
- explanations = sql_segment.params[:explain_plan]
393
- if (isMysql? || isPostgres?) && !NewRelic::LanguageSupport.using_engine?('jruby')
394
- assert_not_nil explanations, "No explains in segment: #{sql_segment}"
395
- assert_equal(2, explanations.size,
396
- "No explains in segment: #{sql_segment}")
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
- ActiveRecordFixtures.setup
404
- sample = NewRelic::Agent.instance.transaction_sampler.reset!
405
- perform_action_with_newrelic_trace :name => 'bogosity' do
406
- ActiveRecordFixtures::Order.add_delay
407
- all_finder(ActiveRecordFixtures::Order)
408
- end
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
- sample = NewRelic::Agent.instance.transaction_sampler.last_sample
411
- sample = sample.prepare_to_send!(:record_sql => :obfuscated, :explain_sql => 0.0)
412
- segment = last_segment(sample)
413
- explanation = segment.params[:explain_plan]
414
- assert_not_nil explanation, "No explains in segment: #{segment}"
415
- assert_equal 2, explanation.size,"No explains in segment: #{segment}"
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
- assert_equal 10, explanation[0].size
418
- ['id', 'select_type', 'table'].each do |c|
419
- assert explanation[0].include?(c)
420
- end
421
- ['1', 'SIMPLE', ActiveRecordFixtures::Order.table_name].each do |c|
422
- assert explanation[1][0].include?(c)
423
- end
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
- s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
426
- assert_equal 1, s.call_count
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
- sample = NewRelic::Agent.instance.transaction_sampler.last_sample
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
- sample = sample.prepare_to_send!(:record_sql => :obfuscated, :explain_sql => 0.0)
442
- segment = last_segment(sample)
443
- explanations = segment.params[:explain_plan]
452
+ sample = sample.prepare_to_send!
453
+ segment = last_segment(sample)
454
+ explanations = segment.params[:explain_plan]
444
455
 
445
- assert_not_nil explanations, "No explains in segment: #{segment}"
446
- assert_equal 1, explanations.size,"No explains in segment: #{segment}"
447
- assert_equal 1, explanations.first.size
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
- assert_equal("Explain Plan", explanations[0][0])
450
- assert_match /Seq Scan on test_data/, explanations[0][1].join(";")
460
+ assert_equal("Explain Plan", explanations[0][0])
461
+ assert_match /Seq Scan on test_data/, explanations[0][1].join(";")
451
462
 
452
- s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
453
- assert_equal 1, s.call_count
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
- sample = NewRelic::Agent.instance.transaction_sampler.last_sample
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
- sample = sample.prepare_to_send!(:record_sql => :obfuscated, :explain_sql => 0.0)
467
- segment = last_segment(sample)
480
+ sample = NewRelic::Agent.instance.transaction_sampler.last_sample
468
481
 
469
- s = NewRelic::Agent.get_stats("ActiveRecord/ActiveRecordFixtures::Order/find")
470
- assert_equal 1, s.call_count
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.harvest_errors
150
+ @agent.error_collector.harvest!
151
151
  run_task_exception rescue nil
152
- errors = @agent.error_collector.harvest_errors
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