rspec-rewind 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -1
  3. data/README.md +42 -124
  4. data/lib/rspec/rewind/api.rb +37 -0
  5. data/lib/rspec/rewind/attempt_runner.rb +7 -2
  6. data/lib/rspec/rewind/backoff.rb +26 -2
  7. data/lib/rspec/rewind/configuration.rb +176 -30
  8. data/lib/rspec/rewind/configuration_validation.rb +75 -0
  9. data/lib/rspec/rewind/core.rb +150 -0
  10. data/lib/rspec/rewind/event.rb +67 -16
  11. data/lib/rspec/rewind/example_state_resetter.rb +14 -42
  12. data/lib/rspec/rewind/failure_fingerprint.rb +19 -0
  13. data/lib/rspec/rewind/flaky_reporter.rb +18 -16
  14. data/lib/rspec/rewind/flaky_transition.rb +20 -3
  15. data/lib/rspec/rewind/matcher_validation.rb +17 -4
  16. data/lib/rspec/rewind/retry_budget.rb +126 -3
  17. data/lib/rspec/rewind/retry_count_resolver.rb +26 -3
  18. data/lib/rspec/rewind/retry_decision.rb +128 -20
  19. data/lib/rspec/rewind/retry_delay_resolver.rb +57 -6
  20. data/lib/rspec/rewind/retry_event_builder.rb +73 -6
  21. data/lib/rspec/rewind/retry_gate.rb +100 -6
  22. data/lib/rspec/rewind/retry_loop.rb +53 -6
  23. data/lib/rspec/rewind/retry_notifier.rb +55 -8
  24. data/lib/rspec/rewind/retry_policy.rb +137 -9
  25. data/lib/rspec/rewind/retry_summary.rb +61 -0
  26. data/lib/rspec/rewind/retry_transition.rb +189 -8
  27. data/lib/rspec/rewind/rspec_adapter.rb +47 -0
  28. data/lib/rspec/rewind/runner.rb +5 -4
  29. data/lib/rspec/rewind/runner_component_factory.rb +16 -0
  30. data/lib/rspec/rewind/runner_components.rb +11 -5
  31. data/lib/rspec/rewind/version.rb +1 -1
  32. data/lib/rspec/rewind.rb +2 -65
  33. data/sig/rspec/rewind.rbs +290 -24
  34. metadata +8 -1
data/sig/rspec/rewind.rbs CHANGED
@@ -2,18 +2,35 @@ module RSpec
2
2
  module Rewind
3
3
  VERSION: String
4
4
  EVENT_SCHEMA_VERSION: Integer
5
+ PUBLIC_API: Array[untyped]
6
+ INTERNAL_API: Array[untyped]
5
7
 
6
8
  class << self
7
9
  def configuration: () -> Configuration
8
10
  def configure: () { (Configuration) -> void } -> void
9
11
  def reset_configuration!: () -> Configuration
10
12
  def install!: () -> bool?
13
+ def installed?: () -> bool
14
+ def auto_install_disabled?: () -> bool
15
+ def close_reporter: () -> void
16
+ def prepare_suite!: () -> void
17
+ def publish_retry_summary: () -> void
18
+ def enforce_flaky_threshold!: () -> void
19
+ def threshold_exceeded?: (Integer count) -> bool
20
+ def warn_on_retry_gem_conflict: () -> nil
11
21
  end
12
22
 
13
23
  module Backoff
14
24
  def self.fixed: (Numeric seconds) -> untyped
15
25
  def self.linear: (step: Numeric, ?max: Numeric?) -> untyped
16
- def self.exponential: (base: Numeric, ?factor: Numeric, ?max: Numeric?, ?jitter: Numeric) -> untyped
26
+ def self.exponential: (base: Numeric, ?factor: Numeric, ?max: Numeric?, ?jitter: Numeric, ?rng: untyped, ?min_factor: Numeric) -> untyped
27
+ end
28
+
29
+ module ConfigurationValidation
30
+ end
31
+
32
+ module FailureFingerprint
33
+ def self.build: (Exception?) -> String?
17
34
  end
18
35
 
19
36
  class Configuration
@@ -24,11 +41,37 @@ module RSpec
24
41
  attr_reader retry_if: untyped?
25
42
  attr_reader retry_callback: untyped?
26
43
  attr_reader flaky_callback: untyped?
44
+ attr_reader not_retried_callback: untyped?
45
+ attr_reader before_retry: untyped?
46
+ attr_reader after_retry: untyped?
27
47
  attr_reader verbose: bool
28
48
  attr_reader display_retry_failure_messages: bool
49
+ attr_reader display_retry_backtrace_top: bool
29
50
  attr_reader clear_lets_on_failure: bool
51
+ attr_reader reset_failure_policy: Symbol
30
52
  attr_reader retry_budget: RetryBudget
31
53
  attr_reader flaky_reporter: FlakyReporter::NullReporter | FlakyReporter::JsonlReporter | untyped
54
+ attr_reader flaky_report_path: String?
55
+ attr_reader retry_if_mode: Symbol
56
+ attr_reader retry_on_default: Symbol
57
+ attr_reader report_retry_events: bool
58
+ attr_reader strict_callbacks: bool
59
+ attr_reader strict_callable_arity: bool
60
+ attr_reader strict_matcher_validation: bool
61
+ attr_reader retry_summary: RetrySummary
62
+ attr_reader display_retry_summary: bool
63
+ attr_reader fail_on_flaky: bool
64
+ attr_reader max_flaky_examples: Integer?
65
+ attr_reader freeze_configuration_at_suite_start: bool
66
+ attr_reader warn_on_delay_conflict: bool
67
+ attr_reader detect_retry_gem_conflicts: bool
68
+ attr_reader metadata_report_keys: Array[Symbol]
69
+ attr_reader max_retries: Integer?
70
+ attr_reader max_elapsed_time: Float?
71
+ attr_reader max_total_sleep: Float?
72
+ attr_reader sleeper: untyped
73
+ attr_reader clock: untyped
74
+ attr_reader dry_run: bool
32
75
 
33
76
  def initialize: () -> void
34
77
  def default_retries=: (untyped) -> Integer
@@ -38,12 +81,62 @@ module RSpec
38
81
  def retry_if=: (untyped?) -> untyped?
39
82
  def retry_callback=: (untyped?) -> untyped?
40
83
  def flaky_callback=: (untyped?) -> untyped?
84
+ def not_retried_callback=: (untyped?) -> untyped?
85
+ def before_retry=: (untyped?) -> untyped?
86
+ def after_retry=: (untyped?) -> untyped?
87
+ def retry_summary=: (untyped) -> untyped
41
88
  def verbose=: (bool) -> bool
42
89
  def display_retry_failure_messages=: (bool) -> bool
90
+ def display_retry_backtrace_top=: (bool) -> bool
91
+ def display_retry_summary=: (bool) -> bool
92
+ def fail_on_flaky=: (bool) -> bool
93
+ def max_flaky_examples=: (untyped?) -> Integer?
94
+ def freeze_configuration_at_suite_start=: (bool) -> bool
95
+ def warn_on_delay_conflict=: (bool) -> bool
96
+ def detect_retry_gem_conflicts=: (bool) -> bool
43
97
  def clear_lets_on_failure=: (bool) -> bool
98
+ def reset_failure_policy=: (Symbol | String) -> Symbol
44
99
  def retry_budget=: (RetryBudget | untyped) -> RetryBudget
45
100
  def flaky_reporter=: (FlakyReporter::NullReporter | FlakyReporter::JsonlReporter | untyped?) -> FlakyReporter::NullReporter | FlakyReporter::JsonlReporter | untyped
46
101
  def flaky_report_path=: (String?) -> FlakyReporter::NullReporter | FlakyReporter::JsonlReporter
102
+ def retry_if_mode=: (Symbol | String) -> Symbol
103
+ def retry_on_default=: (Symbol | String) -> Symbol
104
+ def report_retry_events=: (bool) -> bool
105
+ def strict_callbacks=: (bool) -> bool
106
+ def strict_callable_arity=: (bool) -> bool
107
+ def strict_matcher_validation=: (bool) -> bool
108
+ def metadata_report_keys=: (untyped) -> Array[Symbol]
109
+ def max_retries=: (untyped?) -> Integer?
110
+ def max_elapsed_time=: (untyped?) -> Float?
111
+ def max_total_sleep=: (untyped?) -> Float?
112
+ def sleeper=: (untyped?) -> untyped?
113
+ def clock=: (untyped?) -> untyped?
114
+ def dry_run=: (bool) -> bool
115
+ def snapshot: () -> Configuration
116
+ end
117
+
118
+ class FlakyThresholdExceeded < ::StandardError
119
+ end
120
+
121
+ class RetrySummary
122
+ attr_reader retry_events: Integer
123
+ attr_reader flaky_examples: Integer
124
+ attr_reader not_retried_events: Integer
125
+ attr_reader reset_failed_events: Integer
126
+ attr_reader sleep_seconds: Float
127
+
128
+ def initialize: () -> void
129
+ def record: (Event event) -> untyped
130
+ def reset!: () -> void
131
+ def to_message: (budget: untyped) -> String
132
+ end
133
+
134
+ class BudgetDecision < ::Struct
135
+ attr_accessor allowed: bool
136
+ attr_accessor limit: Integer?
137
+ attr_accessor used: Integer
138
+ attr_accessor remaining: Integer | Float
139
+ def allowed?: () -> bool
47
140
  end
48
141
 
49
142
  class RetryBudget
@@ -52,8 +145,23 @@ module RSpec
52
145
 
53
146
  def initialize: (untyped) -> void
54
147
  def consume!: () -> bool
148
+ def consume: () -> BudgetDecision
55
149
  def remaining: () -> Integer | Float
56
150
  def unlimited?: () -> bool
151
+ def reset!: () -> void
152
+ end
153
+
154
+ class FileRetryBudget
155
+ attr_reader limit: Integer
156
+ attr_reader path: String
157
+
158
+ def initialize: (limit: untyped, path: String) -> void
159
+ def consume!: () -> bool
160
+ def consume: () -> BudgetDecision
161
+ def used: () -> Integer
162
+ def remaining: () -> Integer
163
+ def unlimited?: () -> bool
164
+ def reset!: () -> void
57
165
  end
58
166
 
59
167
  class FlakyReporter
@@ -62,28 +170,53 @@ module RSpec
62
170
 
63
171
  class NullReporter
64
172
  def record: (Event event) -> void
173
+ def flush: () -> void
174
+ def close: () -> void
65
175
  end
66
176
 
67
177
  class JsonlReporter
178
+ attr_reader path: String
68
179
  def initialize: (String path) -> void
69
180
  def record: (Event event) -> void
181
+ def flush: () -> void
182
+ def close: () -> void
70
183
  end
71
184
  end
72
185
 
73
- class Event < ::Struct
74
- attr_accessor schema_version: Integer
75
- attr_accessor status: Symbol
76
- attr_accessor retry_reason: Symbol?
77
- attr_accessor example_id: String
78
- attr_accessor description: String
79
- attr_accessor location: String
80
- attr_accessor attempt: Integer
81
- attr_accessor retries: Integer
82
- attr_accessor exception_class: String?
83
- attr_accessor exception_message: String?
84
- attr_accessor duration: Numeric
85
- attr_accessor sleep_seconds: Numeric
86
- attr_accessor timestamp: String
186
+ class Event
187
+ attr_reader schema_version: Integer
188
+ attr_reader status: Symbol
189
+ attr_reader retry_reason: Symbol?
190
+ attr_reader decision_reason: Symbol?
191
+ attr_reader example_id: String
192
+ attr_reader description: String
193
+ attr_reader location: String
194
+ attr_reader attempt: Integer
195
+ attr_reader retries: Integer
196
+ attr_reader max_attempts: Integer?
197
+ attr_reader exception_class: String?
198
+ attr_reader exception_message: String?
199
+ attr_reader exception_backtrace_top: String?
200
+ attr_reader failure_fingerprint: String?
201
+ attr_reader duration: Numeric
202
+ attr_reader total_duration: Numeric?
203
+ attr_reader attempt_durations: Array[Numeric]?
204
+ attr_reader first_failure_duration: Numeric?
205
+ attr_reader sleep_seconds: Numeric
206
+ attr_reader scheduled_sleep_seconds: Numeric?
207
+ attr_reader actual_sleep_seconds: Numeric?
208
+ attr_reader sleep_total: Numeric?
209
+ attr_reader timestamp: String
210
+ attr_reader budget_limit: Integer?
211
+ attr_reader budget_used: Integer?
212
+ attr_reader budget_remaining: Integer | Float | nil
213
+ attr_reader matched_retry_on: String?
214
+ attr_reader matched_skip_retry_on: String?
215
+ attr_reader matcher_error: String?
216
+ attr_reader metadata: Hash[Symbol, untyped]?
217
+
218
+ def initialize: (**untyped) -> void
219
+ def to_h: () -> Hash[Symbol, untyped]
87
220
  end
88
221
 
89
222
  class ExampleContext
@@ -97,35 +230,108 @@ module RSpec
97
230
  def run_with_rewind: (?Hash[Symbol | String, untyped]) -> void
98
231
  end
99
232
 
233
+ class RetryDecisionResult < ::Struct
234
+ attr_accessor allowed: bool
235
+ attr_accessor reason: Symbol
236
+ attr_accessor matched_retry_on: String?
237
+ attr_accessor matched_skip_retry_on: String?
238
+ attr_accessor matcher_error: String?
239
+ def allowed?: () -> bool
240
+ end
241
+
242
+ class RetryContext < ::Struct
243
+ attr_accessor attempt: Integer?
244
+ attr_accessor retries: Integer?
245
+ attr_accessor metadata: Hash[Symbol, untyped]?
246
+ attr_accessor budget_remaining: Integer | Float | nil
247
+ attr_accessor failure_fingerprint: String?
248
+ attr_accessor elapsed_time: Numeric?
249
+ attr_accessor sleep_total: Numeric?
250
+ end
251
+
100
252
  class RetryDecision
101
- def initialize: (exception: Exception?, example: untyped, retry_on: untyped, skip_retry_on: untyped, retry_if: untyped?) -> void
253
+ def initialize: (
254
+ exception: Exception?,
255
+ example: untyped,
256
+ retry_on: untyped,
257
+ skip_retry_on: untyped,
258
+ retry_if: untyped?,
259
+ ?retry_on_default: Symbol,
260
+ ?context: RetryContext?,
261
+ ?strict_callable_arity: bool
262
+ ) -> void
102
263
  def retry?: () -> bool
264
+ def decision: () -> RetryDecisionResult
103
265
  end
104
266
 
105
267
  class RetryPolicy
106
268
  def initialize: (example: untyped, configuration: Configuration, metadata: Hash[Symbol, untyped]?) -> void
107
269
  def retry_allowed?: (exception: Exception, retry_on: untyped, skip_retry_on: untyped, retry_if: untyped?) -> bool
270
+ def decision: (
271
+ exception: Exception,
272
+ retry_on: untyped,
273
+ skip_retry_on: untyped,
274
+ retry_if: untyped?,
275
+ ?retry_number: Integer?,
276
+ ?resolved_retries: Integer?,
277
+ ?budget_remaining: Integer | Float | nil,
278
+ ?elapsed_time: Numeric?,
279
+ ?sleep_total: Numeric?
280
+ ) -> RetryDecisionResult
108
281
  end
109
282
 
110
283
  class RetryCountResolver
111
284
  ENV_RETRIES_KEY: String
285
+ ENV_DISABLE_KEY: String
112
286
 
113
287
  def initialize: (configuration: Configuration, metadata: Hash[Symbol, untyped]?) -> void
114
288
  def resolve: (explicit_retries: untyped) -> Integer
115
289
  end
116
290
 
117
291
  class RetryDelayResolver
118
- def initialize: (configuration: Configuration, metadata: Hash[Symbol, untyped]?, example: untyped) -> void
119
- def resolve: (retry_number: Integer, backoff: untyped, wait: untyped, exception: Exception) -> Float
292
+ class DelayContext < ::Struct
293
+ attr_accessor retry_number: Integer
294
+ attr_accessor resolved_retries: Integer?
295
+ attr_accessor metadata: Hash[Symbol, untyped]?
296
+ attr_accessor previous_sleep_seconds: Numeric
297
+ attr_accessor failure_fingerprint: String?
298
+ end
299
+
300
+ def initialize: (configuration: Configuration, metadata: Hash[Symbol, untyped]?, example: untyped, ?warn: untyped) -> void
301
+ def resolve: (
302
+ retry_number: Integer,
303
+ backoff: untyped,
304
+ wait: untyped,
305
+ exception: Exception,
306
+ ?resolved_retries: Integer?,
307
+ ?previous_sleep_seconds: Numeric,
308
+ ?failure_fingerprint: String?
309
+ ) -> Float
120
310
  end
121
311
 
122
312
  class AttemptRunner
313
+ def initialize: (?clock: untyped?) -> void
123
314
  def run: (run_target: untyped, exception_source: untyped) -> [Exception?, Float, bool]
124
315
  end
125
316
 
126
317
  class FlakyTransition
127
318
  def initialize: (event_builder: untyped, notifier: untyped) -> void
128
- def perform: (attempt: Integer, retries: Integer, duration: Numeric) -> void
319
+ def perform: (
320
+ attempt: Integer,
321
+ retries: Integer,
322
+ duration: Numeric,
323
+ exception: Exception?,
324
+ ?total_duration: Numeric?,
325
+ ?attempt_durations: Array[Numeric]?,
326
+ ?first_failure_duration: Numeric?,
327
+ ?sleep_total: Numeric,
328
+ ?budget_decision: BudgetDecision?
329
+ ) -> void
330
+ end
331
+
332
+ class SleepMeasurement < ::Struct
333
+ attr_accessor scheduled: Numeric
334
+ attr_accessor actual: Numeric
129
335
  end
130
336
 
131
337
  class RetryTransition
@@ -135,7 +341,8 @@ module RSpec
135
341
  event_builder: untyped,
136
342
  notifier: untyped,
137
343
  state_resetter: untyped,
138
- sleep: untyped
344
+ sleep: untyped,
345
+ ?clock: untyped?
139
346
  ) -> void
140
347
  def perform: (
141
348
  retry_number: Integer,
@@ -144,10 +351,34 @@ module RSpec
144
351
  exception: Exception,
145
352
  backoff: untyped,
146
353
  wait: untyped,
147
- example_source: untyped
354
+ example_source: untyped,
355
+ ?total_duration: Numeric?,
356
+ ?attempt_durations: Array[Numeric]?,
357
+ ?sleep_total: Numeric,
358
+ ?failure_fingerprint: String?,
359
+ ?budget_decision: BudgetDecision?,
360
+ ?policy_decision: RetryDecisionResult?
361
+ ) -> SleepMeasurement
362
+ def publish_not_retried: (
363
+ retry_number: Integer,
364
+ resolved_retries: Integer,
365
+ duration: Numeric,
366
+ exception: Exception,
367
+ decision: RetryGateDecision,
368
+ ?total_duration: Numeric?,
369
+ ?attempt_durations: Array[Numeric]?,
370
+ ?sleep_total: Numeric
148
371
  ) -> void
149
372
  end
150
373
 
374
+ class RetryGateDecision < ::Struct
375
+ attr_accessor allowed: bool
376
+ attr_accessor reason: Symbol
377
+ attr_accessor policy_decision: RetryDecisionResult?
378
+ attr_accessor budget_decision: BudgetDecision?
379
+ def allowed?: () -> bool
380
+ end
381
+
151
382
  class RetryGate
152
383
  def initialize: (configuration: Configuration, retry_policy: RetryPolicy, debug: untyped) -> void
153
384
  def allow?: (
@@ -157,8 +388,33 @@ module RSpec
157
388
  retry_on: untyped,
158
389
  skip_retry_on: untyped,
159
390
  retry_if: untyped?,
160
- example_id: String
391
+ example_id: String,
392
+ ?elapsed_time: Numeric?,
393
+ ?sleep_total: Numeric?
161
394
  ) -> bool
395
+ def decision: (
396
+ exception: Exception,
397
+ retry_number: Integer,
398
+ resolved_retries: Integer,
399
+ retry_on: untyped,
400
+ skip_retry_on: untyped,
401
+ retry_if: untyped?,
402
+ example_id: String,
403
+ ?elapsed_time: Numeric?,
404
+ ?sleep_total: Numeric?
405
+ ) -> RetryGateDecision
406
+ end
407
+
408
+ class RSpecAdapter
409
+ def clear_exception: (untyped) -> void
410
+ def clear_execution_result: (untyped) -> void
411
+ def clear_lets: (untyped) -> void
412
+ end
413
+
414
+ class ExampleStateResetter
415
+ attr_reader last_exception: StandardError?
416
+ def initialize: (configuration: Configuration, ?adapter: RSpecAdapter) -> void
417
+ def reset: (untyped) -> bool
162
418
  end
163
419
 
164
420
  class RunnerLogger
@@ -175,7 +431,8 @@ module RSpec
175
431
  attempt_runner: AttemptRunner,
176
432
  retry_gate: RetryGate,
177
433
  retry_transition: RetryTransition,
178
- flaky_transition: FlakyTransition
434
+ flaky_transition: FlakyTransition,
435
+ ?clock: untyped?
179
436
  ) -> void
180
437
  def run: (
181
438
  retries: untyped,
@@ -203,8 +460,17 @@ module RSpec
203
460
  ) -> void
204
461
  end
205
462
 
463
+ class RunnerComponentFactory
464
+ def build: (
465
+ example: untyped,
466
+ configuration: Configuration,
467
+ context: ExampleContext,
468
+ logger: RunnerLogger
469
+ ) -> RunnerComponents
470
+ end
471
+
206
472
  class Runner
207
- def initialize: (example: untyped, configuration: Configuration) -> void
473
+ def initialize: (example: untyped, configuration: Configuration, ?component_factory: RunnerComponentFactory) -> void
208
474
  def run: (?retries: untyped, ?backoff: untyped, ?wait: untyped, ?retry_on: untyped, ?skip_retry_on: untyped, ?retry_if: untyped) -> void
209
475
  end
210
476
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-rewind
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
@@ -43,13 +43,17 @@ files:
43
43
  - README.md
44
44
  - lib/rspec-rewind.rb
45
45
  - lib/rspec/rewind.rb
46
+ - lib/rspec/rewind/api.rb
46
47
  - lib/rspec/rewind/attempt_runner.rb
47
48
  - lib/rspec/rewind/backoff.rb
48
49
  - lib/rspec/rewind/configuration.rb
50
+ - lib/rspec/rewind/configuration_validation.rb
51
+ - lib/rspec/rewind/core.rb
49
52
  - lib/rspec/rewind/event.rb
50
53
  - lib/rspec/rewind/example_context.rb
51
54
  - lib/rspec/rewind/example_methods.rb
52
55
  - lib/rspec/rewind/example_state_resetter.rb
56
+ - lib/rspec/rewind/failure_fingerprint.rb
53
57
  - lib/rspec/rewind/flaky_reporter.rb
54
58
  - lib/rspec/rewind/flaky_transition.rb
55
59
  - lib/rspec/rewind/matcher_validation.rb
@@ -62,8 +66,11 @@ files:
62
66
  - lib/rspec/rewind/retry_loop.rb
63
67
  - lib/rspec/rewind/retry_notifier.rb
64
68
  - lib/rspec/rewind/retry_policy.rb
69
+ - lib/rspec/rewind/retry_summary.rb
65
70
  - lib/rspec/rewind/retry_transition.rb
71
+ - lib/rspec/rewind/rspec_adapter.rb
66
72
  - lib/rspec/rewind/runner.rb
73
+ - lib/rspec/rewind/runner_component_factory.rb
67
74
  - lib/rspec/rewind/runner_components.rb
68
75
  - lib/rspec/rewind/runner_logger.rb
69
76
  - lib/rspec/rewind/version.rb