#!/usr/bin/perl # -*- Mode: Perl; tab-width: 4; indent-tabs-mode: nil; -*- # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is Mozilla JavaScript Testing Utilities # # The Initial Developer of the Original Code is # Mozilla Corporation. # Portions created by the Initial Developer are Copyright (C) 2007 # the Initial Developer. All Rights Reserved. # # Contributor(s): Bob Clary # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** use strict; use Getopt::Mixed "nextOption"; # predeclarations sub debug; sub usage; sub parse_options; sub escape_string; sub escape_pattern; sub unescape_pattern; # option arguments my $option_desc = "b=s branch>b T=s buildtype>T R=s repo>R t=s testtype>t o=s os>o K=s kernel>K A=s arch>A M=s memory>M S=s speed>S z=s timezone>z J=s jsoptions>J l=s rawlogfile>l f=s failurelogfile>f r=s patterns>r O=s outputprefix>O D debug>D"; my $testid; my $branch; my $repo; my $buildtype; my $testtype; my $rawlogfile; my $failurelogfile; my $os; my $patterns; my $timezone; my $jsoptions; my $outputprefix; my $arch; my $kernel; my $memory; my $cpuspeed; my $debug = $ENV{DEBUG}; # pattern variables my $knownfailurebranchpattern; my $failurebranchpattern; my $knownfailureospattern; my $failureospattern; my $knownfailurerepopattern; my $failurerepopattern; my $knownfailurebuildtypepattern; my $failurebuildtypepattern; my $knownfailuretesttypepattern; my $failuretesttypepattern; my $knownfailuretimezonepattern; my $failuretimezonepattern; my $knownfailurejsoptionspattern; my $failurejsoptionspattern; my $knownfailurearchpattern; my $failurearchpattern; my $knownfailurekernelpattern; my $failurekernelpattern; my $knownfailurememorypattern; my $failurememorypattern; my $knownfailurecpuspeedpattern; my $failurecpuspeedpattern; my @patterns; my $pattern; my @failures; my @fixes; my @excludedtests; my $excludedtest; my $excludedfile; my %includedtests = {}; my $includedfile; my @results; my $regchars = '\[\^\-\]\|\{\}\?\*\+\.\<\>\$\(\)'; &parse_options; my $jsdir = $ENV{TEST_JSDIR}; if (!defined($jsdir)) { $jsdir = "/work/mozilla/mozilla.com/test.mozilla.com/www/tests/mozilla.org/js"; } my @excludedfiles = ("excluded-$branch-$testtype-$buildtype.tests"); my @includedfiles = ("included-$branch-$testtype-$buildtype.tests"); # create working patterns file consisting of matches to users selection # and which has the test description patterns escaped # remove the excluded tests from the possible fixes log foreach $excludedfile ( @excludedfiles ) { open EXCLUDED, "<$jsdir/$excludedfile" or die "Unable to open excluded file $jsdir/$excludedfile: $!\n"; while () { chomp; next if ($_ =~ /^\#/); s/\s+$//; push @excludedtests, ($_); } close EXCLUDED; } @excludedtests = sort @excludedtests; foreach $includedfile ( @includedfiles ) { open INCLUDED, "<$jsdir/$includedfile" or die "Unable to open included file $jsdir/$includedfile: $!\n"; while () { chomp; next if ($_ =~ /^\#/); s/\s+$//; $includedtests{$_} = 1; } close INCLUDED; } debug "loading patterns $patterns"; debug "pattern filter: ^TEST_ID=[^,]*, TEST_BRANCH=$knownfailurebranchpattern, TEST_REPO=$knownfailurerepopattern, TEST_BUILDTYPE=$knownfailurebuildtypepattern, TEST_TYPE=$knownfailuretesttypepattern, TEST_OS=$knownfailureospattern, TEST_KERNEL=$knownfailurekernelpattern, TEST_PROCESSORTYPE=$knownfailurearchpattern, TEST_MEMORY=$knownfailurememorypattern, TEST_CPUSPEED=$knownfailurecpuspeedpattern, TEST_TIMEZONE=$knownfailuretimezonepattern, TEST_OPTIONS=$knownfailurejsoptionspattern,"; open PATTERNS, "<$patterns" or die "Unable to open known failure patterns file $patterns: $!\n"; while () { chomp; s/\s+$//; ($testid) = $_ =~ /^TEST_ID=([^,]*),/; if (!$includedtests{$testid}) { debug "test $testid was not included during this run"; } elsif ($_ =~ /^TEST_ID=[^,]*, TEST_BRANCH=$knownfailurebranchpattern, TEST_REPO=$knownfailurerepopattern, TEST_BUILDTYPE=$knownfailurebuildtypepattern, TEST_TYPE=$knownfailuretesttypepattern, TEST_OS=$knownfailureospattern, TEST_KERNEL=$knownfailurekernelpattern, TEST_PROCESSORTYPE=$knownfailurearchpattern, TEST_MEMORY=$knownfailurememorypattern, TEST_CPUSPEED=$knownfailurecpuspeedpattern, TEST_TIMEZONE=$knownfailuretimezonepattern, TEST_OPTIONS=$knownfailurejsoptionspattern,/) { debug "adding pattern : $_"; push @patterns, (escape_pattern($_)); } else { debug "skipping pattern: $_"; } } close PATTERNS; # create a working copy of the current failures which match the users selection debug "failure filter: ^TEST_ID=[^,]*, TEST_BRANCH=$failurebranchpattern, TEST_REPO=$failurerepopattern, TEST_BUILDTYPE=$failurebuildtypepattern, TEST_TYPE=$failuretesttypepattern, TEST_OS=$failureospattern, TEST_KERNEL=$failurekernelpattern, TEST_PROCESSORTYPE=$failurearchpattern, TEST_MEMORY=$failurememorypattern, TEST_CPUSPEED=$failurecpuspeedpattern, TEST_TIMEZONE=$failuretimezonepattern, TEST_OPTIONS=$failurejsoptionspattern, TEST_RESULT=FAIL[^,]*,/"; if (defined($rawlogfile)) { $failurelogfile = "$outputprefix-results-failures.log"; my $alllog = "$outputprefix-results-all.log"; debug "writing failures $failurelogfile"; open INPUTLOG, "$jsdir/post-process-logs.pl $rawlogfile |" or die "Unable to open $rawlogfile $!\n"; open ALLLOG, ">$alllog" or die "Unable to open $alllog $!\n"; open FAILURELOG, ">$failurelogfile" or die "Unable to open $failurelogfile $!\n"; while () { chomp; print ALLLOG "$_\n"; if ($_ =~ /^TEST_ID=[^,]*, TEST_BRANCH=$failurebranchpattern, TEST_REPO=$failurerepopattern, TEST_BUILDTYPE=$failurebuildtypepattern, TEST_TYPE=$failuretesttypepattern, TEST_OS=$failureospattern, TEST_KERNEL=$failurekernelpattern, TEST_PROCESSORTYPE=$failurearchpattern, TEST_MEMORY=$failurememorypattern, TEST_CPUSPEED=$failurecpuspeedpattern, TEST_TIMEZONE=$failuretimezonepattern, TEST_OPTIONS=$failurejsoptionspattern, TEST_RESULT=FAIL[^,]*,/) { debug "failure: $_"; push @failures, ($_); print FAILURELOG "$_\n"; } } close INPUTLOG; my $inputrc = $?; close ALLLOG; close FAILURELOG; die "FATAL ERROR in post-process-logs.pl" if $inputrc != 0; } else { debug "loading failures $failurelogfile"; my $failurelogfilemode; if ($failurelogfile =~ /\.bz2$/) { $failurelogfilemode = "bzcat $failurelogfile|"; } elsif ($failurelogfile =~ /\.gz$/) { $failurelogfilemode = "zcat $failurelogfile|"; } else { $failurelogfilemode = "<$failurelogfile"; } open FAILURES, "$failurelogfilemode" or die "Unable to open current failure log $failurelogfile: $!\n"; while () { chomp; if ($_ =~ /^TEST_ID=[^,]*, TEST_BRANCH=$failurebranchpattern, TEST_REPO=$failurerepopattern, TEST_BUILDTYPE=$failurebuildtypepattern, TEST_TYPE=$failuretesttypepattern, TEST_OS=$failureospattern, TEST_KERNEL=$failurekernelpattern, TEST_PROCESSORTYPE=$failurearchpattern, TEST_MEMORY=$failurememorypattern, TEST_CPUSPEED=$failurecpuspeedpattern, TEST_TIMEZONE=$failuretimezonepattern, TEST_OPTIONS=$failurejsoptionspattern, TEST_RESULT=FAIL[^,]*,/) { debug "failure: $_"; push @failures, ($_); } } close FAILURES; } debug "finding fixed bugs"; unlink "$outputprefix-results-possible-fixes.log"; foreach $pattern (@patterns) { # look for known failure patterns that don't have matches in the # the current failures selected by the user. debug "searching for matches to $pattern\n"; @results = grep m@^$pattern@, @failures; if ($debug) { my $failure; foreach $failure (@failures) { if ($failure =~ $pattern) { debug "MATCH: $pattern - $failure\n"; } else { debug "NOMATCH: $pattern - $failure\n"; } } } if ($#results == -1) { debug "fix: '$pattern'"; push @fixes, ($pattern) } } foreach $excludedtest ( @excludedtests ) { # remove any potential fixes which are due to the test being excluded if ($debug) { @results = grep m@$excludedtest@, @fixes; if ($#results > -1) { print "excluding: " . (join ', ', @results) . "\n"; } } @results = grep !m@$excludedtest@, @fixes; @fixes = @results; } my $fix; open OUTPUT, ">$outputprefix-results-possible-fixes.log" or die "Unable to open $outputprefix-results-possible-fixes.log: $!"; foreach $fix (@fixes) { print OUTPUT unescape_pattern($fix) . "\n"; if ($debug) { debug "fix: $fix"; } } close OUTPUT; print STDOUT "log: $outputprefix-results-possible-fixes.log\n"; debug "finding regressions"; my $pass = 0; my $changed = ($#patterns != -1); debug "changed=$changed, \$#patterns=$#patterns, \$#failures=$#failures"; while ($changed) { $pass = $pass + 1; $changed = 0; debug "pass $pass"; foreach $pattern (@patterns) { debug "Pattern: $pattern"; my @nomatches = grep !m@^$pattern@, @failures; my @matches = grep m@^$pattern@, @failures; if ($debug) { my $temp = join ', ', @nomatches; debug "nomatches: $#nomatches $temp"; $temp = join ', ', @matches; debug "matches: $#matches $temp"; } @failures = @nomatches; if ($#matches > -1) { $changed = 1; } debug "*****************************************"; } } debug "\$#excludedtests=$#excludedtests, \$#failures=$#failures"; foreach $excludedtest ( @excludedtests ) { if ($debug) { @results = grep m@$excludedtest@, @failures; if ($#results > -1) { print "excluding: " . (join ', ', @results) . "\n"; } } @results = grep !m@$excludedtest@, @failures; debug "\$#results=$#results, \$excludedtest=$excludedtest, \$#failures=$#failures"; @failures = @results; } debug "possible regressions: \$#failures=$#failures"; open OUTPUT, ">$outputprefix-results-possible-regressions.log" or die "Unable to open $outputprefix-results-possible-regressions.log: $!"; my $failure; foreach $failure (@failures) { print OUTPUT "$failure\n"; if ($debug) { debug "regression: $failure"; } } close OUTPUT; print STDOUT "log: $outputprefix-results-possible-regressions.log\n"; sub debug { if ($debug) { my $msg = shift; print STDERR "DEBUG: $msg\n"; } } sub usage { my $msg = shift; print STDERR <