os/mm/mmtestenv/mmtesttools/Scripts/TestResultsComparisonTool/ResultsComparison.pl
Update contrib.
1 # Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
3 # This component and the accompanying materials are made available
4 # under the terms of "Eclipse Public License v1.0"
5 # which accompanies this distribution, and is available
6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 # Initial Contributors:
9 # Nokia Corporation - initial contribution.
18 use TestScriptResults;
22 # Mistral tags the result files from test scripts in a particular format, depending on the test harness used to execute them.
23 # We use these names to identify which files are results files.
24 my $KMistralCoreConfFileName = "-coreconf-";
25 my $KMistralTEFFileName = "-testexecute-";
26 my $KMistralTestFrameworkFileName = "-testframework"; # No trailing hyphen due to different security variants
28 # It appears that Mistral uses a completely different file format for results from HW runs
29 my $KMistrealTEFFileNameHW = "testexecute";
30 my $KMistrealTFFileNameHW1 = "testframework";
31 my $KMistrealTFFileNameHW2 = "testframeworkmmddcap";
32 my $KMistrealTFFileNameHW3 = "testframeworkuecap";
33 my $KMistrealTFFileNameHW4 = "testframeworknone";
35 # Work in progress script outputs.
37 my $iUnknownFailsButKnownInRef;
38 my $iUnknownFailsButKnownInOtherCodelines;
44 ###############################################
45 ## Source test domain specific functionality
46 ###############################################
47 # Scans the test results summary page from the Mistral build and compiles a collection of the
48 # URL paths for the log files.
49 # param1 - the URL to the Test Results HTML Summary page of the Mistral build
50 # returns - the array of logs' URLS
51 sub GetResultFilesFromMistral
53 my $aMistralTestResultsSummaryUrl = shift;
56 my $nextFileNamesIndex = 0;
58 my $summaryContents = get "$aMistralTestResultsSummaryUrl"; # Returns undef if failure
59 unless ($summaryContents)
61 print "\nERROR: Unable to retrieve source summary file from $aMistralTestResultsSummaryUrl\n";
65 #Could add an optimisation to this to search for the <td class="error"> tag BUT doesn't take into account the crashed tests and would need to check here the pass/fail count
66 #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
67 #So it's simpler to do the brute force approach and keep all implementations alike, it doesn't take long anyway
68 while ($summaryContents =~ s/href="(.*?($KMistralCoreConfFileName|$KMistralTEFFileName|$KMistralTestFrameworkFileName).*?\.html?)"//i)
70 $fileNames[$nextFileNamesIndex] = $1;
71 $nextFileNamesIndex++;
74 # Scan this second so we don't accidentally cut off the filenames if they are matched against Winscw runs
75 while ($summaryContents =~ s/href="(.*?($KMistrealTEFFileNameHW|$KMistrealTFFileNameHW1|$KMistrealTFFileNameHW2|$KMistrealTFFileNameHW3|$KMistrealTFFileNameHW4).*?\.html?)"//i)
77 $fileNames[$nextFileNamesIndex] = $1;
78 $nextFileNamesIndex++;
81 unless ($fileNames[0])
83 print "\nERROR: No test result log files found, please ensure the -s parameter points to Mistral's TestResults.html summary page\n";
90 # Parse the Mistral test results summary page and generate an array of TestScriptResults
91 # objects which contain all the required information such as script names, test counts
93 # param1 - the URL of the Test Results HTML Summary page for the Mistral build
94 # returns - the array of parsed log data
95 sub PopulateResultsArrayFromMistral
97 my $aTestResultsSummaryPageUrl = shift;
98 my @aResultsArray = ();
99 my $nextFreeIndexInResultsArray = 0;
101 my @fileNames = GetResultFilesFromMistral($aTestResultsSummaryPageUrl);
102 foreach my $fileName (@fileNames)
104 my $testFileContents = get "$fileName";
105 unless ($testFileContents)
107 print "\nERROR: Unable to open logfile $fileName\n";
111 my $scriptResults = TestScriptResults->TestScriptResults();
112 $scriptResults->SetFilePath($fileName);
113 if (($fileName =~ m/.*?$KMistralTEFFileName(.*?)\.html?/i) || ($fileName =~ m/.*?$KMistrealTEFFileNameHW(.*?)\.html?/i))
115 $scriptResults->SetScriptName($1);
116 if (!($testFileContents =~ m/TEST CASE SUMMARY:/i) && ($testFileContents =~ m/SUMMARY:/i))
118 # One of the old MM TEF tests which didn't use testcases
119 $scriptResults->TEFNoTestcasesTest();
120 $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 0);
124 $scriptResults->TEFTest();
125 $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 1);
128 elsif ($fileName =~ m/.*?$KMistralCoreConfFileName(.*?)\.txt\.html?/i)
130 $scriptResults->SetScriptName($1);
131 $scriptResults->CoreConfTest();
132 $aResultsArray[$nextFreeIndexInResultsArray] = ScanCoreConfLogFileForFailures($scriptResults, \$testFileContents);
134 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))
136 $scriptResults->SetScriptName($1);
137 $scriptResults->TestFrameworkTest();
139 $aResultsArray[$nextFreeIndexInResultsArray] = ScanTestFrameworkLogFileForFailures($scriptResults, \$testFileContents);
143 print "\nWARNING: Results file has unrecognised format - $fileName.\n";
145 $nextFreeIndexInResultsArray++;
148 return \@aResultsArray;
152 # Walk the file path provided by the developer for his local machine, parse test logs
153 # and generate an array of TestScriptResults objects which contain all the required
154 # information such as script names, test counts and failures.
155 # param1 - the pathname of a folder containing the test results
156 # returns - the array of parsed log data
157 sub PopulateResultsArrayFromLocalMachine
159 my $aTestResultsPath = shift;
160 my @aResultsArray = ();
161 my $nextFreeIndexInResultsArray = 0;
163 my @directories = ("$aTestResultsPath");
165 find( sub { push @fileNames, $File::Find::name if /\.html?$/ }, @directories );
167 foreach my $fileName (@fileNames)
169 my $testFileContents = do { local $/; open(I,"$fileName"); <I> };
170 my $scriptResults = TestScriptResults->TestScriptResults();
171 $scriptResults->SetFilePath($fileName);
172 $fileName =~ m/([^\\\/\.]*)\.[^\\\/]*\Z/;
173 $scriptResults->SetScriptName($1);
175 if ($testFileContents =~ m/Core Loader Conformance Suite/)
177 $scriptResults->CoreConfTest();
178 $aResultsArray[$nextFreeIndexInResultsArray] = ScanCoreConfLogFileForFailures($scriptResults, \$testFileContents);
180 elsif ($testFileContents =~ m/TestFrameworkMain.cpp/)
182 $scriptResults->TestFrameworkTest();
183 $aResultsArray[$nextFreeIndexInResultsArray] = ScanTestFrameworkLogFileForFailures($scriptResults, \$testFileContents);
185 elsif ($testFileContents =~ m/TEF Version/)
187 if ($testFileContents =~ m/TEST CASE SUMMARY:/i)
189 $scriptResults->TEFTest();
190 $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 1);
194 # One of the old MM TEF tests which didn't use testcases
195 $scriptResults->TEFNoTestcasesTest();
196 $aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 0);
201 print "\nWARNING: Results file has unrecognised format - $fileName.\n";
204 $nextFreeIndexInResultsArray++;
207 return \@aResultsArray;
210 ###############################################
211 ## Test harness specific functionality
212 ###############################################
214 # Parses a TF log file for failures, inconclusives and crashes
215 # param1 - the TestScriptResults object to populate
216 # param2 - reference to the contents of the log file
217 # returns - the TestScriptResults object containing the parsed data
218 sub ScanTestFrameworkLogFileForFailures
220 my ($aScriptResults, $aLogFileContents) = @_;
222 my $testFileContents = $$aLogFileContents;
223 my $numberOfTests = 0;
224 # Search for test case results, which take the following form:
225 #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
226 while ($testFileContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:([\_|\-|\S]+)[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
231 if ($result =~ /PASS/)
235 elsif ($result =~ /INCONCLUSIVE/)
237 $aScriptResults->AddInconclusiveResult($testId);
241 # Treat all other results as failure
242 $aScriptResults->AddFailureResult($testId);
245 $aScriptResults->SetTotalTestCount($numberOfTests);
247 unless ($testFileContents =~ m/Test Results Summary/)
249 # Test file summary not in the log file - the test has crashed
250 $aScriptResults->TestCrashed();
253 return $aScriptResults;
256 # Parses a TEF log file for failures, inconclusives and crashes
257 # param1 - the TestScriptResults object to populate
258 # param2 - reference to the contents of the log file
259 # param3 - boolean whether the test is using testcases (older MM tests didn't, in which case we use the test steps)
260 # returns - the TestScriptResults object containing the parsed data
261 sub ScanTEFLogFileForFailures
263 my ($aScriptResults, $aLogFileContents, $aTestcasesInUse) = @_;
265 my $testFileContents = $$aLogFileContents;
266 my $numberOfTests = 0;
268 # Search for test case results, which take the following form:
269 # 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
270 # Or if testcases not in use in this script file test step results, which take the following form:
271 # 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
272 while (($testFileContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+([\_|\-|\S]+)[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
273 || (!$aTestcasesInUse && ($testFileContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+([\_|\-|\S]+)[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)))
278 if ($result =~ /PASS/)
282 elsif ($result =~ /INCONCLUSIVE/)
284 $aScriptResults->AddInconclusiveResult($testId);
288 # Treat all other results as failure
289 $aScriptResults->AddFailureResult($testId);
292 $aScriptResults->SetTotalTestCount($numberOfTests);
294 # Testcase scripts use TEST CASE SUMMARY, non-testcase scripts just use SUMMARY
295 unless ($testFileContents =~ m/SUMMARY:/)
297 # Test file summary not in the log file - the test has crashed
298 $aScriptResults->TestCrashed();
301 return $aScriptResults;
304 # Parses a CoreConf log file for failures, inconclusives and crashes
305 # param1 - the TestScriptResults object to populate
306 # param2 - reference to the contents of the log file
307 # returns - the TestScriptResults object containing the parsed data
308 sub ScanCoreConfLogFileForFailures
310 my ($aScriptResults, $aLogFileContents) = @_;
311 my $testFileContents = $$aLogFileContents;
313 if ($testFileContents =~ s/\*\*\*\s*?Summary of tests executed(.*\n)*//)
315 my $numberOfTests = 0;
317 # Parse the summary listings
318 while($testFileContents =~ s/\*\*\*\s*?Passed tests:((.*\n)*?)\*\*\*\s*?Failed tests:.*\n((\*\*\*.*\n)*)//)
320 my $passingTests = $1;
321 my $failingTests = $3;
324 while ($passingTests =~ s/\*\*\*[\s]*?\S+[\s]*\n//)
330 while ($failingTests =~ s/\*\*\*[\s]*?(\S+)[\s]*\n//)
332 $aScriptResults->AddFailureResult($1);
337 $aScriptResults->SetTotalTestCount($numberOfTests);
341 # Test file summary not in the log file - the test has crashed
342 $aScriptResults->TestCrashed();
345 return $aScriptResults;
348 # Gets the test case count from a Test Execute Framework log file
349 # param1 - a reference to the contents of the TEF log file
350 #returns - The number of test cases in the script or -1 if the summary could not be found
353 my $aReferenceLogContents = shift;
354 my $refContents = $$aReferenceLogContents;
356 if ($refContents =~ m/TEST CASE SUMMARY:(.*\n)*?.*?PASS =\s*(\d*)(.*\n)*?.*?FAIL =\s*(\d*)(.*\n)*?.*?INCONCLUSIVE =\s*(\d*)/)
358 my $result = $2 + $4 + $6;
362 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*)/)
364 # One of the MM tests that doesn't use testcases
365 my $result = $2 + $4 + $6 + $8 + $10 + $12 + $14;
369 # Summary not found, we crashed
373 # Gets the test count from a Test Framework log file
374 # param1 - a reference to the contents of the Test Framework log file
375 #returns - The number of test cases in the script or -1 if the summary could not be found
376 sub GetTestFrameworkTestCount
378 my $aReferenceLogContents = shift;
379 my $refContents = $$aReferenceLogContents;
381 unless ($refContents =~ m/Test Results Summary(.*\n)*?.*?Total\s*:(\d*)\s*\n/)
383 # Summary not found, we crashed
389 # Gets the test count from an OpenMAX IL Core Conformance log file
390 # param1 - a reference to the contents of the Core Conformance log file
391 #returns - The number of test cases in the script or -1 if the summary could not be found
392 sub GetCoreConfTestCount
394 my $aReferenceLogContents = shift;
395 my $refContents = $$aReferenceLogContents;
397 unless ($refContents =~ m/\*\*\*\s*Summary of tests executed(.*\n)*?\*\*\*\s*Total :\s*(\d*)\s*\n/)
399 # Summary not found, we crashed
405 # Scans a TEF log looking for the test specified and checks if it returned inconclusive
406 # param1 - the test name
407 # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
408 # param3 - whether the TEF script uses testcases
409 # returns - 1 if it returned inconclusive, 0 otherwise
410 sub MatchingTEFInconclusiveResult
412 my $aInconclusive = shift;
413 my $aReferenceLogContents = shift;
414 my $aTestcasesInUse = shift;
415 my $refContents = $$aReferenceLogContents;
416 if ($aTestcasesInUse)
418 if ($refContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+$aInconclusive[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
420 if ($1 eq "INCONCLUSIVE")
428 if ($refContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+$aInconclusive[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
430 if ($1 eq "INCONCLUSIVE")
439 # Scans a TestFramework log looking for the test specified and checks if it returned inconclusive
440 # param1 - the test name
441 # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
442 # returns - 1 if it returned inconclusive, 0 otherwise
443 sub MatchingTFInconclusiveResult
445 my $aInconclusive = shift;
446 my $aReferenceLogContents = shift;
447 my $refContents = $$aReferenceLogContents;
448 if ($refContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:$aInconclusive[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
450 if ($1 eq "INCONCLUSIVE")
458 # Scans a TEF log looking for the test specified and checks if it returned an error
459 # param1 - the test name
460 # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
461 # param3 - whether the TEF script uses testcases
462 # returns - 1 if it returned an error, 0 otherwise
463 sub MatchingTEFErrorResult
466 my $aReferenceLogContents = shift;
467 my $aTestcasesInUse = shift;
468 my $refContents = $$aReferenceLogContents;
470 if ($aTestcasesInUse)
472 if (not $refContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+$aFail[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
477 if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE"))
484 if (not $refContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+$aFail[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
489 if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE"))
498 # Scans a TestFramework log looking for the test specified and checks if it returned an error
499 # param1 - the test name
500 # param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
501 # returns - 1 if it returned an error, 0 otherwise
502 sub MatchingTFErrorResult
505 my $aReferenceLogContents = shift;
506 my $refContents = $$aReferenceLogContents;
507 if (not $refContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:$aFail[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
512 if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE"))
520 # N.B. VERY IMPORTANT that the log file is passed by reference. Core conf scripts can include numerous
521 # different tests that use the same test name so to avoid false positives from this function the
522 # substitution done in the comparison MUST affect the caller's copy of the log file.
523 sub MatchingCoreConfErrorResult
526 my $aReferenceLogContents = shift;
527 my $refContents = $$aReferenceLogContents;
529 if ($refContents =~ s/\*\*\*[\s]*$aFail[\s]*FAILED//)
537 ###############################################
538 ## Failure comparison functions
539 ###############################################
541 # The analysis takes an array of TestScriptResults, each storing the results of a test script's log file.
542 # It processes this list in stages looking for any scripts with errors and trying to match them against
543 # entries in a Known Failure sheet and/or comparison reference build. Whenever a match is found
544 # the error is removed from the TestScriptResults object, these essentially act as an object containing
545 # unresolved errors. When errors are matched their details are added to the corresponding text
546 # variables at the top of this file (e.g. iKnownFails).
549 my ($aKFSheetLocation, $aReferenceMistralURL, $aIgnoreFailsNotInRef, $aResultsRef, $aKfPlatforms) = @_;
551 my @results = @$aResultsRef;
553 my $refContents = undef;
554 if ($aReferenceMistralURL)
556 $refContents = get "$aReferenceMistralURL"; # Returns undef if failure
557 unless ($refContents)
559 print "\nERROR: Unable to retrieve reference summary file from $aReferenceMistralURL\n";
564 my $kfSheetContents = undef;
565 if ($aKFSheetLocation)
567 unless ($aKFSheetLocation =~ m/\.xml\Z/i)
569 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";
572 $kfSheetContents = do { local $/; open(I,"$aKFSheetLocation"); <I> };
573 unless ($kfSheetContents)
575 print "\nERROR: Unable to open KF sheet at $aKFSheetLocation\n";
580 foreach my $scriptResults (@results)
582 my $scriptName = $scriptResults->ScriptName();
584 my $referenceResults = undef;
586 # If a reference build was provided, find the corresponding log file
589 # We use substitution here because some of the coreconf test scripts
590 # have the same script name. This ensures we don't keep referencing
591 # against the same copy. We cannot do the comparison on the script
592 # path because this isn't resilient to adding new tests or cross domain
594 # N.B. This assumes the test list ordering remains the same.
595 # N.B. The optional .txt is for Core Conf tests
596 $refContents =~ s/href="(.*?$scriptName(\.txt)?(\.script)?\.html?)"//;
600 if ($aIgnoreFailsNotInRef)
604 print "\nWARNING: Unable to find $scriptName in Reference Build\n";
608 $referenceResults = get "$file"; # returns undef on failure
609 unless ($referenceResults)
611 print "\nWARNING: Unable to open $scriptName ($file) in Reference Build\n";
617 # Check the test count hasn't decreased
618 if ($referenceResults)
620 $refTestCrashed = CheckTestCount($scriptResults, \$referenceResults);
623 if (not $scriptResults->AnyFailures())
625 # No errors so move onto the next
629 if ($kfSheetContents)
631 ResolveFailuresAgainstKFSheet($scriptResults, \$kfSheetContents, $aKfPlatforms);
633 if (not $scriptResults->AnyFailures())
635 # All errors resolved against KF sheet so move onto the next
640 if ($referenceResults)
642 ResolveFailuresAgainstReferenceRun($scriptResults, $refTestCrashed, \$referenceResults);
644 if (not $scriptResults->AnyFailures())
646 # All errors resolved against reference run so move onto the next
652 $iUnknownFails = $iUnknownFails . "\n$scriptName\n";
655 my @inconclusives = $scriptResults->Inconclusives();
656 foreach my $inconclusive (@inconclusives)
658 $inconText = $inconText . "$inconclusive\n";
661 my @failures = $scriptResults->Failures();
662 foreach my $failure (@failures)
664 $failText = $failText . "$failure\n";
669 $iUnknownFails = $iUnknownFails . "INCONCLUSIVES:\n$inconText";
673 $iUnknownFails = $iUnknownFails . "FAILS:\n$failText";
675 if ($scriptResults->DidItCrash())
677 $iUnknownFails = $iUnknownFails . "CRASHED\n";
683 # Will compare the test count of the test in question against the equivalent result from a reference build's log
684 # to detect if there has been a reduction in the total number of tests run as part of the script, unless that script
685 # has crashed. As a side effect the return value indicates whether the test in question crashed or not (saves
686 # having to scan it twice).
687 # param1 - the log results to compare against the reference build's run
688 # param2 - the contents of the reference build's corresponding test log
689 # returns = 1 if the reference script crashed and we were unable to compare the counts, 0 otherwise
692 my ($aTestResultsObject, $aReferenceLogContents) = @_;
694 my $testHarness = $aTestResultsObject->TestHarness();
696 if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest))
698 $refTestCount = GetTEFTestCount($aReferenceLogContents);
700 elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest)
702 $refTestCount = GetTestFrameworkTestCount($aReferenceLogContents);
706 $refTestCount = GetCoreConfTestCount($aReferenceLogContents);
709 if ($refTestCount < 0)
711 # Reference test crashed
712 unless ($aTestResultsObject->DidItCrash())
714 my $scriptName = $aTestResultsObject->ScriptName();
715 print "\nWARNING: $scriptName crashed in the reference build, unable to compare test counts\n";
720 my $testCount = $aTestResultsObject->TotalTestCount;
721 if ($testCount < $refTestCount)
723 unless ($aTestResultsObject->DidItCrash())
725 my $testName = $aTestResultsObject->ScriptName();
726 $iMissingTests = $iMissingTests . "$testName Previous = $refTestCount, Current = $testCount\n";
732 # Will scan the Known Failure sheet for any entries indicating if the failures,inconclusives and/or crash
733 # witnessed in the script in question are already known. If so these will be appended to the known failures list
734 # and removed from the TestScriptResults object in question. If matching entries were found but existed for
735 # other codelines then this information is stored but the failures are not removed from the TestScriptResults
737 # param1 - TestScriptResults object for the script with failures
738 # param2 - the contents of the known failure sheet
739 # param3 - the array of platform entries in the known failure sheet that are applicable to this run
740 sub ResolveFailuresAgainstKFSheet
742 my ($aScriptWithProblems, $aKfSheetContents, $aKfPlatforms) = @_;
743 my $kfSheetContents = $$aKfSheetContents;
744 my $scriptName = $aScriptWithProblems->ScriptName();
746 my @kFApplicablePlatforms;
749 # Will error if undef
750 @kFApplicablePlatforms = @$aKfPlatforms;
753 # 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.
754 # 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
755 # regexs. And in reality underneath Perl shouldn't be doing that much in the way of optimisation versus this approach.
757 my $candidatesForOtherPlatforms;
758 my $foundSamePlatFails;
759 my $foundSamePlatInconcs;
760 my $foundSamePlatCrash;
761 while ($kfSheetContents =~ s/<Row((.|\n)*?>)((.|\n)*?)<\/Row>//i)
765 unless ($row =~ m/$scriptName/i)
767 $wipKfSheet = $wipKfSheet . "<Row>$row<\/Row>";
771 # None of the cells prior to the 'Scriptname' named cell are of any interest, now verify this row is actually for
772 # this test script and we didn't pick the hit up off the entries for one of the other fields, e.g. Remarks
774 while ($row =~ s/(<Cell(.|\n)*?<\/Cell>)//i)
777 if ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Scriptname\d*"\//i)
779 # Named field we're looking for
780 if ($cell =~ m/$scriptName/i)
787 $wipKfSheet = $wipKfSheet . "<Row>$cell\n$row<\/Row>"; # This entry isn't applicable to us, reinsert it into the KF sheet
797 # We are now dealing with a Row corresponding to the script in question
798 # So pull out the relevant named cells contents
803 while ($row =~ s/(<Cell(.|\n)*?<\/Cell>)//i)
806 if ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="CrashedStatus\d*"\//i)
810 elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Fails\d*"\//i)
814 elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Inconclusives\d*"\//i)
816 $inconclusives = $cell;
818 elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Platforms\d*"\//i)
825 foreach my $platform (@kFApplicablePlatforms)
827 unless (($targets =~ m/$platform /i) || ($targets =~ m/$platform<\/Data>/i)) # To ensure for example that All isn't picked up by an All Winscw entry
829 next; # Platform not found in the entry
831 $platformMatched = 1;
833 if (($aScriptWithProblems->DidItCrash()) && ($crash =~ m/Crashed/i))
835 $foundSamePlatCrash = 1;
836 $aScriptWithProblems->ResetCrashed();
841 my @failures = $aScriptWithProblems->Failures();
842 $aScriptWithProblems->ResetFailures();
843 foreach my $failure (@failures)
845 if (($fails =~ m/$failure/i) || ($fails =~ m/>ALL<\/Data>/))
847 $foundSamePlatFails = $foundSamePlatFails . "$failure\n";
852 $aScriptWithProblems->AddFailureResult($failure);
859 my @incons = $aScriptWithProblems->Inconclusives();
860 $aScriptWithProblems->ResetInconclusives();
861 foreach my $incon (@incons)
863 if (($inconclusives =~ m/$incon/i) || ($inconclusives =~ m/>ALL<\/Data>/))
865 $foundSamePlatInconcs = $foundSamePlatInconcs . "$incon\n";
869 $aScriptWithProblems->AddInconclusiveResult($incon);
873 } # End of platform matching loop
875 unless ($platformMatched)
877 # The row entry did not match any of the applicable platforms. We need to keep checking for more appropriate rows.
878 # However, if after the KF Sheet has been parsed we still have unknown errors, we need to compare against these rows as well
879 # in case the issue has been seen on other platforms.
881 $candidatesForOtherPlatforms = $candidatesForOtherPlatforms . "<Row>$crash$fails$inconclusives<\/Row>";
884 } # End of row scanning
887 my $foundOtherPlatFails;
888 my $foundOtherPlatInconcs;
889 my $foundOtherPlatCrash;
890 if ($aScriptWithProblems->AnyFailures())
892 # Failures remain, potentially matched against the rows for other platforms
894 while ($candidatesForOtherPlatforms =~ s/<Row>((.|\n)*?)<\/Row>//i)
900 while ($row =~ s/(<Cell(.|\n)*?<\/Cell>)//i)
903 if ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="CrashedStatus\d*"\//i)
907 elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Fails\d*"\//i)
911 elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Inconclusives\d*"\//i)
913 $inconclusives = $cell;
915 } # End of stripping out content details
917 if (($aScriptWithProblems->DidItCrash()) && ($crash =~ m/Crashed<\/Data>/i))
919 $foundOtherPlatCrash = 1;
924 my @failures = $aScriptWithProblems->Failures();
925 foreach my $failure (@failures)
927 if (($fails =~ m/$failure/i) || ($fails =~ m/>ALL<\/Data>/))
929 $foundOtherPlatFails = $foundOtherPlatFails . "$failure\n";
936 my @incons = $aScriptWithProblems->Inconclusives();
937 foreach my $incon (@incons)
939 if (($inconclusives =~ m/$incon/i) || ($inconclusives =~ m/>ALL<\/Data>/))
941 $foundOtherPlatInconcs = $foundOtherPlatInconcs . "$incon\n";
946 } # End of cross-platform candidate matchine
947 } # End of dealing with potential cross-platform matches
949 # Output known failures
950 if ($foundSamePlatFails || $foundSamePlatInconcs || $foundSamePlatCrash)
952 $iKnownFails = $iKnownFails . "\n$scriptName\n";
954 if ($foundSamePlatInconcs)
956 $iKnownFails = $iKnownFails . "INCONCLUSIVES:\n$foundSamePlatInconcs";
958 if ($foundSamePlatFails)
960 $iKnownFails = $iKnownFails . "FAILS:\n$foundSamePlatFails";
962 if ($foundSamePlatCrash)
964 $iKnownFails = $iKnownFails . "CRASHED\n";
967 # Output matches found only in other test platforms
968 if ($foundOtherPlatFails || $foundOtherPlatInconcs || $foundOtherPlatCrash)
970 $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "\n$scriptName\n";
972 if ($foundOtherPlatInconcs)
974 $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "INCONCLUSIVES:\n$foundOtherPlatInconcs";
976 if ($foundOtherPlatFails)
978 $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "FAILS:\n$foundOtherPlatFails";
980 if ($foundOtherPlatCrash)
982 $iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "CRASHED\n";
985 $aKfSheetContents = $wipKfSheet;
989 # Takes the corresponding log file from the reference build and test for a failing script and
990 # compare it to see if the failures match. If so this information is stored and the matching
991 # failures removed from the TestScriptResults object.
992 # param1 - TestScriptResults object for the script with failures
993 # param2 - boolean whether the test crashed in the reference build and test
994 # param3 - the contents of the corresponding log file from the reference build
995 sub ResolveFailuresAgainstReferenceRun
997 my $aReferenceTestResults = shift;
998 my $aRefTestCrashed = shift;
999 my $aReferenceLogContents = shift;
1000 my $refContents = $$aReferenceLogContents;
1002 my $scriptName = $aReferenceTestResults->ScriptName();
1003 my $testHarness = $aReferenceTestResults->TestHarness();
1006 my @inconclusives = $aReferenceTestResults->Inconclusives();
1007 $aReferenceTestResults->ResetInconclusives();
1008 foreach my $inconclusive (@inconclusives)
1010 if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest))
1012 my $testcasesInUse = 0;
1013 if ($testHarness eq $TestScriptResults::KTEFTest)
1015 $testcasesInUse = 1;
1017 if (MatchingTEFInconclusiveResult($inconclusive, \$refContents, $testcasesInUse))
1019 $inconText = $inconText . "$inconclusive\n";
1023 $aReferenceTestResults->AddInconclusiveResult($inconclusive);
1026 elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest)
1028 if (MatchingTFInconclusiveResult($inconclusive, \$refContents))
1030 $inconText = $inconText . "$inconclusive\n";
1034 $aReferenceTestResults->AddInconclusiveResult($inconclusive);
1037 # Core Conf tests have no comprehension of inconclusive
1041 my @failures = $aReferenceTestResults->Failures();
1042 $aReferenceTestResults->ResetFailures();
1043 foreach my $failure (@failures)
1045 if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest))
1047 my $testcasesInUse = 0;
1048 if ($testHarness eq $TestScriptResults::KTEFTest)
1050 $testcasesInUse = 1;
1052 if (MatchingTEFErrorResult($failure, \$refContents, $testcasesInUse))
1054 $failText = $failText . "$failure\n";
1058 $aReferenceTestResults->AddFailureResult($failure);
1061 elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest)
1063 if (MatchingTFErrorResult($failure, \$refContents))
1065 $failText = $failText . "$failure\n";
1069 $aReferenceTestResults->AddFailureResult($failure);
1075 if (MatchingCoreConfErrorResult($failure, \$refContents))
1077 $failText = $failText . "$failure\n";
1081 $aReferenceTestResults->AddFailureResult($failure);
1087 if (($aReferenceTestResults->DidItCrash()) && $aRefTestCrashed)
1090 $aReferenceTestResults->ResetCrashed();
1093 if ($inconText || $failText || $bothCrashed)
1095 $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "\n$scriptName\n";
1100 $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "INCONCLUSIVES:\n$inconText";
1104 $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "FAILS:\n$failText";
1108 $iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "CRASHED\n";
1112 ###############################################
1113 ## Utility functions
1114 ###############################################
1118 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";
1119 print " -m = Mode of operation, specify the source of the results that you are\n";
1120 print " comparing. Currently supported modes: Mistral, Local\n\n";
1121 print " -s = Source of the results, mode dependant:\n";
1122 print " (i) Mistral = The URL of the test results HTML summary page\n";
1123 print " (ii) Local = The pathname of a folder containing the test log files\n\n";
1124 print " -k = Pathname of the KF sheet, this should be exported as an XML spreadsheet\n";
1125 print " from Excel\n\n";
1126 print " -r = Reference Mistral build, the URL of the test results HTML summary page.\n";
1127 print " This can be used in addition or in place of the Known Failure sheet\n\n";
1128 print " -i = Ignore test failures in scripts not found in the Reference Mistral build\n\n";
1129 print " -c = An index indicating the codeline used in the test run, only used in\n";
1130 print " conjunction with a KF sheet. Possible values: TB92, TB101, TB102\n\n";
1131 print " -p = An index indicating the platform the test run is from, only used in\n";
1132 print " conjunction with a KF sheet. Possible values: Winscw, H6, H4 WDP,\n";
1133 print " NaviEngine\n\n";
1134 print " -v = Verbose output\n\n";
1137 ###############################################
1138 ## Main processing loop
1139 ###############################################
1141 # Read in parameters
1143 getopts('ihvm:s:k:r:c:p:', \%aParams);
1150 $iVerbose = $aParams{v};
1152 # The mode affects where we get the source files from and nothing else.
1154 if ($aParams{m} =~ m/\AMistral\Z/i)
1156 @runResults = @{PopulateResultsArrayFromMistral($aParams{s})};
1158 elsif ($aParams{m} =~ m/\ALocal\Z/i)
1160 @runResults = @{PopulateResultsArrayFromLocalMachine($aParams{s})};
1164 print "\nERROR: Operation mode absent or not recognised.\n";
1172 $kfPlatforms[0] = "All";
1174 # KF sheet in use, codeline and platform arguments are required in order to search for matching failures
1175 my $codeline = $aParams{c};
1176 my $platform = $aParams{p};
1177 unless (($codeline eq "TB92") || ($codeline eq "TB101") || ($codeline eq "TB102"))
1179 print "\nERROR: The codeline specified was not recognised, supported options: TB92, TB101, TB102.\n";
1183 if ($platform eq "Winscw")
1185 $kfPlatforms[1] = "All Winscw";
1187 elsif (($platform eq "H6") || ($platform eq "H4 WDP") || ($platform eq "NaviEngine"))
1189 $kfPlatforms[1] = "All HW";
1193 print "\nERROR: The platform specified was not recognised, supported options: Winscw, H6, H4 WDP, NaviEngine.\n";
1197 $kfPlatforms[2] = "$codeline $platform";
1202 print "\nLog files found:\n";
1203 foreach my $file (@runResults)
1205 my $scriptName = $file->ScriptName();
1206 print "$scriptName\n";
1210 AnalyseFailures($aParams{k}, $aParams{r}, $aParams{i}, \@runResults, \@kfPlatforms);
1212 print "\n\nKnown failures:\n";
1213 print "------------------\n";
1214 print "$iKnownFails\n\n";
1216 print "Unknown failures but found in the reference build:\n";
1217 print "----------------------------------------------------\n";
1218 print "$iUnknownFailsButKnownInRef\n\n";
1220 print "Unknown failures but known in other codelines:\n";
1221 print "------------------------------------------------\n";
1222 print "$iUnknownFailsButKnownInOtherCodelines\n\n";
1224 print "Unknown failures:\n";
1225 print "-------------------\n";
1226 print "$iUnknownFails\n\n";
1228 print "Tests with reduced test counts:\n";
1229 print "---------------------------------\n";
1230 print "$iMissingTests\n\n";