Skip to content

Instantly share code, notes, and snippets.

@joakimk
Forked from seancribbs/rspec_retries.rb
Last active June 10, 2016 09:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joakimk/2397889 to your computer and use it in GitHub Desktop.
Save joakimk/2397889 to your computer and use it in GitHub Desktop.
A simple way to retry examples in RSpec using filters and around
# Based on https://gist.github.com/1718985
# Usage:
# 1) Put in spec/support/rspec_retries.rb
# 2) Call from spec_helper.rb: "RSpec::Retries.setup(config)"
# 3) Change around filter to suit your needs.
# Example output:
# ..............
#
# spec/requests/something_spec.rb:10: "should do something" failed.
# Retrying, attempt 1 of 5.
# Retry successful.
#
# .....
# You need something like this:
# SPECS_ARE_NOT_LOCAL = (ENV['USER'] == "jenkins")
module RSpec::Retries
COUNT = 5
def self.enable_retries?
# Only retry certain failures without Spork. I.e. either in CI, or locally
# without Spork, typically when running the whole suite for some reason.
if Spork.using_spork?
false
else
SPECS_ARE_NOT_LOCAL || ENV['ENABLE_RETRIES']
end
end
def self.setup(config)
config.include RSpec::Retries
if enable_retries?
config.around(:each, :retry) do |example|
run_with_retries(example, COUNT)
end
config.around(:each, :sphinx) do |example|
run_with_retries(example, COUNT)
end
config.around(:each, :js) do |example|
run_with_retries(example, COUNT)
end
# This is perhaps because run_with_retries calls example.run which probably doesn't include around filters?
def config.around(*args)
raise "We can't have multiple arounds in this project because of the way retries are implemented."
end
end
end
def run_with_retries(example_to_run, retries)
retry_header_shown = false
retries.times do |t|
self.example.instance_variable_set(:@exception, nil)
example_to_run.run
break unless self.example.exception
raise self.example.exception if self.example.exception == Interrupt # Allow exiting with ^C
info = "#{self.example.location.gsub(/#{Rails.root}\//, '')}: \"#{self.example.description}\""
attempt = t + 1
Rails.logger.error("DEBUG_LOCKUPS: #{Process.pid} #{info} ATTEMPT: #{attempt}")
unless retry_header_shown
puts "\n\n#{info} failed."
retry_header_shown = true
end
# We restart sphinx when a test fails that uses it in case thats the problem.
# RSpec::ThinkingSphinx.restart_if_started
# Clears away let's.
# Without this we got errors where factories appeared to create records without ids, which
# resulted in errors like "No route matches.... :foo_id=>#<Foo id: nil,"
self.class.run_after_all_hooks(self)
puts "Retrying, attempt #{attempt} of #{retries}.\n"
end
if e = self.example.exception
puts "Retries failed.\n\n"
new_exception = e.exception(e.message + " [retried #{retries} times]")
new_exception.set_backtrace e.backtrace
self.example.instance_variable_set(:@exception, new_exception)
elsif retry_header_shown
puts "Retry successful.\n\n"
end
end
end
@henrik
Copy link

henrik commented Jun 10, 2016

run_after_all_hooks seems to have become run_after_context_hooks in Rspec 3.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment