示例#1
0
def testTwoResourcesSameType():
    """Test making a match with two resources of the same types."""
    claim = ResourceClaim.create((
        ResourceSpec.create('ref0', 'typeA', ()),
        ResourceSpec.create('ref1', 'typeA', ()),
    ))
    resA = FakeResource('typeA', ())
    resB = FakeResource('typeA', ())
    resources = (resA, resB)

    resMap = {res.getId(): res for res in resources}
    match = pickResources(claim, resMap)
    assert match is not None
示例#2
0
def testTwoResourcesUniqueCaps():
    """Test making a match with two resources with unique capabilities."""
    claim = ResourceClaim.create((
        ResourceSpec.create('ref0', 'typeA', ('capY', )),
        ResourceSpec.create('ref1', 'typeA', ('capX', )),
    ))
    resX = FakeResource('typeA', ('capX', ))
    resY = FakeResource('typeA', ('capY', ))
    resources = (resX, resY)

    expected = {'ref0': resY, 'ref1': resX}

    check(claim, resources, expected)
示例#3
0
def testTwoResourcesDiffTypes():
    """Test making a match with two resources of different types."""
    claim = ResourceClaim.create((
        ResourceSpec.create('ref0', 'typeA', ()),
        ResourceSpec.create('ref1', 'typeB', ()),
    ))
    resA = FakeResource('typeA', ())
    resB = FakeResource('typeB', ())
    resources = (resA, resB)

    expected = {'ref0': resA, 'ref1': resB}

    check(claim, resources, expected)
示例#4
0
def testAllCombinations():
    """Test all possible claims on all possible resources, at small size.
    It is feasible to do this for low numbers of claims, capabilities and
    resources, but it becomes expotentially slower at larger sizes.
    """
    numCaps = 3
    numSpecs = 3
    numResources = 3

    caps = tuple('cap%d' % i for i in range(numCaps))
    refs = tuple('ref%d' % i for i in range(numSpecs))

    claims = tuple(
        ResourceClaim.create((ResourceSpec.create(refs[i], 'typeA', (
            caps[j]
            for j in range(numCaps) if (claimBits >> (i * numCaps + j)) & 1))
                              for i in range(numSpecs)))
        for claimBits in range(1 << (numSpecs * numCaps)))

    resourceMaps = []
    for resBits in range(1 << (numResources * numCaps)):
        resources = [
            FakeResource('typeA', (caps[j] for j in range(numCaps)
                                   if (resBits >> (i * numCaps + j)) & 1))
            for i in range(numResources)
        ]
        resourceMaps.append({res.getId(): res for res in resources})

    for claim in claims:
        for resMap in resourceMaps:
            checkSolve(claim, resMap)
示例#5
0
 def _addResource(self, attributes: Dict[str, str]) -> ResourceSpec:
     if attributes['type'] == taskRunnerResourceTypeName:
         # COMPAT 2.16: Force reference name for TR.
         attributes['ref'] = taskRunnerResourceRefName
     spec = ResourceSpec(attributes)
     self.addResourceSpec(spec)
     return spec
示例#6
0
def testOneResourceImpossible():
    """Test making a impossible match with one resource."""
    claim = ResourceClaim.create((ResourceSpec.create('ref0', 'typeA', ()), ))
    res = FakeResource('typeB', ())
    resources = (res, )

    check(claim, resources, None)
示例#7
0
def testOverlappingCaps():
    """Test making a match with overlapping capabilities."""
    claim = ResourceClaim.create((
        ResourceSpec.create('ref2', 'typeA', ('capY', )),
        ResourceSpec.create('ref0', 'typeA', ('capW', )),
        ResourceSpec.create('ref1', 'typeA', ('capX', )),
        ResourceSpec.create('ref3', 'typeA', ('capZ', )),
    ))
    resW = FakeResource('typeA', ('capW', ))
    resX = FakeResource('typeA', ('capW', 'capX'))
    resY = FakeResource('typeA', ('capW', 'capX', 'capY'))
    resZ = FakeResource('typeA', ('capW', 'capX', 'capY', 'capZ'))
    resources = (resW, resX, resY, resZ)

    expected = {'ref0': resW, 'ref1': resX, 'ref2': resY, 'ref3': resZ}

    check(claim, resources, expected)
示例#8
0
def testOneResourcePossible():
    """Test making a possible match with one resource."""
    claim = ResourceClaim.create((ResourceSpec.create('ref0', 'typeA', ()), ))
    res = FakeResource('typeA', ())
    resources = (res, )

    expected = {'ref0': res}

    check(claim, resources, expected)
示例#9
0
def testMissingType():
    """Test a claim that can be honored for one type but not for another.
    """
    claim = ResourceClaim.create((ResourceSpec.create('ref%d' % i, 'typeA',
                                                      ('cap%d' % (i % 4), ))
                                  for i in range(10)))
    resources = []
    for i in range(24):
        resources.append(FakeResource('typeA', ('cap%d' % (i % 4), )))

    # Sanity check for our test data.
    resMap = {res.getId(): res for res in resources}
    match = pickResources(claim, resMap)
    assert match is not None

    claim = claim.merge(
        ResourceClaim.create((ResourceSpec.create('refB', 'typeB',
                                                  ('cap0', )), )))
    check(claim, resources, None)
示例#10
0
 def reserveResources(self,
                      claim: ResourceClaim,
                      reservedBy: str,
                      whyNot: Optional[List[ReasonForWaiting]]
                      ) -> Optional[Dict[str, Resource]]:
     resourceDB = self.__jobFactory.resourceDB
     if self.__resources:
         bound = {}
         toReserve = []
         keepPerJob = []
         for spec in claim:
             ref = spec.reference
             resType = spec.typeName
             info = self.__resources.get(ref)
             if info is not None:
                 _, caps, resId = info
                 specCaps = spec.capabilities
                 assert caps >= specCaps
                 if resId is not None:
                     bound[ref] = resId
                 else:
                     keepPerJob.append(ref)
                     if caps != specCaps:
                         spec = ResourceSpec.create(ref, resType, caps)
                     toReserve.append(spec)
             else:
                 toReserve.append(spec)
         reservedPerJob = {}
         for ref, resId in bound.items():
             resource = resourceDB.get(resId)
             if resource is not None:
                 assert isinstance(resource, Resource), resId
                 reservedPerJob[ref] = resource
             else:
                 if whyNot is not None:
                     # TODO: report multiple resources at the same time
                     whyNot.append(ResourceMissingReason(resId))
                 return None
         reservedBy = 'J-' + self.getId()
         reserved = _reserveResources(resourceDB,
                                      ResourceClaim.create(toReserve),
                                      reservedBy, whyNot)
         if reserved is not None:
             for ref in keepPerJob:
                 self.__resources[ref][2] = reserved[ref].getId()
             reserved.update(reservedPerJob)
         return reserved
     else:
         return _reserveResources(resourceDB, claim, reservedBy, whyNot)
示例#11
0
def testUnequalValue():
    """Test making a match with two resources with differing value.
    A resource without capabilities should be picked before resources
    with capabilities.
    """
    claim = ResourceClaim.create((ResourceSpec.create('ref0', 'typeA', ()), ))
    resources = []
    for _ in range(50):
        resources.append(FakeResource('typeA', ('capX', )))
    resNoCaps = FakeResource('typeA', ())
    resources[29] = resNoCaps

    expected = {'ref0': resNoCaps}

    check(claim, resources, expected)
示例#12
0
def simulateRandom(maxCaps,
                   maxSpecs,
                   maxResources,
                   runsPerConfig,
                   numConfigs,
                   verifyFunc,
                   seed=None):
    if seed is None:
        seed = int(time.time())
    print('Random seed: %d' % seed)
    rnd = Random(seed)

    # Pre-create capability and reference names.
    caps = tuple('cap%d' % i for i in range(maxCaps))
    refs = tuple('ref%d' % i for i in range(maxSpecs))

    for _ in range(numConfigs):
        numCaps = rnd.randint(maxCaps // 2, maxCaps)
        numResources = rnd.randint(maxResources // 2, maxResources)

        # Create resources.
        resMap = {}
        for _ in range(numResources):
            capBits = rnd.randrange(1 << numCaps)
            resource = FakeResource('typeA', applyBitmask(caps, capBits))
            resMap[resource.getId()] = resource

        for _ in range(runsPerConfig):
            numSpecs = rnd.randint(maxSpecs // 2, maxSpecs)

            # Create specs.
            specs = []
            for i in range(numSpecs):
                # Create a slight bias towards having fewer capabilities
                # required, so we test finding the lowest cost assignment
                # among multiple possible ones.
                capBits = rnd.randrange(1 << numCaps)
                capBits &= rnd.randrange(1 << numCaps)
                spec = ResourceSpec.create(refs[i], 'typeA',
                                           applyBitmask(caps, capBits))
                specs.append(spec)

            claim = ResourceClaim.create(specs)
            verifyFunc(claim, resMap)
示例#13
0
def testNoResources():
    """Test making a match without resources."""
    claim = ResourceClaim.create((ResourceSpec.create('ref0', 'typeA', ()), ))

    check(claim, (), None)
示例#14
0
 def addTaskRunnerSpec(self, capabilities: Iterable[str] = ()) -> None:
     self.addResourceSpec(
         ResourceSpec.create(taskRunnerResourceRefName,
                             taskRunnerResourceTypeName, capabilities))
示例#15
0
class CapabilitiesPanel(Panel):
    label = 'Capabilities'
    content = xhtml.br.join(
        (textInput(name='capabilities', size=80, style='width:100%'),
         'Multiple capabilities should be separated by spaces.',
         'Task definitions use capabilities to put additional '
         'requirements on the resources they need.'))


class CommentPanel(Panel):
    label = 'Description'
    content = textInput(name='description', size=80, style='width:100%')


initialResourceClaim = ResourceClaim.create(
    (ResourceSpec.create(taskRunnerResourceRefName, taskRunnerResourceTypeName,
                         ()), ))


class ResourceRequirementsArgsMixin:
    '''Adds resource requirement editing arguments to a page.'''
    ref = ListArg()
    type = ListArg()
    caps = ListArg()


class _ResourceRequirementsArgs(ResourceRequirementsArgsMixin, PageArgs):
    """Helper class for type checking."""


def addResourceRequirementsToElement(
        element: TaskDefBase, args: ResourceRequirementsArgsMixin) -> None:
示例#16
0
def addResourceRequirementsToElement(
        element: TaskDefBase, args: ResourceRequirementsArgsMixin) -> None:
    args = cast(_ResourceRequirementsArgs, args)
    for ref, resType, caps in zip(args.ref, args.type, args.caps):
        element.addResourceSpec(ResourceSpec.create(ref, resType,
                                                    caps.split()))
示例#17
0
def _addResources(record, resources):
    if resources is not None:
        for args in resources:
            spec = ResourceSpec.create(*args)
            record.addResourceSpec(spec)