Changeset 61267 in vbox for trunk/src/VBox/ValidationKit
- Timestamp:
- May 28, 2016 8:36:17 PM (9 years ago)
- Location:
- trunk/src/VBox/ValidationKit/testmanager
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/testmanager/core/testresults.py
r61258 r61267 445 445 ksParam_sComment = 'TestResultFailure_sComment'; 446 446 447 kasAllowNullAttributes = ['tsEffective', 'tsExpire', 'uidAuthor', 'sComment' ];447 kasAllowNullAttributes = ['tsEffective', 'tsExpire', 'uidAuthor', 'sComment', 'idTestSet' ]; 448 448 449 449 kcDbColumns = 7; … … 618 618 self.oFailureReason = None; 619 619 if aoRow[31] is not None: 620 self.oFailureReason = oFailureReasonLogic.cachedLookup(aoRow[3 0]);620 self.oFailureReason = oFailureReasonLogic.cachedLookup(aoRow[31]); 621 621 self.oFailureReasonAssigner = None; 622 622 if aoRow[32] is not None: 623 self.oFailureReasonAssigner = oUserAccountLogic.cachedLookup(aoRow[3 1]);623 self.oFailureReasonAssigner = oUserAccountLogic.cachedLookup(aoRow[32]); 624 624 self.tsFailureReasonAssigned = aoRow[33]; 625 625 self.sFailureReasonComment = aoRow[34]; … … 769 769 kdResultGroupingMap = { 770 770 ksResultsGroupingTypeNone: ( 771 # Grouping tables; # Grouping field; # Grouping where addition. # Sort by overrides.772 ' TestSets',None, None, {}771 # Grouping tables; # Grouping field; # Grouping where addition. # Sort by overrides. 772 '', None, None, {} 773 773 ), 774 ksResultsGroupingTypeTestGroup: (' TestSets', 'TestSets.idTestGroup', None,{}),775 ksResultsGroupingTypeTestBox: (' TestSets', 'TestSets.idTestBox', None,{}),776 ksResultsGroupingTypeTestCase: (' TestSets', 'TestSets.idTestCase', None,{}),774 ksResultsGroupingTypeTestGroup: ('', 'TestSets.idTestGroup', None, {}), 775 ksResultsGroupingTypeTestBox: ('', 'TestSets.idTestBox', None, {}), 776 ksResultsGroupingTypeTestCase: ('', 'TestSets.idTestCase', None, {}), 777 777 ksResultsGroupingTypeBuildRev: ( 778 ' TestSets, Builds',778 ', Builds', 779 779 'Builds.iRevision', 780 780 ' AND Builds.idBuild = TestSets.idBuild' … … 784 784 ), 785 785 ksResultsGroupingTypeSchedGroup: ( 786 ' TestSets, TestBoxes',786 ', TestBoxes', 787 787 'TestBoxes.idSchedGroup', 788 788 ' AND TestSets.idGenTestBox = TestBoxes.idGenTestBox', … … 809 809 self.oUserAccountLogic = None; 810 810 811 def _getTimePeriodQueryPart(self, tsNow, sInterval ):811 def _getTimePeriodQueryPart(self, tsNow, sInterval, sExtraIndent = ''): 812 812 """ 813 813 Get part of SQL query responsible for SELECT data within … … 819 819 if tsNow is None: 820 820 sRet = '(TestSets.tsDone IS NULL OR TestSets.tsDone >= (CURRENT_TIMESTAMP - \'%s\'::interval))\n' \ 821 ' AND TestSets.tsCreated >= (CURRENT_TIMESTAMP - \'%s\'::interval - \'%u months\'::interval)\n' \ 822 % (sInterval, sInterval, cMonthsMourningPeriod); 821 '%s AND TestSets.tsCreated >= (CURRENT_TIMESTAMP - \'%s\'::interval - \'%u months\'::interval)\n' \ 822 % ( sInterval, 823 sExtraIndent, sInterval, cMonthsMourningPeriod); 823 824 else: 824 825 sTsNow = '\'%s\'::TIMESTAMP' % (tsNow,); # It's actually a string already. duh. 825 826 sRet = 'TestSets.tsCreated <= %s\n' \ 826 ' AND TestSets.tsCreated >= (%s - \'%s\'::interval - \'%u months\'::interval)\n' \827 ' AND (TestSets.tsDone IS NULL OR TestSets.tsDone >= (%s - \'%s\'::interval))\n' \827 '% AND TestSets.tsCreated >= (%s - \'%s\'::interval - \'%u months\'::interval)\n' \ 828 '% AND (TestSets.tsDone IS NULL OR TestSets.tsDone >= (%s - \'%s\'::interval))\n' \ 828 829 % ( sTsNow, 829 s TsNow, sInterval, cMonthsMourningPeriod,830 s TsNow, sInterval );830 sExtraIndent, sTsNow, sInterval, cMonthsMourningPeriod, 831 sExtraIndent, sTsNow, sInterval ); 831 832 return sRet 832 833 833 def fetchResultsForListing(self, iStart, cMaxRows, tsNow, sInterval, enmResultSortBy, 834 enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures ):834 def fetchResultsForListing(self, iStart, cMaxRows, tsNow, sInterval, enmResultSortBy, # pylint: disable=R0913 835 enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures, fOnlyNeedingReason): 835 836 """ 836 837 Fetches TestResults table content. … … 902 903 ' Builds,\n' \ 903 904 ' TestBoxes,\n' \ 904 ' TestResults LEFT OUTER JOIN TestResultFailures\n' \ 905 ' ON TestResults.idTestResult = TestResultFailures.idTestResult\n' \ 906 ' AND TestResultFailures.tsExpire = \'infinity\'::TIMESTAMP'; 905 ' TestResults\n' \ 906 ' LEFT OUTER JOIN TestResultFailures\n' \ 907 ' ON TestResults.idTestResult = TestResultFailures.idTestResult\n' \ 908 ' AND TestResultFailures.tsExpire = \'infinity\'::TIMESTAMP'; 907 909 if sSortingOrderBy is not None and sSortingOrderBy.find('FailureReason') >= 0: 908 910 sQuery += '\n' \ 909 911 ' LEFT OUTER JOIN FailureReasons\n' \ 910 ' ONTestResultFailures.idFailureReason = FailureReasons.idFailureReason\n' \911 ' AND FailureReasons.tsExpire = \'infinity\'::TIMESTAMP';912 ' ON TestResultFailures.idFailureReason = FailureReasons.idFailureReason\n' \ 913 ' AND FailureReasons.tsExpire = \'infinity\'::TIMESTAMP'; 912 914 sQuery += ',\n'\ 913 915 ' TestCases,\n' \ … … 922 924 ' TestSets.idGenTestCase AS idGenTestCase,\n' \ 923 925 ' TestSets.idGenTestCaseArgs AS idGenTestCaseArgs\n' \ 924 ' FROM ' + sGroupingTables + sSortingTables + '\n' \ 925 ' WHERE ' + self._getTimePeriodQueryPart(tsNow, sInterval); 926 if fOnlyFailures: 927 sQuery += ' AND TestSets.enmStatus != \'success\'::TestStatus_T' \ 928 ' AND TestSets.enmStatus != \'running\'::TestStatus_T'; 926 ' FROM TestSets'; 927 if fOnlyNeedingReason: 928 sQuery += '\n' \ 929 ' LEFT OUTER JOIN TestResultFailures\n' \ 930 ' ON TestSets.idTestSet = TestResultFailures.idTestSet\n' \ 931 ' AND TestResultFailures.tsExpire = \'infinity\'::TIMESTAMP'; 932 sQuery += sGroupingTables.replace(',', ',\n '); 933 sQuery += sSortingTables.replace( ',', ',\n '); 934 sQuery += '\n' \ 935 ' WHERE ' + self._getTimePeriodQueryPart(tsNow, sInterval, ' '); 936 if fOnlyFailures or fOnlyNeedingReason: 937 sQuery += ' AND TestSets.enmStatus != \'success\'::TestStatus_T\n' \ 938 ' AND TestSets.enmStatus != \'running\'::TestStatus_T\n'; 939 if fOnlyNeedingReason: 940 sQuery += ' AND TestResultFailures.idTestSet IS NULL\n'; 929 941 if sGroupingField is not None: 930 942 sQuery += ' AND %s = %d\n' % (sGroupingField, iResultsGroupingValue,); … … 972 984 return aoRows 973 985 974 def getEntriesCount(self, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures ):986 def getEntriesCount(self, tsNow, sInterval, enmResultsGroupingType, iResultsGroupingValue, fOnlyFailures, fOnlyNeedingReason): 975 987 """ 976 988 Get number of table records. … … 997 1009 # Construct the query. 998 1010 # 999 sQuery = 'SELECT COUNT(idTestSet)\n' \ 1000 'FROM ' + sGroupingTables + '\n' \ 1001 'WHERE ' + self._getTimePeriodQueryPart(tsNow, sInterval); 1002 if fOnlyFailures: 1003 sQuery += ' AND TestSets.enmStatus != \'success\'::TestStatus_T' \ 1004 ' AND TestSets.enmStatus != \'running\'::TestStatus_T'; 1011 sQuery = 'SELECT COUNT(TestSets.idTestSet)\n' \ 1012 'FROM TestSets'; 1013 if fOnlyNeedingReason: 1014 sQuery += '\n' \ 1015 ' LEFT OUTER JOIN TestResultFailures\n' \ 1016 ' ON TestSets.idTestSet = TestResultFailures.idTestSet\n' \ 1017 ' AND TestResultFailures.tsExpire = \'infinity\'::TIMESTAMP'; 1018 sQuery += sGroupingTables.replace(',', ',\n '); 1019 sQuery += '\n' \ 1020 'WHERE ' + self._getTimePeriodQueryPart(tsNow, sInterval); 1021 if fOnlyFailures or fOnlyNeedingReason: 1022 sQuery += ' AND TestSets.enmStatus != \'success\'::TestStatus_T\n' \ 1023 ' AND TestSets.enmStatus != \'running\'::TestStatus_T\n'; 1024 if fOnlyNeedingReason: 1025 sQuery += ' AND TestResultFailures.idTestSet IS NULL\n'; 1005 1026 if sGroupingField is not None: 1006 1027 sQuery += ' AND %s = %d\n' % (sGroupingField, iResultsGroupingValue,); … … 1062 1083 """ 1063 1084 1064 ## @todo do all in one query. 1065 self._oDb.execute('SELECT DISTINCT TestBoxes.idTestBox, TestBoxes.idGenTestBox\n' 1066 'FROM TestBoxes, TestSets\n' 1067 'WHERE TestSets.idGenTestBox = TestBoxes.idGenTestBox\n' 1068 ' AND ' + self._getTimePeriodQueryPart(tsNow, sPeriod) + 1069 'ORDER BY TestBoxes.idTestBox, TestBoxes.idGenTestBox DESC' ); 1070 idPrevTestBox = -1; 1071 asIdGenTestBoxes = []; 1085 self._oDb.execute('SELECT TestBoxes.*\n' 1086 'FROM TestBoxes,\n' 1087 ' ( SELECT TestBoxes.idTestBox AS idTestBox,\n' 1088 ' MAX(TestBoxes.idGenTestBox) AS idGenTestBox\n' 1089 ' FROM TestBoxes, TestSets\n' 1090 ' WHERE TestSets.idGenTestBox = TestBoxes.idGenTestBox\n' 1091 ' AND ' + self._getTimePeriodQueryPart(tsNow, sPeriod, ' ') + 1092 ' GROUP BY TestBoxes.idTestBox\n' 1093 ' ORDER BY TestBoxes.idTestBox\n' 1094 ' ) AS TestBoxIDs\n' 1095 'WHERE TestBoxes.idGenTestBox = TestBoxIDs.idGenTestBox\n' 1096 'ORDER BY TestBoxes.sName\n' ); 1097 aoRet = [] 1072 1098 for aoRow in self._oDb.fetchAll(): 1073 if aoRow[0] != idPrevTestBox: 1074 idPrevTestBox = aoRow[0]; 1075 asIdGenTestBoxes.append(str(aoRow[1])); 1076 1077 aoRet = [] 1078 if len(asIdGenTestBoxes) > 0: 1079 self._oDb.execute('SELECT *\n' 1080 'FROM TestBoxes\n' 1081 'WHERE idGenTestBox IN (' + ','.join(asIdGenTestBoxes) + ')\n' 1082 'ORDER BY sName'); 1083 for aoRow in self._oDb.fetchAll(): 1084 aoRet.append(TestBoxData().initFromDbRow(aoRow)); 1099 aoRet.append(TestBoxData().initFromDbRow(aoRow)); 1085 1100 return aoRet 1086 1101 … … 2182 2197 def _resolveSetTestIdIfMissing(self, oData): 2183 2198 """ Resolve any missing idTestSet reference (it's a duplicate for speed efficiency). """ 2184 if oData.idTestSet is None and oData.idTestResult is not None 2199 if oData.idTestSet is None and oData.idTestResult is not None: 2185 2200 self._oDb.execute('SELECT idTestSet FROM TestResults WHERE idTestResult = %s', (oData.idTestResult,)); 2186 oData.idTest Result = self._oDb.fetchOne()[0];2201 oData.idTestSet = self._oDb.fetchOne()[0]; 2187 2202 return oData; 2188 2203 -
trunk/src/VBox/ValidationKit/testmanager/webui/wuibase.py
r61250 r61267 919 919 920 920 921 def _actionGenericFormPost(self, sMode, fnLogicAction, oDataType, oFormType, sRedirectTo, fStrict =True):921 def _actionGenericFormPost(self, sMode, fnLogicAction, oDataType, oFormType, sRedirectTo, fStrict = True): 922 922 """ 923 923 Generic POST request handling from a WuiFormContentBase child. … … 989 989 return self._actionGenericFormPost(WuiFormContentBase.ksMode_Add, oLogic.addEntry, oDataType, oFormType, 990 990 '?' + webutils.encodeUrlParams({self.ksParamAction: sRedirAction}), fStrict=fStrict) 991 991 992 def _actionGenericFormEditPost(self, oDataType, oLogicType, oFormType, sRedirAction, fStrict = True): 992 993 """ -
trunk/src/VBox/ValidationKit/testmanager/webui/wuimain.py
r61250 r61267 154 154 ksParamGroupMemberId = 'GroupMemberId' 155 155 ## Optional parameter for indicating whether to restrict the listing to failures only. 156 ksParamOnlyFailures = 'OnlyFailures' 156 ksParamOnlyFailures = 'OnlyFailures'; 157 ## The sheriff parameter for getting failures needing a reason or two assigned to them. 158 ksParamOnlyNeedingReason = 'OnlyNeedingReason'; 157 159 ## Result listing sorting. 158 160 ksParamTestResultsSortBy = 'enmSortBy' … … 271 273 272 274 # Shorthand to keep within margins. 273 sActUrlBase = self._sActionUrlBase; 274 sOFail = '&%s' % webutils.encodeUrlParams({self.ksParamOnlyFailures: True}); 275 sActUrlBase = self._sActionUrlBase; 276 sOnlyFailures = '&%s%s' % ( webutils.encodeUrlParams({self.ksParamOnlyFailures: True}), sExtraTimeNav, ); 277 sSheriff = '&%s%s' % ( webutils.encodeUrlParams({self.ksParamOnlyNeedingReason: True}), sExtraTimeNav, ); 275 278 276 279 self._aaoMenus = \ 277 280 [ 278 281 [ 279 'Inbox', sActUrlBase + 'TODO', ## @todo list of failures that needs categorizing. 280 [] 282 'Sheriff', sActUrlBase + self.ksActionResultsUnGrouped + sSheriff, 283 [ 284 [ 'Ungrouped results', sActUrlBase + self.ksActionResultsUnGrouped + sSheriff ], 285 [ 'Grouped by Scheduling Group', sActUrlBase + self.ksActionResultsGroupedBySchedGroup + sSheriff ], 286 [ 'Grouped by Test Group', sActUrlBase + self.ksActionResultsGroupedByTestGroup + sSheriff ], 287 [ 'Grouped by TestBox', sActUrlBase + self.ksActionResultsGroupedByTestBox + sSheriff ], 288 [ 'Grouped by Test Case', sActUrlBase + self.ksActionResultsGroupedByTestCase + sSheriff ], 289 [ 'Grouped by Revision', sActUrlBase + self.ksActionResultsGroupedByBuildRev + sSheriff ], 290 ] 281 291 ], 282 292 [ … … 300 310 ], 301 311 [ 302 'Test Failures', sActUrlBase + self.ksActionResultsUnGrouped + sO Fail + sExtraTimeNav,312 'Test Failures', sActUrlBase + self.ksActionResultsUnGrouped + sOnlyFailures, 303 313 [ 304 [ 'Ungrouped results', sActUrlBase + self.ksActionResultsUnGrouped +sOFail+sExtraTimeNav],305 [ 'Grouped by Scheduling Group', sActUrlBase + self.ksActionResultsGroupedBySchedGroup +sOFail+sExtraTimeNav],306 [ 'Grouped by Test Group', sActUrlBase + self.ksActionResultsGroupedByTestGroup +sOFail+sExtraTimeNav],307 [ 'Grouped by TestBox', sActUrlBase + self.ksActionResultsGroupedByTestBox +sOFail+sExtraTimeNav],308 [ 'Grouped by Test Case', sActUrlBase + self.ksActionResultsGroupedByTestCase +sOFail+sExtraTimeNav],309 [ 'Grouped by Revision', sActUrlBase + self.ksActionResultsGroupedByBuildRev +sOFail+sExtraTimeNav],314 [ 'Ungrouped results', sActUrlBase + self.ksActionResultsUnGrouped + sOnlyFailures ], 315 [ 'Grouped by Scheduling Group', sActUrlBase + self.ksActionResultsGroupedBySchedGroup + sOnlyFailures ], 316 [ 'Grouped by Test Group', sActUrlBase + self.ksActionResultsGroupedByTestGroup + sOnlyFailures ], 317 [ 'Grouped by TestBox', sActUrlBase + self.ksActionResultsGroupedByTestBox + sOnlyFailures ], 318 [ 'Grouped by Test Case', sActUrlBase + self.ksActionResultsGroupedByTestCase + sOnlyFailures ], 319 [ 'Grouped by Revision', sActUrlBase + self.ksActionResultsGroupedByBuildRev + sOnlyFailures ], 310 320 ] 311 321 ], … … 326 336 def _isMenuMatch(self, sMenuUrl, sActionParam): 327 337 if super(WuiMain, self)._isMenuMatch(sMenuUrl, sActionParam): 338 fOnlyNeedingReason = self.getBoolParam(self.ksParamOnlyNeedingReason, fDefault = False); 339 if fOnlyNeedingReason: 340 return (sMenuUrl.find(self.ksParamOnlyNeedingReason) > 0); 328 341 fOnlyFailures = self.getBoolParam(self.ksParamOnlyFailures, fDefault = False); 329 return (sMenuUrl.find(self.ksParamOnlyFailures) > 0) == fOnlyFailures; 342 return (sMenuUrl.find(self.ksParamOnlyFailures) > 0) == fOnlyFailures \ 343 and sMenuUrl.find(self.ksParamOnlyNeedingReason) < 0; 330 344 return False; 331 345 … … 705 719 oListContentType is a child of WuiListContentBase. 706 720 """ 707 cItemsPerPage = self.getIntParam(self.ksParamItemsPerPage, iMin = 2, iMax = 9999, iDefault = 128); 708 iPage = self.getIntParam(self.ksParamPageNo, iMin = 0, iMax = 999999, iDefault = 0); 709 tsEffective = self.getEffectiveDateParam(); 710 iGroupMemberId = self.getIntParam(self.ksParamGroupMemberId, iMin = -1, iMax = 999999, iDefault = -1); 711 fOnlyFailures = self.getBoolParam(self.ksParamOnlyFailures, fDefault = False); 712 enmResultSortBy = self.getStringParam(self.ksParamTestResultsSortBy, 713 asValidValues = TestResultLogic.kasResultsSortBy, 714 sDefault = TestResultLogic.ksResultsSortByRunningAndStart); 721 cItemsPerPage = self.getIntParam(self.ksParamItemsPerPage, iMin = 2, iMax = 9999, iDefault = 128); 722 iPage = self.getIntParam(self.ksParamPageNo, iMin = 0, iMax = 999999, iDefault = 0); 723 tsEffective = self.getEffectiveDateParam(); 724 iGroupMemberId = self.getIntParam(self.ksParamGroupMemberId, iMin = -1, iMax = 999999, iDefault = -1); 725 fOnlyFailures = self.getBoolParam(self.ksParamOnlyFailures, fDefault = False); 726 fOnlyNeedingReason = self.getBoolParam(self.ksParamOnlyNeedingReason, fDefault = False); 727 enmResultSortBy = self.getStringParam(self.ksParamTestResultsSortBy, 728 asValidValues = TestResultLogic.kasResultsSortBy, 729 sDefault = TestResultLogic.ksResultsSortByRunningAndStart); 715 730 716 731 # Get testing results period and validate it 717 asValidValues = [x for (x, _, _) in self.kaoResultPeriods]718 sCurPeriod = self.getStringParam(self.ksParamEffectivePeriod, asValidValues = asValidValues,719 sDefault = self.ksResultPeriodDefault)732 asValidValues = [x for (x, _, _) in self.kaoResultPeriods] 733 sCurPeriod = self.getStringParam(self.ksParamEffectivePeriod, asValidValues = asValidValues, 734 sDefault = self.ksResultPeriodDefault) 720 735 assert sCurPeriod != ''; # Impossible! 721 736 … … 790 805 enmResultsGroupingType = enmResultsGroupingType, 791 806 iResultsGroupingValue = idMember, 792 fOnlyFailures = fOnlyFailures); 807 fOnlyFailures = fOnlyFailures, 808 fOnlyNeedingReason = fOnlyNeedingReason); 793 809 if cEntries == 0: # Do not display empty groups 794 810 continue … … 800 816 enmResultsGroupingType = enmResultsGroupingType, 801 817 iResultsGroupingValue = idMember, 802 fOnlyFailures = fOnlyFailures); 818 fOnlyFailures = fOnlyFailures, 819 fOnlyNeedingReason = fOnlyNeedingReason); 803 820 cEntriesMax = max(cEntriesMax, cEntries) 804 821 -
trunk/src/VBox/ValidationKit/testmanager/webui/wuitestresult.py
r61263 r61267 394 394 oForm.addTextHidden(TestResultFailureData.ksParam_uidAuthor, oData.uidAuthor); 395 395 oForm.addSubmit('Change Reason'); 396 397 396 else: 398 397 oForm.addComboBox(TestResultFailureData.ksParam_idFailureReason, -1, 'Reason', aoFailureReasons, … … 808 807 # Reason: 809 808 oReason = None; 809 #assert (oEntry.oFailureReason is None) == (oEntry.tsFailureReasonAssigned is None); 810 810 if oEntry.oFailureReason is not None: 811 811 sReasonTitle = 'Reason: \t%s\n' % ( oEntry.oFailureReason.sShort, );
Note:
See TracChangeset
for help on using the changeset viewer.