newrelic_rpm 3.9.7.266 → 3.9.8.273

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +44 -1
  3. data/lib/new_relic/agent.rb +31 -0
  4. data/lib/new_relic/agent/agent.rb +34 -5
  5. data/lib/new_relic/agent/configuration/default_source.rb +25 -1
  6. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  7. data/lib/new_relic/agent/cross_app_monitor.rb +1 -1
  8. data/lib/new_relic/agent/custom_event_aggregator.rb +2 -4
  9. data/lib/new_relic/agent/error_collector.rb +17 -12
  10. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +9 -8
  11. data/lib/new_relic/agent/instrumentation/grape.rb +67 -0
  12. data/lib/new_relic/agent/new_relic_service.rb +93 -43
  13. data/lib/new_relic/agent/pipe_service.rb +4 -0
  14. data/lib/new_relic/agent/synthetics_event_buffer.rb +42 -0
  15. data/lib/new_relic/agent/system_info.rb +44 -18
  16. data/lib/new_relic/agent/transaction_event_aggregator.rb +9 -2
  17. data/lib/new_relic/agent/utilization_data.rb +77 -0
  18. data/lib/new_relic/agent/vm/mri_vm.rb +3 -3
  19. data/lib/new_relic/rack/agent_hooks.rb +15 -15
  20. data/lib/new_relic/recipes/capistrano3.rb +2 -2
  21. data/lib/new_relic/version.rb +1 -1
  22. data/newrelic_rpm.gemspec +0 -1
  23. data/test/agent_helper.rb +13 -3
  24. data/test/environments/lib/environments/runner.rb +3 -19
  25. data/test/environments/rails42/Gemfile +5 -1
  26. data/test/fixtures/cross_agent_tests/README.md +1 -1
  27. data/test/fixtures/cross_agent_tests/cat_map.json +154 -88
  28. data/test/fixtures/cross_agent_tests/docker_container_id/cases.json +30 -6
  29. data/test/fixtures/cross_agent_tests/docker_container_id/docker-1.1.2-lxc-driver.txt +10 -0
  30. data/test/fixtures/cross_agent_tests/docker_container_id/docker-1.1.2-native-driver-fs.txt +10 -0
  31. data/test/fixtures/cross_agent_tests/docker_container_id/docker-1.1.2-native-driver-systemd.txt +10 -0
  32. data/test/fixtures/cross_agent_tests/docker_container_id/heroku.txt +1 -0
  33. data/test/fixtures/cross_agent_tests/docker_container_id/ubuntu-14.04-lxc-container.txt +10 -0
  34. data/test/fixtures/cross_agent_tests/docker_container_id/{lxc-containers-without-docker.txt → ubuntu-14.04-no-container.txt} +0 -0
  35. data/test/fixtures/cross_agent_tests/docker_container_id/ubuntu-14.10-no-container.txt +10 -0
  36. data/test/multiverse/lib/multiverse/runner.rb +1 -0
  37. data/test/multiverse/lib/multiverse/suite.rb +6 -2
  38. data/test/multiverse/suites/active_record/.gitignore +1 -0
  39. data/test/multiverse/suites/active_record/Envfile +25 -7
  40. data/test/multiverse/suites/active_record/Rakefile +9 -0
  41. data/test/{new_relic/agent/instrumentation → multiverse/suites/active_record}/active_record_test.rb +82 -88
  42. data/test/multiverse/suites/active_record/app/models/models.rb +27 -0
  43. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +5 -46
  44. data/test/multiverse/suites/active_record/before_suite.rb +23 -0
  45. data/test/multiverse/suites/active_record/config/database.rb +79 -0
  46. data/test/multiverse/suites/active_record/config/database.yml +19 -0
  47. data/test/multiverse/suites/active_record/db/migrate/20141105131800_create_users_and_aliases.rb +21 -0
  48. data/test/multiverse/suites/active_record/db/migrate/20141106082200_create_orders_and_shipments.rb +25 -0
  49. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +4 -1
  50. data/test/multiverse/suites/agent_only/custom_analytics_events_test.rb +53 -0
  51. data/test/multiverse/suites/agent_only/keepalive_test.rb +3 -7
  52. data/test/multiverse/suites/agent_only/utilization_data_collection_test.rb +170 -0
  53. data/test/multiverse/suites/grape/Envfile +15 -0
  54. data/test/multiverse/suites/grape/config/newrelic.yml +18 -0
  55. data/test/multiverse/suites/grape/grape_test.rb +60 -0
  56. data/test/multiverse/suites/grape/grape_test_api.rb +43 -0
  57. data/test/multiverse/suites/grape/unsupported_version_test.rb +31 -0
  58. data/test/multiverse/suites/json/Envfile +3 -1
  59. data/test/multiverse/suites/rack/rack_env_mutation_test.rb +54 -0
  60. data/test/multiverse/suites/rails/Envfile +1 -1
  61. data/test/multiverse/suites/rails/view_instrumentation_test.rb +2 -1
  62. data/test/multiverse/suites/resque/resque_marshalling_test.rb +54 -0
  63. data/test/multiverse/suites/typhoeus/Envfile +4 -4
  64. data/test/new_relic/agent/agent_test.rb +37 -0
  65. data/test/new_relic/agent/configuration/default_source_test.rb +14 -0
  66. data/test/new_relic/agent/custom_event_aggregator_test.rb +3 -3
  67. data/test/new_relic/agent/error_collector/notice_error_test.rb +4 -4
  68. data/test/new_relic/agent/error_collector_test.rb +27 -4
  69. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +23 -0
  70. data/test/new_relic/agent/new_relic_service_test.rb +208 -103
  71. data/test/new_relic/agent/pipe_service_test.rb +7 -0
  72. data/test/new_relic/agent/synthetics_event_buffer_test.rb +54 -0
  73. data/test/new_relic/agent/synthetics_monitor_test.rb +0 -3
  74. data/test/new_relic/agent/system_info_test.rb +6 -6
  75. data/test/new_relic/agent/transaction_event_aggregator_test.rb +43 -2
  76. data/test/new_relic/agent/utilization_data_test.rb +18 -0
  77. data/test/new_relic/collection_helper_test.rb +0 -1
  78. data/test/new_relic/data_container_tests.rb +11 -7
  79. data/test/new_relic/fake_collector.rb +23 -0
  80. data/test/new_relic/fake_instance_metadata_service.rb +45 -0
  81. data/test/new_relic/license_test.rb +2 -0
  82. data/test/new_relic/marshalling_test_cases.rb +89 -4
  83. data/test/new_relic/transaction_sample_test.rb +1 -0
  84. data/test/test_helper.rb +1 -0
  85. metadata +33 -6
  86. metadata.gz.sig +1 -2
  87. data/test/active_record_fixtures.rb +0 -79
  88. data/test/new_relic/rack/all_test.rb +0 -14
@@ -238,7 +238,7 @@ class NewRelic::Agent::ErrorCollectorTest < Minitest::Test
238
238
 
239
239
  def test_increment_error_count_record_summary_and_txn_metric
240
240
  in_web_transaction('Controller/class/method') do
241
- @error_collector.increment_error_count!(StandardError.new('Boo'))
241
+ @error_collector.increment_error_count!(NewRelic::Agent::TransactionState.tl_get, StandardError.new('Boo'))
242
242
  end
243
243
 
244
244
  assert_metrics_recorded(['Errors/all',
@@ -248,7 +248,7 @@ class NewRelic::Agent::ErrorCollectorTest < Minitest::Test
248
248
 
249
249
  def test_increment_error_count_record_summary_and_txn_metric
250
250
  in_background_transaction('OtherTransaction/AnotherFramework/Job/perform') do
251
- @error_collector.increment_error_count!(StandardError.new('Boo'))
251
+ @error_collector.increment_error_count!(NewRelic::Agent::TransactionState.tl_get, StandardError.new('Boo'))
252
252
  end
253
253
 
254
254
  assert_metrics_recorded(['Errors/all',
@@ -257,14 +257,15 @@ class NewRelic::Agent::ErrorCollectorTest < Minitest::Test
257
257
  end
258
258
 
259
259
  def test_icrement_error_count_summary_outside_transaction
260
- @error_collector.increment_error_count!(StandardError.new('Boo'))
260
+ @error_collector.increment_error_count!(NewRelic::Agent::TransactionState.tl_get, StandardError.new('Boo'))
261
261
 
262
262
  assert_metrics_recorded(['Errors/all'])
263
263
  assert_metrics_not_recorded(['Errors/allWeb', 'Errors/allOther'])
264
264
  end
265
265
 
266
266
  def test_doesnt_increment_error_count_on_transaction_if_nameless
267
- @error_collector.increment_error_count!(StandardError.new('Boo'),
267
+ @error_collector.increment_error_count!(NewRelic::Agent::TransactionState.tl_get,
268
+ StandardError.new('Boo'),
268
269
  :metric => '(unknown)')
269
270
 
270
271
  assert_metrics_not_recorded(['Errors/(unknown)'])
@@ -395,6 +396,28 @@ class NewRelic::Agent::ErrorCollectorTest < Minitest::Test
395
396
  assert_metrics_recorded_exclusive(['Errors/all'])
396
397
  end
397
398
 
399
+ def test_doesnt_double_count_same_exception
400
+ in_transaction do
401
+ error = StandardError.new('wat')
402
+ @error_collector.notice_error(error)
403
+ @error_collector.notice_error(error)
404
+ end
405
+
406
+ assert_metrics_recorded('Errors/all' => { :call_count => 1 })
407
+ assert_equal 1, @error_collector.errors.length
408
+ end
409
+
410
+ def test_doesnt_count_seen_exceptions
411
+ in_transaction do
412
+ error = StandardError.new('wat')
413
+ @error_collector.tag_as_seen(NewRelic::Agent::TransactionState.tl_get, error)
414
+ @error_collector.notice_error(error)
415
+ end
416
+
417
+ assert_metrics_not_recorded(['Errors/all'])
418
+ assert_empty @error_collector.errors
419
+ end
420
+
398
421
  private
399
422
 
400
423
  def expects_error_count_increase(increase)
@@ -39,6 +39,29 @@ module NewRelic::Agent::Instrumentation
39
39
  add_transaction_tracer :bar
40
40
  end
41
41
 
42
+ class TestNonBlockObject
43
+ attr_reader :called
44
+
45
+ def perform_action_without_newrelic_trace(*args)
46
+ @called = true
47
+ end
48
+
49
+ include ControllerInstrumentation
50
+
51
+ alias_method :perform_action, :perform_action_with_newrelic_trace
52
+ end
53
+
54
+ def test_non_block_form
55
+ state = NewRelic::Agent::TransactionState.tl_get
56
+ state.push_traced(false)
57
+
58
+ object = TestNonBlockObject.new
59
+ object.perform_action
60
+ assert object.called
61
+ ensure
62
+ state.pop_traced if state
63
+ end
64
+
42
65
  def setup
43
66
  NewRelic::Agent.drop_buffered_data
44
67
  @object = TestObject.new
@@ -6,29 +6,33 @@ require 'cgi'
6
6
  require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
7
7
  require 'new_relic/agent/commands/thread_profiler_session'
8
8
 
9
- # Tests of HTTP Keep Alive implementation that require a different setup and
10
- # set of mocks.
11
- class NewRelicServiceKeepAliveTest < Minitest::Test
9
+ class NewRelicServiceTest < Minitest::Test
12
10
  def setup
13
11
  @server = NewRelic::Control::Server.new('somewhere.example.com',
14
12
  30303, '10.10.10.10')
15
13
  @service = NewRelic::Agent::NewRelicService.new('license-key', @server)
14
+
15
+ @http_handle = create_http_handle
16
+ @http_handle.respond_to(:get_redirect_host, 'localhost')
17
+ connect_response = {
18
+ 'config' => 'some config directives',
19
+ 'agent_run_id' => 1
20
+ }
21
+ @http_handle.respond_to(:connect, connect_response)
22
+
23
+ @service.stubs(:create_http_connection).returns(@http_handle)
16
24
  end
17
25
 
18
- def stub_net_http_handle(overrides = {})
19
- defaults = { :address => '10.10.10.10', :port => 30303, :started? => true }
20
- stub('http_handle', defaults.merge(overrides))
26
+ def create_http_handle(name='connection')
27
+ HTTPHandle.new(name)
21
28
  end
22
29
 
23
30
  def test_session_handles_timeouts_opening_connection_gracefully
24
- conn = stub_net_http_handle(:started? => false)
25
- conn.stubs(:start).raises(Timeout::Error)
26
- conn.stubs(:finish).raises(RuntimeError)
27
- @service.stubs(:create_http_connection).returns(conn)
31
+ @http_handle.stubs(:start).raises(Timeout::Error)
28
32
 
29
33
  block_ran = false
30
34
 
31
- assert_raises(Timeout::Error) do
35
+ assert_raises(::NewRelic::Agent::ServerConnectionException) do
32
36
  @service.session do
33
37
  block_ran = true
34
38
  end
@@ -38,14 +42,10 @@ class NewRelicServiceKeepAliveTest < Minitest::Test
38
42
  end
39
43
 
40
44
  def test_session_block_reuses_http_handle_with_aggressive_keepalive_off
41
- handle1 = stub_net_http_handle
42
- handle2 = stub_net_http_handle
45
+ handle1 = create_http_handle
46
+ handle2 = create_http_handle
43
47
  @service.stubs(:create_http_connection).returns(handle1, handle2)
44
48
 
45
- handle1.expects(:start).once
46
- handle1.expects(:finish).once
47
- handle2.expects(:start).never
48
-
49
49
  block_ran = false
50
50
  with_config(:aggressive_keepalive => false) do
51
51
  @service.session do
@@ -58,44 +58,46 @@ class NewRelicServiceKeepAliveTest < Minitest::Test
58
58
  end
59
59
  end
60
60
  assert(block_ran)
61
+
62
+ assert_equal([:start, :finish], handle1.calls)
63
+ assert_equal([], handle2.calls)
61
64
  end
62
65
 
63
66
  def test_multiple_http_handles_are_used_outside_session_block
64
- handle1 = stub_net_http_handle
65
- handle2 = stub_net_http_handle
67
+ handle1 = create_http_handle
68
+ handle2 = create_http_handle
66
69
  @service.stubs(:create_http_connection).returns(handle1, handle2)
67
70
  assert_equal(@service.http_connection.object_id, handle1.object_id)
68
71
  assert_equal(@service.http_connection.object_id, handle2.object_id)
69
72
  end
70
73
 
74
+ # Calling start on a Net::HTTP instance results in connection keep-alive
75
+ # being used, which means that the connection won't be automatically closed
76
+ # once a request is issued. For calls to the service outside of a session
77
+ # block (/get_redirect_host and /connect, namely), we actually want the
78
+ # connection to only be used for a single request.
79
+ def test_connections_not_explicitly_started_outside_session_block
80
+ @http_handle.respond_to(:foo, ['blah'])
71
81
 
72
- def test_session_starts_and_finishes_http_session_with_aggressive_keepalive_off
73
- handle1 = stub_net_http_handle
74
- handle1.expects(:start).once
75
- handle1.expects(:finish).once
76
- @service.stubs(:create_http_connection).returns(handle1)
82
+ @service.send(:invoke_remote, :foo, ['payload'])
83
+
84
+ assert_equal([:request], @http_handle.calls)
85
+ end
77
86
 
87
+ def test_session_starts_and_finishes_http_session_with_aggressive_keepalive_off
78
88
  block_ran = false
79
89
 
80
90
  with_config(:aggressive_keepalive => false) do
81
91
  @service.session do
82
92
  block_ran = true
83
- # mocks expect #start and #finish to be called. This is how Net::HTTP
84
- # implements keep alive
85
93
  end
86
94
  end
95
+
87
96
  assert(block_ran)
97
+ assert_equal([:start, :finish], @http_handle.calls)
88
98
  end
89
99
 
90
100
  def test_session_does_not_close_connection_if_aggressive_keepalive_on
91
- defaults = { :address => '10.10.10.10', :port => 30303, :started? => true }
92
- handle = stub('http_handle', defaults)
93
-
94
- handle.expects(:start).once
95
- handle.expects(:finish).never
96
-
97
- @service.stubs(:create_http_connection).returns(handle)
98
-
99
101
  calls_to_block = 0
100
102
 
101
103
  with_config(:aggressive_keepalive => true) do
@@ -105,51 +107,96 @@ class NewRelicServiceKeepAliveTest < Minitest::Test
105
107
  end
106
108
 
107
109
  assert_equal(2, calls_to_block)
110
+ assert_equal([:start], @http_handle.calls)
108
111
  end
109
- end
110
112
 
111
- class NewRelicServiceTest < Minitest::Test
112
- def initialize(*_)
113
- [ :HTTPSuccess,
114
- :HTTPUnauthorized,
115
- :HTTPNotFound,
116
- :HTTPRequestEntityTooLarge,
117
- :HTTPUnsupportedMediaType ].each do |class_name|
118
- extend_with_mock(class_name)
113
+ def test_requests_after_connection_failure_in_session_still_use_connection_caching
114
+ conn0 = create_http_handle('first connection')
115
+ conn1 = create_http_handle('second connection')
116
+ conn2 = create_http_handle('third connection')
117
+ @service.stubs(:create_http_connection).returns(conn0, conn1, conn2)
118
+
119
+ rsp_payload = ['ok']
120
+
121
+ conn0.respond_to(:foo, EOFError.new)
122
+ conn1.respond_to(:foo, rsp_payload)
123
+ conn1.respond_to(:bar, rsp_payload)
124
+ conn1.respond_to(:baz, rsp_payload)
125
+
126
+ @service.session do
127
+ @service.send(:invoke_remote, :foo, ['payload'])
128
+ @service.send(:invoke_remote, :bar, ['payload'])
129
+ @service.send(:invoke_remote, :baz, ['payload'])
119
130
  end
120
- super
131
+
132
+ assert_equal([:start, :request, :finish], conn0.calls)
133
+ assert_equal([:start, :request, :request, :request], conn1.calls)
134
+ assert_equal([], conn2.calls)
121
135
  end
122
136
 
123
- def extend_with_mock(class_name)
124
- if !self.class.const_defined?(class_name)
125
- klass = self.class.const_set(class_name,
126
- Class.new(Object.const_get(:Net).const_get(class_name)))
127
- klass.class_eval { include HTTPResponseMock }
137
+ def test_repeated_connection_failures
138
+ conn0 = create_http_handle('first connection')
139
+ conn1 = create_http_handle('second connection')
140
+ conn2 = create_http_handle('third connection')
141
+ @service.stubs(:create_http_connection).returns(conn0, conn1, conn2)
142
+
143
+ rsp_payload = ['ok']
144
+
145
+ conn0.respond_to(:foo, EOFError.new)
146
+ conn1.respond_to(:foo, EOFError.new)
147
+ conn2.respond_to(:bar, rsp_payload)
148
+ conn2.respond_to(:baz, rsp_payload)
149
+
150
+ @service.session do
151
+ assert_raises(::NewRelic::Agent::ServerConnectionException) do
152
+ @service.send(:invoke_remote, :foo, ['payload'])
153
+ end
154
+ @service.send(:invoke_remote, :bar, ['payload'])
155
+ @service.send(:invoke_remote, :baz, ['payload'])
128
156
  end
157
+
158
+ assert_equal([:start, :request, :finish], conn0.calls)
159
+ assert_equal([:start, :request, :finish], conn1.calls)
160
+ assert_equal([:start, :request, :request], conn2.calls)
129
161
  end
130
- protected :extend_with_mock
131
162
 
132
- def setup
133
- @server = NewRelic::Control::Server.new('somewhere.example.com',
134
- 30303, '10.10.10.10')
135
- @service = NewRelic::Agent::NewRelicService.new('license-key', @server)
136
- @http_handle = HTTPHandle.new
137
- @service.stubs(:create_http_connection).returns(@http_handle)
163
+ def test_repeated_connection_failures_on_reconnect
164
+ conn0 = create_http_handle('first connection')
165
+ conn1 = create_http_handle('second connection')
166
+ conn2 = create_http_handle('third connection')
138
167
 
139
- @http_handle.respond_to(:get_redirect_host, 'localhost')
140
- connect_response = {
141
- 'config' => 'some config directives',
142
- 'agent_run_id' => 1
143
- }
144
- @http_handle.respond_to(:connect, connect_response)
168
+ conn0.respond_to(:foo, EOFError.new)
169
+ conn1.expects(:start).once.raises(EOFError.new)
170
+ conn2.expects(:start).never
171
+
172
+ @service.stubs(:create_http_connection).returns(conn0, conn1, conn2)
145
173
 
146
- @reverse_encoder = Module.new do
147
- def self.encode(data)
148
- data.reverse
174
+ assert_raises(::NewRelic::Agent::ServerConnectionException) do
175
+ @service.session do
176
+ @service.send(:invoke_remote, :foo, ['payload'])
149
177
  end
150
178
  end
151
179
  end
152
180
 
181
+ def test_repeated_connection_failures_outside_session
182
+ conn0 = create_http_handle('first connection')
183
+ conn1 = create_http_handle('second connection')
184
+ conn2 = create_http_handle('third connection')
185
+
186
+ conn0.respond_to(:foo, EOFError.new)
187
+ conn1.respond_to(:foo, EOFError.new)
188
+
189
+ @service.stubs(:create_http_connection).returns(conn0, conn1, conn2)
190
+
191
+ assert_raises(::NewRelic::Agent::ServerConnectionException) do
192
+ @service.send(:invoke_remote, :foo, ['payload'])
193
+ end
194
+
195
+ assert_equal([:request], conn0.calls)
196
+ assert_equal([:request], conn1.calls)
197
+ assert_equal([], conn2.calls)
198
+ end
199
+
153
200
  def test_cert_file_path
154
201
  assert @service.cert_file_path
155
202
  assert_equal File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'cert', 'cacert.pem')), @service.cert_file_path
@@ -584,7 +631,7 @@ class NewRelicServiceTest < Minitest::Test
584
631
  prepared = marshaller.prepare(dummy, :encoder => identity_encoder)
585
632
  assert_equal(dummy, prepared)
586
633
 
587
- prepared = marshaller.prepare(dummy, :encoder => @reverse_encoder)
634
+ prepared = marshaller.prepare(dummy, :encoder => ReverseEncoder)
588
635
  decoded = prepared.map { |x| x.reverse }
589
636
  assert_equal(dummy, decoded)
590
637
  end
@@ -596,7 +643,7 @@ class NewRelicServiceTest < Minitest::Test
596
643
  end
597
644
  dummy = [[inner_array]]
598
645
  marshaller = NewRelic::Agent::NewRelicService::Marshaller.new
599
- prepared = marshaller.prepare(dummy, :encoder => @reverse_encoder)
646
+ prepared = marshaller.prepare(dummy, :encoder => ReverseEncoder)
600
647
  assert_equal([[['dcba']]], prepared)
601
648
  end
602
649
 
@@ -826,14 +873,82 @@ class NewRelicServiceTest < Minitest::Test
826
873
  end
827
874
  end
828
875
 
876
+ module ReverseEncoder
877
+ def self.encode(data)
878
+ data.reverse
879
+ end
880
+ end
881
+
882
+ # This class acts as a stand-in for instances of Net::HTTP, which represent
883
+ # HTTP connections.
884
+ #
885
+ # It can record the start / finish / request calls made to it, and exposes
886
+ # that call sequence via the #calls accessor.
887
+ #
888
+ # It can also be configured to generate dummy responses for calls to request,
889
+ # via the #respond_to method.
829
890
  class HTTPHandle
830
- attr_accessor :read_timeout, :route_table
891
+ # This module gets included into the Net::HTTPResponse subclasses that we
892
+ # create below. We do this because the code in NewRelicService switches
893
+ # behavior based on the type of response that is returned, and we want to be
894
+ # able to create dummy responses for testing easily.
895
+ module HTTPResponseMock
896
+ attr_accessor :code, :body, :message, :headers
897
+
898
+ def initialize(body, code=200, message='OK')
899
+ @code = code
900
+ @body = body
901
+ @message = message
902
+ @headers = {}
903
+ end
904
+
905
+ def [](key)
906
+ @headers[key]
907
+ end
908
+ end
831
909
 
832
- def initialize
910
+ HTTPSuccess = Class.new(Net::HTTPSuccess) { include HTTPResponseMock }
911
+ HTTPUnauthorized = Class.new(Net::HTTPUnauthorized) { include HTTPResponseMock }
912
+ HTTPNotFound = Class.new(Net::HTTPNotFound) { include HTTPResponseMock }
913
+ HTTPRequestEntityTooLarge = Class.new(Net::HTTPRequestEntityTooLarge) { include HTTPResponseMock }
914
+ HTTPUnsupportedMediaType = Class.new(Net::HTTPUnsupportedMediaType) { include HTTPResponseMock }
915
+
916
+ attr_accessor :read_timeout
917
+ attr_reader :calls, :last_request
918
+
919
+ def initialize(name)
920
+ @name = name
921
+ @started = false
833
922
  reset
834
923
  end
835
924
 
836
- def respond_to(method, payload, opts={})
925
+ def start
926
+ @calls << :start
927
+ @started = true
928
+ end
929
+
930
+ def finish
931
+ @calls << :finish
932
+ @started = false
933
+ end
934
+
935
+ def inspect
936
+ "<HTTPHandle: #{@name}>"
937
+ end
938
+
939
+ def started?
940
+ @started
941
+ end
942
+
943
+ def address
944
+ 'whereever.com'
945
+ end
946
+
947
+ def port
948
+ 8080
949
+ end
950
+
951
+ def create_response_mock(payload, opts={})
837
952
  if NewRelic::Agent::NewRelicService::JsonMarshaller.is_supported?
838
953
  format = :json
839
954
  else
@@ -858,39 +973,44 @@ class NewRelicServiceTest < Minitest::Test
858
973
  end
859
974
 
860
975
  if opts[:format] == :json
861
- register(klass.new(JSON.dump('return_value' => payload), opts[:code])) do |request|
862
- request.path.include?(method.to_s)
863
- end
976
+ klass.new(JSON.dump('return_value' => payload), opts[:code], {})
864
977
  else
865
- register(klass.new(Marshal.dump('return_value' => payload), opts[:code])) do |request|
866
- request.path.include?(method.to_s)
867
- end
978
+ klass.new(Marshal.dump('return_value' => payload), opts[:code], {})
868
979
  end
869
980
  end
870
981
 
871
- def register(response, &block)
872
- @route_table[block] = response
982
+ def respond_to(method, payload, opts={})
983
+ case payload
984
+ when Exception then rsp = payload
985
+ else rsp = create_response_mock(payload, opts)
986
+ end
987
+
988
+ @route_table[method.to_s] = rsp
873
989
  end
874
990
 
875
991
  def request(*args)
876
- @last_request = args.first
877
- @route_table.each_pair do |condition, response|
878
- if condition.call(args[0])
879
- return response
880
- end
992
+ @calls << :request
993
+
994
+ request = args.first
995
+ @last_request = request
996
+
997
+ route = @route_table.keys.find { |r| request.path.include?(r) }
998
+
999
+ if route
1000
+ response = @route_table[route]
1001
+ raise response if response.kind_of?(Exception)
1002
+ response
1003
+ else
1004
+ HTTPNotFound.new('not found', 404)
881
1005
  end
882
- HTTPNotFound.new('not found', 404)
883
1006
  end
884
1007
 
885
1008
  def reset
1009
+ @calls = []
886
1010
  @route_table = {}
887
1011
  @last_request = nil
888
1012
  end
889
1013
 
890
- def last_request
891
- @last_request
892
- end
893
-
894
1014
  def last_request_payload
895
1015
  return nil unless @last_request && @last_request.body
896
1016
 
@@ -908,19 +1028,4 @@ class NewRelicServiceTest < Minitest::Test
908
1028
  end
909
1029
  end
910
1030
  end
911
-
912
- module HTTPResponseMock
913
- attr_accessor :code, :body, :message, :headers
914
-
915
- def initialize(body, code=200, message='OK')
916
- @code = code
917
- @body = body
918
- @message = message
919
- @headers = {}
920
- end
921
-
922
- def [](key)
923
- @headers[key]
924
- end
925
- end
926
1031
  end