Files
2025-09-29 00:52:08 +02:00

269 lines
9.9 KiB
Ruby
Executable File

#
# File:: spit_error.rb
# Description:: Error filtration - success logic of a smoke test TTY dump.
#
# - Takes an input filename, parses it line by line piping what is deemed to be an error to stderr.
# - Further, everything that is not an error is piped to stdout.
# - File contents that are deemed warnings are wrapped with a warning syntax.
# - This is used by the smoke tester.
#
# Author:: Derek Ward <derek.ward@rockstarnorth.com>
# Date:: 16th October 2009
#
# Passed in :- filename to parse
# Passed out :- stderr contains all errors
# stdout for all other contents of file.
# Returns :- returns non zero upon detecting any errors
#-----------------------------------------------------------------------------
# Uses / Requires
#-----------------------------------------------------------------------------
#require 'pipeline/log/log'
require 'pipeline/os/getopt'
include Pipeline
#-----------------------------------------------------------------------------
# Constants
#-----------------------------------------------------------------------------
OPTIONS = [
[ "--help", "-h", Getopt::BOOLEAN, "display usage information." ],
[ "--errorsarenotfail", "-e", Getopt::BOOLEAN, "Does occurence of an error constitute a fail?" ],
[ "--callstack", "-c", Getopt::BOOLEAN, "display callstacks." ],
[ "--filename", "-f", Getopt::REQUIRED, "Filename to parse." ]
]
REGEXP_EXCEPTION = /(.+)(\*\*\* EXCEPTION |Exception:|detected an interrupt)(.+)/i
REGEXP_FATAL_ERROR = /(.+)(Fatal Error)(.+)/i
REGEXP_BASIC_ERROR = /(.+)(Error\s:|Error:\s)(.+)/i
REGEXP_WARNING = /(.+)(Warning:\s)(.+)/i
REGEXP_INFO = /(.+)\[AssetTest\]\s(.+)/i
REGEXP_START = /(.+)Smoke Test(.+)started\sDuration\s(-{0,1}\d+)\sCommandLine\s(.+)/i
REGEXP_STOP = /(.+)Smoke Test finished/i
REGEXP_DESC = /(.+)Smoke Test Description : (.+)/i
REGEXP_CALLSTACK = /(.+)\[35m(.+)/
REGEXP_CALLSTACK_EXCLUSION = /(.+)(- notfound|sysIpcThreadWrapper|CommonMain|ExceptMain|Main\(|rage::diagAssertHelper|rage::diagLog|mainCRTStartup)(.+)/
#-----------------------------------------------------------------------------
# Application entry point
#-----------------------------------------------------------------------------
colourise_callstack = "[colourise=grey]"
colourise_callstack_inside = "[colourise=red]"
colourise_outside = "[colourise=grey]"
colourise_info = "[colourise=black]"
colourise_ok = "[colourise=green]"
colourise_error = "[colourise=red]"
lines_read = 0
error_outside_count = 0
warning_outside_count = 0
error_inside_count = 0
warning_inside_count = 0
info_inside_count = 0
info_outside_count = 0
started = false
stopped = false
inside = "INSIDE SMOKETEST:"
outside = "OUTSIDE SMOKETEST:"
info = "INFO_MSG: "
context_msg_error = "#{colourise_info} ONLY ERRORS *DURING THE SMOKETEST* ARE USED TO DETERMINE IF THIS BUILD FAILED."
context_msg_no_error = "#{colourise_info} ERRORS WILL NOT MAKE THIS BUILD FAIL."
failed = 0
need_smoke_end = true
ignore = "ccignore:"
commandline = ""
description = nil
name = nil
duration = nil
errorsarefail = true
begin
#---------------------------------------------------------------------
# Parse Command Line.
#---------------------------------------------------------------------
opts, trailing = OS::Getopt.getopts( OPTIONS )
if ( opts['help'] )
puts OS::Getopt.usage( OPTIONS )
puts ("Press Enter to continue...")
$stdin.getc( )
exit( 1 )
end
if ( opts['errorsarenotfail'] )
errorsarefail = false
end
#---------------------------------------------------------------------
# Parse file.
#---------------------------------------------------------------------
if ( opts['filename'] )
filename = opts['filename']
lines = []
file = File.new(filename, "r")
while (line = file.gets)
lines << line
end
file.close
lines.each_with_index do |line,line_idx|
if ( line =~ REGEXP_START)
started = true
name = $2.to_s
duration = $3.to_i
commandline = $4.to_s
need_smoke_end = false if duration <= 0
end
if ( line =~ REGEXP_DESC)
description = $2.to_s
end
lines_read += 1
is_inside = (started and not stopped)
is_info = ( line =~ REGEXP_INFO or
line.include? "Player pos" or
line.include? "Camera pos" or
line.include? "Camera dir" or
line.include? "[Script_AUTOPLAY]")
is_warning = line =~ REGEXP_WARNING
is_error = ( line =~ REGEXP_EXCEPTION or
line =~ REGEXP_FATAL_ERROR or
line =~ REGEXP_BASIC_ERROR )
is_callstack = line =~ REGEXP_CALLSTACK
# determine if for an error or a warning?!
callstack_warning = ""
callstack_prefix = ""
callstack_colourise = ""
is_callstack = false if ( is_callstack and line =~ REGEXP_CALLSTACK_EXCLUSION )
is_callstack = false unless opts['callstack']
if (is_callstack and not (is_error or is_warning) )
callstack_colourise = colourise_callstack
callstack_colourise_inside = colourise_callstack_inside
lines[line_idx..-1].each do |search_line|
callstack_prefix = " ***CALLSTACK*** "
is_warning = ( search_line =~ REGEXP_WARNING )
is_error = ( search_line =~ REGEXP_EXCEPTION or
search_line =~ REGEXP_FATAL_ERROR or
search_line =~ REGEXP_BASIC_ERROR )
if (is_error)
break
elsif (is_warning)
callstack_warning = "Warning:"
break
end
end
if (not is_error and (not is_warning) )
is_error = true
end
end
if ( is_error )
if error_inside_count == 0 and error_outside_count == 0
if (not is_callstack)
$stderr.puts context_msg_error if errorsarefail
$stderr.puts context_msg_no_error unless errorsarefail
end
end
if ( is_inside )
$stderr.puts "#{callstack_colourise_inside} #{lines_read}: #{line}"
puts "#{callstack_colourise_inside} #{lines_read}: #{ignore} #{line}"
error_inside_count += 1 unless (is_callstack)
else
$stderr.puts "#{callstack_colourise}#{callstack_prefix}#{outside} #{colourise_outside} #{lines_read}: #{line}"
puts "#{callstack_colourise}#{callstack_prefix}#{outside} #{lines_read}: #{ignore} #{line}"
error_outside_count += 1 unless (is_callstack)
end
elsif ( is_warning )
if ( is_inside )
puts "#{callstack_colourise}#{callstack_prefix}#{inside} #{lines_read}: #{callstack_warning} #{line}"
warning_inside_count += 1 unless (is_callstack)
else
puts "#{callstack_colourise}#{callstack_prefix}#{outside} #{colourise_outside} #{lines_read}: #{callstack_warning} #{line}"
warning_outside_count += 1 unless (is_callstack)
end
elsif ( is_info )
if (is_inside )
puts "#{callstack_colourise}#{callstack_prefix}#{inside} #{info} #{colourise_info} #{lines_read}: #{line}"
info_inside_count += 1 unless (is_callstack)
else
puts "#{callstack_colourise}#{callstack_prefix}#{outside} #{colourise_outside} #{info} #{lines_read}: #{line}"
info_outside_count += 1 unless (is_callstack)
end
else
if (is_inside )
puts "#{callstack_colourise}#{callstack_prefix}#{inside} #{lines_read}: #{line}"
else
puts "#{callstack_colourise}#{callstack_prefix}#{outside} #{lines_read}: #{line}"
end
end
stopped = true if ( line =~ REGEXP_STOP )
end
failed = -1 if (error_inside_count > 0 and errorsarefail)
failed = -1 if not started
puts "#{info} #{colourise_info} ******** SMOKETEST SUMMARY ********"
puts "#{info} #{colourise_info} Smoke name : #{name}" if name
puts "#{info} #{colourise_info} Smoke description : #{description}" if description
puts "#{info} #{colourise_info} Smoke duration was ~#{duration} seconds." if duration
puts "#{info} #{colourise_info} Smoke has No end criteria." unless need_smoke_end
puts "#{info} #{colourise_info} Smoke has end criteria." if need_smoke_end
puts "#{info} #{colourise_info} Started #{started}, Stopped #{stopped}."
puts "#{info} #{colourise_info} Read #{lines_read} lines."
puts "#{info} #{colourise_info} CommandLine for repro: #{commandline}"
puts "#{info} #{colourise_info} Result (Outside of test) #{error_outside_count} errors #{warning_outside_count} warnings #{info_outside_count} infos. ( these do not effect the notion of success / failure in the build )"
puts "#{info} #{colourise_ok} **** THE SMOKE TEST RAN TO COMPLETION. ****" if started and stopped
if not started
$stderr.puts "Error: **** THE SMOKE TEST DID NOT START. ****"
puts "Error: #{ignore} **** THE SMOKE TEST DID NOT START. ****"
puts "#{info} #{colourise_error} **** THE SMOKE TEST DID NOT START. ****"
failed = -1
end
if need_smoke_end and started and not stopped
$stderr.puts "Error: **** THE SMOKE TEST STARTED BUT DID NOT COMPLETE. ****"
puts "Error: #{ignore} **** THE SMOKE TEST STARTED BUT DID NOT COMPLETE. ****"
puts "#{info} #{colourise_error} **** THE SMOKE TEST STARTED BUT DID NOT COMPLETE. ****"
failed = -1
end
colour = (error_inside_count>0 and errorsarefail) ? "#{colourise_error}" : "#{colourise_info}"
str = errorsarefail ? "" : "( these do not effect the notion of success / failure in the build )"
puts "#{info} #{colour} Result (INSIDE of test) #{error_inside_count} errors #{warning_inside_count} warnings #{info_inside_count} infos. #{str}"
puts "#{info} #{colourise_ok} BUILD OK" if failed == 0
puts "#{info} #{colourise_error} BUILD FAILED" unless failed == 0
puts "#{info} #{colourise_info} ******** END SMOKETEST SUMMARY ********"
end
rescue Exception => ex
$stderr.puts "Unhandled exception: #{ex.message}"
$stderr.puts "Backtrace:"
ex.backtrace.each { |m| $stderr.puts "\t#{m}" }
exit -1
end
exit failed