
First parameter should be the expected value. Partial-Bug: #1357117 Change-Id: I2c7345171571a063b649a319a18b1cd712ac6275
298 lines
11 KiB
Python
298 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright (C) 2014 Yahoo! Inc. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from taskflow.engines.action_engine import compiler
|
|
from taskflow.engines.action_engine import scopes as sc
|
|
from taskflow.patterns import graph_flow as gf
|
|
from taskflow.patterns import linear_flow as lf
|
|
from taskflow.patterns import unordered_flow as uf
|
|
from taskflow import test
|
|
from taskflow.tests import utils as test_utils
|
|
|
|
|
|
def _get_scopes(compilation, atom, names_only=True):
|
|
walker = sc.ScopeWalker(compilation, atom, names_only=names_only)
|
|
return list(iter(walker))
|
|
|
|
|
|
class LinearScopingTest(test.TestCase):
|
|
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_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))
|
|
|
|
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 test_nested_prior_linear_begin_middle_end(self):
|
|
r = lf.Flow("root")
|
|
begin_r = test_utils.TaskOneReturn("root.1")
|
|
r.add(begin_r, test_utils.TaskOneReturn("root.2"))
|
|
middle_r = test_utils.TaskOneReturn("root.3")
|
|
r.add(middle_r)
|
|
sub_r = lf.Flow("subroot")
|
|
sub_r.add(test_utils.TaskOneReturn("subroot.1"),
|
|
test_utils.TaskOneReturn("subroot.2"))
|
|
r.add(sub_r)
|
|
end_r = test_utils.TaskOneReturn("root.4")
|
|
r.add(end_r)
|
|
|
|
c = compiler.PatternCompiler(r).compile()
|
|
|
|
self.assertEqual([], _get_scopes(c, begin_r))
|
|
self.assertEqual([['root.2', 'root.1']], _get_scopes(c, middle_r))
|
|
self.assertEqual([['subroot.2', 'subroot.1', 'root.3', 'root.2',
|
|
'root.1']], _get_scopes(c, end_r))
|
|
|
|
|
|
class GraphScopingTest(test.TestCase):
|
|
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_no_visible(self):
|
|
r = gf.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_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))
|
|
|
|
|
|
class UnorderedScopingTest(test.TestCase):
|
|
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))
|
|
|
|
|
|
class MixedPatternScopingTest(test.TestCase):
|
|
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_linear_unordered_scope(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)
|
|
|
|
u = uf.Flow("subroot")
|
|
atoms = []
|
|
for i in range(0, 5):
|
|
atoms.append(test_utils.TaskOneReturn("subroot.%s" % i))
|
|
u.add(*atoms)
|
|
r.add(u)
|
|
|
|
r_3 = test_utils.TaskOneReturn("root.3")
|
|
r.add(r_3)
|
|
|
|
c = compiler.PatternCompiler(r).compile()
|
|
|
|
self.assertEqual([], _get_scopes(c, r_1))
|
|
self.assertEqual([['root.1']], _get_scopes(c, r_2))
|
|
for a in atoms:
|
|
self.assertEqual([[], ['root.2', 'root.1']], _get_scopes(c, a))
|
|
|
|
scope = _get_scopes(c, r_3)
|
|
self.assertEqual(1, len(scope))
|
|
first_root = 0
|
|
for i, n in enumerate(scope[0]):
|
|
if n.startswith('root.'):
|
|
first_root = i
|
|
break
|
|
first_subroot = 0
|
|
for i, n in enumerate(scope[0]):
|
|
if n.startswith('subroot.'):
|
|
first_subroot = i
|
|
break
|
|
self.assertGreater(first_subroot, first_root)
|
|
self.assertEqual(['root.2', 'root.1'], scope[0][-2:])
|
|
|
|
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_shadow_linear(self):
|
|
r = lf.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, customer2, washer)
|
|
|
|
c = compiler.PatternCompiler(r).compile()
|
|
|
|
# This order is guaranteed...
|
|
self.assertEqual(['customer2', 'customer'], _get_scopes(c, washer)[0])
|