class Towel::RSpec::Formatter

Takes RSpec events and turns them into a streaming upload to Towel.

Public Class Methods

new(io) click to toggle source
Calls superclass method
# File lib/towel/rspec/formatter.rb, line 12
def initialize(io)
  super
  @session = Towel::Session.new
  @stdout = nil
  @stderr = nil
  @previous_stdout = nil
  @previous_stderr = nil
  @cancel_queue = Queue.new

  # Start a thread to listen for cancellations. Cancel the invocation if
  # requested. This exists because gRPC requests may not be made directly
  # from within a signal handler. It appears that RSpec shutdown runs as
  # such.
  Thread.new do
    cancelled = @cancel_queue.pop
    @session.cancel_invocation if cancelled
  end
end

Public Instance Methods

close(_notification) click to toggle source
Calls superclass method
# File lib/towel/rspec/formatter.rb, line 111
def close(_notification)
  super

  $stdout = @previous_stdout
  $stderr = @previous_stderr

  unless @cancel_queue.closed?
    @session.finish_invocation
  end
end
example_finished(notification) click to toggle source
# File lib/towel/rspec/formatter.rb, line 72
def example_finished(notification)
  example_group = notification.example.example_group
  example = notification.example
  group = example_group.described_class.to_s + example_group.description

  state = case example.execution_result.status
          when :passed then Towel::V1alpha::ResultState::SUCCESS
          when :failed then Towel::V1alpha::ResultState::FAILURE
          when :pending then Towel::V1alpha::ResultState::SKIPPED
          end

  duration = nil
  unless state == Towel::V1alpha::ResultState::SKIPPED
    duration = example.execution_result.run_time
  end

  description = nil
  if state == Towel::V1alpha::ResultState::SKIPPED
    description = example.execution_result.pending_message
  elsif state == Towel::V1alpha::ResultState::FAILURE
    description = example.execution_result.exception.message
  end

  # Cannot make a gRPC call from a signal handler, so check to make sure
  # we aren't operating from one.
  unless @cancel_queue.closed?
    @session.update_result(
      group,
      example.id,
      state: state,
      duration: duration,
      description: description
    )
  end

  @stdout.context = nil
  @stderr.context = nil
end
example_started(notification) click to toggle source
# File lib/towel/rspec/formatter.rb, line 57
def example_started(notification)
  example_group = notification.example.example_group
  example = notification.example
  group = example_group.described_class.to_s + example_group.description

  context = @session.create_result(
    group,
    example.id,
    display_name: example.description
  )

  @stdout.context = context
  @stderr.context = context
end
start(_notification) click to toggle source
Calls superclass method
# File lib/towel/rspec/formatter.rb, line 31
def start(_notification)
  super

  url = @session.create_invocation
  puts "View test results at #{url}"

  # Register a cancellation handler
  old_handler = Signal.trap("INT") do
    @cancel_queue << true
    # Mark the queue as closed so that other observers can determine if
    # the run has been cancelled or not.
    @cancel_queue.close
    if old_handler.respond_to?(:call)
      old_handler.call
    else
      raise Interrupt
    end
  end

  # Capture logs
  @previous_stdout = $stdout
  $stdout = @stdout = Towel::LogIO.new(@session.create_log("STDOUT"))
  @previous_stderr = $stderr
  $stderr = @stderr = Towel::LogIO.new(@session.create_log("STDERR"))
end