Class: RSpec::Retry

Inherits:
Object
  • Object
show all
Defined in:
lib/rspec/retry.rb,
lib/rspec/retry/version.rb

Defined Under Namespace

Classes: Formatter

Constant Summary collapse

VERSION =
"0.6.2"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ex, opts = {}) ⇒ Retry

Returns a new instance of Retry.



44
45
46
47
48
# File 'lib/rspec/retry.rb', line 44

def initialize(ex, opts = {})
  @ex = ex
  @ex..merge!(opts)
  current_example.attempts ||= 0
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



42
43
44
# File 'lib/rspec/retry.rb', line 42

def context
  @context
end

#exObject (readonly)

Returns the value of attribute ex.



42
43
44
# File 'lib/rspec/retry.rb', line 42

def ex
  @ex
end

Class Method Details

.setupObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rspec/retry.rb', line 7

def self.setup
  RSpec.configure do |config|
    config.add_setting :verbose_retry, :default => false
    config.add_setting :default_retry_count, :default => 1
    config.add_setting :default_sleep_interval, :default => 0
    config.add_setting :exponential_backoff, :default => false
    config.add_setting :clear_lets_on_failure, :default => true
    config.add_setting :display_try_failure_messages, :default => false

    # retry based on example metadata
    config.add_setting :retry_count_condition, :default => ->(_) { nil }

    # If a list of exceptions is provided and 'retry' > 1, we only retry if
    # the exception that was raised by the example is NOT in that list. Otherwise
    # we ignore the 'retry' value and fail immediately.
    #
    # If no list of exceptions is provided and 'retry' > 1, we always retry.
    config.add_setting :exceptions_to_hard_fail, :default => []

    # If a list of exceptions is provided and 'retry' > 1, we only retry if
    # the exception that was raised by the example is in that list. Otherwise
    # we ignore the 'retry' value and fail immediately.
    #
    # If no list of exceptions is provided and 'retry' > 1, we always retry.
    config.add_setting :exceptions_to_retry, :default => []

    # Callback between retries
    config.add_setting :retry_callback, :default => nil

    config.around(:each) do |ex|
      ex.run_with_retry
    end
  end
end

Instance Method Details

#attemptsObject



66
67
68
# File 'lib/rspec/retry.rb', line 66

def attempts
  current_example.attempts ||= 0
end

#attempts=(val) ⇒ Object



70
71
72
# File 'lib/rspec/retry.rb', line 70

def attempts=(val)
  current_example.attempts = val
end

#clear_letsObject



74
75
76
77
78
# File 'lib/rspec/retry.rb', line 74

def clear_lets
  !ex.[:clear_lets_on_failure].nil? ?
      ex.[:clear_lets_on_failure] :
      RSpec.configuration.clear_lets_on_failure
end

#current_exampleObject



50
51
52
# File 'lib/rspec/retry.rb', line 50

def current_example
  @current_example ||= RSpec.current_example
end

#display_try_failure_messages?Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/rspec/retry.rb', line 103

def display_try_failure_messages?
  RSpec.configuration.display_try_failure_messages?
end

#exceptions_to_hard_failObject



89
90
91
92
# File 'lib/rspec/retry.rb', line 89

def exceptions_to_hard_fail
  ex.[:exceptions_to_hard_fail] ||
      RSpec.configuration.exceptions_to_hard_fail
end

#exceptions_to_retryObject



94
95
96
97
# File 'lib/rspec/retry.rb', line 94

def exceptions_to_retry
  ex.[:exceptions_to_retry] ||
      RSpec.configuration.exceptions_to_retry
end

#retry_countObject



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rspec/retry.rb', line 54

def retry_count
  [
      (
      ENV['RSPEC_RETRY_RETRY_COUNT'] ||
          ex.[:retry] ||
          RSpec.configuration.retry_count_condition.call(ex) ||
          RSpec.configuration.default_retry_count
      ).to_i,
      1
  ].max
end

#runObject



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/rspec/retry.rb', line 107

def run
  example = current_example

  loop do
    if attempts > 0
      RSpec.configuration.formatters.each { |f| f.retry(example) if f.respond_to? :retry }
      if verbose_retry?
        message = "RSpec::Retry: #{ordinalize(attempts + 1)} try #{example.location}"
        message = "\n" + message if attempts == 1
        RSpec.configuration.reporter.message(message)
      end
    end

    example.[:retry_attempts] = self.attempts
    example.[:retry_exceptions] ||= []

    example.clear_exception
    ex.run

    self.attempts += 1

    break if example.exception.nil?

    example.[:retry_exceptions] << example.exception

    break if attempts >= retry_count

    if exceptions_to_hard_fail.any?
      break if exception_exists_in?(exceptions_to_hard_fail, example.exception)
    end

    if exceptions_to_retry.any?
      break unless exception_exists_in?(exceptions_to_retry, example.exception)
    end

    if verbose_retry? && display_try_failure_messages?
      if attempts != retry_count
        exception_strings =
          if ::RSpec::Core::MultipleExceptionError::InterfaceTag === example.exception
            example.exception.all_exceptions.map(&:to_s)
          else
            [example.exception.to_s]
          end

        try_message = "\n#{ordinalize(attempts)} Try error in #{example.location}:\n#{exception_strings.join "\n"}\n"
        RSpec.configuration.reporter.message(try_message)
      end
    end

    example.example_group_instance.clear_lets if clear_lets

    # If the callback is defined, let's call it
    if RSpec.configuration.retry_callback
      example.example_group_instance.instance_exec(example, &RSpec.configuration.retry_callback)
    end

    sleep sleep_interval if sleep_interval.to_f > 0
  end
end

#sleep_intervalObject



80
81
82
83
84
85
86
87
# File 'lib/rspec/retry.rb', line 80

def sleep_interval
  if ex.[:exponential_backoff]
      2**(current_example.attempts-1) * ex.[:retry_wait]
  else
      ex.[:retry_wait] ||
          RSpec.configuration.default_sleep_interval
  end
end

#verbose_retry?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/rspec/retry.rb', line 99

def verbose_retry?
  RSpec.configuration.verbose_retry?
end