summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Speicher <rspeicher@gmail.com>2018-11-29 09:37:33 -0600
committerRobert Speicher <rspeicher@gmail.com>2018-11-30 11:02:37 -0600
commitfa4f46b843b2f81ab4c30cf3865bc3f38bc0d4c7 (patch)
treee133d9a65d90f2f28bf33113e60fd7bb141c9e24
parent5125ec5f50c35ae30559ab4ff967e6d7c76c5c2f (diff)
downloadgitlab-ce-rs-slow-specs-to-sentry.tar.gz
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.rb80
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