diff --git a/buildbot/status/web/console.py b/buildbot/status/web/console.py index 375cd39bd72..e1be1ae5f3d 100755 --- a/buildbot/status/web/console.py +++ b/buildbot/status/web/console.py @@ -775,3 +775,31 @@ def body(self, request): revisions, categories, branch, debugInfo) return data + +class RevisionComparator(object): + """Used for comparing between revisions, as some + VCS use a plain counter for revisions (like SVN) + while others use different concepts (see Git). + """ + + # TODO (avivby): Should this be a zope interface? + + def isRevisionEarlier(self, first, second): + raise NotImplementedError + + def getSortingKey(self): + raise NotImplementedError + +class TimeRevisionComparator(RevisionComparator): + def isRevisionEarlier(self, first, second): + return first.when < second.when + + def getSortingKey(self): + return operator.attrgetter('when') + +class IntegerRevisionComparator(RevisionComparator): + def isRevisionEarlier(self, first, second): + return int(first.revision) < int(second.revision) + + def getSortingKey(self): + return operator.attrgetter('revision') diff --git a/buildbot/test/test_console.py b/buildbot/test/test_console.py index 18335dedd34..47c8a4296ed 100644 --- a/buildbot/test/test_console.py +++ b/buildbot/test/test_console.py @@ -5,6 +5,7 @@ from buildbot.status import builder from buildbot.status.web import console from buildbot.test.runutils import RunMixin +from buildbot.changes import changes # Configuration to be used by the getBuildDetailsTest run_config = """ @@ -48,6 +49,57 @@ def testgetResultsClass(self): self.assertEqual(console.getResultsClass(builder.FAILURE, builder.FAILURE, True), "running") self.assertEqual(console.getResultsClass(builder.EXCEPTION, builder.FAILURE, False), "exception") +def _createDummyChange(revision): + return changes.Change('Committer', ['files'], 'comment', revision=revision) + +class TimeRevisionComparatorTest(unittest.TestCase): + def setUp(self): + self.comparator = console.TimeRevisionComparator() + + def testSameRevisionIsNotGreater(self): + change = _createDummyChange('abcdef') + self.assertFalse(self.comparator.isRevisionEarlier(change, change)) + + def testOrdersDifferentRevisions(self): + first = _createDummyChange('first_rev') + second = _createDummyChange('second_rev') + + second.when += 1 # Make sure it's "after" the first + self.assertTrue(self.comparator.isRevisionEarlier(first, second)) + self.assertFalse(self.comparator.isRevisionEarlier(second, first)) + + def testReturnedKeySortsRevisionsCorrectly(self): + my_changes = [_createDummyChange('rev' + str(i)) + for i in range(1, 6)] + for i in range(1, len(my_changes)): + my_changes[i].when = my_changes[i-1].when + 1 + + reversed_changes = list(reversed(my_changes)) + reversed_changes.sort(key=self.comparator.getSortingKey()) + self.assertEqual(my_changes, reversed_changes) + +class IntegerRevisionComparatorTest(unittest.TestCase): + def setUp(self): + self.comparator = console.IntegerRevisionComparator() + + def testSameRevisionIsNotGreater(self): + change = _createDummyChange('1') + self.assertFalse(self.comparator.isRevisionEarlier(change, change)) + + def testOrdersDifferentRevisions(self): + first = _createDummyChange('1') + second = _createDummyChange('2') + + self.assertTrue(self.comparator.isRevisionEarlier(first, second)) + self.assertFalse(self.comparator.isRevisionEarlier(second, first)) + + def testReturnedKeySortsRevisionsCorrectly(self): + my_changes = [_createDummyChange(str(i)) for i in range(1, 6)] + + reversed_changes = list(reversed(my_changes)) + reversed_changes.sort(key=self.comparator.getSortingKey()) + self.assertEqual(my_changes, reversed_changes) + # Helper class to mock a request. We define only what we really need. class MockRequest(object): def childLink(self, link):