Skip to content

Instantly share code, notes, and snippets.

@kirkelifson
Last active March 31, 2019 03:45
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 kirkelifson/b4054457fb583f5771e91613d1cef14c to your computer and use it in GitHub Desktop.
Save kirkelifson/b4054457fb583f5771e91613d1cef14c to your computer and use it in GitHub Desktop.
rspec all day - simple test runner for finding fragile tests
#!/usr/bin/env ruby
require 'json'
require 'awesome_print'
require 'colorize'
class SpecRunner
FILE_NAME = "spec_run_#{Time.now.strftime("%H%M%S_%m%d%y_%Z")}.log"
TEST_LOG_FILE = 'log/test.log'.freeze
LOG_FILE_SIZE_LIMIT = 500
attr_reader :results, :summary, :failure_count
def new
@results = nil
@summary = nil
@failure_count = 0
@duration = 0
end
def run
@results ||= parse_results(rspec)
@summary ||= summarize
@failure_count = @summary['failures'] || @summary['failure'] || 0
@duration = @results.dig('summary', 'duration').round
log_failures if @failure_count.nonzero?
scrub_rails_log if log_reached_size_limit?
print_run_time
end
def rspec
`NO_COVERAGE=true rspec -fj #{ARGV.join(' ')} 2> /dev/null`
end
def parse_results(output)
JSON.parse(output)
rescue JSON::ParserError
puts '[!] Could not parse rspec JSON output, exiting'.red
exit
end
def summarize
keys = []
summary_line = @results['summary_line'].split(',').map do |result|
result.strip!
keys << result[/[a-z]+/]
result[/\d+/].to_i
end
[keys, summary_line].transpose.to_h
end
def log_failures
failures = @results['examples'].select do |example|
example['status'] == 'failed'
end
open(FILE_NAME, 'a') do |file|
puts "[!] Logging #{failure_count} failures".red
file.puts(@results)
end
puts failures.map { |failure| "\t#{failure['id']}\n" }
end
def log_size
File.size(TEST_LOG_FILE) / 2**20
end
def log_reached_size_limit?
log_size > LOG_FILE_SIZE_LIMIT
end
def scrub_rails_log
puts '[+] Cleaning up test log files'.yellow
File.delete(TEST_LOG_FILE)
end
def print_run_time
puts "Run time: #{@duration} seconds, #{(@duration / 60.0).round(2)} minutes\n\n"
end
end
def shutdown
puts '[+] Shutting down gracefully'.yellow
$running = false
end
trap("INT") { shutdown }
def clean_database
puts '[+] Starting reset of the test database'
`RAILS_ENV=test rake db:schema:load 2> /dev/null`
puts '[+] Reset the test database'.green
end
$running = true
$iteration = 1
def run
begin
runner = SpecRunner.new
puts "[+] Started rspec run ##{$iteration}"
runner.run
puts "[+] Finished rspec run ##{$iteration}".green
$iteration += 1
rescue SystemExit, Interrupt
end
end
clean_database
run while $running
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment