def test_retry_in_graph_flow_with_tasks(self): r = retry.AlwaysRevert("r") a, b, c = test_utils.make_many(3) flo = gf.Flow("test", r).add(a, b, c).link(b, c) g = _replicate_graph_with_names( compiler.PatternCompiler(flo).compile()) self.assertItemsEqual(g.edges(data=True), [ ('test', 'r', { 'invariant': True }), ('r', 'a', { 'invariant': True, 'retry': True }), ('r', 'b', { 'invariant': True, 'retry': True }), ('b', 'c', { 'manual': True }), ('a', 'test[$]', { 'invariant': True }), ('c', 'test[$]', { 'invariant': True }), ]) self.assertItemsEqual(['test'], g.no_predecessors_iter()) self.assertItemsEqual(['test[$]'], g.no_successors_iter()) self.assertIs(r, g.node['a']['retry']) self.assertIs(r, g.node['b']['retry']) self.assertIs(r, g.node['c']['retry'])
def test_invalid(self): a, b, c = test_utils.make_many(3) flo = lf.Flow("test") flo.add(a, b, c) flo.add(flo) self.assertRaises(ValueError, compiler.PatternCompiler(flo).compile)
def test_many_empty_in_graph_flow(self): flow = gf.Flow('root') a = test_utils.ProvidesRequiresTask('a', provides=[], requires=[]) flow.add(a) b = lf.Flow('b') b_0 = test_utils.ProvidesRequiresTask('b.0', provides=[], requires=[]) b_3 = test_utils.ProvidesRequiresTask('b.3', provides=[], requires=[]) b.add( b_0, lf.Flow('b.1'), lf.Flow('b.2'), b_3, ) flow.add(b) c = lf.Flow('c') c.add(lf.Flow('c.0'), lf.Flow('c.1'), lf.Flow('c.2')) flow.add(c) d = test_utils.ProvidesRequiresTask('d', provides=[], requires=[]) flow.add(d) flow.link(b, d) flow.link(a, d) flow.link(c, d) compilation = compiler.PatternCompiler(flow).compile() g = compilation.execution_graph self.assertTrue(g.has_edge(b_0, b_3)) self.assertTrue(g.has_edge(b_3, d)) self.assertEqual(4, len(g))
def test_retries_hierarchy(self): c1 = retry.AlwaysRevert("c1") c2 = retry.AlwaysRevert("c2") a, b, c, d = test_utils.make_many(4) inner_flo = lf.Flow("test2", c2).add(b, c) flo = lf.Flow("test", c1).add(a, inner_flo, d) g = _replicate_graph_with_names( compiler.PatternCompiler(flo).compile()) self.assertEqual(10, len(g)) self.assertItemsEqual(g.edges(data=True), [ ('test', 'c1', {'invariant': True}), ('c1', 'a', {'invariant': True, 'retry': True}), ('a', 'test2', {'invariant': True}), ('test2', 'c2', {'invariant': True}), ('c2', 'b', {'invariant': True, 'retry': True}), ('b', 'c', {'invariant': True}), ('c', 'test2[$]', {'invariant': True}), ('test2[$]', 'd', {'invariant': True}), ('d', 'test[$]', {'invariant': True}), ]) self.assertIs(c1, g.node['a']['retry']) self.assertIs(c1, g.node['d']['retry']) self.assertIs(c2, g.node['b']['retry']) self.assertIs(c2, g.node['c']['retry']) self.assertIs(c1, g.node['c2']['retry']) self.assertIsNone(g.node['c1'].get('retry'))
def test_retry_in_graph_flow_with_tasks(self): r = retry.AlwaysRevert("cp") a, b, c = test_utils.make_many(3) flo = gf.Flow("test", r).add(a, b, c).link(b, c) compilation = compiler.PatternCompiler(flo).compile() g = compilation.execution_graph self.assertEqual(5, len(g)) self.assertItemsEqual(g.edges(data=True), [(flo, r, { 'invariant': True }), (r, a, { 'invariant': True, 'retry': True }), (r, b, { 'invariant': True, 'retry': True }), (b, c, { 'manual': True })]) self.assertItemsEqual([flo], g.no_predecessors_iter()) self.assertItemsEqual([a, c], g.no_successors_iter()) self.assertIs(r, g.node[a]['retry']) self.assertIs(r, g.node[b]['retry']) self.assertIs(r, g.node[c]['retry'])
def test_retry_in_unordered_flow_with_tasks(self): c = retry.AlwaysRevert("c") a, b = test_utils.make_many(2) flo = uf.Flow("test", c).add(a, b) compilation = compiler.PatternCompiler(flo).compile() g = compilation.execution_graph self.assertEqual(4, len(g)) self.assertItemsEqual(g.edges(data=True), [ (flo, c, { 'invariant': True }), (c, a, { 'invariant': True, 'retry': True }), (c, b, { 'invariant': True, 'retry': True }), ]) self.assertItemsEqual([flo], g.no_predecessors_iter()) self.assertItemsEqual([a, b], g.no_successors_iter()) self.assertIs(c, g.node[a]['retry']) self.assertIs(c, g.node[b]['retry'])
def test_retry_in_unordered_flow_with_tasks(self): c = retry.AlwaysRevert("c") a, b = test_utils.make_many(2) flo = uf.Flow("test", c).add(a, b) g = _replicate_graph_with_names( compiler.PatternCompiler(flo).compile()) self.assertEqual(5, len(g)) self.assertItemsEqual(g.edges(data=True), [ ('test', 'c', { 'invariant': True }), ('c', 'a', { 'invariant': True, 'retry': True }), ('c', 'b', { 'invariant': True, 'retry': True }), ('b', 'test[$]', { 'invariant': True }), ('a', 'test[$]', { 'invariant': True }), ]) self.assertItemsEqual(['test'], list(g.no_predecessors_iter())) self.assertItemsEqual(['test[$]'], list(g.no_successors_iter())) self.assertIs(c, g.node['a']['retry']) self.assertIs(c, g.node['b']['retry'])
def test_retry_in_nested_flows(self): c1 = retry.AlwaysRevert("c1") c2 = retry.AlwaysRevert("c2") inner_flo = lf.Flow("test2", c2) flo = lf.Flow("test", c1).add(inner_flo) g = _replicate_graph_with_names( compiler.PatternCompiler(flo).compile()) self.assertEqual(6, len(g)) self.assertItemsEqual(g.edges(data=True), [ ('test', 'c1', { 'invariant': True }), ('c1', 'test2', { 'invariant': True, 'retry': True }), ('test2', 'c2', { 'invariant': True }), ('c2', 'test2[$]', { 'invariant': True }), ('test2[$]', 'test[$]', { 'invariant': True }), ]) self.assertIs(c1, g.node['c2']['retry']) self.assertItemsEqual(['test'], list(g.no_predecessors_iter())) self.assertItemsEqual(['test[$]'], list(g.no_successors_iter()))
def test_graph_nested_graph(self): a, b, c, d, e, f, g = test_utils.make_many(7) flo = gf.Flow("test") flo.add(a, b, c, d) flo2 = gf.Flow('test2') flo2.add(e, f, g) flo.add(flo2) g = _replicate_graph_with_names( compiler.PatternCompiler(flo).compile()) self.assertEqual(11, len(g)) self.assertItemsEqual(g.edges(), [ ('test', 'a'), ('test', 'b'), ('test', 'c'), ('test', 'd'), ('test', 'test2'), ('test2', 'e'), ('test2', 'f'), ('test2', 'g'), ('e', 'test2[$]'), ('f', 'test2[$]'), ('g', 'test2[$]'), ('test2[$]', 'test[$]'), ('a', 'test[$]'), ('b', 'test[$]'), ('c', 'test[$]'), ('d', 'test[$]'), ])
def test_graph_links(self): a, b, c, d = test_utils.make_many(4) flo = gf.Flow("test") flo.add(a, b, c, d) flo.link(a, b) flo.link(b, c) flo.link(c, d) compilation = compiler.PatternCompiler(flo).compile() g = compilation.execution_graph self.assertEqual(5, len(g)) self.assertItemsEqual(g.edges(data=True), [ (flo, a, { 'invariant': True }), (a, b, { 'manual': True }), (b, c, { 'manual': True }), (c, d, { 'manual': True }), ]) self.assertItemsEqual([flo], g.no_predecessors_iter()) self.assertItemsEqual([d], g.no_successors_iter())
def test_graph_linear_scope(self): r = gf.Flow("root") r_1 = test_utils.TaskOneReturn("root.1") r_2 = test_utils.TaskOneReturn("root.2") r.add(r_1, r_2) r.link(r_1, r_2) s = lf.Flow("subroot") s_1 = test_utils.TaskOneReturn("subroot.1") s_2 = test_utils.TaskOneReturn("subroot.2") s.add(s_1, s_2) r.add(s) t = gf.Flow("subroot2") t_1 = test_utils.TaskOneReturn("subroot2.1") t_2 = test_utils.TaskOneReturn("subroot2.2") t.add(t_1, t_2) t.link(t_1, t_2) r.add(t) r.link(s, t) c = compiler.PatternCompiler(r).compile() self.assertEqual([], _get_scopes(c, r_1)) self.assertEqual([['root.1']], _get_scopes(c, r_2)) self.assertEqual([], _get_scopes(c, s_1)) self.assertEqual([['subroot.1']], _get_scopes(c, s_2)) self.assertEqual([[], ['subroot.2', 'subroot.1']], _get_scopes(c, t_1)) self.assertEqual([["subroot2.1"], ['subroot.2', 'subroot.1']], _get_scopes(c, t_2))
def test_graph_links(self): a, b, c, d = test_utils.make_many(4) flo = gf.Flow("test") flo.add(a, b, c, d) flo.link(a, b) flo.link(b, c) flo.link(c, d) g = _replicate_graph_with_names( compiler.PatternCompiler(flo).compile()) self.assertEqual(6, len(g)) self.assertItemsEqual(g.edges(data=True), [ ('test', 'a', { 'invariant': True }), ('a', 'b', { 'manual': True }), ('b', 'c', { 'manual': True }), ('c', 'd', { 'manual': True }), ('d', 'test[$]', { 'invariant': True }), ]) self.assertItemsEqual(['test'], g.no_predecessors_iter()) self.assertItemsEqual(['test[$]'], g.no_successors_iter())
def test_shadow_graph(self): r = gf.Flow("root") customer = test_utils.ProvidesRequiresTask("customer", provides=['dog'], requires=[]) customer2 = test_utils.ProvidesRequiresTask("customer2", provides=['dog'], requires=[]) washer = test_utils.ProvidesRequiresTask("washer", requires=['dog'], provides=['wash']) r.add(customer, washer) r.add(customer2, resolve_requires=False) r.link(customer2, washer) c = compiler.PatternCompiler(r).compile() # The order currently is *not* guaranteed to be 'customer' before # 'customer2' or the reverse, since either can occur before the # washer; since *either* is a valid topological ordering of the # dependencies... # # This may be different after/if the following is resolved: # # https://github.com/networkx/networkx/issues/1181 (and a few others) self.assertEqual(set(['customer', 'customer2']), set(_get_scopes(c, washer)[0])) self.assertEqual([], _get_scopes(c, customer2)) self.assertEqual([], _get_scopes(c, customer))
def test_nested(self): r = gf.Flow("root") r_1 = test_utils.TaskOneReturn("root.1") r_2 = test_utils.TaskOneReturn("root.2") r.add(r_1, r_2) r.link(r_1, r_2) subroot = gf.Flow("subroot") subroot_r_1 = test_utils.TaskOneReturn("subroot.1") subroot_r_2 = test_utils.TaskOneReturn("subroot.2") subroot.add(subroot_r_1, subroot_r_2) subroot.link(subroot_r_1, subroot_r_2) r.add(subroot) r_3 = test_utils.TaskOneReturn("root.3") r.add(r_3) r.link(r_2, r_3) c = compiler.PatternCompiler(r).compile() self.assertEqual([], _get_scopes(c, r_1)) self.assertEqual([['root.1']], _get_scopes(c, r_2)) self.assertEqual([['root.2', 'root.1']], _get_scopes(c, r_3)) self.assertEqual([], _get_scopes(c, subroot_r_1)) self.assertEqual([['subroot.1']], _get_scopes(c, subroot_r_2))
def test_graph_nested_provides(self): a = test_utils.ProvidesRequiresTask('a', provides=[], requires=['x']) b = test_utils.ProvidesRequiresTask('b', provides=['x'], requires=[]) c = test_utils.ProvidesRequiresTask('c', provides=[], requires=[]) inner_flo = lf.Flow("test2").add(b, c) flo = gf.Flow("test").add(a, inner_flo) compilation = compiler.PatternCompiler(flo).compile() graph = compilation.execution_graph self.assertEqual(5, len(graph)) self.assertItemsEqual(graph.edges(data=True), [ (flo, inner_flo, { 'invariant': True }), (inner_flo, b, { 'invariant': True }), (b, c, { 'invariant': True }), (c, a, { 'reasons': set(['x']) }), ]) self.assertItemsEqual([flo], graph.no_predecessors_iter()) self.assertItemsEqual([a], graph.no_successors_iter())
def test_dependent(self): r = gf.Flow("root") customer = test_utils.ProvidesRequiresTask("customer", provides=['dog'], requires=[]) washer = test_utils.ProvidesRequiresTask("washer", requires=['dog'], provides=['wash']) dryer = test_utils.ProvidesRequiresTask("dryer", requires=['dog', 'wash'], provides=['dry_dog']) shaved = test_utils.ProvidesRequiresTask("shaver", requires=['dry_dog'], provides=['shaved_dog']) happy_customer = test_utils.ProvidesRequiresTask( "happy_customer", requires=['shaved_dog'], provides=['happiness']) r.add(customer, washer, dryer, shaved, happy_customer) c = compiler.PatternCompiler(r).compile() self.assertEqual([], _get_scopes(c, customer)) self.assertEqual([['washer', 'customer']], _get_scopes(c, dryer)) self.assertEqual([['shaver', 'dryer', 'washer', 'customer']], _get_scopes(c, happy_customer))
def test_graph_nested_requires(self): a = test_utils.ProvidesRequiresTask('a', provides=['x'], requires=[]) b = test_utils.ProvidesRequiresTask('b', provides=[], requires=[]) c = test_utils.ProvidesRequiresTask('c', provides=[], requires=['x']) inner_flo = lf.Flow("test2").add(b, c) flo = gf.Flow("test").add(a, inner_flo) g = _replicate_graph_with_names( compiler.PatternCompiler(flo).compile()) self.assertEqual(7, len(g)) self.assertItemsEqual(g.edges(data=True), [ ('test', 'a', { 'invariant': True }), ('test2', 'b', { 'invariant': True }), ('a', 'test2', { 'reasons': set(['x']) }), ('b', 'c', { 'invariant': True }), ('c', 'test2[$]', { 'invariant': True }), ('test2[$]', 'test[$]', { 'invariant': True }), ]) self.assertItemsEqual(['test'], list(g.no_predecessors_iter())) self.assertItemsEqual(['test[$]'], list(g.no_successors_iter()))
def test_retry_subflows_hierarchy(self): c1 = retry.AlwaysRevert("cp1") a, b, c, d = test_utils.make_many(4) flo = lf.Flow("test", c1).add(a, lf.Flow("test").add(b, c), d) compilation = compiler.PatternCompiler(flo).compile() g = compilation.execution_graph self.assertEqual(5, len(g)) self.assertItemsEqual(g.edges(data=True), [ (c1, a, { 'retry': True }), (a, b, { 'invariant': True }), (b, c, { 'invariant': True }), (c, d, { 'invariant': True }), ]) self.assertIs(c1, g.node[a]['retry']) self.assertIs(c1, g.node[d]['retry']) self.assertIs(c1, g.node[b]['retry']) self.assertIs(c1, g.node[c]['retry']) self.assertIs(None, g.node[c1].get('retry'))
def test_graph(self): a, b, c, d = test_utils.make_many(4) flo = gf.Flow("test") flo.add(a, b, c, d) compilation = compiler.PatternCompiler(flo).compile() self.assertEqual(6, len(compilation.execution_graph)) self.assertEqual(8, compilation.execution_graph.number_of_edges())
def test_unknown(self): r = lf.Flow("root") r_1 = test_utils.TaskOneReturn("root.1") r.add(r_1) r_2 = test_utils.TaskOneReturn("root.2") c = compiler.PatternCompiler(r).compile() self.assertRaises(ValueError, _get_scopes, c, r_2)
def test_unordered_nested_in_linear(self): a, b, c, d = test_utils.make_many(4) flo = lf.Flow('lt').add(a, uf.Flow('ut').add(b, c), d) compilation = compiler.PatternCompiler(flo).compile() g = compilation.execution_graph self.assertEqual(4, len(g)) self.assertItemsEqual(g.edges(), [(a, b), (a, c), (b, d), (c, d)])
def test_no_visible(self): r = uf.Flow("root") atoms = [] for i in range(0, 10): atoms.append(test_utils.TaskOneReturn("root.%s" % i)) r.add(*atoms) c = compiler.PatternCompiler(r).compile() for a in atoms: self.assertEqual([], _get_scopes(c, a))
def test_unordered(self): a, b, c, d = test_utils.make_many(4) flo = uf.Flow("test") flo.add(a, b, c, d) compilation = compiler.PatternCompiler(flo).compile() g = compilation.execution_graph self.assertEqual(4, len(g)) self.assertEqual(0, g.number_of_edges()) self.assertEqual(set([a, b, c, d]), set(g.no_successors_iter())) self.assertEqual(set([a, b, c, d]), set(g.no_predecessors_iter()))
def test_empty_flow_in_graph_flow(self): flow = lf.Flow('lf') a = test_utils.ProvidesRequiresTask('a', provides=['a'], requires=[]) b = test_utils.ProvidesRequiresTask('b', provides=[], requires=['a']) empty_flow = lf.Flow("empty") flow.add(a, empty_flow, b) compilation = compiler.PatternCompiler(flow).compile() g = compilation.execution_graph self.assertTrue(g.has_edge(a, b))
def test_empty_flow_in_graph_flow_empty_linkage(self): flow = gf.Flow('lf') a = test_utils.ProvidesRequiresTask('a', provides=[], requires=[]) b = test_utils.ProvidesRequiresTask('b', provides=[], requires=[]) empty_flow = lf.Flow("empty") flow.add(a, empty_flow, b) flow.link(empty_flow, b) compilation = compiler.PatternCompiler(flow).compile() g = compilation.execution_graph self.assertEqual(0, len(g.edges()))
def test_nested_prior_linear(self): r = lf.Flow("root") r.add(test_utils.TaskOneReturn("root.1"), test_utils.TaskOneReturn("root.2")) sub_r = lf.Flow("subroot") sub_r_1 = test_utils.TaskOneReturn("subroot.1") sub_r.add(sub_r_1) r.add(sub_r) c = compiler.PatternCompiler(r).compile() self.assertEqual([[], ['root.2', 'root.1']], _get_scopes(c, sub_r_1))
def __init__(self, flow, flow_detail, backend, options): super(ActionEngine, self).__init__(flow, flow_detail, backend, options) self._runtime = None self._compiled = False self._compilation = None self._compiler = compiler.PatternCompiler(flow) self._lock = threading.RLock() self._state_lock = threading.RLock() self._storage_ensured = False # Retries are not *currently* executed out of the engines process # or thread (this could change in the future if we desire it to). self._retry_executor = executor.SerialRetryExecutor()
def test_retry_in_nested_flows(self): c1 = retry.AlwaysRevert("c1") c2 = retry.AlwaysRevert("c2") flo = lf.Flow("test", c1).add(lf.Flow("test2", c2)) compilation = compiler.PatternCompiler(flo).compile() g = compilation.execution_graph self.assertEqual(2, len(g)) self.assertItemsEqual(g.edges(data=True), [(c1, c2, {'retry': True})]) self.assertIs(c1, g.node[c2]['retry']) self.assertItemsEqual([c1], g.no_predecessors_iter()) self.assertItemsEqual([c2], g.no_successors_iter())
def test_empty(self): r = lf.Flow("root") r_1 = test_utils.TaskOneReturn("root.1") r.add(r_1) c = compiler.PatternCompiler(r).compile() self.assertIn(r_1, c.execution_graph) self.assertIsNotNone(c.hierarchy.find(r_1)) walker = sc.ScopeWalker(c, r_1) scopes = list(walker) self.assertEqual([], scopes)
def test_single_prior_linear(self): r = lf.Flow("root") r_1 = test_utils.TaskOneReturn("root.1") r_2 = test_utils.TaskOneReturn("root.2") r.add(r_1, r_2) c = compiler.PatternCompiler(r).compile() for a in r: self.assertIn(a, c.execution_graph) self.assertIsNotNone(c.hierarchy.find(a)) self.assertEqual([], _get_scopes(c, r_1)) self.assertEqual([['root.1']], _get_scopes(c, r_2))