You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@gump.apache.org by le...@apache.org on 2005/07/12 23:11:01 UTC
svn commit: r216018 - in /gump/branches/Gump3/pygump/python/gump:
engine/verifier.py test/testEngineVerifier.py
Author: leosimons
Date: Tue Jul 12 14:11:00 2005
New Revision: 216018
URL: http://svn.apache.org/viewcvs?rev=216018&view=rev
Log:
100% coverage for the verifier and fix it to report on all cycles (fix for GUMP-94).
Modified:
gump/branches/Gump3/pygump/python/gump/engine/verifier.py
gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py
Modified: gump/branches/Gump3/pygump/python/gump/engine/verifier.py
URL: http://svn.apache.org/viewcvs/gump/branches/Gump3/pygump/python/gump/engine/verifier.py?rev=216018&r1=216017&r2=216018&view=diff
==============================================================================
--- gump/branches/Gump3/pygump/python/gump/engine/verifier.py (original)
+++ gump/branches/Gump3/pygump/python/gump/engine/verifier.py Tue Jul 12 14:11:00 2005
@@ -44,15 +44,14 @@
pass
def print_cyclic_trace(cycles, handler):
- for cycle in cycles: # isn't there a level of nesting too much here???
- for chain in cycle:
- msg = ""
- indent = " "
- for project in chain:
- msg += "%s%s -->\n" % (indent, project.name)
- indent += " "
- msg = ansicolor.Bright_Red + msg[:-5] + ansicolor.Black
- handler(msg)
+ for chain in cycles:
+ msg = ""
+ indent = " "
+ for project in chain:
+ msg += "%s%s -->\n" % (indent, project.name)
+ indent += " "
+ msg = ansicolor.Bright_Red + msg[:-5] + ansicolor.Black
+ handler(msg)
class AbstractErrorHandler:
"""Base class for supporting configurable error recovery. Instead of
@@ -79,7 +78,7 @@
def handleError(self):
errorType = sys.exc_info()[0]
if errorType is CyclicDependencyError:
- errorValue = sys.exc_info()[1]
+ errorValue = sys.exc_info()[1][0]
self.log.error("The following cyclic dependencies were found:")
print_cyclic_trace(errorValue, self.log.error)
self.log.error("The projects involved will not be built!")
@@ -96,6 +95,8 @@
def __init__(self, walker, errorHandler=AbstractErrorHandler()):
assert hasattr(walker, "walk")
assert callable(walker.walk)
+ assert hasattr(errorHandler, "_handleError")
+ assert callable(errorHandler._handleError)
self.walker = walker
self.errorHandler = errorHandler
@@ -160,10 +161,12 @@
stack.append(dependency)
if dependency == needle: # cycle involving needle!
cycles.append(stack[:])
- visited.append(dependency)
+ # no need for this, its already in there visited.append(dependency)
else:
if not dependency in visited:
- self._visit(dependency,visited,stack,needle,cycles)
+ # note we duplicate the visited[] array here. There may be
+ # multiple cycles involving this project. We want them all.
+ self._visit(dependency,visited[:],stack,needle,cycles)
stack.pop() # get rid of this dependency, we'll be looking
# at the next dependency in the next iteration of
Modified: gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py
URL: http://svn.apache.org/viewcvs/gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py?rev=216018&r1=216017&r2=216018&view=diff
==============================================================================
--- gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py (original)
+++ gump/branches/Gump3/pygump/python/gump/test/testEngineVerifier.py Tue Jul 12 14:11:00 2005
@@ -22,12 +22,249 @@
import unittest
from pmock import *
-from gump.engine.verifier import *
+from gump.engine.verifier import VerificationError
+from gump.engine.verifier import CyclicDependencyError
+from gump.engine.verifier import print_cyclic_trace
+from gump.engine.verifier import AbstractErrorHandler
+from gump.engine.verifier import LoggingErrorHandler
+from gump.engine.verifier import Verifier
+
+class Project:
+ def __init__(self, name):
+ self.name = name
+ self.dependencies = []
+
+ def __str__(self):
+ return "project:%s" % self.name
+
+class Relationship:
+ def __init__(self, project):
+ self.dependency = project
+
+ def __rel__(self):
+ return "relationship:dependency=%s" % self.dependency
+
+class MyError(Exception):
+ pass
+
+counter = 0
+def p():
+ global counter
+ counter = counter + 1
+ return Project("project_%s" % counter)
+
+def r(p):
+ return Relationship(p)
class EngineVerifierTestCase(MockTestCase):
def setUp(self):
- pass
+ self.walker = self.mock()
+ self.walker.stubs().method("walk")
+ self.handler = self.mock()
+ self.handler.stubs().method("_handleError")
- def test_something(self):
- # TODO replace with something useful
- pass
+ def test_VerificationError(self):
+ e = VerificationError()
+
+ def test_CyclicDependencyError(self):
+ e = CyclicDependencyError()
+
+ def test_print_cyclic_trace(self):
+ def handler(msg):
+ pass
+
+ cycles = []
+ p1 = p()
+ p2 = p()
+ cycles.append([p1, p(), p(), p1])
+ cycles.append([p2, p(), p(), p(), p(), p(), p2])
+ print_cyclic_trace(cycles, handler)
+
+
+ def test_AbstractErrorHandler(self):
+ called = []
+ def handleError(called=called):
+ called.append(1)
+
+ e = AbstractErrorHandler()
+ e.handleError = handleError
+ e._handleError()
+ self.failUnless(len(called) == 1)
+
+ e = AbstractErrorHandler()
+ try:
+ raise MyError, "problem"
+ except:
+ try:
+ e._handleError()
+ self.fail("Exception swallowed")
+ except MyError:
+ pass
+
+
+ def test_LoggingErrorHandler(self):
+ log = self.mock()
+ log.expects(at_least_once()).method("error")
+
+ e = LoggingErrorHandler(log)
+ cycles = []
+ cycle = []
+ cycle.append(Project("a"))
+ cycle.append(Project("b"))
+ cycles.append(cycle)
+
+ try:
+ raise CyclicDependencyError, cycles
+ except:
+ e._handleError()
+
+ try:
+ raise MyError, "problem"
+ except:
+ try:
+ e._handleError()
+ self.fail("Exception swallowed")
+ except MyError:
+ pass
+
+ def test_Verifier__init__(self):
+ v = Verifier(self.walker, self.handler)
+ self.assertEqual(self.walker, v.walker)
+ self.assertEqual(self.handler, v.errorHandler)
+ self.assertRaises(AssertionError, Verifier, None, self.handler)
+ self.assertRaises(AssertionError, Verifier, self.walker, None)
+
+ def test_Verifier_verify(self):
+ v = Verifier(self.walker, self.handler)
+
+ p1 = p()
+ p2 = p()
+ p3 = p()
+ p4 = p()
+ p5 = p()
+ p6 = p()
+ p7 = p()
+ p8 = p()
+ p9 = p()
+ p10 = p()
+
+ p1.dependencies.append(r(p2))
+ p1.dependencies.append(r(p3))
+ #p1.dependencies.append(r(p4))
+ p1.dependencies.append(r(p5))
+ p1.dependencies.append(r(p6))
+
+ #p2.dependencies.append(r(p3))
+ #p2.dependencies.append(r(p4))
+ p2.dependencies.append(r(p5))
+ p2.dependencies.append(r(p6))
+
+ #p3.dependencies.append(r(p3))
+ p3.dependencies.append(r(p4))
+ p3.dependencies.append(r(p5))
+ p3.dependencies.append(r(p6))
+ #p3.dependencies.append(r(p7))
+ p3.dependencies.append(r(p8))
+ p3.dependencies.append(r(p9))
+ #p3.dependencies.append(r(p10))
+
+ p4.dependencies.append(r(p5))
+ p4.dependencies.append(r(p6))
+ p4.dependencies.append(r(p7))
+ p4.dependencies.append(r(p8))
+ p4.dependencies.append(r(p9))
+ #p4.dependencies.append(r(p10))
+
+ p7.dependencies.append(r(p8))
+ p7.dependencies.append(r(p9))
+ p7.dependencies.append(r(p10))
+
+ visited = []
+ project = p1
+ stack = [p1]
+ needle = p1
+ cycles = []
+
+ # first we test the internal _visit()
+ v._visit(project,visited,stack,needle,cycles)
+ self.assertEqual(len(cycles), 0)
+
+ # introduce a cycle
+ p10.dependencies.append(r(p1))
+ visited = []
+ project = p1
+ stack = [p1]
+ needle = p1
+ cycles = []
+
+ v._visit(project,visited,stack,needle,cycles)
+ self.assertEqual(len(cycles), 1)
+ cycle = cycles[0]
+ self.assertEqual(p1,cycle[0])
+ self.assertEqual(p3,cycle[1])
+ self.assertEqual(p4,cycle[2])
+ self.assertEqual(p7,cycle[3])
+ self.assertEqual(p10,cycle[4])
+ self.assertEqual(p1,cycle[5])
+
+ # introduce more cycles, and more complex ones
+ p2.dependencies.append(r(p1))
+ p3.dependencies.append(r(p1))
+ p2.dependencies.append(r(p3))
+ visited = []
+ project = p1
+ stack = [p1]
+ needle = p1
+ cycles = []
+
+ v._visit(project,visited,stack,needle,cycles)
+ self.assertEqual(len(cycles), 5)
+
+ # now test _find_cycles method
+ projects = [p1, p2, p3, p4, p7, p10]
+
+ # behaviour manually verified as being correct on Jul 12
+ #def handler(msg):
+ #print msg
+ #print_cyclic_trace(v._find_cycles(projects), handler)
+ self.assertEqual(len(v._find_cycles(projects)), 18)
+
+ # finally, the sugared up verify...
+ walker = self.mock()
+ # (visited_repositories, visited_modules, visited_projects) = self.walker.walk(workspace, visitor)
+ walker.expects(at_least_once()).method("walk").will(return_value((None, None, [p5, p6, p8, p9])))
+
+ handler = self.mock()
+ handler.expects(once()).method("_handleError").will(raise_exception(CyclicDependencyError))
+
+ class Workspace:
+ projects = {"p1": p1,
+ "p2": p2,
+ "p3": p3,
+ "p4": p4,
+ "p5": p5,
+ "p6": p6,
+ "p7": p7,
+ "p8": p8,
+ "p9": p9,
+ "p10": p10}
+ cycles = []
+ unvisited = []
+
+ w = Workspace()
+
+ v = Verifier(walker, handler)
+ self.assertRaises(CyclicDependencyError, v.verify, w)
+ self.assertEqual(len(w.cycles), 18)
+ self.assertEqual(len(w.unvisited), 6)
+ self.assertEqual(len(w.unvisited), 6)
+
+ v = Verifier(walker, self.handler)
+ w = Workspace()
+ w.projects = {"p5": p5,
+ "p6": p6,
+ "p8": p8,
+ "p9": p9}
+ v.verify(w)
+ self.assertEqual(len(w.cycles), 0)
+ self.assertEqual(len(w.unvisited), 0)