http://scons.tigris.org/issues/show_bug.cgi?id=2345
[scons.git] / src / engine / SCons / JobTests.py
index 2ace9c31c12e83f5b71d8b4ae3b4875c4975710a..6e39d4bc413193d958c9bdaaf2dc9aea7b0b59f3 100644 (file)
@@ -20,6 +20,7 @@
 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
+from __future__ import generators  ### KEEP FOR COMPATIBILITY FIXERS
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
@@ -61,17 +62,20 @@ class Task:
         self.taskmaster = taskmaster
         self.was_executed = 0
         self.was_prepared = 0
-        
+
     def prepare(self):
         self.was_prepared = 1
 
     def _do_something(self):
         pass
 
+    def needs_execute(self):
+        return True
+
     def execute(self):
         self.taskmaster.test_case.failUnless(self.was_prepared,
                                   "the task wasn't prepared")
-        
+
         self.taskmaster.guard.acquire()
         self.taskmaster.begin_list.append(self.i)
         self.taskmaster.guard.release()
@@ -119,9 +123,12 @@ class ExceptionTask:
 
     def prepare(self):
         self.was_prepared = 1
-        
+
+    def needs_execute(self):
+        return True
+
     def execute(self):
-        raise "exception"
+        raise Exception
 
     def executed(self):
         self.taskmaster.num_executed = self.taskmaster.num_executed + 1
@@ -188,14 +195,6 @@ class Taskmaster:
     def all_tasks_are_postprocessed(self):
         return self.num_postprocessed == self.num_tasks
 
-    def is_blocked(self):
-        if self.stop or self.all_tasks_are_executed():
-            return 0
-        if self.all_tasks_are_iterated():
-            return 1
-        # simulate blocking tasks
-        return self.num_iterated - self.num_executed >= max(num_jobs/2, 2)
-
     def tasks_were_serial(self):
         "analyze the task order to see if they were serial"
         serial = 1 # assume the tasks were serial
@@ -208,6 +207,9 @@ class Taskmaster:
     def exception_set(self):
         pass
 
+    def cleanup(self):
+        pass
+
 SaveThreadPool = None
 ThreadPoolCallList = []
 
@@ -233,7 +235,7 @@ class ParallelTestCase(unittest.TestCase):
         self.failUnless(taskmaster.all_tasks_are_postprocessed(),
                         "all the tests were not postprocessed")
         self.failIf(taskmaster.num_failed,
-                    "some task(s) failed to execute") 
+                    "some task(s) failed to execute")
 
         # Verify that parallel jobs will pull all of the completed tasks
         # out of the queue at once, instead of one by one.  We do this by
@@ -267,16 +269,14 @@ class ParallelTestCase(unittest.TestCase):
             jobs.run()
 
             # The key here is that we get(1) and get(2) from the
-            # resultsQueue before we put(3).
+            # resultsQueue before we put(3), but get(1) and get(2) can
+            # be in either order depending on how the first two parallel
+            # tasks get scheduled by the operating system.
             expect = [
-                'put(1)',
-                'put(2)',
-                'get(1)',
-                'get(2)',
-                'put(3)',
-                'get(3)',
+                ['put(1)', 'put(2)', 'get(1)', 'get(2)', 'put(3)', 'get(3)'],
+                ['put(1)', 'put(2)', 'get(2)', 'get(1)', 'put(3)', 'get(3)'],
             ]
-            assert ThreadPoolCallList == expect, ThreadPoolCallList
+            assert ThreadPoolCallList in expect, ThreadPoolCallList
 
         finally:
             SCons.Job.ThreadPool = SaveThreadPool
@@ -298,19 +298,19 @@ class SerialTestCase(unittest.TestCase):
         self.failUnless(taskmaster.all_tasks_are_postprocessed(),
                         "all the tests were not postprocessed")
         self.failIf(taskmaster.num_failed,
-                    "some task(s) failed to execute") 
+                    "some task(s) failed to execute")
 
 class NoParallelTestCase(unittest.TestCase):
     def runTest(self):
         "test handling lack of parallel support"
-        def NoParallel(tm, num):
+        def NoParallel(tm, num, stack_size):
             raise NameError
         save_Parallel = SCons.Job.Parallel
         SCons.Job.Parallel = NoParallel
         try:
             taskmaster = Taskmaster(num_tasks, self, RandomTask)
             jobs = SCons.Job.Jobs(2, taskmaster)
-            self.failUnless(jobs.num_jobs == 1, 
+            self.failUnless(jobs.num_jobs == 1,
                             "unexpected number of jobs %d" % jobs.num_jobs)
             jobs.run()
             self.failUnless(taskmaster.tasks_were_serial(),
@@ -322,7 +322,7 @@ class NoParallelTestCase(unittest.TestCase):
             self.failUnless(taskmaster.all_tasks_are_postprocessed(),
                             "all the tests were not postprocessed")
             self.failIf(taskmaster.num_failed,
-                        "some task(s) failed to execute") 
+                        "some task(s) failed to execute")
         finally:
             SCons.Job.Parallel = save_Parallel
 
@@ -357,7 +357,7 @@ class ParallelExceptionTestCase(unittest.TestCase):
         self.failUnless(taskmaster.num_iterated >= 1,
                     "one or more task should have been iterated")
         self.failUnless(taskmaster.num_failed >= 1,
-                    "one or more tasks should have failed") 
+                    "one or more tasks should have failed")
         self.failUnless(taskmaster.num_postprocessed >= 1,
                     "one or more tasks should have been postprocessed")
 
@@ -369,14 +369,21 @@ import SCons.Taskmaster
 import SCons.Node
 import time
 
+class DummyNodeInfo:
+    def update(self, obj):
+        pass
 
 class testnode (SCons.Node.Node):
     def __init__(self):
         SCons.Node.Node.__init__(self)
         self.expect_to_be = SCons.Node.executed
+        self.ninfo = DummyNodeInfo()
 
 class goodnode (testnode):
-    pass
+    def __init__(self):
+        SCons.Node.Node.__init__(self)
+        self.expect_to_be = SCons.Node.up_to_date
+        self.ninfo = DummyNodeInfo()
 
 class slowgoodnode (goodnode):
     def prepare(self):
@@ -385,13 +392,13 @@ class slowgoodnode (goodnode):
         # by this test.
         time.sleep(0.15)
         goodnode.prepare(self)
-        
+
 class badnode (goodnode):
     def __init__(self):
         goodnode.__init__(self)
         self.expect_to_be = SCons.Node.failed
     def build(self, **kw):
-        raise 'badnode exception'
+        raise Exception('badnode exception')
 
 class slowbadnode (badnode):
     def build(self, **kw):
@@ -400,11 +407,11 @@ class slowbadnode (badnode):
         # it is faster than slowgoodnode then these could complete
         # while the scheduler is sleeping.
         time.sleep(0.05)
-        raise 'slowbadnode exception'
+        raise Exception('slowbadnode exception')
 
 class badpreparenode (badnode):
     def prepare(self):
-        raise 'badpreparenode exception'
+        raise Exception('badpreparenode exception')
 
 class _SConsTaskTest(unittest.TestCase):
 
@@ -431,12 +438,14 @@ class _SConsTaskTest(unittest.TestCase):
         for tnum in range(num_tasks):
             testnodes.append(node_seq[tnum % len(node_seq)]())
 
-        taskmaster = SCons.Taskmaster.Taskmaster(testnodes)
+        taskmaster = SCons.Taskmaster.Taskmaster(testnodes,
+                                                 tasker=SCons.Taskmaster.AlwaysTask)
+
         jobs = SCons.Job.Jobs(num_jobs, taskmaster)
 
         # Exceptions thrown by tasks are not actually propagated to
         # this level, but are instead stored in the Taskmaster.
-        
+
         jobs.run()
 
         # Now figure out if tests proceeded correctly.  The first test
@@ -479,10 +488,11 @@ class _SConsTaskTest(unittest.TestCase):
         # mislabelling of results).
 
         for N in testnodes:
-            self.failUnless(N.get_state() in [SCons.Node.no_state, N.expect_to_be],
-                            "node ran but got unexpected result")
+            state = N.get_state()
+            self.failUnless(state in [SCons.Node.no_state, N.expect_to_be],
+                            "Node %s got unexpected result: %s" % (N, state))
 
-        self.failUnless(filter(lambda N: N.get_state(), testnodes),
+        self.failUnless([N for N in testnodes if N.get_state()],
                         "no nodes ran at all.")
 
 
@@ -517,8 +527,14 @@ if __name__ == "__main__":
     result = runner.run(suite())
     if (len(result.failures) == 0
         and len(result.errors) == 1
-        and type(result.errors[0][0]) == SerialTestCase
-        and type(result.errors[0][1][0]) == NoThreadsException):
+        and isinstance(result.errors[0][0], SerialTestCase)
+        and isinstance(result.errors[0][1][0], NoThreadsException)):
         sys.exit(2)
     elif not result.wasSuccessful():
         sys.exit(1)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: