testresults.py revision 044c12a522da4180f67ab7a51a66446647a1f15d
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# -*- coding: utf-8 -*-
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# pylint: disable=C0302
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync## @todo Rename this file to testresult.py!
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncTest Manager - Fetch test results.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCopyright (C) 2012-2014 Oracle Corporation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThis file is part of VirtualBox Open Source Edition (OSE), as
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncavailable from http://www.virtualbox.org. This file is free software;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncyou can redistribute it and/or modify it under the terms of the GNU
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncGeneral Public License (GPL) as published by the Free Software
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncFoundation, in version 2 as it comes in the "COPYING" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsynchope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThe contents of this file may alternatively be used under the terms
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncof the Common Development and Distribution License Version 1.0
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync(CDDL) only, as it comes in the "COPYING.CDDL" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution, in which case the provisions of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCDDL are applicable instead of those of the GPL.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncYou may elect to license modified versions of this file under the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncterms and conditions of either the GPL or the CDDL or both.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Standard python imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Validation Kit imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.base import ModelDataBase, ModelLogicBase, ModelDataBaseTestCase, TMExceptionBase, TMTooManyRows;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.testgroup import TestGroupData
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.schedgroup import SchedGroupData
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.systemlog import SystemLogData, SystemLogLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Test case execution result data
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @name TestStatus_T
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## List of relatively harmless (to testgroup/case) statuses.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync kasHarmlessTestStatuses = [ ksTestStatus_Skipped, ksTestStatus_BadTestBox, ksTestStatus_Aborted, ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## List of bad statuses.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync kasBadTestStatuses = [ ksTestStatus_Failure, ksTestStatus_TimedOut, ksTestStatus_Rebooted, ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResult = 'TestResultData_idTestResult';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResultParent = 'TestResultData_idTestResultParent';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_iNestingDepth = 'TestResultData_iNestingDepth';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a SELECT * FROM TestResults.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Test result record not found.')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Check if it's a real failure. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Extended test result data class.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync This is intended for use as a node in a result tree. This is not intended
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for serialization to parameters or vice versa. Use TestResultLogic to
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync construct the tree.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.oParent = None; # idTestResultParent within the tree.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Initialize from a query like this:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SELECT TestResults.*, TestResultStrTab.sValue
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync FROM TestResults, TestResultStrTab
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WHERE TestResultStrTab.idStr = TestResults.idStrName
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Note! The caller is expected to fetch children, values, failure
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync details, and files.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Test result value data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResultValue = 'TestResultValue_idTestResultValue';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResult = 'TestResultValue_idTestResult';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a SELECT * FROM TestResultValues.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Test result value record not found.')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Extends TestResultValue by resolving the value name and unit string.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a query like this:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SELECT TestResultValues.*, TestResultStrTab.sValue
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync FROM TestResultValues, TestResultStrTab
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WHERE TestResultStrTab.idStr = TestResultValues.idStrName
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self.iUnit < len(constants.valueunit.g_asNames):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.sUnit = constants.valueunit.g_asNames[self.iUnit];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Test result message data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResultMsg = 'TestResultValue_idTestResultMsg';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResult = 'TestResultValue_idTestResult';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a SELECT * FROM TestResultMsgs.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Test result value record not found.')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Extends TestResultMsg by resolving the message string.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a query like this:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SELECT TestResultMsg.*, TestResultStrTab.sValue
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync FROM TestResultMsg, TestResultStrTab
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync WHERE TestResultStrTab.idStr = TestResultMsgs.idStrName
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Test result message data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResultFile = 'TestResultFile_idTestResultFile';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestResult = 'TestResultFile_idTestResult';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idStrDescription = 'TestResultFile_idStrDescription';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a SELECT * FROM TestResultFiles.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Test result file record not found.')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Extends TestResultFile by resolving the strings.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a query like this:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SELECT TestResultFiles.*,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync StrTabFile.sValue AS sFile,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync StrTabDesc.sValue AS sDescription
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync StrTabKind.sValue AS sKind,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync StrTabMime.sValue AS sMime,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitializes to represent the main.log object (not in DB).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns self.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Checks if the file is likely to be UTF-8 encoded.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Gets the MIME type with encoding if likely to be UTF-8.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass TestResultListingData(ModelDataBase): # pylint: disable=R0902
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Test case result data representation for table listing
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Initialize"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize from a database query.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self. Raises exception if no row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Test result record not found.')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Hanging offence committed by test case."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass TestResultLogic(ModelLogicBase): # pylint: disable=R0903
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Results grouped by scheduling group.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Result grinding for displaying in the WUI.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksResultsGroupingTypeNone = 'ResultsGroupingTypeNone'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksResultsGroupingTypeTestGroup = 'ResultsGroupingTypeTestGroup'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksResultsGroupingTypeBuildRev = 'ResultsGroupingTypeBuild'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksResultsGroupingTypeTestBox = 'ResultsGroupingTypeTestBox'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksResultsGroupingTypeTestCase = 'ResultsGroupingTypeTestCase'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksResultsGroupingTypeSchedGroup = 'ResultsGroupingTypeSchedGroup'
044c12a522da4180f67ab7a51a66446647a1f15dvboxsync ksBaseTables = 'BuildCategories, Builds, TestBoxes, TestResults, TestCases, TestCaseArgs,\n' \
044c12a522da4180f67ab7a51a66446647a1f15dvboxsync + ' TestSets LEFT OUTER JOIN Builds AS TestSuiteBits\n' \
044c12a522da4180f67ab7a51a66446647a1f15dvboxsync ' ON TestSets.idBuildTestSuite = TestSuiteBits.idBuild\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksBasePreCondition = 'TestSets.idTestSet = TestResults.idTestSet\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND TestResults.idTestResultParent is NULL\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND TestSets.idBuild = Builds.idBuild\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND Builds.tsExpire > TestSets.tsCreated\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND Builds.tsEffective <= TestSets.tsCreated\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND Builds.idBuildCategory = BuildCategories.idBuildCategory\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND TestSets.idGenTestBox = TestBoxes.idGenTestBox\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND TestSets.idGenTestCase = TestCases.idGenTestCase\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ' AND TestSets.idGenTestCaseArgs = TestCaseArgs.idGenTestCaseArgs\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksBasePreCondition + ' AND TestSets.idTestGroup',),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksBasePreCondition + ' AND TestBoxes.idSchedGroup',),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _getTimePeriodQueryPart(self, tsNow, sInterval):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get part of SQL query responsible for SELECT data within
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync specified period of time.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cMonthsMourningPeriod = 2; # Stop reminding everyone about testboxes after 2 months. (May also speed up the query.)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sRet = '(TestSets.tsDone IS NULL OR TestSets.tsDone >= (CURRENT_TIMESTAMP - \'%s\'::interval))\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestSets.tsCreated >= (CURRENT_TIMESTAMP - \'%s\'::interval - \'%u months\'::interval)\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTsNow = '\'%s\'::TIMESTAMP' % (tsNow,); # It's actually a string already. duh.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestSets.tsCreated >= (%s - \'%s\'::interval - \'%u months\'::interval)\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND (TestSets.tsDone IS NULL OR TestSets.tsDone >= (%s - \'%s\'::interval))\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _getSqlQueryForGroupSearch(self, sWhat, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns an SQL query that limits SELECT result
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync in order to satisfy @param enmResultsGroupingType.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if enmResultsGroupingType not in self.kdResultGroupingMap:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Get SQL query parameters
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTables, sCondition = self.kdResultGroupingMap[enmResultsGroupingType]
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Extend SQL query with time period limitation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTimePeriodQuery = self._getTimePeriodQueryPart(tsNow, sInterval)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sCondition += ' = %d' % iResultsGroupingValue + '\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Extend the condition with test status limitations if requested.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sCondition += '\n AND TestSets.enmStatus != \'success\'::TestStatus_T' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync '\n AND TestSets.enmStatus != \'running\'::TestStatus_T';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Assemble the query.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchResultsForListing(self, iStart, cMaxRows, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Fetches TestResults table content.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync If @param enmResultsGroupingType and @param iResultsGroupingValue
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync are not None, then resulting (returned) list contains only records
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync that match specified @param enmResultsGroupingType.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync If @param enmResultsGroupingType is None, then
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync @param iResultsGroupingValue is ignored.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns an array (list) of TestResultData items, empty list if none.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Raises exception on error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' BuildCategories.idBuildCategory,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' BuildCategories.sProduct,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' BuildCategories.sRepository,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' BuildCategories.sBranch,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' BuildCategories.sType,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' Builds.idBuild,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' Builds.sVersion,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' Builds.iRevision,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.sOs,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.sOsVersion,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.sCpuArch,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.sCpuVendor,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.sCpuName,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.cCpus,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.fCpuHwVirt,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.fCpuNestedPaging,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.fCpu64BitGuest,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.idTestBox,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestBoxes.sName,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResults.tsCreated,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' COALESCE(TestResults.tsElapsed, CURRENT_TIMESTAMP - TestResults.tsCreated),\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestSets.enmStatus,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResults.cErrors,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestCases.idTestCase,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestCases.sName,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestCases.sBaseCmd,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestCaseArgs.sArgs,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestSuiteBits.idBuild AS idBuildTestSuite,\n' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestSuiteBits.iRevision AS iRevisionTestSuite,\n' \
044c12a522da4180f67ab7a51a66446647a1f15dvboxsync ' (TestSets.tsDone IS NULL) SortRunningFirst' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sSqlQuery = self._getSqlQueryForGroupSearch(sWhat, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sSqlQuery += 'ORDER BY SortRunningFirst DESC, TestSets.idTestSet DESC\n';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sSqlQuery += 'LIMIT %s OFFSET %s\n' % (cMaxRows, iStart,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoRows.append(TestResultListingData().initFromDbRow(aoRow))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def getEntriesCount(self, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get number of table records.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync If @param enmResultsGroupingType and @param iResultsGroupingValue
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync are not None, then we count only only those records
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync that match specified @param enmResultsGroupingType.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync If @param enmResultsGroupingType is None, then
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync @param iResultsGroupingValue is ignored.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sSqlQuery = self._getSqlQueryForGroupSearch('COUNT(TestSets.idTestSet)', tsNow, sInterval,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get list of uniq TestGroupData objects which
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync found in all test results.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestGroups, TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestSets.idTestGroup = TestGroups.idTestGroup\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestGroups.tsExpire > TestSets.tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestGroups.tsEffective <= TestSets.tsCreated'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND ' + self._getTimePeriodQueryPart(tsNow, sPeriod))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo Need to take time into consideration. Will go belly up if we delete a testgroup.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get list of uniq BuildDataEx objects which
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync found in all test results.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT DISTINCT Builds.*, BuildCategories.*\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM Builds, BuildCategories, TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestSets.idBuild = Builds.idBuild\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND Builds.idBuildCategory = BuildCategories.idBuildCategory\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND Builds.tsExpire > TestSets.tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND Builds.tsEffective <= TestSets.tsCreated'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND ' + self._getTimePeriodQueryPart(tsNow, sPeriod))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get list of uniq TestBoxData objects which
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync found in all test results.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo do all in one query.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT DISTINCT TestBoxes.idTestBox, TestBoxes.idGenTestBox\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestBoxes, TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestSets.idGenTestBox = TestBoxes.idGenTestBox\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND ' + self._getTimePeriodQueryPart(tsNow, sPeriod) +
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY TestBoxes.idTestBox, TestBoxes.idGenTestBox DESC' );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestBoxes\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idGenTestBox IN (' + ','.join(asIdGenTestBoxes) + ')\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY sName');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get a list of unique TestCaseData objects which is appears in the test
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync specified result period.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT DISTINCT TestCases.idTestCase, TestCases.idGenTestCase, TestSets.tsConfig\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestCases, TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestSets.idTestCase = TestCases.idTestCase\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestCases.tsExpire > TestSets.tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestCases.tsEffective <= TestSets.tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND ' + self._getTimePeriodQueryPart(tsNow, sPeriod) +
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY TestCases.idTestCase, TestCases.idGenTestCase DESC\n');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo reduce subqueries
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoRet.append(TestCaseData().initFromDbWithGenId(self._oDb, aoRow[1], aoRow[2]))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get list of uniq SchedGroupData objects which
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync found in all test results.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT DISTINCT TestBoxes.idSchedGroup\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestBoxes, TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestSets.idGenTestBox = TestBoxes.idGenTestBox\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestBoxes.tsExpire > TestSets.tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestBoxes.tsEffective <= TestSets.tsCreated'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND ' + self._getTimePeriodQueryPart(tsNow, sPeriod))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo reduce subqueries
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoRet.append(SchedGroupData().initFromDbWithId(self._oDb, iRow))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Get build record by its id
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResults\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResult = %s\n',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Found more than one test result with the same credentials. Database structure is corrupted.')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Details view and interface.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchResultTree(self, idTestSet, cMaxDepth = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Fetches the result tree for the given test set.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns a tree of TestResultDataEx nodes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Raises exception on invalid input and database issues.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Depth first, i.e. just like the XML added them.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo this still isn't performing extremely well, consider optimizations.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SELECT TestResults.*,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResultStrTab.sValue,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' EXISTS ( SELECT idTestResultValue\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' FROM TestResultValues\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' WHERE TestResultValues.idTestResult = TestResults.idTestResult ) AS fHasValues,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' EXISTS ( SELECT idTestResultMsg\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' FROM TestResultMsgs\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' WHERE TestResultMsgs.idTestResult = TestResults.idTestResult ) AS fHasMsgs,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' EXISTS ( SELECT idTestResultFile\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' FROM TestResultFiles\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' WHERE TestResultFiles.idTestResult = TestResults.idTestResult ) AS fHasFiles\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResults, TestResultStrTab\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestResults.idTestSet = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResults.idStrName = TestResultStrTab.idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if cMaxDepth is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sQuery += self._oDb.formatBindArgs(' AND TestResults.iNestingDepth <= %s\n', (cMaxDepth,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMTooManyRows('Too many rows returned for idTestSet=%d: %d' % (idTestSet, cRows,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('No test results for idTestSet=%d.' % (idTestSet,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Set up the root node first.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise self._oDb.integrityException('The root TestResult (#%s) has a parent (#%s)!'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fetchResultTreeNodeExtras(oRoot, aoRow[-3], aoRow[-2], aoRow[-1]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The chilren (if any).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fetchResultTreeNodeExtras(oCur, aoRow[-3], aoRow[-2], aoRow[-1]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Figure out and vet the parent.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oParent.idTestResult != oCur.idTestResultParent:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oParent = dLookup.get(oCur.idTestResultParent, None);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise self._oDb.integrityException('TestResult #%d is orphaned from its parent #%s.'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oParent.iNestingDepth + 1 != oCur.iNestingDepth:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise self._oDb.integrityException('TestResult #%d has incorrect nesting depth (%d instead of %d)'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (oCur.idTestResult, oCur.iNestingDepth, oParent.iNestingDepth + 1,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Link it up.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _fetchResultTreeNodeExtras(self, oCurNode, fHasValues, fHasMsgs, fHasFiles):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync fetchResultTree worker that fetches values, message and files for the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync specified node.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResultStrTab.sValue\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResultValues, TestResultStrTab\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestResultValues.idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResultValues.idStrName = TestResultStrTab.idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idTestResultValue ASC\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oCurNode.aoValues.append(TestResultValueDataEx().initFromDbRow(aoRow));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResultStrTab.sValue\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResultMsgs, TestResultStrTab\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestResultMsgs.idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResultMsgs.idStrMsg = TestResultStrTab.idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idTestResultMsg ASC\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oCurNode.aoMsgs.append(TestResultMsgDataEx().initFromDbRow(aoRow));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' StrTabFile.sValue AS sFile,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' StrTabDesc.sValue AS sDescription,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' StrTabKind.sValue AS sKind,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' StrTabMime.sValue AS sMime\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResultFiles,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResultStrTab AS StrTabFile,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResultStrTab AS StrTabDesc,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResultStrTab AS StrTabKind,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestResultStrTab AS StrTabMime\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestResultFiles.idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResultFiles.idStrFile = StrTabFile.idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResultFiles.idStrDescription = StrTabDesc.idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResultFiles.idStrKind = StrTabKind.idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResultFiles.idStrMime = StrTabMime.idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idTestResultFile ASC\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oCurNode.aoFiles.append(TestResultFileDataEx().initFromDbRow(aoRow));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # TestBoxController interface(s).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _inhumeTestResults(self, aoStack, idTestSet, sError):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync The test produces too much output, kill and bury it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Note! We leave the test set open, only the test result records are
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync completed. Thus, _getResultStack will return an empty stack and
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cause XML processing to fail immediately, while we can still
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync record when it actually completed in the test set the normal way.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.dprint('** _inhumeTestResults: idTestSet=%d\n%s' % (idTestSet, self._stringifyStack(aoStack),));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # First add a message.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._newFailureDetails(aoStack[0].idTestResult, sError, None);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The complete all open test results.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._completeTestResults(oTestResult, None, TestResultData.ksTestStatus_Failure, oTestResult.cErrors);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # A bit of paranoia.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SET cErrors = cErrors + 1,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' enmStatus = \'failure\'::TestStatus_T,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsElapsed = CURRENT_TIMESTAMP - tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestSet = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND enmStatus = \'running\'::TestStatus_T\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Gets the string table id for the given string, adding it if new.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Note! A copy of this code is also in TestSetLogic.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo move this and make a stored procedure for it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResultStrTab\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE sValue = %s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('INSERT INTO TestResultStrTab (sValue)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES (%s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'RETURNING idStr\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Returns a string rep of the stack."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Gets the current stack of result sets.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResults\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestSet = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND enmStatus = \'running\'::TestStatus_T\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idTestResult DESC'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoStack.append(TestResultData().initFromDbRow(aoRow));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert aoStack[i].iNestingDepth == len(aoStack) - i - 1, self._stringifyStack(aoStack);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _newTestResult(self, idTestResultParent, idTestSet, iNestingDepth, tsCreated, sName, dCounts, fCommit = False):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Creates a new test result.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns the TestResultData object for the new record.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync May raise exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert idTestResultParent is not None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # This isn't necessarily very efficient, but it's necessary to prevent
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # a wild test or testbox from filling up the database.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResults\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestSet = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dCounts[sCountName] > config.g_kcMaxTestResultsPerTS:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Too many sub-tests in total!');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sCountName = 'cTestResultsIn%d' % (idTestResultParent,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResults\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResultParent = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dCounts[sCountName] > config.g_kcMaxTestResultsPerTR:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Too many immediate sub-tests!');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # This is also a hanging offence.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('To deep sub-test nesting!');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Test name is too long: %d chars - "%s"' % (len(sName), sName));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Within bounds, do the job.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestResultParent,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSet,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsCreated,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idStrName,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iNestingDepth )\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES (%s, %s, TIMESTAMP WITH TIME ZONE %s, %s, %s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'RETURNING *\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( idTestResultParent, idTestSet, tsCreated, idStrName, iNestingDepth) )
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oData = TestResultData().initFromDbRow(self._oDb.fetchOne());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _newTestValue(self, idTestResult, idTestSet, sName, lValue, sUnit, dCounts, tsCreated = None, fCommit = False):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Creates a test value.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync May raise exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Bounds checking.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT COUNT(idTestResultValue)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResultValues, TestResults\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestResultValues.idTestResult = TestResults.idTestResult\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestResults.idTestSet = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dCounts[sCountName] > config.g_kcMaxTestValuesPerTS:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Too many values in total!');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT COUNT(idTestResultValue)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResultValues\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dCounts[sCountName] > config.g_kcMaxTestValuesPerTR:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Too many immediate values for one test result!');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Value name is too long: %d chars - "%s"' % (len(sName), sName));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Do the job.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iUnit = constants.valueunit.g_kdNameToConst.get(sUnit, constants.valueunit.NONE);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('INSERT INTO TestResultValues (\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestResult,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSet,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idStrName,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' lValue,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iUnit)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES ( %s, %s, %s, %s, %s )\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( idTestResult, idTestSet, idStrName, lValue, iUnit,) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('INSERT INTO TestResultValues (\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestResult,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSet,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsCreated,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idStrName,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' lValue,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iUnit)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES ( %s, %s, TIMESTAMP WITH TIME ZONE %s, %s, %s, %s )\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( idTestResult, idTestSet, tsCreated, idStrName, lValue, iUnit,) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _newFailureDetails(self, idTestResult, sText, dCounts, tsCreated = None, fCommit = False):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Creates a record detailing cause of failure.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync May raise exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Overflow protection.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dCounts is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT COUNT(idTestResultMsg)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResultMsgs\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dCounts[sCountName] > config.g_kcMaxTestMsgsPerTR:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Too many messages under for one test result!');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TestResultHangingOffence('Failure details message is too long: %d chars - "%s"' % (len(sText), sText));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Do the job.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestResult,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idStrMsg,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' enmLevel)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES ( %s, %s, %s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestResult,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsCreated,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idStrMsg,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' enmLevel)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES ( %s, TIMESTAMP WITH TIME ZONE %s, %s, %s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( idTestResult, tsCreated, idStrMsg, 'failure',) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _completeTestResults(self, oTestResult, tsDone, enmStatus, cErrors = 0, fCommit = False):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Completes a test result. Updates the oTestResult object.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync May raise exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.dprint('** _completeTestResults: cErrors=%s tsDone=%s enmStatus=%s oTestResults=\n%s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Sanity check: No open sub tests (aoStack should make sure about this!).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResults\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResultParent = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND enmStatus = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( oTestResult.idTestResult, TestResultData.ksTestStatus_Running,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert cOpenSubTest == 0, 'cOpenSubTest=%d - %s' % (cOpenSubTest, oTestResult,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert oTestResult.enmStatus == TestResultData.ksTestStatus_Running;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Make sure the reporter isn't lying about successes or error counts.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT COALESCE(SUM(cErrors), 0)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestResults\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResultParent = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cMinErrors = self._oDb.fetchOne()[0] + oTestResult.cErrors;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if cErrors > 0 and enmStatus == TestResultData.ksTestStatus_Success:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Do the update.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SET cErrors = %s,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' enmStatus = %s,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsElapsed = CURRENT_TIMESTAMP - tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'RETURNING tsElapsed'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( cErrors, enmStatus, oTestResult.idTestResult,) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SET cErrors = %s,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' enmStatus = %s,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsElapsed = TIMESTAMP WITH TIME ZONE %s - tsCreated\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'RETURNING tsElapsed'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( cErrors, enmStatus, tsDone, oTestResult.idTestResult,) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _doPopHint(self, aoStack, cStackEntries, dCounts):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Executes a PopHint. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if aoStack[0].enmStatus == TestResultData.ksTestStatus_Running:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._newFailureDetails(aoStack[0].idTestResult, 'XML error: Missing </Test>', dCounts);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._completeTestResults(aoStack[0], tsDone = None, cErrors = 1,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync enmStatus = TestResultData.ksTestStatus_Failure, fCommit = True);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Validates an element and its attributes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate attributes by name.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate integer attributes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'Element %s has an invalid %s attribute value: %s.' % (sName, sAttr, dAttribs[sAttr],);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate long attributes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'Element %s has an invalid %s attribute value: %s.' % (sName, sAttr, dAttribs[sAttr],);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate string attributes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sAttr in dAttribs and len(dAttribs[sAttr]) == 0:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'Element %s has an empty %s attribute value.' % (sName, sAttr,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate the timestamp attribute.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (dAttribs['timestamp'], sError) = ModelDataBase.validateTs(dAttribs['timestamp'], fAllowNull = False);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sError is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'Element %s has an invalid timestamp ("%s"): %s' % (sName, dAttribs['timestamp'], sError,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check that attributes that are required are present.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We ignore extra attributes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'Value': [ 'timestamp', 'name', 'unit', 'value', ],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'Element %s requires attribute "%s".' % (sName, sAttr);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Only the Test element can (and must) remain open.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return '<Test/> is not allowed.';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'All elements except <Test> must be closed.';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Parses an element.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Element level bits.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Attributes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Extract attribute name.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = 'Attributes shall have alpha numberical names and have values.';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Extract attribute value.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if off + 2 >= len(sElement) or sElement[off + 1] != '"':
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = 'Attribute (%s) value is missing or not in double quotes.' % (sAttr,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = 'Attribute (%s) value is missing end quotation mark.' % (sAttr,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check for duplicates.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = 'Attribute "%s" appears more than once.' % (sAttr,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Unescape the value.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate the element before we return.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = TestResultLogic._validateElement(sName, dAttribs, fClosed);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _handleElement(self, sName, dAttribs, idTestSet, aoStack, aaiHints, dCounts):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Worker for processXmlStream that handles one element.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns None on success, error string on bad XML or similar.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Raises exception on hanging offence and on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iNestingDepth = aoStack[0].iNestingDepth + 1 if len(aoStack) > 0 else 0;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoStack.insert(0, self._newTestResult(idTestResultParent = aoStack[0].idTestResult, idTestSet = idTestSet,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync tsCreated = dAttribs['timestamp'], sName = dAttribs['name'],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iNestingDepth = iNestingDepth, dCounts = dCounts, fCommit = True) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._newTestValue(idTestResult = aoStack[0].idTestResult, idTestSet = idTestSet, tsCreated = dAttribs['timestamp'],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sName = dAttribs['name'], sUnit = dAttribs['unit'], lValue = long(dAttribs['value']),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._newFailureDetails(idTestResult = aoStack[0].idTestResult, tsCreated = dAttribs['timestamp'],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sText = dAttribs['text'], dCounts = dCounts, fCommit = True);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._completeTestResults(aoStack[0], tsDone = dAttribs['timestamp'],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync enmStatus = TestResultData.ksTestStatus_Success, fCommit = True);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._completeTestResults(aoStack[0], tsDone = dAttribs['timestamp'],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync enmStatus = TestResultData.ksTestStatus_Skipped, fCommit = True);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._completeTestResults(aoStack[0], tsDone = dAttribs['timestamp'], cErrors = int(dAttribs['errors']),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync enmStatus = TestResultData.ksTestStatus_Failure, fCommit = True);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._completeTestResults(aoStack[0], tsDone = dAttribs['timestamp'], cErrors = int(dAttribs['errors']),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync enmStatus = TestResultData.ksTestStatus_TimedOut, fCommit = True);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._completeTestResults(aoStack[0], tsDone = dAttribs['timestamp'],
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync enmStatus = TestResultData.ksTestStatus_Success, fCommit = True);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'PushHint cannot be nested.'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aaiHints.insert(0, [len(aoStack), int(dAttribs['testdepth'])]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'No hint to pop.'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._doPopHint(aoStack, cStackEntries, dCounts); # Fake the necessary '<End/></Test>' tags.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return 'PopHint tag has different testdepth: %d, on stack %d.' % (iDesiredTestDepth, iTestDepth);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Processes the "XML" stream section given in sXml.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync The sXml isn't a complete XML document, even should we save up all sXml
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for a given set, they may not form a complete and well formed XML
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync document since the test may be aborted, abend or simply be buggy. We
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync therefore do our own parsing and treat the XML tags as commands more
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync than anything else.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns (sError, fUnforgivable), where sError is None on success.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync May raise database exception.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoStack = self._getResultStack(idTestSet); # [0] == top; [-1] == bottom.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.dprint('** processXmlStream len(aoStack)=%s' % (len(aoStack),));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #self._oDb.dprint('processXmlStream: %s' % (self._stringifyStack(aoStack),));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync #self._oDb.dprint('processXmlStream: sXml=%s' % (sXml,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # ASSUMES that we've just seen an <End/>, <Passed/>, <Failed/>,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # <TimedOut/> or <Skipped/> tag earlier in this call!
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if aoStack[0].enmStatus == TestResultData.ksTestStatus_Running or not fExpectCloseTest:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = 'Missing <End/>, <Passed/>, <Failed/>, <TimedOut/> or <Skipped/> tag.';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync elif sXml.startswith('<?xml '): # Ignore (included files).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Parse and check the tag.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (sName, dAttribs, sError) = self._parseElement(sXml[1:offNext]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sError is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Handle it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = self._handleElement(sName, dAttribs, idTestSet, aoStack, aaiHints, dCounts);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._inhumeTestResults(aoStack, idTestSet, str(oXcpt));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync fExpectCloseTest = sName in [ 'End', 'Passed', 'Failed', 'TimedOut', 'Skipped', ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Post processing checks.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = 'Expected </Test> before the end of the XML section.'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sError = 'Expected </PopHint> before the end of the XML section.'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._doPopHint(aoStack, aaiHints[-1][0], dCounts);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Log the error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sError is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SystemLogLogic(self._oDb).addEntry(SystemLogData.ksEvent_XmlResultMalformed,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'idTestSet=%s idTestResult=%s XML="%s" %s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoStack[0].idTestResult if len(aoStack) > 0 else -1,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Unit testing.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# pylint: disable=C0111
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass TestResultDataTestCase(ModelDataBaseTestCase):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass TestResultValueDataTestCase(ModelDataBaseTestCase):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # not reached.