def test_min_resource_per_node() -> None: assert (MinResourcePerNode("pcpus", 2).to_dict() == get_constraint({ "pcpus": 2 }).to_dict()) c = get_constraint({"pcpus": 2}) assert isinstance(c, MinResourcePerNode) assert 0 == c.minimum_space(SchedulerNode("")) try: assert not c.do_decrement(SchedulerNode("")) assert False except RuntimeError: pass s = SchedulerNode("has-pcpus", {"pcpus": 4}) assert s.available["pcpus"] == 4 assert c.do_decrement(s) assert s.available["pcpus"] == 2 assert s.resources["pcpus"] == 4 assert not c.satisfied_by_node(SchedulerNode("no-blah-define")) assert not c.satisfied_by_node( SchedulerNode("wrong-blah-define", {"pcpus": 1})) assert c.satisfied_by_node(SchedulerNode("min-blah-define", {"pcpus": 2})) assert c.satisfied_by_node( SchedulerNode("more-blah-define", {"pcpus": 100}))
def test_node_resource_constraint() -> None: assert ( NodeResourceConstraint("blah", "A").to_dict() == get_constraint({"blah": ["A"]}).to_dict() ) c = get_constraint({"blah": ["A"]}) assert isinstance(c, NodeResourceConstraint) assert -1 == c.minimum_space(SchedulerNode("")) assert c.do_decrement(SchedulerNode("")) assert not c.satisfied_by_node(SchedulerNode("no-blah-define")) assert not c.satisfied_by_node(SchedulerNode("wrong-blah-define", {"blah": "B"})) assert c.satisfied_by_node(SchedulerNode("wrong-blah-define", {"blah": "A"}))
def test_or() -> None: assert ( Or( NodeResourceConstraint("blah", "A"), NodeResourceConstraint("blah", "B") ).to_dict() == get_constraint({"or": [{"blah": ["A"]}, {"blah": ["B"]}]}).to_dict() ) or_expr = {"or": [{"blah": ["A"]}, {"blah": ["B"]}]} assert isinstance(get_constraint(or_expr), Or) c = get_constraint({"node.vcpu_count": 2}) assert -1 == c.minimum_space(SchedulerNode("")) assert c.do_decrement(SchedulerNode(""))
def test_node_property_constraint() -> None: assert ( NodePropertyConstraint("vcpu_count", 2).to_dict() == get_constraint({"node.vcpu_count": 2}).to_dict() ) assert isinstance(get_constraint({"node.vcpu_count": 2}), NodePropertyConstraint) for attr in dir(Node): if not attr[0].lower(): continue try: get_constraint({"node.{}".format(attr): 2}) except ValueError: assert attr not in QUERYABLE_PROPERTIES c = get_constraint({"node.vcpu_count": 2}) assert -1 == c.minimum_space(SchedulerNode("")) assert c.do_decrement(SchedulerNode(""))
def test_xor() -> None: assert ( XOr( NodeResourceConstraint("blah", "A"), NodeResourceConstraint("blah", "B") ).to_dict() == get_constraint({"xor": [{"blah": ["A"]}, {"blah": ["B"]}]}).to_dict() ) xor_expr = {"xor": [{"blah": ["A"]}, {"blah": ["B"]}]} assert isinstance(get_constraint(xor_expr), XOr) c = XOr(NodeResourceConstraint("blah", "A"), NodeResourceConstraint("blah", "B")) assert not c.satisfied_by_node(SchedulerNode("")) assert not c.satisfied_by_node(SchedulerNode("", {"blah": ["A", "B"]})) assert c.satisfied_by_node(SchedulerNode("", {"blah": "A"})) assert c.satisfied_by_node(SchedulerNode("", {"blah": "B"})) assert c.do_decrement(SchedulerNode("", {"blah": "A"}))
def test_never() -> None: c = Never("my message") node = SchedulerNode("test", {"memgb": 4.0}) assert not c.satisfied_by_node(node) assert c.satisfied_by_node(node).reasons == ["my message"] c = get_constraint({"never": "my other message"}) assert isinstance(c, Never) assert c.message == "my other message"
def __init__( self, qnames: List[str], resource_name: str, value: Union[float, int], target_qname: str, bucket_preprocessor: Callable[[Node], bool], ) -> None: self.resource_name = resource_name self.value = value self.target_qname = target_qname self.pattern = re.compile("([^@]+@)?{}".format(resource_name)) self.target_resource = "{}@{}".format(target_qname, resource_name) self.bucket_preprocessor = bucket_preprocessor self.child_constraint = And( get_constraint({resource_name: value}), get_constraint({self.target_resource: value}), )
def test_exclusive_node_parsing() -> None: assert ( ExclusiveNode(True).to_dict() == get_constraint({"exclusive": True}).to_dict() ) assert ( ExclusiveNode(True).to_dict() == get_constraint({"exclusive": "true"}).to_dict() ) assert ExclusiveNode(True).to_dict() == get_constraint({"exclusive": 1}).to_dict() # assert ( # ExclusiveNode(False).to_dict() # == get_constraint({"exclusive": "faLse"}).to_dict() # ) # assert ExclusiveNode(False).to_dict() == get_constraint({"exclusive": 0}).to_dict() # assert ( # ExclusiveNode(False).to_dict() == get_constraint({"exclusive": False}).to_dict() # ) try: get_constraint({"exclusive": "asdf"}) assert False except RuntimeError: pass
def test_job_excl() -> None: s = SchedulerNode("") # typical exclusive behavior - one task per job per node job_excl = get_constraint({"exclusive": True}) assert job_excl.job_exclusive assert isinstance(job_excl, ExclusiveNode) assert job_excl.satisfied_by_node(s) assert -1 == job_excl.minimum_space(s) assert job_excl.do_decrement(s) s.assign("1") job_excl.assignment_id = "1" # can't put the same jobid on the same node twice assert not job_excl.satisfied_by_node(s) assert not job_excl.do_decrement(s) assert s.closed assert 0 == job_excl.minimum_space(s)
def test_task_excl() -> None: s = SchedulerNode("") # now to test tack exclusive, where multiple tasks from the same # job can run on the same machine task_excl = get_constraint({"exclusive_task": True}) assert not task_excl.job_exclusive assert isinstance(task_excl, ExclusiveNode) assert task_excl.satisfied_by_node(s) assert -1 == task_excl.minimum_space(s) assert task_excl.do_decrement(s) s.assign("1") task_excl.assignment_id = "1" assert task_excl.satisfied_by_node(s) assert task_excl.do_decrement(s) assert s.closed assert -1 == task_excl.minimum_space(s)
def test_custom_parser() -> None: ge_env = common_ge_env() qc = driver.HostgroupConstraint hg = Hostgroup("@htc_q_mpipg0", {"node.nodearray": "htc"}) bhg = BoundHostgroup(ge_env.queues["htc.q"], hg, 0) q = qc(bhg, bhg.name.replace("@", "pg0")) json_dump(q.to_dict()) expected_dict: Dict[str, Optional[Any]] = { "hostgroup-and-pg": { "hostgroup": "@htc_q_mpipg0", "user": None, "project": None, "placement-group": "pg0htc_q_mpipg0", "seq-no": 0, "constraints": [{ "nodearray": ["htc"] }], } } assert q.to_dict() == expected_dict parsed = constraints.get_constraint(q.to_dict()) assert parsed.hostgroups_set == q.hostgroups_set assert parsed.hostgroups_sorted == q.hostgroups_sorted assert parsed.placement_group == q.placement_group q = qc("htc.q", ["@htc.q", "@another"], None) expected_dict = { "hostgroups-and-pg": { "hostgroups": ["@another", "@htc.q"], # sort the hostgroups for consistency "placement-group": None, } } assert q.to_dict() == expected_dict parsed = constraints.get_constraint(q.to_dict()) assert parsed.hostgroups_set == q.hostgroups_set assert parsed.hostgroups_sorted == q.hostgroups_sorted assert parsed.placement_group == q.placement_group node = SchedulerNode( "tux", {"_gridengine_hostgroups": q.hostgroups_sorted}, ) assert q.satisfied_by_node(node) assert q.do_decrement(node) node = SchedulerNode( "tux", {"_gridengine_hostgroups": q.hostgroups_sorted}, ) node.placement_group = "pg0" assert not q.satisfied_by_node(node) node = SchedulerNode("tux", {}) node.exists = True assert not q.satisfied_by_node(node) node.exists = False assert q.satisfied_by_node(node) assert q.do_decrement(node) assert node.available["_gridengine_hostgroups"] == q.hostgroups_sorted assert node.software_configuration["gridengine_hostgroups"] == " ".join( q.hostgroups_sorted)