sl@0: # Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: # All rights reserved. sl@0: # This component and the accompanying materials are made available sl@0: # under the terms of "Eclipse Public License v1.0" sl@0: # which accompanies this distribution, and is available sl@0: # at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: # sl@0: # Initial Contributors: sl@0: # Nokia Corporation - initial contribution. sl@0: # sl@0: # Contributors: sl@0: # sl@0: # Description: sl@0: # sl@0: sl@0: use strict; sl@0: use LWP::Simple; sl@0: use TestScriptResults; sl@0: use Getopt::Std; sl@0: use File::Find; sl@0: sl@0: # Mistral tags the result files from test scripts in a particular format, depending on the test harness used to execute them. sl@0: # We use these names to identify which files are results files. sl@0: my $KMistralCoreConfFileName = "-coreconf-"; sl@0: my $KMistralTEFFileName = "-testexecute-"; sl@0: my $KMistralTestFrameworkFileName = "-testframework"; # No trailing hyphen due to different security variants sl@0: sl@0: # It appears that Mistral uses a completely different file format for results from HW runs sl@0: my $KMistrealTEFFileNameHW = "testexecute"; sl@0: my $KMistrealTFFileNameHW1 = "testframework"; sl@0: my $KMistrealTFFileNameHW2 = "testframeworkmmddcap"; sl@0: my $KMistrealTFFileNameHW3 = "testframeworkuecap"; sl@0: my $KMistrealTFFileNameHW4 = "testframeworknone"; sl@0: sl@0: # Work in progress script outputs. sl@0: my $iKnownFails; sl@0: my $iUnknownFailsButKnownInRef; sl@0: my $iUnknownFailsButKnownInOtherCodelines; sl@0: my $iUnknownFails; sl@0: my $iMissingTests; sl@0: sl@0: my $iVerbose; sl@0: sl@0: ############################################### sl@0: ## Source test domain specific functionality sl@0: ############################################### sl@0: # Scans the test results summary page from the Mistral build and compiles a collection of the sl@0: # URL paths for the log files. sl@0: # param1 - the URL to the Test Results HTML Summary page of the Mistral build sl@0: # returns - the array of logs' URLS sl@0: sub GetResultFilesFromMistral sl@0: { sl@0: my $aMistralTestResultsSummaryUrl = shift; sl@0: sl@0: my @fileNames; sl@0: my $nextFileNamesIndex = 0; sl@0: sl@0: my $summaryContents = get "$aMistralTestResultsSummaryUrl"; # Returns undef if failure sl@0: unless ($summaryContents) sl@0: { sl@0: print "\nERROR: Unable to retrieve source summary file from $aMistralTestResultsSummaryUrl\n"; sl@0: exit; sl@0: } sl@0: sl@0: #Could add an optimisation to this to search for the tag BUT doesn't take into account the crashed tests and would need to check here the pass/fail count sl@0: #In addition this might lead to migration problems with Sirroco and certainly isn't appliable to developer's personal builds where we must scan each file sl@0: #So it's simpler to do the brute force approach and keep all implementations alike, it doesn't take long anyway sl@0: while ($summaryContents =~ s/href="(.*?($KMistralCoreConfFileName|$KMistralTEFFileName|$KMistralTestFrameworkFileName).*?\.html?)"//i) sl@0: { sl@0: $fileNames[$nextFileNamesIndex] = $1; sl@0: $nextFileNamesIndex++; sl@0: } sl@0: sl@0: # Scan this second so we don't accidentally cut off the filenames if they are matched against Winscw runs sl@0: while ($summaryContents =~ s/href="(.*?($KMistrealTEFFileNameHW|$KMistrealTFFileNameHW1|$KMistrealTFFileNameHW2|$KMistrealTFFileNameHW3|$KMistrealTFFileNameHW4).*?\.html?)"//i) sl@0: { sl@0: $fileNames[$nextFileNamesIndex] = $1; sl@0: $nextFileNamesIndex++; sl@0: } sl@0: sl@0: unless ($fileNames[0]) sl@0: { sl@0: print "\nERROR: No test result log files found, please ensure the -s parameter points to Mistral's TestResults.html summary page\n"; sl@0: exit; sl@0: } sl@0: sl@0: return @fileNames; sl@0: } sl@0: sl@0: # Parse the Mistral test results summary page and generate an array of TestScriptResults sl@0: # objects which contain all the required information such as script names, test counts sl@0: # and failures. sl@0: # param1 - the URL of the Test Results HTML Summary page for the Mistral build sl@0: # returns - the array of parsed log data sl@0: sub PopulateResultsArrayFromMistral sl@0: { sl@0: my $aTestResultsSummaryPageUrl = shift; sl@0: my @aResultsArray = (); sl@0: my $nextFreeIndexInResultsArray = 0; sl@0: sl@0: my @fileNames = GetResultFilesFromMistral($aTestResultsSummaryPageUrl); sl@0: foreach my $fileName (@fileNames) sl@0: { sl@0: my $testFileContents = get "$fileName"; sl@0: unless ($testFileContents) sl@0: { sl@0: print "\nERROR: Unable to open logfile $fileName\n"; sl@0: next; sl@0: } sl@0: sl@0: my $scriptResults = TestScriptResults->TestScriptResults(); sl@0: $scriptResults->SetFilePath($fileName); sl@0: if (($fileName =~ m/.*?$KMistralTEFFileName(.*?)\.html?/i) || ($fileName =~ m/.*?$KMistrealTEFFileNameHW(.*?)\.html?/i)) sl@0: { sl@0: $scriptResults->SetScriptName($1); sl@0: if (!($testFileContents =~ m/TEST CASE SUMMARY:/i) && ($testFileContents =~ m/SUMMARY:/i)) sl@0: { sl@0: # One of the old MM TEF tests which didn't use testcases sl@0: $scriptResults->TEFNoTestcasesTest(); sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 0); sl@0: } sl@0: else sl@0: { sl@0: $scriptResults->TEFTest(); sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 1); sl@0: } sl@0: } sl@0: elsif ($fileName =~ m/.*?$KMistralCoreConfFileName(.*?)\.txt\.html?/i) sl@0: { sl@0: $scriptResults->SetScriptName($1); sl@0: $scriptResults->CoreConfTest(); sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanCoreConfLogFileForFailures($scriptResults, \$testFileContents); sl@0: } sl@0: elsif (($fileName =~ m/.*?$KMistralTestFrameworkFileName[^\-]*?\-(.*?)\.html?/i) || ($fileName =~ m/.*?$KMistrealTFFileNameHW2(.*?)\.html?/i) || ($fileName =~ m/.*?$KMistrealTFFileNameHW3(.*?)\.html?/i) || ($fileName =~ m/.*?$KMistrealTFFileNameHW4(.*?)\.html?/i) || ($fileName =~ m/.*?$KMistrealTFFileNameHW1(.*?)\.html?/i)) sl@0: { sl@0: $scriptResults->SetScriptName($1); sl@0: $scriptResults->TestFrameworkTest(); sl@0: sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanTestFrameworkLogFileForFailures($scriptResults, \$testFileContents); sl@0: } sl@0: else sl@0: { sl@0: print "\nWARNING: Results file has unrecognised format - $fileName.\n"; sl@0: } sl@0: $nextFreeIndexInResultsArray++; sl@0: } sl@0: sl@0: return \@aResultsArray; sl@0: } sl@0: sl@0: sl@0: # Walk the file path provided by the developer for his local machine, parse test logs sl@0: # and generate an array of TestScriptResults objects which contain all the required sl@0: # information such as script names, test counts and failures. sl@0: # param1 - the pathname of a folder containing the test results sl@0: # returns - the array of parsed log data sl@0: sub PopulateResultsArrayFromLocalMachine sl@0: { sl@0: my $aTestResultsPath = shift; sl@0: my @aResultsArray = (); sl@0: my $nextFreeIndexInResultsArray = 0; sl@0: sl@0: my @directories = ("$aTestResultsPath"); sl@0: my @fileNames; sl@0: find( sub { push @fileNames, $File::Find::name if /\.html?$/ }, @directories ); sl@0: sl@0: foreach my $fileName (@fileNames) sl@0: { sl@0: my $testFileContents = do { local $/; open(I,"$fileName"); }; sl@0: my $scriptResults = TestScriptResults->TestScriptResults(); sl@0: $scriptResults->SetFilePath($fileName); sl@0: $fileName =~ m/([^\\\/\.]*)\.[^\\\/]*\Z/; sl@0: $scriptResults->SetScriptName($1); sl@0: sl@0: if ($testFileContents =~ m/Core Loader Conformance Suite/) sl@0: { sl@0: $scriptResults->CoreConfTest(); sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanCoreConfLogFileForFailures($scriptResults, \$testFileContents); sl@0: } sl@0: elsif ($testFileContents =~ m/TestFrameworkMain.cpp/) sl@0: { sl@0: $scriptResults->TestFrameworkTest(); sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanTestFrameworkLogFileForFailures($scriptResults, \$testFileContents); sl@0: } sl@0: elsif ($testFileContents =~ m/TEF Version/) sl@0: { sl@0: if ($testFileContents =~ m/TEST CASE SUMMARY:/i) sl@0: { sl@0: $scriptResults->TEFTest(); sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 1); sl@0: } sl@0: else sl@0: { sl@0: # One of the old MM TEF tests which didn't use testcases sl@0: $scriptResults->TEFNoTestcasesTest(); sl@0: $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 0); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: print "\nWARNING: Results file has unrecognised format - $fileName.\n"; sl@0: } sl@0: sl@0: $nextFreeIndexInResultsArray++; sl@0: } sl@0: sl@0: return \@aResultsArray; sl@0: } sl@0: sl@0: ############################################### sl@0: ## Test harness specific functionality sl@0: ############################################### sl@0: sl@0: # Parses a TF log file for failures, inconclusives and crashes sl@0: # param1 - the TestScriptResults object to populate sl@0: # param2 - reference to the contents of the log file sl@0: # returns - the TestScriptResults object containing the parsed data sl@0: sub ScanTestFrameworkLogFileForFailures sl@0: { sl@0: my ($aScriptResults, $aLogFileContents) = @_; sl@0: sl@0: my $testFileContents = $$aLogFileContents; sl@0: my $numberOfTests = 0; sl@0: # Search for test case results, which take the following form: sl@0: #04/09/2002 15:51:39:772 V Log.cpp 736 Test Result for TSI_ICL_BTRANS_01:MM_ICL_BTRANS_I_0202_CP is PASS sl@0: while ($testFileContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:([\_|\-|\S]+)[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: { sl@0: my $testId = $1; sl@0: my $result = $2; sl@0: $numberOfTests++; sl@0: if ($result =~ /PASS/) sl@0: { sl@0: # Do nothing sl@0: } sl@0: elsif ($result =~ /INCONCLUSIVE/) sl@0: { sl@0: $aScriptResults->AddInconclusiveResult($testId); sl@0: } sl@0: else sl@0: { sl@0: # Treat all other results as failure sl@0: $aScriptResults->AddFailureResult($testId); sl@0: } sl@0: } sl@0: $aScriptResults->SetTotalTestCount($numberOfTests); sl@0: sl@0: unless ($testFileContents =~ m/Test Results Summary/) sl@0: { sl@0: # Test file summary not in the log file - the test has crashed sl@0: $aScriptResults->TestCrashed(); sl@0: } sl@0: sl@0: return $aScriptResults; sl@0: } sl@0: sl@0: # Parses a TEF log file for failures, inconclusives and crashes sl@0: # param1 - the TestScriptResults object to populate sl@0: # param2 - reference to the contents of the log file sl@0: # param3 - boolean whether the test is using testcases (older MM tests didn't, in which case we use the test steps) sl@0: # returns - the TestScriptResults object containing the parsed data sl@0: sub ScanTEFLogFileForFailures sl@0: { sl@0: my ($aScriptResults, $aLogFileContents, $aTestcasesInUse) = @_; sl@0: sl@0: my $testFileContents = $$aLogFileContents; sl@0: my $numberOfTests = 0; sl@0: sl@0: # Search for test case results, which take the following form: sl@0: # 02:56:42:145 c:\mm\tsu_3gp_compose_api_te.script Line = 58 Command = END_TESTCASE MM-3GP-COMP-U-0003-CP ***TestCaseResult = PASS sl@0: # Or if testcases not in use in this script file test step results, which take the following form: sl@0: # 14:20:51:459 c:\mm\tsu_mmf_aclnt_securedrmtestdata.script Line = 36 Command = RUN_TEST_STEP 1000 RTAUtils ImportDrmArchive c:\mm\tsu_mmf_aclnt_securedrmtestdata.ini ImportSmallWavDrmArchiveAudio ***Result = UNEXECUTED sl@0: while (($testFileContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+([\_|\-|\S]+)[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: || (!$aTestcasesInUse && ($testFileContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+([\_|\-|\S]+)[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//))) sl@0: { sl@0: my $testId = $1; sl@0: my $result = $2; sl@0: $numberOfTests++; sl@0: if ($result =~ /PASS/) sl@0: { sl@0: # Do nothing sl@0: } sl@0: elsif ($result =~ /INCONCLUSIVE/) sl@0: { sl@0: $aScriptResults->AddInconclusiveResult($testId); sl@0: } sl@0: else sl@0: { sl@0: # Treat all other results as failure sl@0: $aScriptResults->AddFailureResult($testId); sl@0: } sl@0: } sl@0: $aScriptResults->SetTotalTestCount($numberOfTests); sl@0: sl@0: # Testcase scripts use TEST CASE SUMMARY, non-testcase scripts just use SUMMARY sl@0: unless ($testFileContents =~ m/SUMMARY:/) sl@0: { sl@0: # Test file summary not in the log file - the test has crashed sl@0: $aScriptResults->TestCrashed(); sl@0: } sl@0: sl@0: return $aScriptResults; sl@0: } sl@0: sl@0: # Parses a CoreConf log file for failures, inconclusives and crashes sl@0: # param1 - the TestScriptResults object to populate sl@0: # param2 - reference to the contents of the log file sl@0: # returns - the TestScriptResults object containing the parsed data sl@0: sub ScanCoreConfLogFileForFailures sl@0: { sl@0: my ($aScriptResults, $aLogFileContents) = @_; sl@0: my $testFileContents = $$aLogFileContents; sl@0: sl@0: if ($testFileContents =~ s/\*\*\*\s*?Summary of tests executed(.*\n)*//) sl@0: { sl@0: my $numberOfTests = 0; sl@0: sl@0: # Parse the summary listings sl@0: while($testFileContents =~ s/\*\*\*\s*?Passed tests:((.*\n)*?)\*\*\*\s*?Failed tests:.*\n((\*\*\*.*\n)*)//) sl@0: { sl@0: my $passingTests = $1; sl@0: my $failingTests = $3; sl@0: sl@0: # Passing tests sl@0: while ($passingTests =~ s/\*\*\*[\s]*?\S+[\s]*\n//) sl@0: { sl@0: $numberOfTests++; sl@0: } sl@0: sl@0: # Failing tests sl@0: while ($failingTests =~ s/\*\*\*[\s]*?(\S+)[\s]*\n//) sl@0: { sl@0: $aScriptResults->AddFailureResult($1); sl@0: $numberOfTests++; sl@0: } sl@0: } sl@0: sl@0: $aScriptResults->SetTotalTestCount($numberOfTests); sl@0: } sl@0: else sl@0: { sl@0: # Test file summary not in the log file - the test has crashed sl@0: $aScriptResults->TestCrashed(); sl@0: } sl@0: sl@0: return $aScriptResults; sl@0: } sl@0: sl@0: # Gets the test case count from a Test Execute Framework log file sl@0: # param1 - a reference to the contents of the TEF log file sl@0: #returns - The number of test cases in the script or -1 if the summary could not be found sl@0: sub GetTEFTestCount sl@0: { sl@0: my $aReferenceLogContents = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: sl@0: if ($refContents =~ m/TEST CASE SUMMARY:(.*\n)*?.*?PASS =\s*(\d*)(.*\n)*?.*?FAIL =\s*(\d*)(.*\n)*?.*?INCONCLUSIVE =\s*(\d*)/) sl@0: { sl@0: my $result = $2 + $4 + $6; sl@0: return $result; sl@0: } sl@0: sl@0: if ($refContents =~ m/SUMMARY:(.*\n)*?.*?PASS =\s*(\d*)(.*\n)*?.*?FAIL =\s*(\d*)(.*\n)*?.*?ABORT =\s*(\d*)(.*\n)*?.*?PANIC =\s*(\d*)(.*\n)*?.*?INCONCLUSIVE =\s*(\d*)(.*\n)*?.*?UNKNOWN =\s*(\d*)(.*\n)*?.*?UNEXECUTED =\s*(\d*)/) sl@0: { sl@0: # One of the MM tests that doesn't use testcases sl@0: my $result = $2 + $4 + $6 + $8 + $10 + $12 + $14; sl@0: return $result; sl@0: } sl@0: sl@0: # Summary not found, we crashed sl@0: return -1; sl@0: } sl@0: sl@0: # Gets the test count from a Test Framework log file sl@0: # param1 - a reference to the contents of the Test Framework log file sl@0: #returns - The number of test cases in the script or -1 if the summary could not be found sl@0: sub GetTestFrameworkTestCount sl@0: { sl@0: my $aReferenceLogContents = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: sl@0: unless ($refContents =~ m/Test Results Summary(.*\n)*?.*?Total\s*:(\d*)\s*\n/) sl@0: { sl@0: # Summary not found, we crashed sl@0: return -1; sl@0: } sl@0: return $2; sl@0: } sl@0: sl@0: # Gets the test count from an OpenMAX IL Core Conformance log file sl@0: # param1 - a reference to the contents of the Core Conformance log file sl@0: #returns - The number of test cases in the script or -1 if the summary could not be found sl@0: sub GetCoreConfTestCount sl@0: { sl@0: my $aReferenceLogContents = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: sl@0: unless ($refContents =~ m/\*\*\*\s*Summary of tests executed(.*\n)*?\*\*\*\s*Total :\s*(\d*)\s*\n/) sl@0: { sl@0: # Summary not found, we crashed sl@0: return -1; sl@0: } sl@0: return $2; sl@0: } sl@0: sl@0: # Scans a TEF log looking for the test specified and checks if it returned inconclusive sl@0: # param1 - the test name sl@0: # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref sl@0: # param3 - whether the TEF script uses testcases sl@0: # returns - 1 if it returned inconclusive, 0 otherwise sl@0: sub MatchingTEFInconclusiveResult sl@0: { sl@0: my $aInconclusive = shift; sl@0: my $aReferenceLogContents = shift; sl@0: my $aTestcasesInUse = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: if ($aTestcasesInUse) sl@0: { sl@0: if ($refContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+$aInconclusive[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: { sl@0: if ($1 eq "INCONCLUSIVE") sl@0: { sl@0: return 1; sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if ($refContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+$aInconclusive[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: { sl@0: if ($1 eq "INCONCLUSIVE") sl@0: { sl@0: return 1; sl@0: } sl@0: } sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: # Scans a TestFramework log looking for the test specified and checks if it returned inconclusive sl@0: # param1 - the test name sl@0: # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref sl@0: # returns - 1 if it returned inconclusive, 0 otherwise sl@0: sub MatchingTFInconclusiveResult sl@0: { sl@0: my $aInconclusive = shift; sl@0: my $aReferenceLogContents = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: if ($refContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:$aInconclusive[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: { sl@0: if ($1 eq "INCONCLUSIVE") sl@0: { sl@0: return 1; sl@0: } sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: # Scans a TEF log looking for the test specified and checks if it returned an error sl@0: # param1 - the test name sl@0: # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref sl@0: # param3 - whether the TEF script uses testcases sl@0: # returns - 1 if it returned an error, 0 otherwise sl@0: sub MatchingTEFErrorResult sl@0: { sl@0: my $aFail = shift; sl@0: my $aReferenceLogContents = shift; sl@0: my $aTestcasesInUse = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: sl@0: if ($aTestcasesInUse) sl@0: { sl@0: if (not $refContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+$aFail[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: { sl@0: return 0; sl@0: } sl@0: sl@0: if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE")) sl@0: { sl@0: return 0; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (not $refContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+$aFail[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: { sl@0: return 0; sl@0: } sl@0: sl@0: if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE")) sl@0: { sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: return 1; sl@0: } sl@0: sl@0: # Scans a TestFramework log looking for the test specified and checks if it returned an error sl@0: # param1 - the test name sl@0: # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref sl@0: # returns - 1 if it returned an error, 0 otherwise sl@0: sub MatchingTFErrorResult sl@0: { sl@0: my $aFail = shift; sl@0: my $aReferenceLogContents = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: if (not $refContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:$aFail[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//) sl@0: { sl@0: return 0; sl@0: } sl@0: sl@0: if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE")) sl@0: { sl@0: return 0; sl@0: } sl@0: sl@0: return 1; sl@0: } sl@0: sl@0: # N.B. VERY IMPORTANT that the log file is passed by reference. Core conf scripts can include numerous sl@0: # different tests that use the same test name so to avoid false positives from this function the sl@0: # substitution done in the comparison MUST affect the caller's copy of the log file. sl@0: sub MatchingCoreConfErrorResult sl@0: { sl@0: my $aFail = shift; sl@0: my $aReferenceLogContents = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: sl@0: if ($refContents =~ s/\*\*\*[\s]*$aFail[\s]*FAILED//) sl@0: { sl@0: return 1; sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: ############################################### sl@0: ## Failure comparison functions sl@0: ############################################### sl@0: sl@0: # The analysis takes an array of TestScriptResults, each storing the results of a test script's log file. sl@0: # It processes this list in stages looking for any scripts with errors and trying to match them against sl@0: # entries in a Known Failure sheet and/or comparison reference build. Whenever a match is found sl@0: # the error is removed from the TestScriptResults object, these essentially act as an object containing sl@0: # unresolved errors. When errors are matched their details are added to the corresponding text sl@0: # variables at the top of this file (e.g. iKnownFails). sl@0: sub AnalyseFailures sl@0: { sl@0: my ($aKFSheetLocation, $aReferenceMistralURL, $aIgnoreFailsNotInRef, $aResultsRef, $aKfPlatforms) = @_; sl@0: sl@0: my @results = @$aResultsRef; sl@0: sl@0: my $refContents = undef; sl@0: if ($aReferenceMistralURL) sl@0: { sl@0: $refContents = get "$aReferenceMistralURL"; # Returns undef if failure sl@0: unless ($refContents) sl@0: { sl@0: print "\nERROR: Unable to retrieve reference summary file from $aReferenceMistralURL\n"; sl@0: exit; sl@0: } sl@0: } sl@0: sl@0: my $kfSheetContents = undef; sl@0: if ($aKFSheetLocation) sl@0: { sl@0: unless ($aKFSheetLocation =~ m/\.xml\Z/i) sl@0: { sl@0: print "\nERROR: KF sheet ($aKFSheetLocation) does not appear to be in XML format, you should save the Excel worksheet as XML Spreadsheet 2003 format for input to this script.\n"; sl@0: exit; sl@0: } sl@0: $kfSheetContents = do { local $/; open(I,"$aKFSheetLocation"); }; sl@0: unless ($kfSheetContents) sl@0: { sl@0: print "\nERROR: Unable to open KF sheet at $aKFSheetLocation\n"; sl@0: exit; sl@0: } sl@0: } sl@0: sl@0: foreach my $scriptResults (@results) sl@0: { sl@0: my $scriptName = $scriptResults->ScriptName(); sl@0: sl@0: my $referenceResults = undef; sl@0: sl@0: # If a reference build was provided, find the corresponding log file sl@0: if ($refContents) sl@0: { sl@0: # We use substitution here because some of the coreconf test scripts sl@0: # have the same script name. This ensures we don't keep referencing sl@0: # against the same copy. We cannot do the comparison on the script sl@0: # path because this isn't resilient to adding new tests or cross domain sl@0: # comparisons. sl@0: # N.B. This assumes the test list ordering remains the same. sl@0: # N.B. The optional .txt is for Core Conf tests sl@0: $refContents =~ s/href="(.*?$scriptName(\.txt)?(\.script)?\.html?)"//; sl@0: my $file = $1; sl@0: if ($file eq undef) sl@0: { sl@0: if ($aIgnoreFailsNotInRef) sl@0: { sl@0: next; sl@0: } sl@0: print "\nWARNING: Unable to find $scriptName in Reference Build\n"; sl@0: } sl@0: else sl@0: { sl@0: $referenceResults = get "$file"; # returns undef on failure sl@0: unless ($referenceResults) sl@0: { sl@0: print "\nWARNING: Unable to open $scriptName ($file) in Reference Build\n"; sl@0: } sl@0: } sl@0: } sl@0: sl@0: my $refTestCrashed; sl@0: # Check the test count hasn't decreased sl@0: if ($referenceResults) sl@0: { sl@0: $refTestCrashed = CheckTestCount($scriptResults, \$referenceResults); sl@0: } sl@0: sl@0: if (not $scriptResults->AnyFailures()) sl@0: { sl@0: # No errors so move onto the next sl@0: next; sl@0: } sl@0: sl@0: if ($kfSheetContents) sl@0: { sl@0: ResolveFailuresAgainstKFSheet($scriptResults, \$kfSheetContents, $aKfPlatforms); sl@0: sl@0: if (not $scriptResults->AnyFailures()) sl@0: { sl@0: # All errors resolved against KF sheet so move onto the next sl@0: next; sl@0: } sl@0: } sl@0: sl@0: if ($referenceResults) sl@0: { sl@0: ResolveFailuresAgainstReferenceRun($scriptResults, $refTestCrashed, \$referenceResults); sl@0: sl@0: if (not $scriptResults->AnyFailures()) sl@0: { sl@0: # All errors resolved against reference run so move onto the next sl@0: next; sl@0: } sl@0: } sl@0: sl@0: # Unknown failures sl@0: $iUnknownFails = $iUnknownFails . "\n$scriptName\n"; sl@0: sl@0: my $inconText; sl@0: my @inconclusives = $scriptResults->Inconclusives(); sl@0: foreach my $inconclusive (@inconclusives) sl@0: { sl@0: $inconText = $inconText . "$inconclusive\n"; sl@0: } sl@0: my $failText; sl@0: my @failures = $scriptResults->Failures(); sl@0: foreach my $failure (@failures) sl@0: { sl@0: $failText = $failText . "$failure\n"; sl@0: } sl@0: sl@0: if ($inconText) sl@0: { sl@0: $iUnknownFails = $iUnknownFails . "INCONCLUSIVES:\n$inconText"; sl@0: } sl@0: if ($failText) sl@0: { sl@0: $iUnknownFails = $iUnknownFails . "FAILS:\n$failText"; sl@0: } sl@0: if ($scriptResults->DidItCrash()) sl@0: { sl@0: $iUnknownFails = $iUnknownFails . "CRASHED\n"; sl@0: } sl@0: } sl@0: sl@0: } sl@0: sl@0: # Will compare the test count of the test in question against the equivalent result from a reference build's log sl@0: # to detect if there has been a reduction in the total number of tests run as part of the script, unless that script sl@0: # has crashed. As a side effect the return value indicates whether the test in question crashed or not (saves sl@0: # having to scan it twice). sl@0: # param1 - the log results to compare against the reference build's run sl@0: # param2 - the contents of the reference build's corresponding test log sl@0: # returns = 1 if the reference script crashed and we were unable to compare the counts, 0 otherwise sl@0: sub CheckTestCount sl@0: { sl@0: my ($aTestResultsObject, $aReferenceLogContents) = @_; sl@0: sl@0: my $testHarness = $aTestResultsObject->TestHarness(); sl@0: my $refTestCount; sl@0: if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest)) sl@0: { sl@0: $refTestCount = GetTEFTestCount($aReferenceLogContents); sl@0: } sl@0: elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest) sl@0: { sl@0: $refTestCount = GetTestFrameworkTestCount($aReferenceLogContents); sl@0: } sl@0: else sl@0: { sl@0: $refTestCount = GetCoreConfTestCount($aReferenceLogContents); sl@0: } sl@0: sl@0: if ($refTestCount < 0) sl@0: { sl@0: # Reference test crashed sl@0: unless ($aTestResultsObject->DidItCrash()) sl@0: { sl@0: my $scriptName = $aTestResultsObject->ScriptName(); sl@0: print "\nWARNING: $scriptName crashed in the reference build, unable to compare test counts\n"; sl@0: } sl@0: return 1; sl@0: } sl@0: sl@0: my $testCount = $aTestResultsObject->TotalTestCount; sl@0: if ($testCount < $refTestCount) sl@0: { sl@0: unless ($aTestResultsObject->DidItCrash()) sl@0: { sl@0: my $testName = $aTestResultsObject->ScriptName(); sl@0: $iMissingTests = $iMissingTests . "$testName Previous = $refTestCount, Current = $testCount\n"; sl@0: } sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: # Will scan the Known Failure sheet for any entries indicating if the failures,inconclusives and/or crash sl@0: # witnessed in the script in question are already known. If so these will be appended to the known failures list sl@0: # and removed from the TestScriptResults object in question. If matching entries were found but existed for sl@0: # other codelines then this information is stored but the failures are not removed from the TestScriptResults sl@0: # object. sl@0: # param1 - TestScriptResults object for the script with failures sl@0: # param2 - the contents of the known failure sheet sl@0: # param3 - the array of platform entries in the known failure sheet that are applicable to this run sl@0: sub ResolveFailuresAgainstKFSheet sl@0: { sl@0: my ($aScriptWithProblems, $aKfSheetContents, $aKfPlatforms) = @_; sl@0: my $kfSheetContents = $$aKfSheetContents; sl@0: my $scriptName = $aScriptWithProblems->ScriptName(); sl@0: sl@0: my @kFApplicablePlatforms; sl@0: if ($aKfPlatforms) sl@0: { sl@0: # Will error if undef sl@0: @kFApplicablePlatforms = @$aKfPlatforms; sl@0: } sl@0: sl@0: # Modified version of the KF Sheet contents, at the end of this function it will contain the Rows from the KF Sheet with any that correspond to the current test script stripped out. sl@0: # This is a by product of the fact that we inspect each row one at a time looking for any that are relevant, trying to do a global search results in potentially error prone and difficult to maintain sl@0: # regexs. And in reality underneath Perl shouldn't be doing that much in the way of optimisation versus this approach. sl@0: my $wipKfSheet; sl@0: my $candidatesForOtherPlatforms; sl@0: my $foundSamePlatFails; sl@0: my $foundSamePlatInconcs; sl@0: my $foundSamePlatCrash; sl@0: while ($kfSheetContents =~ s/)((.|\n)*?)<\/Row>//i) sl@0: { sl@0: my $row = $3; sl@0: # Optimisation sl@0: unless ($row =~ m/$scriptName/i) sl@0: { sl@0: $wipKfSheet = $wipKfSheet . "$row<\/Row>"; sl@0: next; sl@0: } sl@0: sl@0: # None of the cells prior to the 'Scriptname' named cell are of any interest, now verify this row is actually for sl@0: # this test script and we didn't pick the hit up off the entries for one of the other fields, e.g. Remarks sl@0: my $applicable; sl@0: while ($row =~ s/()//i) sl@0: { sl@0: my $cell = $1; sl@0: if ($cell =~ m/$cell\n$row<\/Row>"; # This entry isn't applicable to us, reinsert it into the KF sheet sl@0: last; sl@0: } sl@0: } sl@0: } sl@0: unless ($applicable) sl@0: { sl@0: next; sl@0: } sl@0: sl@0: # We are now dealing with a Row corresponding to the script in question sl@0: # So pull out the relevant named cells contents sl@0: my $crash; sl@0: my $fails; sl@0: my $inconclusives; sl@0: my $targets; sl@0: while ($row =~ s/()//i) sl@0: { sl@0: my $cell = $1; sl@0: if ($cell =~ m//i)) # To ensure for example that All isn't picked up by an All Winscw entry sl@0: { sl@0: next; # Platform not found in the entry sl@0: } sl@0: $platformMatched = 1; sl@0: sl@0: if (($aScriptWithProblems->DidItCrash()) && ($crash =~ m/Crashed/i)) sl@0: { sl@0: $foundSamePlatCrash = 1; sl@0: $aScriptWithProblems->ResetCrashed(); sl@0: } sl@0: sl@0: if ($fails) sl@0: { sl@0: my @failures = $aScriptWithProblems->Failures(); sl@0: $aScriptWithProblems->ResetFailures(); sl@0: foreach my $failure (@failures) sl@0: { sl@0: if (($fails =~ m/$failure/i) || ($fails =~ m/>ALL<\/Data>/)) sl@0: { sl@0: $foundSamePlatFails = $foundSamePlatFails . "$failure\n"; sl@0: } sl@0: else sl@0: { sl@0: sl@0: $aScriptWithProblems->AddFailureResult($failure); sl@0: } sl@0: } sl@0: } sl@0: sl@0: if ($inconclusives) sl@0: { sl@0: my @incons = $aScriptWithProblems->Inconclusives(); sl@0: $aScriptWithProblems->ResetInconclusives(); sl@0: foreach my $incon (@incons) sl@0: { sl@0: if (($inconclusives =~ m/$incon/i) || ($inconclusives =~ m/>ALL<\/Data>/)) sl@0: { sl@0: $foundSamePlatInconcs = $foundSamePlatInconcs . "$incon\n"; sl@0: } sl@0: else sl@0: { sl@0: $aScriptWithProblems->AddInconclusiveResult($incon); sl@0: } sl@0: } sl@0: } sl@0: } # End of platform matching loop sl@0: sl@0: unless ($platformMatched) sl@0: { sl@0: # The row entry did not match any of the applicable platforms. We need to keep checking for more appropriate rows. sl@0: # However, if after the KF Sheet has been parsed we still have unknown errors, we need to compare against these rows as well sl@0: # in case the issue has been seen on other platforms. sl@0: sl@0: $candidatesForOtherPlatforms = $candidatesForOtherPlatforms . "$crash$fails$inconclusives<\/Row>"; sl@0: } sl@0: sl@0: } # End of row scanning sl@0: sl@0: sl@0: my $foundOtherPlatFails; sl@0: my $foundOtherPlatInconcs; sl@0: my $foundOtherPlatCrash; sl@0: if ($aScriptWithProblems->AnyFailures()) sl@0: { sl@0: # Failures remain, potentially matched against the rows for other platforms sl@0: sl@0: while ($candidatesForOtherPlatforms =~ s/((.|\n)*?)<\/Row>//i) sl@0: { sl@0: my $row = $1; sl@0: my $crash; sl@0: my $fails; sl@0: my $inconclusives; sl@0: while ($row =~ s/()//i) sl@0: { sl@0: my $cell = $1; sl@0: if ($cell =~ m/DidItCrash()) && ($crash =~ m/Crashed<\/Data>/i)) sl@0: { sl@0: $foundOtherPlatCrash = 1; sl@0: } sl@0: sl@0: if ($fails) sl@0: { sl@0: my @failures = $aScriptWithProblems->Failures(); sl@0: foreach my $failure (@failures) sl@0: { sl@0: if (($fails =~ m/$failure/i) || ($fails =~ m/>ALL<\/Data>/)) sl@0: { sl@0: $foundOtherPlatFails = $foundOtherPlatFails . "$failure\n"; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if ($inconclusives) sl@0: { sl@0: my @incons = $aScriptWithProblems->Inconclusives(); sl@0: foreach my $incon (@incons) sl@0: { sl@0: if (($inconclusives =~ m/$incon/i) || ($inconclusives =~ m/>ALL<\/Data>/)) sl@0: { sl@0: $foundOtherPlatInconcs = $foundOtherPlatInconcs . "$incon\n"; sl@0: } sl@0: } sl@0: } sl@0: sl@0: } # End of cross-platform candidate matchine sl@0: } # End of dealing with potential cross-platform matches sl@0: sl@0: # Output known failures sl@0: if ($foundSamePlatFails || $foundSamePlatInconcs || $foundSamePlatCrash) sl@0: { sl@0: $iKnownFails = $iKnownFails . "\n$scriptName\n"; sl@0: } sl@0: if ($foundSamePlatInconcs) sl@0: { sl@0: $iKnownFails = $iKnownFails . "INCONCLUSIVES:\n$foundSamePlatInconcs"; sl@0: } sl@0: if ($foundSamePlatFails) sl@0: { sl@0: $iKnownFails = $iKnownFails . "FAILS:\n$foundSamePlatFails"; sl@0: } sl@0: if ($foundSamePlatCrash) sl@0: { sl@0: $iKnownFails = $iKnownFails . "CRASHED\n"; sl@0: } sl@0: sl@0: # Output matches found only in other test platforms sl@0: if ($foundOtherPlatFails || $foundOtherPlatInconcs || $foundOtherPlatCrash) sl@0: { sl@0: $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "\n$scriptName\n"; sl@0: } sl@0: if ($foundOtherPlatInconcs) sl@0: { sl@0: $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "INCONCLUSIVES:\n$foundOtherPlatInconcs"; sl@0: } sl@0: if ($foundOtherPlatFails) sl@0: { sl@0: $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "FAILS:\n$foundOtherPlatFails"; sl@0: } sl@0: if ($foundOtherPlatCrash) sl@0: { sl@0: $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "CRASHED\n"; sl@0: } sl@0: sl@0: $aKfSheetContents = $wipKfSheet; sl@0: } sl@0: sl@0: sl@0: # Takes the corresponding log file from the reference build and test for a failing script and sl@0: # compare it to see if the failures match. If so this information is stored and the matching sl@0: # failures removed from the TestScriptResults object. sl@0: # param1 - TestScriptResults object for the script with failures sl@0: # param2 - boolean whether the test crashed in the reference build and test sl@0: # param3 - the contents of the corresponding log file from the reference build sl@0: sub ResolveFailuresAgainstReferenceRun sl@0: { sl@0: my $aReferenceTestResults = shift; sl@0: my $aRefTestCrashed = shift; sl@0: my $aReferenceLogContents = shift; sl@0: my $refContents = $$aReferenceLogContents; sl@0: sl@0: my $scriptName = $aReferenceTestResults->ScriptName(); sl@0: my $testHarness = $aReferenceTestResults->TestHarness(); sl@0: sl@0: my $inconText; sl@0: my @inconclusives = $aReferenceTestResults->Inconclusives(); sl@0: $aReferenceTestResults->ResetInconclusives(); sl@0: foreach my $inconclusive (@inconclusives) sl@0: { sl@0: if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest)) sl@0: { sl@0: my $testcasesInUse = 0; sl@0: if ($testHarness eq $TestScriptResults::KTEFTest) sl@0: { sl@0: $testcasesInUse = 1; sl@0: } sl@0: if (MatchingTEFInconclusiveResult($inconclusive, \$refContents, $testcasesInUse)) sl@0: { sl@0: $inconText = $inconText . "$inconclusive\n"; sl@0: } sl@0: else sl@0: { sl@0: $aReferenceTestResults->AddInconclusiveResult($inconclusive); sl@0: } sl@0: } sl@0: elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest) sl@0: { sl@0: if (MatchingTFInconclusiveResult($inconclusive, \$refContents)) sl@0: { sl@0: $inconText = $inconText . "$inconclusive\n"; sl@0: } sl@0: else sl@0: { sl@0: $aReferenceTestResults->AddInconclusiveResult($inconclusive); sl@0: } sl@0: } sl@0: # Core Conf tests have no comprehension of inconclusive sl@0: } sl@0: sl@0: my $failText; sl@0: my @failures = $aReferenceTestResults->Failures(); sl@0: $aReferenceTestResults->ResetFailures(); sl@0: foreach my $failure (@failures) sl@0: { sl@0: if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest)) sl@0: { sl@0: my $testcasesInUse = 0; sl@0: if ($testHarness eq $TestScriptResults::KTEFTest) sl@0: { sl@0: $testcasesInUse = 1; sl@0: } sl@0: if (MatchingTEFErrorResult($failure, \$refContents, $testcasesInUse)) sl@0: { sl@0: $failText = $failText . "$failure\n"; sl@0: } sl@0: else sl@0: { sl@0: $aReferenceTestResults->AddFailureResult($failure); sl@0: } sl@0: } sl@0: elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest) sl@0: { sl@0: if (MatchingTFErrorResult($failure, \$refContents)) sl@0: { sl@0: $failText = $failText . "$failure\n"; sl@0: } sl@0: else sl@0: { sl@0: $aReferenceTestResults->AddFailureResult($failure); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: # Core Conf sl@0: if (MatchingCoreConfErrorResult($failure, \$refContents)) sl@0: { sl@0: $failText = $failText . "$failure\n"; sl@0: } sl@0: else sl@0: { sl@0: $aReferenceTestResults->AddFailureResult($failure); sl@0: } sl@0: } sl@0: } sl@0: sl@0: my $bothCrashed; sl@0: if (($aReferenceTestResults->DidItCrash()) && $aRefTestCrashed) sl@0: { sl@0: $bothCrashed = 1; sl@0: $aReferenceTestResults->ResetCrashed(); sl@0: } sl@0: sl@0: if ($inconText || $failText || $bothCrashed) sl@0: { sl@0: $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "\n$scriptName\n"; sl@0: } sl@0: sl@0: if ($inconText) sl@0: { sl@0: $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "INCONCLUSIVES:\n$inconText"; sl@0: } sl@0: if ($failText) sl@0: { sl@0: $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "FAILS:\n$failText"; sl@0: } sl@0: if ($bothCrashed) sl@0: { sl@0: $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "CRASHED\n"; sl@0: } sl@0: } sl@0: sl@0: ############################################### sl@0: ## Utility functions sl@0: ############################################### sl@0: sl@0: sub PrintHelp sl@0: { sl@0: print "\n\nResultsComparison.pl -m Mode -s Results_source [-k Known_failure_sheet_path -c Codeline -p Platform] [-r Mistral_comparison_job_url] [-i] [-v]\n\n"; sl@0: print " -m = Mode of operation, specify the source of the results that you are\n"; sl@0: print " comparing. Currently supported modes: Mistral, Local\n\n"; sl@0: print " -s = Source of the results, mode dependant:\n"; sl@0: print " (i) Mistral = The URL of the test results HTML summary page\n"; sl@0: print " (ii) Local = The pathname of a folder containing the test log files\n\n"; sl@0: print " -k = Pathname of the KF sheet, this should be exported as an XML spreadsheet\n"; sl@0: print " from Excel\n\n"; sl@0: print " -r = Reference Mistral build, the URL of the test results HTML summary page.\n"; sl@0: print " This can be used in addition or in place of the Known Failure sheet\n\n"; sl@0: print " -i = Ignore test failures in scripts not found in the Reference Mistral build\n\n"; sl@0: print " -c = An index indicating the codeline used in the test run, only used in\n"; sl@0: print " conjunction with a KF sheet. Possible values: TB92, TB101, TB102\n\n"; sl@0: print " -p = An index indicating the platform the test run is from, only used in\n"; sl@0: print " conjunction with a KF sheet. Possible values: Winscw, H6, H4 WDP,\n"; sl@0: print " NaviEngine\n\n"; sl@0: print " -v = Verbose output\n\n"; sl@0: } sl@0: sl@0: ############################################### sl@0: ## Main processing loop sl@0: ############################################### sl@0: sl@0: # Read in parameters sl@0: my %aParams; sl@0: getopts('ihvm:s:k:r:c:p:', \%aParams); sl@0: if ($aParams{h}) sl@0: { sl@0: PrintHelp(); sl@0: exit; sl@0: } sl@0: sl@0: $iVerbose = $aParams{v}; sl@0: sl@0: # The mode affects where we get the source files from and nothing else. sl@0: my @runResults; sl@0: if ($aParams{m} =~ m/\AMistral\Z/i) sl@0: { sl@0: @runResults = @{PopulateResultsArrayFromMistral($aParams{s})}; sl@0: } sl@0: elsif ($aParams{m} =~ m/\ALocal\Z/i) sl@0: { sl@0: @runResults = @{PopulateResultsArrayFromLocalMachine($aParams{s})}; sl@0: } sl@0: else sl@0: { sl@0: print "\nERROR: Operation mode absent or not recognised.\n"; sl@0: PrintHelp(); sl@0: exit; sl@0: } sl@0: sl@0: my @kfPlatforms; sl@0: if ($aParams{k}) sl@0: { sl@0: $kfPlatforms[0] = "All"; sl@0: sl@0: # KF sheet in use, codeline and platform arguments are required in order to search for matching failures sl@0: my $codeline = $aParams{c}; sl@0: my $platform = $aParams{p}; sl@0: unless (($codeline eq "TB92") || ($codeline eq "TB101") || ($codeline eq "TB102")) sl@0: { sl@0: print "\nERROR: The codeline specified was not recognised, supported options: TB92, TB101, TB102.\n"; sl@0: exit; sl@0: } sl@0: sl@0: if ($platform eq "Winscw") sl@0: { sl@0: $kfPlatforms[1] = "All Winscw"; sl@0: } sl@0: elsif (($platform eq "H6") || ($platform eq "H4 WDP") || ($platform eq "NaviEngine")) sl@0: { sl@0: $kfPlatforms[1] = "All HW"; sl@0: } sl@0: else sl@0: { sl@0: print "\nERROR: The platform specified was not recognised, supported options: Winscw, H6, H4 WDP, NaviEngine.\n"; sl@0: exit; sl@0: } sl@0: sl@0: $kfPlatforms[2] = "$codeline $platform"; sl@0: } sl@0: sl@0: if ($iVerbose) sl@0: { sl@0: print "\nLog files found:\n"; sl@0: foreach my $file (@runResults) sl@0: { sl@0: my $scriptName = $file->ScriptName(); sl@0: print "$scriptName\n"; sl@0: } sl@0: } sl@0: sl@0: AnalyseFailures($aParams{k}, $aParams{r}, $aParams{i}, \@runResults, \@kfPlatforms); sl@0: sl@0: print "\n\nKnown failures:\n"; sl@0: print "------------------\n"; sl@0: print "$iKnownFails\n\n"; sl@0: sl@0: print "Unknown failures but found in the reference build:\n"; sl@0: print "----------------------------------------------------\n"; sl@0: print "$iUnknownFailsButKnownInRef\n\n"; sl@0: sl@0: print "Unknown failures but known in other codelines:\n"; sl@0: print "------------------------------------------------\n"; sl@0: print "$iUnknownFailsButKnownInOtherCodelines\n\n"; sl@0: sl@0: print "Unknown failures:\n"; sl@0: print "-------------------\n"; sl@0: print "$iUnknownFails\n\n"; sl@0: sl@0: print "Tests with reduced test counts:\n"; sl@0: print "---------------------------------\n"; sl@0: print "$iMissingTests\n\n"; sl@0: sl@0: