=begin
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Parameters:
--------------------------------------------------------------------------------
=end
require 'date'
# This one is needed to get Time.parse() ????? Go figure.
require 'open-uri'
class OutputSuiteParser
attr :errors
attr :warnings
attr :start_time
attr :end_time
attr :elapsed_time
attr :suites
attr :tests
attr :overall_status
# ------------------------------------------------------------------------------------
private
# ------------------------------------------------------------------------------------
#
# Scan the log file for start time, end time, and the names of the suites that
# were run. Figure elapsed time also.
#
def parse_log_file()
@start_time = nil
@end_time = nil
@elapsed_time = "unknown"
@suite_names = []
File.open(@log_file) do |f|
f.each_line do |line|
md = %r{Start time: (.*)$}.match line
if md
@start_time = md[1]
end
md = %r{End time: (.*)$}.match line
if md
@end_time = md[1]
end
md = %r{Running suite (.*)$}.match line
if md
@suite_names << md[1]
end
md = %r{ERROR\s*(.*)}.match line
if md
@errors << md[1]
end
md = %r{WARN\s*(.*)}.match line
if md
@warnings << md[1]
end
end
end
if @start_time && @end_time
@elapsed_time = format_elapsed_time(@start_time, @end_time)
end
end
# Scan the output of a suite run.
#
def parse_suite_output(suite_name)
file_name = @output_manager.output_filename(suite_name)
s = SuiteInfo.new
s.name = suite_name
s.output_link = File.basename(file_name)
s.status = Status::GOOD
@suites << s
tests = []
begin
File.open(file_name) do |f|
f.each_line do |line|
md = %r{
([^<]*) |
}.match line
if md
t = TestInfo.new
t.test_name = md[3]
t.suite_name = s.name
t.output_link = s.output_link + md[2]
if md[1] == 'status_passed'
t.status = Status::GOOD
elsif @output_manager.ignore_test?(t.suite_name, t.test_name)
t.status = Status::FAIR
t.reason_for_ignoring = @output_manager.get_reason_for_ignoring(t.suite_name, t.test_name)
else
t.status = Status::BAD
end
tests << t
end
end
end
rescue Exception
log_error("Failed to parse output for suite '#{s.name}': #{$!}")
s.status = Status::BAD
end
s.status = get_worst_status(s.status, tests)
@tests = @tests.concat(tests)
end
# Look at the info from all of the suites and prepare summary info.
#
def collate_and_summarize()
status = Status::GOOD
status = Status::FAIR if !@warnings.empty?
status = Status::BAD if !@errors.empty?
@overall_status = get_worst_status(status, @suites)
end
# Find the worst status in an array of tests or suites
#
def get_worst_status(starting_status, statused)
worst = starting_status
statused.each do |s|
worst = s.status if s.status > worst
end
return worst
end
# Take two parsable time stamps and express the elapsed time as a string.
# Examples: 4h 37m 6.7s
# 15m 4s
# 55.6s
#
def format_elapsed_time(start_time_string, end_time_string)
start = Time.parse(start_time_string)
ender = Time.parse(end_time_string)
elapsed = ender - start
s = elapsed % 60
m = ((elapsed - s) / 60) % 60
h = (elapsed - s - (60 * m))/ 3600
elapsed_time = ""
elapsed_time << "#{h.to_i}h " if h > 0
elapsed_time << "#{m.to_i}m " if h > 0 || m > 0
elapsed_time << "#{s}s"
end
def log_error(message)
@output_manager.log("ERROR", message)
# By the time we get here, we've already scanned the log file for errors.
@errors << message
end
# ------------------------------------------------------------------------------------
public
# ------------------------------------------------------------------------------------
#
# Set up and get ready to process.
#
def initialize(output_manager, log_file)
@output_manager = output_manager
@log_file = log_file
@errors = []
@warnings = []
@suites = []
@tests = []
end
# Parse the output from each suite, and the log file, and munge it all together
# for easy access.
#
def parse()
parse_log_file()
@suite_names.each do |suite_name|
parse_suite_output(suite_name)
end
collate_and_summarize()
end
end