Skip to content

Commit

Permalink
Merge pull request #206 from dylanratcliffe/parallel_formatting
Browse files Browse the repository at this point in the history
Parallel formatting
  • Loading branch information
dylanratcliffe authored Mar 17, 2019
2 parents 32e75c7 + f41c438 commit 223ac02
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 40 deletions.
5 changes: 5 additions & 0 deletions features/run.feature
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Feature: Run rspec and acceptance test suites
When I run onceover command "run spec"
Then I should not see any errors

Scenario: Run correct spec tests in parallel
Given initialized control repo "basic"
When I run onceover command "run spec --parallel"
Then I should not see any errors

Scenario: Using regexes to define tests
Given initialized control repo "caching"
When I run onceover command "run spec"
Expand Down
107 changes: 77 additions & 30 deletions lib/onceover/rspec/formatters.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'rspec'
require 'pathname'

class OnceoverFormatter
Expand Down Expand Up @@ -53,6 +54,21 @@ def example_pending notification
def dump_failures notification
require 'onceover/controlrepo'

failures = extract_failures(notification)

# Put some spacing before the results
@output << "\n\n\n"

failures.each do |_name, role|
@output << Onceover::Controlrepo.evaluate_template('error_summary.yaml.erb', binding)
end

@output << "\n"
end

# This method takes a notification and formats it into a hash that can be
# printed easily
def extract_failures notification
# Group by role
grouped = notification.failed_examples.group_by { |e| e.metadata[:example_group][:parent_example_group][:description]}

Expand All @@ -61,17 +77,15 @@ def dump_failures notification
grouped[role] = failures.uniq { |f| f.metadata[:execution_result].exception.to_s }
end

# Put some spacing before the results
@output << "\n\n\n"

# Extract the errors and remove all RSpec objects
grouped.each do |role, failures|
role = {
grouped[role] = {
name: role,
errors: failures.map { |f| parse_errors(f.metadata[:execution_result].exception.to_s)}.flatten,
}

@output << Onceover::Controlrepo.evaluate_template('error_summary.yaml.erb', binding)
end

grouped
end

def parse_errors(raw_error)
Expand Down Expand Up @@ -140,8 +154,6 @@ def calculate_relative_source(file)
file.relative_path_from(tempdir + environmentpath + "production").to_s
end

private

# Below are defined the styles for the output
def class_name(text)
RSpec::Core::Formatters::ConsoleCodes.wrap(text, :bold)
Expand Down Expand Up @@ -189,34 +201,69 @@ def longest_group

end

# class OnceoverFormatterParallel < OnceoverFormatter
# require 'yaml'
class OnceoverFormatterParallel < OnceoverFormatter
require 'yaml'

RSpec::Core::Formatters.register self, :example_group_started,
:example_passed, :example_failed, :example_pending, :dump_failures

def example_group_started notification
# Do nothing
end

def example_passed notification
@output << green('P')
@output.flush
end

def example_failed notification
@output << red('F')
@output.flush
end

def example_pending notification
@output << yellow('?')
@output.flush
end

def dump_failures notification
# Create a random string
require 'securerandom'
random_string = SecureRandom.hex

# def example_group_started notification
# # Do nothing
# end
# Ensure that the folder exists
FileUtils.mkdir_p "#{RSpec.configuration.onceover_tempdir}/parallel"

# def example_passed notification
# @output << green('P')
# end
# Dump the notification to a unique file
File.open("#{RSpec.configuration.onceover_tempdir}/parallel/results-#{random_string}.yaml", "w") do |file|
file.write(extract_failures(notification).to_yaml)
end
end

# def example_failed notification
# @output << red('F')
# end
def output_results(directory)
require 'rspec/core/example'
# Read all yaml files
results = {}
files = Dir["#{directory}/*.yaml"]

# def example_pending notification
# @output << yellow('?')
# end
# Merge data
errors = files.reduce({}) do |errs, file|
# Read all files and merge them
errs.merge(YAML.load(File.read(file))) # rubocop:disable Security/YAMLLoad
end

# Delete files from the disk
files.each { |f| File.delete(f) }

# def dump_failures
# # TODO: This should write to a file and then get picked up and formatted by onceover itself
# # might need to use a module for the formatting
# require 'pry'
# binding.pry
# RSpec.configuration.onceover_tempdir
# end
@output << "\n\n\n"

# end
# Output errors
errors.each do |_name, role|
@output << Onceover::Controlrepo.evaluate_template('error_summary.yaml.erb', binding)
end
@output << "\n"
end
end

class FailureCollector
RSpec::Core::Formatters.register self, :dump_failures
Expand Down
15 changes: 6 additions & 9 deletions lib/onceover/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,12 @@ def run_spec!
logger.debug "Running #{@command_prefix}rake spec_standalone from #{@repo.tempdir}"
result = Backticks::Runner.new(interactive:true).run(@command_prefix.strip.split, 'rake', 'spec_standalone').join
end
# TODO: Refactor this to be much nicer
if @config.formatters.include? 'FailureCollector'
puts '----------- Summary of failures -----------'
if File.exist?("#{@repo.tempdir}/failures.out") and ! File.zero?("#{@repo.tempdir}/failures.out")
logger.debug "Reading failures from #{@repo.tempdir}/failures.out"
puts File.read("#{@repo.tempdir}/failures.out")
else
puts 'No failures detected'
end

# Print a summary if we were running ion parallel
if @config.formatters.include? 'OnceoverFormatterParallel'
require 'onceover/rspec/formatters'
formatter = OnceoverFormatterParallel.new(STDOUT)
formatter.output_results("#{repo.tempdir}/parallel")
end

# Finally exit and preserve the exit code
Expand Down
2 changes: 1 addition & 1 deletion lib/onceover/testconfig.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def initialize(file, opts = {})

# Set dynamic defaults for format
if opts[:format] == [:defaults]
@formatters = opts[:parallel] ? ['documentation', 'FailureCollector'] : ['OnceoverFormatter']
@formatters = opts[:parallel] ? ['OnceoverFormatterParallel'] : ['OnceoverFormatter']
else
@formatters = opts[:format]
end
Expand Down

0 comments on commit 223ac02

Please sign in to comment.