[Buildbot-commits] buildbot/buildbot/test test_svnpoller.py, 1.1, 1.2

Brian Warner warner at users.sourceforge.net
Mon Oct 2 00:13:20 UTC 2006


Update of /cvsroot/buildbot/buildbot/buildbot/test
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv17137/buildbot/test

Modified Files:
	test_svnpoller.py 
Log Message:
[project @ svnpoller: lots of work, make branches behave properly, write lots of tests, docs]

Original author: warner at lothar.com
Date: 2006-10-01 23:23:25

Index: test_svnpoller.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_svnpoller.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- test_svnpoller.py	2 Oct 2006 00:13:12 -0000	1.1
+++ test_svnpoller.py	2 Oct 2006 00:13:18 -0000	1.2
@@ -1,227 +1,9 @@
-# Here are the tests for the SvnSource
+# -*- test-case-name: buildbot.test.test_svnpoller -*-
 
-import sys
 import time
-
-from twisted.python import log, failure
 from twisted.internet import defer
 from twisted.trial import unittest
-
-from buildbot.twcompat import maybeWait
-from buildbot.changes.changes import Change
-from buildbot.changes.svnpoller import SvnSource, split_file_branches
-
-# was changes 1012 in xenomai.org
-svn_change_1 = """<?xml version="1.0" encoding="utf-8"?>
-<log>
-<logentry
-   revision="101">
-<author>rpm</author>
-<date>2006-05-17T14:58:28.494960Z</date>
-<paths>
-<path
-   action="M">/branch/ksrc/arch/i386/hal.c</path>
-</paths>
-<msg>Remove unused variable</msg>
-</logentry>
-</log>
-"""
-
-svn_change_2 = """<?xml version="1.0" encoding="utf-8"?>
-<log>
-<logentry
-   revision="102">
-<author>rpm</author>
-<date>2006-05-15T12:54:08.891420Z</date>
-<paths>
-<path
-   action="M">/trunk/ChangeLog</path>
-<path
-   action="D">/trunk/ksrc/first_file</path>
-<path
-   action="D">/trunk/ksrc/second_file</path>
-</paths>
-<msg>Initial Adeos support</msg>
-</logentry>
-</log>
-"""
-
-svn_change_3 = """<?xml version="1.0" encoding="utf-8"?>
-<log>
-<logentry
-   revision="102">
-<author>rpm</author>
-<date>2006-05-15T12:54:08.891420Z</date>
-<paths>
-<path
-   action="M">/trunk/ChangeLog</path>
-<path
-   action="D">/trunk/ksrc/first_file</path>
-<path
-   action="D">/trunk/ksrc/second_file</path>
-</paths>
-<msg>Upgrade Adeos support</msg>
-</logentry>
-</log>
-"""
-
-def dbgMsg(myString):
-    log.msg(myString)
-    return 1
-
-class MockSvnSource(SvnSource):
-    """Test SvnSource which doesn't actually invoke svn."""
-    invocation = 0
-
-    def __init__(self, svnchanges, *args, **kwargs):
-        SvnSource.__init__(self, None, *args, **kwargs)
-        self.svnchanges = svnchanges
-
-    def _get_changes(self):
-        assert self.working
-        result = self.svnchanges[self.invocation]
-        self.invocation += 1
-        #log.msg("MockSvnSource._get_changes %s result %s " % (self.invocation-1, result))
-        dbgMsg("MockSvnSource._get_changes %s " % (self.invocation-1))
-        return defer.succeed(result)
-
-    def _get_describe(self, dummy, num):
-        assert self.working
-        dbgMsg("MockSvnSource._get_describe %s " % num)
-        return defer.succeed(self.svnchanges[num])
-
-class TestSvnPoller(unittest.TestCase):
-    def setUp(self):
-        self.changes = []
-        self.addChange = self.changes.append
-
-    def failUnlessIn(self, substr, string):
-        # this is for compatibility with python2.2
-        if isinstance(string, str):
-            self.failUnless(string.find(substr) != -1)
-        else:
-            self.assertIn(substr, string)
-
-    def testCheck(self):
-        """successful checks"""
-        self.t = MockSvnSource(svnchanges=[ svn_change_1, svn_change_2, svn_change_3],
-                              svnuser=None,
-                              svnurl='/trunk/',)
-        self.t.parent = self
-
-        # The first time, it just learns the change to start at
-        self.assert_(self.t.last_change is None)
-        self.assert_(not self.t.working)
-	dbgMsg("zzz")
-        return maybeWait(self.t.checksvn().addCallback(self._testCheck2))
-
-    def _testCheck2(self, res):
-	dbgMsg("zzz1")
-        self.assertEquals(self.changes, [])
-	dbgMsg("zzz2 %s %s" % (self.t.last_change, self.changes))
-        self.assertEquals(self.t.last_change, '101')
-	dbgMsg("zzz3")
-
-        # Subsequent times, it returns Change objects for new changes.
-        return self.t.checksvn().addCallback(self._testCheck3)
-
-    def _testCheck3(self, res):
-        # They're supposed to go oldest to newest, so this one must be first.
-	tstChange1 = Change(who='rpm',
-                   files=['/trunk/ChangeLog',
-		          '/trunk/ksrc/first_file',
-			  '/trunk/ksrc/second_file'],
-                   comments="Initial Adeos support",
-                   revision='2',
-                   when=self.makeTime("2006/05/15 12:54:08"),
-                   branch='trunk').asText()
-	dbgMsg("tstChange" + tstChange1)
-	dbgMsg("changes[0]" + self.changes[0].asText())
-
-	self.assertEquals(self.changes[0].asText(), tstChange1)
-        # Subsequent times, it returns Change objects for new changes.
-        return self.t.checksvn().addCallback(self._testCheck4)
-
-    def _testCheck4(self, res):
-	dbgMsg("zzz5 %s " % len(self.changes))
-        self.assertEquals(len(self.changes), 1)
-	dbgMsg("zzz6 %s %s" % (self.t.last_change, self.changes))
-        self.assertEquals(self.t.last_change, '102')
-	dbgMsg("zzz7")
-        self.assert_(not self.t.working)
-	tstChange2 = Change(who='rpm',
-                   files=['/trunk/ChangeLog',
-		          '/trunk/ksrc/first_file',
-			  '/trunk/ksrc/second_file'],
-                   comments="Initial Adeos support",
-                   revision='2',
-                   when=self.makeTime("2006/05/15 12:54:08"),
-                   branch='trunk').asText()
-	dbgMsg("changes[0]" + self.changes[0].asText())
-	dbgMsg("tstChange2" + tstChange2)
-        self.assertEquals(self.changes[0].asText(), tstChange2)
-	dbgMsg(7777)
-
-    def makeTime(self, timestring):
-        datefmt = '%Y/%m/%d %H:%M:%S'
-        when = time.mktime(time.strptime(timestring, datefmt))
-        return when
-
-    def testFailedChanges(self):
-        """'svn changes' failure is properly reported"""
-        self.t = MockSvnSource(svnchanges=['Subversion client error:\n...'],
-                               svnuser=None,
-                               svnurl="/trunk")
-        self.t.parent = self
-        d = self.t.checksvn()
-        d.addBoth(self._testFailedChanges2)
-        return maybeWait(d)
-
-    def _testFailedChanges2(self, f):
-        self.assert_(isinstance(f, failure.Failure))
-        self.failUnlessIn('Subversion client error', str(f))
-        self.assert_(not self.t.working)
-
-    def testFailedDescribe(self):
-        """'svn describe' failure is properly reported"""
-        self.t = MockSvnSource(svnchanges=[
-	                       svn_change_1,
-			       'Subversion client error:\n...',
-			       svn_change_2,],
-                               svnuser=None)
-        self.t.parent = self
-        d = self.t.checksvn()
-	dbgMsg("xxx")
-        d.addCallback(self._testFailedDescribe2)
-        return maybeWait(d)
-
-    def _testFailedDescribe2(self, res):
-        # first time finds nothing; check again.
-	dbgMsg("yy")
-        res = self.t.checksvn().addBoth(self._testFailedDescribe3)
-        return res
-
-    def _testFailedDescribe3(self, f):
-	dbgMsg("yy1 %s" % f)
-        self.assert_(isinstance(f, failure.Failure))
-	dbgMsg("yy2")
-        self.failUnlessIn('Subversion client error', str(f))
-	dbgMsg("yy3")
-        self.assert_(not self.t.working)
-	dbgMsg("yy4")
-        self.assertEquals(self.t.last_change, '101')
-	dbgMsg("yy5")
-
-    def testAlreadyWorking(self):
-        """don't launch a new poll while old is still going"""
-        self.t = SvnSource()
-        self.t.working = True
-        self.assert_(self.t.last_change is None)
-        d = self.t.checksvn()
-        d.addCallback(self._testAlreadyWorking2)
-
-    def _testAlreadyWorking2(self, res):
-        self.assert_(self.t.last_change is None)
+from buildbot.changes.svnpoller import SvnSource
 
 # this is the output of "svn info --xml
 # svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk"
@@ -307,7 +89,7 @@
         base = "svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk"
         s = SvnSource(base + "/")
         self.failUnlessEqual(s.svnurl, base) # certify slash-stripping
-        prefix = s._determine_prefix_2(prefix_output)
+        prefix = s.determine_prefix(prefix_output)
         self.failUnlessEqual(prefix, "trunk")
         self.failUnlessEqual(s._prefix, prefix)
 
@@ -315,42 +97,59 @@
         base = "svn+ssh://svn.twistedmatrix.com/svn/Twisted"
         s = SvnSource(base)
         self.failUnlessEqual(s.svnurl, base)
-        prefix = s._determine_prefix_2(prefix_output_2)
+        prefix = s.determine_prefix(prefix_output_2)
         self.failUnlessEqual(prefix, "")
 
     def test3(self):
         base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository"
         s = SvnSource(base)
         self.failUnlessEqual(s.svnurl, base)
-        prefix = s._determine_prefix_2(prefix_output_3)
+        prefix = s.determine_prefix(prefix_output_3)
         self.failUnlessEqual(prefix, "")
 
     def test4(self):
         base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample/trunk"
         s = SvnSource(base)
         self.failUnlessEqual(s.svnurl, base)
-        prefix = s._determine_prefix_2(prefix_output_4)
+        prefix = s.determine_prefix(prefix_output_4)
         self.failUnlessEqual(prefix, "sample/trunk")
 
 # output from svn log on .../SVN-Repository/sample
 # (so it includes trunk and branches)
-changes_output_1 = """\
-<?xml version="1.0"?>
-<log>
+sample_base = "file:///usr/home/warner/stuff/Projects/BuildBot/trees/misc/_trial_temp/test_vc/repositories/SVN-Repository/sample"
+sample_logentries = [None] * 4
+
+sample_logentries[3] = """\
+<logentry
+   revision="4">
+<author>warner</author>
+<date>2006-10-01T19:35:16.165664Z</date>
+<paths>
+<path
+   action="M">/sample/trunk/version.c</path>
+</paths>
+<msg>revised_to_2</msg>
+</logentry>
+"""
+
+sample_logentries[2] = """\
 <logentry
    revision="3">
 <author>warner</author>
-<date>2006-10-01T07:37:04.182499Z</date>
+<date>2006-10-01T19:35:10.215692Z</date>
 <paths>
 <path
    action="M">/sample/branch/main.c</path>
 </paths>
 <msg>commit_on_branch</msg>
 </logentry>
+"""
+
+sample_logentries[1] = """\
 <logentry
    revision="2">
 <author>warner</author>
-<date>2006-10-01T07:37:03.175326Z</date>
+<date>2006-10-01T19:35:09.154973Z</date>
 <paths>
 <path
    copyfrom-path="/sample/trunk"
@@ -359,44 +158,272 @@
 </paths>
 <msg>make_branch</msg>
 </logentry>
-</log>
 """
 
+sample_logentries[0] = """\
+<logentry
+   revision="1">
+<author>warner</author>
+<date>2006-10-01T19:35:08.642045Z</date>
+<paths>
+<path
+   action="A">/sample</path>
+<path
+   action="A">/sample/trunk</path>
+<path
+   action="A">/sample/trunk/subdir/subdir.c</path>
+<path
+   action="A">/sample/trunk/main.c</path>
+<path
+   action="A">/sample/trunk/version.c</path>
+<path
+   action="A">/sample/trunk/subdir</path>
+</paths>
+<msg>sample_project_files</msg>
+</logentry>
+"""
+
+sample_info_output = """\
+<?xml version="1.0"?>
+<info>
+<entry
+   kind="dir"
+   path="sample"
+   revision="4">
+<url>file:///usr/home/warner/stuff/Projects/BuildBot/trees/misc/_trial_temp/test_vc/repositories/SVN-Repository/sample</url>
+<repository>
+<root>file:///usr/home/warner/stuff/Projects/BuildBot/trees/misc/_trial_temp/test_vc/repositories/SVN-Repository</root>
+<uuid>4f94adfc-c41e-0410-92d5-fbf86b7c7689</uuid>
+</repository>
+<commit
+   revision="4">
+<author>warner</author>
+<date>2006-10-01T19:35:16.165664Z</date>
+</commit>
+</entry>
+</info>
+"""
+
+
+changes_output_template = """\
+<?xml version="1.0"?>
+<log>
+%s</log>
+"""
+
+def make_changes_output(maxrevision):
+    # return what 'svn log' would have just after the given revision was
+    # committed
+    logs = sample_logentries[0:maxrevision]
+    assert len(logs) == maxrevision
+    logs.reverse()
+    output = changes_output_template % ("".join(logs))
+    return output
+
+def split_file(path):
+    pieces = path.split("/")
+    if pieces[0] == "branch":
+        return "branch", "/".join(pieces[1:])
+    if pieces[0] == "trunk":
+        return None, "/".join(pieces[1:])
+    raise RuntimeError("there shouldn't be any files like %s" % path)
+
+class MySvnSource(SvnSource):
+    def __init__(self, *args, **kwargs):
+        SvnSource.__init__(self, *args, **kwargs)
+        self.pending_commands = []
+        self.finished_changes = []
+
+    def getProcessOutput(self, args):
+        d = defer.Deferred()
+        self.pending_commands.append((args, d))
+        return d
+
+    def submit_changes(self, changes):
+        self.finished_changes.extend(changes)
+
 class ComputeChanges(unittest.TestCase):
     def test1(self):
         base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample"
         s = SvnSource(base)
         s._prefix = "sample"
-        doc = s._parse_logs(changes_output_1)
+        output = make_changes_output(4)
+        doc = s.parse_logs(output)
 
-        newlast, logentries = s._filter_new_logentries(doc, 3)
-        self.failUnlessEqual(newlast, 3)
+        newlast, logentries = s._filter_new_logentries(doc, 4)
+        self.failUnlessEqual(newlast, 4)
         self.failUnlessEqual(len(logentries), 0)
 
-        newlast, logentries = s._filter_new_logentries(doc, 2)
-        self.failUnlessEqual(newlast, 3)
+        newlast, logentries = s._filter_new_logentries(doc, 3)
+        self.failUnlessEqual(newlast, 4)
         self.failUnlessEqual(len(logentries), 1)
 
-        newlast, logentries = s._filter_new_logentries(doc, 0)
-        self.failUnlessEqual(newlast, 3)
-        self.failUnlessEqual(len(logentries), 2)
+        newlast, logentries = s._filter_new_logentries(doc, 1)
+        self.failUnlessEqual(newlast, 4)
+        self.failUnlessEqual(len(logentries), 3)
 
-    def split_file(self, path):
-        pieces = path.split("/")
-        if pieces[0] == "branch":
-            return "branch", "/".join(pieces[1:])
-        if pieces[0] == "trunk":
-            return None, "/".join(pieces[1:])
-        raise RuntimeError("there shouldn't be any files like %s" % path)
+        newlast, logentries = s._filter_new_logentries(doc, None)
+        self.failUnlessEqual(newlast, 4)
+        self.failUnlessEqual(len(logentries), 0)
 
     def testChanges(self):
         base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample"
-        s = SvnSource(base, split_file=self.split_file)
+        s = SvnSource(base, split_file=split_file)
         s._prefix = "sample"
-        doc = s._parse_logs(changes_output_1)
-        newlast, logentries = s._filter_new_logentries(doc, 0)
-        changes = s._create_changes(logentries)
+        doc = s.parse_logs(make_changes_output(3))
+        newlast, logentries = s._filter_new_logentries(doc, 1)
+        # so we see revisions 2 and 3 as being new
+        self.failUnlessEqual(newlast, 3)
+        changes = s.create_changes(logentries)
         self.failUnlessEqual(len(changes), 2)
         self.failUnlessEqual(changes[0].branch, "branch")
+        self.failUnlessEqual(changes[0].revision, 2)
         self.failUnlessEqual(changes[1].branch, "branch")
         self.failUnlessEqual(changes[1].files, ["main.c"])
+        self.failUnlessEqual(changes[1].revision, 3)
+
+        # and now pull in r4
+        doc = s.parse_logs(make_changes_output(4))
+        newlast, logentries = s._filter_new_logentries(doc, newlast)
+        self.failUnlessEqual(newlast, 4)
+        # so we see revision 4 as being new
+        changes = s.create_changes(logentries)
+        self.failUnlessEqual(len(changes), 1)
+        self.failUnlessEqual(changes[0].branch, None)
+        self.failUnlessEqual(changes[0].revision, 4)
+        self.failUnlessEqual(changes[0].files, ["version.c"])
+
+    def testFirstTime(self):
+        base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample"
+        s = SvnSource(base, split_file=split_file)
+        s._prefix = "sample"
+        doc = s.parse_logs(make_changes_output(4))
+        logentries = s.get_new_logentries(doc)
+        # SvnSource ignores all changes that happened before it was started
+        self.failUnlessEqual(len(logentries), 0)
+        self.failUnlessEqual(s.last_change, 4)
+
+class Misc(unittest.TestCase):
+    def testAlreadyWorking(self):
+        base = "file:///home/warner/stuff/Projects/BuildBot/trees/svnpoller/_trial_temp/test_vc/repositories/SVN-Repository/sample"
+        s = MySvnSource(base)
+        d = s.checksvn()
+        # the SvnSource is now waiting for its getProcessOutput to finish
+        self.failUnlessEqual(s.overrun_counter, 0)
+        d2 = s.checksvn()
+        self.failUnlessEqual(s.overrun_counter, 1)
+        self.failUnlessEqual(len(s.pending_commands), 1)
+
+    def testGetRoot(self):
+        base = "svn+ssh://svn.twistedmatrix.com/svn/Twisted/trunk"
+        s = MySvnSource(base)
+        d = s.checksvn()
+        # the SvnSource is now waiting for its getProcessOutput to finish
+        self.failUnlessEqual(len(s.pending_commands), 1)
+        self.failUnlessEqual(s.pending_commands[0][0],
+                             ["info", "--xml", "--non-interactive", base])
+
+def makeTime(timestring):
+    datefmt = '%Y/%m/%d %H:%M:%S'
+    when = time.mktime(time.strptime(timestring, datefmt))
+    return when
+
+
+class Everything(unittest.TestCase):
+    def test1(self):
+        s = MySvnSource(sample_base, split_file=split_file)
+        d = s.checksvn()
+        # the SvnSource is now waiting for its getProcessOutput to finish
+        self.failUnlessEqual(len(s.pending_commands), 1)
+        self.failUnlessEqual(s.pending_commands[0][0],
+                             ["info", "--xml", "--non-interactive",
+                              sample_base])
+        d = s.pending_commands[0][1]
+        s.pending_commands.pop(0)
+        d.callback(sample_info_output)
+        # now it should be waiting for the 'svn log' command
+        self.failUnlessEqual(len(s.pending_commands), 1)
+        self.failUnlessEqual(s.pending_commands[0][0],
+                             ["log", "--xml", "--verbose", "--non-interactive",
+                              "--limit=100", sample_base])
+        d = s.pending_commands[0][1]
+        s.pending_commands.pop(0)
+        d.callback(make_changes_output(1))
+        # the command ignores the first batch of changes
+        self.failUnlessEqual(len(s.finished_changes), 0)
+        self.failUnlessEqual(s.last_change, 1)
+
+        # now fire it again, nothing changing
+        d = s.checksvn()
+        self.failUnlessEqual(s.pending_commands[0][0],
+                             ["log", "--xml", "--verbose", "--non-interactive",
+                              "--limit=100", sample_base])
+        d = s.pending_commands[0][1]
+        s.pending_commands.pop(0)
+        d.callback(make_changes_output(1))
+        # nothing has changed
+        self.failUnlessEqual(len(s.finished_changes), 0)
+        self.failUnlessEqual(s.last_change, 1)
+
+        # and again, with r2 this time
+        d = s.checksvn()
+        self.failUnlessEqual(s.pending_commands[0][0],
+                             ["log", "--xml", "--verbose", "--non-interactive",
+                              "--limit=100", sample_base])
+        d = s.pending_commands[0][1]
+        s.pending_commands.pop(0)
+        d.callback(make_changes_output(2))
+        # r2 should appear
+        self.failUnlessEqual(len(s.finished_changes), 1)
+        self.failUnlessEqual(s.last_change, 2)
+
+        c = s.finished_changes[0]
+        self.failUnlessEqual(c.branch, "branch")
+        self.failUnlessEqual(c.revision, 2)
+        self.failUnlessEqual(c.files, [''])
+        # TODO: this is what creating the branch looks like: a Change with a
+        # zero-length file. We should decide if we want filenames like this
+        # in the Change (and make sure nobody else gets confused by it) or if
+        # we want to strip them out.
+        self.failUnlessEqual(c.comments, "make_branch")
+
+        # and again at r2, so nothing should change
+        d = s.checksvn()
+        self.failUnlessEqual(s.pending_commands[0][0],
+                             ["log", "--xml", "--verbose", "--non-interactive",
+                              "--limit=100", sample_base])
+        d = s.pending_commands[0][1]
+        s.pending_commands.pop(0)
+        d.callback(make_changes_output(2))
+        # nothing has changed
+        self.failUnlessEqual(len(s.finished_changes), 1)
+        self.failUnlessEqual(s.last_change, 2)
+
+        # and again with both r3 and r4 appearing together
+        d = s.checksvn()
+        self.failUnlessEqual(s.pending_commands[0][0],
+                             ["log", "--xml", "--verbose", "--non-interactive",
+                              "--limit=100", sample_base])
+        d = s.pending_commands[0][1]
+        s.pending_commands.pop(0)
+        d.callback(make_changes_output(4))
+        self.failUnlessEqual(len(s.finished_changes), 3)
+        self.failUnlessEqual(s.last_change, 4)
+
+        c3 = s.finished_changes[1]
+        self.failUnlessEqual(c3.branch, "branch")
+        self.failUnlessEqual(c3.revision, 3)
+        self.failUnlessEqual(c3.files, ["main.c"])
+        self.failUnlessEqual(c3.comments, "commit_on_branch")
+
+        c4 = s.finished_changes[2]
+        self.failUnlessEqual(c4.branch, None)
+        self.failUnlessEqual(c4.revision, 4)
+        self.failUnlessEqual(c4.files, ["version.c"])
+        self.failUnlessEqual(c4.comments, "revised_to_2")
+        self.failUnlessEqual(c4.when, makeTime("2006/10/01 19:35:16"))
+
+
+# TODO:
+#  get coverage of split_file returning None
+#  point at a live SVN server for a little while





More information about the Commits mailing list