schedgroup.py revision cf22150eaeeb72431bf1cf65c309a431454fb22b
# -*- coding: utf-8 -*-
# $Id$
"""
Test Manager - Scheduling Group.
"""
__copyright__ = \
"""
Copyright (C) 2012-2014 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
General Public License (GPL) as published by the Free Software
Foundation, in version 2 as it comes in the "COPYING" file of the
VirtualBox OSE distribution. VirtualBox OSE is distributed in the
hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
The contents of this file may alternatively be used under the terms
of the Common Development and Distribution License Version 1.0
(CDDL) only, as it comes in the "COPYING.CDDL" file of the
VirtualBox OSE distribution, in which case the provisions of the
CDDL are applicable instead of those of the GPL.
You may elect to license modified versions of this file under the
terms and conditions of either the GPL or the CDDL or both.
"""
__version__ = "$Revision$"
# Standard python imports.
import unittest;
# Validation Kit imports.
from testmanager.core.base import ModelDataBase, ModelDataBaseTestCase, ModelLogicBase, TMExceptionBase;
class SchedGroupMemberData(ModelDataBase):
"""
SchedGroupMember Data.
"""
ksIdAttr = 'idSchedGroup';
ksParam_idSchedGroup = 'SchedGroupMember_idSchedGroup';
ksParam_idTestGroup = 'SchedGroupMember_idTestGroup';
ksParam_tsEffective = 'SchedGroupMember_tsEffective';
ksParam_tsExpire = 'SchedGroupMember_tsExpire';
ksParam_uidAuthor = 'SchedGroupMember_uidAuthor';
ksParam_iSchedPriority = 'SchedGroupMember_iSchedPriority';
ksParam_bmHourlySchedule = 'SchedGroupMember_bmHourlySchedule';
ksParam_idTestGroupPreReq = 'SchedGroupMember_idTestGroupPreReq';
'uidAuthor', 'bmHourlySchedule', 'idTestGroupPreReq' ];
kiMin_iSchedPriority = 0;
kiMax_iSchedPriority = 32;
#
# Initialize with defaults.
# See the database for explanations of each of these fields.
#
self.idSchedGroup = None;
self.idTestGroup = None;
self.tsEffective = None;
self.bmHourlySchedule = None;
self.idTestGroupPreReq = None;
"""
Re-initializes the data with a row from a SELECT * FROM SchedGroupMembers.
Returns self. Raises exception if the row is None or otherwise invalid.
"""
if aoRow is None:
raise TMExceptionBase('SchedGroupMember not found.');
return self;
"""
Extended SchedGroupMember data class.
This adds the testgroups.
"""
self.oTestGroup = None;
"""
Re-initializes the data with a row from a query like this:
SELECT SchedGroupMembers.*, TestGroups.*
FROM SchedGroupMembers
JOIN TestGroups
ON (SchedGroupMembers.idTestGroup = TestGroups.idTestGroup);
Returns self. Raises exception if the row is None or otherwise invalid.
"""
return self;
def getDataAttributes(self):
return asAttributes;
try:
return dErrors;
class SchedGroupData(ModelDataBase):
"""
SchedGroup Data.
"""
## @name TestBoxState_T
# @{
ksScheduler_BestEffortContinousItegration = 'bestEffortContinousItegration';
ksScheduler_Reserved = 'reserved';
## @}
ksIdAttr = 'idSchedGroup';
ksParam_idSchedGroup = 'SchedGroup_idSchedGroup';
ksParam_tsEffective = 'SchedGroup_tsEffective';
ksParam_tsExpire = 'SchedGroup_tsExpire';
ksParam_uidAuthor = 'SchedGroup_uidAuthor';
ksParam_sName = 'SchedGroup_sName';
ksParam_sDescription = 'SchedGroup_sDescription';
ksParam_fEnabled = 'SchedGroup_fEnabled';
ksParam_enmScheduler = 'SchedGroup_enmScheduler';
ksParam_idBuildSrc = 'SchedGroup_idBuildSrc';
ksParam_idBuildSrcTestSuite = 'SchedGroup_idBuildSrcTestSuite';
'idBuildSrc', 'idBuildSrcTestSuite'];
# Scheduler types
kasSchedulerDesc = \
[
( ksScheduler_BestEffortContinousItegration, 'Best-Effort-Continous-Itegration (BECI) scheduler.', ''),
]
#
# Initialize with defaults.
# See the database for explanations of each of these fields.
#
self.idSchedGroup = None;
self.tsEffective = None;
self.sDescription = None;
self.idBuildSrc = None;
self.idBuildSrcTestSuite = None;
"""
Re-initializes the data with a row from a SELECT * FROM SchedGroups.
Returns self. Raises exception if the row is None or otherwise invalid.
"""
if aoRow is None:
raise TMExceptionBase('SchedGroup not found.');
return self;
"""
Initialize the object from the database.
"""
'SELECT *\n'
'FROM SchedGroups\n'
'WHERE idSchedGroup = %s\n'
if aoRow is None:
raise TMExceptionBase('idSchedGroup=%s not found (tsNow=%s, sPeriodBack=%s)' % (idSchedGroup, tsNow, sPeriodBack));
class SchedGroupDataEx(SchedGroupData):
"""
Extended scheduling group data.
Note! Similar to TestGroupDataEx.
"""
ksParam_aoMembers = 'SchedGroup_aoMembers';
kasAltArrayNull = [ 'aoMembers', ];
## Helper parameter containing the comma separated list with the IDs of
# potential members found in the parameters.
ksParam_aidTestGroups = 'TestGroupDataEx_aidTestGroups';
# Two build sources for convenience sake.
self.oBuildSrcValidationKit = None;
# List of test boxes that uses this group for convenience.
self.aoTestBoxes = None;
"""
Worker shared by the initFromDb* methods.
Returns self. Raises exception if no row or database error.
"""
#
# It all upfront so the object has some kind of consistency if anything
# below raises exceptions.
#
self.oBuildSrcValidationKit = None;
self.aoTestBoxes = [];
#
# Build source.
#
if self.idBuildSrc:
tsNow, sPeriodBack);
#
# Test Boxes.
#
## @todo sPeriodBack!
if tsNow is None:
'FROM TestBoxes\n'
'WHERE TestBoxes.idSchedGroup = %s\n'
' AND TestBoxes.tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY TestBoxes.sName, TestBoxes.idTestBox\n'
, (self.idSchedGroup,));
else:
'FROM TestBoxes\n'
'WHERE TestBoxes.idSchedGroup = %s\n'
' AND TestBoxes.tsExpire > %s\n'
' AND TestBoxes.tsEffective <= %s\n'
'ORDER BY TestBoxes.sName, TestBoxes.idTestBox\n'
#
# Test groups.
#
## @todo sPeriodBack!
if tsNow is None:
'FROM SchedGroupMembers\n'
'LEFT OUTER JOIN TestGroups ON (SchedGroupMembers.idTestGroup = TestGroups.idTestGroup)\n'
'WHERE SchedGroupMembers.idSchedGroup = %s\n'
' AND SchedGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroups.tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY SchedGroupMembers.idTestGroupPreReq, SchedGroupMembers.idTestGroup\n'
, (self.idSchedGroup,));
else:
'FROM SchedGroupMembers\n'
'LEFT OUTER JOIN TestGroups ON (SchedGroupMembers.idTestGroup = TestGroups.idTestGroup)\n'
'WHERE SchedGroupMembers.idSchedGroup = %s\n'
' AND SchedGroupMembers.tsExpire > %s\n'
' AND SchedGroupMembers.tsEffective <= %s\n'
' AND TestGroups.tsExpire > %s\n'
' AND TestGroups.tsEffective <= %s\n'
'ORDER BY SchedGroupMembers.idTestGroupPreReq, SchedGroupMembers.idTestGroup\n'
return self;
"""
Reinitialize from a SELECT * FROM SchedGroups row. Will query the
necessary additional data from oDb using tsNow.
Returns self. Raises exception if no row or database error.
"""
"""
Initialize the object from the database.
"""
def getDataAttributes(self):
return asAttributes;
if sAttr != 'aoMembers':
return ['', [], None];
if sAttr != 'aoMembers':
aoNewValue = [];
except: pass;
oDispWrapper = self.DispWrapper(oDisp, '%s[%s][%%s]' % (SchedGroupDataEx.ksParam_aoMembers, idTestGroup,))
if idTestGroup in aidSelected:
return aoNewValue;
if sAttr != 'aoMembers':
return SchedGroupData._validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb);
asErrors = [];
aoNewMembers = [];
for oOldMember in oValue:
idTestGroup = aoNewMembers[i];
break;
#
# Fetch the extended build source bits.
#
or self.idBuildSrc is None:
else:
try:
or self.idBuildSrcTestSuite is None:
self.oBuildSrcValidationKit = None;
else:
try:
return dErrors;
"""
SchedGroup logic.
"""
#
# Standard methods.
#
"""
Fetches build sources.
Returns an array (list) of BuildSourceData items, empty list if none.
Raises exception on error.
"""
if tsNow is None:
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY idSchedGroup DESC\n'
'LIMIT %s OFFSET %s\n'
else:
'FROM SchedGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
'ORDER BY idSchedGroup DESC\n'
'LIMIT %s OFFSET %s\n'
aoRet = [];
return aoRet;
"""Add Scheduling Group record"""
#
# Validate.
#
#
# Add it.
#
' uidAuthor,\n'
' sName,\n'
' sDescription,\n'
' fEnabled,\n'
' enmScheduler,\n'
' idBuildSrc,\n'
' idBuildSrcTestSuite)\n'
'VALUES (%s, %s, %s, %s, %s, %s, %s)\n'
'RETURNING idSchedGroup\n'
, (uidAuthor,
return True;
"""Edit Scheduling Group record"""
#
# Validate input and retrieve the old data.
#
#
# Make the changes.
#
if not oData.isEqualEx(oOldData, [ 'tsEffective', 'tsExpire', 'uidAuthor', 'aoMembers', 'aoTestBoxes',
'oBuildSrc', 'oBuildSrcValidationKit', ]):
# Remove groups.
break;
if fRemove:
# Add / modify groups.
oOldMember = None;
oOldMember = oOld;
break;
if oOldMember is None:
return True;
"""
Deletes a scheduling group.
"""
#
# Input validation and retrival of current data.
#
if idSchedGroup == 1:
raise TMExceptionBase('Cannot remove the default scheduling group (id 1).');
#
# We use cascade a little different here... We don't actually delete
# associated testboxes or testgroups.
#
# 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'
else:
# Reassign testboxes to scheduling group #1 (the default group).
raise TMExceptionBase('More testboxes was added to the scheduling group as we were trying to delete it.');
#
# Remove the group and all member records.
#
'SET tsExpire = CURRENT_TIMESTAMP\n'
'WHERE idSchedGroup = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
, (idSchedGroup,));
'SET tsExpire = CURRENT_TIMESTAMP\n'
'WHERE idSchedGroup = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
, (idSchedGroup,))
return True;
#
# Other methods.
#
"""
Return list of objects of type SchedGroups ordered by name.
May raise exception on database error.
"""
if tsNow is None:
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY sName ASC\n');
else:
'FROM SchedGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
'ORDER BY sName ASC\n'
aoRet = []
return aoRet;
"""
Gets the list of all scheduling groups.
Returns an array of SchedGroupData instances.
"""
if tsEffective is None:
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n');
else:
'FROM SchedGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
, (tsEffective, tsEffective));
aoRet = [];
return aoRet;
"""
Gets the list of active scheduling groups for a combo box.
Returns an array of (value [idSchedGroup], drop-down-name [sName],
hover-text [sDescription]) tuples.
"""
if tsEffective is None:
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY sName');
else:
'FROM SchedGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
'ORDER BY sName'
, (tsEffective, tsEffective));
"""
Gets the scheduling groups members for the given scheduling group.
Returns an array of SchedGroupMemberDataEx instances (sorted by
priority and idTestGroup). May raise exception DB error.
"""
if tsEffective is None:
'FROM SchedGroupMembers, TestGroups\n'
'WHERE SchedGroupMembers.idSchedGroup = %s\n'
' AND SchedGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroups.idTestGroup = SchedGroupMembers.idTestGroup\n'
' AND TestGroups.tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY SchedGroupMembers.iSchedPriority, SchedGroupMembers.idTestGroup\n'
, (idSchedGroup,));
else:
'FROM SchedGroupMembers, TestGroups\n'
'WHERE SchedGroupMembers.idSchedGroup = %s\n'
' AND SchedGroupMembers.tsExpire < %s\n'
' AND SchedGroupMembers.tsEffective >= %s\n'
' AND TestGroups.idTestGroup = SchedGroupMembers.idTestGroup\n'
' AND TestGroups.tsExpire < %s\n'
' AND TestGroups.tsEffective >= %s\n'
'ORDER BY SchedGroupMembers.iSchedPriority DESC, SchedGroupMembers.idTestGroup\n'
aoRet = [];
return aoRet;
"""
Gets the enabled testcases w/ testgroup+priority for the given scheduling group.
Returns an array TestCaseData instance (group id, testcase priority and
testcase ids) with an extra iSchedPriority member.
May raise exception on DB error or if the result exceeds cMax.
"""
self._oDb.execute('SELECT TestGroupMembers.idTestGroup, TestGroupMembers.iSchedPriority, TestCases.*\n'
'FROM SchedGroupMembers, TestGroups, TestGroupMembers, TestCases\n'
'WHERE SchedGroupMembers.idSchedGroup = %s\n'
' AND SchedGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroups.idTestGroup = SchedGroupMembers.idTestGroup\n'
' AND TestGroups.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroupMembers.idTestGroup = TestGroups.idTestGroup\n'
' AND TestGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestCases.idTestCase = TestGroupMembers.idTestCase\n'
' AND TestCases.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestCases.fEnabled = TRUE\n'
'ORDER BY TestGroupMembers.idTestGroup, TestGroupMembers.iSchedPriority, TestCases.idTestCase\n'
, (idSchedGroup,));
raise TMExceptionBase('Too many testcases for scheduling group %s: %s, max %s'
aoRet = [];
return aoRet;
"""
Gets the testcase argument variation w/ testgroup+priority for the given scheduling group.
Returns an array TestCaseArgsData instance (sorted by group and
variation id) with an extra iSchedPriority member.
May raise exception on DB error or if the result exceeds cMax.
"""
self._oDb.execute('SELECT TestGroupMembers.idTestGroup, TestGroupMembers.iSchedPriority, TestCaseArgs.*\n'
'FROM SchedGroupMembers, TestGroups, TestGroupMembers, TestCaseArgs, TestCases\n'
'WHERE SchedGroupMembers.idSchedGroup = %s\n'
' AND SchedGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroups.idTestGroup = SchedGroupMembers.idTestGroup\n'
' AND TestGroups.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroupMembers.idTestGroup = TestGroups.idTestGroup\n'
' AND TestGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestCaseArgs.idTestCase = TestGroupMembers.idTestCase\n'
' AND TestCaseArgs.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND ( TestGroupMembers.aidTestCaseArgs is NULL\n'
' OR TestCaseArgs.idTestCaseArgs = ANY(TestGroupMembers.aidTestCaseArgs) )\n'
' AND TestCases.idTestCase = TestCaseArgs.idTestCase\n'
' AND TestCases.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestCases.fEnabled = TRUE\n'
'ORDER BY TestGroupMembers.idTestGroup, TestGroupMembers.idTestCase, TestCaseArgs.idTestCaseArgs\n'
, (idSchedGroup,));
raise TMExceptionBase('Too many argument variations for scheduling group %s: %s, max %s'
aoRet = [];
return aoRet;
"""Checks if a group with the given name exists."""
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
' AND sName = %s\n'
, (sName,));
"""Get Scheduling Group data by idSchedGroup"""
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::timestamp\n'
' AND idSchedGroup = %s;', (idSchedGroup,))
'Found more than one scheduling groups with the same credentials. Database structure is corrupted.')
try:
except IndexError:
return None
"""Historize Scheduling Group record"""
'SET tsExpire = CURRENT_TIMESTAMP,\n'
' uidAuthor = %s\n'
'WHERE idSchedGroup = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n',
(uidAuthor, idScedGroup))
if fNeedCommit:
return True
#
# Internal helpers.
#
"""
Checks that the scheduling group name is unique.
Raises exception if the name is already in use.
"""
if idSchedGroupIgnore is None:
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
' AND sName = %s\n'
, ( sName, ) );
else:
'FROM SchedGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
' AND sName = %s\n'
' AND idSchedGroup <> %s\n'
, ( sName, idSchedGroupIgnore, ) );
return True;
"""
Re-adds the SchedGroups entry. Used by editEntry and removeEntry.
"""
if tsEffective is None:
' uidAuthor,\n'
' tsEffective,\n'
' idSchedGroup,\n'
' sName,\n'
' sDescription,\n'
' fEnabled,\n'
' enmScheduler,\n'
' idBuildSrc,\n'
' idBuildSrcTestSuite )\n'
'VALUES ( %s, %s, %s, %s, %s, %s, %s, %s, %s )\n'
, ( uidAuthor,
oData.idBuildSrcTestSuite, ));
return True;
"""
Historizes the current entry for the given scheduling group.
"""
if tsExpire is None:
'SET tsExpire = %s\n'
'WHERE idSchedGroup = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
, ( tsExpire, idSchedGroup, ));
return True;
"""
addEntry worker for adding a scheduling group member.
"""
if tsEffective is None:
' idSchedGroup,\n'
' idTestGroup,\n'
' tsEffective,\n'
' uidAuthor,\n'
' iSchedPriority,\n'
' bmHourlySchedule,\n'
' idTestGroupPreReq)\n'
'VALUES (%s, %s, %s, %s, %s, %s, %s)\n'
, ( oMember.idSchedGroup,
oMember.idTestGroupPreReq, ));
return True;
"""
Removes a scheduling group member.
"""
# Try record who removed it by adding an dummy entry that expires immediately.
else:
return True;
"""
Historizes the current entry for the given scheduling group.
"""
if tsExpire is None:
'SET tsExpire = %s\n'
'WHERE idSchedGroup = %s\n'
' AND idTestGroup = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
return True;
#
# Unit testing.
#
# pylint: disable=C0111
if __name__ == '__main__':
# not reached.