cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# -*- coding: utf-8 -*-
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# pylint: disable=C0302
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncTest Manager - Base class and utilities for the schedulers.
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.build import BuildDataEx, BuildLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.base import ModelDataBase, ModelDataBaseTestCase, TMExceptionBase;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.buildsource import BuildSourceData, BuildSourceLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.globalresource import GlobalResourceLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.schedgroup import SchedGroupData, SchedGroupLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.systemlog import SystemLogData, SystemLogLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.testboxstatus import TestBoxStatusData, TestBoxStatusLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.testcase import TestCaseLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.testcaseargs import TestCaseArgsDataEx, TestCaseArgsLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncfrom testmanager.core.testset import TestSetData, TestSetLogic;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Data object for recreating a scheduling queue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync It's mostly a storage object, but has a few data checking operation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync associated with it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Load data from the database.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Will extend the entries with aoTestCases and dTestCases members
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # further down. checkForGroupDepCycles will add aidTestGroupPreReqs.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.aoTestGroups = SchedGroupLogic(oDb).getMembers(idSchedGroup);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # aoTestCases entries are TestCaseData instance with iSchedPriority
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # and idTestGroup added for our purposes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We will add oTestGroup and aoArgsVariations members to each further down.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.aoTestCases = SchedGroupLogic(oDb).getTestCasesForGroup(idSchedGroup, cMax = 4096);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Load dependencies.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestCase.aidPreReqs = oTestCaseLogic.getTestCasePreReqIds(oTestCase.idTestCase, cMax = 4096);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # aoTestCases entries are TestCaseArgsData instance with iSchedPriority
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # and idTestGroup added for our purposes.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We will add oTestGroup and oTestCase members to each further down.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.aoArgsVariations = SchedGroupLogic(oDb).getTestCaseArgsForGroup(idSchedGroup, cMax = 65536);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Generate global lookups.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Generate a testcase lookup dictionary for use when working on
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # argument variations.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert len(self.dTestCases) <= len(self.aoTestCases); # Note! Can be shorter!
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Generate a testgroup lookup dictionary.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dTestGroups[oTestGroup.idTestGroup] = oTestGroup;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert len(self.dTestGroups) == len(self.aoTestGroups);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Associate extra members with the base data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Prep the test groups.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Link testcases to their group, both directions. Prep testcases for
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # argument varation association.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oTestGroup.idTestGroup != oTestCase.idTestGroup:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestGroup = self.dTestGroups[oTestCase.idTestGroup];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert oTestCase.idTestCase not in oTestGroup.dTestCases;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestGroup.dTestCases[oTestCase.idTestCase] = oTestCase;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Associate testcase argument variations with their testcases (group)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # in both directions.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestCase = self.aoTestCases[0] if len(self.aoTestCases) > 0 else None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oTestGroup.idTestGroup != oArgVariation.idTestGroup:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestGroup = self.dTestGroups[oArgVariation.idTestGroup];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oTestCase.idTestCase != oArgVariation.idTestCase or oTestCase.idTestGroup != oArgVariation.idTestGroup:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestCase = oTestGroup.dTestCases[oArgVariation.idTestCase];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _addPreReqError(aoErrors, aidChain, oObj, sMsg):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Returns a chain of IDs error entry. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Checks for testgroup depencency cycles and any missing testgroup
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dependencies.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns array of errors (see SchedulderBase.recreateQueue()).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync while idPreReq is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._addPreReqError(aoErrors, aidChain, oTestGroup,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'TestGroup #%s prerequisite chain is too long!'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oDep is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._addPreReqError(aoErrors, aidChain, oTestGroup,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'TestGroup #%s prerequisite #%s is not in the scheduling group!'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Checks that testcase dependencies stays within bounds. We do not allow
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dependencies outside a testgroup, no dependency cycles or even remotely
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync long dependency chains.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns array of errors (see SchedulderBase.recreateQueue()).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Stupid recursion code using special stack(s).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aiIndexes[-1][1] = i + 1; # whatever happens, we'll advance on the current level.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oDep is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._addPreReqError(aoErrors, aidChain, oTestCase,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'TestCase #%s prerequisite #%s is not in the scheduling group!'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._addPreReqError(aoErrors, aidChain, oTestCase,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'TestCase #%s prerequisite #%s creates a cycle!'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._addPreReqError(aoErrors, aidChain, oTestCase,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'TestCase #%s prerequisite chain is too long!' % (oTestCase.idTestCase,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Sorts the testgroups and their testcases by priority and dependencies.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Note! Don't call this before checking for dependency cycles!
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # ASSUMES groups as well as testcases are sorted by priority by the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # database. So we only have to concern ourselves with the dependency
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Incorrectly sorted testgroups returned by database.');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('Incorrectly sorted testcases returned by database.');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Sort the testgroups by dependencies.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iPreReq = self.aoTestGroups.index(self.dTestGroups[oTestGroup.idTestGroupPreReq]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The prerequisite is after the current entry. Move the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # current entry so that it's following it's prereq entry.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Sort the testcases by dependencies.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Same algorithm as above, just more prerequisites.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync iPreReq = oTestGroup.aoTestCases.index(oTestGroup.dTestCases[idPreReq]);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The prerequisite is after the current entry. Move the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # current entry so that it's following it's prereq entry.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestGroup.aoTestGroups.insert(iPreReq + 1, oTestCase);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Scheduling queue data item.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idSchedGroup = 'SchedQueueData_idSchedGroup';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idGenTestCaseArgs = 'SchedQueueData_idGenTestCaseArgs';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestGroup = 'SchedQueueData_idTestGroup';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_aidTestGroupPreReqs = 'SchedQueueData_aidTestGroupPreReqs';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_bmHourlySchedule = 'SchedQueueData_bmHourlySchedule';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_tsLastScheduled = 'SchedQueueData_tsLastScheduled';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_idTestSetGangLeader = 'SchedQueueData_idTestSetGangLeader';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ksParam_cMissingGangMembers = 'SchedQueueData_cMissingGangMembers';
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync kasAllowNullAttributes = [ 'idItem', 'offQueue', 'aidTestGroupPreReqs', 'bmHourlySchedule', 'idTestSetGangLeader',
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Initialize with defaults.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # See the database for explanations of each of these fields.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def initFromValues(self, idSchedGroup, idGenTestCaseArgs, idTestGroup, aidTestGroupPreReqs, # pylint: disable=R0913
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync idItem = None, offQueue = None, tsConfig = None, tsLastScheduled = None, idTestSetGangLeader = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Reinitialize with all attributes potentially given as inputs.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Return self.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Initialize from database row (SELECT * FROM SchedQueues).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns self.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Raises exception if no row is specfied.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise TMExceptionBase('SchedQueueData not found.');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync The scheduler base class.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync The scheduler classes have two functions:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 1. Recreate the scheduling queue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 2. Pick the next task from the queue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync The first is scheduler specific, the latter isn't.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Build cache. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Build class iterator. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Returns self, required by the language."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Returns the next build, raises StopIteration when the end has been reached."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Build cache entry. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fBlacklisted = None if fMaybeBlacklisted is True else False;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Marks the cache entry as removed.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync This doesn't actually remove it from the cache array, only marks
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync it as removed. It has no effect on open iterators.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Retrieves a cached prerequisite decision.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns boolean if found, None if not.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def setPreReqDecision(self, sPreReqSet, fDecision):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Caches a prerequistie decision.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Checks if the build is blacklisted. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._fBlacklisted = BuildLogic(oDb).isBuildBlacklisted(self.oBuild);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def setupSource(self, oDb, idBuildSrc, sOs, sCpuArch, tsNow):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Configures the build cursor for the cache. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if len(self.aoEntries) == 0 and self.oCursor is None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oBuildSource = BuildSourceData().initFromDbWithId(oDb, idBuildSrc, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.oCursor = BuildSourceLogic(oDb).openBuildCursor(oBuildSource, sOs, sCpuArch, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Return an iterator."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Fetches a build from the cursor and adds it to the cache."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def __init__(self, oDb, oSchedGrpData, iVerbosity = 0, tsSecStart = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._tsSecStart = tsSecStart if tsSecStart is not None else utils.timestampSecond();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _instantiate(oDb, oSchedGrpData, iVerbosity = 0, tsSecStart = None):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Instantiate the scheduler specified by the scheduling group.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns scheduler child class instance. May raise exception if
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync the input is invalid.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oSchedGrpData.enmScheduler == SchedGroupData.ksScheduler_BestEffortContinousItegration:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync from testmanager.core.schedulerbeci import SchdulerBeci;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oScheduler = SchdulerBeci(oDb, oSchedGrpData, iVerbosity, tsSecStart);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync raise oDb.integrityException('Invalid scheduler "%s", idSchedGroup=%d' \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (oSchedGrpData.enmScheduler, oSchedGrpData.idSchedGroup));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Debug printing."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Info printing."""
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """Prints a debug message to the srv glue log (see config.py). """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync """ Returns the number of seconds this scheduling task has been running. """
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Create schedule.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Cancels all pending gang gatherings on the current queue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM SchedQueues\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idSchedGroup = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND idTestSetGangLeader is not NULL\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTBStatusLogic.updateGangStatus(idTestSetGangLeader,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TestBoxStatusData.ksTestBoxState_GangGatheringTimedOut,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns an array of queue items (SchedQueueData).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Child classes must override this.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Worker for recreateQueue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Collect the necessary data and validate it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oData = ReCreateQueueData(self._oDb, self._oSchedGrpData.idSchedGroup);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoErrors.extend(oData.checkForMissingTestCaseDeps());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The creation of the scheduling queue is done by the child class.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We will try guess where in queue we're currently at and rotate
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # the items such that we will resume execution in the approximately
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # same position. The goal of the scheduler is to provide a 100%
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # deterministic result so that if we regenerate the queue when there
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # are no changes to the testcases, testgroups or scheduling groups
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # involved, test execution will be unchanged (save for maybe just a
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # little for gang gathering).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.msgDebug('len(aoItems)=%s' % (len(aoItems),));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.msgDebug('aoItems[%2d]=%s' % (i, aoItems[i]));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT offQueue FROM SchedQueues WHERE idSchedGroup = %s ORDER BY idItem LIMIT 1'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT COUNT(*) FROM SchedQueues WHERE idSchedGroup = %s'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoItems = aoItems[offQueueNew:] + aoItems[:offQueueNew];
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Replace the scheduling queue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Care need to be take to first timeout/abort any gangs in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # gathering state since these use the queue to set up the date.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('DELETE FROM SchedQueues WHERE idSchedGroup = %s\n', (self._oSchedGrpData.idSchedGroup,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idSchedGroup,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' offQueue,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idGenTestCaseArgs,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestGroup,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' aidTestGroupPreReqs,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' bmHourlySchedule,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cMissingGangMembers )\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'VALUES ( %s, %s, %s, %s, %s, %s, %s )\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oItem.aidTestGroupPreReqs if len(oItem.aidTestGroupPreReqs) > 0 else None,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def recreateQueue(oDb, uidAuthor, idSchedGroup, iVerbosity = 1):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (Re-)creates the scheduling queue for the given group.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns (asMessages, asMessages). On success the array with the error
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync will be empty, on failure it will contain (sError, oRelatedObject)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync entries. The messages is for debugging and are simple strings.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Raises exception database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # To avoid concurrency issues (SchedQueues) and inconsistent data (*),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # we lock quite a few tables while doing this work. We access more
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # data than scheduleNewTask so we lock some additional tables.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDb.execute('LOCK TABLE SchedGroups, SchedGroupMembers, TestGroups, TestGroupMembers IN SHARE MODE');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDb.execute('LOCK TABLE TestBoxes, TestCaseArgs, TestCases IN SHARE MODE');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDb.execute('LOCK TABLE TestBoxStatuses, SchedQueues IN EXCLUSIVE MODE');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Instantiate the scheduler and call the worker function.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oSchedGrpData = SchedGroupData().initFromDbWithId(oDb, idSchedGroup);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oScheduler = SchedulerBase._instantiate(oDb, oSchedGrpData, iVerbosity);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync (aoErrors, asMessages) = oScheduler.recreateQueueWorker();
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync SystemLogLogic(oDb).addEntry(SystemLogData.ksEvent_SchedQueueRecreate,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'User #%d recreated sched queue #%d.' % (uidAuthor, idSchedGroup,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Schedule Task.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Composes the gang specific testdriver arguments.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns command line string, including a leading space.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestSet = TestSetData().initFromDbWithId(self._oDb, idTestSet);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync aoGangMembers = TestSetLogic(self._oDb).getGang(oTestSet.idTestSetGangLeader);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sArgs = ' --gang-member-no %s --gang-members %s' % (oTestSet.iGangMemberNo, len(aoGangMembers));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sArgs = ' --gang-ipv4-%s %s' % (i, aoGangMembers[i].ip); ## @todo IPv6
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def composeExecResponseWorker(self, idTestSet, oTestEx, oTestBox, oBuild, oValidationKitBuild, sBaseUrl):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Given all the bits of data, compose an EXEC command response to the testbox.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sScriptZips = oTestEx.oTestCase.sValidationKitZips;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if sScriptZips is None or sScriptZips.find('@VALIDATIONKIT_ZIP@') >= 0:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sScriptZips = sScriptZips.replace('@VALIDATIONKIT_ZIP@', oValidationKitBuild.sBinaries);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sScriptZips = sScriptZips.replace('@DOWNLOAD_BASE_URL@', sBaseUrl + config.g_ksTmDownloadBaseUrlRel);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sCmdLine = oTestEx.oTestCase.sBaseCmd + ' ' + oTestEx.sArgs;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sCmdLine = sCmdLine.replace('@BUILD_BINARIES@', oBuild.sBinaries);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sCmdLine += ' ' + self._composeGangArguments(idTestSet);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cSecTimeout = oTestEx.cSecTimeout if oTestEx.cSecTimeout is not None else oTestEx.oTestCase.cSecTimeout;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync cSecTimeout = cSecTimeout * oTestBox.pctScaleTimeout / 100;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync constants.tbresp.ALL_PARAM_RESULT: constants.tbresp.CMD_EXEC,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync constants.tbresp.EXEC_PARAM_SCRIPT_ZIPS: sScriptZips,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync constants.tbresp.EXEC_PARAM_SCRIPT_CMD_LINE: sCmdLine,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def composeExecResponse(oDb, idTestSet, sBaseUrl, iVerbosity = 0):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Composes an EXEC response for a gang member (other than the last).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns a EXEC response or raises an exception (DB/input error).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Gather the necessary data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestSet = TestSetData().initFromDbWithId(oDb, idTestSet);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestBox = TestBoxData().initFromDbWithGenId(oDb, oTestSet.idGenTestBox);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestEx = TestCaseArgsDataEx().initFromDbWithGenId(oDb, oTestSet.idGenTestCaseArgs);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oBuild = BuildDataEx().initFromDbWithId(oDb, oTestSet.idBuild);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oValidationKitBuild = BuildDataEx().initFromDbWithId(oDb, oTestSet.idBuildTestSuite);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Instantiate the specified scheduler and let it do the rest.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oSchedGrpData = SchedGroupData().initFromDbWithId(oDb, oTestBox.idSchedGroup, oTestSet.tsCreated);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oScheduler = SchedulerBase._instantiate(oDb, oSchedGrpData, iVerbosity);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return oScheduler.composeExecResponseWorker(idTestSet, oTestEx, oTestBox, oBuild, oValidationKitBuild, sBaseUrl);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Updates a gang schedule task.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if tsNow is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' SET idTestSetGangLeader = %s,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cMissingGangMembers = %s,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsLastScheduled = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idItem = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , (oTask.idTestSetGangLeader, oTask.cMissingGangMembers, tsNow, oTask.idItem,) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' SET cMissingGangMembers = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idItem = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _moveTaskToEndOfQueue(self, oTask, cGangMembers, tsNow):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync The task has been scheduled successfully, reset it's data move it to
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync the end of the queue.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' SET idItem = NEXTVAL(\'SchedQueueItemIdSeq\'),\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSetGangLeader = NULL,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cMissingGangMembers = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idItem = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' SET idItem = NEXTVAL(\'SchedQueueItemIdSeq\'),\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSetGangLeader = NULL,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cMissingGangMembers = 1,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsLastScheduled = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idItem = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _createTestSet(self, oTask, oTestEx, oTestBoxData, oBuild, oValidationKitBuild, tsNow):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Creates a test set for using the given data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Will not commit, someone up the callstack will that later on.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns the test set ID, may raise an exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Lazy bird doesn't want to write testset.py and does it all here.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We're getting the TestSet ID first in order to include it in the base
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # file name (that way we can directly relate files on the disk to the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # test set when doing batch work), and also for idTesetSetGangLeader.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT NEXTVAL(\'TestSetIdSeq\')');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (tsNow.year, tsNow.month, tsNow.day, (tsNow.hour / 6) * 6, idTestSet);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Gang scheduling parameters. Changes the oTask data for updating by caller.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert oTask.cMissingGangMembers == oTestEx.cGangMembers;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTask.cMissingGangMembers = oTestEx.cGangMembers - 1;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert oTask.cMissingGangMembers > 0 and oTask.cMissingGangMembers < oTestEx.cGangMembers;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Do the database stuff.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSet,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsConfig,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsCreated,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idBuild,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idBuildCategory,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idBuildTestSuite,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idGenTestBox,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestBox,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestGroup,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idGenTestCase,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestCase,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idGenTestCaseArgs,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestCaseArgs,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' sBaseFilename,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iGangMemberNo,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSetGangLeader )\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oValidationKitBuild.idBuild if oValidationKitBuild is not None else None,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestResultParent,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSet,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' tsCreated,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idStrName,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cErrors,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' enmStatus,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' iNestingDepth)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' \'running\'::TestStatus_T,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'RETURNING idTestResult'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' SET idTestResult = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestSet = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _tryFindValidationKitBit(self, oTestBoxData, tsNow):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Tries to find the most recent validation kit build suitable for the given testbox.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns BuildDataEx or None. Raise exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Can be overridden by child classes to change the default build requirements.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oBuildSource = BuildSourceData().initFromDbWithId(self._oDb, self._oSchedGrpData.idBuildSrcTestSuite, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oCursor = BuildSourceLogic(self._oDb).openBuildCursor(oBuildSource, oTestBoxData.sOs, oTestBoxData.sCpuArch, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oBuild = BuildDataEx().initFromDbRow(oCursor.fetchOne());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _tryFindBuild(self, oTask, oTestEx, oTestBoxData, tsNow):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Tries to find a fitting build.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns BuildDataEx or None. Raise exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Can be overridden by child classes to change the default build requirements.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Gather the set of prerequisites we have and turn them into a value
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # set for use in the loop below.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Note! We're scheduling on testcase level and ignoring argument variation
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # selections in TestGroupMembers is intentional.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Direct prerequisites. We assume they're all enabled as this can be
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # checked at queue creation time.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Testgroup dependencies from the scheduling group config.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Make sure the _active_ test group members are in the cache.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('SELECT DISTINCT TestGroupMembers.idTestCase\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM TestGroupMembers, TestCases\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestGroupMembers.idTestGroup = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestGroupMembers.tsExpire > %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestGroupMembers.tsEffective <= %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestCases.idTestCase = TestGroupMembers.idTestCase\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestCases.tsExpire > %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestCases.tsEffective <= %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestCases.fEnabled is TRUE\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , (iTestGroup, oTask.tsConfig, oTask.tsConfig, oTask.tsConfig, oTask.tsConfig,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Add the testgroup members to the prerequisites.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for idTestCase in self.dTestGroupMembers[iTestGroup]:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Create a SQL values table out of them.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sPreReqSet = sPreReqSet[2:]; # drop the leading ', '.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Try the builds.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.oBuildCache.setupSource(self._oDb, self._oSchedGrpData.idBuildSrc, oTestBoxData.sOs, oTestBoxData.sCpuArch, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check build requirements set by the test.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check prerequisites. The default scheduler is satisfied if one
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # argument variation has been executed successfully. It is not
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # satisfied if there are any failure runs.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ## @todo DB Tuning
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check for missing prereqs.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM (VALUES ' + sPreReqSet + ') AS PreReqs(idTestCase)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'LEFT OUTER JOIN (SELECT *\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' FROM TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' WHERE enmStatus IN (%s, %s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND idBuild = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' ) AS TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' ON (PreReqs.idTestCase = TestSets.idTestCase)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE TestSets.idTestSet is NULL\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , ( TestSetData.ksTestStatus_Success, TestSetData.ksTestStatus_Skipped,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('build %s is missing %u prerequisites (out of %s)'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (oEntry.oBuild.idBuild, cMissingPreReqs, sPreReqSet,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check for failed prereq runs.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM (VALUES ' + sPreReqSet + ') AS PreReqs(idTestCase),\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' TestSets\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE PreReqs.idTestCase = TestSets.idTestCase\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestSets.idBuild = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND TestSets.enmStatus IN (%s, %s, %s)\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('build %s is has %u prerequisite failures (out of %s)'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % (oEntry.oBuild.idBuild, cFailedPreReqs, sPreReqSet,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # If we can, check if the build files still exist.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('build %s no longer exists' % (oEntry.oBuild.idBuild,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _tryFindMatchingBuild(self, oLeaderBuild, oTestBoxData, idBuildSrc):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Tries to find a matching build for gang scheduling.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns BuildDataEx or None. Raise exception on database error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Can be overridden by child classes to change the default build requirements.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Note! Should probably check build prerequisites if we get a different
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # build back, so that we don't use a build which hasn't passed
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # the smoke test.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return BuildLogic(self._oDb).tryFindSameBuildForOsArch(oLeaderBuild, oTestBoxData.sOs, oTestBoxData.sCpuArch);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _tryAsLeader(self, oTask, oTestEx, oTestBoxData, tsNow, sBaseUrl):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Try schedule the task as a gang leader (can be a gang of one).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns response or None. May raise exception on DB error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We don't wait for busy resources, we just try the next test.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Find a matching build (this is the difficult bit).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oBuild = self._tryFindBuild(oTask, oTestEx, oTestBoxData, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oValidationKitBuild = self._tryFindValidationKitBit(oTestBoxData, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Create a testset, allocate the resources and update the state.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Note! Since resource allocation may still fail, we create a nested
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # transaction so we can roll back. (Heed lock warning in docs!)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync idTestSet = self._createTestSet(oTask, oTestEx, oTestBoxData, oBuild, oValidationKitBuild, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if GlobalResourceLogic(self._oDb).allocateResources(oTestBoxData.idTestBox, oTestEx.aoGlobalRsrc, fCommit = False) \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('ROLLBACK TO SAVEPOINT tryAsLeader');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('Failed to allocate global resources!');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We're alone, put the task back at the end of the queue and issue EXEC cmd.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._moveTaskToEndOfQueue(oTask, oTestEx.cGangMembers, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dResponse = self.composeExecResponseWorker(idTestSet, oTestEx, oTestBoxData, oBuild, oValidationKitBuild, sBaseUrl);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTBState = TestBoxStatusData.ksTestBoxState_Testing;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We're missing gang members, issue WAIT cmd.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._updateTask(oTask, tsNow if idTestSet == oTask.idTestSetGangLeader else None);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dResponse = { constants.tbresp.ALL_PARAM_RESULT: constants.tbresp.CMD_WAIT, };
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTBState = TestBoxStatusData.ksTestBoxState_GangGathering;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TestBoxStatusLogic(self._oDb).updateState(oTestBoxData.idTestBox, sTBState, idTestSet, fCommit = False);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._oDb.execute('RELEASE SAVEPOINT tryAsLeader');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def _tryAsGangMember(self, oTask, oTestEx, oTestBoxData, tsNow, sBaseUrl):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Try schedule the task as a gang member.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns response or None. May raise exception on DB error.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The leader has choosen a build, we need to find a matching one for our platform.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # (It's up to the scheduler decide upon how strict dependencies are to be enforced
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # upon subordinate group members.)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oLeaderTestSet = TestSetData().initFromDbWithId(self._oDb, oTestBoxData.idTestSetGangLeader);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oLeaderBuild = BuildDataEx().initFromDbWithId(self._oDb, oLeaderTestSet.idBuild);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oBuild = self._tryFindMatchingBuild(oLeaderBuild, oTestBoxData, self._oSchedGrpData.idBuildSrc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oLeaderValidationKitBit = BuildDataEx().initFromDbWithId(self._oDb, oLeaderTestSet.idBuildTestSuite);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oValidationKitBuild = self._tryFindMatchingBuild(oLeaderValidationKitBit, oTestBoxData,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Create a testset and update the state(s).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync idTestSet = self._createTestSet(oTask, oTestEx, oTestBoxData, oBuild, oValidationKitBuild, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # The whole gang is there, move the task to the end of the queue
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # and update the status on the other gang members.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._moveTaskToEndOfQueue(oTask, oTestEx.cGangMembers, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dResponse = self.composeExecResponseWorker(idTestSet, oTestEx, oTestBoxData, oBuild, oValidationKitBuild, sBaseUrl);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTBState = TestBoxStatusData.ksTestBoxState_GangTesting;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTBStatusLogic.updateGangStatus(oTask.idTestSetGangLeader, sTBState, fCommit = False);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We're still missing some gang members, issue WAIT cmd.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self._updateTask(oTask, tsNow if idTestSet == oTask.idTestSetGangLeader else None);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dResponse = { constants.tbresp.ALL_PARAM_RESULT: constants.tbresp.CMD_WAIT, };
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sTBState = TestBoxStatusData.ksTestBoxState_GangGathering;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTBStatusLogic.updateState(oTestBoxData.idTestBox, sTBState, idTestSet, fCommit = False);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def scheduleNewTaskWorker(self, oTestBoxData, tsNow, sBaseUrl):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Worker for schduling a new task.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Iterate the scheduler queue (fetch all to avoid having to concurrent
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # queries), trying out each task to see if the testbox can execute it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dRejected = {}; # variations we've already checked out and rejected.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM SchedQueues\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idSchedGroup = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' AND ( bmHourlySchedule IS NULL\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' OR get_bit(bmHourlySchedule, %s) = 1 )\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'ORDER BY idItem ASC\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync , (self._oSchedGrpData.idSchedGroup, utils.getLocalHourOfWeek()) );
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Don't loop forever.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if self.getElapsedSecs() >= config.g_kcSecMaxNewTask:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Unpack the data and check if we've rejected the testcasevar/group variation already (they repeat).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('** Considering: idItem=%s idGenTestCaseArgs=%s idTestGroup=%s Deps=%s last=%s cfg=%s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync % ( oTask.idItem, oTask.idGenTestCaseArgs, oTask.idTestGroup, oTask.aidTestGroupPreReqs,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync sRejectNm = '%s:%s' % (oTask.idGenTestCaseArgs, oTask.idTestGroup,);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('Duplicate, already rejected! (%s)' % (sRejectNm,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Fetch all the test case info (too much, but who cares right now).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestEx = TestCaseArgsDataEx().initFromDbWithGenIdEx(self._oDb, oTask.idGenTestCaseArgs,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('TestCase "%s": %s %s' % (oTestEx.oTestCase.sName, oTestEx.oTestCase.sBaseCmd, oTestEx.sArgs,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # This shouldn't happen, but just in case it does...
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Check if the testbox properties matches the test.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Try schedule it.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oTask.idTestSetGangLeader is None or oTestEx.cGangMembers <= 1:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dResponse = self._tryAsLeader(oTask, oTestEx, oTestBoxData, tsNow, sBaseUrl);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dResponse = self._tryAsGangMember(oTask, oTestEx, oTestBoxData, tsNow, sBaseUrl);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dResponse is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync self.dprint('Found a task! dResponse=%s' % (dResponse,));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Found no suitable task.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync def scheduleNewTask(oDb, oTestBoxData, sBaseUrl, iVerbosity = 0):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Schedules a new task.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # To avoid concurrency issues in SchedQueues we lock all the rows
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # related to our scheduling queue. Also, since this is a very
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # expensive operation we lock the testbox status row to fend of
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # repeated retires by fault testbox script.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDb.execute('SELECT idTestBox FROM TestBoxStatuses WHERE idTestBox = %s FOR UPDATE NOWAIT'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDb.execute('SELECT idSchedGroup FROM SchedQueues WHERE idSchedGroup = %s FOR UPDATE'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # We need the current timestamp.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Re-read the testbox data ...
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestBoxDataCur = TestBoxData().initFromDbWithId(oDb, oTestBoxData.idTestBox, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync and oTestBoxDataCur.idGenTestBox == oTestBoxData.idGenTestBox \
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync and oTestBoxDataCur.idSchedGroup == oTestBoxData.idSchedGroup: # (paranoia wrt idSchedGroup)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # ... and schedule group data.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oSchedGrpData = SchedGroupData().initFromDbWithId(oDb, oTestBoxDataCur.idSchedGroup, tsNow);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oSchedGrpData.fEnabled and oSchedGrpData.idBuildSrc is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Instantiate the specified scheduler and let it do the rest.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oScheduler = SchedulerBase._instantiate(oDb, oSchedGrpData, iVerbosity, tsSecStart);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync dResponse = oScheduler.scheduleNewTaskWorker(oTestBoxDataCur, tsNow, sBaseUrl);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if dResponse is not None:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Not enabled, rollback and return no task.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return None;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Try canceling a gang gathering.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns True if successfully cancelled.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Returns False if not (someone raced us to the SchedQueue table).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync Note! oStatusData is re-initialized.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync assert oStatusData.enmState == TestBoxStatusData.ksTestBoxState_GangGathering;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Lock the tables we're updating so we don't run into concurrency
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # issues (we're racing both scheduleNewTask and other callers of
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # this method).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oDb.execute('LOCK TABLE TestBoxStatuses, SchedQueues IN EXCLUSIVE MODE');
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Re-read the testbox data and check that we're still in the same state.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oStatusData.initFromDbWithId(oDb, oStatusData.idTestBox);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if oStatusData.enmState == TestBoxStatusData.ksTestBoxState_GangGathering:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Get the leader thru the test set and change the state of the whole gang.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestSetData = TestSetData().initFromDbWithId(oDb, oStatusData.idTestSet);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTBStatusLogic.updateGangStatus(oTestSetData.idTestSetGangLeader,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync TestBoxStatusData.ksTestBoxState_GangGatheringTimedOut,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Move the scheduling queue item to the end.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'FROM SchedQueues\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idTestSetGangLeader = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTask = SchedQueueData().initFromDbRow(oDb.fetchOne());
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync oTestEx = TestCaseArgsDataEx().initFromDbWithGenId(oDb, oTask.idGenTestCaseArgs);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' SET idItem = NEXTVAL(\'SchedQueueItemIdSeq\'),\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' idTestSetGangLeader = NULL,\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ' cMissingGangMembers = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync 'WHERE idItem = %s\n'
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync elif oStatusData.enmState == TestBoxStatusData.ksTestBoxState_GangGatheringTimedOut:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # Not enabled, rollback and return no task.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# Unit testing.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync# pylint: disable=C0111
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncclass SchedQueueDataTestCase(ModelDataBaseTestCase):
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync # not reached.