newrelic_rpm 3.17.2.327 → 3.18.0.329

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +32 -10
  3. data/CHANGELOG.md +43 -3
  4. data/Rakefile +0 -21
  5. data/lib/new_relic/agent/cross_app_tracing.rb +34 -269
  6. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +10 -2
  7. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +18 -9
  8. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +12 -6
  9. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +13 -6
  10. data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +13 -6
  11. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +14 -3
  12. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +10 -15
  13. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +4 -7
  14. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +4 -19
  15. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +0 -1
  16. data/lib/new_relic/agent/instrumentation/curb.rb +9 -7
  17. data/lib/new_relic/agent/instrumentation/evented_subscriber.rb +4 -0
  18. data/lib/new_relic/agent/instrumentation/excon/connection.rb +15 -5
  19. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +17 -12
  20. data/lib/new_relic/agent/instrumentation/http.rb +12 -5
  21. data/lib/new_relic/agent/instrumentation/httpclient.rb +13 -4
  22. data/lib/new_relic/agent/instrumentation/net.rb +13 -2
  23. data/lib/new_relic/agent/instrumentation/rails5/action_controller.rb +2 -10
  24. data/lib/new_relic/agent/instrumentation/typhoeus.rb +8 -3
  25. data/lib/new_relic/agent/method_tracer_helpers.rb +3 -1
  26. data/lib/new_relic/agent/parameter_filtering.rb +1 -1
  27. data/lib/new_relic/agent/stats_engine/metric_stats.rb +0 -18
  28. data/lib/new_relic/agent/supported_versions.rb +1 -0
  29. data/lib/new_relic/agent/transaction/abstract_segment.rb +7 -9
  30. data/lib/new_relic/agent/transaction/external_request_segment.rb +139 -0
  31. data/lib/new_relic/agent/transaction/segment.rb +1 -1
  32. data/lib/new_relic/agent/transaction/tracing.rb +10 -1
  33. data/lib/new_relic/recipes/capistrano3.rb +3 -1
  34. data/lib/new_relic/version.rb +2 -2
  35. data/lib/tasks/multiverse.rb +27 -7
  36. data/test/environments/rails42/Gemfile +1 -0
  37. data/test/multiverse/lib/multiverse.rb +32 -0
  38. data/test/multiverse/lib/multiverse/runner.rb +2 -2
  39. data/test/multiverse/lib/multiverse/suite.rb +43 -22
  40. data/test/multiverse/suites/active_record/Envfile +3 -1
  41. data/test/multiverse/suites/activemerchant/Envfile +5 -1
  42. data/test/multiverse/suites/agent_only/Envfile +1 -0
  43. data/test/multiverse/suites/capistrano/deployment_test.rb +6 -9
  44. data/test/multiverse/suites/capistrano2/deployment_test.rb +6 -6
  45. data/test/multiverse/suites/curb/curb_test.rb +2 -3
  46. data/test/multiverse/suites/datamapper/Envfile +4 -0
  47. data/test/multiverse/suites/datamapper/datamapper_test.rb +106 -36
  48. data/test/multiverse/suites/delayed_job/Envfile +3 -3
  49. data/test/multiverse/suites/excon/excon_test.rb +1 -1
  50. data/test/multiverse/suites/grape/grape_test.rb +1 -1
  51. data/test/multiverse/suites/grape/grape_test_api.rb +1 -1
  52. data/test/multiverse/suites/grape/grape_versioning_test.rb +1 -1
  53. data/test/multiverse/suites/grape/grape_versioning_test_api.rb +1 -1
  54. data/test/multiverse/suites/grape/unsupported_version_test.rb +1 -1
  55. data/test/multiverse/suites/httpclient/Envfile +2 -0
  56. data/test/multiverse/suites/httpclient/httpclient_test.rb +1 -1
  57. data/test/multiverse/suites/httprb/Envfile +2 -0
  58. data/test/multiverse/suites/httprb/httprb_test.rb +1 -1
  59. data/test/multiverse/suites/json/Envfile +7 -2
  60. data/test/multiverse/suites/memcached/Envfile +2 -0
  61. data/test/multiverse/suites/mongo/Envfile +2 -0
  62. data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +95 -33
  63. data/test/multiverse/suites/mongo/mongo2_instrumentation_test.rb +62 -23
  64. data/test/multiverse/suites/net_http/Envfile +2 -0
  65. data/test/multiverse/suites/net_http/net_http_test.rb +7 -3
  66. data/test/multiverse/suites/padrino/Envfile +2 -0
  67. data/test/multiverse/suites/rack/Envfile +2 -0
  68. data/test/multiverse/suites/rack/url_map_test.rb +4 -0
  69. data/test/multiverse/suites/rails/Envfile +34 -29
  70. data/test/multiverse/suites/rake/Envfile +11 -6
  71. data/test/multiverse/suites/redis/Envfile +2 -0
  72. data/test/multiverse/suites/redis/redis_instrumentation_test.rb +31 -12
  73. data/test/multiverse/suites/sidekiq/Envfile +6 -2
  74. data/test/multiverse/suites/sinatra/Envfile +2 -0
  75. data/test/multiverse/suites/typhoeus/Envfile +31 -27
  76. data/test/multiverse/suites/typhoeus/typhoeus_test.rb +4 -3
  77. data/test/multiverse/suites/yajl/Envfile +4 -2
  78. data/test/new_relic/agent/datastores_test.rb +0 -10
  79. data/test/new_relic/agent/instrumentation/action_cable_subscriber_test.rb +2 -2
  80. data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +64 -65
  81. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +11 -9
  82. data/test/new_relic/agent/instrumentation/instance_identification_test.rb +9 -8
  83. data/test/new_relic/agent/instrumentation/mongodb_command_subscriber_test.rb +7 -11
  84. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +4 -0
  85. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +0 -9
  86. data/test/new_relic/agent/method_tracer_test.rb +24 -8
  87. data/test/new_relic/agent/parameter_filtering_test.rb +2 -2
  88. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +1 -0
  89. data/test/new_relic/agent/transaction/abstract_segment_test.rb +25 -16
  90. data/test/new_relic/agent/transaction/datastore_segment_test.rb +55 -38
  91. data/test/new_relic/agent/transaction/external_request_segment_test.rb +330 -0
  92. data/test/new_relic/agent/transaction/segment_test.rb +28 -4
  93. data/test/new_relic/agent/transaction/tracing_test.rb +60 -22
  94. data/test/new_relic/agent_test.rb +2 -1
  95. data/test/new_relic/collection_helper_test.rb +1 -0
  96. data/test/new_relic/dispatcher_test.rb +1 -0
  97. data/test/new_relic/fake_external_server.rb +1 -1
  98. data/test/new_relic/filtering_test_app.rb +1 -1
  99. data/test/new_relic/http_client_test_cases.rb +38 -20
  100. data/test/new_relic/rack/error_collector_test.rb +1 -0
  101. data/test/performance/suites/external_segment.rb +82 -0
  102. data/test/script/before_install/update_bundler.sh +12 -0
  103. data/test/script/external_server.rb +31 -0
  104. metadata +8 -5
  105. data/test/multiverse/lib/multiverse/environment.rb +0 -19
  106. data/test/new_relic/agent/cross_app_tracing_test.rb +0 -71
  107. data/test/script/before_install/jruby_bundler.sh +0 -22
@@ -30,7 +30,7 @@ class NewRelic::Agent::Instrumentation::MongodbCommandSubscriberTest < Minitest:
30
30
  end
31
31
 
32
32
  def test_records_metrics_for_simple_find
33
- simulate_query
33
+ in_transaction { simulate_query }
34
34
 
35
35
  metric_name = 'Datastore/statement/MongoDB/users/find'
36
36
  assert_metrics_recorded(
@@ -65,31 +65,29 @@ class NewRelic::Agent::Instrumentation::MongodbCommandSubscriberTest < Minitest:
65
65
 
66
66
  def test_should_not_raise_due_to_an_exception_during_instrumentation_callback
67
67
  @subscriber.stubs(:metrics).raises(StandardError)
68
- simulate_query
68
+ in_transaction { simulate_query }
69
69
  end
70
70
 
71
71
  def test_records_instance_metrics_for_tcp_connection
72
- simulate_query
72
+ in_transaction { simulate_query }
73
73
  assert_metrics_recorded('Datastore/instance/MongoDB/nerd-server/27017')
74
74
  end
75
75
 
76
76
  def test_records_instance_metrics_for_unix_domain_socket
77
77
  address = stub('address', :host => "/tmp/mongodb-27017.sock", :port => nil)
78
78
  @started_event.stubs(:address).returns(address)
79
- simulate_query
79
+ in_transaction { simulate_query }
80
80
  assert_metrics_recorded('Datastore/instance/MongoDB/nerd-server//tmp/mongodb-27017.sock')
81
81
  end
82
82
 
83
83
  def test_records_unknown_unknown_metric_when_error_gathering_instance_data
84
84
  @started_event.stubs(:address).returns(nil)
85
- simulate_query
85
+ in_transaction { simulate_query }
86
86
  assert_metrics_recorded('Datastore/instance/MongoDB/unknown/unknown')
87
87
  end
88
88
 
89
89
  def test_records_tt_segment_parameters_for_datastore_instance
90
- in_transaction do
91
- simulate_query
92
- end
90
+ in_transaction { simulate_query }
93
91
 
94
92
  tt = last_transaction_trace
95
93
 
@@ -103,12 +101,10 @@ class NewRelic::Agent::Instrumentation::MongodbCommandSubscriberTest < Minitest:
103
101
  def test_does_not_record_unknown_unknown_metric_when_data_empty
104
102
  address = stub('address', :host => "", :port => "")
105
103
  @started_event.stubs(:address).returns(address)
106
- simulate_query
104
+ in_transaction { simulate_query }
107
105
  assert_metrics_not_recorded('Datastore/instance/MongoDB/unknown/unknown')
108
106
  end
109
107
 
110
-
111
-
112
108
  def simulate_query
113
109
  @subscriber.started(@started_event)
114
110
  advance_time @succeeded_event.duration
@@ -23,6 +23,10 @@ class NewRelic::Agent::Instrumentation::NetInstrumentationTest < Minitest::Test
23
23
  NewRelic::Agent.instance.stats_engine.clear_stats
24
24
  end
25
25
 
26
+ def teardown
27
+ NewRelic::Agent.shutdown
28
+ end
29
+
26
30
  def test_scope_stack_integrity_maintained_on_request_failure
27
31
  @socket.stubs(:write).raises('fake network error')
28
32
  with_config(:"cross_application_tracer.enabled" => true) do
@@ -11,15 +11,6 @@ class NewRelic::Agent::MethodTracer::TraceExecutionScopedTest < Minitest::Test
11
11
  NewRelic::Agent.agent.stats_engine.clear_stats
12
12
  end
13
13
 
14
- def test_metric_recording_outside_transaction
15
- trace_execution_scoped(['foo']) do
16
- # meh
17
- end
18
- assert_metrics_recorded_exclusive(
19
- 'foo' => { :call_count => 1 }
20
- )
21
- end
22
-
23
14
  def test_metric_recording_in_non_nested_transaction
24
15
  in_transaction('outer') do
25
16
  trace_execution_scoped(['foo', 'bar']) do
@@ -95,6 +95,7 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
95
95
  end
96
96
 
97
97
  @metric_name = nil
98
+ NewRelic::Agent.shutdown
98
99
  super
99
100
  end
100
101
 
@@ -112,8 +113,11 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
112
113
 
113
114
  def test_trace_execution_scoped_records_metric_data
114
115
  metric = "hello"
115
- self.class.trace_execution_scoped(metric) do
116
- advance_time 0.05
116
+
117
+ in_transaction do
118
+ self.class.trace_execution_scoped(metric) do
119
+ advance_time 0.05
120
+ end
117
121
  end
118
122
 
119
123
  stats = @stats_engine.get_stats(metric)
@@ -177,14 +181,18 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
177
181
  def test_add_method_tracer__default
178
182
  self.class.add_method_tracer :simple_method
179
183
 
180
- simple_method
184
+ in_transaction do
185
+ simple_method
186
+ end
181
187
 
182
188
  stats = @stats_engine.get_stats("Custom/#{self.class.name}/simple_method")
183
189
  assert stats.call_count == 1
184
190
  end
185
191
 
186
192
  def test_add_class_method_tracer
187
- MyClass.class_method
193
+ in_transaction do
194
+ MyClass.class_method
195
+ end
188
196
  stats = @stats_engine.get_stats("Custom/MyClass/Class/class_method")
189
197
  assert stats.call_count == 1
190
198
  end
@@ -196,7 +204,10 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
196
204
  add_method_tracer :instance_method
197
205
  end
198
206
 
199
- cls.new.instance_method
207
+ in_transaction do
208
+ cls.new.instance_method
209
+ end
210
+
200
211
  stats = @stats_engine.get_stats("Custom/AnonymousClass/instance_method")
201
212
  assert stats.call_count == 1
202
213
  end
@@ -206,7 +217,9 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
206
217
  self.class.add_method_tracer :simple_method
207
218
  self.class.add_method_tracer :simple_method
208
219
 
209
- simple_method
220
+ in_transaction do
221
+ simple_method
222
+ end
210
223
 
211
224
  stats = @stats_engine.get_stats("Custom/#{self.class.name}/simple_method")
212
225
  assert stats.call_count == 1
@@ -247,8 +260,11 @@ class NewRelic::Agent::MethodTracerTest < Minitest::Test
247
260
  NewRelic::Agent.instance.stubs(:transaction_sampler).returns(@old_sampler)
248
261
 
249
262
  mock = Insider.new(@stats_engine)
250
- mock.catcher(0)
251
- mock.catcher(5)
263
+
264
+ in_transaction do
265
+ mock.catcher(0)
266
+ mock.catcher(5)
267
+ end
252
268
 
253
269
  stats = @stats_engine.get_stats("catcher")
254
270
  assert_equal 2, stats.call_count
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # This file is distributed under New Relic"s license terms.
2
+ # This file is distributed under New Relic's license terms.
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'))
@@ -36,4 +36,4 @@ module NewRelic
36
36
  end
37
37
  end
38
38
  end
39
- end
39
+ end
@@ -15,6 +15,7 @@ class NewRelic::Agent::MetricStatsTest < Minitest::Test
15
15
 
16
16
  def teardown
17
17
  @engine.reset!
18
+ NewRelic::Agent.shutdown
18
19
  super
19
20
  end
20
21
 
@@ -45,18 +45,21 @@ module NewRelic
45
45
  end
46
46
 
47
47
  def test_segment_records_metrics
48
- segment = BasicSegment.new "Custom/basic/segment"
49
- segment.start
50
- advance_time 1.0
51
- segment.finish
48
+ in_transaction do |txn|
49
+ segment = BasicSegment.new "Custom/basic/segment"
50
+ txn.add_segment segment
51
+ segment.start
52
+ advance_time 1.0
53
+ segment.finish
54
+ end
52
55
 
53
56
  assert_metrics_recorded ["Custom/basic/segment", "Basic/all"]
54
57
  end
55
58
 
56
59
  def test_segment_records_metrics_in_local_cache_if_part_of_transaction
57
60
  segment = BasicSegment.new "Custom/basic/segment"
58
- txn = in_transaction "test_transaction" do
59
- segment.transaction = txn
61
+ in_transaction "test_transaction" do |txn|
62
+ txn.add_segment segment
60
63
  segment.start
61
64
  advance_time 1.0
62
65
  segment.finish
@@ -72,21 +75,27 @@ module NewRelic
72
75
  # segments we would like to create a TT node for the segment, but not record
73
76
  # metrics
74
77
  def test_segments_will_not_record_metrics_when_turned_off
75
- segment = BasicSegment.new "Custom/basic/segment"
76
- segment.record_metrics = false
77
- segment.start
78
- advance_time 1.0
79
- segment.finish
78
+ in_transaction do |txn|
79
+ segment = BasicSegment.new "Custom/basic/segment"
80
+ txn.add_segment segment
81
+ segment.record_metrics = false
82
+ segment.start
83
+ advance_time 1.0
84
+ segment.finish
85
+ end
80
86
 
81
87
  refute_metrics_recorded ["Custom/basic/segment", "Basic/all"]
82
88
  end
83
89
 
84
90
  def test_segment_complete_callback_executes_when_segment_finished
85
- segment = BasicSegment.new "Custom/basic/segment"
86
- segment.expects(:segment_complete)
87
- segment.start
88
- advance_time 1.0
89
- segment.finish
91
+ in_transaction do |txn|
92
+ segment = BasicSegment.new "Custom/basic/segment"
93
+ txn.add_segment segment
94
+ segment.expects(:segment_complete)
95
+ segment.start
96
+ advance_time 1.0
97
+ segment.finish
98
+ end
90
99
  end
91
100
  end
92
101
  end
@@ -28,14 +28,31 @@ module NewRelic
28
28
  assert_equal "Datastore/operation/SQLite/select", segment.name
29
29
  end
30
30
 
31
- def test_segment_records_expected_metrics
32
- Transaction.stubs(:recording_web_transaction?).returns(true)
33
31
 
32
+ def test_segment_does_not_record_metrics_outside_of_txn
34
33
  segment = DatastoreSegment.new "SQLite", "insert", "Blog"
35
34
  segment.start
36
35
  advance_time 1
37
36
  segment.finish
38
37
 
38
+ refute_metrics_recorded [
39
+ "Datastore/statement/SQLite/Blog/insert",
40
+ "Datastore/operation/SQLite/insert",
41
+ "Datastore/SQLite/allWeb",
42
+ "Datastore/SQLite/all",
43
+ "Datastore/allWeb",
44
+ "Datastore/all"
45
+ ]
46
+ end
47
+
48
+ def test_segment_records_expected_metrics
49
+ in_web_transaction "text_txn" do
50
+ segment = NewRelic::Agent::Transaction.start_datastore_segment "SQLite", "insert", "Blog"
51
+ segment.start
52
+ advance_time 1
53
+ segment.finish
54
+ end
55
+
39
56
  assert_metrics_recorded [
40
57
  "Datastore/statement/SQLite/Blog/insert",
41
58
  "Datastore/operation/SQLite/insert",
@@ -47,12 +64,12 @@ module NewRelic
47
64
  end
48
65
 
49
66
  def test_segment_records_expected_metrics_without_collection
50
- Transaction.stubs(:recording_web_transaction?).returns(true)
51
-
52
- segment = DatastoreSegment.new "SQLite", "select"
53
- segment.start
54
- advance_time 1
55
- segment.finish
67
+ in_web_transaction "text_txn" do
68
+ segment = Transaction.start_datastore_segment "SQLite", "select"
69
+ segment.start
70
+ advance_time 1
71
+ segment.finish
72
+ end
56
73
 
57
74
  assert_metrics_recorded [
58
75
  "Datastore/operation/SQLite/select",
@@ -64,12 +81,12 @@ module NewRelic
64
81
  end
65
82
 
66
83
  def test_segment_records_expected_metrics_with_instance_identifier
67
- Transaction.stubs(:recording_web_transaction?).returns(true)
68
-
69
- segment = DatastoreSegment.new "SQLite", "select", nil, "jonan-01", "1337807"
70
- segment.start
71
- advance_time 1
72
- segment.finish
84
+ in_web_transaction "text_txn" do
85
+ segment = Transaction.start_datastore_segment "SQLite", "select", nil, "jonan-01", "1337807"
86
+ segment.start
87
+ advance_time 1
88
+ segment.finish
89
+ end
73
90
 
74
91
  assert_metrics_recorded [
75
92
  "Datastore/instance/SQLite/jonan-01/1337807",
@@ -82,12 +99,12 @@ module NewRelic
82
99
  end
83
100
 
84
101
  def test_segment_records_expected_metrics_with_instance_identifier_host_only
85
- Transaction.stubs(:recording_web_transaction?).returns(true)
86
-
87
- segment = DatastoreSegment.new "SQLite", "select", nil, "jonan-01"
88
- segment.start
89
- advance_time 1
90
- segment.finish
102
+ in_web_transaction "text_txn" do
103
+ segment = Transaction.start_datastore_segment "SQLite", "select", nil, "jonan-01"
104
+ segment.start
105
+ advance_time 1
106
+ segment.finish
107
+ end
91
108
 
92
109
  assert_metrics_recorded [
93
110
  "Datastore/instance/SQLite/jonan-01/unknown",
@@ -100,12 +117,12 @@ module NewRelic
100
117
  end
101
118
 
102
119
  def test_segment_records_expected_metrics_with_instance_identifier_port_only
103
- Transaction.stubs(:recording_web_transaction?).returns(true)
104
-
105
- segment = DatastoreSegment.new "SQLite", "select", nil, nil, 1337807
106
- segment.start
107
- advance_time 1
108
- segment.finish
120
+ in_web_transaction "text_txn" do
121
+ segment = Transaction.start_datastore_segment "SQLite", "select", nil, nil, 1337807
122
+ segment.start
123
+ advance_time 1
124
+ segment.finish
125
+ end
109
126
 
110
127
  assert_metrics_recorded [
111
128
  "Datastore/instance/SQLite/unknown/1337807",
@@ -118,24 +135,24 @@ module NewRelic
118
135
  end
119
136
 
120
137
  def test_segment_does_not_record_expected_metrics_with_empty_data
121
- Transaction.stubs(:recording_web_transaction?).returns(true)
122
-
123
- segment = DatastoreSegment.new "SQLite", "select", nil
124
- segment.start
125
- advance_time 1
126
- segment.finish
138
+ in_web_transaction "text_txn" do
139
+ segment = Transaction.start_datastore_segment "SQLite", "select", nil
140
+ segment.start
141
+ advance_time 1
142
+ segment.finish
143
+ end
127
144
 
128
145
  assert_metrics_not_recorded "Datastore/instance/SQLite/unknown/unknown"
129
146
  end
130
147
 
131
148
  def test_segment_does_not_record_instance_id_metrics_when_disabled
132
149
  with_config(:'datastore_tracer.instance_reporting.enabled' => false) do
133
- Transaction.stubs(:recording_web_transaction?).returns(true)
134
-
135
- segment = DatastoreSegment.new "SQLite", "select", nil, "jonan-01", "1337807"
136
- segment.start
137
- advance_time 1
138
- segment.finish
150
+ in_web_transaction "text_txn" do
151
+ segment = Transaction.start_datastore_segment "SQLite", "select", nil, "jonan-01", "1337807"
152
+ segment.start
153
+ advance_time 1
154
+ segment.finish
155
+ end
139
156
 
140
157
  assert_metrics_not_recorded "Datastore/instance/SQLite/jonan-01/1337807"
141
158
  end
@@ -0,0 +1,330 @@
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
+
7
+ require 'new_relic/agent/transaction'
8
+ require 'new_relic/agent/transaction/external_request_segment'
9
+
10
+ module NewRelic
11
+ module Agent
12
+ class Transaction
13
+ class ExternalRequestSegmentTest < Minitest::Test
14
+ class RequestWrapper
15
+ attr_reader :headers
16
+
17
+ def initialize headers = {}
18
+ @headers = headers
19
+ end
20
+
21
+ def [] key
22
+ @headers[key]
23
+ end
24
+
25
+ def []= key, value
26
+ @headers[key] = value
27
+ end
28
+
29
+ def host_from_header
30
+ self['host']
31
+ end
32
+ end
33
+
34
+ TRANSACTION_GUID = 'BEC1BC64675138B9'
35
+
36
+ def setup
37
+ @obfuscator = NewRelic::Agent::Obfuscator.new "jotorotoes"
38
+ CrossAppTracing.stubs(:obfuscator).returns(@obfuscator)
39
+ CrossAppTracing.stubs(:valid_encoding_key?).returns(true)
40
+ end
41
+
42
+ def teardown
43
+ NewRelic::Agent.drop_buffered_data
44
+ end
45
+
46
+ def test_generates_expected_name
47
+ segment = ExternalRequestSegment.new "Typhoeus", "http://remotehost.com/blogs/index", "GET"
48
+ assert_equal "External/remotehost.com/Typhoeus/GET", segment.name
49
+ end
50
+
51
+ def test_segment_does_not_record_metrics_outside_of_txn
52
+ segment = ExternalRequestSegment.new "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
53
+ segment.finish
54
+
55
+ refute_metrics_recorded [
56
+ "External/remotehost.com/Net::HTTP/GET",
57
+ "External/all",
58
+ "External/remotehost.com/all",
59
+ "External/allWeb",
60
+ ["External/remotehost.com/Net::HTTP/GET", "test"]
61
+ ]
62
+ end
63
+
64
+ def test_segment_records_expected_metrics_for_non_cat_txn
65
+ in_transaction "test", :category => :controller do
66
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
67
+ segment.finish
68
+ end
69
+
70
+ expected_metrics = [
71
+ "External/remotehost.com/Net::HTTP/GET",
72
+ "External/all",
73
+ "External/remotehost.com/all",
74
+ "External/allWeb",
75
+ ["External/remotehost.com/Net::HTTP/GET", "test"]
76
+ ]
77
+
78
+ assert_metrics_recorded expected_metrics
79
+ end
80
+
81
+ def test_segment_records_noncat_metrics_when_cat_disabled
82
+ request = RequestWrapper.new
83
+ response = {
84
+ 'X-NewRelic-App-Data' => make_app_data_payload("1#1884", "txn-name", 2, 8, 0, TRANSACTION_GUID)
85
+ }
86
+
87
+ with_config(cat_config.merge({:"cross_application_tracer.enabled" => false})) do
88
+ in_transaction "test", :category => :controller do
89
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
90
+ segment.add_request_headers request
91
+ segment.read_response_headers response
92
+ segment.finish
93
+ end
94
+ end
95
+
96
+ expected_metrics = [
97
+ "External/remotehost.com/Net::HTTP/GET",
98
+ "External/all",
99
+ "External/remotehost.com/all",
100
+ "External/allWeb",
101
+ ["External/remotehost.com/Net::HTTP/GET", "test"]
102
+ ]
103
+
104
+ assert_metrics_recorded expected_metrics
105
+ end
106
+
107
+ def test_segment_records_noncat_metrics_without_valid_cross_process_id
108
+ request = RequestWrapper.new
109
+ response = {
110
+ 'X-NewRelic-App-Data' => make_app_data_payload("1#1884", "txn-name", 2, 8, 0, TRANSACTION_GUID)
111
+ }
112
+
113
+ with_config(cat_config.merge({:cross_process_id => ''})) do
114
+ in_transaction "test", :category => :controller do
115
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
116
+ segment.add_request_headers request
117
+ segment.read_response_headers response
118
+ segment.finish
119
+ end
120
+ end
121
+
122
+ expected_metrics = [
123
+ "External/remotehost.com/Net::HTTP/GET",
124
+ "External/all",
125
+ "External/remotehost.com/all",
126
+ "External/allWeb",
127
+ ["External/remotehost.com/Net::HTTP/GET", "test"]
128
+ ]
129
+
130
+ assert_metrics_recorded expected_metrics
131
+ end
132
+
133
+ def test_segment_records_noncat_metrics_without_valid_encoding_key
134
+ CrossAppTracing.unstub(:valid_encoding_key?)
135
+ request = RequestWrapper.new
136
+ response = {
137
+ 'X-NewRelic-App-Data' => make_app_data_payload("1#1884", "txn-name", 2, 8, 0, TRANSACTION_GUID)
138
+ }
139
+
140
+ with_config(cat_config.merge({:encoding_key => ''})) do
141
+ in_transaction "test", :category => :controller do
142
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
143
+ segment.add_request_headers request
144
+ segment.read_response_headers response
145
+ segment.finish
146
+ end
147
+ end
148
+
149
+ expected_metrics = [
150
+ "External/remotehost.com/Net::HTTP/GET",
151
+ "External/all",
152
+ "External/remotehost.com/all",
153
+ "External/allWeb",
154
+ ["External/remotehost.com/Net::HTTP/GET", "test"]
155
+ ]
156
+
157
+ assert_metrics_recorded expected_metrics
158
+ end
159
+
160
+ def test_segment_records_expected_metrics_for_cat_transaction
161
+ response = {
162
+ 'X-NewRelic-App-Data' => make_app_data_payload("1#1884", "txn-name", 2, 8, 0, TRANSACTION_GUID)
163
+ }
164
+
165
+ with_config cat_config do
166
+ in_transaction "test", :category => :controller do |txn|
167
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://newrelic.com/blogs/index", "GET"
168
+ segment.read_response_headers response
169
+ segment.finish
170
+ end
171
+ end
172
+
173
+ expected_metrics = [
174
+ "ExternalTransaction/newrelic.com/1#1884/txn-name",
175
+ "ExternalApp/newrelic.com/1#1884/all",
176
+ "External/all",
177
+ "External/newrelic.com/all",
178
+ "External/allWeb",
179
+ ["ExternalTransaction/newrelic.com/1#1884/txn-name", "test"]
180
+ ]
181
+
182
+ assert_metrics_recorded expected_metrics
183
+ end
184
+
185
+ def test_segment_writes_outbound_request_headers
186
+ request = RequestWrapper.new
187
+ with_config cat_config do
188
+ in_transaction :category => :controller do
189
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
190
+ segment.add_request_headers request
191
+ segment.finish
192
+ end
193
+ end
194
+ assert request.headers.key?("X-NewRelic-ID"), "Expected to find X-NewRelic-ID header"
195
+ assert request.headers.key?("X-NewRelic-Transaction"), "Expected to find X-NewRelic-Transaction header"
196
+ end
197
+
198
+ def test_segment_writes_synthetics_header_for_synthetics_txn
199
+ request = RequestWrapper.new
200
+ with_config cat_config do
201
+ in_transaction :category => :controller do |txn|
202
+ txn.raw_synthetics_header = json_dump_and_encode [1, 42, 100, 200, 300]
203
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
204
+ segment.add_request_headers request
205
+ segment.finish
206
+ end
207
+ end
208
+ assert request.headers.key?("X-NewRelic-Synthetics"), "Expected to find X-NewRelic-Synthetics header"
209
+ end
210
+
211
+ def test_add_request_headers_renames_segment_based_on_host_header
212
+ request = RequestWrapper.new({"host" => "anotherhost.local"})
213
+ with_config cat_config do
214
+ in_transaction :category => :controller do
215
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
216
+ assert_equal "External/remotehost.com/Net::HTTP/GET", segment.name
217
+ segment.add_request_headers request
218
+ assert_equal "External/anotherhost.local/Net::HTTP/GET", segment.name
219
+ segment.finish
220
+ end
221
+ end
222
+ end
223
+
224
+ def test_read_response_headers_decodes_valid_appdata
225
+ response = {
226
+ 'X-NewRelic-App-Data' => make_app_data_payload("1#1884", "txn-name", 2, 8, 0, TRANSACTION_GUID)
227
+ }
228
+
229
+ with_config cat_config do
230
+ in_transaction :category => :controller do |txn|
231
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
232
+ segment.read_response_headers response
233
+ segment.finish
234
+
235
+ assert segment.cross_app_request?
236
+ assert_equal "1#1884", segment.cross_process_id
237
+ assert_equal "txn-name", segment.cross_process_transaction_name
238
+ assert_equal "BEC1BC64675138B9", segment.transaction_guid
239
+ end
240
+ end
241
+ end
242
+
243
+ def test_read_response_headers_ignores_invalid_appdata
244
+ response = {
245
+ 'X-NewRelic-App-Data' => "this#is#not#valid#appdata"
246
+ }
247
+
248
+ with_config cat_config do
249
+ in_transaction :category => :controller do |txn|
250
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
251
+ segment.read_response_headers response
252
+ segment.finish
253
+
254
+ refute segment.cross_app_request?
255
+ assert_nil segment.cross_process_id
256
+ assert_nil segment.cross_process_transaction_name
257
+ assert_nil segment.transaction_guid
258
+ end
259
+ end
260
+ end
261
+
262
+ def test_read_response_headers_ignores_invalid_cross_app_id
263
+ response = {
264
+ 'X-NewRelic-App-Data' => make_app_data_payload("not_an_ID", "txn-name", 2, 8, 0, TRANSACTION_GUID)
265
+ }
266
+
267
+ with_config cat_config do
268
+ in_transaction :category => :controller do |txn|
269
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://remotehost.com/blogs/index", "GET"
270
+ segment.read_response_headers response
271
+ segment.finish
272
+
273
+ refute segment.cross_app_request?
274
+ assert_nil segment.cross_process_id
275
+ assert_nil segment.cross_process_transaction_name
276
+ assert_nil segment.transaction_guid
277
+ end
278
+ end
279
+ end
280
+
281
+ def test_uri_recorded_as_tt_attribute
282
+ segment = nil
283
+ uri = "http://newrelic.com/blogs/index"
284
+
285
+ in_transaction :category => :controller do
286
+ segment = Transaction.start_external_request_segment "Net::HTTP", uri, "GET"
287
+ segment.finish
288
+ end
289
+
290
+ sample = NewRelic::Agent.agent.transaction_sampler.last_sample
291
+ node = find_node_with_name(sample, segment.name)
292
+
293
+ assert_equal uri, node.params[:uri]
294
+ end
295
+
296
+ def test_guid_recorded_as_tt_attribute_for_cat_txn
297
+ segment = nil
298
+
299
+ response = {
300
+ 'X-NewRelic-App-Data' => make_app_data_payload("1#1884", "txn-name", 2, 8, 0, TRANSACTION_GUID)
301
+ }
302
+
303
+ with_config cat_config do
304
+ in_transaction :category => :controller do
305
+ segment = Transaction.start_external_request_segment "Net::HTTP", "http://newrelic.com/blogs/index", "GET"
306
+ segment.read_response_headers response
307
+ segment.finish
308
+ end
309
+ end
310
+
311
+ sample = NewRelic::Agent.agent.transaction_sampler.last_sample
312
+ node = find_node_with_name(sample, segment.name)
313
+
314
+ assert_equal TRANSACTION_GUID, node.params[:transaction_guid]
315
+ end
316
+
317
+ def cat_config
318
+ {
319
+ :cross_process_id => "269975#22824",
320
+ :trusted_account_ids => [1,269975]
321
+ }
322
+ end
323
+
324
+ def make_app_data_payload( *args )
325
+ @obfuscator.obfuscate( args.to_json ) + "\n"
326
+ end
327
+ end
328
+ end
329
+ end
330
+ end