testresults.py revision 044c12a522da4180f67ab7a51a66446647a1f15d
af062818b47340eef15700d2f0211576ba3506eevboxsync# -*- coding: utf-8 -*-
af062818b47340eef15700d2f0211576ba3506eevboxsync# pylint: disable=C0302
af062818b47340eef15700d2f0211576ba3506eevboxsync## @todo Rename this file to testresult.py!
af062818b47340eef15700d2f0211576ba3506eevboxsyncTest Manager - Fetch test results.
af062818b47340eef15700d2f0211576ba3506eevboxsyncCopyright (C) 2012-2014 Oracle Corporation
af062818b47340eef15700d2f0211576ba3506eevboxsyncThis file is part of VirtualBox Open Source Edition (OSE), as
af062818b47340eef15700d2f0211576ba3506eevboxsyncavailable from http://www.virtualbox.org. This file is free software;
af062818b47340eef15700d2f0211576ba3506eevboxsyncyou can redistribute it and/or modify it under the terms of the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsyncGeneral Public License (GPL) as published by the Free Software
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsyncFoundation, in version 2 as it comes in the "COPYING" file of the
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsyncVirtualBox OSE distribution. VirtualBox OSE is distributed in the
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsynchope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsyncThe contents of this file may alternatively be used under the terms
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsyncof the Common Development and Distribution License Version 1.0
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync(CDDL) only, as it comes in the "COPYING.CDDL" file of the
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsyncVirtualBox OSE distribution, in which case the provisions of the
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsyncCDDL are applicable instead of those of the GPL.
af062818b47340eef15700d2f0211576ba3506eevboxsyncYou may elect to license modified versions of this file under the
af062818b47340eef15700d2f0211576ba3506eevboxsyncterms and conditions of either the GPL or the CDDL or both.
af062818b47340eef15700d2f0211576ba3506eevboxsync# Standard python imports.
af062818b47340eef15700d2f0211576ba3506eevboxsync# Validation Kit imports.
af062818b47340eef15700d2f0211576ba3506eevboxsyncfrom testmanager.core.base import ModelDataBase, ModelLogicBase, ModelDataBaseTestCase, TMExceptionBase, TMTooManyRows;
af062818b47340eef15700d2f0211576ba3506eevboxsyncfrom testmanager.core.testgroup import TestGroupData
af062818b47340eef15700d2f0211576ba3506eevboxsyncfrom testmanager.core.schedgroup import SchedGroupData
af062818b47340eef15700d2f0211576ba3506eevboxsyncfrom testmanager.core.systemlog import SystemLogData, SystemLogLogic;
af062818b47340eef15700d2f0211576ba3506eevboxsync Test case execution result data
af062818b47340eef15700d2f0211576ba3506eevboxsync ## @name TestStatus_T
af062818b47340eef15700d2f0211576ba3506eevboxsync ## List of relatively harmless (to testgroup/case) statuses.
af062818b47340eef15700d2f0211576ba3506eevboxsync kasHarmlessTestStatuses = [ ksTestStatus_Skipped, ksTestStatus_BadTestBox, ksTestStatus_Aborted, ];
af062818b47340eef15700d2f0211576ba3506eevboxsync ## List of bad statuses.
af062818b47340eef15700d2f0211576ba3506eevboxsync kasBadTestStatuses = [ ksTestStatus_Failure, ksTestStatus_TimedOut, ksTestStatus_Rebooted, ];
af062818b47340eef15700d2f0211576ba3506eevboxsync ksParam_idTestResult = 'TestResultData_idTestResult';
af062818b47340eef15700d2f0211576ba3506eevboxsync ksParam_idTestResultParent = 'TestResultData_idTestResultParent';
af062818b47340eef15700d2f0211576ba3506eevboxsync ksParam_iNestingDepth = 'TestResultData_iNestingDepth';
af062818b47340eef15700d2f0211576ba3506eevboxsync Reinitialize from a SELECT * FROM TestResults.
af062818b47340eef15700d2f0211576ba3506eevboxsync Return self. Raises exception if no row.
af062818b47340eef15700d2f0211576ba3506eevboxsync raise TMExceptionBase('Test result record not found.')
af062818b47340eef15700d2f0211576ba3506eevboxsync """ Check if it's a real failure. """
af062818b47340eef15700d2f0211576ba3506eevboxsync Extended test result data class.
af062818b47340eef15700d2f0211576ba3506eevboxsync This is intended for use as a node in a result tree. This is not intended
af062818b47340eef15700d2f0211576ba3506eevboxsync for serialization to parameters or vice versa. Use TestResultLogic to
af062818b47340eef15700d2f0211576ba3506eevboxsync construct the tree.
af062818b47340eef15700d2f0211576ba3506eevboxsync self.oParent = None; # idTestResultParent within the tree.
af062818b47340eef15700d2f0211576ba3506eevboxsync Initialize from a query like this:
af062818b47340eef15700d2f0211576ba3506eevboxsync SELECT TestResults.*, TestResultStrTab.sValue
af062818b47340eef15700d2f0211576ba3506eevboxsync FROM TestResults, TestResultStrTab
af062818b47340eef15700d2f0211576ba3506eevboxsync WHERE TestResultStrTab.idStr = TestResults.idStrName
af062818b47340eef15700d2f0211576ba3506eevboxsync Note! The caller is expected to fetch children, values, failure
af062818b47340eef15700d2f0211576ba3506eevboxsync details, and files.
af062818b47340eef15700d2f0211576ba3506eevboxsync Test result value data.
af062818b47340eef15700d2f0211576ba3506eevboxsync ksParam_idTestResultValue = 'TestResultValue_idTestResultValue';
af062818b47340eef15700d2f0211576ba3506eevboxsync ksParam_idTestResult = 'TestResultValue_idTestResult';
if aoRow is None:
return self;
return self;
if aoRow is None:
return self;
return self;
if aoRow is None:
return self;
return self;
return self;
return True;
return False;
if aoRow is None:
return self
cMonthsMourningPeriod = 2; # Stop reminding everyone about testboxes after 2 months. (May also speed up the query.)
if tsNow is None:
% ( sTsNow,
return sRet
def _getSqlQueryForGroupSearch(self, sWhat, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures):
if enmResultsGroupingType is None:
if iResultsGroupingValue is not None:
if fOnlyFailures:
return sQuery
def fetchResultsForListing(self, iStart, cMaxRows, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue,
sSqlQuery = self._getSqlQueryForGroupSearch(sWhat, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue,
aoRows = [];
return aoRows
def getEntriesCount(self, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures):
aoRet = []
return aoRet
aoRet = []
return aoRet
asIdGenTestBoxes = [];
aoRet = []
return aoRet
self._oDb.execute('SELECT DISTINCT TestCases.idTestCase, TestCases.idGenTestCase, TestSets.tsConfig\n'
aoRet = []
return aoRet
aoRet = []
return aoRet
(idTestResult,))
raise TMExceptionBase('Found more than one test result with the same credentials. Database structure is corrupted.')
except IndexError:
, ( idTestSet, ));
if cMaxDepth is not None:
if oParent is None:
if fHasValues:
if fHasMsgs:
if fHasFiles:
return True;
self._oDb.dprint('** _inhumeTestResults: idTestSet=%d\n%s' % (idTestSet, self._stringifyStack(aoStack),));
self._completeTestResults(oTestResult, None, TestResultData.ksTestStatus_Failure, oTestResult.cErrors);
, ( idTestSet, ));
, (sString,));
, (sString,));
if fCommit:
return sRet;
, ( idTestSet, ));
aoStack = [];
return aoStack;
def _newTestResult(self, idTestResultParent, idTestSet, iNestingDepth, tsCreated, sName, dCounts, fCommit = False):
assert idTestResultParent is not None;
, ( idTestSet,));
, ( idTestResultParent,));
return oData;
def _newTestValue(self, idTestResult, idTestSet, sName, lValue, sUnit, dCounts, tsCreated = None, fCommit = False):
, ( idTestSet,));
, ( idTestResult,));
if tsCreated is None:
return True;
if dCounts is not None:
, ( idTestResult,));
raise TestResultHangingOffence('Failure details message is too long: %d chars - "%s"' % (len(sText), sText));
if tsCreated is None:
return True;
if tsDone is None:
return True;
(dAttribs['timestamp'], sError) = ModelDataBase.validateTs(dAttribs['timestamp'], fAllowNull = False);
if sError is not None:
dElementAttribs = \
if fClosed:
sError = None;
dAttribs = {};
if sError is None:
aoStack.insert(0, self._newTestResult(idTestResultParent = aoStack[0].idTestResult, idTestSet = idTestSet,
self._newTestValue(idTestResult = aoStack[0].idTestResult, idTestSet = idTestSet, tsCreated = dAttribs['timestamp'],
self._completeTestResults(aoStack[0], tsDone = dAttribs['timestamp'], cErrors = int(dAttribs['errors']),
self._completeTestResults(aoStack[0], tsDone = dAttribs['timestamp'], cErrors = int(dAttribs['errors']),
dCounts = {};
aaiHints = [];
sError = None;
elif fExpectCloseTest:
if sError is not None:
if sError is not None:
% ( idTestSet,
sError, ),