X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=src%2Fengine%2FSCons%2FTaskmasterTests.py;h=65d10b59ebafc032c02e60ca424363a709d31156;hb=704f6e2480ef60718f1aa42c266f04afc9c79580;hp=f3cb5f02a863bf8e95fc553edd3b10be53eecedf;hpb=9e4766b23bc76aa8147df825d024af06efe8007c;p=scons.git diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index f3cb5f02..65d10b59 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -46,6 +46,7 @@ class Node: self.scanned = 0 self.scanner = None self.targets = [self] + self.prerequisites = [] class Builder: def targets(self, node): return node.targets @@ -54,27 +55,44 @@ class Node: self.csig = None self.state = SCons.Node.no_state self.prepared = None - self.waiting_parents = [] + self.ref_count = 0 + self.waiting_parents = set() + self.waiting_s_e = set() self.side_effect = 0 self.side_effects = [] self.alttargets = [] self.postprocessed = None self._bsig_val = None self._current_val = 0 + self.always_build = None def disambiguate(self): return self + def push_to_cache(self): + pass + def retrieve_from_cache(self): global cache_text if self.cached: cache_text.append(self.name + " retrieved") return self.cached + def make_ready(self): + pass + + def prepare(self): + self.prepared = 1 + def build(self): global built_text built_text = self.name + " built" + def built(self): + global built_text + if not self.cached: + built_text = built_text + " really" + def has_builder(self): return not self.builder is None @@ -84,17 +102,10 @@ class Node: def alter_targets(self): return self.alttargets, None - def built(self): - global built_text - built_text = built_text + " really" - def visited(self): global visited_nodes visited_nodes.append(self.name) - def prepare(self): - self.prepared = 1 - def children(self): if not self.scanned: self.scan() @@ -109,14 +120,13 @@ class Node: def scanner_key(self): return self.name - + def add_to_waiting_parents(self, node): - self.waiting_parents.append(node) - - def call_for_all_waiting_parents(self, func): - func(self) - for parent in self.waiting_parents: - parent.call_for_all_waiting_parents(func) + wp = self.waiting_parents + if node in wp: + return 0 + wp.add(node) + return 1 def get_state(self): return self.state @@ -136,18 +146,11 @@ class Node: def store_bsig(self): pass - def calculator(self): - class Calc: - def bsig(self, node): - return node._bsig_val - def current(self, node, sig): - return node._current_val - return Calc() - - def current(self, calc=None): - if calc is None: - calc = self.calculator() - return calc.current(self, calc.bsig(self)) + def is_pseudo_derived(self): + pass + + def is_up_to_date(self): + return self._current_val def depends_on(self, nodes): for node in nodes: @@ -160,6 +163,29 @@ class Node: def postprocess(self): self.postprocessed = 1 + self.waiting_parents = set() + + def get_executor(self): + if not hasattr(self, 'executor'): + class Executor: + def prepare(self): + pass + def get_action_targets(self): + return self.targets + def get_all_targets(self): + return self.targets + def get_all_children(self): + result = [] + for node in self.targets: + result.extend(node.children()) + return result + def get_all_prerequisites(self): + return [] + def get_action_side_effects(self): + return [] + self.executor = Executor() + self.executor.targets = self.targets + return self.executor class OtherError(Exception): pass @@ -181,12 +207,12 @@ class TaskmasterTestCase(unittest.TestCase): t.prepare() t.execute() t = tm.next_task() - assert t == None + assert t is None n1 = Node("n1") n2 = Node("n2") n3 = Node("n3", [n1, n2]) - + tm = SCons.Taskmaster.Taskmaster([n3]) t = tm.next_task() @@ -194,20 +220,23 @@ class TaskmasterTestCase(unittest.TestCase): t.execute() assert built_text == "n1 built", built_text t.executed() + t.postprocess() t = tm.next_task() t.prepare() t.execute() assert built_text == "n2 built", built_text t.executed() + t.postprocess() t = tm.next_task() t.prepare() t.execute() assert built_text == "n3 built", built_text t.executed() + t.postprocess() - assert tm.next_task() == None + assert tm.next_task() is None built_text = "up to date: " top_node = n3 @@ -236,20 +265,23 @@ class TaskmasterTestCase(unittest.TestCase): t.execute() assert built_text == "n1 up-to-date", built_text t.executed() + t.postprocess() t = tm.next_task() t.prepare() t.execute() assert built_text == "n2 up-to-date", built_text t.executed() + t.postprocess() t = tm.next_task() t.prepare() t.execute() assert built_text == "n3 up-to-date top", built_text t.executed() + t.postprocess() - assert tm.next_task() == None + assert tm.next_task() is None n1 = Node("n1") @@ -259,55 +291,47 @@ class TaskmasterTestCase(unittest.TestCase): n5 = Node("n5", [n3, n4]) tm = SCons.Taskmaster.Taskmaster([n5]) - assert not tm.is_blocked() - t1 = tm.next_task() assert t1.get_target() == n1 - assert not tm.is_blocked() - + t2 = tm.next_task() assert t2.get_target() == n2 - assert not tm.is_blocked() t4 = tm.next_task() assert t4.get_target() == n4 - assert tm.is_blocked() t4.executed() - assert tm.is_blocked() - + t4.postprocess() + t1.executed() - assert tm.is_blocked() + t1.postprocess() t2.executed() - assert not tm.is_blocked() + t2.postprocess() t3 = tm.next_task() assert t3.get_target() == n3 - assert tm.is_blocked() t3.executed() - assert not tm.is_blocked() + t3.postprocess() t5 = tm.next_task() assert t5.get_target() == n5, t5.get_target() - assert tm.is_blocked() # still executing t5 t5.executed() - assert not tm.is_blocked() + t5.postprocess() + + assert tm.next_task() is None - assert tm.next_task() == None - n4 = Node("n4") n4.set_state(SCons.Node.executed) tm = SCons.Taskmaster.Taskmaster([n4]) - assert tm.next_task() == None + assert tm.next_task() is None n1 = Node("n1") n2 = Node("n2", [n1]) tm = SCons.Taskmaster.Taskmaster([n2,n2]) t = tm.next_task() - assert tm.is_blocked() t.executed() - assert not tm.is_blocked() + t.postprocess() t = tm.next_task() - assert tm.next_task() == None + assert tm.next_task() is None n1 = Node("n1") @@ -318,15 +342,18 @@ class TaskmasterTestCase(unittest.TestCase): target = t.get_target() assert target == n1, target t.executed() + t.postprocess() t = tm.next_task() target = t.get_target() assert target == n2, target t.executed() + t.postprocess() t = tm.next_task() target = t.get_target() assert target == n3, target t.executed() - assert tm.next_task() == None + t.postprocess() + assert tm.next_task() is None n1 = Node("n1") n2 = Node("n2") @@ -339,23 +366,27 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() assert t.get_target() == n1 t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n2 t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n3 t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n4 t.executed() - assert tm.next_task() == None + t.postprocess() + assert tm.next_task() is None assert scan_called == 4, scan_called tm = SCons.Taskmaster.Taskmaster([n5]) t = tm.next_task() assert t.get_target() == n5, t.get_target() t.executed() - assert tm.next_task() == None + assert tm.next_task() is None assert scan_called == 5, scan_called n1 = Node("n1") @@ -368,28 +399,26 @@ class TaskmasterTestCase(unittest.TestCase): tm = SCons.Taskmaster.Taskmaster([n1,n2,n3,n4,n5]) t = tm.next_task() assert t.get_target() == n1 - assert n4.state == SCons.Node.executing - assert tm.is_blocked() + assert n4.state == SCons.Node.executing, n4.state t.executed() - assert not tm.is_blocked() + t.postprocess() t = tm.next_task() assert t.get_target() == n2 - assert tm.is_blocked() t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n3 - assert tm.is_blocked() t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n4 - assert tm.is_blocked() t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n5 - assert tm.is_blocked() # still executing n5 assert not tm.next_task() t.executed() - assert not tm.is_blocked() + t.postprocess() n1 = Node("n1") n2 = Node("n2") @@ -402,31 +431,40 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() assert t.get_target() == n3, t.get_target() t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n2, t.get_target() t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n1, t.get_target() t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n4, t.get_target() t.executed() + t.postprocess() n5 = Node("n5") n6 = Node("n6") n7 = Node("n7") n6.alttargets = [n7] + tm = SCons.Taskmaster.Taskmaster([n5]) t = tm.next_task() assert t.get_target() == n5 t.executed() + t.postprocess() + tm = SCons.Taskmaster.Taskmaster([n6]) t = tm.next_task() assert t.get_target() == n7 t.executed() + t.postprocess() t = tm.next_task() assert t.get_target() == n6 t.executed() + t.postprocess() n1 = Node("n1") n2 = Node("n2", [n1]) @@ -441,9 +479,10 @@ class TaskmasterTestCase(unittest.TestCase): tm = SCons.Taskmaster.Taskmaster([n1]) t = tm.next_task() t.executed() + t.postprocess() s = n1.get_state() - assert s == SCons.Node.up_to_date, s + assert s == SCons.Node.executed, s s = n2.get_state() assert s == SCons.Node.executed, s @@ -467,7 +506,10 @@ class TaskmasterTestCase(unittest.TestCase): n3 = Node("n3") c4 = Node("c4") c4._current_val = 1 - tm = SCons.Taskmaster.Taskmaster(targets = [n1, c2, n3, c4], + a5 = Node("a5") + a5._current_val = 1 + a5.always_build = 1 + tm = SCons.Taskmaster.Taskmaster(targets = [n1, c2, n3, c4, a5], tasker = TaskGen) del ood[:] @@ -486,6 +528,9 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() assert ood == [], ood + del ood[:] + t = tm.next_task() + assert ood == [a5], ood def test_make_ready_exception(self): """Test handling exceptions from Task.make_ready() @@ -590,56 +635,19 @@ class TaskmasterTestCase(unittest.TestCase): def test_cycle_detection(self): """Test detecting dependency cycles - """ n1 = Node("n1") n2 = Node("n2", [n1]) n3 = Node("n3", [n2]) n1.kids = [n3] + tm = SCons.Taskmaster.Taskmaster([n3]) try: - tm = SCons.Taskmaster.Taskmaster([n3]) t = tm.next_task() except SCons.Errors.UserError, e: assert str(e) == "Dependency cycle: n3 -> n1 -> n2 -> n3", str(e) else: - assert 0 - - def test_is_blocked(self): - """Test whether a task is blocked - - Both default and overridden in a subclass. - """ - tm = SCons.Taskmaster.Taskmaster() - assert not tm.is_blocked() - - class MyTM(SCons.Taskmaster.Taskmaster): - def _find_next_ready_node(self): - self.ready = 1 - tm = MyTM() - assert not tm.is_blocked() - - class MyTM(SCons.Taskmaster.Taskmaster): - def _find_next_ready_node(self): - self.ready = None - self.pending = [] - self.executing = [] - tm = MyTM() - assert not tm.is_blocked() - - class MyTM(SCons.Taskmaster.Taskmaster): - def _find_next_ready_node(self): - self.ready = None - self.pending = [1] - tm = MyTM() - assert tm.is_blocked() - - class MyTM(SCons.Taskmaster.Taskmaster): - def _find_next_ready_node(self): - self.ready = None - self.executing = [1] - tm = MyTM() - assert tm.is_blocked() + assert 'Did not catch expected UserError' def test_next_top_level_candidate(self): """Test the next_top_level_candidate() method @@ -650,9 +658,9 @@ class TaskmasterTestCase(unittest.TestCase): tm = SCons.Taskmaster.Taskmaster([n3]) t = tm.next_task() - assert tm.executing == [n1], tm.executing + assert t.targets == [n1], t.targets t.fail_stop() - assert t.targets == [n3], t.targets + assert t.targets == [n3], list(map(str, t.targets)) assert t.top == 1, t.top def test_stop(self): @@ -665,13 +673,14 @@ class TaskmasterTestCase(unittest.TestCase): n1 = Node("n1") n2 = Node("n2") n3 = Node("n3", [n1, n2]) - + tm = SCons.Taskmaster.Taskmaster([n3]) t = tm.next_task() t.prepare() t.execute() assert built_text == "n1 built", built_text t.executed() + t.postprocess() assert built_text == "n1 built really", built_text tm.stop() @@ -696,16 +705,6 @@ class TaskmasterTestCase(unittest.TestCase): assert built_text == "MyTM.stop()" assert tm.next_task() is None - def test_failed(self): - """Test when a task has failed - """ - n1 = Node("n1") - tm = SCons.Taskmaster.Taskmaster([n1]) - t = tm.next_task() - assert tm.executing == [n1], tm.executing - tm.failed(n1) - assert tm.executing == [], tm.executing - def test_executed(self): """Test when a task has been executed """ @@ -724,7 +723,7 @@ class TaskmasterTestCase(unittest.TestCase): s = n1.get_state() assert s == SCons.Node.executed, s assert built_text == "xxx really", built_text - assert visited_nodes == [], visited_nodes + assert visited_nodes == ['n1'], visited_nodes n2 = Node("n2") tm = SCons.Taskmaster.Taskmaster([n2]) @@ -755,11 +754,10 @@ class TaskmasterTestCase(unittest.TestCase): assert s == SCons.Node.up_to_date, s s = n4.get_state() assert s == SCons.Node.executed, s - assert visited_nodes == ['n3'], visited_nodes + assert visited_nodes == ['n3', 'n4'], visited_nodes def test_prepare(self): """Test preparation of multiple Nodes for a task - """ n1 = Node("n1") n2 = Node("n2") @@ -771,7 +769,7 @@ class TaskmasterTestCase(unittest.TestCase): # set it up by having something that approximates a real Builder # return this list--but that's more work than is probably # warranted right now. - t.targets = [n1, n2] + n1.get_executor().targets = [n1, n2] t.prepare() assert n1.prepared assert n2.prepared @@ -782,7 +780,7 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() # More bogus reaching in and setting the targets. n3.set_state(SCons.Node.up_to_date) - t.targets = [n3, n4] + n3.get_executor().targets = [n3, n4] t.prepare() assert n3.prepared assert n4.prepared @@ -818,11 +816,11 @@ class TaskmasterTestCase(unittest.TestCase): n6.side_effects = [ n8 ] n7.side_effects = [ n9, n10 ] - + tm = SCons.Taskmaster.Taskmaster([n6, n7]) t = tm.next_task() # More bogus reaching in and setting the targets. - t.targets = [n6, n7] + n6.get_executor().targets = [n6, n7] t.prepare() assert n6.prepared assert n7.prepared @@ -830,9 +828,36 @@ class TaskmasterTestCase(unittest.TestCase): assert n9.prepared assert n10.prepared + # Make sure we call an Executor's prepare() method. + class ExceptionExecutor: + def prepare(self): + raise Exception, "Executor.prepare() exception" + def get_all_targets(self): + return self.nodes + def get_all_children(self): + result = [] + for node in self.nodes: + result.extend(node.children()) + return result + def get_all_prerequisites(self): + return [] + def get_action_side_effects(self): + return [] + + n11 = Node("n11") + n11.executor = ExceptionExecutor() + n11.executor.nodes = [n11] + tm = SCons.Taskmaster.Taskmaster([n11]) + t = tm.next_task() + try: + t.prepare() + except Exception, e: + assert str(e) == "Executor.prepare() exception", e + else: + raise AssertionError, "did not catch expected exception" + def test_execute(self): """Test executing a task - """ global built_text global cache_text @@ -882,12 +907,10 @@ class TaskmasterTestCase(unittest.TestCase): t.execute() except SCons.Errors.BuildError, e: assert e.node == n4, e.node - assert e.errstr == "Exception", e.errstr - assert len(e.args) == 3, `e.args` - assert e.args[0] == OtherError, e.args[0] - assert isinstance(e.args[1], OtherError), type(e.args[1]) + assert e.errstr == "OtherError : ", e.errstr + assert len(e.exc_info) == 3, e.exc_info exc_traceback = sys.exc_info()[2] - assert type(e.args[2]) == type(exc_traceback), e.args[2] + assert isinstance(e.exc_info[2], type(exc_traceback)), e.exc_info[2] else: raise TestFailed, "did not catch expected BuildError" @@ -955,37 +978,46 @@ class TaskmasterTestCase(unittest.TestCase): ] assert str(exc_value) in exception_values, exc_value - t.exception_set(("exception 1", None)) + class Exception1(Exception): + pass + + t.exception_set((Exception1, None)) try: t.exception_raise() except: exc_type, exc_value = sys.exc_info()[:2] - assert exc_type == "exception 1", exc_type - assert exc_value is None, exc_value + assert exc_type == Exception1, exc_type + assert str(exc_value) == '', exc_value else: assert 0, "did not catch expected exception" - t.exception_set(("exception 2", "xyzzy")) + class Exception2(Exception): + pass + + t.exception_set((Exception2, "xyzzy")) try: t.exception_raise() except: exc_type, exc_value = sys.exc_info()[:2] - assert exc_type == "exception 2", exc_type - assert exc_value == "xyzzy", exc_value + assert exc_type == Exception2, exc_type + assert str(exc_value) == "xyzzy", exc_value else: assert 0, "did not catch expected exception" + class Exception3(Exception): + pass + try: 1/0 except: tb = sys.exc_info()[2] - t.exception_set(("exception 3", "arg", tb)) + t.exception_set((Exception3, "arg", tb)) try: t.exception_raise() except: exc_type, exc_value, exc_tb = sys.exc_info() - assert exc_type == 'exception 3', exc_type - assert exc_value == "arg", exc_value + assert exc_type == Exception3, exc_type + assert str(exc_value) == "arg", exc_value import traceback x = traceback.extract_tb(tb)[-1] y = traceback.extract_tb(exc_tb)[-1] @@ -993,23 +1025,8 @@ class TaskmasterTestCase(unittest.TestCase): else: assert 0, "did not catch expected exception" - t.exception_set(("exception 4", "XYZZY")) - def fw_exc(exc): - raise 'exception_forwarded', exc - tm.exception_raise = fw_exc - try: - t.exception_raise() - except: - exc_type, exc_value = sys.exc_info()[:2] - assert exc_type == 'exception_forwarded', exc_type - assert exc_value[0] == "exception 4", exc_value[0] - assert exc_value[1] == "XYZZY", exc_value[1] - else: - assert 0, "did not catch expected exception" - def test_postprocess(self): """Test postprocessing targets to give them a chance to clean up - """ n1 = Node("n1") tm = SCons.Taskmaster.Taskmaster([n1]) @@ -1047,29 +1064,63 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() t.prepare() t.execute() + t.postprocess() n1.set_state(SCons.Node.executed) t = tm.next_task() t.prepare() t.execute() + t.postprocess() + n2.set_state(SCons.Node.executed) + t = tm.next_task() + t.prepare() + t.execute() + t.postprocess() t = tm.next_task() + assert t is None value = trace.getvalue() expect = """\ -Taskmaster: 'n1': children: - [] - evaluating -Taskmaster: 'n1': already handled -Taskmaster: 'n3': children: - ['n1', 'n2'] - waiting on unstarted children: - ['n2'] -Taskmaster: 'n2': children: - [] - evaluating -Taskmaster: 'n3': children: - ['n1', 'n2'] - waiting on unfinished children: - ['n2'] + +Taskmaster: Looking for a node to evaluate +Taskmaster: Considering node and its children: +Taskmaster: Evaluating + +Task.make_ready_current(): node +Task.prepare(): node +Task.execute(): node +Task.postprocess(): node + +Taskmaster: Looking for a node to evaluate +Taskmaster: Considering node and its children: +Taskmaster: already handled (executed) +Taskmaster: Considering node and its children: +Taskmaster: +Taskmaster: +Taskmaster: adjusted ref count: , child 'n2' +Taskmaster: Considering node and its children: +Taskmaster: Evaluating + +Task.make_ready_current(): node +Task.prepare(): node +Task.execute(): node +Task.postprocess(): node +Task.postprocess(): removing +Task.postprocess(): adjusted parent ref count + +Taskmaster: Looking for a node to evaluate +Taskmaster: Considering node and its children: +Taskmaster: +Taskmaster: +Taskmaster: Evaluating + +Task.make_ready_current(): node +Task.prepare(): node +Task.execute(): node +Task.postprocess(): node + +Taskmaster: Looking for a node to evaluate +Taskmaster: No candidate anymore. + """ assert value == expect, value @@ -1079,3 +1130,9 @@ if __name__ == "__main__": suite = unittest.makeSuite(TaskmasterTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): sys.exit(1) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: