diff options
author | Robert Speicher <rspeicher@gmail.com> | 2018-11-29 18:37:33 +0300 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2018-11-30 20:02:37 +0300 |
commit | fa4f46b843b2f81ab4c30cf3865bc3f38bc0d4c7 (patch) | |
tree | e133d9a65d90f2f28bf33113e60fd7bb141c9e24 | |
parent | 5125ec5f50c35ae30559ab4ff967e6d7c76c5c2f (diff) |
Add RSpec listener to report slow tests to Sentryrs-slow-specs-to-sentry
When configured, this listener will report any example that has a run
time exceeding a defined threshold to Sentry.
-rw-r--r-- | spec/support/listeners/slow_example_listener.rb | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/spec/support/listeners/slow_example_listener.rb b/spec/support/listeners/slow_example_listener.rb new file mode 100644 index 00000000000..80b7def7483 --- /dev/null +++ b/spec/support/listeners/slow_example_listener.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +# Reports slow example runtimes to a configured Sentry DSN +class SlowExampleListener + # Maximum execution time for a single example + DEFAULT_THRESHOLD = 10.0 + + # Type-specific maximum execution times for a single example + TYPE_THRESHOLDS = { + feature: -> (meta) { meta[:js] ? 20.0 : DEFAULT_THRESHOLD } + }.freeze + + def self.enabled? + (ENV['CI'] || ENV['ENABLE_RSPEC_TIMINGS']) && + ENV['RSPEC_TIMINGS_DSN'].present? + end + + def initialize + @raven = Raven::Instance.new(Raven::Context.new, Raven::Configuration.new) + @raven.configure do |config| + config.dsn = ENV['RSPEC_TIMINGS_DSN'] + config.silence_ready = true + end + end + + def threshold(meta) + threshold = TYPE_THRESHOLDS.fetch(meta[:type], DEFAULT_THRESHOLD) + + if threshold.respond_to?(:call) + threshold.call(meta) + else + threshold + end + end + + def example_passed(notification) + example = notification.example + metadata = example.metadata + result = example.execution_result + threshold = threshold(metadata) + + if result.run_time > threshold + message = "Slow example: #{metadata[:location]}" + + extra = metadata + .slice(:file_path, :line_number, :location, :full_description) + .merge({ run_time: result.run_time, threshold: threshold }) + + capture_message( + message, + extra: extra, + fingerprint: fingerprint(metadata), + tags: metadata.slice(:type, :js) + ) + end + rescue StandardError => ex + @raven.capture_exception(ex) + end + + private + + def fingerprint(meta) + # Fingerprint on the full description, otherwise the example's location + # changing would create a new event + [Digest::SHA256.hexdigest(meta[:full_description])] + end + + def capture_message(message, options = {}) + # Temporarily disable WebMock so that Raven can post the message + WebMock.disable! + @raven.capture_message(message, options) + WebMock.enable! + end +end + +if SlowExampleListener.enabled? + RSpec.configure do |config| + config.reporter.register_listener SlowExampleListener.new, :example_passed + end +end |