os/mm/mmtestenv/mmtesttools/Scripts/TestResultsComparisonTool/ResultsComparison.pl
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
# All rights reserved.
sl@0
     3
# This component and the accompanying materials are made available
sl@0
     4
# under the terms of "Eclipse Public License v1.0"
sl@0
     5
# which accompanies this distribution, and is available
sl@0
     6
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
#
sl@0
     8
# Initial Contributors:
sl@0
     9
# Nokia Corporation - initial contribution.
sl@0
    10
#
sl@0
    11
# Contributors:
sl@0
    12
#
sl@0
    13
# Description:
sl@0
    14
#
sl@0
    15
sl@0
    16
use strict;
sl@0
    17
use LWP::Simple;
sl@0
    18
use TestScriptResults;
sl@0
    19
use Getopt::Std;
sl@0
    20
use File::Find;
sl@0
    21
sl@0
    22
# Mistral tags the result files from test scripts in a particular format, depending on the test harness used to execute them. 
sl@0
    23
# We use these names to identify which files are results files.
sl@0
    24
my $KMistralCoreConfFileName = "-coreconf-";
sl@0
    25
my $KMistralTEFFileName = "-testexecute-";
sl@0
    26
my $KMistralTestFrameworkFileName = "-testframework"; # No trailing hyphen due to different security variants
sl@0
    27
sl@0
    28
#  It appears that Mistral uses a completely different file format for results from HW runs
sl@0
    29
my $KMistrealTEFFileNameHW = "testexecute";
sl@0
    30
my $KMistrealTFFileNameHW1 = "testframework";
sl@0
    31
my $KMistrealTFFileNameHW2 = "testframeworkmmddcap";
sl@0
    32
my $KMistrealTFFileNameHW3 = "testframeworkuecap";
sl@0
    33
my $KMistrealTFFileNameHW4 = "testframeworknone";
sl@0
    34
sl@0
    35
# Work in progress script outputs.
sl@0
    36
my $iKnownFails;
sl@0
    37
my $iUnknownFailsButKnownInRef;
sl@0
    38
my $iUnknownFailsButKnownInOtherCodelines;
sl@0
    39
my $iUnknownFails;
sl@0
    40
my $iMissingTests; 	
sl@0
    41
sl@0
    42
my $iVerbose;
sl@0
    43
sl@0
    44
###############################################
sl@0
    45
##	Source test domain specific functionality
sl@0
    46
###############################################
sl@0
    47
# Scans the test results summary page from the Mistral build and compiles a collection of the 
sl@0
    48
# URL paths for the log files.
sl@0
    49
# param1 - the URL to the Test Results HTML Summary page of the Mistral build
sl@0
    50
# returns - the array of logs' URLS
sl@0
    51
sub GetResultFilesFromMistral
sl@0
    52
	{
sl@0
    53
	my $aMistralTestResultsSummaryUrl = shift;
sl@0
    54
sl@0
    55
	my @fileNames;
sl@0
    56
	my $nextFileNamesIndex = 0;
sl@0
    57
sl@0
    58
	my $summaryContents = get "$aMistralTestResultsSummaryUrl"; # Returns undef if failure
sl@0
    59
	unless ($summaryContents)
sl@0
    60
		{
sl@0
    61
		print "\nERROR: Unable to retrieve source summary file from $aMistralTestResultsSummaryUrl\n";
sl@0
    62
		exit;
sl@0
    63
		}
sl@0
    64
	
sl@0
    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
sl@0
    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
sl@0
    67
	#So it's simpler to do the brute force approach and keep all implementations alike, it doesn't take long anyway
sl@0
    68
	while ($summaryContents =~ s/href="(.*?($KMistralCoreConfFileName|$KMistralTEFFileName|$KMistralTestFrameworkFileName).*?\.html?)"//i)
sl@0
    69
		{
sl@0
    70
		$fileNames[$nextFileNamesIndex] = $1;
sl@0
    71
		$nextFileNamesIndex++;
sl@0
    72
		}
sl@0
    73
sl@0
    74
	# Scan this second so we don't accidentally cut off the filenames if they are matched against Winscw runs
sl@0
    75
	while ($summaryContents =~ s/href="(.*?($KMistrealTEFFileNameHW|$KMistrealTFFileNameHW1|$KMistrealTFFileNameHW2|$KMistrealTFFileNameHW3|$KMistrealTFFileNameHW4).*?\.html?)"//i)
sl@0
    76
		{
sl@0
    77
		$fileNames[$nextFileNamesIndex] = $1;
sl@0
    78
		$nextFileNamesIndex++;
sl@0
    79
		}
sl@0
    80
	
sl@0
    81
	unless ($fileNames[0])
sl@0
    82
		{
sl@0
    83
		print "\nERROR: No test result log files found, please ensure the -s parameter points to Mistral's TestResults.html summary page\n";	
sl@0
    84
		exit;
sl@0
    85
		}
sl@0
    86
		
sl@0
    87
	return @fileNames;
sl@0
    88
	}
sl@0
    89
sl@0
    90
# Parse the Mistral test results summary page and generate an array of TestScriptResults
sl@0
    91
# objects which contain all the required information such as script names, test counts
sl@0
    92
# and failures.
sl@0
    93
# param1 - the URL of the Test Results HTML Summary page for the Mistral build 
sl@0
    94
# returns - the array of parsed log data
sl@0
    95
sub PopulateResultsArrayFromMistral
sl@0
    96
	{
sl@0
    97
	my $aTestResultsSummaryPageUrl = shift;
sl@0
    98
	my @aResultsArray = ();
sl@0
    99
	my $nextFreeIndexInResultsArray = 0;
sl@0
   100
	
sl@0
   101
	my @fileNames = GetResultFilesFromMistral($aTestResultsSummaryPageUrl);
sl@0
   102
	foreach my $fileName (@fileNames)
sl@0
   103
		{
sl@0
   104
		my $testFileContents = get "$fileName";
sl@0
   105
		unless ($testFileContents)
sl@0
   106
			{
sl@0
   107
			print "\nERROR: Unable to open logfile $fileName\n";
sl@0
   108
			next;
sl@0
   109
			}
sl@0
   110
			
sl@0
   111
		my $scriptResults = TestScriptResults->TestScriptResults();
sl@0
   112
		$scriptResults->SetFilePath($fileName);		
sl@0
   113
		if (($fileName =~ m/.*?$KMistralTEFFileName(.*?)\.html?/i) || ($fileName =~ m/.*?$KMistrealTEFFileNameHW(.*?)\.html?/i))
sl@0
   114
			{
sl@0
   115
			$scriptResults->SetScriptName($1);
sl@0
   116
			if (!($testFileContents =~ m/TEST CASE SUMMARY:/i) && ($testFileContents =~ m/SUMMARY:/i))
sl@0
   117
				{
sl@0
   118
				# One of the old MM TEF tests which didn't use testcases
sl@0
   119
				$scriptResults->TEFNoTestcasesTest();
sl@0
   120
				$aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 0);
sl@0
   121
				}
sl@0
   122
			else
sl@0
   123
				{
sl@0
   124
				$scriptResults->TEFTest();
sl@0
   125
				$aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 1);
sl@0
   126
				}	
sl@0
   127
			}
sl@0
   128
		elsif ($fileName =~ m/.*?$KMistralCoreConfFileName(.*?)\.txt\.html?/i)
sl@0
   129
			{
sl@0
   130
			$scriptResults->SetScriptName($1);
sl@0
   131
			$scriptResults->CoreConfTest();
sl@0
   132
			$aResultsArray[$nextFreeIndexInResultsArray] = ScanCoreConfLogFileForFailures($scriptResults, \$testFileContents);
sl@0
   133
			}
sl@0
   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))
sl@0
   135
			{
sl@0
   136
			$scriptResults->SetScriptName($1);
sl@0
   137
			$scriptResults->TestFrameworkTest();
sl@0
   138
			
sl@0
   139
			$aResultsArray[$nextFreeIndexInResultsArray] = ScanTestFrameworkLogFileForFailures($scriptResults, \$testFileContents);
sl@0
   140
			}
sl@0
   141
		else
sl@0
   142
			{
sl@0
   143
			print "\nWARNING: Results file has unrecognised format - $fileName.\n";			
sl@0
   144
			}
sl@0
   145
		$nextFreeIndexInResultsArray++;	
sl@0
   146
		}
sl@0
   147
	
sl@0
   148
	return \@aResultsArray;
sl@0
   149
	}
sl@0
   150
	
sl@0
   151
sl@0
   152
# Walk the file path provided by the developer for his local machine, parse test logs
sl@0
   153
#  and generate an array of TestScriptResults objects which contain all the required 
sl@0
   154
# information such as script names, test counts and failures.
sl@0
   155
# param1 - the pathname of a folder containing the test results
sl@0
   156
# returns - the array of parsed log data
sl@0
   157
sub PopulateResultsArrayFromLocalMachine
sl@0
   158
	{
sl@0
   159
	my $aTestResultsPath = shift;
sl@0
   160
	my @aResultsArray = ();
sl@0
   161
	my $nextFreeIndexInResultsArray = 0;
sl@0
   162
sl@0
   163
	my @directories = ("$aTestResultsPath");
sl@0
   164
	my @fileNames;
sl@0
   165
	find( sub { push @fileNames, $File::Find::name if /\.html?$/ }, @directories );
sl@0
   166
sl@0
   167
	foreach my $fileName (@fileNames)
sl@0
   168
		{
sl@0
   169
		my $testFileContents = do { local $/; open(I,"$fileName"); <I> };
sl@0
   170
		my $scriptResults = TestScriptResults->TestScriptResults();
sl@0
   171
		$scriptResults->SetFilePath($fileName);
sl@0
   172
		$fileName =~ m/([^\\\/\.]*)\.[^\\\/]*\Z/;
sl@0
   173
		$scriptResults->SetScriptName($1);
sl@0
   174
		
sl@0
   175
		if ($testFileContents =~ m/Core Loader Conformance Suite/)
sl@0
   176
			{
sl@0
   177
			$scriptResults->CoreConfTest();
sl@0
   178
			$aResultsArray[$nextFreeIndexInResultsArray] = ScanCoreConfLogFileForFailures($scriptResults, \$testFileContents);
sl@0
   179
			}
sl@0
   180
		elsif ($testFileContents =~ m/TestFrameworkMain.cpp/)
sl@0
   181
			{
sl@0
   182
			$scriptResults->TestFrameworkTest();
sl@0
   183
			$aResultsArray[$nextFreeIndexInResultsArray] = ScanTestFrameworkLogFileForFailures($scriptResults, \$testFileContents);
sl@0
   184
			}
sl@0
   185
		elsif ($testFileContents =~ m/TEF Version/)
sl@0
   186
			{
sl@0
   187
			if ($testFileContents =~ m/TEST CASE SUMMARY:/i)
sl@0
   188
				{
sl@0
   189
				$scriptResults->TEFTest();
sl@0
   190
				$aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 1);
sl@0
   191
				}
sl@0
   192
			else
sl@0
   193
				{
sl@0
   194
				# One of the old MM TEF tests which didn't use testcases
sl@0
   195
				$scriptResults->TEFNoTestcasesTest();
sl@0
   196
				$aResultsArray[$nextFreeIndexInResultsArray] = ScanTEFLogFileForFailures($scriptResults, \$testFileContents, 0);
sl@0
   197
				}			
sl@0
   198
			}
sl@0
   199
		else
sl@0
   200
			{
sl@0
   201
			print "\nWARNING: Results file has unrecognised format - $fileName.\n";	
sl@0
   202
			}
sl@0
   203
					
sl@0
   204
		$nextFreeIndexInResultsArray++;	
sl@0
   205
		}
sl@0
   206
	
sl@0
   207
	return \@aResultsArray;
sl@0
   208
	}
sl@0
   209
	
sl@0
   210
###############################################
sl@0
   211
##	Test harness specific functionality
sl@0
   212
###############################################	
sl@0
   213
sl@0
   214
# Parses a TF log file for failures, inconclusives and crashes
sl@0
   215
# param1 - the TestScriptResults object to populate
sl@0
   216
# param2 - reference to the contents of the log file
sl@0
   217
# returns - the TestScriptResults object containing the parsed data
sl@0
   218
sub ScanTestFrameworkLogFileForFailures
sl@0
   219
	{
sl@0
   220
	my ($aScriptResults, $aLogFileContents) = @_;
sl@0
   221
	
sl@0
   222
	my $testFileContents = $$aLogFileContents;
sl@0
   223
	my $numberOfTests = 0;
sl@0
   224
	# Search for test case results, which take the following form:
sl@0
   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
sl@0
   226
	while ($testFileContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:([\_|\-|\S]+)[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   227
		{
sl@0
   228
		my $testId  = $1;
sl@0
   229
	    my $result = $2;
sl@0
   230
	    $numberOfTests++;
sl@0
   231
		if ($result =~ /PASS/)
sl@0
   232
			{
sl@0
   233
			# Do nothing
sl@0
   234
			}
sl@0
   235
		elsif ($result =~ /INCONCLUSIVE/)
sl@0
   236
			{
sl@0
   237
			$aScriptResults->AddInconclusiveResult($testId);
sl@0
   238
			}
sl@0
   239
		else
sl@0
   240
			{
sl@0
   241
			# Treat all other results as failure
sl@0
   242
			$aScriptResults->AddFailureResult($testId);
sl@0
   243
			}
sl@0
   244
		}
sl@0
   245
	$aScriptResults->SetTotalTestCount($numberOfTests);
sl@0
   246
	
sl@0
   247
	unless ($testFileContents =~ m/Test Results Summary/)
sl@0
   248
		{
sl@0
   249
		# Test file summary not in the log file - the test has crashed
sl@0
   250
		$aScriptResults->TestCrashed();
sl@0
   251
		}
sl@0
   252
	
sl@0
   253
	return $aScriptResults;
sl@0
   254
	}
sl@0
   255
sl@0
   256
# Parses a TEF log file for failures, inconclusives and crashes
sl@0
   257
# param1 - the TestScriptResults object to populate
sl@0
   258
# param2 - reference to the contents of the log file
sl@0
   259
# param3 - boolean whether the test is using testcases (older MM tests didn't, in which case we use the test steps)
sl@0
   260
# returns - the TestScriptResults object containing the parsed data
sl@0
   261
sub ScanTEFLogFileForFailures
sl@0
   262
	{
sl@0
   263
	my ($aScriptResults, $aLogFileContents, $aTestcasesInUse) = @_;
sl@0
   264
	
sl@0
   265
	my $testFileContents = $$aLogFileContents;
sl@0
   266
	my $numberOfTests = 0;
sl@0
   267
sl@0
   268
	# Search for test case results, which take the following form:
sl@0
   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 
sl@0
   270
	# Or if testcases not in use in this script file test step results, which take the following form:
sl@0
   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 
sl@0
   272
	while (($testFileContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+([\_|\-|\S]+)[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   273
			|| (!$aTestcasesInUse && ($testFileContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+([\_|\-|\S]+)[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)))
sl@0
   274
		{
sl@0
   275
		my $testId  = $1;
sl@0
   276
	    my $result = $2;
sl@0
   277
	    $numberOfTests++;
sl@0
   278
		if ($result =~ /PASS/)
sl@0
   279
			{
sl@0
   280
			# Do nothing
sl@0
   281
			}
sl@0
   282
		elsif ($result =~ /INCONCLUSIVE/)
sl@0
   283
			{
sl@0
   284
			$aScriptResults->AddInconclusiveResult($testId);
sl@0
   285
			}
sl@0
   286
		else
sl@0
   287
			{
sl@0
   288
			# Treat all other results as failure
sl@0
   289
			$aScriptResults->AddFailureResult($testId);
sl@0
   290
			}
sl@0
   291
		}
sl@0
   292
	$aScriptResults->SetTotalTestCount($numberOfTests);
sl@0
   293
	
sl@0
   294
	# Testcase scripts use TEST CASE SUMMARY, non-testcase scripts just use SUMMARY
sl@0
   295
	unless ($testFileContents =~ m/SUMMARY:/)
sl@0
   296
		{
sl@0
   297
		# Test file summary not in the log file - the test has crashed
sl@0
   298
		$aScriptResults->TestCrashed();
sl@0
   299
		}
sl@0
   300
	
sl@0
   301
	return $aScriptResults;	
sl@0
   302
	}
sl@0
   303
sl@0
   304
# Parses a CoreConf log file for failures, inconclusives and crashes
sl@0
   305
# param1 - the TestScriptResults object to populate
sl@0
   306
# param2 - reference to the contents of the log file
sl@0
   307
# returns - the TestScriptResults object containing the parsed data	
sl@0
   308
sub ScanCoreConfLogFileForFailures
sl@0
   309
	{
sl@0
   310
	my ($aScriptResults, $aLogFileContents) = @_;
sl@0
   311
	my $testFileContents = $$aLogFileContents;
sl@0
   312
	
sl@0
   313
	if ($testFileContents =~ s/\*\*\*\s*?Summary of tests executed(.*\n)*//)
sl@0
   314
		{
sl@0
   315
		my $numberOfTests = 0;
sl@0
   316
sl@0
   317
		# Parse the summary listings
sl@0
   318
		while($testFileContents =~ s/\*\*\*\s*?Passed tests:((.*\n)*?)\*\*\*\s*?Failed tests:.*\n((\*\*\*.*\n)*)//)
sl@0
   319
			{
sl@0
   320
			my $passingTests = $1;
sl@0
   321
			my $failingTests = $3;
sl@0
   322
			
sl@0
   323
			# Passing tests
sl@0
   324
			while ($passingTests =~ s/\*\*\*[\s]*?\S+[\s]*\n//)
sl@0
   325
				{
sl@0
   326
				$numberOfTests++;
sl@0
   327
				}
sl@0
   328
			
sl@0
   329
			# Failing tests
sl@0
   330
			while ($failingTests =~ s/\*\*\*[\s]*?(\S+)[\s]*\n//)
sl@0
   331
				{
sl@0
   332
				$aScriptResults->AddFailureResult($1);
sl@0
   333
				$numberOfTests++;
sl@0
   334
				}			
sl@0
   335
			}
sl@0
   336
sl@0
   337
		$aScriptResults->SetTotalTestCount($numberOfTests);		
sl@0
   338
		}
sl@0
   339
	else
sl@0
   340
		{
sl@0
   341
		# Test file summary not in the log file - the test has crashed
sl@0
   342
		$aScriptResults->TestCrashed();		
sl@0
   343
		}
sl@0
   344
	
sl@0
   345
	return $aScriptResults;		
sl@0
   346
	}
sl@0
   347
sl@0
   348
# Gets the test case count from a Test Execute Framework log file
sl@0
   349
# param1 - a reference to the contents of the TEF log file
sl@0
   350
#returns - The number of test cases in the script or -1 if the summary could not be found
sl@0
   351
sub GetTEFTestCount
sl@0
   352
	{
sl@0
   353
	my $aReferenceLogContents = shift;
sl@0
   354
	my $refContents = $$aReferenceLogContents;
sl@0
   355
sl@0
   356
	if ($refContents =~ m/TEST CASE SUMMARY:(.*\n)*?.*?PASS =\s*(\d*)(.*\n)*?.*?FAIL =\s*(\d*)(.*\n)*?.*?INCONCLUSIVE =\s*(\d*)/)
sl@0
   357
		{
sl@0
   358
		my $result = $2 + $4 + $6;
sl@0
   359
		return $result;
sl@0
   360
		}
sl@0
   361
	
sl@0
   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*)/)	
sl@0
   363
		{
sl@0
   364
		# One of the MM tests that doesn't use testcases
sl@0
   365
		my $result = $2 + $4 + $6 + $8 + $10 + $12 + $14;
sl@0
   366
		return $result;
sl@0
   367
		}									
sl@0
   368
	
sl@0
   369
	# Summary not found, we crashed
sl@0
   370
	return -1;
sl@0
   371
	}
sl@0
   372
sl@0
   373
# Gets the test count from a Test Framework log file
sl@0
   374
# param1 - a reference to the contents of the Test Framework log file
sl@0
   375
#returns - The number of test cases in the script or -1 if the summary could not be found	
sl@0
   376
sub GetTestFrameworkTestCount
sl@0
   377
	{
sl@0
   378
	my $aReferenceLogContents = shift;
sl@0
   379
	my $refContents = $$aReferenceLogContents;
sl@0
   380
	
sl@0
   381
	unless ($refContents =~ m/Test Results Summary(.*\n)*?.*?Total\s*:(\d*)\s*\n/)
sl@0
   382
		{
sl@0
   383
		# Summary not found, we crashed
sl@0
   384
		return -1;
sl@0
   385
		}
sl@0
   386
	return $2;
sl@0
   387
	}
sl@0
   388
sl@0
   389
# Gets the test count from an OpenMAX IL Core Conformance log file
sl@0
   390
# param1 - a reference to the contents of the Core Conformance log file
sl@0
   391
#returns - The number of test cases in the script or -1 if the summary could not be found	
sl@0
   392
sub GetCoreConfTestCount
sl@0
   393
	{
sl@0
   394
	my $aReferenceLogContents = shift;
sl@0
   395
	my $refContents = $$aReferenceLogContents;
sl@0
   396
	
sl@0
   397
	unless ($refContents =~ m/\*\*\*\s*Summary of tests executed(.*\n)*?\*\*\*\s*Total :\s*(\d*)\s*\n/)
sl@0
   398
		{
sl@0
   399
		# Summary not found, we crashed
sl@0
   400
		return -1;
sl@0
   401
		}
sl@0
   402
	return $2;
sl@0
   403
	}
sl@0
   404
sl@0
   405
# Scans a TEF log looking for the test specified and checks if it returned inconclusive
sl@0
   406
# param1 - the test name
sl@0
   407
# param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
sl@0
   408
# param3 - whether the TEF script uses testcases
sl@0
   409
# returns - 1 if it returned inconclusive, 0 otherwise	
sl@0
   410
sub MatchingTEFInconclusiveResult	
sl@0
   411
	{
sl@0
   412
	my $aInconclusive = shift;
sl@0
   413
	my $aReferenceLogContents = shift;
sl@0
   414
	my $aTestcasesInUse = shift;
sl@0
   415
	my $refContents = $$aReferenceLogContents;
sl@0
   416
	if ($aTestcasesInUse)
sl@0
   417
		{
sl@0
   418
		if ($refContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+$aInconclusive[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   419
			{
sl@0
   420
			if ($1 eq "INCONCLUSIVE")
sl@0
   421
				{
sl@0
   422
				return 1;
sl@0
   423
				}
sl@0
   424
			}
sl@0
   425
		}
sl@0
   426
	else
sl@0
   427
		{
sl@0
   428
		if ($refContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+$aInconclusive[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   429
			{
sl@0
   430
			if ($1 eq "INCONCLUSIVE")
sl@0
   431
				{
sl@0
   432
				return 1;
sl@0
   433
				}
sl@0
   434
			}
sl@0
   435
		}
sl@0
   436
	return 0;
sl@0
   437
	}
sl@0
   438
sl@0
   439
# Scans a TestFramework log looking for the test specified and checks if it returned inconclusive
sl@0
   440
# param1 - the test name
sl@0
   441
# param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
sl@0
   442
# returns - 1 if it returned inconclusive, 0 otherwise		
sl@0
   443
sub MatchingTFInconclusiveResult 
sl@0
   444
	{
sl@0
   445
	my $aInconclusive = shift;
sl@0
   446
	my $aReferenceLogContents = shift;
sl@0
   447
	my $refContents = $$aReferenceLogContents;
sl@0
   448
	if ($refContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:$aInconclusive[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   449
		{
sl@0
   450
		if ($1 eq "INCONCLUSIVE")
sl@0
   451
			{
sl@0
   452
			return 1;
sl@0
   453
			}
sl@0
   454
		}
sl@0
   455
	return 0;
sl@0
   456
	}
sl@0
   457
sl@0
   458
# Scans a TEF log looking for the test specified and checks if it returned an error
sl@0
   459
# param1 - the test name
sl@0
   460
# param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
sl@0
   461
# param3 - whether the TEF script uses testcases
sl@0
   462
# returns - 1 if it returned an error, 0 otherwise		
sl@0
   463
sub MatchingTEFErrorResult 
sl@0
   464
	{
sl@0
   465
	my $aFail = shift;
sl@0
   466
	my $aReferenceLogContents = shift;
sl@0
   467
	my $aTestcasesInUse = shift;
sl@0
   468
	my $refContents = $$aReferenceLogContents;
sl@0
   469
	
sl@0
   470
	if ($aTestcasesInUse)
sl@0
   471
		{
sl@0
   472
		if (not $refContents =~ s/Command[\s]+=[\s]+END\_TESTCASE[\s]+$aFail[\s]+\*\*\*TestCaseResult[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   473
			{
sl@0
   474
			return 0;
sl@0
   475
			}
sl@0
   476
	
sl@0
   477
		if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE"))
sl@0
   478
			{
sl@0
   479
			return 0;
sl@0
   480
			}
sl@0
   481
		}
sl@0
   482
	else
sl@0
   483
		{
sl@0
   484
		if (not $refContents =~ s/Command[\s]+=[\s]+RUN\_TEST\_STEP[\s]+\d*[\s]+.*?[\s]+$aFail[\s]+.*?\*\*\*Result[\s]+=[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   485
			{
sl@0
   486
			return 0;
sl@0
   487
			}
sl@0
   488
	
sl@0
   489
		if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE"))
sl@0
   490
			{
sl@0
   491
			return 0;
sl@0
   492
			}
sl@0
   493
		}
sl@0
   494
		
sl@0
   495
	return 1;
sl@0
   496
	}	
sl@0
   497
	
sl@0
   498
# Scans a TestFramework log looking for the test specified and checks if it returned an error
sl@0
   499
# param1 - the test name
sl@0
   500
# param2 - reference to the contents of the log file, the test case result is removed from the argument if passed by ref
sl@0
   501
# returns - 1 if it returned an error, 0 otherwise		
sl@0
   502
sub MatchingTFErrorResult 
sl@0
   503
	{
sl@0
   504
	my $aFail = shift;
sl@0
   505
	my $aReferenceLogContents = shift;
sl@0
   506
	my $refContents = $$aReferenceLogContents;
sl@0
   507
	if (not $refContents =~ s/Test[\s]+Result[\s]+for[\s]+[\S]+:$aFail[\s]+is[\s]+([\_|\-|\S]+)[\s]*\<\/font\>//)
sl@0
   508
		{
sl@0
   509
		return 0;
sl@0
   510
		}
sl@0
   511
	
sl@0
   512
	if (($1 eq "PASS") || ($1 eq "INCONCLUSIVE"))
sl@0
   513
		{
sl@0
   514
		return 0;
sl@0
   515
		}
sl@0
   516
		
sl@0
   517
	return 1;
sl@0
   518
	}	
sl@0
   519
	
sl@0
   520
# N.B. VERY IMPORTANT that the log file is passed by reference.  Core conf scripts can include numerous
sl@0
   521
# different tests that use the same test name so to avoid false positives from this function the 
sl@0
   522
# substitution done in the comparison MUST affect the caller's copy of the log file.
sl@0
   523
sub MatchingCoreConfErrorResult
sl@0
   524
	{	
sl@0
   525
	my $aFail = shift;
sl@0
   526
	my $aReferenceLogContents = shift;
sl@0
   527
	my $refContents = $$aReferenceLogContents;
sl@0
   528
	
sl@0
   529
	if ($refContents =~ s/\*\*\*[\s]*$aFail[\s]*FAILED//)
sl@0
   530
		{
sl@0
   531
		return 1;
sl@0
   532
		}
sl@0
   533
sl@0
   534
	return 0;	
sl@0
   535
	}
sl@0
   536
	
sl@0
   537
###############################################		
sl@0
   538
##	Failure comparison functions
sl@0
   539
###############################################		
sl@0
   540
sl@0
   541
# The analysis takes an array of TestScriptResults, each storing the results of a test script's log file.
sl@0
   542
# It processes this list in stages looking for any scripts with errors and trying to match them against
sl@0
   543
# entries in a Known Failure sheet and/or comparison reference build.  Whenever a match is found
sl@0
   544
# the error is removed from the TestScriptResults object, these essentially act as an object containing
sl@0
   545
# unresolved errors.  When errors are matched their details are added to the corresponding text 
sl@0
   546
# variables at the top of this file (e.g. iKnownFails).
sl@0
   547
sub AnalyseFailures
sl@0
   548
	{
sl@0
   549
	my ($aKFSheetLocation, $aReferenceMistralURL, $aIgnoreFailsNotInRef, $aResultsRef, $aKfPlatforms) = @_;
sl@0
   550
sl@0
   551
	my @results = @$aResultsRef;
sl@0
   552
	
sl@0
   553
	my $refContents = undef;
sl@0
   554
	if ($aReferenceMistralURL)
sl@0
   555
		{
sl@0
   556
		$refContents = get "$aReferenceMistralURL"; # Returns undef if failure
sl@0
   557
		unless ($refContents)
sl@0
   558
			{
sl@0
   559
			print "\nERROR: Unable to retrieve reference summary file from $aReferenceMistralURL\n";
sl@0
   560
			exit;
sl@0
   561
			}		
sl@0
   562
		}
sl@0
   563
	
sl@0
   564
	my $kfSheetContents = undef;
sl@0
   565
	if ($aKFSheetLocation)
sl@0
   566
		{
sl@0
   567
		unless ($aKFSheetLocation =~ m/\.xml\Z/i)
sl@0
   568
			{
sl@0
   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";	
sl@0
   570
			exit;
sl@0
   571
			}		
sl@0
   572
		$kfSheetContents = do { local $/; open(I,"$aKFSheetLocation"); <I> };
sl@0
   573
		unless ($kfSheetContents)
sl@0
   574
			{
sl@0
   575
			print "\nERROR: Unable to open KF sheet at $aKFSheetLocation\n";	
sl@0
   576
			exit;			
sl@0
   577
			}
sl@0
   578
		}
sl@0
   579
		
sl@0
   580
	foreach my $scriptResults (@results)
sl@0
   581
		{
sl@0
   582
		my $scriptName = $scriptResults->ScriptName();
sl@0
   583
		
sl@0
   584
		my $referenceResults = undef;
sl@0
   585
		
sl@0
   586
		# If a reference build was provided, find the corresponding log file
sl@0
   587
		if ($refContents)
sl@0
   588
			{
sl@0
   589
			# We use substitution here because some of the coreconf test scripts
sl@0
   590
			# have the same script name.  This ensures we don't keep referencing
sl@0
   591
			# against the same copy.  We cannot do the comparison on the script 
sl@0
   592
			# path because this isn't resilient to adding new tests or cross domain 
sl@0
   593
			# comparisons.
sl@0
   594
			# N.B. This assumes the test list ordering remains the same.
sl@0
   595
			# N.B. The optional .txt is for Core Conf tests
sl@0
   596
			$refContents =~ s/href="(.*?$scriptName(\.txt)?(\.script)?\.html?)"//;
sl@0
   597
			my $file = $1;
sl@0
   598
			if ($file eq undef)
sl@0
   599
				{
sl@0
   600
				if ($aIgnoreFailsNotInRef)
sl@0
   601
					{
sl@0
   602
					next;
sl@0
   603
					}
sl@0
   604
				print "\nWARNING: Unable to find $scriptName in Reference Build\n";	
sl@0
   605
				}
sl@0
   606
			else
sl@0
   607
				{
sl@0
   608
				$referenceResults = get "$file";	# returns undef on failure
sl@0
   609
				unless ($referenceResults)
sl@0
   610
					{
sl@0
   611
					print "\nWARNING: Unable to open $scriptName ($file) in Reference Build\n";			
sl@0
   612
					}
sl@0
   613
				}
sl@0
   614
			}
sl@0
   615
		
sl@0
   616
		my $refTestCrashed;
sl@0
   617
		# Check the test count hasn't decreased
sl@0
   618
		if ($referenceResults)
sl@0
   619
			{
sl@0
   620
			$refTestCrashed = CheckTestCount($scriptResults, \$referenceResults);
sl@0
   621
			}
sl@0
   622
			
sl@0
   623
		if (not $scriptResults->AnyFailures())
sl@0
   624
			{
sl@0
   625
			# No errors so move onto the next
sl@0
   626
			next;
sl@0
   627
			}
sl@0
   628
		
sl@0
   629
		if ($kfSheetContents)
sl@0
   630
			{
sl@0
   631
			ResolveFailuresAgainstKFSheet($scriptResults, \$kfSheetContents, $aKfPlatforms); 
sl@0
   632
		
sl@0
   633
			if (not $scriptResults->AnyFailures())
sl@0
   634
				{
sl@0
   635
				# All errors resolved against KF sheet so move onto the next
sl@0
   636
				next;
sl@0
   637
				}
sl@0
   638
			}	
sl@0
   639
		
sl@0
   640
		if ($referenceResults)
sl@0
   641
			{
sl@0
   642
			ResolveFailuresAgainstReferenceRun($scriptResults, $refTestCrashed, \$referenceResults);
sl@0
   643
			
sl@0
   644
			if (not $scriptResults->AnyFailures())
sl@0
   645
				{
sl@0
   646
				# All errors resolved against reference run so move onto the next
sl@0
   647
				next;
sl@0
   648
				}			
sl@0
   649
			}
sl@0
   650
		
sl@0
   651
		# Unknown failures
sl@0
   652
		$iUnknownFails = $iUnknownFails . "\n$scriptName\n";
sl@0
   653
		
sl@0
   654
		my $inconText;
sl@0
   655
		my @inconclusives = $scriptResults->Inconclusives();
sl@0
   656
		foreach my $inconclusive (@inconclusives)
sl@0
   657
			{
sl@0
   658
			$inconText = $inconText . "$inconclusive\n";
sl@0
   659
			}
sl@0
   660
		my $failText;
sl@0
   661
		my @failures = $scriptResults->Failures();
sl@0
   662
		foreach my $failure (@failures)
sl@0
   663
			{
sl@0
   664
			$failText = $failText . "$failure\n";
sl@0
   665
			}	
sl@0
   666
			
sl@0
   667
		if ($inconText)
sl@0
   668
			{
sl@0
   669
			$iUnknownFails = $iUnknownFails . "INCONCLUSIVES:\n$inconText";
sl@0
   670
			}
sl@0
   671
		if ($failText)
sl@0
   672
			{
sl@0
   673
			$iUnknownFails = $iUnknownFails . "FAILS:\n$failText";
sl@0
   674
			}
sl@0
   675
		if ($scriptResults->DidItCrash())	
sl@0
   676
			{
sl@0
   677
			$iUnknownFails = $iUnknownFails . "CRASHED\n";
sl@0
   678
			}
sl@0
   679
		}	
sl@0
   680
	
sl@0
   681
	}
sl@0
   682
sl@0
   683
# Will compare the test count of the test in question against the equivalent result from a reference build's log
sl@0
   684
# 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
   685
# has crashed.  As a side effect the return value indicates whether the test in question crashed or not (saves
sl@0
   686
# having to scan it twice).
sl@0
   687
# param1 - the log results to compare against the reference build's run
sl@0
   688
# param2 - the contents of the reference build's corresponding test log
sl@0
   689
# returns = 1 if the reference script crashed and we were unable to compare the counts, 0 otherwise
sl@0
   690
sub CheckTestCount
sl@0
   691
	{
sl@0
   692
	my ($aTestResultsObject, $aReferenceLogContents) = @_;
sl@0
   693
	
sl@0
   694
	my $testHarness = $aTestResultsObject->TestHarness();
sl@0
   695
	my $refTestCount;
sl@0
   696
	if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest))
sl@0
   697
		{
sl@0
   698
		$refTestCount = GetTEFTestCount($aReferenceLogContents);
sl@0
   699
		}
sl@0
   700
	elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest)
sl@0
   701
		{
sl@0
   702
		$refTestCount = GetTestFrameworkTestCount($aReferenceLogContents);
sl@0
   703
		}
sl@0
   704
	else
sl@0
   705
		{
sl@0
   706
		$refTestCount = GetCoreConfTestCount($aReferenceLogContents);
sl@0
   707
		}
sl@0
   708
	
sl@0
   709
	if ($refTestCount < 0)
sl@0
   710
		{
sl@0
   711
		# Reference test crashed
sl@0
   712
		unless ($aTestResultsObject->DidItCrash())
sl@0
   713
			{
sl@0
   714
			my $scriptName = $aTestResultsObject->ScriptName();
sl@0
   715
			print "\nWARNING: $scriptName crashed in the reference build, unable to compare test counts\n";
sl@0
   716
			}
sl@0
   717
		return 1;
sl@0
   718
		}
sl@0
   719
	
sl@0
   720
	my $testCount = $aTestResultsObject->TotalTestCount;
sl@0
   721
	if ($testCount < $refTestCount)
sl@0
   722
		{
sl@0
   723
		unless ($aTestResultsObject->DidItCrash())
sl@0
   724
			{
sl@0
   725
			my $testName = $aTestResultsObject->ScriptName();
sl@0
   726
			$iMissingTests = $iMissingTests . "$testName  Previous = $refTestCount, Current = $testCount\n"; 	
sl@0
   727
			}
sl@0
   728
		}
sl@0
   729
	return 0;	
sl@0
   730
	}	
sl@0
   731
sl@0
   732
# Will scan the Known Failure sheet for any entries indicating if the failures,inconclusives and/or crash
sl@0
   733
# witnessed in the script in question are already known. If so these will be appended to the known failures list
sl@0
   734
# and removed from the TestScriptResults object in question. If matching entries were found but existed for
sl@0
   735
# other codelines then this information is stored but the failures are not removed from the TestScriptResults 
sl@0
   736
# object.
sl@0
   737
# param1 - TestScriptResults object for the script with failures
sl@0
   738
# param2 - the contents of the known failure sheet
sl@0
   739
# param3 - the array of platform entries in the known failure sheet that are applicable to this run
sl@0
   740
sub ResolveFailuresAgainstKFSheet
sl@0
   741
	{
sl@0
   742
	my ($aScriptWithProblems, $aKfSheetContents, $aKfPlatforms) = @_;
sl@0
   743
	my $kfSheetContents = $$aKfSheetContents;
sl@0
   744
	my $scriptName = $aScriptWithProblems->ScriptName();
sl@0
   745
	
sl@0
   746
	my @kFApplicablePlatforms;
sl@0
   747
	if ($aKfPlatforms)
sl@0
   748
		{
sl@0
   749
		# Will error if undef
sl@0
   750
		@kFApplicablePlatforms = @$aKfPlatforms;
sl@0
   751
		}
sl@0
   752
sl@0
   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.
sl@0
   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
sl@0
   755
	# regexs.  And in reality underneath Perl shouldn't be doing that much in the way of optimisation versus this approach.
sl@0
   756
	my $wipKfSheet;
sl@0
   757
	my $candidatesForOtherPlatforms;
sl@0
   758
	my $foundSamePlatFails;
sl@0
   759
	my $foundSamePlatInconcs;
sl@0
   760
	my $foundSamePlatCrash;
sl@0
   761
	while ($kfSheetContents =~ s/<Row((.|\n)*?>)((.|\n)*?)<\/Row>//i)
sl@0
   762
		{
sl@0
   763
		my $row = $3;
sl@0
   764
		# Optimisation
sl@0
   765
		unless ($row =~ m/$scriptName/i)
sl@0
   766
			{
sl@0
   767
			$wipKfSheet = $wipKfSheet . "<Row>$row<\/Row>";
sl@0
   768
			next;
sl@0
   769
			}
sl@0
   770
		
sl@0
   771
		# None of the cells prior to the 'Scriptname' named cell are of any interest, now verify this row is actually for 
sl@0
   772
		# 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
   773
		my $applicable;
sl@0
   774
		while ($row =~ s/(<Cell(.|\n)*?<\/Cell>)//i)
sl@0
   775
			{
sl@0
   776
			my $cell = $1;
sl@0
   777
			if ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Scriptname\d*"\//i)
sl@0
   778
				{
sl@0
   779
				# Named field we're looking for
sl@0
   780
				if ($cell =~ m/$scriptName/i)
sl@0
   781
					{
sl@0
   782
					$applicable = 1;
sl@0
   783
					last;
sl@0
   784
					}
sl@0
   785
				else
sl@0
   786
					{
sl@0
   787
					$wipKfSheet = $wipKfSheet . "<Row>$cell\n$row<\/Row>";	# This entry isn't applicable to us, reinsert it into the KF sheet
sl@0
   788
					last;
sl@0
   789
					}
sl@0
   790
				}
sl@0
   791
			}
sl@0
   792
		unless ($applicable)
sl@0
   793
			{
sl@0
   794
			next;
sl@0
   795
			}
sl@0
   796
		
sl@0
   797
		# We are now dealing with a Row corresponding to the script in question
sl@0
   798
		# So pull out the relevant named cells contents
sl@0
   799
		my $crash;
sl@0
   800
		my $fails;
sl@0
   801
		my $inconclusives;
sl@0
   802
		my $targets;
sl@0
   803
		while ($row =~ s/(<Cell(.|\n)*?<\/Cell>)//i)
sl@0
   804
			{
sl@0
   805
			my $cell = $1;
sl@0
   806
			if ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="CrashedStatus\d*"\//i)
sl@0
   807
				{
sl@0
   808
				$crash = $cell;
sl@0
   809
				}
sl@0
   810
			elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Fails\d*"\//i)
sl@0
   811
				{
sl@0
   812
				$fails = $cell;			
sl@0
   813
				}
sl@0
   814
			elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Inconclusives\d*"\//i)
sl@0
   815
				{
sl@0
   816
				$inconclusives = $cell;			
sl@0
   817
				}
sl@0
   818
			elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Platforms\d*"\//i)
sl@0
   819
				{
sl@0
   820
				$targets = $cell;			
sl@0
   821
				}				
sl@0
   822
			}
sl@0
   823
			
sl@0
   824
		my $platformMatched;
sl@0
   825
		foreach my $platform (@kFApplicablePlatforms)
sl@0
   826
			{
sl@0
   827
			unless (($targets =~ m/$platform&#10;/i) || ($targets =~ m/$platform<\/Data>/i))	# To ensure for example that All isn't picked up by an All Winscw entry
sl@0
   828
				{
sl@0
   829
				next;	# Platform not found in the entry
sl@0
   830
				}		
sl@0
   831
			$platformMatched = 1;
sl@0
   832
sl@0
   833
			if (($aScriptWithProblems->DidItCrash()) && ($crash =~ m/Crashed/i))
sl@0
   834
				{
sl@0
   835
				$foundSamePlatCrash = 1;
sl@0
   836
				$aScriptWithProblems->ResetCrashed();
sl@0
   837
				}
sl@0
   838
				
sl@0
   839
			if ($fails)
sl@0
   840
				{
sl@0
   841
				my @failures = $aScriptWithProblems->Failures();
sl@0
   842
				$aScriptWithProblems->ResetFailures();
sl@0
   843
				foreach my $failure (@failures)
sl@0
   844
					{
sl@0
   845
					if (($fails =~ m/$failure/i) || ($fails =~ m/>ALL<\/Data>/))
sl@0
   846
						{
sl@0
   847
						$foundSamePlatFails = $foundSamePlatFails . "$failure\n";
sl@0
   848
						}
sl@0
   849
					else
sl@0
   850
						{
sl@0
   851
						
sl@0
   852
						$aScriptWithProblems->AddFailureResult($failure);
sl@0
   853
						}
sl@0
   854
					}
sl@0
   855
				}
sl@0
   856
sl@0
   857
			if ($inconclusives)
sl@0
   858
				{
sl@0
   859
				my @incons = $aScriptWithProblems->Inconclusives();
sl@0
   860
				$aScriptWithProblems->ResetInconclusives();
sl@0
   861
				foreach my $incon (@incons)
sl@0
   862
					{
sl@0
   863
					if (($inconclusives =~ m/$incon/i) || ($inconclusives =~ m/>ALL<\/Data>/))
sl@0
   864
						{
sl@0
   865
						$foundSamePlatInconcs = $foundSamePlatInconcs . "$incon\n";
sl@0
   866
						}
sl@0
   867
					else
sl@0
   868
						{
sl@0
   869
						$aScriptWithProblems->AddInconclusiveResult($incon);
sl@0
   870
						}
sl@0
   871
					}
sl@0
   872
				}
sl@0
   873
			}	# End of platform matching loop
sl@0
   874
		
sl@0
   875
		unless ($platformMatched)
sl@0
   876
			{
sl@0
   877
			# The row entry did not match any of the applicable platforms.  We need to keep checking for more appropriate rows.
sl@0
   878
			# 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
   879
			# in case the issue has been seen on other platforms.
sl@0
   880
	
sl@0
   881
			$candidatesForOtherPlatforms = $candidatesForOtherPlatforms . "<Row>$crash$fails$inconclusives<\/Row>";
sl@0
   882
			}
sl@0
   883
			
sl@0
   884
		}	# End of row scanning
sl@0
   885
	
sl@0
   886
sl@0
   887
	my $foundOtherPlatFails;
sl@0
   888
	my $foundOtherPlatInconcs;
sl@0
   889
	my $foundOtherPlatCrash;	
sl@0
   890
	if ($aScriptWithProblems->AnyFailures())	
sl@0
   891
		{
sl@0
   892
		# Failures remain, potentially matched against the rows for other platforms
sl@0
   893
		
sl@0
   894
		while ($candidatesForOtherPlatforms =~ s/<Row>((.|\n)*?)<\/Row>//i)
sl@0
   895
			{
sl@0
   896
			my $row = $1;
sl@0
   897
			my $crash;
sl@0
   898
			my $fails;
sl@0
   899
			my $inconclusives;
sl@0
   900
			while ($row =~ s/(<Cell(.|\n)*?<\/Cell>)//i)
sl@0
   901
				{
sl@0
   902
				my $cell = $1;
sl@0
   903
				if ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="CrashedStatus\d*"\//i)
sl@0
   904
					{
sl@0
   905
					$crash = $cell;
sl@0
   906
					}
sl@0
   907
				elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Fails\d*"\//i)
sl@0
   908
					{
sl@0
   909
					$fails = $cell;
sl@0
   910
					}
sl@0
   911
				elsif ($cell =~ m/<NamedCell\s*\n?\s*ss:Name="Inconclusives\d*"\//i)
sl@0
   912
					{
sl@0
   913
					$inconclusives = $cell;
sl@0
   914
					}					
sl@0
   915
				}	# End of stripping out content details
sl@0
   916
			
sl@0
   917
			if (($aScriptWithProblems->DidItCrash()) && ($crash =~ m/Crashed<\/Data>/i))
sl@0
   918
				{
sl@0
   919
				$foundOtherPlatCrash = 1;
sl@0
   920
				}
sl@0
   921
				
sl@0
   922
			if ($fails)
sl@0
   923
				{
sl@0
   924
				my @failures = $aScriptWithProblems->Failures();
sl@0
   925
				foreach my $failure (@failures)
sl@0
   926
					{
sl@0
   927
					if (($fails =~ m/$failure/i) || ($fails =~ m/>ALL<\/Data>/))
sl@0
   928
						{
sl@0
   929
						$foundOtherPlatFails = $foundOtherPlatFails . "$failure\n";
sl@0
   930
						}
sl@0
   931
					}
sl@0
   932
				}
sl@0
   933
sl@0
   934
			if ($inconclusives)
sl@0
   935
				{
sl@0
   936
				my @incons = $aScriptWithProblems->Inconclusives();
sl@0
   937
				foreach my $incon (@incons)
sl@0
   938
					{
sl@0
   939
					if (($inconclusives =~ m/$incon/i) || ($inconclusives =~ m/>ALL<\/Data>/))
sl@0
   940
						{
sl@0
   941
						$foundOtherPlatInconcs = $foundOtherPlatInconcs . "$incon\n";
sl@0
   942
						}
sl@0
   943
					}
sl@0
   944
				}
sl@0
   945
				
sl@0
   946
			}	# End of cross-platform candidate matchine
sl@0
   947
		}	# End of dealing with potential cross-platform matches
sl@0
   948
sl@0
   949
	# Output known failures
sl@0
   950
	if ($foundSamePlatFails || $foundSamePlatInconcs || $foundSamePlatCrash)
sl@0
   951
		{
sl@0
   952
		$iKnownFails = $iKnownFails . "\n$scriptName\n";
sl@0
   953
		}
sl@0
   954
	if ($foundSamePlatInconcs)
sl@0
   955
		{
sl@0
   956
		$iKnownFails = $iKnownFails . "INCONCLUSIVES:\n$foundSamePlatInconcs";
sl@0
   957
		}
sl@0
   958
	if ($foundSamePlatFails)
sl@0
   959
		{
sl@0
   960
		$iKnownFails = $iKnownFails . "FAILS:\n$foundSamePlatFails";
sl@0
   961
		}
sl@0
   962
	if ($foundSamePlatCrash)
sl@0
   963
		{
sl@0
   964
		$iKnownFails = $iKnownFails . "CRASHED\n";
sl@0
   965
		}		
sl@0
   966
	
sl@0
   967
	# Output matches found only in other test platforms
sl@0
   968
	if ($foundOtherPlatFails || $foundOtherPlatInconcs || $foundOtherPlatCrash)
sl@0
   969
		{
sl@0
   970
		$iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines .  "\n$scriptName\n";
sl@0
   971
		}
sl@0
   972
	if ($foundOtherPlatInconcs)
sl@0
   973
		{
sl@0
   974
		$iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "INCONCLUSIVES:\n$foundOtherPlatInconcs";
sl@0
   975
		}
sl@0
   976
	if ($foundOtherPlatFails)
sl@0
   977
		{
sl@0
   978
		$iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "FAILS:\n$foundOtherPlatFails";
sl@0
   979
		}
sl@0
   980
	if ($foundOtherPlatCrash)
sl@0
   981
		{
sl@0
   982
		$iUnknownFailsButKnownInOtherCodelines = $iUnknownFailsButKnownInOtherCodelines . "CRASHED\n";
sl@0
   983
		}
sl@0
   984
		
sl@0
   985
	$aKfSheetContents = $wipKfSheet;
sl@0
   986
	}
sl@0
   987
sl@0
   988
sl@0
   989
# Takes the corresponding log file from the reference build and test for a failing script and
sl@0
   990
# compare it to see if the failures match.  If so this information is stored and the matching
sl@0
   991
# failures removed from the TestScriptResults object.
sl@0
   992
# param1 - TestScriptResults object for the script with failures
sl@0
   993
# param2 - boolean whether the test crashed in the reference build and test
sl@0
   994
# param3 - the contents of the corresponding log file from the reference build
sl@0
   995
sub ResolveFailuresAgainstReferenceRun
sl@0
   996
	{
sl@0
   997
	my $aReferenceTestResults = shift;
sl@0
   998
	my $aRefTestCrashed = shift;
sl@0
   999
	my $aReferenceLogContents = shift;
sl@0
  1000
	my $refContents = $$aReferenceLogContents;	
sl@0
  1001
sl@0
  1002
	my $scriptName = $aReferenceTestResults->ScriptName();
sl@0
  1003
	my $testHarness = $aReferenceTestResults->TestHarness();
sl@0
  1004
	
sl@0
  1005
	my $inconText;
sl@0
  1006
	my @inconclusives = $aReferenceTestResults->Inconclusives();
sl@0
  1007
	$aReferenceTestResults->ResetInconclusives();
sl@0
  1008
	foreach my $inconclusive (@inconclusives)
sl@0
  1009
		{
sl@0
  1010
		if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest))
sl@0
  1011
			{
sl@0
  1012
			my $testcasesInUse = 0;
sl@0
  1013
			if ($testHarness eq $TestScriptResults::KTEFTest)
sl@0
  1014
				{
sl@0
  1015
				$testcasesInUse = 1;
sl@0
  1016
				}
sl@0
  1017
			if (MatchingTEFInconclusiveResult($inconclusive, \$refContents, $testcasesInUse))
sl@0
  1018
				{
sl@0
  1019
				$inconText = $inconText . "$inconclusive\n";
sl@0
  1020
				}
sl@0
  1021
			else
sl@0
  1022
				{
sl@0
  1023
				$aReferenceTestResults->AddInconclusiveResult($inconclusive);
sl@0
  1024
				}
sl@0
  1025
			}
sl@0
  1026
		elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest)
sl@0
  1027
			{
sl@0
  1028
			if (MatchingTFInconclusiveResult($inconclusive, \$refContents))
sl@0
  1029
				{
sl@0
  1030
				$inconText = $inconText . "$inconclusive\n";
sl@0
  1031
				}
sl@0
  1032
			else
sl@0
  1033
				{
sl@0
  1034
				$aReferenceTestResults->AddInconclusiveResult($inconclusive);			
sl@0
  1035
				}			
sl@0
  1036
			}
sl@0
  1037
		# Core Conf tests have no comprehension of inconclusive
sl@0
  1038
		}
sl@0
  1039
			
sl@0
  1040
	my $failText;
sl@0
  1041
	my @failures = $aReferenceTestResults->Failures();
sl@0
  1042
	$aReferenceTestResults->ResetFailures();
sl@0
  1043
	foreach my $failure (@failures)
sl@0
  1044
		{
sl@0
  1045
		if (($testHarness eq $TestScriptResults::KTEFTest) || ($testHarness eq $TestScriptResults::KTEFNoTestcasesTest))
sl@0
  1046
			{
sl@0
  1047
			my $testcasesInUse = 0;
sl@0
  1048
			if ($testHarness eq $TestScriptResults::KTEFTest)
sl@0
  1049
				{
sl@0
  1050
				$testcasesInUse = 1;
sl@0
  1051
				}
sl@0
  1052
			if (MatchingTEFErrorResult($failure, \$refContents, $testcasesInUse))
sl@0
  1053
				{
sl@0
  1054
				$failText = $failText . "$failure\n";
sl@0
  1055
				}
sl@0
  1056
			else
sl@0
  1057
				{
sl@0
  1058
				$aReferenceTestResults->AddFailureResult($failure);
sl@0
  1059
				}
sl@0
  1060
			}
sl@0
  1061
		elsif ($testHarness eq $TestScriptResults::KTestFrameworkTest)
sl@0
  1062
			{
sl@0
  1063
			if (MatchingTFErrorResult($failure, \$refContents))
sl@0
  1064
				{
sl@0
  1065
				$failText = $failText . "$failure\n";
sl@0
  1066
				}
sl@0
  1067
			else
sl@0
  1068
				{
sl@0
  1069
				$aReferenceTestResults->AddFailureResult($failure);
sl@0
  1070
				}			
sl@0
  1071
			}
sl@0
  1072
		else
sl@0
  1073
			{
sl@0
  1074
			# Core Conf 
sl@0
  1075
			if (MatchingCoreConfErrorResult($failure, \$refContents))
sl@0
  1076
				{
sl@0
  1077
				$failText = $failText . "$failure\n";
sl@0
  1078
				}
sl@0
  1079
			else
sl@0
  1080
				{
sl@0
  1081
				$aReferenceTestResults->AddFailureResult($failure);
sl@0
  1082
				}			
sl@0
  1083
			}
sl@0
  1084
		}
sl@0
  1085
sl@0
  1086
	my $bothCrashed;
sl@0
  1087
	if (($aReferenceTestResults->DidItCrash()) && $aRefTestCrashed)
sl@0
  1088
		{
sl@0
  1089
		$bothCrashed = 1;
sl@0
  1090
		$aReferenceTestResults->ResetCrashed();
sl@0
  1091
		}
sl@0
  1092
	
sl@0
  1093
	if ($inconText || $failText || $bothCrashed)
sl@0
  1094
		{
sl@0
  1095
		$iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "\n$scriptName\n";
sl@0
  1096
		}
sl@0
  1097
	
sl@0
  1098
	if 	($inconText)
sl@0
  1099
		{
sl@0
  1100
		$iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "INCONCLUSIVES:\n$inconText";
sl@0
  1101
		}
sl@0
  1102
	if ($failText)
sl@0
  1103
		{
sl@0
  1104
		$iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "FAILS:\n$failText";
sl@0
  1105
		}
sl@0
  1106
	if ($bothCrashed)
sl@0
  1107
		{
sl@0
  1108
		$iUnknownFailsButKnownInRef = $iUnknownFailsButKnownInRef . "CRASHED\n";
sl@0
  1109
		}
sl@0
  1110
	}
sl@0
  1111
	
sl@0
  1112
###############################################
sl@0
  1113
##	Utility functions
sl@0
  1114
###############################################	
sl@0
  1115
sl@0
  1116
sub PrintHelp
sl@0
  1117
	{
sl@0
  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";
sl@0
  1119
	print "  -m = Mode of operation, specify the source of the results that you are\n";
sl@0
  1120
	print "    comparing. Currently supported modes: Mistral, Local\n\n";
sl@0
  1121
	print "  -s = Source of the results, mode dependant:\n";
sl@0
  1122
	print "      (i) Mistral = The URL of the test results HTML summary page\n";
sl@0
  1123
	print "      (ii) Local = The pathname of a folder containing the test log files\n\n";
sl@0
  1124
	print "  -k = Pathname of the KF sheet, this should be exported as an XML spreadsheet\n";
sl@0
  1125
	print "    from Excel\n\n";
sl@0
  1126
	print "  -r = Reference Mistral build, the URL of the test results HTML summary page.\n";
sl@0
  1127
	print "    This can be used in addition or in place of the Known Failure sheet\n\n";
sl@0
  1128
	print "  -i = Ignore test failures in scripts not found in the Reference Mistral build\n\n";
sl@0
  1129
	print "  -c = An index indicating the codeline used in the test run, only used in\n";
sl@0
  1130
	print "    conjunction with a KF sheet. Possible values: TB92, TB101, TB102\n\n";	
sl@0
  1131
	print "  -p = An index indicating the platform the test run is from, only used in\n";
sl@0
  1132
	print "    conjunction with a KF sheet. Possible values: Winscw, H6, H4 WDP,\n";
sl@0
  1133
	print "    NaviEngine\n\n";
sl@0
  1134
	print "  -v = Verbose output\n\n";
sl@0
  1135
	}
sl@0
  1136
	
sl@0
  1137
###############################################
sl@0
  1138
##	Main processing loop
sl@0
  1139
###############################################		
sl@0
  1140
sl@0
  1141
# Read in parameters
sl@0
  1142
my %aParams;
sl@0
  1143
getopts('ihvm:s:k:r:c:p:', \%aParams);
sl@0
  1144
if ($aParams{h})
sl@0
  1145
	{
sl@0
  1146
	PrintHelp();
sl@0
  1147
	exit;
sl@0
  1148
	}
sl@0
  1149
sl@0
  1150
$iVerbose = $aParams{v};
sl@0
  1151
	
sl@0
  1152
# The mode affects where we get the source files from and nothing else.
sl@0
  1153
my @runResults;
sl@0
  1154
if ($aParams{m} =~ m/\AMistral\Z/i)
sl@0
  1155
	{
sl@0
  1156
	@runResults = @{PopulateResultsArrayFromMistral($aParams{s})};	
sl@0
  1157
	}
sl@0
  1158
elsif ($aParams{m} =~ m/\ALocal\Z/i)
sl@0
  1159
	{
sl@0
  1160
	@runResults = @{PopulateResultsArrayFromLocalMachine($aParams{s})};	
sl@0
  1161
	}
sl@0
  1162
else
sl@0
  1163
	{
sl@0
  1164
	print "\nERROR: Operation mode absent or not recognised.\n";
sl@0
  1165
	PrintHelp();
sl@0
  1166
	exit;
sl@0
  1167
	}
sl@0
  1168
	
sl@0
  1169
my @kfPlatforms;
sl@0
  1170
if ($aParams{k})
sl@0
  1171
	{
sl@0
  1172
	$kfPlatforms[0] = "All";
sl@0
  1173
	
sl@0
  1174
	# KF sheet in use, codeline and platform arguments are required in order to search for matching failures
sl@0
  1175
	my $codeline = $aParams{c};
sl@0
  1176
	my $platform = $aParams{p};
sl@0
  1177
	unless (($codeline eq "TB92") || ($codeline eq "TB101") || ($codeline eq "TB102"))
sl@0
  1178
		{
sl@0
  1179
		print "\nERROR: The codeline specified was not recognised, supported options: TB92, TB101, TB102.\n";
sl@0
  1180
		exit;		
sl@0
  1181
		}
sl@0
  1182
sl@0
  1183
	if ($platform eq "Winscw")
sl@0
  1184
		{
sl@0
  1185
		$kfPlatforms[1] = "All Winscw";
sl@0
  1186
		}
sl@0
  1187
	elsif (($platform eq "H6") || ($platform eq "H4 WDP") || ($platform eq "NaviEngine"))
sl@0
  1188
		{
sl@0
  1189
		$kfPlatforms[1] = "All HW";
sl@0
  1190
		}
sl@0
  1191
	else
sl@0
  1192
		{
sl@0
  1193
		print "\nERROR: The platform specified was not recognised, supported options: Winscw, H6, H4 WDP, NaviEngine.\n";
sl@0
  1194
		exit;		
sl@0
  1195
		}
sl@0
  1196
	
sl@0
  1197
	$kfPlatforms[2] = "$codeline $platform";
sl@0
  1198
	}
sl@0
  1199
sl@0
  1200
if ($iVerbose)
sl@0
  1201
	{
sl@0
  1202
	print "\nLog files found:\n";
sl@0
  1203
	foreach my $file (@runResults)
sl@0
  1204
		{
sl@0
  1205
		my $scriptName = $file->ScriptName();
sl@0
  1206
		print "$scriptName\n";
sl@0
  1207
		}
sl@0
  1208
	}
sl@0
  1209
	
sl@0
  1210
AnalyseFailures($aParams{k}, $aParams{r}, $aParams{i}, \@runResults, \@kfPlatforms);
sl@0
  1211
sl@0
  1212
print "\n\nKnown failures:\n";
sl@0
  1213
print "------------------\n";
sl@0
  1214
print "$iKnownFails\n\n";
sl@0
  1215
sl@0
  1216
print "Unknown failures but found in the reference build:\n";
sl@0
  1217
print "----------------------------------------------------\n";
sl@0
  1218
print "$iUnknownFailsButKnownInRef\n\n";
sl@0
  1219
sl@0
  1220
print "Unknown failures but known in other codelines:\n";
sl@0
  1221
print "------------------------------------------------\n";
sl@0
  1222
print "$iUnknownFailsButKnownInOtherCodelines\n\n";
sl@0
  1223
sl@0
  1224
print "Unknown failures:\n";
sl@0
  1225
print "-------------------\n";
sl@0
  1226
print "$iUnknownFails\n\n";
sl@0
  1227
sl@0
  1228
print "Tests with reduced test counts:\n";
sl@0
  1229
print "---------------------------------\n";
sl@0
  1230
print "$iMissingTests\n\n";
sl@0
  1231
sl@0
  1232