cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# -*- coding: utf-8 -*-
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncTest Manager - Build Sources.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCopyright (C) 2012-2014 Oracle Corporation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThis file is part of VirtualBox Open Source Edition (OSE), as
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncavailable from http://www.virtualbox.org. This file is free software;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncyou can redistribute it and/or modify it under the terms of the GNU
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncGeneral Public License (GPL) as published by the Free Software
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncFoundation, in version 2 as it comes in the "COPYING" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsynchope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncThe contents of this file may alternatively be used under the terms
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncof the Common Development and Distribution License Version 1.0
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync(CDDL) only, as it comes in the "COPYING.CDDL" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncVirtualBox OSE distribution, in which case the provisions of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncCDDL are applicable instead of those of the GPL.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncYou may elect to license modified versions of this file under the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncterms and conditions of either the GPL or the CDDL or both.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Standard python imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Validation Kit imports.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.base import ModelDataBase, ModelDataBaseTestCase, ModelLogicBase, TMExceptionBase;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync A build source.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_iFirstRevision = 'BuildSource_iFirstRevision';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_iLastRevision = 'BuildSource_iLastRevision';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync kasAllowNullAttributes = [ 'idBuildSrc', 'tsEffective', 'tsExpire', 'uidAuthor', 'sDescription', 'asTypes',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'asOsArches', 'iFirstRevision', 'iLastRevision', 'cSecMaxAge' ];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Initialize with defaults.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # See the database for explanations of each of these fields.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Re-initializes the object from a SELECT * FROM BuildSources row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns self. Raises exception if aoRow is None.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def initFromDbWithId(self, oDb, idBuildSrc, tsNow = None, sPeriodBack = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Initialize from the database, given the ID of a row.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDb.execute(self.formatSimpleNowAndPeriodQuery(oDb,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SELECT *\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM BuildSources\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idBuildSrc = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('idBuildSrc=%s not found (tsNow=%s sPeriodBack=%s)' % (idBuildSrc, tsNow, sPeriodBack,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Handle asType and asOsArches specially.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (oNewValue, sError) = ModelDataBase._validateAndConvertAttribute(self, sAttr, sParam, oValue,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (oNewValue, sError) = self.validateListOfStr(oValue, aoNilValues = aoNilValues, fAllowNull = fAllowNull,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync elif sAttr == 'cSecMaxAge' and oValue not in aoNilValues: # Allow human readable interval formats.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (oNewValue, sError) = utils.parseIntervalSeconds(oValue);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return ModelDataBase._validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass BuildSourceLogic(ModelLogicBase): # pylint: disable=R0903
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Build source database logic.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Standard methods.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def fetchForListing(self, iStart, cMaxRows, tsNow):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Fetches build sources.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns an array (list) of BuildSourceData items, empty list if none.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Raises exception on error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM BuildSources\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idBuildSrc DESC\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'LIMIT %s OFFSET %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM BuildSources\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE tsExpire > %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND tsEffective <= %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idBuildSrc DESC\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'LIMIT %s OFFSET %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoRows.append(BuildSourceData().initFromDbRow(aoRow))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Fetch data which is aimed to be passed to HTML form"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT idBuildSrc, sName, sProduct\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM BuildSources\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idBuildSrc DESC\n')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def addEntry(self, oData, uidAuthor, fCommit = False):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Add a new build source to the database.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate the input.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('addEntry invalid input: %s' % (dErrors,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' uidAuthor,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sName,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sDescription,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sProduct,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sBranch,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' asTypes,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' asOsArches,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iFirstRevision,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iLastRevision,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cSecMaxAge)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def editEntry(self, oData, uidAuthor, fCommit = False):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Modifies a build source.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Validate the input and read the old entry.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('addEntry invalid input: %s' % (dErrors,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oOldData = BuildSourceData().initFromDbWithId(self._oDb, oData.idBuildSrc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Make the changes (if something actually changed).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if not oData.isEqualEx(oOldData, [ 'tsEffective', 'tsExpire', 'uidAuthor', ]):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' uidAuthor,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idBuildSrc,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sName,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sDescription,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sProduct,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sBranch,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' asTypes,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' asOsArches,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iFirstRevision,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iLastRevision,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cSecMaxAge)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def removeEntry(self, uidAuthor, idBuildSrc, fCascade = False, fCommit = False):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Deletes a build sources.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check cascading.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM SchedGroups\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idBuildSrc = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' OR idBuildSrcTestSuite = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync asGroups.append('%s (#%d)' % (aoRow[1], aoRow[0]));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Build source #%d is used by one or more scheduling groups: %s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SET idBuildSrc = NULL\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idBuildSrc = %s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SET idBuildSrcTestSuite = NULL\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idBuildSrcTestSuite = %s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Do the job.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Other methods.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def openBuildCursor(self, oBuildSource, sOs, sCpuArch, tsNow):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Opens a cursor (SELECT) using the criteria found in the build source
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync and the given OS.CPUARCH.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns database cursor. May raise exception on bad input or logic error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Used by SchedulerBase.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Construct the extra conditionals.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oBuildSource.asTypes is not None and len(oBuildSource.asTypes) > 0:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(' AND BuildCategories.sType = %s', (oBuildSource.asTypes[0],));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(' AND BuildCategories.sType IN (%s', (oBuildSource.asTypes[0],))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(', %s', (oBuildSource.asTypes[i],));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(', %s)\n', (oBuildSource.asTypes[-1],));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # BuildSource OSes.ARCHes. (Paranoia: use a dictionary to avoid duplicate values.)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oBuildSource.asOsArches is not None and len(oBuildSource.asOsArches) > 0:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(' AND BuildCategories.asOsArches && %s', (oBuildSource.asOsArches,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # TestBox OSes.ARCHes. (Paranoia: use a dictionary to avoid duplicate values.)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dOsDotArches[sOs + '.' + coreconsts.g_ksCpuArchAgnostic] = 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dOsDotArches[coreconsts.g_ksOsAgnostic + '.' + sCpuArch] = 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dOsDotArches[coreconsts.g_ksOsDotArchAgnostic] = 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(' AND BuildCategories.asOsArches && %s', (list(dOsDotArches.keys()),));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Revision range.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(' AND Builds.iRevision >= %s\n', (oBuildSource.iFirstRevision,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(' AND Builds.iRevision <= %s\n', (oBuildSource.iLastRevision,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sExtraConditions += oCursor.formatBindArgs(' AND Builds.tsCreated >= (%s - \'%s seconds\'::INTERVAL)\n',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Execute the query.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oCursor.execute('SELECT Builds.*, BuildCategories.*,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' EXISTS( SELECT tsExpire\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' FROM BuildBlacklist\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' WHERE BuildBlacklist.tsExpire = \'infinity\'::TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND BuildBlacklist.sProduct = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND BuildBlacklist.sBranch = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND BuildBlacklist.iFirstRevision <= Builds.iRevision\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND BuildBlacklist.iLastRevision >= Builds.iRevision ) AS fMaybeBlacklisted\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM Builds, BuildCategories\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE Builds.idBuildCategory = BuildCategories.idBuildCategory\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND Builds.tsExpire = \'infinity\'::TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND Builds.tsEffective <= %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND Builds.fBinariesDeleted is FALSE\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND BuildCategories.sProduct = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND BuildCategories.sBranch = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY Builds.idBuild DESC\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'LIMIT 256\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync tsNow, oBuildSource.sProduct, oBuildSource.sBranch,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Get Build Source data by idBuildSrc"""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM BuildSources\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE tsExpire = \'infinity\'::timestamp\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'Found more than one build sources with the same credentials. Database structure is corrupted.')
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Internal helpers.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Checks that the build source name is unique, raises exception if it isn't. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM BuildSources\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE sName = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND tsExpire = \'infinity\'::TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync + ('' if idBuildSrcIgnore is None else ' AND idBuildSrc <> %d\n' % (idBuildSrcIgnore,))
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('A build source with name "%s" already exist.' % (oData.sName,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _historizeBuildSource(self, idBuildSrc, tsExpire = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Historizes the current build source entry. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SET tsExpire = CURRENT_TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idBuildSrc = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND tsExpire = \'infinity\'::TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'SET tsExpire = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idBuildSrc = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND tsExpire = \'infinity\'::TIMESTAMP\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Unit testing.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# pylint: disable=C0111
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass BuildSourceDataTestCase(ModelDataBaseTestCase):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # not reached.