- Timestamp:
- May 30, 2016 12:22:41 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 107578
- Location:
- trunk/src/VBox/ValidationKit/testmanager
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/testmanager/core/failurecategory.py
r61270 r61286 109 109 def __init__(self, oDb): 110 110 ModelLogicBase.__init__(self, oDb) 111 self. ahCache = None;111 self.dCache = None; 112 112 113 113 def fetchForListing(self, iStart, cMaxRows, tsNow): … … 309 309 Raises exception on DB error. 310 310 """ 311 if self. ahCache is None:312 self. ahCache = self._oDb.getCache('FailureCategory');313 314 oEntry = self. ahCache.get(idFailureCategory, None);311 if self.dCache is None: 312 self.dCache = self._oDb.getCache('FailureCategory'); 313 314 oEntry = self.dCache.get(idFailureCategory, None); 315 315 if oEntry is None: 316 316 self._oDb.execute('SELECT *\n' … … 332 332 if self._oDb.getRowCount() == 1: 333 333 oEntry = FailureCategoryData().initFromDbRow(self._oDb.fetchOne()); 334 self. ahCache[idFailureCategory] = oEntry;334 self.dCache[idFailureCategory] = oEntry; 335 335 return oEntry; 336 336 -
trunk/src/VBox/ValidationKit/testmanager/core/failurereason.py
r61284 r61286 144 144 def __init__(self, oDb): 145 145 ModelLogicBase.__init__(self, oDb) 146 self. ahCache = None;147 self. ahCacheNameAndCat = None;146 self.dCache = None; 147 self.dCacheNameAndCat = None; 148 148 self.oCategoryLogic = None; 149 149 self.oUserAccountLogic = None; … … 404 404 def cachedLookup(self, idFailureReason): 405 405 """ 406 Looks up the most recent FailureReasonDataEx object for uididFailureReason407 an object cache.406 Looks up the most recent FailureReasonDataEx object for idFailureReason 407 via an object cache. 408 408 409 409 Returns a shared FailureReasonData object. None if not found. 410 410 Raises exception on DB error. 411 411 """ 412 if self. ahCache is None:413 self. ahCache = self._oDb.getCache('FailureReasonDataEx');414 oEntry = self. ahCache.get(idFailureReason, None);412 if self.dCache is None: 413 self.dCache = self._oDb.getCache('FailureReasonDataEx'); 414 oEntry = self.dCache.get(idFailureReason, None); 415 415 if oEntry is None: 416 416 self._oDb.execute('SELECT *\n' … … 434 434 oEntry = FailureReasonDataEx().initFromDbRowEx(self._oDb.fetchOne(), self.oCategoryLogic, 435 435 self.oUserAccountLogic); 436 self. ahCache[idFailureReason] = oEntry;436 self.dCache[idFailureReason] = oEntry; 437 437 return oEntry; 438 438 … … 447 447 Raises exception on DB error. 448 448 """ 449 if self. ahCacheNameAndCat is None:450 self. ahCacheNameAndCat = self._oDb.getCache('FailureReasonDataEx-By-Name-And-Category');449 if self.dCacheNameAndCat is None: 450 self.dCacheNameAndCat = self._oDb.getCache('FailureReasonDataEx-By-Name-And-Category'); 451 451 sKey = '%s:::%s' % (sName, sCategory,); 452 oEntry = self. ahCacheNameAndCat.get(sKey, None);452 oEntry = self.dCacheNameAndCat.get(sKey, None); 453 453 if oEntry is None: 454 454 self._oDb.execute('SELECT *\n' … … 482 482 oEntry = FailureReasonDataEx().initFromDbRowEx(self._oDb.fetchOne(), self.oCategoryLogic, 483 483 self.oUserAccountLogic); 484 self. ahCacheNameAndCat[sKey] = oEntry;484 self.dCacheNameAndCat[sKey] = oEntry; 485 485 if sName != oEntry.sShort or sCategory != oEntry.oCategory.sShort: 486 486 sKey2 = '%s:::%s' % (oEntry.sShort, oEntry.oCategory.sShort,); 487 self. ahCacheNameAndCat[sKey2] = oEntry;487 self.dCacheNameAndCat[sKey2] = oEntry; 488 488 return oEntry; 489 489 -
trunk/src/VBox/ValidationKit/testmanager/core/report.py
r61278 r61286 35 35 from testmanager.core.dbobjcache import DatabaseObjCache; 36 36 from testmanager.core.failurereason import FailureReasonLogic; 37 from testmanager.core.testbox import TestBox Data;37 from testmanager.core.testbox import TestBoxLogic, TestBoxData; 38 38 from testmanager.core.testcase import TestCaseLogic; 39 from testmanager.core.testcaseargs import TestCaseArgsLogic; 39 40 from common import constants; 40 41 … … 198 199 class ReportTransientBase(object): 199 200 """ Details on the test where a problem was first/last seen. """ 200 def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter): 201 def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, # pylint: disable=too-many-arguments 202 iPeriod, fEnter, idSubject, oSubject): 201 203 self.idBuild = idBuild; # Build ID. 202 204 self.iRevision = iRevision; # SVN revision for build. … … 207 209 self.iPeriod = iPeriod; # Data set period. 208 210 self.fEnter = fEnter; # True if enter event, False if leave event. 211 self.idSubject = idSubject; 212 self.oSubject = oSubject; 209 213 210 214 class ReportFailureReasonTransient(ReportTransientBase): … … 212 216 def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, # pylint: disable=R0913 213 217 iPeriod, fEnter, oReason): 214 ReportTransientBase.__init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter); 218 ReportTransientBase.__init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter, 219 oReason.idFailureReason, oReason); 215 220 self.oReason = oReason; # FailureReasonDataEx 216 217 class ReportTestCaseFailureTransient(ReportTransientBase):218 """ Details on the test where a test case was first/last seen. """219 def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, # pylint: disable=R0913220 iPeriod, fEnter, oTestCase):221 ReportTransientBase.__init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter);222 self.oTestCase = oTestCase; # TestCaseDataEx223 224 221 225 222 … … 246 243 self.idFailureReason = aoRow[0]; 247 244 self.oReason = oReason; # FailureReasonDataEx 248 249 class ReportTestCaseFailureRow(ReportHitRowWithTotalBase):250 """ The account of one test case for a period. """251 def __init__(self, aoRow, oTestCase):252 ReportHitRowWithTotalBase.__init__(self, aoRow[0], oTestCase, aoRow[1], aoRow[4], aoRow[2], aoRow[3]);253 245 254 246 … … 369 361 ReportPeriodBase.__init__(self, oSet, iPeriod, sDesc, tsFrom, tsTo); 370 362 self.cWithoutReason = 0; # Number of failed test sets without any assigned reason. 371 372 class ReportTestCaseFailurePeriod(ReportPeriodWithTotalBase):373 """ A period in ReportTestCaseFailureSet. """374 def __init__(self, oSet, iPeriod, sDesc, tsFrom, tsTo):375 ReportPeriodWithTotalBase.__init__(self, oSet, iPeriod, sDesc, tsFrom, tsTo);376 363 377 364 … … 513 500 ReportPeriodSetBase.__init__(self, 'idFailureReason'); 514 501 515 class ReportTestCaseFailureSet(ReportPeriodSetWithTotalBase):516 """ What ReportLazyModel.getTestCaseFailures returns. """517 def __init__(self):518 ReportPeriodSetWithTotalBase.__init__(self, 'idTestCase');519 502 520 503 … … 720 703 Gets the test case failures of the subject in the specified period. 721 704 722 Returns a ReportTestCaseFailureSet instance. 723 724 """ 725 726 oTestCaseLogic = TestCaseLogic(self._oDb); 705 Returns a ReportPeriodSetWithTotalBase instance. 706 707 """ 708 return self._getSimpleFailures('idTestCase', TestCaseLogic); 709 710 711 def getTestCaseVariationFailures(self): 712 """ 713 Gets the test case failures of the subject in the specified period. 714 715 Returns a ReportPeriodSetWithTotalBase instance. 716 717 """ 718 return self._getSimpleFailures('idTestCaseArgs', TestCaseArgsLogic); 719 720 721 def getTestBoxFailures(self): 722 """ 723 Gets the test box failures of the subject in the specified period. 724 725 Returns a ReportPeriodSetWithTotalBase instance. 726 727 """ 728 return self._getSimpleFailures('idTestBox', TestBoxLogic); 729 730 731 def _getSimpleFailures(self, sIdColumn, oCacheLogicType, sIdAttr = None): 732 """ 733 Gets the test box failures of the subject in the specified period. 734 735 Returns a ReportPeriodSetWithTotalBase instance. 736 737 """ 738 739 oLogic = oCacheLogicType(self._oDb); 740 oSet = ReportPeriodSetWithTotalBase(sIdColumn if sIdAttr is None else sIdAttr); 727 741 728 742 # Retrieve the period results. 729 oSet = ReportTestCaseFailureSet();730 743 for iPeriod in xrange(self.cPeriods): 731 self._oDb.execute('SELECT idTestCase,\n'744 self._oDb.execute('SELECT ' + sIdColumn + ',\n' 732 745 ' COUNT(CASE WHEN enmStatus >= \'failure\' THEN 1 END),\n' 733 746 ' MIN(tsDone),\n' … … 738 751 + self.getExtraWhereExprForPeriod(iPeriod) 739 752 + self.getExtraSubjectWhereExpr() + '\n' 740 'GROUP BY idTestCase\n');753 'GROUP BY ' + sIdColumn + '\n'); 741 754 aaoRows = self._oDb.fetchAll() 742 755 743 oPeriod = Report TestCaseFailurePeriod(oSet, iPeriod, self.getStraightPeriodDesc(iPeriod),744 756 oPeriod = ReportPeriodWithTotalBase(oSet, iPeriod, self.getStraightPeriodDesc(iPeriod), 757 self.getPeriodStart(iPeriod), self.getPeriodEnd(iPeriod)); 745 758 746 759 for aoRow in aaoRows: 747 o TestCase = oTestCaseLogic.cachedLookup(aoRow[0]);748 oPeriodRow = Report TestCaseFailureRow(aoRow, oTestCase);749 oPeriod.appendRow(oPeriodRow, oTestCase.idTestCase, oTestCase);760 oSubject = oLogic.cachedLookup(aoRow[0]); 761 oPeriodRow = ReportHitRowWithTotalBase(aoRow[0], oSubject, aoRow[1], aoRow[4], aoRow[2], aoRow[3]); 762 oPeriod.appendRow(oPeriodRow, aoRow[0], oSubject); 750 763 751 764 oSet.appendPeriod(oPeriod); … … 762 775 for iPeriod in xrange(1, self.cPeriods): 763 776 oPeriod = oSet.aoPeriods[iPeriod]; 764 for oTestCase in oPeriod.dFirst.values(): 765 oSet.aoEnterInfo.append(self._getEdgeTestCaseFailureOccurence(oTestCase, iPeriod, fEnter = True)); 777 for idSubject, oSubject in oPeriod.dFirst.items(): 778 oSet.aoEnterInfo.append(self._getEdgeSimpleFailureOccurence(idSubject, sIdColumn, oSubject, 779 iPeriod, fEnter = True)); 766 780 767 781 # Ditto for reasons leaving before the last. 768 782 for iPeriod in xrange(self.cPeriods - 1): 769 783 oPeriod = oSet.aoPeriods[iPeriod]; 770 for oTestCase in oPeriod.dLast.values(): 771 oSet.aoLeaveInfo.append(self._getEdgeTestCaseFailureOccurence(oTestCase, iPeriod, fEnter = False)); 784 for idSubject, oSubject in oPeriod.dLast.items(): 785 oSet.aoLeaveInfo.append(self._getEdgeSimpleFailureOccurence(idSubject, sIdColumn, oSubject, 786 iPeriod, fEnter = False)); 772 787 773 788 oSet.finalizePass2(); … … 775 790 return oSet; 776 791 777 778 def _getEdgeTestCaseFailureOccurence(self, oTestCase, iPeriod, fEnter = True): 792 def _getEdgeSimpleFailureOccurence(self, idSubject, sIdColumn, oSubject, iPeriod, fEnter = True): 779 793 """ 780 794 Helper for the failure reason report that finds the oldest or newest build … … 784 798 is is returned. 785 799 786 Returns Report FailureReasonTransientinstant.800 Returns ReportTransientBase instant. 787 801 788 802 """ … … 797 811 ' Builds,\n' 798 812 ' BuildCategories' + self.getExtraSubjectTables() + '\n' 799 'WHERE TestSets. idTestCase= %s\n'813 'WHERE TestSets.' + sIdColumn + ' = %s\n' 800 814 ' AND TestSets.idBuild = Builds.idBuild\n' 801 815 ' AND TestSets.enmStatus >= \'failure\'\n' … … 808 822 ' TestSets.tsCreated ' + sSorting + '\n' 809 823 'LIMIT 1\n' 810 , ( oTestCase.idTestCase, ));824 , ( idSubject, )); 811 825 aoRow = self._oDb.fetchOne(); 812 826 if aoRow is None: 813 return ReportTestCaseFailureTransient(-1, -1, 'internal-error', -1, -1, 814 self._oDb.getCurrentTimestamp(), oTestCase, iPeriod, fEnter); 815 return ReportTestCaseFailureTransient(idBuild = aoRow[3], iRevision = aoRow[4], sRepository = aoRow[5], 816 idTestSet = aoRow[1], idTestResult = aoRow[0], tsDone = aoRow[2], 817 oTestCase = oTestCase, iPeriod = iPeriod, fEnter = fEnter); 827 return ReportTransientBase(-1, -1, 'internal-error', -1, -1, self._oDb.getCurrentTimestamp(), 828 iPeriod, fEnter, idSubject, oSubject); 829 return ReportTransientBase(idBuild = aoRow[3], iRevision = aoRow[4], sRepository = aoRow[5], 830 idTestSet = aoRow[1], idTestResult = aoRow[0], tsDone = aoRow[2], 831 iPeriod = iPeriod, fEnter = fEnter, idSubject = idSubject, oSubject = oSubject); 832 818 833 819 834 -
trunk/src/VBox/ValidationKit/testmanager/core/testbox.py
r61283 r61286 279 279 def __init__(self, oDb): 280 280 ModelLogicBase.__init__(self, oDb); 281 self.dCache = None; 281 282 282 283 def tryFetchTestBoxByUuid(self, sTestBoxUuid): … … 888 889 889 890 891 def cachedLookup(self, idTestBox): 892 """ 893 Looks up the most recent TestBoxData object for idTestBox via 894 an object cache. 895 896 Returns a shared TestBoxData object. None if not found. 897 Raises exception on DB error. 898 """ 899 if self.dCache is None: 900 self.dCache = self._oDb.getCache('TestBoxData'); 901 oEntry = self.dCache.get(idTestBox, None); 902 if oEntry is None: 903 self._oDb.execute('SELECT *\n' 904 'FROM TestBoxes\n' 905 'WHERE idTestBox = %s\n' 906 ' AND tsExpire = \'infinity\'::TIMESTAMP\n' 907 , (idTestBox, )); 908 if self._oDb.getRowCount() == 0: 909 # Maybe it was deleted, try get the last entry. 910 self._oDb.execute('SELECT *\n' 911 'FROM TestBoxes\n' 912 'WHERE idTestBox = %s\n' 913 'ORDER BY tsExpire DESC\n' 914 'LIMIT 1\n' 915 , (idTestBox, )); 916 elif self._oDb.getRowCount() > 1: 917 raise self._oDb.integrityException('%s infinity rows for %s' % (self._oDb.getRowCount(), idTestBox)); 918 919 if self._oDb.getRowCount() == 1: 920 aaoRow = self._oDb.fetchOne(); 921 oEntry = TestBoxData().initFromDbRow(aaoRow); 922 self.dCache[idTestBox] = oEntry; 923 return oEntry; 924 925 926 890 927 # 891 928 # The virtual test sheriff interface. -
trunk/src/VBox/ValidationKit/testmanager/core/testcase.py
r61284 r61286 941 941 def __init__(self, oDb): 942 942 ModelLogicBase.__init__(self, oDb) 943 self. ahCache = None;943 self.dCache = None; 944 944 945 945 def getAll(self): … … 1359 1359 def cachedLookup(self, idTestCase): 1360 1360 """ 1361 Looks up the most recent TestCaseDataEx object for uididTestCase1362 an object cache.1361 Looks up the most recent TestCaseDataEx object for idTestCase 1362 via an object cache. 1363 1363 1364 1364 Returns a shared TestCaseDataEx object. None if not found. 1365 1365 Raises exception on DB error. 1366 1366 """ 1367 if self. ahCache is None:1368 self. ahCache = self._oDb.getCache('TestCaseDataEx');1369 oEntry = self. ahCache.get(idTestCase, None);1367 if self.dCache is None: 1368 self.dCache = self._oDb.getCache('TestCaseDataEx'); 1369 oEntry = self.dCache.get(idTestCase, None); 1370 1370 if oEntry is None: 1371 ##fNeedTsNow = False; 1372 fNeedTsNow = True; 1371 fNeedTsNow = False; 1373 1372 self._oDb.execute('SELECT *\n' 1374 1373 'FROM TestCases\n' … … 1393 1392 tsNow = oEntry.initFromDbRow(aaoRow).tsEffective if fNeedTsNow else None; 1394 1393 oEntry.initFromDbRowEx(aaoRow, self._oDb, tsNow); 1395 self. ahCache[idTestCase] = oEntry;1394 self.dCache[idTestCase] = oEntry; 1396 1395 return oEntry; 1397 1396 -
trunk/src/VBox/ValidationKit/testmanager/core/testcaseargs.py
r61262 r61286 193 193 raise TMExceptionBase('Do not call me: %s' % (aoRow,)) 194 194 195 def initFromDbRowEx(self, aoRow, oDb, tsConfigEff = None, tsRsrcEff = None): 196 """ 197 Extended version of initFromDbRow that fills in the rest from the database. 198 """ 199 TestCaseArgsData.initFromDbRow(self, aoRow); 200 201 if tsConfigEff is None: tsConfigEff = oDb.getCurrentTimestamp(); 202 if tsRsrcEff is None: tsRsrcEff = oDb.getCurrentTimestamp(); 203 204 self.oTestCase = TestCaseData().initFromDbWithId(oDb, self.idTestCase, tsConfigEff); 205 self.aoTestCasePreReqs = TestCaseDependencyLogic(oDb).getTestCaseDeps(self.idTestCase, tsConfigEff); 206 self.aoGlobalRsrc = TestCaseGlobalRsrcDepLogic(oDb).getTestCaseDeps(self.idTestCase, tsRsrcEff); 207 208 return self; 209 195 210 def initFromDbWithId(self, oDb, idTestCaseArgs, tsNow = None, sPeriodBack = None): 196 211 _ = oDb; _ = idTestCaseArgs; _ = tsNow; _ = sPeriodBack; … … 205 220 Initialize from the database, given the ID of a row. 206 221 """ 207 208 222 oDb.execute('SELECT *, CURRENT_TIMESTAMP FROM TestCaseArgs WHERE idGenTestCaseArgs = %s', (idGenTestCaseArgs,)); 209 223 aoRow = oDb.fetchOne(); 210 TestCaseArgsData.initFromDbRow(self, aoRow); 211 212 tsNow = aoRow[TestCaseArgsData.kcDbColumns]; 213 if tsConfigEff is None: tsConfigEff = tsNow; 214 if tsRsrcEff is None: tsRsrcEff = tsNow; 215 216 self.oTestCase = TestCaseData().initFromDbWithId(oDb, self.idTestCase, tsConfigEff); 217 self.aoTestCasePreReqs = TestCaseDependencyLogic(oDb).getTestCaseDeps(self.idTestCase, tsConfigEff); 218 self.aoGlobalRsrc = TestCaseGlobalRsrcDepLogic(oDb).getTestCaseDeps(self.idTestCase, tsRsrcEff); 219 220 return self; 224 return self.initFromDbRowEx(aoRow, oDb, tsConfigEff, tsRsrcEff); 221 225 222 226 def convertFromParamNull(self): … … 259 263 def __init__(self, oDb): 260 264 ModelLogicBase.__init__(self, oDb); 265 self.dCache = None; 261 266 262 267 … … 348 353 pass 349 354 355 def cachedLookup(self, idTestCaseArgs): 356 """ 357 Looks up the most recent TestCaseArgsDataEx object for idTestCaseArg 358 via in an object cache. 359 360 Returns a shared TestCaseArgDataEx object. None if not found. 361 Raises exception on DB error. 362 """ 363 if self.dCache is None: 364 self.dCache = self._oDb.getCache('TestCaseArgsDataEx'); 365 oEntry = self.dCache.get(idTestCaseArgs, None); 366 if oEntry is None: 367 fNeedTsNow = False; 368 self._oDb.execute('SELECT *\n' 369 'FROM TestCaseArgs\n' 370 'WHERE idTestCaseArgs = %s\n' 371 ' AND tsExpire = \'infinity\'::TIMESTAMP\n' 372 , (idTestCaseArgs, )); 373 if self._oDb.getRowCount() == 0: 374 # Maybe it was deleted, try get the last entry. 375 self._oDb.execute('SELECT *\n' 376 'FROM TestCaseArgs\n' 377 'WHERE idTestCaseArgs = %s\n' 378 'ORDER BY tsExpire DESC\n' 379 'LIMIT 1\n' 380 , (idTestCaseArgs, )); 381 fNeedTsNow = True; 382 elif self._oDb.getRowCount() > 1: 383 raise self._oDb.integrityException('%s infinity rows for %s' % (self._oDb.getRowCount(), idTestCaseArgs)); 384 385 if self._oDb.getRowCount() == 1: 386 aaoRow = self._oDb.fetchOne(); 387 oEntry = TestCaseArgsDataEx(); 388 tsNow = oEntry.initFromDbRow(aaoRow).tsEffective if fNeedTsNow else None; 389 oEntry.initFromDbRowEx(aaoRow, self._oDb, tsNow, tsNow); 390 self.dCache[idTestCaseArgs] = oEntry; 391 return oEntry; 392 350 393 351 394 # -
trunk/src/VBox/ValidationKit/testmanager/core/useraccount.py
r61270 r61286 121 121 def __init__(self, oDb): 122 122 ModelLogicBase.__init__(self, oDb) 123 self. ahCache = None;123 self.dCache = None; 124 124 125 125 def fetchForListing(self, iStart, cMaxRows, tsNow): … … 232 232 Raises exception on DB error. 233 233 """ 234 if self. ahCache is None:235 self. ahCache = self._oDb.getCache('UserAccount');236 237 oUser = self. ahCache.get(uid, None);234 if self.dCache is None: 235 self.dCache = self._oDb.getCache('UserAccount'); 236 237 oUser = self.dCache.get(uid, None); 238 238 if oUser is None: 239 239 self._oDb.execute('SELECT *\n' … … 255 255 if self._oDb.getRowCount() == 1: 256 256 oUser = UserAccountData().initFromDbRow(self._oDb.fetchOne()); 257 self. ahCache[uid] = oUser;257 self.dCache[uid] = oUser; 258 258 return oUser; 259 259 -
trunk/src/VBox/ValidationKit/testmanager/webui/wuiadmintestbox.py
r61220 r61286 35 35 # Validation Kit imports. 36 36 from common import utils; 37 from testmanager.webui.wuicontentbase import Wui ListContentWithActionBase, WuiFormContentBase, WuiLinkBase, WuiSvnLink, \38 Wui TmLink, WuiSpanText, WuiRawHtml;37 from testmanager.webui.wuicontentbase import WuiContentBase, WuiListContentWithActionBase, WuiFormContentBase, WuiLinkBase, \ 38 WuiSvnLink, WuiTmLink, WuiSpanText, WuiRawHtml; 39 39 from testmanager.core.db import TMDatabaseConnection; 40 40 from testmanager.core.schedgroup import SchedGroupLogic, SchedGroupData; … … 42 42 from testmanager.core.testset import TestSetData; 43 43 from testmanager.core.db import isDbTimestampInfinity; 44 45 46 47 class WuiTestBoxDetailsLink(WuiTmLink): 48 """ Test box details link by ID. """ 49 50 def __init__(self, idTestBox, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False, tsNow = None): 51 from testmanager.webui.wuiadmin import WuiAdmin; 52 dParams = { 53 WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxDetails, 54 TestBoxData.ksParam_idTestBox: idTestBox, 55 }; 56 if tsNow is not None: 57 dParams[WuiAdmin.ksParamEffectiveDate] = tsNow; ## ?? 58 WuiTmLink.__init__(self, sName, WuiAdmin.ksScriptName, dParams, fBracketed = fBracketed); 59 self.idTestBox = idTestBox; 60 44 61 45 62 -
trunk/src/VBox/ValidationKit/testmanager/webui/wuimain.py
r61278 r61286 81 81 ksActionReportRate = 'ReportRate'; 82 82 ksActionReportTestCaseFailures = 'ReportTestCaseFailures'; 83 ksActionReportTestBoxFailures = 'ReportTestBoxFailures'; 83 84 ksActionReportFailureReasons = 'ReportFailureReasons'; 84 85 ksActionGraphWiz = 'GraphWiz'; … … 272 273 dCurParams = oSrvGlue.getParameters() 273 274 if dCurParams is not None: 274 asActionUrlExtras = [ self.ksParamItemsPerPage, self.ksParamEffectiveDate, self.ksParamEffectivePeriod, ]; 275 for sExtraParam in asActionUrlExtras: 275 for sExtraParam in [ self.ksParamItemsPerPage, self.ksParamEffectiveDate, self.ksParamEffectivePeriod, ]: 276 276 if sExtraParam in dCurParams: 277 sExtraTimeNav += '&%s' % webutils.encodeUrlParams({sExtraParam: dCurParams[sExtraParam]}) 277 sExtraTimeNav += '&%s' % (webutils.encodeUrlParams({sExtraParam: dCurParams[sExtraParam]}),) 278 279 # Additional URL parameters for reports 280 sExtraReports = ''; 281 if dCurParams is not None: 282 for sExtraParam in [ self.ksParamReportPeriods, self.ksParamReportPeriodInHours, self.ksParamEffectiveDate, ]: 283 if sExtraParam in dCurParams: 284 sExtraReports += '&%s' % (webutils.encodeUrlParams({sExtraParam: dCurParams[sExtraParam]}),) 278 285 279 286 # Shorthand to keep within margins. … … 298 305 'Reports', sActUrlBase + self.ksActionReportSummary, 299 306 [ 300 [ 'Summary', sActUrlBase + self.ksActionReportSummary ], 301 [ 'Success Rate', sActUrlBase + self.ksActionReportRate ], 302 [ 'Test Case Failures', sActUrlBase + self.ksActionReportTestCaseFailures ], 303 [ 'Failure Reasons', sActUrlBase + self.ksActionReportFailureReasons ], 307 [ 'Summary', sActUrlBase + self.ksActionReportSummary + sExtraReports ], 308 [ 'Success Rate', sActUrlBase + self.ksActionReportRate + sExtraReports ], 309 [ 'Test Case Failures', sActUrlBase + self.ksActionReportTestCaseFailures + sExtraReports ], 310 [ 'TestBox Failures', sActUrlBase + self.ksActionReportTestBoxFailures + sExtraReports ], 311 [ 'Failure Reasons', sActUrlBase + self.ksActionReportFailureReasons + sExtraReports ], 304 312 ] 305 313 ], -
trunk/src/VBox/ValidationKit/testmanager/webui/wuireport.py
r61275 r61286 36 36 from testmanager.webui.wuitestresult import WuiTestSetLink; 37 37 from testmanager.webui.wuiadmintestcase import WuiTestCaseDetailsLink; 38 from testmanager.webui.wuiadmintestbox import WuiTestBoxDetailsLink; 38 39 from testmanager.core.report import ReportModelBase; 39 40 … … 43 44 44 45 def __init__(self, sSubject, aIdSubjects, sName = WuiContentBase.ksShortReportLink, 45 tsNow = None, cPeriods = None, cHoursPerPeriod = None, fBracketed = False ):46 tsNow = None, cPeriods = None, cHoursPerPeriod = None, fBracketed = False, dExtraParams = None): 46 47 from testmanager.webui.wuimain import WuiMain; 47 48 dParams = { … … 50 51 WuiMain.ksParamReportSubjectIds: aIdSubjects, 51 52 }; 53 if dExtraParams is not None: 54 dParams.update(dExtraParams); 52 55 if tsNow is not None: 53 56 dParams[WuiMain.ksParamEffectiveDate] = tsNow; … … 70 73 self._fSubReport = fSubReport; 71 74 self._sTitle = None; 75 76 # Additional URL parameters for reports 77 self._dExtraParams = {}; 78 dCurParams = None if oDisp is None else oDisp.getParameters(); 79 if dCurParams is not None: 80 from testmanager.webui.wuimain import WuiMain; 81 for sExtraParam in [ WuiMain.ksParamReportPeriods, WuiMain.ksParamReportPeriodInHours, 82 WuiMain.ksParamEffectiveDate, ]: 83 if sExtraParam in dCurParams: 84 self._dExtraParams[sExtraParam] = dCurParams[sExtraParam]; 85 72 86 73 87 def generateNavigator(self, sWhere): … … 287 301 288 302 289 290 291 class WuiReportFailureReasons(WuiReportFailuresBase): 292 """ 293 Generates a report displaying the failure reasons over time. 294 """ 295 296 def _formatEdgeOccurenceSubject(self, oTransient): 297 return u'%s / %s' % ( webutils.escapeElem(oTransient.oReason.oCategory.sShort), 298 webutils.escapeElem(oTransient.oReason.sShort),); 299 300 def _formatSeriesNameForTable(self, oSet, idKey): 301 oReason = oSet.dSubjects[idKey]; 302 sHtml = '<td>' 303 sHtml += u'%s / %s' % ( webutils.escapeElem(oReason.oCategory.sShort), webutils.escapeElem(oReason.sShort),); 304 sHtml += '</td>' 305 return sHtml; 306 307 308 def generateReportBody(self): 309 self._sTitle = 'Failure reasons'; 310 311 # 312 # Get the data and sort the data series in descending order of badness. 313 # 314 oSet = self._oModel.getFailureReasons(); 315 aidSortedRaw = sorted(oSet.dSubjects, key = lambda idReason: oSet.dcHitsPerId[idReason], reverse = True); 316 317 # 318 # Generate table and transition list. These are the most useful ones with the current graph machinery. 319 # 320 sHtml = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw); 321 sHtml += self._generateTransitionList(oSet); 322 323 # 324 # Check if most of the stuff is without any assign reason, if so, skip 325 # that part of the graph so it doesn't offset the interesting bits. 326 # 327 fIncludeWithoutReason = True; 328 for oPeriod in reversed(oSet.aoPeriods): 329 if oPeriod.cWithoutReason > oSet.cMaxHits * 4: 330 fIncludeWithoutReason = False; 331 sHtml += '<p>Warning: Many failures without assigned reason!</p>\n'; 332 break; 333 334 # 335 # Generate the graph. 336 # 337 fGenerateGraph = len(aidSortedRaw) <= 9 and len(aidSortedRaw) > 0; ## Make this configurable. 338 if fGenerateGraph: 339 aidSorted = aidSortedRaw; 340 341 asNames = []; 342 for idReason in aidSorted: 343 oReason = oSet.dSubjects[idReason]; 344 asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) ) 345 if fIncludeWithoutReason: 346 asNames.append('No reason'); 347 348 oTable = WuiHlpGraphDataTable('Period', asNames); 349 350 cMax = oSet.cMaxHits; 351 for _, oPeriod in enumerate(reversed(oSet.aoPeriods)): 352 aiValues = []; 353 354 for idReason in aidSorted: 355 oRow = oPeriod.dRowsById.get(idReason, None); 356 iValue = oRow.cHits if oRow is not None else 0; 357 aiValues.append(iValue); 358 359 if fIncludeWithoutReason: 360 aiValues.append(oPeriod.cWithoutReason); 361 if oPeriod.cWithoutReason > cMax: 362 cMax = oPeriod.cWithoutReason; 363 364 oTable.addRow(oPeriod.sDesc, aiValues); 365 366 oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp); 367 oGraph.setRangeMax(max(cMax + 1, 3)); 368 sHtml += oGraph.renderGraph(); 369 return sHtml; 370 371 372 class WuiReportTestCaseFailures(WuiReportFailuresBase): 373 """ 374 Generates a report displaying the failure reasons over time. 375 """ 376 377 def _formatEdgeOccurenceSubject(self, oTransient): 378 sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oTestCase.sName),); 379 sHtml += WuiTestCaseDetailsLink(oTransient.oTestCase.idTestCase, fBracketed = False).toHtml(); 380 return sHtml; 381 382 def _formatSeriesNameForTable(self, oSet, idKey): 383 oTestCase = oSet.dSubjects[idKey]; 384 sHtml = '<td>' 385 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCase.idTestCase, sName = oTestCase.sName).toHtml(); 386 sHtml += u' '; 387 sHtml += WuiTestCaseDetailsLink(oTestCase.idTestCase).toHtml(); 388 sHtml += '</td>' 389 return sHtml; 390 391 def generateReportBody(self): 392 self._sTitle = 'Test Case Failures'; 393 394 395 # 396 # Get the data and sort the data series in descending order of badness. 397 # 398 oSet = self._oModel.getTestCaseFailures(); 303 class WuiReportFailuresWithTotalBase(WuiReportFailuresBase): 304 """ 305 For ReportPeriodSetWithTotalBase. 306 """ 307 308 def _getSortedIds(self, oSet): 309 """ 310 Get default sorted subject IDs. 311 """ 312 399 313 if self._oModel.tsNow is not None and False: 400 314 # Sort the total. … … 410 324 else: dTmp[idKey] = oRow.cHits * 10000 / max(1, oRow.cTotal); 411 325 aidSortedRaw = sorted(dTmp, key = lambda idKey: dTmp[idKey], reverse = True); 412 413 # 414 # Generate table and transition list. These are the most useful ones with the current graph machinery. 415 # 416 sHtml = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw); 417 sHtml += self._generateTransitionList(oSet); 418 419 # 420 # Generate the graph. 421 # 326 return aidSortedRaw; 327 328 def _generateGraph(self, oSet, sIdBase, aidSortedRaw): 329 """ 330 Generates graph. 331 """ 332 sHtml = u''; 422 333 fGenerateGraph = len(aidSortedRaw) <= 6 and len(aidSortedRaw) > 0; ## Make this configurable. 423 334 if fGenerateGraph: … … 459 370 oTable.addRow('Totals', aiValues, asValues); 460 371 461 oGraph = WuiHlpBarGraph( 'testcase-failures', oTable, self._oDisp);372 oGraph = WuiHlpBarGraph(sIdBase, oTable, self._oDisp); 462 373 oGraph.setRangeMax(uPctMax); 463 374 sHtml += '<br>\n'; 464 375 sHtml += oGraph.renderGraph(); 465 376 return sHtml; 377 378 379 380 class WuiReportFailureReasons(WuiReportFailuresBase): 381 """ 382 Generates a report displaying the failure reasons over time. 383 """ 384 385 def _formatEdgeOccurenceSubject(self, oTransient): 386 return u'%s / %s' % ( webutils.escapeElem(oTransient.oReason.oCategory.sShort), 387 webutils.escapeElem(oTransient.oReason.sShort),); 388 389 def _formatSeriesNameForTable(self, oSet, idKey): 390 oReason = oSet.dSubjects[idKey]; 391 sHtml = u'<td>'; 392 sHtml += u'%s / %s' % ( webutils.escapeElem(oReason.oCategory.sShort), webutils.escapeElem(oReason.sShort),); 393 sHtml += u'</td>'; 394 return sHtml; 395 396 397 def generateReportBody(self): 398 self._sTitle = 'Failure reasons'; 399 400 # 401 # Get the data and sort the data series in descending order of badness. 402 # 403 oSet = self._oModel.getFailureReasons(); 404 aidSortedRaw = sorted(oSet.dSubjects, key = lambda idReason: oSet.dcHitsPerId[idReason], reverse = True); 405 406 # 407 # Generate table and transition list. These are the most useful ones with the current graph machinery. 408 # 409 sHtml = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw); 410 sHtml += self._generateTransitionList(oSet); 411 412 # 413 # Check if most of the stuff is without any assign reason, if so, skip 414 # that part of the graph so it doesn't offset the interesting bits. 415 # 416 fIncludeWithoutReason = True; 417 for oPeriod in reversed(oSet.aoPeriods): 418 if oPeriod.cWithoutReason > oSet.cMaxHits * 4: 419 fIncludeWithoutReason = False; 420 sHtml += '<p>Warning: Many failures without assigned reason!</p>\n'; 421 break; 422 423 # 424 # Generate the graph. 425 # 426 fGenerateGraph = len(aidSortedRaw) <= 9 and len(aidSortedRaw) > 0; ## Make this configurable. 427 if fGenerateGraph: 428 aidSorted = aidSortedRaw; 429 430 asNames = []; 431 for idReason in aidSorted: 432 oReason = oSet.dSubjects[idReason]; 433 asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) ) 434 if fIncludeWithoutReason: 435 asNames.append('No reason'); 436 437 oTable = WuiHlpGraphDataTable('Period', asNames); 438 439 cMax = oSet.cMaxHits; 440 for _, oPeriod in enumerate(reversed(oSet.aoPeriods)): 441 aiValues = []; 442 443 for idReason in aidSorted: 444 oRow = oPeriod.dRowsById.get(idReason, None); 445 iValue = oRow.cHits if oRow is not None else 0; 446 aiValues.append(iValue); 447 448 if fIncludeWithoutReason: 449 aiValues.append(oPeriod.cWithoutReason); 450 if oPeriod.cWithoutReason > cMax: 451 cMax = oPeriod.cWithoutReason; 452 453 oTable.addRow(oPeriod.sDesc, aiValues); 454 455 oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp); 456 oGraph.setRangeMax(max(cMax + 1, 3)); 457 sHtml += oGraph.renderGraph(); 458 return sHtml; 459 460 461 class WuiReportTestCaseFailures(WuiReportFailuresWithTotalBase): 462 """ 463 Generates a report displaying the failure reasons over time. 464 """ 465 466 def _formatEdgeOccurenceSubject(self, oTransient): 467 sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),); 468 sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml(); 469 return sHtml; 470 471 def _formatSeriesNameForTable(self, oSet, idKey): 472 oTestCase = oSet.dSubjects[idKey]; 473 sHtml = u'<td>'; 474 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCase.idTestCase, sName = oTestCase.sName, 475 dExtraParams = self._dExtraParams).toHtml(); 476 sHtml += u' '; 477 sHtml += WuiTestCaseDetailsLink(oTestCase.idTestCase).toHtml(); 478 sHtml += u'</td>'; 479 return sHtml; 480 481 def generateReportBody(self): 482 self._sTitle = 'Test Case Failures'; 483 oSet = self._oModel.getTestCaseFailures(); 484 aidSortedRaw = self._getSortedIds(oSet); 485 486 sHtml = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw); 487 sHtml += self._generateTransitionList(oSet); 488 sHtml += self._generateGraph(oSet, 'testcase-graph', aidSortedRaw); 489 return sHtml; 490 491 492 class WuiReportTestCaseArgsFailures(WuiReportFailuresWithTotalBase): 493 """ 494 Generates a report displaying the failure reasons over time. 495 """ 496 497 @staticmethod 498 def _formatName(oTestCaseArgs): 499 if oTestCaseArgs.sSubName is not None and len(oTestCaseArgs.sSubName) > 0: 500 sName = u'%s / %s' % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.sSubName, ); 501 else: 502 sName = u'%s / #%u' % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.idTestCaseArgs, ); 503 return sName; 504 505 def _formatEdgeOccurenceSubject(self, oTransient): 506 sHtml = u'%s ' % ( webutils.escapeElem(self._formatName(oTransient.oSubject)),); 507 sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml(); 508 return sHtml; 509 510 def _formatSeriesNameForTable(self, oSet, idKey): 511 oTestCaseArgs = oSet.dSubjects[idKey]; 512 sHtml = u'<td>'; 513 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCaseArgs, oTestCaseArgs.idTestCaseArgs, 514 sName = self._formatName(oTestCaseArgs), dExtraParams = self._dExtraParams).toHtml(); 515 sHtml += u' '; 516 sHtml += WuiTestCaseDetailsLink(oTestCaseArgs.idTestCase).toHtml(); 517 sHtml += u'</td>'; 518 return sHtml; 519 520 def generateReportBody(self): 521 self._sTitle = 'Test Case Variation Failures'; 522 oSet = self._oModel.getTestCaseVariationFailures(); 523 aidSortedRaw = self._getSortedIds(oSet); 524 525 sHtml = self._generateTableForSet(oSet, 'Test Case Variations', aidSortedRaw); 526 sHtml += self._generateTransitionList(oSet); 527 sHtml += self._generateGraph(oSet, 'testcasearg-graph', aidSortedRaw); 528 return sHtml; 529 530 531 532 class WuiReportTestBoxFailures(WuiReportFailuresWithTotalBase): 533 """ 534 Generates a report displaying the failure reasons over time. 535 """ 536 537 def _formatEdgeOccurenceSubject(self, oTransient): 538 sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),); 539 sHtml += WuiTestBoxDetailsLink(oTransient.oSubject.idTestBox, fBracketed = False).toHtml(); 540 return sHtml; 541 542 def _formatSeriesNameForTable(self, oSet, idKey): 543 oTestBox = oSet.dSubjects[idKey]; 544 sHtml = u'<td>'; 545 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oTestBox.idTestBox, sName = oTestBox.sName, 546 dExtraParams = self._dExtraParams).toHtml(); 547 sHtml += u' '; 548 sHtml += WuiTestBoxDetailsLink(oTestBox.idTestBox).toHtml(); 549 sHtml += u'</td>'; 550 return sHtml; 551 552 def generateReportBody(self): 553 self._sTitle = 'Test Box Failures'; 554 oSet = self._oModel.getTestBoxFailures(); 555 aidSortedRaw = self._getSortedIds(oSet); 556 557 sHtml = self._generateTableForSet(oSet, 'Test Boxes', aidSortedRaw); 558 sHtml += self._generateTransitionList(oSet); 559 sHtml += self._generateGraph(oSet, 'testbox-graph', aidSortedRaw); 466 560 return sHtml; 467 561 … … 477 571 % (self._oModel.sSubject, self._oModel.aidSubjects,); 478 572 479 oSuccessRate = WuiReportSuccessRate( self._oModel, self._dParams, fSubReport = True, 480 fnDPrint = self._fnDPrint, oDisp = self._oDisp); 481 oTestCaseFailures = WuiReportTestCaseFailures(self._oModel, self._dParams, fSubReport = True, 482 fnDPrint = self._fnDPrint, oDisp = self._oDisp); 483 oFailureReasons = WuiReportFailureReasons( self._oModel, self._dParams, fSubReport = True, 484 fnDPrint = self._fnDPrint, oDisp = self._oDisp); 485 for oReport in [oSuccessRate, oTestCaseFailures, oFailureReasons, ]: 573 aoReports = []; 574 575 aoReports.append(WuiReportSuccessRate( self._oModel, self._dParams, fSubReport = True, 576 fnDPrint = self._fnDPrint, oDisp = self._oDisp)); 577 aoReports.append(WuiReportTestCaseFailures(self._oModel, self._dParams, fSubReport = True, 578 fnDPrint = self._fnDPrint, oDisp = self._oDisp)); 579 if self._oModel.sSubject == ReportModelBase.ksSubTestCase: 580 aoReports.append(WuiReportTestCaseArgsFailures(self._oModel, self._dParams, fSubReport = True, 581 fnDPrint = self._fnDPrint, oDisp = self._oDisp)); 582 aoReports.append(WuiReportTestBoxFailures( self._oModel, self._dParams, fSubReport = True, 583 fnDPrint = self._fnDPrint, oDisp = self._oDisp)); 584 aoReports.append(WuiReportFailureReasons( self._oModel, self._dParams, fSubReport = True, 585 fnDPrint = self._fnDPrint, oDisp = self._oDisp)); 586 587 for oReport in aoReports: 486 588 (sTitle, sContent) = oReport.show(); 487 589 sHtml += '<br>'; # drop this layout hack
Note:
See TracChangeset
for help on using the changeset viewer.