Beispiel #1
0
 def convertFromParamNull(self):
     raise TMExceptionBase('Not implemented')
Beispiel #2
0
    def createFile(self,
                   oTestSet,
                   sName,
                   sMime,
                   sKind,
                   sDesc,
                   cbFile,
                   fCommit=False):  # pylint: disable=R0914
        """
        Creates a file and associating with the current test result record in
        the test set.

        Returns file object that the file content can be written to.
        Raises exception on database error, I/O errors, if there are too many
        files in the test set or if they take up too much disk space.

        The caller (testboxdisp.py) is expected to do basic input validation,
        so we skip that and get on with the bits only we can do.
        """

        #
        # Furhter input and limit checks.
        #
        if oTestSet.enmStatus != TestSetData.ksTestStatus_Running:
            raise TMExceptionBase(
                'Cannot create files on a test set with status "%s".' %
                (oTestSet.enmStatus, ))

        self._oDb.execute(
            'SELECT   TestResultStrTab.sValue\n'
            'FROM     TestResultFiles,\n'
            '         TestResults,\n'
            '         TestResultStrTab\n'
            'WHERE    TestResults.idTestSet        = %s\n'
            '     AND TestResultFiles.idTestResult = TestResults.idTestResult\n'
            '     AND TestResultStrTab.idStr       = TestResultFiles.idStrFile\n',
            (oTestSet.idTestSet, ))
        if self._oDb.getRowCount() + 1 > config.g_kcMaxUploads:
            raise TMExceptionBase('Uploaded too many files already (%d).' %
                                  (self._oDb.getRowCount(), ))

        dFiles = {}
        cbTotalFiles = 0
        for aoRow in self._oDb.fetchAll():
            dFiles[aoRow[0].lower()] = 1
            # For determining a unique filename further down.
            sFile = os.path.join(config.g_ksFileAreaRootDir,
                                 oTestSet.sBaseFilename + '-' + aoRow[0])
            try:
                cbTotalFiles += os.path.getsize(sFile)
            except:
                cbTotalFiles += config.g_kcMbMaxUploadSingle * 1048576
        if (cbTotalFiles + cbFile +
                1048575) / 1048576 > config.g_kcMbMaxUploadTotal:
            raise TMExceptionBase('Will exceed total upload limit: %u bytes + %u bytes > %s MiB.' \
                                  % (cbTotalFiles, cbFile, config.g_kcMbMaxUploadTotal))

        #
        # Create a new file.
        #
        self._oDb.execute('SELECT   idTestResult\n'
                          'FROM     TestResults\n'
                          'WHERE    idTestSet = %s\n'
                          '     AND enmStatus = \'running\'::TestStatus_T\n'
                          'ORDER BY idTestResult DESC\n'
                          'LIMIT    1\n' % (oTestSet.idTestSet, ))
        if self._oDb.getRowCount() < 1:
            raise TMExceptionBase(
                'No open test results - someone committed a capital offence or we ran into a race.'
            )
        idTestResult = self._oDb.fetchOne()[0]

        if sName.lower() in dFiles:
            # Note! There is in theory a race here, but that's something the
            #       test driver doing parallel upload with non-unique names
            #       should worry about. The TD should always avoid this path.
            sOrgName = sName
            for i in range(2, config.g_kcMaxUploads + 6):
                sName = '%s-%s' % (
                    i,
                    sName,
                )
                if sName not in dFiles:
                    break
                sName = None
            if sName is None:
                raise TMExceptionBase('Failed to find unique name for %s.' %
                                      (sOrgName, ))

        self._oDb.execute(
            'INSERT INTO TestResultFiles(idTestResult, idTestSet, idStrFile, idStrDescription,\n'
            '                            idStrKind, idStrMime)\n'
            'VALUES (%s, %s, %s, %s, %s, %s)\n', (
                idTestResult,
                oTestSet.idTestSet,
                self.strTabString(sName),
                self.strTabString(sDesc),
                self.strTabString(sKind),
                self.strTabString(sMime),
            ))

        oFile = oTestSet.createFile(sName, 'wb')
        if utils.isString(oFile):
            raise TMExceptionBase('Error creating "%s": %s' % (sName, oFile))
        self._oDb.maybeCommit(fCommit)
        return oFile
Beispiel #3
0
    def __init__(
            self,
            oDb,
            tsNow,
            cPeriods,
            cHoursPerPeriod,
            sSubject,
            aidSubjects,  # pylint: disable=R0913
            aidTestBoxes,
            aidBuildCats,
            aidTestCases,
            fSepTestVars):
        assert (sSubject == self.ksSubEverything)
        # dummy
        ReportModelBase.__init__(self, oDb, tsNow, cPeriods, cHoursPerPeriod,
                                 sSubject, aidSubjects)
        self.aidTestBoxes = aidTestBoxes
        self.aidBuildCats = aidBuildCats
        self.aidTestCases = aidTestCases
        self.fOnTestCase = not fSepTestVars
        # (Separates testcase variations into separate data series.)
        self.oCache = DatabaseObjCache(self._oDb, self.tsNow, None,
                                       self.cPeriods * self.cHoursPerPeriod)

        # Quickly validate and convert the subject "IDs".
        self.aoLookups = []
        for sCur in self.aidSubjects:
            asParts = sCur.split(':')
            if len(asParts) < 2:
                raise TMExceptionBase('Invalid graph value "%s"' % (sCur, ))

            sType = asParts[0]
            if sType not in ReportGraphModel.kasTypes:
                raise TMExceptionBase(
                    'Invalid graph value type "%s" (full: "%s")' % (
                        sType,
                        sCur,
                    ))

            aidStrTests = []
            for sIdStr in asParts[1:]:
                try:
                    idStr = int(sIdStr)
                except:
                    raise TMExceptionBase(
                        'Invalid graph value id "%s" (full: "%s")' % (
                            sIdStr,
                            sCur,
                        ))
                if idStr < 0:
                    raise TMExceptionBase(
                        'Invalid graph value id "%u" (full: "%s")' % (
                            idStr,
                            sCur,
                        ))
                aidStrTests.append(idStr)

            idStrValue = None
            if sType == ReportGraphModel.ksTypeValue:
                idStrValue = aidStrTests.pop()
            self.aoLookups.append(
                ReportGraphModel.SampleSource(sType, aidStrTests, idStrValue))
 def isEqual(self, oOther):
     raise TMExceptionBase('Not implemented')
Beispiel #5
0
    def complete(self, idTestSet, sStatus, fCommit=False):
        """
        Completes the testset.
        Returns the test set ID of the gang leader, None if no gang involvement.
        Raises exceptions on database errors and invalid input.
        """

        assert sStatus != TestSetData.ksTestStatus_Running

        #
        # Get the basic test set data and check if there is anything to do here.
        #
        oData = TestSetData().initFromDbWithId(self._oDb, idTestSet)
        if oData.enmStatus != TestSetData.ksTestStatus_Running:
            raise TMExceptionBase('TestSet %s is already completed as %s.' %
                                  (idTestSet, oData.enmStatus))
        if oData.idTestResult is None:
            raise self._oDb.integrityException(
                'idTestResult is NULL for TestSet %u' % (idTestSet, ))

        #
        # Close open sub test results, count these as errors.
        # Note! No need to propagate error counts here. Only one tree line will
        #       have open sets, and it will go all the way to the root.
        #
        self._oDb.execute(
            'SELECT idTestResult\n'
            'FROM   TestResults\n'
            'WHERE  idTestSet     = %s\n'
            '   AND enmStatus     = %s\n'
            '   AND idTestResult <> %s\n'
            'ORDER BY idTestResult DESC\n',
            (idTestSet, TestSetData.ksTestStatus_Running, oData.idTestResult))
        aaoRows = self._oDb.fetchAll()
        if aaoRows:
            idStr = self.strTabString('Unclosed test result', fCommit=fCommit)
            for aoRow in aaoRows:
                self._oDb.execute(
                    'UPDATE   TestResults\n'
                    'SET      enmStatus = \'failure\',\n'
                    '         tsElapsed = CURRENT_TIMESTAMP - tsCreated,\n'
                    '         cErrors   = cErrors + 1\n'
                    'WHERE    idTestResult = %s\n', (aoRow[0], ))
                self._oDb.execute(
                    'INSERT INTO TestResultMsgs (idTestResult, idTestSet, idStrMsg, enmLevel)\n'
                    'VALUES ( %s, %s, %s, \'failure\'::TestResultMsgLevel_T)\n',
                    (
                        aoRow[0],
                        idTestSet,
                        idStr,
                    ))

        #
        # If it's a success result, check it against error counters.
        #
        if sStatus not in TestSetData.kasBadTestStatuses:
            self._oDb.execute(
                'SELECT COUNT(*)\n'
                'FROM   TestResults\n'
                'WHERE  idTestSet = %s\n'
                '   AND cErrors > 0\n', (idTestSet, ))
            cErrors = self._oDb.fetchOne()[0]
            if cErrors > 0:
                sStatus = TestSetData.ksTestStatus_Failure

        #
        # If it's an pure 'failure', check for timeouts and propagate it.
        #
        if sStatus == TestSetData.ksTestStatus_Failure:
            self._oDb.execute(
                'SELECT COUNT(*)\n'
                'FROM   TestResults\n'
                'WHERE  idTestSet = %s\n'
                '   AND enmStatus = %s\n', (
                    idTestSet,
                    TestSetData.ksTestStatus_TimedOut,
                ))
            if self._oDb.fetchOne()[0] > 0:
                sStatus = TestSetData.ksTestStatus_TimedOut

        #
        # Complete the top level test result and then the test set.
        #
        self._oDb.execute(
            'UPDATE   TestResults\n'
            'SET      cErrors = (SELECT COALESCE(SUM(cErrors), 0)\n'
            '                    FROM   TestResults\n'
            '                    WHERE idTestResultParent = %s)\n'
            'WHERE    idTestResult = %s\n'
            'RETURNING cErrors\n', (oData.idTestResult, oData.idTestResult))
        cErrors = self._oDb.fetchOne()[0]
        if cErrors == 0 and sStatus in TestSetData.kasBadTestStatuses:
            self._oDb.execute(
                'UPDATE   TestResults\n'
                'SET      cErrors = 1\n'
                'WHERE    idTestResult = %s\n', (oData.idTestResult, ))
        elif cErrors > 0 and sStatus not in TestSetData.kasBadTestStatuses:
            sStatus = TestSetData.ksTestStatus_Failure
            # Impossible.
        self._oDb.execute(
            'UPDATE   TestResults\n'
            'SET      enmStatus = %s,\n'
            '         tsElapsed = CURRENT_TIMESTAMP - tsCreated\n'
            'WHERE    idTestResult = %s\n', (
                sStatus,
                oData.idTestResult,
            ))

        self._oDb.execute(
            'UPDATE   TestSets\n'
            'SET      enmStatus = %s,\n'
            '         tsDone    = CURRENT_TIMESTAMP\n'
            'WHERE    idTestSet = %s\n', (
                sStatus,
                idTestSet,
            ))

        self._oDb.maybeCommit(fCommit)
        return oData.idTestSetGangLeader
Beispiel #6
0
 def initFromDbWithId(self, oDb, idTestCaseArgs, tsNow = None, sPeriodBack = None):
     _ = oDb; _ = idTestCaseArgs; _ = tsNow; _ = sPeriodBack;
     raise TMExceptionBase('Not supported.');
Beispiel #7
0
 def initFromDbWithGenId(self, oDb, idGenTestCaseArgs):
     _ = oDb; _ = idGenTestCaseArgs;
     raise TMExceptionBase('Use initFromDbWithGenIdEx...');
    def editEntry(self, oData, uidAuthor, fCommit=False):
        """
        Data edit update, web UI is the primary user.
        Returns the new generation ID and effective date.
        """

        dDataErrors = oData.validateAndConvert(self._oDb)
        if len(dDataErrors) > 0:
            raise TMExceptionBase('Invalid data passed to create(): %s' %
                                  (dDataErrors, ))

        ## @todo check if the data changed.

        self._oDb.execute(
            'UPDATE ONLY TestBoxes\n'
            'SET      tsExpire = CURRENT_TIMESTAMP\n'
            'WHERE    idGenTestBox = %s\n'
            '     AND tsExpire = \'infinity\'::timestamp\n'
            'RETURNING tsExpire\n', (oData.idGenTestBox, ))
        try:
            tsEffective = self._oDb.fetchOne()[0]

            # Would be easier to do this using an insert or update hook, I think. Much easier.
            self._oDb.execute(
                'INSERT INTO TestBoxes (\n'
                '         idGenTestBox,\n'
                '         idTestBox,\n'
                '         tsEffective,\n'
                '         uidAuthor,\n'
                '         ip,\n'
                '         uuidSystem,\n'
                '         sName,\n'
                '         sDescription,\n'
                '         idSchedGroup,\n'
                '         fEnabled,\n'
                '         enmLomKind,\n'
                '         ipLom,\n'
                '         pctScaleTimeout,\n'
                '         sOs,\n'
                '         sOsVersion,\n'
                '         sCpuVendor,\n'
                '         sCpuArch,\n'
                '         sCpuName,\n'
                '         lCpuRevision,\n'
                '         cCpus,\n'
                '         fCpuHwVirt,\n'
                '         fCpuNestedPaging,\n'
                '         fCpu64BitGuest,\n'
                '         fChipsetIoMmu,\n'
                '         cMbMemory,\n'
                '         cMbScratch,\n'
                '         iTestBoxScriptRev,\n'
                '         iPythonHexVersion,\n'
                '         enmPendingCmd\n'
                '         )\n'
                'SELECT   NEXTVAL(\'TestBoxGenIdSeq\'),\n'
                '         idTestBox,\n'
                '         %s,\n'  # tsEffective
                '         %s,\n'  # uidAuthor
                '         %s,\n'  # ip
                '         %s,\n'  # uuidSystem
                '         %s,\n'  # sName
                '         %s,\n'  # sDescription
                '         %s,\n'  # idSchedGroup
                '         %s,\n'  # fEnabled
                '         %s,\n'  # enmLomKind
                '         %s,\n'  # ipLom
                '         %s,\n'  # pctScaleTimeout
                '         sOs,\n'
                '         sOsVersion,\n'
                '         sCpuVendor,\n'
                '         sCpuArch,\n'
                '         sCpuName,\n'
                '         lCpuRevision,\n'
                '         cCpus,\n'
                '         fCpuHwVirt,\n'
                '         fCpuNestedPaging,\n'
                '         fCpu64BitGuest,\n'
                '         fChipsetIoMmu,\n'
                '         cMbMemory,\n'
                '         cMbScratch,\n'
                '         iTestBoxScriptRev,\n'
                '         iPythonHexVersion,\n'
                '         %s\n'  # enmPendingCmd
                'FROM     TestBoxes\n'
                'WHERE    idGenTestBox = %s\n'
                'RETURNING idGenTestBox, tsEffective',
                (
                    tsEffective,
                    uidAuthor,
                    oData.ip,
                    oData.uuidSystem,
                    oData.sName,
                    oData.sDescription,
                    oData.idSchedGroup,
                    oData.fEnabled,
                    oData.enmLomKind,
                    oData.ipLom,
                    oData.pctScaleTimeout,
                    oData.enmPendingCmd,
                    oData.idGenTestBox,
                ))
            aRow = self._oDb.fetchOne()
            if aRow is None:
                raise TMExceptionBase('Insert failed? oRow=None')
            idGenTestBox = aRow[0]
            tsEffective = aRow[1]
            self._oDb.maybeCommit(fCommit)
        except:
            self._oDb.rollback()
            raise

        return (idGenTestBox, tsEffective)
Beispiel #9
0
 def initFromDbRow(self, aoRow):
     raise TMExceptionBase('Do not call me: %s' % (aoRow,))
    def addEntry(self, oData, uidAuthor, fCommit=False):
        """
        Creates a testbox in the database.
        Returns the testbox ID, testbox generation ID and effective timestamp
        of the created testbox on success.  Throws error on failure.
        """
        dDataErrors = oData.validateAndConvert(self._oDb)
        if len(dDataErrors) > 0:
            raise TMExceptionBase('Invalid data passed to create(): %s' %
                                  (dDataErrors, ))

        self._oDb.execute(
            'INSERT INTO TestBoxes (\n'
            '         idTestBox,\n'
            '         tsEffective,\n'
            '         tsExpire,\n'
            '         uidAuthor,\n'
            '         idGenTestBox,\n'
            '         ip,\n'
            '         uuidSystem,\n'
            '         sName,\n'
            '         sDescription,\n'
            '         idSchedGroup,\n'
            '         fEnabled,\n'
            '         enmLomKind,\n'
            '         ipLom,\n'
            '         pctScaleTimeout,\n'
            '         sOs,\n'
            '         sOsVersion,\n'
            '         sCpuVendor,\n'
            '         sCpuArch,\n'
            '         sCpuName,\n'
            '         lCpuRevision,\n'
            '         cCpus,\n'
            '         fCpuHwVirt,\n'
            '         fCpuNestedPaging,\n'
            '         fCpu64BitGuest,\n'
            '         fChipsetIoMmu,\n'
            '         cMbMemory,\n'
            '         cMbScratch,\n'
            '         sReport,\n'
            '         iTestBoxScriptRev,\n'
            '         iPythonHexVersion,\n'
            '         enmPendingCmd\n'
            '         )'
            'VALUES (\n'
            '         DEFAULT,\n'
            '         CURRENT_TIMESTAMP,\n'
            '         DEFAULT,\n'
            '         %s,\n'  # uidAuthor
            '         DEFAULT,\n'
            '         %s,\n'  # ip
            '         %s,\n'  # uuidSystem
            '         %s,\n'  # sName
            '         %s,\n'  # sDescription
            '         %s,\n'  # idSchedGroup
            '         %s,\n'  # fEnabled
            '         %s,\n'  # enmLomKind
            '         %s,\n'  # ipLom
            '         %s,\n'  # pctScaleTimeout
            '         %s,\n'  # sOs
            '         %s,\n'  # sOsVersion
            '         %s,\n'  # sCpuVendor
            '         %s,\n'  # sCpuArch
            '         %s,\n'  # sCpuName
            '         %s,\n'  # lCpuRevision
            '         %s,\n'  # cCpus
            '         %s,\n'  # fCpuHwVirt
            '         %s,\n'  # fCpuNestedPaging
            '         %s,\n'  # fCpu64BitGuest
            '         %s,\n'  # fChipsetIoMmu
            '         %s,\n'  # cMbMemory
            '         %s,\n'  # cMbScratch
            '         %s,\n'  # sReport
            '         %s,\n'  # iTestBoxScriptRev
            '         %s,\n'  # iPythonHexVersion
            '         %s\n'  # enmPendingCmd
            '         )\n'
            'RETURNING idTestBox, idGenTestBox, tsEffective',
            (uidAuthor, oData.ip, oData.uuidSystem, oData.sName,
             oData.sDescription, oData.idSchedGroup, oData.fEnabled,
             oData.enmLomKind, oData.ipLom, oData.pctScaleTimeout, oData.sOs,
             oData.sOsVersion, oData.sCpuVendor, oData.sCpuArch,
             oData.sCpuName, oData.lCpuRevision, oData.cCpus, oData.fCpuHwVirt,
             oData.fCpuNestedPaging, oData.fCpu64BitGuest, oData.fChipsetIoMmu,
             oData.cMbMemory, oData.cMbScratch, oData.sReport,
             oData.iTestBoxScriptRev, oData.iPythonHexVersion,
             oData.enmPendingCmd))
        oRow = self._oDb.fetchOne()
        self._oDb.maybeCommit(fCommit)
        return (oRow[0], oRow[1], oRow[2])
Beispiel #11
0
    def removeEntry(self,
                    uidAuthor,
                    idSchedGroup,
                    fCascade=False,
                    fCommit=False):
        """
        Deletes a scheduling group.
        """

        #
        # Input validation and retrival of current data.
        #
        if idSchedGroup == 1:
            raise TMExceptionBase(
                'Cannot remove the default scheduling group (id 1).')
        oData = SchedGroupDataEx().initFromDbWithId(self._oDb, idSchedGroup)

        #
        # We use cascade a little different here... We don't actually delete
        # associated testboxes or testgroups.
        #
        if len(oData.aoTestBoxes) > 0:
            if fCascade is not True:
                # Complain about there being associated testboxes.
                asTestBoxes = [
                    '%s (#%d)' % (oTestBox.sName, oTestBox.idTestBox)
                    for oTestBox in oData.aoTestBoxes
                ]
                raise TMExceptionBase(
                    'Scheduling group #%d is associated with one or more test boxes: %s'
                    % (
                        idSchedGroup,
                        ', '.join(asTestBoxes),
                    ))
            else:
                # Reassign testboxes to scheduling group #1 (the default group).
                oTbLogic = TestBoxLogic(self._oDb)
                for oTestBox in oData.aoTestBoxes:
                    oTbCopy = TestBoxData().initFromOther(oTestBox)
                    oTbCopy.idSchedGroup = 1
                    oTbLogic.editEntry(oTbCopy, uidAuthor, fCommit=False)

                oData = SchedGroupDataEx().initFromDbWithId(
                    self._oDb, idSchedGroup)
                if len(oData.aoTestBoxes) != 0:
                    raise TMExceptionBase(
                        'More testboxes was added to the scheduling group as we were trying to delete it.'
                    )

        #
        # Remove the group and all member records.
        #
        for oMember in oData.aoMembers:
            self._removeSchedGroupMember(uidAuthor, oMember)
        self._oDb.execute(
            'UPDATE   SchedGroupMembers\n'
            'SET      tsExpire     = CURRENT_TIMESTAMP\n'
            'WHERE    idSchedGroup = %s\n'
            '     AND tsExpire     = \'infinity\'::TIMESTAMP\n',
            (idSchedGroup, ))

        (tsCur, tsCurMinusOne) = self._oDb.getCurrentTimestamps()
        if oData.tsEffective != tsCur and oData.tsEffective != tsCurMinusOne:
            self._historizeEntry(idSchedGroup, tsCurMinusOne)
            self._readdEntry(uidAuthor, oData, tsCurMinusOne)
            self._historizeEntry(idSchedGroup)
        self._oDb.execute(
            'UPDATE   SchedGroups\n'
            'SET      tsExpire     = CURRENT_TIMESTAMP\n'
            'WHERE    idSchedGroup = %s\n'
            '     AND tsExpire     = \'infinity\'::TIMESTAMP\n',
            (idSchedGroup, ))

        self._oDb.maybeCommit(fCommit)
        return True
Beispiel #12
0
 def __init__(self, sMsg, iStatus):
     TMExceptionBase.__init__(self, sMsg)
     self.iStatus = iStatus
Beispiel #13
0
    def removeEntry(self,
                    uidAuthor,
                    idTestGroup,
                    fCascade=False,
                    fCommit=False):
        """
        Deletes a test group.
        """
        _ = uidAuthor
        ## @todo record uidAuthor.

        #
        # Cascade.
        #
        if fCascade is not True:
            self._oDb.execute(
                'SELECT   SchedGroups.idSchedGroup, SchedGroups.sName\n'
                'FROM     SchedGroupMembers, SchedGroups\n'
                'WHERE    SchedGroupMembers.idTestGroup = %s\n'
                '     AND SchedGroupMembers.tsExpire    = \'infinity\'::TIMESTAMP\n'
                '     AND SchedGroups.idSchedGroup      = SchedGroupMembers.idSchedGroup\n'
                '     AND SchedGroups.tsExpire          = \'infinity\'::TIMESTAMP\n',
                (idTestGroup, ))
            aoGroups = self._oDb.fetchAll()
            if len(aoGroups) > 0:
                asGroups = [
                    '%s (#%d)' % (sName, idSchedGroup)
                    for idSchedGroup, sName in aoGroups
                ]
                raise TMExceptionBase(
                    'Test group #%d is member of one ore more scheduling groups: %s'
                    % (
                        idTestGroup,
                        ', '.join(asGroups),
                    ))
        else:
            self._oDb.execute(
                'UPDATE   SchedGroupMembers\n'
                'SET      tsExpire = CURRENT_TIMESTAMP\n'
                'WHERE    idTestGroup = %s\n'
                '     AND tsExpire = \'infinity\'::TIMESTAMP\n',
                (idTestGroup, ))

        #
        # Remove the group.
        #
        self._oDb.execute(
            'UPDATE   TestGroupMembers\n'
            'SET      tsExpire    = CURRENT_TIMESTAMP\n'
            'WHERE    idTestGroup = %s\n'
            '     AND tsExpire    = \'infinity\'::TIMESTAMP\n',
            (idTestGroup, ))
        self._oDb.execute(
            'UPDATE   TestGroups\n'
            'SET      tsExpire    = CURRENT_TIMESTAMP\n'
            'WHERE    idTestGroup = %s\n'
            '     AND tsExpire    = \'infinity\'::TIMESTAMP\n',
            (idTestGroup, ))

        self._oDb.maybeCommit(fCommit)
        return True
Beispiel #14
0
    def editEntry(self, oData, uidAuthor, fCommit=False):
        """
        Modifies a test group.
        """

        #
        # Validate inputs and read in the old(/current) data.
        #
        assert isinstance(oData, TestGroupDataEx)
        dErrors = oData.validateAndConvert(self._oDb)
        if len(dErrors) > 0:
            raise TMExceptionBase('editEntry invalid input: %s' % (dErrors, ))
        self._assertUniq(oData, oData.idTestGroup)

        oOldData = TestGroupDataEx().initFromDbWithId(self._oDb,
                                                      oData.idTestGroup)

        #
        # Update the data that needs updating.
        #

        if not oData.isEqualEx(oOldData, [
                'aoMembers',
                'tsEffective',
                'tsExpire',
                'uidAuthor',
        ]):
            self._historizeTestGroup(oData.idTestGroup)
            self._oDb.execute(
                'INSERT INTO TestGroups\n'
                '       (uidAuthor, idTestGroup, sName, sDescription)\n'
                'VALUES (%s, %s, %s, %s)\n', (
                    uidAuthor,
                    oData.idTestGroup,
                    oData.sName,
                    oData.sDescription,
                ))

        # Create a lookup dictionary for old entries.
        dOld = {}
        for oOld in oOldData.aoMembers:
            dOld[oOld.idTestCase] = oOld
        assert len(dOld) == len(oOldData.aoMembers)

        # Add new members, updated existing ones.
        dNew = {}
        for oNewMember in oData.aoMembers:
            oNewMember.idTestGroup = oData.idTestGroup
            if oNewMember.idTestCase in dNew:
                raise TMExceptionBase(
                    'Duplicate test group member: idTestCase=%d (%s / %s)' % (
                        oNewMember.idTestCase,
                        oNewMember,
                        dNew[oNewMember.idTestCase],
                    ))
            dNew[oNewMember.idTestCase] = oNewMember

            oOldMember = dOld.get(oNewMember.idTestCase, None)
            if oOldMember is not None:
                if oNewMember.isEqualEx(
                        oOldMember, ['uidAuthor', 'tsEffective', 'tsExpire']):
                    continue
                    # Skip, nothing changed.
                self._historizeTestGroupMember(oData.idTestGroup,
                                               oNewMember.idTestCase)
            self._insertTestGroupMember(uidAuthor, oNewMember)

        # Expire members that have been removed.
        sQuery = self._oDb.formatBindArgs(
            'UPDATE TestGroupMembers\n'
            'SET    tsExpire    = CURRENT_TIMESTAMP\n'
            'WHERE  idTestGroup = %s\n'
            '   AND tsExpire    = \'infinity\'::TIMESTAMP\n',
            (oData.idTestGroup, ))
        if len(dNew) > 0:
            sQuery += '   AND idTestCase NOT IN (%s)' % (', '.join(
                [str(iKey) for iKey in dNew.keys()]), )
        self._oDb.execute(sQuery)

        self._oDb.maybeCommit(fCommit)
        return True