newrelic_rpm 6.8.0.360 → 9.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -1
  3. data/.rubocop.yml +1845 -0
  4. data/.rubocop_todo.yml +61 -0
  5. data/.simplecov +16 -0
  6. data/.snyk +11 -0
  7. data/.yardopts +1 -0
  8. data/Brewfile +13 -0
  9. data/CHANGELOG.md +4029 -2514
  10. data/CONTRIBUTING.md +132 -19
  11. data/DOCKER.md +167 -0
  12. data/Dockerfile +10 -0
  13. data/Gemfile +5 -2
  14. data/Guardfile +21 -8
  15. data/LICENSE +202 -38
  16. data/README.md +86 -87
  17. data/Rakefile +32 -32
  18. data/THIRD_PARTY_NOTICES.md +28 -0
  19. data/Thorfile +5 -0
  20. data/bin/newrelic +4 -2
  21. data/bin/newrelic_cmd +2 -0
  22. data/bin/nrdebug +86 -63
  23. data/config.dot +5 -5
  24. data/docker-compose.yml +107 -0
  25. data/init.rb +5 -7
  26. data/install.rb +3 -3
  27. data/lefthook.yml +9 -0
  28. data/lib/new_relic/agent/adaptive_sampler.rb +14 -10
  29. data/lib/new_relic/agent/agent.rb +114 -942
  30. data/lib/new_relic/agent/agent_helpers/connect.rb +222 -0
  31. data/lib/new_relic/agent/agent_helpers/harvest.rb +153 -0
  32. data/lib/new_relic/agent/agent_helpers/shutdown.rb +72 -0
  33. data/lib/new_relic/agent/agent_helpers/special_startup.rb +74 -0
  34. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +175 -0
  35. data/lib/new_relic/agent/agent_helpers/startup.rb +202 -0
  36. data/lib/new_relic/agent/agent_helpers/transmit.rb +76 -0
  37. data/lib/new_relic/agent/agent_logger.rb +28 -24
  38. data/lib/new_relic/agent/attribute_filter.rb +66 -49
  39. data/lib/new_relic/agent/attribute_processing.rb +10 -10
  40. data/lib/new_relic/agent/attributes.rb +9 -8
  41. data/lib/new_relic/agent/audit_logger.rb +22 -7
  42. data/lib/new_relic/agent/autostart.rb +22 -21
  43. data/lib/new_relic/agent/chained_call.rb +2 -2
  44. data/lib/new_relic/agent/commands/agent_command.rb +5 -5
  45. data/lib/new_relic/agent/commands/agent_command_router.rb +16 -14
  46. data/lib/new_relic/agent/commands/thread_profiler_session.rb +17 -15
  47. data/lib/new_relic/agent/configuration/default_source.rb +1444 -1167
  48. data/lib/new_relic/agent/configuration/dotted_hash.rb +7 -6
  49. data/lib/new_relic/agent/configuration/environment_source.rb +14 -12
  50. data/lib/new_relic/agent/configuration/event_harvest_config.rb +41 -18
  51. data/lib/new_relic/agent/configuration/high_security_source.rb +12 -13
  52. data/lib/new_relic/agent/configuration/manager.rb +96 -70
  53. data/lib/new_relic/agent/configuration/manual_source.rb +2 -2
  54. data/lib/new_relic/agent/configuration/mask_defaults.rb +4 -4
  55. data/lib/new_relic/agent/configuration/security_policy_source.rb +93 -96
  56. data/lib/new_relic/agent/configuration/server_source.rb +44 -42
  57. data/lib/new_relic/agent/configuration/yaml_source.rb +36 -12
  58. data/lib/new_relic/agent/configuration.rb +2 -2
  59. data/lib/new_relic/agent/connect/request_builder.rb +19 -19
  60. data/lib/new_relic/agent/connect/response_handler.rb +6 -9
  61. data/lib/new_relic/agent/custom_event_aggregator.rb +16 -16
  62. data/lib/new_relic/agent/database/explain_plan_helpers.rb +6 -7
  63. data/lib/new_relic/agent/database/obfuscation_helpers.rb +18 -17
  64. data/lib/new_relic/agent/database/obfuscator.rb +5 -5
  65. data/lib/new_relic/agent/database/postgres_explain_obfuscator.rb +4 -4
  66. data/lib/new_relic/agent/database.rb +47 -56
  67. data/lib/new_relic/agent/database_adapter.rb +35 -0
  68. data/lib/new_relic/agent/datastores/metric_helper.rb +22 -23
  69. data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +8 -7
  70. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +18 -22
  71. data/lib/new_relic/agent/datastores/mongo.rb +7 -12
  72. data/lib/new_relic/agent/datastores/nosql_obfuscator.rb +41 -0
  73. data/lib/new_relic/agent/datastores/redis.rb +10 -16
  74. data/lib/new_relic/agent/datastores.rb +14 -16
  75. data/lib/new_relic/agent/deprecator.rb +2 -2
  76. data/lib/new_relic/agent/{cross_app_payload.rb → distributed_tracing/cross_app_payload.rb} +13 -12
  77. data/lib/new_relic/agent/{cross_app_tracing.rb → distributed_tracing/cross_app_tracing.rb} +90 -70
  78. data/lib/new_relic/agent/distributed_tracing/distributed_trace_attributes.rb +84 -0
  79. data/lib/new_relic/agent/distributed_tracing/distributed_trace_metrics.rb +75 -0
  80. data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +163 -0
  81. data/lib/new_relic/agent/distributed_tracing/distributed_trace_transport_type.rb +38 -0
  82. data/lib/new_relic/agent/distributed_tracing/trace_context.rb +245 -0
  83. data/lib/new_relic/agent/distributed_tracing/trace_context_payload.rb +127 -0
  84. data/lib/new_relic/agent/distributed_tracing.rb +113 -32
  85. data/lib/new_relic/agent/encoding_normalizer.rb +5 -3
  86. data/lib/new_relic/agent/error_collector.rb +129 -65
  87. data/lib/new_relic/agent/error_event_aggregator.rb +9 -8
  88. data/lib/new_relic/agent/error_filter.rb +174 -0
  89. data/lib/new_relic/agent/error_trace_aggregator.rb +10 -8
  90. data/lib/new_relic/agent/event_aggregator.rb +23 -22
  91. data/lib/new_relic/agent/event_buffer.rb +8 -9
  92. data/lib/new_relic/agent/event_listener.rb +2 -3
  93. data/lib/new_relic/agent/event_loop.rb +28 -26
  94. data/lib/new_relic/agent/external.rb +19 -52
  95. data/lib/new_relic/agent/guid_generator.rb +14 -12
  96. data/lib/new_relic/agent/harvester.rb +6 -9
  97. data/lib/new_relic/agent/heap.rb +9 -10
  98. data/lib/new_relic/agent/hostname.rb +22 -9
  99. data/lib/new_relic/agent/http_clients/abstract.rb +69 -0
  100. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +30 -26
  101. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +37 -21
  102. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +22 -23
  103. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +18 -17
  104. data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +28 -8
  105. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +17 -17
  106. data/lib/new_relic/agent/http_clients/uri_util.rb +13 -14
  107. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +10 -25
  108. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +42 -0
  109. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +46 -34
  110. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +31 -0
  111. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +64 -0
  112. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +30 -0
  113. data/lib/new_relic/agent/instrumentation/action_mailbox_subscriber.rb +33 -0
  114. data/lib/new_relic/agent/instrumentation/action_mailer.rb +30 -0
  115. data/lib/new_relic/agent/instrumentation/action_mailer_subscriber.rb +85 -0
  116. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +28 -21
  117. data/lib/new_relic/agent/instrumentation/active_job.rb +34 -14
  118. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +41 -0
  119. data/lib/new_relic/agent/instrumentation/active_merchant.rb +21 -7
  120. data/lib/new_relic/agent/instrumentation/active_record.rb +97 -47
  121. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +97 -73
  122. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +53 -66
  123. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +36 -12
  124. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +37 -24
  125. data/lib/new_relic/agent/instrumentation/active_storage.rb +8 -4
  126. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +9 -30
  127. data/lib/new_relic/agent/instrumentation/active_support.rb +27 -0
  128. data/lib/new_relic/agent/instrumentation/active_support_logger/chain.rb +23 -0
  129. data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +20 -0
  130. data/lib/new_relic/agent/instrumentation/active_support_logger/prepend.rb +12 -0
  131. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +24 -0
  132. data/lib/new_relic/agent/instrumentation/active_support_subscriber.rb +41 -0
  133. data/lib/new_relic/agent/instrumentation/bunny/chain.rb +45 -0
  134. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +150 -0
  135. data/lib/new_relic/agent/instrumentation/bunny/prepend.rb +35 -0
  136. data/lib/new_relic/agent/instrumentation/bunny.rb +14 -138
  137. data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +36 -0
  138. data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +21 -0
  139. data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +27 -0
  140. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +31 -0
  141. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +75 -63
  142. data/lib/new_relic/agent/instrumentation/curb/chain.rb +91 -0
  143. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +221 -0
  144. data/lib/new_relic/agent/instrumentation/curb/prepend.rb +61 -0
  145. data/lib/new_relic/agent/instrumentation/curb.rb +16 -201
  146. data/lib/new_relic/agent/instrumentation/custom_events.rb +12 -0
  147. data/lib/new_relic/agent/instrumentation/custom_events_subscriber.rb +38 -0
  148. data/lib/new_relic/agent/instrumentation/delayed_job/chain.rb +36 -0
  149. data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +48 -0
  150. data/lib/new_relic/agent/instrumentation/delayed_job/prepend.rb +33 -0
  151. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +31 -52
  152. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +29 -0
  153. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +67 -0
  154. data/lib/new_relic/agent/instrumentation/elasticsearch/prepend.rb +13 -0
  155. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +31 -0
  156. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +10 -8
  157. data/lib/new_relic/agent/instrumentation/excon.rb +29 -31
  158. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +20 -0
  159. data/lib/new_relic/agent/instrumentation/fiber/instrumentation.rb +24 -0
  160. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +18 -0
  161. data/lib/new_relic/agent/instrumentation/fiber.rb +25 -0
  162. data/lib/new_relic/agent/instrumentation/grape/chain.rb +24 -0
  163. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +100 -0
  164. data/lib/new_relic/agent/instrumentation/grape/prepend.rb +17 -0
  165. data/lib/new_relic/agent/instrumentation/grape.rb +17 -123
  166. data/lib/new_relic/agent/instrumentation/grpc/client/chain.rb +97 -0
  167. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +90 -0
  168. data/lib/new_relic/agent/instrumentation/grpc/client/prepend.rb +111 -0
  169. data/lib/new_relic/agent/instrumentation/grpc/client/request_wrapper.rb +30 -0
  170. data/lib/new_relic/agent/instrumentation/grpc/helper.rb +32 -0
  171. data/lib/new_relic/agent/instrumentation/grpc/server/chain.rb +69 -0
  172. data/lib/new_relic/agent/instrumentation/grpc/server/instrumentation.rb +134 -0
  173. data/lib/new_relic/agent/instrumentation/grpc/server/rpc_desc_prepend.rb +35 -0
  174. data/lib/new_relic/agent/instrumentation/grpc/server/rpc_server_prepend.rb +26 -0
  175. data/lib/new_relic/agent/instrumentation/grpc_client.rb +23 -0
  176. data/lib/new_relic/agent/instrumentation/grpc_server.rb +25 -0
  177. data/lib/new_relic/agent/instrumentation/httpclient/chain.rb +24 -0
  178. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +37 -0
  179. data/lib/new_relic/agent/instrumentation/httpclient/prepend.rb +15 -0
  180. data/lib/new_relic/agent/instrumentation/httpclient.rb +12 -32
  181. data/lib/new_relic/agent/instrumentation/httprb/chain.rb +22 -0
  182. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +30 -0
  183. data/lib/new_relic/agent/instrumentation/httprb/prepend.rb +15 -0
  184. data/lib/new_relic/agent/instrumentation/httprb.rb +29 -0
  185. data/lib/new_relic/agent/instrumentation/ignore_actions.rb +6 -7
  186. data/lib/new_relic/agent/instrumentation/logger/chain.rb +21 -0
  187. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +66 -0
  188. data/lib/new_relic/agent/instrumentation/logger/prepend.rb +13 -0
  189. data/lib/new_relic/agent/instrumentation/logger.rb +26 -0
  190. data/lib/new_relic/agent/instrumentation/memcache/chain.rb +15 -0
  191. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +60 -125
  192. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +59 -0
  193. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +90 -0
  194. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +103 -0
  195. data/lib/new_relic/agent/instrumentation/memcache.rb +57 -71
  196. data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +16 -15
  197. data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +11 -11
  198. data/lib/new_relic/agent/instrumentation/mongo.rb +7 -132
  199. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +53 -17
  200. data/lib/new_relic/agent/instrumentation/net_http/chain.rb +24 -0
  201. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +40 -0
  202. data/lib/new_relic/agent/instrumentation/net_http/prepend.rb +21 -0
  203. data/lib/new_relic/agent/instrumentation/net_http.rb +44 -0
  204. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +75 -9
  205. data/lib/new_relic/agent/instrumentation/padrino/chain.rb +38 -0
  206. data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +28 -0
  207. data/lib/new_relic/agent/instrumentation/padrino/prepend.rb +20 -0
  208. data/lib/new_relic/agent/instrumentation/padrino.rb +22 -58
  209. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +7 -7
  210. data/lib/new_relic/agent/instrumentation/queue_time.rb +9 -10
  211. data/lib/new_relic/agent/instrumentation/rack/chain.rb +66 -0
  212. data/lib/new_relic/agent/instrumentation/rack/helpers.rb +33 -0
  213. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +75 -0
  214. data/lib/new_relic/agent/instrumentation/rack/prepend.rb +43 -0
  215. data/lib/new_relic/agent/instrumentation/rack.rb +33 -141
  216. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +22 -57
  217. data/lib/new_relic/agent/instrumentation/rails_middleware.rb +5 -5
  218. data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +10 -9
  219. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +18 -6
  220. data/lib/new_relic/agent/instrumentation/rails_notifications/action_view.rb +9 -6
  221. data/lib/new_relic/agent/instrumentation/rails_notifications/custom_events.rb +30 -0
  222. data/lib/new_relic/agent/instrumentation/rake/chain.rb +20 -0
  223. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +142 -0
  224. data/lib/new_relic/agent/instrumentation/rake/prepend.rb +14 -0
  225. data/lib/new_relic/agent/instrumentation/rake.rb +18 -158
  226. data/lib/new_relic/agent/instrumentation/redis/chain.rb +45 -0
  227. data/lib/new_relic/agent/instrumentation/redis/constants.rb +17 -0
  228. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +94 -0
  229. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +16 -0
  230. data/lib/new_relic/agent/instrumentation/redis/prepend.rb +29 -0
  231. data/lib/new_relic/agent/instrumentation/redis.rb +20 -103
  232. data/lib/new_relic/agent/instrumentation/resque/chain.rb +21 -0
  233. data/lib/new_relic/agent/instrumentation/resque/helper.rb +19 -0
  234. data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +34 -0
  235. data/lib/new_relic/agent/instrumentation/resque/prepend.rb +15 -0
  236. data/lib/new_relic/agent/instrumentation/resque.rb +33 -41
  237. data/lib/new_relic/agent/instrumentation/sequel.rb +17 -20
  238. data/lib/new_relic/agent/instrumentation/sequel_helper.rb +13 -13
  239. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +20 -0
  240. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +30 -0
  241. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +37 -0
  242. data/lib/new_relic/agent/instrumentation/sidekiq.rb +30 -46
  243. data/lib/new_relic/agent/instrumentation/sinatra/chain.rb +55 -0
  244. data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +31 -37
  245. data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +126 -0
  246. data/lib/new_relic/agent/instrumentation/sinatra/prepend.rb +33 -0
  247. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +4 -4
  248. data/lib/new_relic/agent/instrumentation/sinatra.rb +35 -165
  249. data/lib/new_relic/agent/instrumentation/thread/chain.rb +24 -0
  250. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +28 -0
  251. data/lib/new_relic/agent/instrumentation/thread/prepend.rb +22 -0
  252. data/lib/new_relic/agent/instrumentation/thread.rb +20 -0
  253. data/lib/new_relic/agent/instrumentation/tilt/chain.rb +24 -0
  254. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +42 -0
  255. data/lib/new_relic/agent/instrumentation/tilt/prepend.rb +13 -0
  256. data/lib/new_relic/agent/instrumentation/tilt.rb +25 -0
  257. data/lib/new_relic/agent/instrumentation/typhoeus/chain.rb +22 -0
  258. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +80 -0
  259. data/lib/new_relic/agent/instrumentation/typhoeus/prepend.rb +14 -0
  260. data/lib/new_relic/agent/instrumentation/typhoeus.rb +14 -76
  261. data/lib/new_relic/agent/instrumentation.rb +2 -2
  262. data/lib/new_relic/agent/internal_agent_error.rb +3 -3
  263. data/lib/new_relic/agent/javascript_instrumentor.rb +59 -48
  264. data/lib/new_relic/agent/linking_metadata.rb +44 -0
  265. data/lib/new_relic/agent/local_log_decorator.rb +37 -0
  266. data/lib/new_relic/agent/log_event_aggregator.rb +235 -0
  267. data/lib/new_relic/agent/log_once.rb +2 -2
  268. data/lib/new_relic/agent/log_priority.rb +20 -0
  269. data/lib/new_relic/agent/logging.rb +104 -51
  270. data/lib/new_relic/agent/memory_logger.rb +3 -3
  271. data/lib/new_relic/agent/messaging.rb +74 -156
  272. data/lib/new_relic/agent/method_tracer.rb +157 -150
  273. data/lib/new_relic/agent/method_tracer_helpers.rb +89 -12
  274. data/lib/new_relic/agent/monitors/cross_app_monitor.rb +117 -0
  275. data/lib/new_relic/agent/monitors/distributed_tracing_monitor.rb +28 -0
  276. data/lib/new_relic/agent/{inbound_request_monitor.rb → monitors/inbound_request_monitor.rb} +3 -4
  277. data/lib/new_relic/agent/{synthetics_monitor.rb → monitors/synthetics_monitor.rb} +8 -13
  278. data/lib/new_relic/agent/monitors.rb +26 -0
  279. data/lib/new_relic/agent/new_relic_service/encoders.rb +8 -8
  280. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +7 -7
  281. data/lib/new_relic/agent/new_relic_service/marshaller.rb +3 -3
  282. data/lib/new_relic/agent/new_relic_service/security_policy_settings.rb +5 -5
  283. data/lib/new_relic/agent/new_relic_service.rb +266 -193
  284. data/lib/new_relic/agent/noticeable_error.rb +19 -0
  285. data/lib/new_relic/agent/null_logger.rb +8 -4
  286. data/lib/new_relic/agent/obfuscator.rb +9 -11
  287. data/lib/new_relic/agent/parameter_filtering.rb +30 -16
  288. data/lib/new_relic/agent/payload_metric_mapping.rb +10 -11
  289. data/lib/new_relic/agent/pipe_channel_manager.rb +34 -23
  290. data/lib/new_relic/agent/pipe_service.rb +14 -9
  291. data/lib/new_relic/agent/prepend_supportability.rb +3 -3
  292. data/lib/new_relic/agent/priority_sampled_buffer.rb +16 -16
  293. data/lib/new_relic/agent/rules_engine/replacement_rule.rb +12 -12
  294. data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +13 -14
  295. data/lib/new_relic/agent/rules_engine.rb +6 -5
  296. data/lib/new_relic/agent/sampler.rb +6 -6
  297. data/lib/new_relic/agent/sampler_collection.rb +5 -6
  298. data/lib/new_relic/agent/samplers/cpu_sampler.rb +9 -8
  299. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +21 -18
  300. data/lib/new_relic/agent/samplers/memory_sampler.rb +33 -22
  301. data/lib/new_relic/agent/samplers/object_sampler.rb +3 -3
  302. data/lib/new_relic/agent/samplers/vm_sampler.rb +22 -20
  303. data/lib/new_relic/agent/span_event_aggregator.rb +16 -16
  304. data/lib/new_relic/agent/span_event_primitive.rb +106 -68
  305. data/lib/new_relic/agent/sql_sampler.rb +23 -23
  306. data/lib/new_relic/agent/stats.rb +80 -43
  307. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +11 -13
  308. data/lib/new_relic/agent/stats_engine/stats_hash.rb +13 -14
  309. data/lib/new_relic/agent/stats_engine.rb +9 -9
  310. data/lib/new_relic/agent/synthetics_event_aggregator.rb +9 -10
  311. data/lib/new_relic/agent/system_info.rb +97 -68
  312. data/lib/new_relic/agent/threading/agent_thread.rb +19 -15
  313. data/lib/new_relic/agent/threading/backtrace_node.rb +13 -14
  314. data/lib/new_relic/agent/threading/backtrace_service.rb +18 -22
  315. data/lib/new_relic/agent/threading/thread_profile.rb +25 -25
  316. data/lib/new_relic/agent/timestamp_sampled_buffer.rb +3 -3
  317. data/lib/new_relic/agent/tracer.rb +127 -107
  318. data/lib/new_relic/agent/transaction/abstract_segment.rb +145 -49
  319. data/lib/new_relic/agent/transaction/datastore_segment.rb +23 -19
  320. data/lib/new_relic/agent/transaction/distributed_tracer.rb +185 -0
  321. data/lib/new_relic/agent/transaction/distributed_tracing.rb +76 -86
  322. data/lib/new_relic/agent/transaction/external_request_segment.rb +67 -77
  323. data/lib/new_relic/agent/transaction/message_broker_segment.rb +34 -46
  324. data/lib/new_relic/agent/transaction/request_attributes.rb +40 -40
  325. data/lib/new_relic/agent/transaction/segment.rb +41 -11
  326. data/lib/new_relic/agent/transaction/slowest_sample_buffer.rb +2 -4
  327. data/lib/new_relic/agent/transaction/synthetics_sample_buffer.rb +3 -3
  328. data/lib/new_relic/agent/transaction/trace.rb +19 -17
  329. data/lib/new_relic/agent/transaction/trace_builder.rb +11 -11
  330. data/lib/new_relic/agent/transaction/trace_context.rb +102 -93
  331. data/lib/new_relic/agent/transaction/trace_node.rb +31 -32
  332. data/lib/new_relic/agent/transaction/tracing.rb +22 -13
  333. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +7 -7
  334. data/lib/new_relic/agent/transaction.rb +239 -198
  335. data/lib/new_relic/agent/transaction_error_primitive.rb +32 -28
  336. data/lib/new_relic/agent/transaction_event_aggregator.rb +17 -17
  337. data/lib/new_relic/agent/transaction_event_primitive.rb +43 -47
  338. data/lib/new_relic/agent/transaction_event_recorder.rb +17 -16
  339. data/lib/new_relic/agent/transaction_metrics.rb +11 -10
  340. data/lib/new_relic/agent/transaction_sampler.rb +8 -9
  341. data/lib/new_relic/agent/transaction_time_aggregator.rb +33 -28
  342. data/lib/new_relic/agent/utilization/aws.rb +35 -5
  343. data/lib/new_relic/agent/utilization/azure.rb +7 -7
  344. data/lib/new_relic/agent/utilization/gcp.rb +11 -11
  345. data/lib/new_relic/agent/utilization/pcf.rb +7 -6
  346. data/lib/new_relic/agent/utilization/vendor.rb +45 -30
  347. data/lib/new_relic/agent/utilization_data.rb +8 -6
  348. data/lib/new_relic/agent/vm/jruby_vm.rb +2 -2
  349. data/lib/new_relic/agent/vm/monotonic_gc_profiler.rb +4 -4
  350. data/lib/new_relic/agent/vm/mri_vm.rb +54 -26
  351. data/lib/new_relic/agent/vm/snapshot.rb +6 -6
  352. data/lib/new_relic/agent/vm.rb +2 -2
  353. data/lib/new_relic/agent/worker_loop.rb +11 -13
  354. data/lib/new_relic/agent.rb +159 -109
  355. data/lib/new_relic/cli/command.rb +22 -24
  356. data/lib/new_relic/cli/commands/deployments.rb +101 -51
  357. data/lib/new_relic/cli/commands/install.rb +33 -35
  358. data/lib/new_relic/coerce.rb +19 -15
  359. data/lib/new_relic/collection_helper.rb +51 -49
  360. data/lib/new_relic/constants.rb +38 -0
  361. data/lib/new_relic/control/class_methods.rb +6 -6
  362. data/lib/new_relic/control/frameworks/external.rb +3 -3
  363. data/lib/new_relic/control/frameworks/rails.rb +50 -32
  364. data/lib/new_relic/control/frameworks/rails3.rb +4 -5
  365. data/lib/new_relic/control/frameworks/rails4.rb +2 -2
  366. data/lib/new_relic/control/frameworks/rails_notifications.rb +2 -2
  367. data/lib/new_relic/control/frameworks/ruby.rb +4 -4
  368. data/lib/new_relic/control/frameworks/sinatra.rb +8 -2
  369. data/lib/new_relic/control/frameworks.rb +2 -2
  370. data/lib/new_relic/control/instance_methods.rb +28 -46
  371. data/lib/new_relic/control/instrumentation.rb +26 -12
  372. data/lib/new_relic/control/private_instance_methods.rb +48 -0
  373. data/lib/new_relic/control/server_methods.rb +4 -5
  374. data/lib/new_relic/control.rb +2 -3
  375. data/lib/new_relic/delayed_job_injection.rb +2 -2
  376. data/lib/new_relic/dependency_detection.rb +138 -31
  377. data/lib/new_relic/environment_report.rb +42 -36
  378. data/lib/new_relic/helper.rb +50 -8
  379. data/lib/new_relic/language_support.rb +31 -7
  380. data/lib/new_relic/latest_changes.rb +11 -10
  381. data/lib/new_relic/local_environment.rb +23 -27
  382. data/lib/new_relic/metric_data.rb +32 -27
  383. data/lib/new_relic/metric_spec.rb +9 -7
  384. data/lib/new_relic/noticed_error.rb +58 -47
  385. data/lib/new_relic/rack/agent_hooks.rb +2 -2
  386. data/lib/new_relic/rack/agent_middleware.rb +6 -4
  387. data/lib/new_relic/rack/browser_monitoring.rb +136 -117
  388. data/lib/new_relic/rack.rb +2 -2
  389. data/lib/new_relic/recipes/capistrano3.rb +5 -63
  390. data/lib/new_relic/recipes/capistrano_legacy.rb +25 -28
  391. data/lib/new_relic/recipes/helpers/send_deployment.rb +70 -0
  392. data/lib/new_relic/recipes.rb +2 -2
  393. data/lib/new_relic/supportability_helper.rb +23 -7
  394. data/lib/new_relic/traced_thread.rb +39 -0
  395. data/lib/new_relic/version.rb +7 -18
  396. data/lib/newrelic_rpm.rb +21 -34
  397. data/lib/sequel/extensions/{newrelic_instrumentation.rb → new_relic_instrumentation.rb} +18 -21
  398. data/lib/sequel/plugins/{newrelic_instrumentation.rb → new_relic_instrumentation.rb} +10 -16
  399. data/lib/tasks/all.rb +4 -4
  400. data/lib/tasks/config.rake +24 -119
  401. data/lib/tasks/coverage_report.rake +28 -0
  402. data/lib/tasks/helpers/config.html.erb +21 -0
  403. data/lib/tasks/helpers/format.rb +123 -0
  404. data/lib/tasks/helpers/matches.rb +12 -0
  405. data/lib/tasks/helpers/prompt.rb +24 -0
  406. data/lib/tasks/helpers/removers.rb +33 -0
  407. data/lib/tasks/install.rake +8 -4
  408. data/lib/tasks/instrumentation_generator/README.md +63 -0
  409. data/lib/tasks/instrumentation_generator/TODO.md +33 -0
  410. data/lib/tasks/instrumentation_generator/instrumentation.thor +121 -0
  411. data/lib/tasks/instrumentation_generator/templates/Envfile.tt +9 -0
  412. data/lib/tasks/instrumentation_generator/templates/chain.tt +22 -0
  413. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +8 -0
  414. data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +29 -0
  415. data/lib/tasks/instrumentation_generator/templates/instrumentation.tt +13 -0
  416. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +3 -0
  417. data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +19 -0
  418. data/lib/tasks/instrumentation_generator/templates/prepend.tt +13 -0
  419. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +3 -0
  420. data/lib/tasks/instrumentation_generator/templates/test.tt +15 -0
  421. data/lib/tasks/multiverse.rake +4 -0
  422. data/lib/tasks/multiverse.rb +23 -9
  423. data/lib/tasks/newrelic.rb +3 -2
  424. data/lib/tasks/tests.rake +17 -17
  425. data/newrelic.yml +672 -3
  426. data/newrelic_rpm.gemspec +46 -39
  427. data/recipes/newrelic.rb +3 -3
  428. data/test/agent_helper.rb +340 -110
  429. metadata +272 -97
  430. data/.travis.yml +0 -210
  431. data/bin/mongrel_rpm +0 -33
  432. data/cert/cacert.pem +0 -1177
  433. data/lib/new_relic/agent/cross_app_monitor.rb +0 -110
  434. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +0 -44
  435. data/lib/new_relic/agent/datastores/mongo/statement_formatter.rb +0 -53
  436. data/lib/new_relic/agent/distributed_trace_intrinsics.rb +0 -90
  437. data/lib/new_relic/agent/distributed_trace_metrics.rb +0 -74
  438. data/lib/new_relic/agent/distributed_trace_monitor.rb +0 -30
  439. data/lib/new_relic/agent/distributed_trace_payload.rb +0 -175
  440. data/lib/new_relic/agent/distributed_trace_transport_type.rb +0 -43
  441. data/lib/new_relic/agent/http_clients/abstract_request.rb +0 -31
  442. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +0 -74
  443. data/lib/new_relic/agent/instrumentation/authlogic.rb +0 -25
  444. data/lib/new_relic/agent/instrumentation/data_mapper.rb +0 -202
  445. data/lib/new_relic/agent/instrumentation/excon/connection.rb +0 -46
  446. data/lib/new_relic/agent/instrumentation/http.rb +0 -46
  447. data/lib/new_relic/agent/instrumentation/merb/controller.rb +0 -44
  448. data/lib/new_relic/agent/instrumentation/merb/errors.rb +0 -33
  449. data/lib/new_relic/agent/instrumentation/net.rb +0 -50
  450. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +0 -125
  451. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +0 -46
  452. data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +0 -26
  453. data/lib/new_relic/agent/instrumentation/sunspot.rb +0 -33
  454. data/lib/new_relic/agent/range_extensions.rb +0 -47
  455. data/lib/new_relic/agent/supported_versions.rb +0 -275
  456. data/lib/new_relic/agent/trace_context.rb +0 -244
  457. data/lib/new_relic/agent/trace_context_payload.rb +0 -134
  458. data/lib/new_relic/agent/trace_context_request_monitor.rb +0 -42
  459. data/lib/new_relic/build.rb +0 -2
  460. data/lib/new_relic/control/frameworks/merb.rb +0 -29
  461. data/lib/new_relic/metrics.rb +0 -13
  462. data/lib/tasks/config.html.erb +0 -32
  463. data/true +0 -0
  464. /data/lib/tasks/{config.text.erb → helpers/config.text.erb} +0 -0
data/test/agent_helper.rb CHANGED
@@ -1,26 +1,36 @@
1
- # encoding: utf-8
2
1
  # This file is distributed under New Relic's license terms.
3
- # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
4
 
5
5
  # These helpers should not have any gem dependencies except on newrelic_rpm
6
6
  # itself, and should be usable from within any multiverse suite.
7
7
 
8
8
  require 'json'
9
+ require 'net/http'
10
+ begin
11
+ require 'net/http/status'
12
+ rescue LoadError
13
+ # NOP -- Net::HTTP::STATUS_CODES was introduced in Ruby 2.5
14
+ end
9
15
 
10
16
  class ArrayLogDevice
11
- def initialize( array=[] )
17
+ def initialize(array = [])
12
18
  @array = array
13
19
  end
14
20
  attr_reader :array
15
21
 
16
- def write( message )
22
+ def write(message)
17
23
  @array << message
18
24
  end
19
25
 
20
26
  def close; end
21
27
  end
22
28
 
23
- def assert_between(floor, ceiling, value, message="expected #{floor} <= #{value} <= #{ceiling}")
29
+ def fake_guid(length = 16)
30
+ NewRelic::Agent::GuidGenerator.generate_guid(length)
31
+ end
32
+
33
+ def assert_between(floor, ceiling, value, message = "expected #{floor} <= #{value} <= #{ceiling}")
24
34
  assert((floor <= value && value <= ceiling), message)
25
35
  end
26
36
 
@@ -38,8 +48,8 @@ end
38
48
 
39
49
  def assert_has_traced_error(error_class)
40
50
  errors = harvest_error_traces!
41
- assert \
42
- errors.find {|e| e.exception_class_name == error_class.name} != nil, \
51
+
52
+ refute_nil errors.find { |e| e.exception_class_name == error_class.name }, \
43
53
  "Didn't find error of class #{error_class}"
44
54
  end
45
55
 
@@ -55,6 +65,14 @@ def last_transaction_event
55
65
  harvest_transaction_events!.last.last
56
66
  end
57
67
 
68
+ def harvest_span_events!
69
+ NewRelic::Agent.instance.span_event_aggregator.harvest!
70
+ end
71
+
72
+ def last_span_event
73
+ harvest_span_events!.last.last
74
+ end
75
+
58
76
  def harvest_error_events!
59
77
  NewRelic::Agent.instance.error_collector.error_event_aggregator.harvest!
60
78
  end
@@ -63,29 +81,25 @@ def last_error_event
63
81
  harvest_error_events!.last.last
64
82
  end
65
83
 
66
- unless defined?( assert_block )
67
- def assert_block(*msgs)
68
- assert yield, *msgs
69
- end
70
- end
71
-
72
- unless defined?( assert_includes )
73
- def assert_includes( collection, member, msg=nil )
84
+ unless defined? assert_includes
85
+ def assert_includes(collection, member, msg = nil)
74
86
  msg = "Expected #{collection.inspect} to include #{member.inspect}"
75
- assert_block( msg ) { collection.include?(member) }
87
+
88
+ assert_includes collection, member, msg
76
89
  end
77
90
  end
78
91
 
79
- unless defined?( assert_not_includes )
80
- def assert_not_includes( collection, member, msg=nil )
92
+ unless defined? assert_not_includes
93
+ def assert_not_includes(collection, member, msg = nil)
81
94
  msg = "Expected #{collection.inspect} not to include #{member.inspect}"
82
- assert !collection.include?(member), msg
95
+
96
+ refute_includes collection, member, msg
83
97
  end
84
98
  end
85
99
 
86
- unless defined?( assert_empty )
87
- def assert_empty(collection, msg=nil)
88
- assert collection.empty?, msg
100
+ unless defined? assert_empty
101
+ def assert_empty(collection, msg = nil)
102
+ assert_empty collection, msg
89
103
  end
90
104
  end
91
105
 
@@ -94,6 +108,13 @@ def assert_equal_unordered(left, right)
94
108
  left.each { |element| assert_includes(right, element) }
95
109
  end
96
110
 
111
+ def assert_log_contains(log, message)
112
+ lines = log.array
113
+
114
+ assert (lines.any? { |line| line.match(message) }),
115
+ "Could not find message. Log contained: #{lines.join("\n")}"
116
+ end
117
+
97
118
  def assert_audit_log_contains(audit_log_contents, needle)
98
119
  # Original request bodies dumped to the log have symbol keys, but once
99
120
  # they go through a dump/load, they're strings again, so we strip
@@ -101,7 +122,8 @@ def assert_audit_log_contains(audit_log_contents, needle)
101
122
  regex = /[:"]/
102
123
  needle = needle.gsub(regex, '')
103
124
  haystack = audit_log_contents.gsub(regex, '')
104
- assert(haystack.include?(needle), "Expected log to contain '#{needle}'")
125
+
126
+ assert_includes(haystack, needle, "Expected log to contain '#{needle}'")
105
127
  end
106
128
 
107
129
  # Because we don't generate a strictly machine-readable representation of
@@ -115,30 +137,33 @@ end
115
137
  def assert_audit_log_contains_object(audit_log_contents, o, format = :json)
116
138
  case o
117
139
  when Hash
118
- o.each do |k,v|
140
+ o.each do |k, v|
119
141
  assert_audit_log_contains_object(audit_log_contents, v, format)
120
142
  assert_audit_log_contains_object(audit_log_contents, k, format)
121
143
  end
122
144
  when Array
145
+
123
146
  o.each do |el|
124
147
  assert_audit_log_contains_object(audit_log_contents, el, format)
125
148
  end
126
149
  when NilClass
127
- assert_audit_log_contains(audit_log_contents, format == :json ? "null" : "nil")
150
+
151
+ assert_audit_log_contains(audit_log_contents, format == :json ? 'null' : 'nil')
128
152
  else
129
153
  assert_audit_log_contains(audit_log_contents, o.inspect)
130
154
  end
131
155
  end
132
156
 
133
157
  def compare_metrics(expected, actual)
134
- actual.delete_if {|a| a.include?('GC/Transaction/') }
158
+ actual.delete_if { |a| a.include?('GC/Transaction/') }
159
+
135
160
  assert_equal(expected.to_a.sort, actual.to_a.sort, "extra: #{(actual - expected).to_a.inspect}; missing: #{(expected - actual).to_a.inspect}")
136
161
  end
137
162
 
138
163
  def metric_spec_from_specish(specish)
139
164
  spec = case specish
140
165
  when String then NewRelic::MetricSpec.new(specish)
141
- when Array then NewRelic::MetricSpec.new(*specish)
166
+ when Array then NewRelic::MetricSpec.new(*specish)
142
167
  end
143
168
  spec
144
169
  end
@@ -148,17 +173,17 @@ def _normalize_metric_expectations(expectations)
148
173
  when Array
149
174
  hash = {}
150
175
  # Just assert that the metric is present, nothing about the attributes
151
- expectations.each { |k| hash[k] = { } }
176
+ expectations.each { |k| hash[k] = {} }
152
177
  hash
153
178
  when String
154
- { expectations => {} }
179
+ {expectations => {}}
155
180
  else
156
181
  expectations
157
182
  end
158
183
  end
159
184
 
160
185
  def dump_stats(stats)
161
- str = " Call count: #{stats.call_count}\n"
186
+ str = +" Call count: #{stats.call_count}\n"
162
187
  str << " Total call time: #{stats.total_call_time}\n"
163
188
  str << " Total exclusive time: #{stats.total_exclusive_time}\n"
164
189
  str << " Min call time: #{stats.min_call_time}\n"
@@ -173,16 +198,31 @@ end
173
198
  def assert_stats_has_values(stats, expected_spec, expected_attrs)
174
199
  expected_attrs.each do |attr, expected_value|
175
200
  actual_value = stats.send(attr)
201
+
202
+ msg = "Expected #{attr} for #{expected_spec} to be #{'~' unless attr == :call_count}#{expected_value}, " \
203
+ "got #{actual_value}.\nActual stats:\n#{dump_stats(stats)}"
204
+
176
205
  if attr == :call_count
177
- assert_equal(expected_value, actual_value,
178
- "Expected #{attr} for #{expected_spec} to be #{expected_value}, got #{actual_value}.\nActual stats:\n#{dump_stats(stats)}")
206
+ assert_stats_has_values_with_call_count(expected_value, actual_value, msg)
179
207
  else
180
- assert_in_delta(expected_value, actual_value, 0.0001,
181
- "Expected #{attr} for #{expected_spec} to be ~#{expected_value}, got #{actual_value}.\nActual stats:\n#{dump_stats(stats)}")
208
+ assert_in_delta(expected_value, actual_value, 0.0001, msg)
182
209
  end
183
210
  end
184
211
  end
185
212
 
213
+ def assert_stats_has_values_with_call_count(expected_value, actual_value, msg)
214
+ # >, <, >=, <= comparisons
215
+ if expected_value.to_s =~ /([<>]=?)\s*(\d+)/
216
+ operator = Regexp.last_match(1).to_sym
217
+ count = Regexp.last_match(2).to_i
218
+
219
+ assert_operator(actual_value, operator, count, msg)
220
+ # == comparison
221
+ else
222
+ assert_equal(expected_value, actual_value, msg)
223
+ end
224
+ end
225
+
186
226
  def assert_metrics_recorded(expected)
187
227
  expected = _normalize_metric_expectations(expected)
188
228
  expected.each do |specish, expected_attrs|
@@ -199,6 +239,7 @@ def assert_metrics_recorded(expected)
199
239
 
200
240
  assert(actual_stats, msg)
201
241
  end
242
+
202
243
  assert_stats_has_values(actual_stats, expected_spec, expected_attrs)
203
244
  end
204
245
  end
@@ -214,8 +255,9 @@ end
214
255
  # the :ignore_filter option. This will allow you to specify a Regex that
215
256
  # allowlists broad swathes of metric territory (e.g. 'Supportability/').
216
257
  #
217
- def assert_metrics_recorded_exclusive(expected, options={})
258
+ def assert_metrics_recorded_exclusive(expected, options = {})
218
259
  expected = _normalize_metric_expectations(expected)
260
+
219
261
  assert_metrics_recorded(expected)
220
262
 
221
263
  recorded_metrics = NewRelic::Agent.instance.stats_engine.to_h.keys
@@ -227,14 +269,23 @@ def assert_metrics_recorded_exclusive(expected, options={})
227
269
  recorded_metrics.reject! { |m| m.name.match(options[:ignore_filter]) }
228
270
  end
229
271
 
230
- expected_metrics = expected.keys.map { |s| metric_spec_from_specish(s) }
272
+ expected_metrics = expected.keys.map { |s| metric_spec_from_specish(s) }
231
273
 
232
274
  unexpected_metrics = recorded_metrics - expected_metrics
233
- unexpected_metrics.reject! { |m| m.name =~ /GC\/Transaction/ }
275
+ unexpected_metrics.reject! { |m| m.name.include?('GC/Transaction') }
234
276
 
235
277
  assert_equal(0, unexpected_metrics.size, "Found unexpected metrics: #{format_metric_spec_list(unexpected_metrics)}")
236
278
  end
237
279
 
280
+ def assert_newrelic_metadata_present(metadata)
281
+ assert metadata.key?('newrelic')
282
+ refute_nil metadata['newrelic']
283
+ end
284
+
285
+ def assert_distributed_tracing_payload_created_for_transaction(transaction)
286
+ assert transaction.distributed_tracer.instance_variable_get(:@distributed_trace_payload_created)
287
+ end
288
+
238
289
  # The clear_metrics! method prevents metrics from "leaking" between tests by resetting
239
290
  # the @stats_hash instance variable in the current instance of NewRelic::Agent::StatsEngine.
240
291
 
@@ -261,7 +312,8 @@ def assert_metrics_not_recorded(not_expected)
261
312
  found_but_not_expected << spec
262
313
  end
263
314
  end
264
- assert_equal([], found_but_not_expected, "Found unexpected metrics: #{format_metric_spec_list(found_but_not_expected)}")
315
+
316
+ assert_empty(found_but_not_expected, "Found unexpected metrics: #{format_metric_spec_list(found_but_not_expected)}")
265
317
  end
266
318
 
267
319
  alias :refute_metrics_recorded :assert_metrics_not_recorded
@@ -269,13 +321,12 @@ alias :refute_metrics_recorded :assert_metrics_not_recorded
269
321
  def assert_no_metrics_match(regex)
270
322
  matching_metrics = []
271
323
  NewRelic::Agent.instance.stats_engine.to_h.keys.map(&:to_s).each do |metric|
272
- matching_metrics << metric if metric.match regex
324
+ matching_metrics << metric if metric.match(regex)
273
325
  end
274
326
 
275
- assert_equal(
276
- [],
327
+ assert_empty(
277
328
  matching_metrics,
278
- "Found unexpected metrics:\n" + matching_metrics.map { |m| " '#{m}'"}.join("\n") + "\n\n"
329
+ "Found unexpected metrics:\n" + matching_metrics.map { |m| " '#{m}'" }.join("\n") + "\n\n"
279
330
  )
280
331
  end
281
332
 
@@ -290,21 +341,23 @@ end
290
341
 
291
342
  def assert_truthy(expected, msg = nil)
292
343
  msg ||= "Expected #{expected.inspect} to be truthy"
293
- assert !!expected, msg
344
+
345
+ refute !expected, msg
294
346
  end
295
347
 
296
348
  def assert_falsy(expected, msg = nil)
297
349
  msg ||= "Expected #{expected.inspect} to be falsy"
298
- assert !expected, msg
350
+
351
+ refute expected, msg
299
352
  end
300
353
 
301
- unless defined?( assert_false )
354
+ unless defined? assert_false
302
355
  def assert_false(expected)
303
- assert_equal false, expected
356
+ refute expected
304
357
  end
305
358
  end
306
359
 
307
- unless defined?(refute)
360
+ unless defined? refute
308
361
  alias refute assert_false
309
362
  end
310
363
 
@@ -327,30 +380,67 @@ end
327
380
  # in_transaction('foobar', :category => :controller) { ... }
328
381
  #
329
382
  def in_transaction(*args, &blk)
330
- opts = (args.last && args.last.is_a?(Hash)) ? args.pop : {}
331
- category = (opts && opts.delete(:category)) || :other
383
+ opts = args.last&.is_a?(Hash) ? args.pop : {}
384
+ category = (opts&.delete(:category)) || :other
332
385
 
333
386
  # At least one test passes `:transaction_name => nil`, so handle it gently
334
- name = opts.key?(:transaction_name) ? opts.delete(:transaction_name) :
335
- args.first || 'dummy'
387
+ name = opts.key?(:transaction_name) ? opts.delete(:transaction_name) : args.first || 'dummy'
336
388
 
337
389
  state = NewRelic::Agent::Tracer.state
338
390
  txn = nil
339
391
 
340
392
  NewRelic::Agent::Tracer.in_transaction(name: name, category: category, options: opts) do
341
393
  txn = state.current_transaction
342
- yield state.current_transaction
394
+ yield(state.current_transaction)
343
395
  end
344
396
 
345
397
  txn
346
398
  end
347
399
 
400
+ # Temporarily disables default transformer so tests with invalid inputs can be tried
401
+ def with_disabled_defaults_transformer(key)
402
+ begin
403
+ transformer = NewRelic::Agent::Configuration::DEFAULTS[key][:transform]
404
+ NewRelic::Agent::Configuration::DEFAULTS[key][:transform] = nil
405
+ yield
406
+ ensure
407
+ NewRelic::Agent::Configuration::DEFAULTS[key][:transform] = transformer
408
+ end
409
+ end
410
+
348
411
  # Convenience wrapper to stand up a transaction and provide a segment within
349
- # that transaction to work with. The same arguements as provided to in_transaction
412
+ # that transaction to work with. The same arguments as provided to in_transaction
350
413
  # may be supplied.
351
- def with_segment *args, &blk
352
- in_transaction *args do |txn|
353
- yield txn.current_segment, txn
414
+ def with_segment(*args, &blk)
415
+ segment = nil
416
+ txn = in_transaction(*args) do |t|
417
+ segment = t.current_segment
418
+ yield(segment, t)
419
+ end
420
+ [segment, txn]
421
+ end
422
+
423
+ # building error attributes on segments are deferred until it's time
424
+ # to publish/harvest them as spans, so for testing, we'll explicitly
425
+ # build 'em as appropriate so we can test 'em
426
+ def build_deferred_error_attributes(segment)
427
+ return unless segment.noticed_error
428
+ return if segment.noticed_error_attributes.frozen?
429
+
430
+ segment.noticed_error.build_error_attributes
431
+ end
432
+
433
+ def capture_segment_with_error
434
+ begin
435
+ segment_with_error = nil
436
+ with_segment do |segment|
437
+ segment_with_error = segment
438
+ raise 'oops!'
439
+ end
440
+ rescue Exception => exception
441
+ assert segment_with_error, 'expected to have a segment_with_error'
442
+ build_deferred_error_attributes(segment_with_error)
443
+ return segment_with_error, exception
354
444
  end
355
445
  end
356
446
 
@@ -360,15 +450,15 @@ end
360
450
 
361
451
  # Convenience wrapper around in_transaction that sets the category so that it
362
452
  # looks like we are in a web transaction
363
- def in_web_transaction(name='dummy')
453
+ def in_web_transaction(name = 'dummy')
364
454
  in_transaction(name, :category => :controller, :request => stub(:path => '/')) do |txn|
365
- yield txn
455
+ yield(txn)
366
456
  end
367
457
  end
368
458
 
369
- def in_background_transaction(name='silly')
459
+ def in_background_transaction(name = 'silly')
370
460
  in_transaction(name, :category => :task) do |txn|
371
- yield txn
461
+ yield(txn)
372
462
  end
373
463
  end
374
464
 
@@ -380,13 +470,14 @@ end
380
470
 
381
471
  def last_transaction_trace
382
472
  return unless last_sample = NewRelic::Agent.agent.transaction_sampler.last_sample
473
+
383
474
  NewRelic::Agent::Transaction::TraceBuilder.build_trace(last_sample)
384
475
  end
385
476
 
386
477
  def last_transaction_trace_request_params
387
478
  agent_attributes = attributes_for(last_transaction_trace, :agent)
388
479
  agent_attributes.inject({}) do |memo, (key, value)|
389
- memo[key] = value if key.to_s.start_with?("request.parameters.")
480
+ memo[key] = value if key.to_s.start_with?('request.parameters.')
390
481
  memo
391
482
  end
392
483
  end
@@ -401,7 +492,7 @@ def last_sql_trace
401
492
  NewRelic::Agent.agent.sql_sampler.sql_traces.values.last
402
493
  end
403
494
 
404
- def find_last_transaction_node(transaction_sample=nil)
495
+ def find_last_transaction_node(transaction_sample = nil)
405
496
  if transaction_sample
406
497
  root_node = transaction_sample.root_node
407
498
  else
@@ -409,7 +500,7 @@ def find_last_transaction_node(transaction_sample=nil)
409
500
  end
410
501
 
411
502
  last_node = nil
412
- root_node.each_node {|s| last_node = s }
503
+ root_node.each_node { |s| last_node = s }
413
504
 
414
505
  return last_node
415
506
  end
@@ -426,7 +517,7 @@ end
426
517
 
427
518
  def find_node_with_name_matching(transaction_sample, regex)
428
519
  transaction_sample.root_node.each_node do |node|
429
- if node.metric_name.match regex
520
+ if node.metric_name.match(regex)
430
521
  return node
431
522
  end
432
523
  end
@@ -440,7 +531,7 @@ def find_all_nodes_with_name_matching(transaction_sample, regexes)
440
531
 
441
532
  transaction_sample.root_node.each_node do |node|
442
533
  regexes.each do |regex|
443
- if node.metric_name.match regex
534
+ if node.metric_name.match(regex)
444
535
  matching_nodes << node
445
536
  end
446
537
  end
@@ -449,7 +540,7 @@ def find_all_nodes_with_name_matching(transaction_sample, regexes)
449
540
  matching_nodes
450
541
  end
451
542
 
452
- def with_config(config_hash, at_start=true)
543
+ def with_config(config_hash, at_start = true)
453
544
  config = NewRelic::Agent::Configuration::DottedHash.new(config_hash, true)
454
545
  NewRelic::Agent.config.add_config_for_testing(config, at_start)
455
546
  NewRelic::Agent.instance.refresh_attribute_filter
@@ -461,8 +552,8 @@ def with_config(config_hash, at_start=true)
461
552
  end
462
553
  end
463
554
 
464
- def with_server_source config_hash, at_start=true
465
- with_config config_hash, at_start do
555
+ def with_server_source(config_hash, at_start = true)
556
+ with_config(config_hash, at_start) do
466
557
  NewRelic::Agent.config.notify_server_source_added
467
558
  yield
468
559
  end
@@ -500,7 +591,7 @@ unless Time.respond_to?(:__original_now)
500
591
  end
501
592
  end
502
593
 
503
- def nr_freeze_time(now=Time.now)
594
+ def nr_freeze_time(now = Time.now)
504
595
  Time.__frozen_now = now
505
596
  end
506
597
 
@@ -512,7 +603,32 @@ def advance_time(seconds)
512
603
  Time.__frozen_now = Time.now + seconds
513
604
  end
514
605
 
515
- def with_constant_defined(constant_symbol, implementation=Module.new)
606
+ unless Process.respond_to?(:__original_clock_gettime)
607
+ Process.instance_eval do
608
+ class << self
609
+ attr_accessor :__frozen_clock_gettime
610
+ alias_method :__original_clock_gettime, :clock_gettime
611
+
612
+ def clock_gettime(clock_id, unit = :float_second)
613
+ __frozen_clock_gettime || __original_clock_gettime(clock_id, unit)
614
+ end
615
+ end
616
+ end
617
+ end
618
+
619
+ def advance_process_time(seconds, clock_id = Process::CLOCK_REALTIME)
620
+ Process.__frozen_clock_gettime = Process.clock_gettime(clock_id) + seconds
621
+ end
622
+
623
+ def nr_freeze_process_time(now = Process.clock_gettime(Process::CLOCK_REALTIME))
624
+ Process.__frozen_clock_gettime = now
625
+ end
626
+
627
+ def nr_unfreeze_process_time
628
+ Process.__frozen_clock_gettime = nil
629
+ end
630
+
631
+ def with_constant_defined(constant_symbol, implementation = Module.new)
516
632
  const_path = constant_path(constant_symbol.to_s)
517
633
 
518
634
  if const_path
@@ -532,7 +648,7 @@ def with_constant_defined(constant_symbol, implementation=Module.new)
532
648
  end
533
649
  end
534
650
 
535
- def constant_path(name, opts={})
651
+ def constant_path(name, opts = {})
536
652
  allow_partial = opts[:allow_partial]
537
653
  path = [Object]
538
654
  parts = name.gsub(/^::/, '').split('::')
@@ -540,6 +656,7 @@ def constant_path(name, opts={})
540
656
  if !path.last.constants.include?(part.to_sym)
541
657
  return allow_partial ? path : nil
542
658
  end
659
+
543
660
  path << path.last.const_get(part)
544
661
  end
545
662
  path
@@ -555,7 +672,8 @@ def undefine_constant(constant_symbol)
555
672
  const_str = constant_symbol.to_s
556
673
  parent = get_parent(const_str)
557
674
  const_name = const_str.gsub(/.*::/, '')
558
- return yield unless parent && parent.constants.include?(const_name.to_sym)
675
+ return yield unless parent&.constants&.include?(const_name.to_sym)
676
+
559
677
  removed_constant = parent.send(:remove_const, const_name)
560
678
  yield
561
679
  ensure
@@ -566,7 +684,7 @@ def with_debug_logging
566
684
  orig_logger = NewRelic::Agent.logger
567
685
  $stderr.puts '', '---', ''
568
686
  NewRelic::Agent.logger =
569
- NewRelic::Agent::AgentLogger.new('', Logger.new($stderr) )
687
+ NewRelic::Agent::AgentLogger.new('', Logger.new($stderr))
570
688
 
571
689
  with_config(:log_level => 'debug') do
572
690
  yield
@@ -576,17 +694,17 @@ ensure
576
694
  end
577
695
 
578
696
  def create_agent_command(args = {})
579
- NewRelic::Agent::Commands::AgentCommand.new([-1, { "name" => "command_name", "arguments" => args}])
697
+ NewRelic::Agent::Commands::AgentCommand.new([-1, {'name' => 'command_name', 'arguments' => args}])
580
698
  end
581
699
 
582
- def wait_for_backtrace_service_poll(opts={})
700
+ def wait_for_backtrace_service_poll(opts = {})
583
701
  defaults = {
584
702
  :timeout => 10.0,
585
- :service => NewRelic::Agent.agent.agent_command_router.backtrace_service,
703
+ :service => NewRelic::Agent.agent.instance_variable_get(:@agent_command_router).backtrace_service,
586
704
  :iterations => 1
587
705
  }
588
706
  opts = defaults.merge(opts)
589
- deadline = Time.now + opts[:timeout]
707
+ deadline = Process.clock_gettime(Process::CLOCK_REALTIME) + opts[:timeout]
590
708
 
591
709
  service = opts[:service]
592
710
  worker_loop = service.worker_loop
@@ -594,25 +712,25 @@ def wait_for_backtrace_service_poll(opts={})
594
712
 
595
713
  until worker_loop.iterations > opts[:iterations]
596
714
  sleep(0.01)
597
- if Time.now > deadline
715
+ if Process.clock_gettime(Process::CLOCK_REALTIME) > deadline
598
716
  raise "Timed out waiting #{opts[:timeout]} s for backtrace service poll\n" +
599
- "Worker loop ran for #{opts[:service].worker_loop.iterations} iterations\n\n" +
600
- Thread.list.map { |t|
601
- "#{t.to_s}: newrelic_label: #{t[:newrelic_label].inspect}\n\n" +
602
- (t.backtrace || []).join("\n\t")
603
- }.join("\n\n")
717
+ "Worker loop ran for #{opts[:service].worker_loop.iterations} iterations\n\n" +
718
+ Thread.list.map { |t|
719
+ "#{t.to_s}: newrelic_label: #{t[:newrelic_label].inspect}\n\n" +
720
+ (t.backtrace || []).join("\n\t")
721
+ }.join("\n\n")
604
722
  end
605
723
  end
606
724
  end
607
725
 
608
- def with_array_logger(level=:info)
726
+ def with_array_logger(level = :info)
609
727
  orig_logger = NewRelic::Agent.logger
610
- config = { :log_level => level }
728
+ config = {:log_level => level}
611
729
  logdev = ArrayLogDevice.new
612
730
  override_logger = Logger.new(logdev)
613
731
 
614
732
  with_config(config) do
615
- NewRelic::Agent.logger = NewRelic::Agent::AgentLogger.new("", override_logger)
733
+ NewRelic::Agent.logger = NewRelic::Agent::AgentLogger.new('', override_logger)
616
734
  yield
617
735
  end
618
736
 
@@ -627,7 +745,7 @@ end
627
745
  # a core bug in the JVM implementation of Ruby. Root cause was not
628
746
  # discovered, but it was found that a combination of retrying and using
629
747
  # mutex lock around the update operation was the only consistently working
630
- # solution as the error continued to surface without the mutex and
748
+ # solution as the error continued to surface without the mutex and
631
749
  # retry alone wasn't enough, either.
632
750
  #
633
751
  # JRUBY: oraclejdk8 + jruby-9.2.6.0
@@ -640,9 +758,9 @@ class EnvUpdater
640
758
  @mutex = Mutex.new
641
759
  end
642
760
 
643
- # Will attempt the given block up to MAX_RETRIES before
761
+ # Will attempt the given block up to MAX_RETRIES before
644
762
  # surfacing the exception down the chain.
645
- def with_retry retry_limit=MAX_RETRIES
763
+ def with_retry(retry_limit = MAX_RETRIES)
646
764
  retries ||= 0
647
765
  sleep(retries)
648
766
  yield
@@ -651,19 +769,19 @@ class EnvUpdater
651
769
  end
652
770
 
653
771
  # Locks and updates the ENV
654
- def safe_update env
772
+ def safe_update(env)
655
773
  with_retry do
656
774
  @mutex.synchronize do
657
- env.each{ |key, val| ENV[key] = val.to_s }
775
+ env.each { |key, val| ENV[key] = val.to_s }
658
776
  end
659
777
  end
660
778
  end
661
779
 
662
780
  # Locks and restores the ENV
663
- def safe_restore old_env
781
+ def safe_restore(old_env)
664
782
  with_retry do
665
783
  @mutex.synchronize do
666
- old_env.each{ |key, val| val ? ENV[key] = val : ENV.delete(key) }
784
+ old_env.each { |key, val| val ? ENV[key] = val : ENV.delete(key) }
667
785
  end
668
786
  end
669
787
  end
@@ -673,32 +791,32 @@ class EnvUpdater
673
791
  @@instance ||= EnvUpdater.new
674
792
  end
675
793
 
676
- def self.safe_update env
677
- instance.safe_update env
794
+ def self.safe_update(env)
795
+ instance.safe_update(env)
678
796
  end
679
797
 
680
- def self.safe_restore old_env
681
- instance.safe_restore old_env
798
+ def self.safe_restore(old_env)
799
+ instance.safe_restore(old_env)
682
800
  end
683
801
 
684
802
  # Effectively saves current ENV settings for given env's key/values,
685
803
  # runs given block, then restores ENV to original state before returning.
686
- def self.inject env, &block
804
+ def self.inject(env, &block)
687
805
  old_env = {}
688
- env.each{ |key, val| old_env[key] = ENV[key] }
806
+ env.each { |key, val| old_env[key] = ENV[key] }
689
807
  begin
690
808
  safe_update(env)
691
809
  yield
692
810
  ensure
693
811
  safe_restore(old_env)
694
812
  end
695
- end
813
+ end
696
814
 
697
815
  # must call instance here to ensure only one @mutex for all threads.
698
816
  instance
699
817
  end
700
818
 
701
- # Changes ENV settings to given and runs given block and restores ENV
819
+ # Changes ENV settings to given and runs given block and restores ENV
702
820
  # to original values before returning.
703
821
  def with_environment(env, &block)
704
822
  EnvUpdater.inject(env) { yield }
@@ -727,7 +845,7 @@ ensure
727
845
  end
728
846
 
729
847
  def json_dump_and_encode(object)
730
- Base64.encode64(::JSON.dump(object))
848
+ Base64.encode64(JSON.dump(object))
731
849
  end
732
850
 
733
851
  def get_last_analytics_event
@@ -753,15 +871,15 @@ def load_cross_agent_test(name)
753
871
  test_file_path = File.join(cross_agent_tests_dir, "#{name}.json")
754
872
  data = File.read(test_file_path)
755
873
  data.gsub!('callCount', 'call_count')
756
- data = ::JSON.load(data)
757
- data.each { |testcase| testcase['testname'].gsub! ' ', '_' if String === testcase['testname'] }
874
+ data = JSON.load(data)
875
+ data.each { |testcase| testcase['testname'].tr!(' ', '_') if String === testcase['testname'] }
758
876
  data
759
877
  end
760
878
 
761
879
  def each_cross_agent_test(options)
762
- options = {:dir => nil, :pattern => "*"}.update(options)
763
- path = File.join [cross_agent_tests_dir, options[:dir], options[:pattern]].compact
764
- Dir.glob(path).each { |file| yield file}
880
+ options = {:dir => nil, :pattern => '*'}.update(options)
881
+ path = File.join([cross_agent_tests_dir, options[:dir], options[:pattern]].compact)
882
+ Dir.glob(path).each { |file| yield(file) }
765
883
  end
766
884
 
767
885
  def assert_event_attributes(event, test_name, expected_attributes, non_expected_attributes)
@@ -774,7 +892,7 @@ def assert_event_attributes(event, test_name, expected_attributes, non_expected_
774
892
  incorrect_attributes << name unless actual_value == expected_value
775
893
  end
776
894
 
777
- msg = "Found missing or incorrect attribute values in #{test_name}:\n"
895
+ msg = +"Found missing or incorrect attribute values in #{test_name}:\n"
778
896
 
779
897
  incorrect_attributes.each do |name|
780
898
  msg << " #{name}: expected = #{expected_attributes[name].inspect}, actual = #{event_attrs[name].inspect}\n"
@@ -785,13 +903,125 @@ def assert_event_attributes(event, test_name, expected_attributes, non_expected_
785
903
  event_attrs.each do |name, actual_value|
786
904
  msg << " #{name}: #{actual_value.inspect}\n"
787
905
  end
788
- assert(incorrect_attributes.empty?, msg)
906
+
907
+ assert_empty(incorrect_attributes, msg)
789
908
 
790
909
  non_expected_attributes.each do |name|
791
- assert_nil(event_attrs[name], "Found value '#{event_attrs[name]}' for attribute '#{name}', but expected nothing in #{test_name}")
910
+ refute event_attrs[name], "Found value '#{event_attrs[name]}' for attribute '#{name}', but expected nothing in #{test_name}"
792
911
  end
793
912
  end
794
913
 
795
914
  def attributes_for(sample, type)
796
915
  sample.attributes.instance_variable_get("@#{type}_attributes")
797
916
  end
917
+
918
+ def uncache_trusted_account_key
919
+ NewRelic::Agent::Transaction::TraceContext::AccountHelpers.instance_variable_set(:@trace_state_entry_key, nil)
920
+ end
921
+
922
+ def reset_buffers_and_caches
923
+ NewRelic::Agent.drop_buffered_data
924
+ uncache_trusted_account_key
925
+ end
926
+
927
+ def message_for_status_code(code)
928
+ # Net::HTTP::STATUS_CODES was introduced in Ruby 2.5
929
+ if defined?(Net::HTTP::STATUS_CODES)
930
+ return Net::HTTP::STATUS_CODES[code]
931
+ end
932
+
933
+ case code
934
+ when 200 then 'OK'
935
+ when 404 then 'Not Found'
936
+ when 403 then 'Forbidden'
937
+ else 'Unknown'
938
+ end
939
+ end
940
+
941
+ # wraps the given headers in a Net::HTTPResponse which has accompanying
942
+ # http status code associated with it.
943
+ # a "status_code" may be passed in the headers to alter the HTTP Status Code
944
+ # that is wrapped in the response.
945
+ def mock_http_response(headers, wrap_it = true)
946
+ status_code = (headers.delete('status_code') || 200).to_i
947
+ net_http_resp = Net::HTTPResponse.new(1.0, status_code, message_for_status_code(status_code))
948
+ headers.each do |key, value|
949
+ net_http_resp.add_field(key.to_s, value)
950
+ end
951
+ return net_http_resp unless wrap_it
952
+
953
+ NewRelic::Agent::HTTPClients::NetHTTPResponse.new(net_http_resp)
954
+ end
955
+
956
+ # +expected+ can be a string or regular expression
957
+ def assert_match_or_equal(expected, value)
958
+ if expected.is_a?(Regexp)
959
+ assert_match expected, value
960
+ else
961
+ assert_equal expected, value
962
+ end
963
+ end
964
+
965
+ # selects the last segment with a noticed_error and checks
966
+ # the expectations against it.
967
+ def assert_segment_noticed_error(txn, segment_name, error_classes, error_message)
968
+ error_segment = txn.segments.reverse.detect { |s| s.noticed_error }
969
+
970
+ assert error_segment, 'Expected at least one segment with a noticed_error'
971
+
972
+ assert_match_or_equal segment_name, error_segment.name
973
+
974
+ noticed_error = error_segment.noticed_error
975
+
976
+ assert_match_or_equal error_classes, noticed_error.exception_class_name
977
+ assert_match_or_equal error_message, noticed_error.message
978
+ end
979
+
980
+ def assert_transaction_noticed_error(txn, error_classes)
981
+ refute_empty txn.exceptions, 'Expected transaction to notice the error'
982
+ assert_match_or_equal error_classes, txn.exceptions.keys.first.class.name
983
+ end
984
+
985
+ def refute_transaction_noticed_error(txn, error_class)
986
+ error_segment = txn.segments.reverse.detect { |s| s.noticed_error }
987
+
988
+ assert error_segment, 'Expected at least one segment with a noticed_error'
989
+ assert_empty txn.exceptions, 'Expected transaction to NOT notice any segment errors'
990
+ end
991
+
992
+ def refute_raises(*exp)
993
+ msg = "#{exp.pop}.\n" if String === exp.last
994
+
995
+ begin
996
+ yield
997
+ rescue MiniTest::Skip => e
998
+ puts "SKIP REPORTS: #{e.inspect}"
999
+ return e if exp.include?(MiniTest::Skip)
1000
+
1001
+ raise e
1002
+ rescue Exception => e
1003
+ puts "EXCEPTION RAISED: #{e.inspect}\n#{e.backtrace}"
1004
+ exp = exp.first if exp.size == 1
1005
+
1006
+ flunk(msg || "unexpected exception raised: #{e}")
1007
+ end
1008
+ end
1009
+
1010
+ def assert_implements(instance, method, *args)
1011
+ fail_message = "expected #{instance.class}##{method} method to be implemented"
1012
+ refute_raises NotImplementedError, fail_message do
1013
+ instance.send(method, *args)
1014
+ end
1015
+ end
1016
+
1017
+ def defer_testing_to_min_supported_rails(test_file, min_rails_version, supports_jruby = true)
1018
+ if defined?(Rails) &&
1019
+ defined?(Rails::VERSION::STRING) &&
1020
+ (Rails::VERSION::STRING.to_f >= min_rails_version) &&
1021
+ (supports_jruby || !NewRelic::LanguageSupport.jruby?)
1022
+
1023
+ yield
1024
+ else
1025
+ puts "Skipping tests in #{File.basename(test_file)} because Rails >= #{min_rails_version} is unavailable" if ENV['VERBOSE_TEST_OUTPUT']
1026
+ end
1027
+ end