# -*- coding: utf-8 -*-
# $Id$
"""
Test Manager - Test groups management.
"""
__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;
you can redistribute it and/or modify it under the terms of the GNU
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
from testmanager.core.testcase import TestCaseData, TestCaseDataEx;
class TestGroupMemberData(ModelDataBase):
"""Representation of a test group member database row."""
ksParam_idTestGroup = 'TestGroupMember_idTestGroup';
ksParam_idTestCase = 'TestGroupMember_idTestCase';
ksParam_tsEffective = 'TestGroupMember_tsEffective';
ksParam_tsExpire = 'TestGroupMember_tsExpire';
ksParam_uidAuthor = 'TestGroupMember_uidAuthor';
ksParam_iSchedPriority = 'TestGroupMember_iSchedPriority';
ksParam_aidTestCaseArgs = 'TestGroupMember_aidTestCaseArgs';
kasAllowNullAttributes = ['idTestGroup', 'idTestCase', 'tsEffective', 'tsExpire', 'uidAuthor', 'aidTestCaseArgs' ];
kiMin_iSchedPriority = 0;
kiMax_iSchedPriority = 31;
def __init__(self):
ModelDataBase.__init__(self)
#
# Initialize with defaults.
# See the database for explanations of each of these fields.
#
self.idTestGroup = None;
self.idTestCase = None;
self.tsEffective = None;
self.tsExpire = None;
self.uidAuthor = None;
self.iSchedPriority = 16;
self.aidTestCaseArgs = None;
def initFromDbRow(self, aoRow):
"""
Reinitialize from a SELECT * FROM TestCaseGroupMembers.
Return self. Raises exception if no row.
"""
if aoRow is None:
raise TMExceptionBase('Test group member not found.')
self.idTestGroup = aoRow[0];
self.idTestCase = aoRow[1];
self.tsEffective = aoRow[2];
self.tsExpire = aoRow[3];
self.uidAuthor = aoRow[4];
self.iSchedPriority = aoRow[5];
self.aidTestCaseArgs = aoRow[6];
return self
def getAttributeParamNullValues(self, sAttr):
# Arrays default to [] as NULL currently. That doesn't work for us.
if sAttr == 'aidTestCaseArgs':
aoNilValues = [None, '-1'];
else:
aoNilValues = ModelDataBase.getAttributeParamNullValues(self, sAttr);
return aoNilValues;
def _validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb):
if sAttr != 'aidTestCaseArgs':
return ModelDataBase._validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb);
# -1 is a special value, which when present make the whole thing NULL (None).
(aidVariations, sError) = self.validateListOfInts(oValue, aoNilValues = aoNilValues, fAllowNull = fAllowNull,
iMin = -1, iMax = 0x7ffffffe);
if sError is None:
if aidVariations is None:
pass;
elif -1 in aidVariations:
aidVariations = None;
elif 0 in aidVariations:
sError = 'Invalid test case varation ID #0.';
else:
aidVariations = sorted(aidVariations);
return (aidVariations, sError);
class TestGroupMemberDataEx(TestGroupMemberData):
"""Extended representation of a test group member."""
def __init__(self):
"""Extend parent class"""
TestGroupMemberData.__init__(self)
self.oTestCase = None; # TestCaseDataEx.
def initFromDbRowEx(self, aoRow, oDb, tsNow = None):
"""
Reinitialize from a SELECT * FROM TestGroupMembers, TestCases row.
Will query the necessary additional data from oDb using tsNow.
Returns self. Raises exception if no row or database error.
"""
TestGroupMemberData.initFromDbRow(self, aoRow);
self.oTestCase = TestCaseDataEx();
self.oTestCase.initFromDbRowEx(aoRow[7:], oDb, tsNow);
return self;
def initFromParams(self, oDisp, fStrict = True):
self.oTestCase = None;
return TestGroupMemberData.initFromParams(self, oDisp, fStrict);
def getDataAttributes(self):
asAttributes = TestGroupMemberData.getDataAttributes(self);
asAttributes.remove('oTestCase');
return asAttributes;
def _validateAndConvertWorker(self, asAllowNullAttributes, oDb):
dErrors = TestGroupMemberData._validateAndConvertWorker(self, asAllowNullAttributes, oDb);
if self.ksParam_idTestCase not in dErrors:
self.oTestCase = TestCaseDataEx()
try:
self.oTestCase.initFromDbWithId(oDb, self.idTestCase);
except Exception as oXcpt:
self.oTestCase = TestCaseDataEx()
dErrors[self.ksParam_idTestCase] = str(oXcpt);
return dErrors;
class TestGroupMemberData2(TestCaseData):
"""Special representation of a Test Group Member item"""
def __init__(self):
"""Extend parent class"""
TestCaseData.__init__(self)
self.idTestGroup = None
self.aidTestCaseArgs = []
def initFromDbRowEx(self, aoRow):
"""
Reinitialize from a :WRONG QUERY:
SELECT TestCases.idTestCase,
TestGroupMembers.tsEffective,
TestGroupMembers.tsExpire,
TestGroupMembers.uidAuthor,
TestCases.idGenTestCase,
TestCases.sName,
TestCases.sDescription,
TestCases.fEnabled,
TestCases.cSecTimeout,
TestCases.sBaseCmd,
TestCases.sValidationKitZips,
TestGroupMembers.idTestGroup,
TestGroupMembers.aidTestCaseArgs
FROM TestCases, TestGroupMembers
WHERE TestCases.idTestCase = TestGroupMembers.idTestCase
..row. Represents complete test group member (test case) info.
Returns object of type TestGroupMemberData2. Raises exception if no row.
"""
TestCaseData.initFromDbRow(self, aoRow);
self.idTestGroup = aoRow[-2]
self.aidTestCaseArgs = aoRow[-1]
return self;
class TestGroupData(ModelDataBase):
"""
Test group data.
"""
ksIdAttr = 'idTestGroup';
ksParam_idTestGroup = 'TestGroup_idTestGroup'
ksParam_tsEffective = 'TestGroup_tsEffective'
ksParam_tsExpire = 'TestGroup_tsExpire'
ksParam_uidAuthor = 'TestGroup_uidAuthor'
ksParam_sName = 'TestGroup_sName'
ksParam_sDescription = 'TestGroup_sDescription'
kasAllowNullAttributes = ['idTestGroup', 'tsEffective', 'tsExpire', 'uidAuthor', 'sDescription' ];
def __init__(self):
ModelDataBase.__init__(self);
#
# Initialize with defaults.
# See the database for explanations of each of these fields.
#
self.idTestGroup = None
self.tsEffective = None
self.tsExpire = None
self.uidAuthor = None
self.sName = None
self.sDescription = None
def initFromDbRow(self, aoRow):
"""
Reinitialize from a SELECT * FROM TestGroups row.
Returns object of type TestGroupData. Raises exception if no row.
"""
if aoRow is None:
raise TMExceptionBase('Test group not found.')
self.idTestGroup = aoRow[0]
self.tsEffective = aoRow[1]
self.tsExpire = aoRow[2]
self.uidAuthor = aoRow[3]
self.sName = aoRow[4]
self.sDescription = aoRow[5]
return self
def initFromDbWithId(self, oDb, idTestGroup, tsNow = None, sPeriodBack = None):
"""
Initialize the object from the database.
"""
oDb.execute(self.formatSimpleNowAndPeriodQuery(oDb,
'SELECT *\n'
'FROM TestGroups\n'
'WHERE idTestGroup = %s\n'
, ( idTestGroup,), tsNow, sPeriodBack));
aoRow = oDb.fetchOne()
if aoRow is None:
raise TMExceptionBase('idTestGroup=%s not found (tsNow=%s sPeriodBack=%s)' % (idTestGroup, tsNow, sPeriodBack,));
return self.initFromDbRow(aoRow);
class TestGroupDataEx(TestGroupData):
"""
Extended test group data.
"""
ksParam_aoMembers = 'TestGroupDataEx_aoMembers';
kasAltArrayNull = [ 'aoMembers', ];
## Helper parameter containing the comma separated list with the IDs of
# potential members found in the parameters.
ksParam_aidTestCases = 'TestGroupDataEx_aidTestCases';
def __init__(self):
TestGroupData.__init__(self);
self.aoMembers = []; # TestGroupMemberDataEx.
def _initExtraMembersFromDb(self, oDb, tsNow = None, sPeriodBack = None):
"""
Worker shared by the initFromDb* methods.
Returns self. Raises exception if no row or database error.
"""
self.aoMembers = [];
_ = sPeriodBack; ## @todo sPeriodBack
if tsNow is None:
oDb.execute('SELECT TestGroupMembers.*, TestCases.*\n'
'FROM TestGroupMembers\n'
'LEFT OUTER JOIN TestCases ON (\n'
' TestGroupMembers.idTestCase = TestCases.idTestCase\n'
' AND TestCases.tsExpire = \'infinity\'::TIMESTAMP)\n'
'WHERE TestGroupMembers.idTestGroup = %s\n'
' AND TestGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY TestCases.sName, TestCases.idTestCase\n'
, (self.idTestGroup,));
else:
oDb.execute('SELECT TestGroupMembers.*, TestCases.*\n'
'FROM TestGroupMembers\n'
'LEFT OUTER JOIN TestCases ON (\n'
' TestGroupMembers.idTestCase = TestCases.idTestCase\n'
' AND TestCases.tsExpire > %s\n'
' AND TestCases.tsEffective <= %s)\n'
'WHERE TestGroupMembers.idTestGroup = %s\n'
' AND TestGroupMembers.tsExpire > %s\n'
' AND TestGroupMembers.tsEffective <= %s\n'
'ORDER BY TestCases.sName, TestCases.idTestCase\n'
, (tsNow, tsNow, self.idTestGroup, tsNow, tsNow));
for aoRow in oDb.fetchAll():
self.aoMembers.append(TestGroupMemberDataEx().initFromDbRowEx(aoRow, oDb, tsNow));
return self;
def initFromDbRowEx(self, aoRow, oDb, tsNow = None, sPeriodBack = None):
"""
Reinitialize from a SELECT * FROM TestGroups row. Will query the
necessary additional data from oDb using tsNow.
Returns self. Raises exception if no row or database error.
"""
TestGroupData.initFromDbRow(self, aoRow);
return self._initExtraMembersFromDb(oDb, tsNow, sPeriodBack);
def initFromDbWithId(self, oDb, idTestGroup, tsNow = None, sPeriodBack = None):
"""
Initialize the object from the database.
"""
TestGroupData.initFromDbWithId(self, oDb, idTestGroup, tsNow, sPeriodBack);
return self._initExtraMembersFromDb(oDb, tsNow, sPeriodBack);
def getAttributeParamNullValues(self, sAttr):
if sAttr != 'aoMembers':
return TestGroupData.getAttributeParamNullValues(self, sAttr);
return ['', [], None];
def convertParamToAttribute(self, sAttr, sParam, oValue, oDisp, fStrict):
if sAttr != 'aoMembers':
return TestGroupData.convertParamToAttribute(self, sAttr, sParam, oValue, oDisp, fStrict);
aoNewValue = [];
aidSelected = oDisp.getListOfIntParams(sParam, iMin = 1, iMax = 0x7ffffffe, aiDefaults = [])
sIds = oDisp.getStringParam(self.ksParam_aidTestCases, sDefault = '');
for idTestCase in sIds.split(','):
try: idTestCase = int(idTestCase);
except: pass;
oDispWrapper = self.DispWrapper(oDisp, '%s[%s][%%s]' % (TestGroupDataEx.ksParam_aoMembers, idTestCase,))
oMember = TestGroupMemberDataEx().initFromParams(oDispWrapper, fStrict = False);
if idTestCase in aidSelected:
aoNewValue.append(oMember);
return aoNewValue;
def _validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb):
if sAttr != 'aoMembers':
return TestGroupData._validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb);
asErrors = [];
aoNewMembers = [];
for oOldMember in oValue:
oNewMember = TestGroupMemberDataEx().initFromOther(oOldMember);
aoNewMembers.append(oNewMember);
dErrors = oNewMember.validateAndConvert(oDb);
if len(dErrors) > 0:
asErrors.append(str(dErrors));
if len(asErrors) == 0:
for i in range(len(aoNewMembers)):
idTestCase = aoNewMembers[i];
for j in range(i + 1, len(aoNewMembers)):
if aoNewMembers[j].idTestCase == idTestCase:
asErrors.append('Duplicate testcase #%d!' % (idTestCase, ));
break;
return (aoNewMembers, None if len(asErrors) == 0 else '<br>\n'.join(asErrors));
class TestGroupLogic(ModelLogicBase):
"""
Test case management logic.
"""
#
# Standard methods.
#
def fetchForListing(self, iStart, cMaxRows, tsNow):
"""
Fetches test groups.
Returns an array (list) of TestGroupDataEx items, empty list if none.
Raises exception on error.
"""
if tsNow is None:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY sName ASC\n'
'LIMIT %s OFFSET %s\n'
, (cMaxRows, iStart,));
else:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
'ORDER BY sName ASC\n'
'LIMIT %s OFFSET %s\n'
, (tsNow, tsNow, cMaxRows, iStart,));
aoRet = [];
for aoRow in self._oDb.fetchAll():
aoRet.append(TestGroupDataEx().initFromDbRowEx(aoRow, self._oDb, tsNow));
return aoRet;
def addEntry(self, oData, uidAuthor, fCommit = False):
"""
Adds a testgroup to the database.
"""
#
# Validate inputs.
#
assert isinstance(oData, TestGroupDataEx);
dErrors = oData.validateAndConvert(self._oDb);
if len(dErrors) > 0:
raise TMExceptionBase('addEntry invalid input: %s' % (dErrors,));
self._assertUniq(oData, None);
#
# Do the job.
#
self._oDb.execute('INSERT INTO TestGroups (uidAuthor, sName, sDescription)\n'
'VALUES (%s, %s, %s)\n'
'RETURNING idTestGroup\n'
, ( uidAuthor,
oData.sName,
oData.sDescription,));
idTestGroup = self._oDb.fetchOne()[0];
oData.idTestGroup = idTestGroup;
for oMember in oData.aoMembers:
oMember.idTestGroup = idTestGroup;
self._insertTestGroupMember(uidAuthor, oMember)
self._oDb.maybeCommit(fCommit);
return True;
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;
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;
#
# Other methods.
#
def fetchOrderedByName(self, tsNow = None):
"""
Return list of objects of type TestGroupData ordered by name.
May raise exception on database error.
"""
if tsNow is None:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY sName ASC\n');
else:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
'ORDER BY sName ASC\n'
, (tsNow, tsNow,));
aoRet = []
for _ in range(self._oDb.getRowCount()):
aoRet.append(TestGroupData().initFromDbRow(self._oDb.fetchOne()));
return aoRet;
def getMembers(self, idTestGroup):
"""
Fetches all test case records from DB which are
belong to current Test Group.
Returns list of objects of type TestGroupMemberData2 (!).
"""
self._oDb.execute('SELECT TestCases.*,\n'
' TestGroupMembers.idTestGroup,\n'
' TestGroupMembers.aidTestCaseArgs\n'
'FROM TestCases, TestGroupMembers\n'
'WHERE TestCases.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroupMembers.tsExpire = \'infinity\'::TIMESTAMP\n'
' AND TestGroupMembers.idTestCase = TestCases.idTestCase\n'
' AND TestGroupMembers.idTestGroup = %s\n'
'ORDER BY TestCases.idTestCase ASC;',
(idTestGroup,))
aaoRows = self._oDb.fetchAll()
aoRet = []
for aoRow in aaoRows:
aoRet.append(TestGroupMemberData2().initFromDbRowEx(aoRow))
return aoRet
def getAll(self, tsNow=None):
"""Return list of objects of type TestGroupData"""
if tsNow is None:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
'ORDER BY idTestGroup ASC;')
else:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
'ORDER BY idTestGroup ASC;',
(tsNow, tsNow))
aaoRows = self._oDb.fetchAll()
aoRet = []
for aoRow in aaoRows:
aoRet.append(TestGroupData().initFromDbRow(aoRow))
return aoRet
def getById(self, idTestGroup, tsNow=None):
"""Get Test Group data by its ID"""
if tsNow is None:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire = \'infinity\'::timestamp\n'
' AND idTestGroup = %s\n'
'ORDER BY idTestGroup ASC;', (idTestGroup,))
else:
self._oDb.execute('SELECT *\n'
'FROM TestGroups\n'
'WHERE tsExpire > %s\n'
' AND tsEffective <= %s\n'
' AND idTestGroup = %s\n'
'ORDER BY idTestGroup ASC;',
(tsNow, tsNow, idTestGroup))
aRows = self._oDb.fetchAll()
if len(aRows) not in (0, 1):
raise TMExceptionBase('Found more than one test groups with the same credentials. Database structure is corrupted.')
try:
return TestGroupData().initFromDbRow(aRows[0])
except IndexError:
return None
#
# Helpers.
#
def _assertUniq(self, oData, idTestGroupIgnore):
""" Checks that the test group name is unique, raises exception if it isn't. """
self._oDb.execute('SELECT idTestGroup\n'
'FROM TestGroups\n'
'WHERE sName = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
+ ('' if idTestGroupIgnore is None else ' AND idTestGroup <> %d\n' % (idTestGroupIgnore,))
, ( oData.sName, ))
if self._oDb.getRowCount() > 0:
raise TMExceptionBase('A Test group with name "%s" already exist.' % (oData.sName,));
return True;
def _historizeTestGroup(self, idTestGroup):
""" Historize Test Group record. """
self._oDb.execute('UPDATE TestGroups\n'
'SET tsExpire = CURRENT_TIMESTAMP\n'
'WHERE idTestGroup = %s\n'
' AND tsExpire = \'infinity\'::TIMESTAMP\n'
, ( idTestGroup, ));
return True;
def _historizeTestGroupMember(self, idTestGroup, idTestCase):
""" Historize Test Group Member record. """
self._oDb.execute('UPDATE TestGroupMembers\n'
'SET tsExpire = CURRENT_TIMESTAMP\n'
'WHERE idTestGroup = %s\n'
' AND idTestCase = %s\n'
' AND tsExpire = \'infinity\'::timestamp\n'
, (idTestGroup, idTestCase,));
return True;
def _insertTestGroupMember(self, uidAuthor, oMember):
""" Inserts a test group member. """
self._oDb.execute('INSERT INTO TestGroupMembers\n'
' (uidAuthor, idTestGroup, idTestCase, iSchedPriority, aidTestCaseArgs)\n'
'VALUES (%s, %s, %s, %s, %s)\n'
, ( uidAuthor,
oMember.idTestGroup,
oMember.idTestCase,
oMember.iSchedPriority,
oMember.aidTestCaseArgs, ));
return True;
#
# Unit testing.
#
# pylint: disable=C0111
class TestGroupMemberDataTestCase(ModelDataBaseTestCase):
def setUp(self):
self.aoSamples = [TestGroupMemberData(),];
class TestGroupDataTestCase(ModelDataBaseTestCase):
def setUp(self):
self.aoSamples = [TestGroupData(),];
if __name__ == '__main__':
unittest.main();
# not reached.