Class: Bulldogger::Replay
- Inherits:
-
Object
- Object
- Bulldogger::Replay
- Defined in:
- lib/bulldogger/replay.rb
Overview
Records one failed test again because a failure snapshot can miss the cause. The application method has returned when an assertion raises. In one third-party gem, its snapshot could not reveal a one-character fault. Additional stack frames were rejected because they cannot contain that call. Replay observes a new execution and records the application call. This class does not change the parent test result or record green tests.
Class Method Summary collapse
-
.boot_replay_child!(run_dir: ENV.fetch("BULLDOGGER_REPLAY_RUN_DIR")) ⇒ Object
The replay uses a child because an in-process run can pollute global state and change the parent result.
Instance Method Summary collapse
- #call(test:, run_dir:, frames: []) ⇒ Object
-
#initialize(config:) ⇒ Replay
constructor
A new instance of Replay.
Constructor Details
#initialize(config:) ⇒ Replay
Returns a new instance of Replay.
16 17 18 19 20 |
# File 'lib/bulldogger/replay.rb', line 16 def initialize(config:) @config = config @count = 0 @mutex = Mutex.new end |
Class Method Details
.boot_replay_child!(run_dir: ENV.fetch("BULLDOGGER_REPLAY_RUN_DIR")) ⇒ Object
The replay uses a child because an in-process run can pollute global state and change the parent result. Parent recording was rejected because it makes green runs about sixty times slower. The child confines this cost.
This method starts recording before the test framework starts. A later start can miss boot calls that the test needs. The method also gives the coverage suite a callable seam. Ruby loads command-line requirements before the coverage setup in RUBYOPT, so coverage cannot see the call site.
50 51 52 53 54 55 56 |
# File 'lib/bulldogger/replay.rb', line 50 def self.boot_replay_child!(run_dir: ENV.fetch("BULLDOGGER_REPLAY_RUN_DIR")) require_relative "../bulldogger" replay_instance = Struct.new(:config, :run_dir).new(Bulldogger::Config.new, run_dir) session = Bulldogger::Record.start(instance: replay_instance) at_exit { session.stop } session end |
Instance Method Details
#call(test:, run_dir:, frames: []) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/bulldogger/replay.rb', line 22 def call(test:, run_dir:, frames: []) return unless eligible?(test) if @config.replay_on_failure != :always && ApplicationFrames.available?(test[:file], frames) return { skipped_reason: "application_frame_available" } end return unless reserve before = traces(run_dir) _stdout, _stderr, status = Timeout.timeout(@config.replay_timeout) do Open3.capture3(child_env(run_dir), *command(test)) end path = (traces(run_dir) - before).last { path: path, reproduced: !status.success? } # Replay is diagnostic work. A timeout, crash, or setup error must not # change the parent exit code or add a failure to the parent suite. rescue Exception => e # rubocop:disable Lint/RescueException warn("bulldogger: replay failed: #{e.class}: #{e.}") if ENV["BULLDOGGER_DEBUG"] == "1" nil end |