newrelic_rpm 3.5.5.540.dev → 3.5.6.42.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/.gitignore +1 -1
  2. data/CHANGELOG +7 -0
  3. data/Rakefile +9 -18
  4. data/lib/new_relic/agent/agent.rb +51 -83
  5. data/lib/new_relic/agent/configuration/manager.rb +12 -0
  6. data/lib/new_relic/agent/configuration/yaml_source.rb +5 -1
  7. data/lib/new_relic/agent/cross_process_monitoring.rb +164 -20
  8. data/lib/new_relic/agent/error_collector.rb +2 -0
  9. data/lib/new_relic/agent/event_listener.rb +39 -0
  10. data/lib/new_relic/agent/instrumentation/browser_monitoring_timings.rb +17 -7
  11. data/lib/new_relic/agent/stats_engine/transactions.rb +1 -0
  12. data/lib/new_relic/build.rb +1 -0
  13. data/lib/new_relic/control/frameworks/rails.rb +17 -3
  14. data/lib/new_relic/rack/agent_hooks.rb +20 -0
  15. data/lib/new_relic/rack/error_collector.rb +11 -1
  16. data/lib/new_relic/recipes.rb +32 -10
  17. data/lib/new_relic/version.rb +10 -15
  18. data/newrelic.yml +6 -0
  19. data/newrelic_rpm.gemspec +23 -454
  20. data/test/multiverse/lib/multiverse/suite.rb +2 -0
  21. data/test/multiverse/suites/active_record/Envfile +1 -1
  22. data/test/multiverse/suites/active_record/config/newrelic.yml +2 -2
  23. data/test/multiverse/suites/agent_only/Envfile +2 -1
  24. data/test/multiverse/suites/agent_only/config/newrelic.yml +3 -1
  25. data/test/multiverse/suites/agent_only/cross_process_test.rb +56 -0
  26. data/test/multiverse/suites/{logging → agent_only}/logging_test.rb +24 -23
  27. data/test/multiverse/suites/agent_only/no_dns_resolv.rb +17 -0
  28. data/test/multiverse/suites/{rum_auto_instrumentation/sanity_test.rb → agent_only/rum_instrumentation_test.rb} +25 -46
  29. data/test/multiverse/suites/{no_load → agent_only}/start_up_test.rb +0 -0
  30. data/test/multiverse/suites/agent_only/testing_app.rb +17 -0
  31. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +6 -5
  32. data/test/multiverse/suites/datamapper/config/newrelic.yml +1 -1
  33. data/test/multiverse/suites/{rails_3_queue_time → rails}/Envfile +3 -0
  34. data/test/multiverse/suites/{rails_3_views → rails}/app/views/foos/_foo.html.haml +0 -0
  35. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/_a_partial.html.erb +0 -0
  36. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/_mid_partial.html.erb +0 -0
  37. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/_top_partial.html.erb +0 -0
  38. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/deep_partial.html.erb +0 -0
  39. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/haml_view.html.haml +0 -0
  40. data/test/multiverse/suites/{rails_3_views/app/views/test → rails/app/views/views}/index.html.erb +0 -0
  41. data/test/multiverse/suites/rails/app.rb +49 -0
  42. data/test/multiverse/suites/{rails_3_error_tracing → rails}/config/newrelic.yml +0 -0
  43. data/test/multiverse/suites/{rails_3_error_tracing → rails}/error_tracing_test.rb +13 -68
  44. data/test/multiverse/suites/{rails_3_gc/instrumentation_test.rb → rails/gc_instrumentation_test.rb} +14 -35
  45. data/test/multiverse/suites/{rails_3_queue_time → rails}/queue_time_test.rb +3 -23
  46. data/test/multiverse/suites/{rails_3_views → rails}/view_instrumentation_test.rb +21 -61
  47. data/test/multiverse/suites/resque/config/newrelic.yml +1 -1
  48. data/test/multiverse/suites/sinatra/config/newrelic.yml +1 -2
  49. data/test/multiverse/test/suite_examples/one/a/config/newrelic.yml +1 -1
  50. data/test/multiverse/test/suite_examples/one/b/config/newrelic.yml +1 -1
  51. data/test/new_relic/agent/agent/connect_test.rb +17 -74
  52. data/test/new_relic/agent/agent/start_worker_thread_test.rb +3 -3
  53. data/test/new_relic/agent/agent_test.rb +59 -2
  54. data/test/new_relic/agent/configuration/manager_test.rb +28 -0
  55. data/test/new_relic/agent/configuration/yaml_source_test.rb +12 -2
  56. data/test/new_relic/agent/cross_process_monitoring_test.rb +144 -31
  57. data/test/new_relic/agent/event_listener_test.rb +46 -0
  58. data/test/new_relic/agent/instrumentation/browser_monitoring_timings_test.rb +57 -30
  59. data/test/new_relic/agent/worker_loop_test.rb +1 -1
  60. data/test/new_relic/fake_collector.rb +17 -4
  61. data/test/new_relic/rack/agent_hooks_test.rb +30 -0
  62. data/test/new_relic/rack/error_collector_test.rb +16 -0
  63. data/test/new_relic/version_number_test.rb +6 -30
  64. data/test/script/ci.sh +6 -5
  65. data/test/test_contexts.rb +1 -0
  66. data/test/test_helper.rb +2 -4
  67. metadata +34 -42
  68. data/newrelic_rpm.gemspec.erb +0 -53
  69. data/test/fixtures/gemspec_no_build.rb +0 -442
  70. data/test/fixtures/gemspec_with_build.rb +0 -442
  71. data/test/fixtures/gemspec_with_build_and_stage.rb +0 -442
  72. data/test/multiverse/suites/logging/Envfile +0 -4
  73. data/test/multiverse/suites/logging/config/newrelic.yml +0 -22
  74. data/test/multiverse/suites/monitor_mode_false/Envfile +0 -2
  75. data/test/multiverse/suites/monitor_mode_false/config/newrelic.yml +0 -25
  76. data/test/multiverse/suites/monitor_mode_false/no_dns_resolv.rb +0 -29
  77. data/test/multiverse/suites/no_load/Envfile +0 -2
  78. data/test/multiverse/suites/no_load/config/newrelic.yml +0 -22
  79. data/test/multiverse/suites/rails_3_error_tracing/Envfile +0 -15
  80. data/test/multiverse/suites/rails_3_gc/Envfile +0 -8
  81. data/test/multiverse/suites/rails_3_gc/config/newrelic.yml +0 -167
  82. data/test/multiverse/suites/rails_3_queue_time/config/newrelic.yml +0 -165
  83. data/test/multiverse/suites/rails_3_views/.gitignore +0 -3
  84. data/test/multiverse/suites/rails_3_views/Envfile +0 -16
  85. data/test/multiverse/suites/rails_3_views/config/newrelic.yml +0 -164
  86. data/test/multiverse/suites/rum_auto_instrumentation/Envfile +0 -4
  87. data/test/multiverse/suites/rum_auto_instrumentation/config/newrelic.yml +0 -24
  88. data/test/multiverse/suites/rum_auto_instrumentation/responses/worst_case_small.html +0 -5000
@@ -11,7 +11,7 @@ development:
11
11
  app_name: test
12
12
  host: 127.0.0.1
13
13
  api_host: 127.0.0.1
14
- port: 30303
14
+ port: <%= 30_000 + ($$ % 10_000) %>
15
15
  transaction_tracer:
16
16
  record_sql: obfuscated
17
17
  enabled: true
@@ -12,7 +12,7 @@ development:
12
12
  app_name: test
13
13
  host: 127.0.0.1
14
14
  api_host: 127.0.0.1
15
- port: 30303
15
+ port: <%= 30_000 + ($$ % 10_000) %>
16
16
  transaction_tracer:
17
17
  record_sql: obfuscated
18
18
  enabled: true
@@ -20,5 +20,4 @@ development:
20
20
  transaction_threshold: 1.0
21
21
  capture_params: false
22
22
  log_level: debug
23
- #log_file_path: STDOUT
24
23
  disable_serialization: false
@@ -13,7 +13,7 @@ development:
13
13
  app_name: test
14
14
  host: 127.0.0.1
15
15
  api_host: 127.0.0.1
16
- port: 30303
16
+ port: <%= 30_000 + ($$ % 10_000) %>
17
17
  transaction_tracer:
18
18
  record_sql: obfuscated
19
19
  enabled: true
@@ -13,7 +13,7 @@ development:
13
13
  app_name: test
14
14
  host: 127.0.0.1
15
15
  api_host: 127.0.0.1
16
- port: 30303
16
+ port: <%= 30_000 + ($$ % 10_000) %>
17
17
  transaction_tracer:
18
18
  record_sql: obfuscated
19
19
  enabled: true
@@ -8,7 +8,7 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
8
8
  def setup
9
9
  @connected = nil
10
10
  @keep_retrying = nil
11
- @connect_attempts = 1
11
+ @connect_attempts = 0
12
12
  @connect_retry_period = 0
13
13
  @transaction_sampler = NewRelic::Agent::TransactionSampler.new
14
14
  @sql_sampler = NewRelic::Agent::SqlSampler.new
@@ -33,76 +33,35 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
33
33
  fake_control
34
34
  end
35
35
 
36
- def test_tried_to_connect?
37
- # base case, should default to false
38
- assert !tried_to_connect?({})
36
+ def test_should_connect_if_pending
37
+ @connect_state = :pending
38
+ assert(should_connect?, "should attempt to connect if pending")
39
39
  end
40
40
 
41
- def test_tried_to_connect_connected
42
- # is true if connected is true.
43
- @connected = true
44
- assert tried_to_connect?({})
41
+ def test_should_not_connect_if_disconnected
42
+ @connect_state = :disconnected
43
+ assert(!should_connect?, "should not attempt to connect if force disconnected")
45
44
  end
46
45
 
47
- def test_tried_to_connect_forced
48
- # is false if force_reconnect is true
49
- assert !tried_to_connect?({:force_reconnect => true})
50
- end
51
-
52
- def test_should_keep_retrying_base
53
- # default to true
54
- should_keep_retrying?({})
55
- assert @keep_retrying, "should keep retrying by default"
56
- end
57
-
58
- def test_should_keep_retrying_option_true
59
- # should be true if keep_retrying is true
60
- should_keep_retrying?({:keep_retrying => true})
61
- end
62
-
63
- def test_get_retry_period
64
- (1..6).each do |x|
65
- @connect_attempts = x
66
- assert_equal get_retry_period, x * 60, "should be #{x} minutes"
67
- end
68
- @connect_attempts = 100
69
- assert_equal get_retry_period, 600, "should max out at 10 minutes after 6 tries"
46
+ def test_should_connect_if_forced
47
+ @connect_state = :disconnected
48
+ assert(should_connect?(true), "should connect if forced")
49
+ @connect_state = :connected
50
+ assert(should_connect?(true), "should connect if forced")
70
51
  end
71
52
 
72
53
  def test_increment_retry_period
73
- @connect_retry_period = 0
74
- @connect_attempts = 1
75
- assert_equal 0, connect_retry_period
76
- increment_retry_period!
77
- assert_equal 60, connect_retry_period
78
- end
79
-
80
- def test_should_retry_true
81
- @keep_retrying = true
82
- @connect_attempts = 1
83
- self.expects(:increment_retry_period!).once
84
- assert should_retry?, "should retry in this circumstance"
85
- assert_equal 2, @connect_attempts, "should be on the second attempt"
86
- end
87
-
88
- def test_should_retry_false
89
- @keep_retrying = false
90
- self.expects(:disconnect).once
91
- assert !should_retry?
54
+ 10.times do |i|
55
+ assert_equal((i * 60), connect_retry_period)
56
+ note_connect_failure
57
+ end
58
+ assert_equal(600, connect_retry_period)
92
59
  end
93
60
 
94
61
  def test_disconnect
95
62
  assert disconnect
96
63
  end
97
64
 
98
- def test_attr_accessor_connect_retry_period
99
- assert_accessor(:connect_retry_period)
100
- end
101
-
102
- def test_attr_accessor_connect_attempts
103
- assert_accessor(:connect_attempts)
104
- end
105
-
106
65
  def test_log_error
107
66
  error = StandardError.new("message")
108
67
 
@@ -242,8 +201,6 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
242
201
  'collect_traces' => true,
243
202
  'collect_errors' => true,
244
203
  'sample_rate' => 10,
245
- 'cross_process_id' => '1#234',
246
- 'encoding_key' => 'a' * 30,
247
204
  'agent_config' => { 'transaction_tracer.record_sql' => 'raw' }
248
205
  }
249
206
  self.expects(:log_connection!).with(config)
@@ -253,16 +210,10 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
253
210
  with_config(:'transaction_tracer.enabled' => true) do
254
211
  finish_setup(config)
255
212
  assert_equal 'fishsticks', @service.agent_id
256
- assert_equal '1#234', @cross_process_id
257
- assert_equal 'a' * 30, @cross_process_encoding_key
258
- assert_equal [97] * 30, @cross_process_encoding_bytes
259
213
  assert_equal 'raw', NewRelic::Agent.config[:'transaction_tracer.record_sql']
260
214
  end
261
215
  end
262
216
 
263
- def test_get_bytes_with_nil
264
- assert_equal [], get_bytes(nil)
265
- end
266
217
 
267
218
  def test_logging_collector_messages
268
219
  NewRelic::Agent.manual_start
@@ -316,12 +267,4 @@ class NewRelic::Agent::Agent::ConnectTest < Test::Unit::TestCase
316
267
  self.stubs(:error_collector).returns(fake_collector)
317
268
  fake_collector
318
269
  end
319
-
320
- def assert_accessor(sym)
321
- var_name = "@#{sym}"
322
- instance_variable_set(var_name, 1)
323
- assert (self.send(sym) == 1)
324
- self.send(sym.to_s + '=', 10)
325
- assert (instance_variable_get(var_name) == 10)
326
- end
327
270
  end
@@ -6,7 +6,7 @@ class NewRelic::Agent::Agent::StartWorkerThreadTest < Test::Unit::TestCase
6
6
  def test_deferred_work_connects
7
7
  self.expects(:catch_errors).yields
8
8
  self.expects(:connect).with('connection_options')
9
- @connected = true
9
+ self.stubs(:connected?).returns(true)
10
10
  self.expects(:log_worker_loop_start)
11
11
  self.expects(:create_and_run_worker_loop)
12
12
  deferred_work!('connection_options')
@@ -15,7 +15,7 @@ class NewRelic::Agent::Agent::StartWorkerThreadTest < Test::Unit::TestCase
15
15
  def test_deferred_work_connect_failed
16
16
  self.expects(:catch_errors).yields
17
17
  self.expects(:connect).with('connection_options')
18
- @connected = false
18
+ self.stubs(:connected?).returns(false)
19
19
  deferred_work!('connection_options')
20
20
  end
21
21
 
@@ -43,7 +43,7 @@ class NewRelic::Agent::Agent::StartWorkerThreadTest < Test::Unit::TestCase
43
43
  handle_force_restart(error)
44
44
 
45
45
  assert_equal({}, @metric_ids)
46
- assert @connected.nil?
46
+ assert_equal(:pending, @connect_state)
47
47
  end
48
48
 
49
49
  def test_handle_force_disconnect
@@ -11,12 +11,26 @@ module NewRelic
11
11
  end
12
12
 
13
13
  def test_after_fork_reporting_to_channel
14
+ @agent.stubs(:connected?).returns(true)
14
15
  @agent.after_fork(:report_to_channel => 123)
15
16
  assert(@agent.service.kind_of?(NewRelic::Agent::PipeService),
16
17
  'Agent should use PipeService when directed to report to pipe channel')
18
+ NewRelic::Agent::PipeService.any_instance.expects(:shutdown).never
17
19
  assert_equal 123, @agent.service.channel_id
18
20
  end
19
21
 
22
+ def test_after_fork_should_close_pipe_if_parent_not_connected
23
+ pipe = mock
24
+ pipe.expects(:write).with('EOF')
25
+ pipe.expects(:close)
26
+ dummy_channels = { 123 => pipe }
27
+ NewRelic::Agent::PipeChannelManager.stubs(:channels).returns(dummy_channels)
28
+
29
+ @agent.stubs(:connected?).returns(false)
30
+ @agent.after_fork(:report_to_channel => 123)
31
+ assert(@agent.disconnected?)
32
+ end
33
+
20
34
  def test_transmit_data_should_transmit
21
35
  @agent.instance_eval { transmit_data }
22
36
  assert @agent.service.agent_data.any?
@@ -57,8 +71,7 @@ module NewRelic
57
71
 
58
72
  def test_graceful_shutdown_ends_thread_profiling
59
73
  @agent.thread_profiler.expects(:stop).once
60
- @agent.instance_variable_set(:@connected, true)
61
-
74
+ @agent.stubs(:connected?).returns(true)
62
75
  @agent.send(:graceful_disconnect)
63
76
  end
64
77
 
@@ -221,6 +234,50 @@ module NewRelic
221
234
  assert_equal 10, @agent.metric_ids[MetricSpec.new('WebFrontend/QueueTime')]
222
235
  assert_equal 1017, @agent.metric_ids[MetricSpec.new('ActiveRecord/Blog/find')]
223
236
  end
237
+
238
+ def test_connect_retries_on_timeout
239
+ service = @agent.service
240
+ def service.connect(opts={})
241
+ unless @tried
242
+ @tried = true
243
+ raise Timeout::Error
244
+ end
245
+ nil
246
+ end
247
+ @agent.stubs(:connect_retry_period).returns(0)
248
+ @agent.send(:connect)
249
+ assert(@agent.connected?)
250
+ end
251
+
252
+ def test_connect_does_not_retry_if_keep_retrying_false
253
+ @agent.service.expects(:connect).once.raises(Timeout::Error)
254
+ @agent.send(:connect, :keep_retrying => false)
255
+ assert(@agent.disconnected?)
256
+ end
257
+
258
+ def test_connect_does_not_retry_on_license_error
259
+ @agent.service.stubs(:connect).raises(NewRelic::Agent::LicenseException)
260
+ @agent.send(:connect)
261
+ assert(@agent.disconnected?)
262
+ end
263
+
264
+ def test_connect_does_not_reconnect_by_default
265
+ @agent.stubs(:connected?).returns(true)
266
+ @agent.service.expects(:connect).never
267
+ @agent.send(:connect)
268
+ end
269
+
270
+ def test_connect_does_not_reconnect_if_disconnected
271
+ @agent.stubs(:disconnected?).returns(true)
272
+ @agent.service.expects(:connect).never
273
+ @agent.send(:connect)
274
+ end
275
+
276
+ def test_connect_does_reconnect_if_forced
277
+ @agent.stubs(:connected?).returns(true)
278
+ @agent.service.expects(:connect)
279
+ @agent.send(:connect, :force_reconnect => true)
280
+ end
224
281
  end
225
282
  end
226
283
  end
@@ -182,6 +182,34 @@ module NewRelic::Agent::Configuration
182
182
  assert_equal 'right', state
183
183
  end
184
184
 
185
+ def test_finished_configuring
186
+ @manager.apply_config(:layer => "yo")
187
+ assert_equal false, @manager.finished_configuring?
188
+
189
+ @manager.apply_config(ServerSource.new({}))
190
+ assert_equal true, @manager.finished_configuring?
191
+ end
192
+
193
+ def test_notifies_finished_configuring
194
+ called = false
195
+ NewRelic::Agent.instance.events.subscribe(:finished_configuring) { called = true }
196
+ @manager.apply_config(ServerSource.new({}))
197
+
198
+ assert_equal true, called
199
+ end
200
+
201
+ def test_doesnt_notify_unless_finished
202
+ called = false
203
+ NewRelic::Agent.instance.events.subscribe(:finished_configuring) { called = true }
204
+
205
+ @manager.apply_config(:fake => "config")
206
+ @manager.apply_config(ManualSource.new(:manual => true))
207
+ @manager.apply_config(YamlSource.new("", "test"))
208
+
209
+ assert_equal false, called
210
+ end
211
+
212
+
185
213
  def test_should_log_when_applying
186
214
  expects_logging(:debug, anything, includes("asdf"))
187
215
  @manager.apply_config(:test => "asdf")
@@ -4,10 +4,10 @@ require 'new_relic/agent/configuration/yaml_source'
4
4
  module NewRelic::Agent::Configuration
5
5
  class YamlSourceTest < Test::Unit::TestCase
6
6
  def setup
7
- test_yml_path = File.expand_path(File.join(File.dirname(__FILE__),
7
+ @test_yml_path = File.expand_path(File.join(File.dirname(__FILE__),
8
8
  '..','..','..',
9
9
  'config','newrelic.yml'))
10
- @source = YamlSource.new(test_yml_path, 'test')
10
+ @source = YamlSource.new(@test_yml_path, 'test')
11
11
  end
12
12
 
13
13
  def test_should_load_given_yaml_file
@@ -48,11 +48,21 @@ module NewRelic::Agent::Configuration
48
48
  assert_equal 1.1, @source[:apdex_t]
49
49
  end
50
50
 
51
+ def test_should_not_log_error_by_default
52
+ expects_no_logging(:error)
53
+ YamlSource.new(@test_yml_path, 'test')
54
+ end
55
+
51
56
  def test_should_log_if_no_file_is_found
52
57
  expects_logging(:error, any_parameters)
53
58
  source = YamlSource.new('no_such_file.yml', 'test')
54
59
  end
55
60
 
61
+ def test_should_log_if_environment_is_not_present
62
+ expects_logging(:error, any_parameters)
63
+ source = YamlSource.new(@test_yml_path, 'nonsense')
64
+ end
65
+
56
66
  def test_should_not_fail_to_log_missing_file_during_startup
57
67
  without_logger do
58
68
  ::NewRelic::Agent::StartupLogger.any_instance.expects(:error)
@@ -1,69 +1,181 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper'))
2
2
 
3
3
  module NewRelic::Agent
4
- class CrossProcessMonitoringTest < Test::Unit::TestCase
4
+ class CrossProcessMonitorTest < Test::Unit::TestCase
5
5
  AGENT_CROSS_PROCESS_ID = "qwerty"
6
- REQUEST_CROSS_PROCESS_ID = "asdf"
6
+ REQUEST_CROSS_PROCESS_ID = "42#1234"
7
7
 
8
- def setup
9
- NewRelic::Agent.instance.stubs(:cross_process_id).returns(AGENT_CROSS_PROCESS_ID)
10
- NewRelic::Agent.instance.stubs(:cross_process_encoding_bytes).returns([0])
8
+ ENCODING_KEY_NOOP = "\0"
9
+ TRUSTED_ACCOUNT_IDS = [42,13]
11
10
 
12
- @request_with_id = stub(:env => {'X-NewRelic-ID' => REQUEST_CROSS_PROCESS_ID})
13
- @empty_request = stub(:env => {})
11
+ CROSS_PROCESS_ID_POSITION = 0
12
+ TRANSACTION_NAME_POSITION = 1
13
+ QUEUE_TIME_POSITION = 2
14
+ APP_TIME_POSITION = 3
15
+ CONTENT_LENGTH_POSITION = 4
14
16
 
17
+ def setup
15
18
  @response = {}
19
+
20
+ @monitor = NewRelic::Agent::CrossProcessMonitor.new()
21
+ @monitor.finish_setup(
22
+ :cross_process_id => AGENT_CROSS_PROCESS_ID,
23
+ :encoding_key => ENCODING_KEY_NOOP,
24
+ :trusted_account_ids => TRUSTED_ACCOUNT_IDS)
25
+ end
26
+
27
+ def when_request_runs(request=for_id(REQUEST_CROSS_PROCESS_ID))
28
+ @monitor.save_client_cross_process_id(request)
29
+ @monitor.set_transaction_custom_parameters
30
+ @monitor.insert_response_header(request, @response)
31
+ end
32
+
33
+ def when_request_has_error(request=for_id(REQUEST_CROSS_PROCESS_ID))
34
+ options = {}
35
+ @monitor.save_client_cross_process_id(request)
36
+ @monitor.set_error_custom_parameters(options)
37
+ @monitor.insert_response_header(request, @response)
38
+
39
+ options
16
40
  end
17
41
 
18
42
  def test_adds_response_header
19
- timings = stub(
20
- :transaction_name => "transaction",
21
- :queue_time_in_millis => 1000,
22
- :app_time_in_millis => 2000)
43
+ with_default_timings
44
+
45
+ when_request_runs
46
+
47
+ assert_equal ["qwerty", "transaction", 1000, 2000, -1], unpacked_response
48
+ end
49
+
50
+ def test_strips_bad_characters_in_transaction_name
51
+ NewRelic::Agent::BrowserMonitoring.stubs(:timings).returns(stub(
52
+ :transaction_name => "\"'goo",
53
+ :queue_time_in_seconds => 1000,
54
+ :app_time_in_seconds => 2000))
55
+
56
+ when_request_runs
23
57
 
24
- NewRelic::Agent::BrowserMonitoring.stubs(:timings).returns(timings)
58
+ assert_equal "goo", unpacked_response[TRANSACTION_NAME_POSITION]
59
+ end
25
60
 
26
- CrossProcessMonitoring.insert_response_header(@request_with_id, @response)
61
+ def test_doesnt_write_response_header_if_id_blank
62
+ with_default_timings
27
63
 
28
- assert unpacked_response.include?("transaction")
29
- assert unpacked_response.include?("1000")
30
- assert unpacked_response.include?("2000")
31
- assert unpacked_response.include?(AGENT_CROSS_PROCESS_ID)
64
+ when_request_runs(for_id(''))
65
+ assert_nil response_app_data
66
+ end
67
+
68
+ def test_doesnt_write_response_header_if_untrusted_id
69
+ with_default_timings
70
+
71
+ when_request_runs(for_id("4#1234"))
72
+ assert_nil response_app_data
73
+ end
74
+
75
+ def test_doesnt_write_response_header_if_improperly_formatted_id
76
+ with_default_timings
77
+
78
+ when_request_runs(for_id("42"))
79
+ assert_nil response_app_data
32
80
  end
33
81
 
34
82
  def test_doesnt_add_header_if_no_id_in_request
35
- CrossProcessMonitoring.insert_response_header(@empty_request, @response)
83
+ when_request_runs({})
36
84
  assert_nil response_app_data
37
85
  end
38
86
 
39
87
  def test_doesnt_add_header_if_no_id_on_agent
40
- NewRelic::Agent.instance.stubs(:cross_process_id).returns(nil)
88
+ @monitor.finish_setup(
89
+ :cross_process_id => nil,
90
+ :encoding_key => ENCODING_KEY_NOOP,
91
+ :trusted_account_ids => TRUSTED_ACCOUNT_IDS)
41
92
 
42
- CrossProcessMonitoring.insert_response_header(@request_with_id, @response)
93
+ when_request_runs
43
94
  assert_nil response_app_data
44
95
  end
45
96
 
46
97
  def test_doesnt_add_header_if_config_disabled
47
98
  with_config(:'cross_process.enabled' => false) do
48
- CrossProcessMonitoring.insert_response_header(@request_with_id, @response)
99
+ when_request_runs
49
100
  assert_nil response_app_data
50
101
  end
51
102
  end
52
103
 
53
- def test_finds_id_from_headers
54
- %w{X-NewRelic-ID HTTP_X_NEWRELIC_ID X_NEWRELIC_ID}.each do |key|
55
- request = stub(:env => { key => REQUEST_CROSS_PROCESS_ID })
104
+ def test_includes_content_length
105
+ with_default_timings
106
+
107
+ when_request_runs(for_id(REQUEST_CROSS_PROCESS_ID).merge("Content-Length" => 3000))
108
+ assert_equal 3000, unpacked_response[CONTENT_LENGTH_POSITION]
109
+ end
110
+
111
+ def test_finds_content_length_from_headers
112
+ %w{Content-Length HTTP_CONTENT_LENGTH CONTENT_LENGTH cOnTeNt-LeNgTh}.each do |key|
113
+ request = { key => 42 }
56
114
 
57
- assert_equal(
58
- REQUEST_CROSS_PROCESS_ID, \
59
- CrossProcessMonitoring.id_from_request(request),
115
+ assert_equal(42, @monitor.content_length_from_request(request), \
60
116
  "Failed to find header on key #{key}")
61
117
  end
62
118
  end
63
119
 
64
- def test_doesnt_find_id_in_headers
65
- request = stub(:env => {})
66
- assert_nil CrossProcessMonitoring.id_from_request(request)
120
+ def test_writes_custom_parameters
121
+ with_default_timings
122
+
123
+ NewRelic::Agent.expects(:add_custom_parameters).once
124
+
125
+ when_request_runs
126
+ end
127
+
128
+ def test_error_writes_custom_parameters
129
+ with_default_timings
130
+
131
+ options = when_request_has_error
132
+
133
+ assert_equal REQUEST_CROSS_PROCESS_ID, options[:client_cross_process_id]
134
+ end
135
+
136
+ def test_error_doesnt_write_custom_parameters_if_no_id
137
+ with_default_timings
138
+
139
+ options = when_request_has_error(for_id(''))
140
+
141
+ assert_equal false, options.key?(:client_cross_process_id)
142
+ end
143
+
144
+ def test_writes_metric
145
+ with_default_timings
146
+
147
+ metric = mock()
148
+ metric.expects(:record_data_point).with(2000)
149
+ NewRelic::Agent.instance.stats_engine.stubs(:get_stats_no_scope).returns(metric)
150
+
151
+ when_request_runs
152
+ end
153
+
154
+ def test_doesnt_write_metric_if_id_blank
155
+ with_default_timings
156
+ NewRelic::Agent.instance.stats_engine.expects(:get_stats_no_scope).never
157
+
158
+ when_request_runs(for_id(''))
159
+ end
160
+
161
+ def test_decoding_blank
162
+ assert_equal "", @monitor.decode_with_key("")
163
+ end
164
+
165
+ def test_get_bytes_with_nil
166
+ assert_equal [], @monitor.send(:get_bytes, nil)
167
+ end
168
+
169
+ def with_default_timings
170
+ NewRelic::Agent::BrowserMonitoring.stubs(:timings).returns(stub(
171
+ :transaction_name => "transaction",
172
+ :queue_time_in_seconds => 1000,
173
+ :app_time_in_seconds => 2000))
174
+ end
175
+
176
+ def for_id(id)
177
+ encoded_id = id == "" ? "" : Base64.encode64(id)
178
+ { 'X-NewRelic-ID' => encoded_id }
67
179
  end
68
180
 
69
181
  def response_app_data
@@ -71,7 +183,8 @@ module NewRelic::Agent
71
183
  end
72
184
 
73
185
  def unpacked_response
74
- response_app_data.unpack("m0").first
186
+ # Assumes array is valid JSON and Ruby, which is currently is
187
+ eval(Base64.decode64(response_app_data))
75
188
  end
76
189
  end
77
190
  end