Changeset 83364 in vbox for trunk/src/VBox/ValidationKit/testmanager/core
- Timestamp:
- Mar 23, 2020 9:47:01 AM (5 years ago)
- Location:
- trunk/src/VBox/ValidationKit/testmanager/core
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/testmanager/core/schedgroup.py
r83340 r83364 39 39 from testmanager.core.testcase import TestCaseData; 40 40 from testmanager.core.testcaseargs import TestCaseArgsData; 41 from testmanager.core.testbox import TestBox Data, TestBoxLogic;41 from testmanager.core.testbox import TestBoxLogic, TestBoxDataForSchedGroup; 42 42 from testmanager.core.testgroup import TestGroupData; 43 43 … … 250 250 251 251 ksParam_aoMembers = 'SchedGroup_aoMembers'; 252 kasAltArrayNull = [ 'aoMembers', ]; 252 ksParam_aoTestBoxes = 'SchedGroup_aoTestboxes'; 253 kasAltArrayNull = [ 'aoMembers', 'aoTestboxes' ]; 253 254 254 255 ## Helper parameter containing the comma separated list with the IDs of 255 256 # potential members found in the parameters. 256 257 ksParam_aidTestGroups = 'TestGroupDataEx_aidTestGroups'; 258 ## Ditto for testbox meembers. 259 ksParam_aidTestBoxes = 'TestGroupDataEx_aidTestBoxes'; 257 260 258 261 259 262 def __init__(self): 260 263 SchedGroupData.__init__(self); 261 self.aoMembers = [] # type: SchedGroupMemberDataEx 262 263 # Two build sources for convenience sake. 264 self.oBuildSrc = None # type: TestBoxData 265 self.oBuildSrcValidationKit = None # type: TestBoxData 266 # List of test boxes that uses this group for convenience. 267 self.aoTestBoxes = None # type: list[TestBoxData] 264 self.aoMembers = [] # type: list[SchedGroupMemberDataEx] 265 self.aoTestBoxes = [] # type: list[TestBoxDataForSchedGroup] 266 267 # The two build sources for the sake of convenience. 268 self.oBuildSrc = None # type: BuildSourceData 269 self.oBuildSrcValidationKit = None # type: BuildSourceData 268 270 269 271 def _initExtraMembersFromDb(self, oDb, tsNow = None, sPeriodBack = None): … … 273 275 """ 274 276 # 275 # It all upfront so the object has some kind of consistency if anything276 # below raises exceptions.277 # 278 self.oBuildSrc = None;277 # Clear all members upfront so the object has some kind of consistency 278 # if anything below raises exceptions. 279 # 280 self.oBuildSrc = None; 279 281 self.oBuildSrcValidationKit = None; 280 self.aoTestBoxes = [];281 self.aoMembers = [];282 self.aoTestBoxes = []; 283 self.aoMembers = []; 282 284 283 285 # … … 294 296 # Test Boxes. 295 297 # 296 oDb.execute('SELECT TestBoxesWithStrings.*\n' 297 'FROM TestBoxesWithStrings,\n' 298 ' TestBoxesInSchedGroups\n' 299 'WHERE TestBoxesInSchedGroups.idSchedGroup = %s\n' 300 + self.formatSimpleNowAndPeriod(oDb, tsNow, sPeriodBack, sTablePrefix = 'TestBoxesInSchedGroups.') + 301 ' AND TestBoxesWithStrings.idTestBox = TestBoxesInSchedGroups.idTestBox\n' 302 + self.formatSimpleNowAndPeriod(oDb, tsNow, sPeriodBack, sTablePrefix = 'TestBoxesWithStrings.') + 303 'ORDER BY TestBoxesWithStrings.sName, TestBoxesWithStrings.idTestBox\n' 304 , (self.idSchedGroup,)); 305 for aoRow in oDb.fetchAll(): 306 self.aoTestBoxes.append(TestBoxData().initFromDbRow(aoRow)); 298 self.aoTestBoxes = TestBoxLogic(oDb).fetchForSchedGroup(self.idSchedGroup, tsNow); 307 299 308 300 # … … 341 333 asAttributes.remove('oBuildSrc'); 342 334 asAttributes.remove('oBuildSrcValidationKit'); 343 asAttributes.remove('aoTestBoxes');344 335 return asAttributes; 345 336 346 337 def getAttributeParamNullValues(self, sAttr): 347 if sAttr != 'aoMembers':338 if sAttr not in [ 'aoMembers', 'aoTestBoxes' ]: 348 339 return SchedGroupData.getAttributeParamNullValues(self, sAttr); 349 340 return ['', [], None]; 350 341 351 342 def convertParamToAttribute(self, sAttr, sParam, oValue, oDisp, fStrict): 352 if sAttr != 'aoMembers': 343 aoNewValue = []; 344 if sAttr == 'aoMembers': 345 aidSelected = oDisp.getListOfIntParams(sParam, iMin = 1, iMax = 0x7ffffffe, aiDefaults = []) 346 sIds = oDisp.getStringParam(self.ksParam_aidTestGroups, sDefault = ''); 347 for idTestGroup in sIds.split(','): 348 try: idTestGroup = int(idTestGroup); 349 except: pass; 350 oDispWrapper = self.DispWrapper(oDisp, '%s[%s][%%s]' % (SchedGroupDataEx.ksParam_aoMembers, idTestGroup,)) 351 oMember = SchedGroupMemberDataEx().initFromParams(oDispWrapper, fStrict = False); 352 if idTestGroup in aidSelected: 353 aoNewValue.append(oMember); 354 elif sAttr == 'aoTestBoxes': 355 aidSelected = oDisp.getListOfIntParams(sParam, iMin = 1, iMax = 0x7ffffffe, aiDefaults = []) 356 sIds = oDisp.getStringParam(self.ksParam_aidTestBoxes, sDefault = ''); 357 for idTestBox in sIds.split(','): 358 try: idTestBox = int(idTestBox); 359 except: pass; 360 oDispWrapper = self.DispWrapper(oDisp, '%s[%s][%%s]' % (SchedGroupDataEx.ksParam_aoTestBoxes, idTestBox,)) 361 oTestBox = TestBoxDataForSchedGroup().initFromParams(oDispWrapper, fStrict = False); 362 if idTestBox in aidSelected: 363 aoNewValue.append(oTestBox); 364 else: 353 365 return SchedGroupData.convertParamToAttribute(self, sAttr, sParam, oValue, oDisp, fStrict); 354 355 aoNewValue = [];356 aidSelected = oDisp.getListOfIntParams(sParam, iMin = 1, iMax = 0x7ffffffe, aiDefaults = [])357 sIds = oDisp.getStringParam(self.ksParam_aidTestGroups, sDefault = '');358 for idTestGroup in sIds.split(','):359 try: idTestGroup = int(idTestGroup);360 except: pass;361 oDispWrapper = self.DispWrapper(oDisp, '%s[%s][%%s]' % (SchedGroupDataEx.ksParam_aoMembers, idTestGroup,))362 oMember = SchedGroupMemberDataEx().initFromParams(oDispWrapper, fStrict = False);363 if idTestGroup in aidSelected:364 aoNewValue.append(oMember);365 366 return aoNewValue; 366 367 367 368 def _validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb): 368 if sAttr != 'aoMembers':369 if sAttr not in [ 'aoMembers', 'aoTestBoxes' ]: 369 370 return SchedGroupData._validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb); 370 371 371 372 asErrors = []; 372 373 aoNewMembers = []; 373 for oOldMember in oValue: 374 oNewMember = SchedGroupMemberDataEx().initFromOther(oOldMember); 375 aoNewMembers.append(oNewMember); 376 377 dErrors = oNewMember.validateAndConvert(oDb, ModelDataBase.ksValidateFor_Other); 378 if dErrors: 379 asErrors.append(str(dErrors)); 380 381 if not asErrors: 382 for i, _ in enumerate(aoNewMembers): 383 idTestGroup = aoNewMembers[i]; 384 for j in range(i + 1, len(aoNewMembers)): 385 if aoNewMembers[j].idTestGroup == idTestGroup: 386 asErrors.append('Duplicate test group #%d!' % (idTestGroup, )); 387 break; 374 if sAttr == 'aoMembers': 375 for oOldMember in oValue: 376 oNewMember = SchedGroupMemberDataEx().initFromOther(oOldMember); 377 aoNewMembers.append(oNewMember); 378 379 dErrors = oNewMember.validateAndConvert(oDb, ModelDataBase.ksValidateFor_Other); 380 if dErrors: 381 asErrors.append(str(dErrors)); 382 383 if not asErrors: 384 for i, _ in enumerate(aoNewMembers): 385 idTestGroup = aoNewMembers[i]; 386 for j in range(i + 1, len(aoNewMembers)): 387 if aoNewMembers[j].idTestGroup == idTestGroup: 388 asErrors.append('Duplicate test group #%d!' % (idTestGroup, )); 389 break; 390 else: 391 for oOldMember in oValue: 392 oNewMember = TestBoxDataForSchedGroup().initFromOther(oOldMember); 393 aoNewMembers.append(oNewMember); 394 395 dErrors = oNewMember.validateAndConvert(oDb, ModelDataBase.ksValidateFor_Other); 396 if dErrors: 397 asErrors.append(str(dErrors)); 398 399 if not asErrors: 400 for i, _ in enumerate(aoNewMembers): 401 idTestBox = aoNewMembers[i]; 402 for j in range(i + 1, len(aoNewMembers)): 403 if aoNewMembers[j].idTestBox == idTestBox: 404 asErrors.append('Duplicate test group #%d!' % (idTestBox, )); 405 break; 406 388 407 389 408 return (aoNewMembers, None if not asErrors else '<br>\n'.join(asErrors)); … … 501 520 oData.idSchedGroup = idSchedGroup; 502 521 522 for oBoxInGrp in oData.aoTestBoxes: 523 oBoxInGrp.idSchedGroup = idSchedGroup; 524 self._addSchedGroupTestBox(uidAuthor, oBoxInGrp); 525 503 526 for oMember in oData.aoMembers: 504 527 oMember.idSchedGroup = idSchedGroup; … … 553 576 self._addSchedGroupMember(uidAuthor, oMember); 554 577 578 # Remove testboxes. 579 for oOld in oOldData.aoTestBoxes: 580 fRemove = True; 581 for oNew in oData.aoTestBoxes: 582 if oNew.idTestBox == oOld.idTestBox: 583 fRemove = False; 584 break; 585 if fRemove: 586 self._removeSchedGroupTestBox(uidAuthor, oOld); 587 588 # Add / modify testboxes. 589 for oBoxInGrp in oData.aoTestBoxes: 590 oOldBoxInGrp = None; 591 for oOld in oOldData.aoTestBoxes: 592 if oOld.idTestBox == oBoxInGrp.idTestBox: 593 oOldBoxInGrp = oOld; 594 break; 595 596 oBoxInGrp.idSchedGroup = oData.idSchedGroup; 597 if oOldBoxInGrp is None: 598 self._addSchedGroupTestBox(uidAuthor, oBoxInGrp); 599 elif not oBoxInGrp.isEqualEx(oOldBoxInGrp, ['tsEffective', 'tsExpire', 'uidAuthor', 'oTestBox']): 600 self._historizeSchedGroupTestBox(oBoxInGrp); 601 self._addSchedGroupTestBox(uidAuthor, oBoxInGrp); 602 555 603 self._oDb.maybeCommit(fCommit); 556 604 return True; … … 560 608 Deletes a scheduling group. 561 609 """ 610 _ = fCascade; 562 611 563 612 # … … 569 618 570 619 # 571 # We use cascade a little different here... We don't actually delete 572 # associated testboxes or testgroups. 573 # 574 if oData.aoTestBoxes: 575 if fCascade is not True: 576 # Complain about there being associated testboxes. 577 asTestBoxes = ['%s (#%d)' % (oTestBox.sName, oTestBox.idTestBox) for oTestBox in oData.aoTestBoxes]; 578 raise TMRowInUse('Scheduling group #%d is associated with one or more test boxes: %s' 579 % (idSchedGroup, ', '.join(asTestBoxes),)); 580 # Reassign testboxes to scheduling group #1 (the default group). 581 oTbLogic = TestBoxLogic(self._oDb); 582 for oTestBox in oData.aoTestBoxes: 583 oTbCopy = TestBoxData().initFromOther(oTestBox); 584 oTbCopy.idSchedGroup = 1; 585 oTbLogic.editEntry(oTbCopy, uidAuthor, fCommit = False); 586 587 oData = SchedGroupDataEx().initFromDbWithId(self._oDb, idSchedGroup); 588 if oData.aoTestBoxes: 589 raise TMRowInUse('More testboxes was added to the scheduling group as we were trying to delete it.'); 590 591 # 592 # Remove the group and all member records. 620 # Remove the test box member records. 621 # 622 for oBoxInGrp in oData.aoTestBoxes: 623 self._removeSchedGroupTestBox(uidAuthor, oBoxInGrp); 624 self._oDb.execute('UPDATE TestBoxesInSchedGroups\n' 625 'SET tsExpire = CURRENT_TIMESTAMP\n' 626 'WHERE idSchedGroup = %s\n' 627 ' AND tsExpire = \'infinity\'::TIMESTAMP\n' 628 , (idSchedGroup,)); 629 630 # 631 # Remove the test group member records. 593 632 # 594 633 for oMember in oData.aoMembers: … … 600 639 , (idSchedGroup,)); 601 640 641 # 642 # Now the SchedGroups entry. 643 # 602 644 (tsCur, tsCurMinusOne) = self._oDb.getCurrentTimestamps(); 603 645 if oData.tsEffective != tsCur and oData.tsEffective != tsCurMinusOne: … … 974 1016 return True; 975 1017 1018 # 1019 def _addSchedGroupTestBox(self, uidAuthor, oBoxInGroup, tsEffective = None): 1020 """ 1021 addEntry worker for adding a test box to a scheduling group. 1022 """ 1023 if tsEffective is None: 1024 tsEffective = self._oDb.getCurrentTimestamp(); 1025 self._oDb.execute('INSERT INTO TestBoxesInSchedGroups(\n' 1026 ' idSchedGroup,\n' 1027 ' idTestBox,\n' 1028 ' tsEffective,\n' 1029 ' uidAuthor,\n' 1030 ' iSchedPriority)\n' 1031 'VALUES (%s, %s, %s, %s, %s)\n' 1032 , ( oBoxInGroup.idSchedGroup, 1033 oBoxInGroup.idTestBox, 1034 tsEffective, 1035 uidAuthor, 1036 oBoxInGroup.iSchedPriority, )); 1037 return True; 1038 1039 def _removeSchedGroupTestBox(self, uidAuthor, oBoxInGroup): 1040 """ 1041 Removes a testbox from a scheduling group. 1042 """ 1043 1044 # Try record who removed it by adding an dummy entry that expires immediately. 1045 (tsCur, tsCurMinusOne) = self._oDb.getCurrentTimestamps(); 1046 if oBoxInGroup.tsEffective != tsCur and oBoxInGroup.tsEffective != tsCurMinusOne: 1047 self._historizeSchedGroupTestBox(oBoxInGroup, tsCurMinusOne); 1048 self._addSchedGroupTestBox(uidAuthor, oBoxInGroup, tsCurMinusOne); # lazy bird. 1049 self._historizeSchedGroupTestBox(oBoxInGroup); 1050 else: 1051 self._historizeSchedGroupTestBox(oBoxInGroup); 1052 return True; 1053 1054 def _historizeSchedGroupTestBox(self, oBoxInGroup, tsExpire = None): 1055 """ 1056 Historizes the current entry for the given scheduling group. 1057 """ 1058 if tsExpire is None: 1059 tsExpire = self._oDb.getCurrentTimestamp(); 1060 self._oDb.execute('UPDATE TestBoxesInSchedGroups\n' 1061 'SET tsExpire = %s\n' 1062 'WHERE idSchedGroup = %s\n' 1063 ' AND idTestBox = %s\n' 1064 ' AND tsExpire = \'infinity\'::TIMESTAMP\n' 1065 , ( tsExpire, oBoxInGroup.idSchedGroup, oBoxInGroup.idTestBox, )); 1066 return True; 976 1067 977 1068 -
trunk/src/VBox/ValidationKit/testmanager/core/schedqueue.py
r83343 r83364 46 46 ModelDataBase.__init__(self) 47 47 48 self.idItem = None 49 self.tsLastScheduled = None 50 self.sSchedGroup = None 51 self.sTestGroup = None 52 self.sTestCase = None 53 self.fUpToDate = None 48 self.idItem = None 49 self.tsLastScheduled = None 50 self.sSchedGroup = None 51 self.sTestGroup = None 52 self.sTestCase = None 53 self.fUpToDate = None 54 self.iPerSchedGroupRowNumber = None; 54 55 55 56 def initFromDbRow(self, aoRow): … … 61 62 raise TMExceptionBase('TestCaseQueue row not found.') 62 63 63 self.idItem = aoRow[0] 64 self.tsLastScheduled = aoRow[1] 65 self.sSchedGroup = aoRow[2] 66 self.sTestGroup = aoRow[3] 67 self.sTestCase = aoRow[4] 68 self.fUpToDate = aoRow[5] 64 self.idItem = aoRow[0] 65 self.tsLastScheduled = aoRow[1] 66 self.sSchedGroup = aoRow[2] 67 self.sTestGroup = aoRow[3] 68 self.sTestCase = aoRow[4] 69 self.fUpToDate = aoRow[5] 70 self.iPerSchedGroupRowNumber = aoRow[6]; 69 71 return self 70 72 -
trunk/src/VBox/ValidationKit/testmanager/core/testbox.py
r82968 r83364 109 109 self.oSchedGroup = SchedGroupData().initFromDbWithId(oDb, self.idSchedGroup, tsNow, sPeriodBack); 110 110 return self; 111 112 class TestBoxDataForSchedGroup(TestBoxInSchedGroupData): 113 """ 114 Extended version of TestBoxInSchedGroupData that adds the testbox data (if available). 115 Used by TestBoxLogic.fetchForSchedGroup 116 """ 117 118 def __init__(self): 119 TestBoxInSchedGroupData.__init__(self); 120 self.oTestBox = None # type: TestBoxData 121 122 def initFromDbRow(self, aoRow): 123 """ 124 The row is: TestBoxesInSchedGroups.*, TestBoxesWithStrings.* 125 """ 126 TestBoxInSchedGroupData.initFromDbRow(self, aoRow); 127 if aoRow[self.kcDbColumns]: 128 self.oTestBox = TestBoxData().initFromDbRow(aoRow[self.kcDbColumns:]); 129 else: 130 self.oTestBox = None; 131 return self; 132 133 def getDataAttributes(self): 134 asAttributes = TestBoxInSchedGroupData.getDataAttributes(self); 135 asAttributes.remove('oTestBox'); 136 return asAttributes; 137 138 def _validateAndConvertWorker(self, asAllowNullAttributes, oDb, enmValidateFor = ModelDataBase.ksValidateFor_Other): 139 dErrors = TestBoxInSchedGroupData._validateAndConvertWorker(self, asAllowNullAttributes, oDb, enmValidateFor); 140 if self.ksParam_idTestBox not in dErrors: 141 self.oTestBox = TestBoxData(); 142 try: 143 self.oTestBox.initFromDbWithId(oDb, self.idTestBox); 144 except Exception as oXcpt: 145 self.oTestBox = TestBoxData() 146 dErrors[self.ksParam_idTestBox] = str(oXcpt); 147 return dErrors; 111 148 112 149 … … 811 848 return aoRows; 812 849 850 def fetchForSchedGroup(self, idSchedGroup, tsNow, aiSortColumns = None): 851 """ 852 Fetches testboxes for listing. 853 854 Returns an array (list) of TestBoxDataForSchedGroup items, empty list if none. 855 856 Raises exception on error. 857 """ 858 if not aiSortColumns: 859 aiSortColumns = [self.kiSortColumn_sName,]; 860 861 if tsNow is None: 862 self._oDb.execute(''' 863 SELECT TestBoxesInSchedGroups.*, 864 TestBoxesWithStrings.* 865 FROM TestBoxesInSchedGroups 866 LEFT OUTER JOIN TestBoxesWithStrings 867 ON TestBoxesWithStrings.idTestBox = TestBoxesInSchedGroups.idTestBox 868 AND TestBoxesWithStrings.tsExpire = 'infinity'::TIMESTAMP 869 WHERE TestBoxesInSchedGroups.idSchedGroup = %s 870 AND TestBoxesInSchedGroups.tsExpire = 'infinity'::TIMESTAMP 871 ORDER BY ''' + ', '.join([self.kdSortColumnMap[i] for i in aiSortColumns]) + ''' 872 ''', (idSchedGroup, )); 873 else: 874 self._oDb.execute(''' 875 SELECT TestBoxesInSchedGroups.*, 876 TestBoxesWithStrings.* 877 FROM TestBoxesInSchedGroups 878 LEFT OUTER JOIN TestBoxesWithStrings 879 ON TestBoxesWithStrings.idTestBox = TestBoxesInSchedGroups.idTestBox 880 AND TestBoxesWithStrings.tsExpire > %s 881 AND TestBoxesWithStrings.tsEffective <= %s 882 WHERE TestBoxesInSchedGroups.idSchedGroup = %s 883 AND TestBoxesInSchedGroups.tsExpire > % 884 AND TestBoxesInSchedGroups.tsEffective <= % 885 ORDER BY ''' + ', '.join([self.kdSortColumnMap[i] for i in aiSortColumns]) + ''' 886 ''', (tsNow, tsNow, idSchedGroup, tsNow, tsNow, )); 887 888 aoRows = []; 889 for aoOne in self._oDb.fetchAll(): 890 aoRows.append(TestBoxDataForSchedGroup().initFromDbRow(aoOne)); 891 return aoRows; 892 813 893 def fetchForChangeLog(self, idTestBox, iStart, cMaxRows, tsNow): # pylint: disable=too-many-locals 814 894 """ … … 1063 1143 self._oDb.execute('SELECT *\n' 1064 1144 'FROM TestBoxesWithStrings\n' 1065 'WHERE tsExpire=\'infinity\'::timestamp;') 1145 'WHERE tsExpire=\'infinity\'::timestamp\n' 1146 'ORDER BY sName') 1066 1147 1067 1148 aaoRows = self._oDb.fetchAll()
Note:
See TracChangeset
for help on using the changeset viewer.