newrelic_rpm 3.6.5.130 → 3.6.6.147

Sign up to get free protection for your applications and to get access to all the features.
Files changed (240) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +27 -3
  3. data/Gemfile +1 -14
  4. data/Rakefile +15 -5
  5. data/config.dot +1 -1
  6. data/lib/new_relic/agent/agent.rb +15 -0
  7. data/lib/new_relic/agent/agent_logger.rb +19 -14
  8. data/lib/new_relic/agent/configuration/defaults.rb +4 -3
  9. data/lib/new_relic/agent/configuration/environment_source.rb +6 -4
  10. data/lib/new_relic/agent/configuration/manager.rb +7 -2
  11. data/lib/new_relic/agent/configuration/mask_defaults.rb +1 -2
  12. data/lib/new_relic/agent/cross_app_monitor.rb +5 -4
  13. data/lib/new_relic/agent/cross_app_tracing.rb +0 -1
  14. data/lib/new_relic/agent/error_collector.rb +30 -1
  15. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +67 -0
  16. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +59 -0
  17. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +12 -0
  18. data/lib/new_relic/agent/instrumentation/active_merchant.rb +3 -3
  19. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +3 -3
  20. data/lib/new_relic/agent/instrumentation/authlogic.rb +3 -3
  21. data/lib/new_relic/agent/instrumentation/curb.rb +179 -0
  22. data/lib/new_relic/agent/instrumentation/data_mapper.rb +3 -3
  23. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +35 -26
  24. data/lib/new_relic/agent/instrumentation/httpclient.rb +46 -0
  25. data/lib/new_relic/agent/instrumentation/merb/controller.rb +3 -3
  26. data/lib/new_relic/agent/instrumentation/puma.rb +23 -0
  27. data/lib/new_relic/agent/instrumentation/rack.rb +40 -0
  28. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +4 -4
  29. data/lib/new_relic/agent/instrumentation/rails/errors.rb +0 -1
  30. data/lib/new_relic/agent/instrumentation/sequel.rb +0 -1
  31. data/lib/new_relic/agent/instrumentation/sunspot.rb +1 -1
  32. data/lib/new_relic/agent/internal_agent_error.rb +18 -0
  33. data/lib/new_relic/agent/new_relic_service.rb +2 -8
  34. data/lib/new_relic/agent/request_sampler.rb +4 -6
  35. data/lib/new_relic/agent/samplers/cpu_sampler.rb +0 -1
  36. data/lib/new_relic/agent/stats.rb +9 -0
  37. data/lib/new_relic/agent/stats_engine/stats_hash.rb +44 -6
  38. data/lib/new_relic/agent/system_info.rb +1 -1
  39. data/lib/new_relic/agent/thread_profiler.rb +6 -6
  40. data/lib/new_relic/agent/transaction.rb +1 -1
  41. data/lib/new_relic/agent/transaction_info.rb +0 -1
  42. data/lib/new_relic/agent/transaction_sample_builder.rb +6 -5
  43. data/lib/new_relic/agent/transaction_sampler.rb +1 -1
  44. data/lib/new_relic/commands/deployments.rb +6 -0
  45. data/lib/new_relic/commands/install.rb +2 -2
  46. data/lib/new_relic/control/frameworks/rails.rb +1 -2
  47. data/lib/new_relic/control/instrumentation.rb +2 -2
  48. data/lib/new_relic/control/server_methods.rb +1 -2
  49. data/lib/new_relic/delayed_job_injection.rb +0 -40
  50. data/lib/new_relic/helper.rb +0 -1
  51. data/lib/new_relic/latest_changes.rb +1 -1
  52. data/lib/new_relic/local_environment.rb +9 -4
  53. data/lib/new_relic/metric_spec.rb +19 -3
  54. data/lib/new_relic/noticed_error.rb +2 -1
  55. data/lib/new_relic/rack/agent_hooks.rb +0 -1
  56. data/lib/new_relic/rack/developer_mode.rb +1 -1
  57. data/lib/new_relic/rack/error_collector.rb +42 -21
  58. data/lib/new_relic/recipes.rb +0 -1
  59. data/lib/new_relic/transaction_analysis.rb +0 -1
  60. data/lib/new_relic/transaction_sample/segment.rb +4 -4
  61. data/lib/new_relic/version.rb +1 -1
  62. data/lib/sequel/extensions/newrelic_instrumentation.rb +6 -7
  63. data/lib/sequel/plugins/newrelic_instrumentation.rb +0 -1
  64. data/lib/tasks/install.rake +2 -2
  65. data/newrelic_rpm.gemspec +11 -1
  66. data/test/active_record_fixtures.rb +2 -2
  67. data/test/agent_helper.rb +46 -3
  68. data/test/config/newrelic.yml +2 -2
  69. data/test/multiverse/.gitignore +2 -0
  70. data/test/multiverse/lib/multiverse/envfile.rb +6 -9
  71. data/test/multiverse/lib/multiverse/environment.rb +0 -1
  72. data/test/multiverse/lib/multiverse/output_collector.rb +43 -11
  73. data/test/multiverse/lib/multiverse/runner.rb +37 -5
  74. data/test/multiverse/lib/multiverse/suite.rb +149 -67
  75. data/test/multiverse/script/run_one +4 -2
  76. data/test/multiverse/script/runner +1 -5
  77. data/test/multiverse/suites/active_record/Envfile +3 -2
  78. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +13 -12
  79. data/test/multiverse/suites/active_record/config/newrelic.yml +0 -3
  80. data/test/multiverse/suites/agent_only/audit_log_test.rb +30 -34
  81. data/test/multiverse/suites/agent_only/before_suite.rb +7 -0
  82. data/test/multiverse/suites/agent_only/config/newrelic.yml +1 -7
  83. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +12 -20
  84. data/test/multiverse/suites/agent_only/http_response_code_test.rb +16 -34
  85. data/test/multiverse/suites/agent_only/key_transactions_test.rb +18 -28
  86. data/test/multiverse/suites/agent_only/logging_test.rb +25 -49
  87. data/test/multiverse/suites/agent_only/marshaling_test.rb +30 -38
  88. data/test/multiverse/suites/agent_only/pipe_manager_test.rb +12 -6
  89. data/test/multiverse/suites/agent_only/rename_rule_test.rb +30 -38
  90. data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +16 -18
  91. data/test/multiverse/suites/agent_only/service_timeout_test.rb +6 -7
  92. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +26 -32
  93. data/test/multiverse/suites/agent_only/ssl_test.rb +10 -14
  94. data/test/multiverse/suites/agent_only/start_up_test.rb +1 -1
  95. data/test/multiverse/suites/agent_only/testing_app.rb +2 -0
  96. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +23 -24
  97. data/test/multiverse/suites/config_file_loading/Envfile +6 -2
  98. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +8 -4
  99. data/test/multiverse/suites/curb/Envfile +19 -0
  100. data/test/multiverse/suites/curb/config/newrelic.yml +19 -0
  101. data/test/multiverse/suites/curb/curb_test.rb +195 -0
  102. data/test/multiverse/suites/datamapper/Envfile +2 -0
  103. data/test/multiverse/suites/datamapper/config/newrelic.yml +0 -2
  104. data/test/multiverse/suites/datamapper/datamapper_test.rb +6 -10
  105. data/test/multiverse/suites/deferred_instrumentation/Envfile +19 -0
  106. data/test/multiverse/suites/deferred_instrumentation/config/newrelic.yml +22 -0
  107. data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +103 -0
  108. data/test/multiverse/suites/excon/config/newrelic.yml +0 -2
  109. data/test/multiverse/suites/excon/excon_test.rb +3 -3
  110. data/test/multiverse/suites/httpclient/Envfile +15 -0
  111. data/test/multiverse/suites/httpclient/config/newrelic.yml +19 -0
  112. data/test/multiverse/suites/httpclient/httpclient_test.rb +70 -0
  113. data/test/multiverse/suites/net_http/config/newrelic.yml +0 -2
  114. data/test/multiverse/suites/net_http/net_http_test.rb +9 -4
  115. data/test/multiverse/suites/padrino/Envfile +2 -0
  116. data/test/multiverse/suites/padrino/config/newrelic.yml +0 -3
  117. data/test/multiverse/suites/padrino/padrino_test.rb +5 -4
  118. data/test/multiverse/suites/rails/Envfile +3 -0
  119. data/test/multiverse/suites/rails/app.rb +1 -0
  120. data/test/multiverse/suites/rails/bad_instrumentation_test.rb +31 -0
  121. data/test/multiverse/suites/rails/config/newrelic.yml +2 -3
  122. data/test/multiverse/suites/rails/error_tracing_test.rb +32 -41
  123. data/test/multiverse/suites/rails/gc_instrumentation_test.rb +6 -16
  124. data/test/multiverse/suites/rails/queue_time_test.rb +4 -20
  125. data/test/multiverse/suites/rails/request_statistics_test.rb +7 -32
  126. data/test/multiverse/suites/rails/view_instrumentation_test.rb +6 -10
  127. data/test/multiverse/suites/resque/config/newrelic.yml +1 -3
  128. data/test/multiverse/suites/resque/instrumentation_test.rb +10 -7
  129. data/test/multiverse/suites/sequel/Envfile +8 -0
  130. data/test/multiverse/suites/sequel/config/newrelic.yml +0 -3
  131. data/test/multiverse/suites/sequel/sequel_test.rb +1 -2
  132. data/test/multiverse/suites/sidekiq/Envfile +0 -12
  133. data/test/multiverse/suites/sidekiq/config/newrelic.yml +1 -3
  134. data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +44 -100
  135. data/test/multiverse/suites/sinatra/config/newrelic.yml +0 -3
  136. data/test/multiverse/suites/sinatra/ignoring_test.rb +8 -5
  137. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +8 -1
  138. data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +9 -12
  139. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +9 -8
  140. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +1 -1
  141. data/test/multiverse/suites/sinatra/sinatra_routes_test.rb +6 -5
  142. data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +10 -13
  143. data/test/multiverse/suites/typhoeus/config/newrelic.yml +0 -2
  144. data/test/multiverse/suites/typhoeus/typhoeus_test.rb +7 -4
  145. data/test/multiverse/test/suite_examples/one/a/a_test.rb +0 -1
  146. data/test/multiverse/test/suite_examples/one/a/config/newrelic.yml +0 -1
  147. data/test/multiverse/test/suite_examples/one/b/b_test.rb +0 -1
  148. data/test/multiverse/test/suite_examples/one/b/config/newrelic.yml +0 -1
  149. data/test/new_relic/agent/agent/connect_test.rb +1 -1
  150. data/test/new_relic/agent/agent/start_test.rb +0 -1
  151. data/test/new_relic/agent/agent/start_worker_thread_test.rb +0 -1
  152. data/test/new_relic/agent/agent_logger_test.rb +37 -3
  153. data/test/new_relic/agent/agent_test.rb +23 -1
  154. data/test/new_relic/agent/browser_monitoring_test.rb +0 -1
  155. data/test/new_relic/agent/busy_calculator_test.rb +2 -2
  156. data/test/new_relic/agent/configuration/environment_source_test.rb +22 -0
  157. data/test/new_relic/agent/error_collector/notice_error_test.rb +1 -1
  158. data/test/new_relic/agent/error_collector_test.rb +95 -13
  159. data/test/new_relic/agent/event_listener_test.rb +0 -1
  160. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +23 -0
  161. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +4 -2
  162. data/test/new_relic/agent/instrumentation/instrumentation_test.rb +0 -1
  163. data/test/new_relic/agent/instrumentation/queue_time_test.rb +16 -11
  164. data/test/new_relic/agent/instrumentation/rack_test.rb +0 -1
  165. data/test/new_relic/agent/memcache_instrumentation_test.rb +7 -7
  166. data/test/{multiverse/suites/agent_only/test_trace_method_with_punctuation.rb → new_relic/agent/method_interrobang_test.rb} +3 -5
  167. data/test/new_relic/agent/method_tracer/instance_methods/trace_execution_scoped_test.rb +1 -2
  168. data/test/{multiverse/suites/agent_only → new_relic/agent}/method_visibility_test.rb +17 -29
  169. data/test/new_relic/agent/new_relic_service_test.rb +1 -1
  170. data/test/new_relic/agent/pipe_service_test.rb +1 -1
  171. data/test/new_relic/agent/request_sampler_test.rb +10 -10
  172. data/test/new_relic/agent/rpm_agent_test.rb +1 -2
  173. data/test/new_relic/agent/stats_hash_test.rb +83 -5
  174. data/test/new_relic/agent/stats_test.rb +0 -1
  175. data/test/new_relic/agent/thread_profiler_test.rb +7 -7
  176. data/test/new_relic/agent/threaded_test.rb +1 -2
  177. data/test/new_relic/agent/transaction/pop_test.rb +0 -1
  178. data/test/{multiverse/suites/agent_only/test_trace_transaction_with_punctuation.rb → new_relic/agent/transaction_interrobang_test.rb} +2 -4
  179. data/test/new_relic/agent/transaction_sample_builder_test.rb +13 -0
  180. data/test/new_relic/agent/transaction_test.rb +7 -5
  181. data/test/new_relic/agent/worker_loop_test.rb +0 -1
  182. data/test/new_relic/agent_test.rb +0 -27
  183. data/test/new_relic/collection_helper_test.rb +17 -17
  184. data/test/new_relic/control/class_methods_test.rb +1 -1
  185. data/test/new_relic/control_test.rb +6 -6
  186. data/test/new_relic/dependency_detection_test.rb +28 -0
  187. data/test/new_relic/evil_server.rb +0 -1
  188. data/test/new_relic/fake_collector.rb +20 -2
  189. data/test/new_relic/fake_server.rb +0 -12
  190. data/test/new_relic/http_client_test_cases.rb +20 -24
  191. data/test/new_relic/metric_spec_test.rb +18 -0
  192. data/test/new_relic/multiverse_helpers.rb +164 -0
  193. data/test/new_relic/rack/agent_hooks_test.rb +0 -1
  194. data/test/new_relic/rack/all_test.rb +0 -1
  195. data/test/new_relic/rack/deferred_instrumentation_test.rb +35 -0
  196. data/test/new_relic/rack/developer_mode_helper_test.rb +8 -9
  197. data/test/new_relic/rack/developer_mode_test.rb +0 -2
  198. data/test/new_relic/rack/error_collector_test.rb +52 -8
  199. data/test/new_relic/transaction_sample/composite_segment_test.rb +0 -1
  200. data/test/new_relic/transaction_sample/fake_segment_test.rb +0 -1
  201. data/test/new_relic/transaction_sample/segment_test.rb +0 -1
  202. data/test/new_relic/transaction_sample/summary_segment_test.rb +0 -1
  203. data/test/performance/README.md +162 -0
  204. data/test/performance/lib/performance.rb +28 -0
  205. data/test/performance/lib/performance/console_reporter.rb +51 -0
  206. data/test/performance/lib/performance/hako_client.rb +31 -0
  207. data/test/performance/lib/performance/hako_reporter.rb +26 -0
  208. data/test/performance/lib/performance/instrumentation/cpu_usage.rb +26 -0
  209. data/test/performance/lib/performance/instrumentation/gc_stats.rb +53 -0
  210. data/test/performance/lib/performance/instrumentation/perf_tools.rb +30 -0
  211. data/test/performance/lib/performance/instrumentor.rb +110 -0
  212. data/test/performance/lib/performance/json_reporter.rb +15 -0
  213. data/test/performance/lib/performance/result.rb +80 -0
  214. data/test/performance/lib/performance/runner.rb +207 -0
  215. data/test/performance/lib/performance/test_case.rb +65 -0
  216. data/test/performance/lib/performance/timer.rb +38 -0
  217. data/test/performance/script/mega-runner +37 -0
  218. data/test/performance/script/runner +81 -0
  219. data/test/performance/suites/startup.rb +12 -0
  220. data/test/performance/suites/transaction_tracing.rb +66 -0
  221. data/test/script/ci_agent-tests_runner.sh +4 -4
  222. data/test/script/ci_multiverse_runner.sh +3 -3
  223. data/test/test_helper.rb +0 -11
  224. data/ui/helpers/developer_mode_helper.rb +1 -1
  225. data/ui/views/layouts/newrelic_default.rhtml +1 -1
  226. data/ui/views/newrelic/_segment.rhtml +2 -2
  227. data/ui/views/newrelic/_segment_limit_message.rhtml +1 -1
  228. data/ui/views/newrelic/_show_sample_detail.rhtml +1 -1
  229. data/ui/views/newrelic/_show_sample_sql.rhtml +4 -4
  230. data/ui/views/newrelic/_stack_trace.rhtml +2 -2
  231. data/ui/views/newrelic/file/javascript/transaction_sample.js +3 -3
  232. data/ui/views/newrelic/file/stylesheets/style.css +13 -13
  233. data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection.rb +18 -4
  234. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +0 -1
  235. metadata +186 -17
  236. metadata.gz.sig +0 -0
  237. data/test/multiverse/suites/active_record/encoding_test.rb +0 -30
  238. data/test/multiverse/suites/agent_only/no_dns_resolv.rb +0 -21
  239. data/test/multiverse/suites/sidekiq/app.rb +0 -25
  240. data/test/new_relic/delayed_job_injection_test.rb +0 -25
@@ -32,14 +32,14 @@ test:
32
32
  fval: false
33
33
  yval: yes
34
34
  sval: sure
35
-
35
+
36
36
  transaction_tracer:
37
37
  record_sql: raw
38
38
  transaction_threshold: Apdex_f # case insensitive
39
39
  explain_threshold: 0.1
40
40
  explain_enabled: true
41
41
  stack_trace_threshold: 0.1
42
-
42
+
43
43
  error_collector:
44
44
  enabled: true
45
45
  capture_source: true
@@ -3,6 +3,8 @@ tmp
3
3
  .bundler_work_area
4
4
  Gemfile
5
5
  Gemfile.lock
6
+ Gemfile.*
7
+ Gemfile.*.lock
6
8
  *.log
7
9
  *.db
8
10
  .idea
@@ -6,8 +6,8 @@ module Multiverse
6
6
  # Reads an envfile.rb and converts it into gemfiles that can be used by
7
7
  # bundler
8
8
  class Envfile
9
- attr_accessor :file_path, :condition, :newrelic_gemfile_options
10
- attr_reader :before, :after, :mode, :skip_message, :omit_mocha
9
+ attr_accessor :file_path, :condition
10
+ attr_reader :before, :after, :mode, :skip_message, :omit_mocha, :omit_collector
11
11
 
12
12
  def initialize(file_path)
13
13
  self.file_path = file_path
@@ -25,13 +25,6 @@ module Multiverse
25
25
  @condition = block
26
26
  end
27
27
 
28
- # string representation options hash to append to the newrelic_rpm line
29
- # when setting up Gemfile
30
- # e.g. ":require => false"
31
- def newrelic_gemfile_options=(options_string)
32
- @newrelic_gemfile_options = options_string
33
- end
34
-
35
28
  def gemfile(content)
36
29
  @gemfiles.push content
37
30
  end
@@ -40,6 +33,10 @@ module Multiverse
40
33
  @omit_mocha = true
41
34
  end
42
35
 
36
+ def omit_collector!
37
+ @omit_collector = true
38
+ end
39
+
43
40
  def before_suite(&block)
44
41
  @before = block
45
42
  end
@@ -3,7 +3,6 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
5
  require 'fileutils'
6
- require 'test/unit'
7
6
  module Multiverse
8
7
  ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
9
8
  $: << File.expand_path(File.join(ROOT, 'lib'))
@@ -5,28 +5,60 @@
5
5
  # This module is responsible for intercepting output made through various stdlib
6
6
  # calls (i.e. puts, print, etc.) and printing summary information (e.g. a list
7
7
  # of failing tests) at the end of the process.
8
- #
8
+
9
+ require 'thread'
10
+
9
11
  module Multiverse
10
12
  module OutputCollector
11
13
  include Color
12
14
  extend Color
13
- def self.buffers
14
- @buffer ||= []
15
- end
15
+
16
+ @output_lock = Mutex.new
17
+ @buffer_lock = Mutex.new
16
18
 
17
19
  def self.failing_output
18
20
  @failing ||= []
19
21
  end
20
22
 
21
- def self.report
22
- puts
23
- puts
23
+ def self.buffer(suite, env)
24
+ key = [suite, env]
25
+ @buffer_lock.synchronize do
26
+ @buffers ||= {}
27
+ @buffers[key] ||= ""
28
+ @buffers[key]
29
+ end
30
+ end
31
+
32
+ def self.failed(suite, env)
33
+ @failing ||= []
34
+ @failing << buffer(suite, env) + "\n"
35
+ end
36
+
37
+ def self.write(suite, env, msg)
38
+ buffer(suite, env) << msg
39
+ end
40
+
41
+ def self.suite_report(suite, env)
42
+ output(buffer(suite, env))
43
+ end
44
+
45
+ def self.overall_report
46
+ output("", "")
24
47
  if failing_output.empty?
25
- puts green("There were no test failures")
48
+ output(green("There were no test failures"))
26
49
  else
27
- puts red("There were failures in #{failing_output.size} test suites")
28
- puts "Here is their output"
29
- puts *failing_output
50
+ output(
51
+ red("There were failures in #{failing_output.size} test suites"),
52
+ "Here is their output",
53
+ *failing_output)
54
+ end
55
+ end
56
+
57
+ # Because the various environments potentially run in separate threads to
58
+ # start their processes, make sure we don't blatantly interleave output.
59
+ def self.output(*args)
60
+ @output_lock.synchronize do
61
+ puts *args
30
62
  end
31
63
  end
32
64
  end
@@ -24,13 +24,36 @@ module Multiverse
24
24
  @exit_status
25
25
  end
26
26
 
27
- def run(filter="")
27
+ # Args without a = are turned into just opts[key] = true
28
+ # Args with = get split, then assigned as key + value
29
+ # :suite gets ignored
30
+ def parse_args(args)
31
+ opts = {}
32
+ args.each do |(k, v)|
33
+ if v.index("name=") == 0
34
+ parts = v.split("=")
35
+ opts[:names] ||= []
36
+ opts[:names] << parts.last
37
+ elsif v.include?("=")
38
+ parts = v.split("=")
39
+ opts[parts.first.to_sym] = parts.last
40
+ elsif k != :suite
41
+ opts[v.to_sym] = true
42
+ end
43
+ end
44
+ opts
45
+ end
46
+
47
+ def run(filter="", opts={})
28
48
  Dir.new(SUITES_DIRECTORY).entries.each do |dir|
29
- next if dir =~ /\A\./
30
- next unless dir.include? filter
31
49
  full_path = File.join(SUITES_DIRECTORY, dir)
50
+
51
+ next if dir =~ /\A\./
52
+ next unless filter.nil? || dir.include?(filter)
53
+ next unless File.exists?(File.join(full_path, "Envfile"))
54
+
32
55
  begin
33
- suite = Suite.new full_path
56
+ suite = Suite.new(full_path, opts)
34
57
  suite.execute
35
58
  rescue => e
36
59
  puts red("Error when trying to run suite in #{full_path.inspect}")
@@ -41,8 +64,17 @@ module Multiverse
41
64
  end
42
65
  end
43
66
 
44
- OutputCollector.report
67
+ OutputCollector.overall_report
45
68
  exit exit_status
46
69
  end
70
+
71
+ # run_one is used to run a suite directly in process
72
+ # Pipe shenanigans in the typical Suite runner interferes with the debugger
73
+ def run_one(filter="", opts={})
74
+ dir = Dir.new(SUITES_DIRECTORY).entries.find { |d| d.include?(filter) }
75
+ full_path = File.join(SUITES_DIRECTORY, dir)
76
+ $stderr.reopen($stdout)
77
+ Suite.new(full_path, opts).execute_child_environment(opts.fetch(:env, "0").to_i)
78
+ end
47
79
  end
48
80
  end
@@ -3,26 +3,30 @@
3
3
  # This file is distributed under New Relic's license terms.
4
4
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
5
5
 
6
- # this is to make sure that the Multiverse environment loads with the
7
- # the gem version of Minitest (necessary for Rails 4) and not the one
8
- # in standard library.
9
- if defined?(gem)
10
- gem 'minitest'
11
- end
6
+ # This makes sure that the Multiverse environment loads with the gem
7
+ # version of Minitest, which we use throughout, not the one in stdlib on
8
+ # Rubies starting with 1.9.x
9
+ require 'rubygems'
10
+ gem 'minitest', '~> 4.7.5'
12
11
 
13
12
  require File.expand_path(File.join(File.dirname(__FILE__), 'environment'))
13
+
14
14
  module Multiverse
15
15
  class Suite
16
16
  include Color
17
- attr_accessor :directory, :include_debugger
18
- def initialize(directory, include_debugger=nil)
17
+ attr_accessor :directory, :include_debugger, :seed, :names
18
+
19
+ def initialize(directory, opts={})
19
20
  self.directory = directory
20
- self.include_debugger = !!include_debugger
21
+ self.include_debugger = opts.fetch(:run_one, false)
22
+ self.seed = opts.fetch(:seed, "")
23
+ self.names = opts.fetch(:names, [])
24
+ ENV["VERBOSE"] = '1' if opts[:verbose]
21
25
  end
22
26
 
23
- def clean_gemfiles
24
- FileUtils.rm_rf File.join(directory, 'Gemfile')
25
- FileUtils.rm_rf File.join(directory, 'Gemfile.lock')
27
+ def clean_gemfiles(env_index)
28
+ FileUtils.rm_rf File.join(directory, "Gemfile.#{env_index}")
29
+ FileUtils.rm_rf File.join(directory, "Gemfile.#{env_index}.lock")
26
30
  end
27
31
 
28
32
 
@@ -34,16 +38,17 @@ module Multiverse
34
38
  end
35
39
 
36
40
  # load the environment for this suite after we've forked
37
- def load_dependencies(gemfile_text)
38
- clean_gemfiles
41
+ def load_dependencies(gemfile_text, env_index)
42
+ ENV["BUNDLE_GEMFILE"] = "Gemfile.#{env_index}"
43
+ clean_gemfiles(env_index)
39
44
  begin
40
- generate_gemfile(gemfile_text)
45
+ generate_gemfile(gemfile_text, env_index)
41
46
  bundle
42
47
  rescue => e
43
48
  puts "#{e.class}: #{e}"
44
49
  puts "Fast local bundle failed. Attempting to install from rubygems.org"
45
- clean_gemfiles
46
- generate_gemfile(gemfile_text, false)
50
+ clean_gemfiles(env_index)
51
+ generate_gemfile(gemfile_text, env_index, false)
47
52
  bundle
48
53
  end
49
54
  print_environment
@@ -57,34 +62,32 @@ module Multiverse
57
62
  raise "bundle command failed with (#{$?})" unless $? == 0
58
63
  Bundler.require
59
64
 
60
- # Ensure mocha is loaded after the test framework by deferring until here
61
- # see: http://gofreerange.com/mocha/docs/
62
- unless environments.omit_mocha
63
- if RUBY_VERSION > '1.8.7'
64
- require 'mocha/setup'
65
- else
66
- require 'mocha'
67
- end
68
- end
69
65
  end
70
66
 
71
- def generate_gemfile(gemfile_text, local = true)
72
- gemfile = File.join(Dir.pwd, 'Gemfile')
67
+ def generate_gemfile(gemfile_text, env_index, local = true)
68
+ gemfile = File.join(Dir.pwd, "Gemfile.#{env_index}")
73
69
  File.open(gemfile,'w') do |f|
74
70
  f.puts ' source :rubygems' unless local
75
71
  f.print gemfile_text
76
72
  f.puts newrelic_gemfile_line unless gemfile_text =~ /^\s*gem .newrelic_rpm./
77
73
  f.puts jruby_openssl_line unless gemfile_text =~ /^\s*gem .jruby-openssl./
74
+ f.puts minitest_line unless gemfile_text =~ /^\s*gem .minitest[^_]./
75
+
76
+ # We currently pin usage of mocha at the 0.9.x line for compatibility
77
+ # 0.10.x had issues with the integration handlers and MiniTest on old Rubies
78
+ # 0.11.x introduced syntax that breaks 1.8.6 entirely :(
79
+ #
80
+ # If we want to move forward to MiniTest 5.0.x, this will need to be
81
+ # resolved in some fashion at that point
82
+ f.puts " gem 'mocha', '~> 0.9.8', :require => false" unless environments.omit_mocha
83
+
78
84
  if RUBY_VERSION > '1.8.7'
79
- f.puts " gem 'test-unit', :require => 'test/unit'"
80
85
  f.puts " gem 'debugger'" if include_debugger
81
- f.puts " gem 'mocha', '~> 0.13.0', :require => false" unless environments.omit_mocha
82
86
  else
83
87
  f.puts " gem 'ruby-debug'" if include_debugger
84
- f.puts " gem 'mocha', '~> 0.9.8', :require => false" unless environments.omit_mocha
85
88
  end
86
89
  end
87
- puts yellow("Gemfile set to:") if verbose?
90
+ puts yellow("Gemfile.#{env_index} set to:") if verbose?
88
91
  puts File.open(gemfile).read if verbose?
89
92
  end
90
93
 
@@ -92,7 +95,6 @@ module Multiverse
92
95
  line = ENV['NEWRELIC_GEMFILE_LINE'] if ENV['NEWRELIC_GEMFILE_LINE']
93
96
  path = ENV['NEWRELIC_GEM_PATH'] || '../../../..'
94
97
  line ||= " gem 'newrelic_rpm', :path => '#{path}'"
95
- line += ", #{environments.newrelic_gemfile_options}" if environments.newrelic_gemfile_options
96
98
  line
97
99
  end
98
100
 
@@ -100,6 +102,10 @@ module Multiverse
100
102
  "gem 'jruby-openssl', :require => false, :platforms => [:jruby]"
101
103
  end
102
104
 
105
+ def minitest_line
106
+ "gem 'minitest', '~> 4.7.5'"
107
+ end
108
+
103
109
  def print_environment
104
110
  puts yellow("Environment loaded with:") if verbose?
105
111
  gems = Bundler.definition.specs.inject([]) do |m, s|
@@ -111,10 +117,14 @@ module Multiverse
111
117
  end
112
118
 
113
119
  def execute_child_environment(env_index)
120
+ configure_before_bundling
121
+
114
122
  gemfile_text = environments[env_index]
115
- load_dependencies(gemfile_text)
123
+ load_dependencies(gemfile_text, env_index)
124
+
125
+ configure_child_environment
116
126
  execute_ruby_files
117
- trigger_test_unit
127
+ trigger_test_run
118
128
  end
119
129
 
120
130
  # Load the test suite's environment and execute it.
@@ -130,68 +140,140 @@ module Multiverse
130
140
  end
131
141
  puts yellow("\nRunning #{directory.inspect} in #{environments.size} environments")
132
142
  environments.before.call if environments.before
143
+
144
+ threads = []
133
145
  environments.each_with_index do |gemfile_text, i|
134
- execute_with_pipe(i)
146
+ threads << execute_with_pipe(i)
135
147
  end
148
+ threads.each {|t| t.join}
149
+
136
150
  environments.after.call if environments.after
137
151
  end
138
152
 
139
153
  def execute_with_pipe(env)
140
- OutputCollector.buffers.push('')
141
- puts yellow("Running #{directory.inspect} for Envfile entry #{env}")
142
- IO.popen("#{__FILE__} #{directory} #{env}") do |io|
143
- puts yellow("Starting tests in child PID #{io.pid}")
144
- while chars = io.read(8) do
145
- OutputCollector.buffers.last << chars
146
- print chars
154
+ Thread.new do
155
+ suite = File.basename(directory)
156
+ IO.popen("#{__FILE__} #{directory} #{env} '#{seed}' '#{names.join(",")}'") do |io|
157
+ OutputCollector.write(suite, env, yellow("Running #{suite.inspect} for Envfile entry #{env}\n"))
158
+ OutputCollector.write(suite, env, yellow("Starting tests in child PID #{io.pid}\n"))
159
+ until io.eof do
160
+ chars = io.read
161
+ OutputCollector.write(suite, env, chars)
162
+ end
163
+ OutputCollector.suite_report(suite, env)
147
164
  end
165
+
166
+ if $? != 0
167
+ OutputCollector.failed(suite, env)
168
+ end
169
+ Multiverse::Runner.notice_exit_status $?
148
170
  end
149
- if $? != 0
150
- OutputCollector.failing_output.push(OutputCollector.buffers.last)
151
- end
152
- Multiverse::Runner.notice_exit_status $?
153
171
  end
154
172
 
155
- # something makes Test::Unit not want to run automatically. Seems like the
156
- # at_exit hook may be failing to run due to forking.
157
- def trigger_test_unit
158
- case
159
- when defined? Test::Unit::RunCount # 1.9.3
160
- # JRuby 1.7 doesn't seem to have a problem triggering test unit. In
161
- # contrast to MRI triggering it like this causes an error.
162
- return if defined?(JRuby)
173
+ def trigger_test_run
174
+ # We drive everything manually ourselves through MiniTest.
175
+ #
176
+ # Autorun behaves differently across the different Ruby version we have
177
+ # to support, so this is simplest for making our test running consistent
178
+ options = []
179
+ options << "-v" if verbose?
180
+ options << "--seed=#{seed}" unless seed == ""
181
+ options << "--name=/#{names.map {|n| n + ".*"}.join("|")}/" unless names == []
182
+ exit(::MiniTest::Unit.new.run(options))
183
+ end
184
+
185
+ def configure_before_bundling
186
+ disable_harvest_thread
187
+ configure_fake_collector
188
+ end
189
+
190
+ def configure_child_environment
191
+ require 'minitest/unit'
192
+ patch_minitest_for_old_mocha
193
+ prevent_minitest_auto_run
194
+ require_mocha
195
+ end
196
+
197
+ def patch_minitest_for_old_mocha
198
+ # We use mocha 0.9 for compatibility with old Rubies
199
+ # Its MiniTest integration isn't quite ok for 4.7.5, though, so patch it
200
+ unless defined?(::MiniTest::Unit::TestCase::SUPPORTS_INFO_SIGNAL)
201
+ ::MiniTest::Unit::TestCase.const_set("SUPPORTS_INFO_SIGNAL", false)
202
+ end
203
+ end
163
204
 
164
- Test::Unit::RunCount.run_once do
165
- exit(Test::Unit::Runner.new.run || true)
205
+ # Rails and minitest_tu_shim both want to do MiniTest::Unit.autorun for us
206
+ # We can't sidestep, so just gut the method to avoid doubled test runs
207
+ def prevent_minitest_auto_run
208
+ ::MiniTest::Unit.class_eval do
209
+ def self.autorun
210
+ # NO-OP
166
211
  end
167
- when defined? MiniTest::Unit # 1.9.2
168
- exit(MiniTest::Unit.new.run)
169
- when defined? Test::Unit::AutoRunner # 1.8.7
170
- exit(Test::Unit::AutoRunner.run)
171
- else
172
- raise "Can't figure out how to trigger Test::Unit"
173
212
  end
174
213
  end
175
214
 
215
+ def require_mocha
216
+ # We use an older version of mocha, so we just require mocha instead of mocha/setup
217
+ unless environments.omit_mocha
218
+ require 'mocha'
219
+ end
220
+ end
221
+
222
+ def disable_harvest_thread
223
+ # We don't want to have additional harvest threads running in our multiverse
224
+ # tests. The tests explicitly manage their lifecycle--resetting and harvesting
225
+ # to check results against the FakeCollector--so the harvest thread is actually
226
+ # destabilizing if it's running. Also, multiple restarts result in lots of
227
+ # threads running in some test suites.
228
+
229
+ ENV["NEWRELIC_DISABLE_HARVEST_THREAD"] = "true"
230
+ end
231
+
232
+ def configure_fake_collector
233
+ ENV["NEWRELIC_OMIT_FAKE_COLLECTOR"] = "true" if environments.omit_collector
234
+ end
235
+
176
236
  def execute_ruby_files
177
237
  Dir.chdir directory
178
- Dir[File.join(directory, '*.rb')].each do |file|
238
+ ordered_ruby_files(directory).each do |file|
179
239
  puts yellow("Executing #{file.inspect}") if verbose?
180
240
  load file
181
241
  end
182
242
  end
183
243
 
244
+ def ordered_ruby_files(directory)
245
+ files = Dir[File.join(directory, '*.rb')]
246
+
247
+ before = files.find { |file| File.basename(file) == "before_suite.rb" }
248
+ after = files.find { |file| File.basename(file) == "after_suite.rb" }
249
+
250
+ files.delete(before)
251
+ files.delete(after)
252
+
253
+ files.insert(0, before) if before
254
+ files.insert(-1, after) if after
255
+
256
+ files
257
+ end
258
+
184
259
  def verbose?
185
260
  ENV['VERBOSE']
186
261
  end
187
262
  end
188
263
  end
189
264
 
190
- # Exectute the suite. We need this if we want to execute a suite by spawning a
265
+ # Execute the suite. We need this if we want to execute a suite by spawning a
191
266
  # new process instead of forking.
192
- if $0 == __FILE__
267
+ if $0 == __FILE__ && $already_running.nil?
268
+ # Suite might get re-required, but don't execute again
269
+ $already_running = true
270
+
193
271
  # Redirect stderr to stdout so that we can capture both in the popen that
194
272
  # feeds into the OutputCollector above.
195
273
  $stderr.reopen($stdout)
196
- Multiverse::Suite.new(ARGV[0], ARGV[2]).execute_child_environment(ARGV[1].to_i)
274
+
275
+ # Ugly, but seralized args passed along to #popen when kicking child off
276
+ dir, env_index, seed, names, _ = *ARGV
277
+ suite = Multiverse::Suite.new(dir, {:seed => seed, :names => names.split(",")})
278
+ suite.execute_child_environment(env_index.to_i)
197
279
  end