def test_brute(self): expected = list(range(99)) for size in range(1, len(expected) // 2): batches = list(tags.gen_batches(expected, size)) # Every element in the original list is present in the # reconsolidated list. observed = sorted(chain.from_iterable(batches)) self.assertSequenceEqual(expected, observed) # The longest batch is never more than 1 element longer # than the shortest batch. lens = [len(batch) for batch in batches] self.assertIn(max(lens) - min(lens), (0, 1))
def populate_tag_for_multiple_nodes(tag, nodes, batch_size=DEFAULT_BATCH_SIZE): """Reevaluate a single tag for a multiple nodes. Presumably this tag's expression has recently changed. Use `populate_tags` when many nodes need reevaluating AND there are rack controllers available to which to farm-out work. Use this only when many nodes need reevaluating locally, i.e. when there are no rack controllers connected. """ # Same expression, multuple documents: compile expression with XPath. xpath = etree.XPath(tag.definition, namespaces=tag_nsmap) # The XML details documents can be large so work in batches. for batch in gen_batches(nodes, batch_size): probed_details = get_probed_details(batch) probed_details_docs_by_node = { node: merge_details(probed_details[node.system_id]) for node in batch } nodes_matching, nodes_nonmatching = classify( partial(try_match_xpath, xpath, logger=maaslog), probed_details_docs_by_node.items()) tag.node_set.remove(*nodes_nonmatching) tag.node_set.add(*nodes_matching)
def test_more_things(self): self.assertSequenceEqual( [[0, 3, 6, 9], [1, 4, 7], [2, 5, 8]], list(tags.gen_batches(list(range(10)), 4)), )
def test_one_thing(self): self.assertSequenceEqual([[1]], list(tags.gen_batches([1], 4)))
def test_no_things(self): self.assertSequenceEqual([], list(tags.gen_batches([], 4)))
def test_batch_of_1_more_things(self): self.assertSequenceEqual([[1], [2], [3]], list(tags.gen_batches([1, 2, 3], 1)))