Repository: buildbot/buildbot

Issue:
enable evaluation of coverage for buildbot-worker



Discussion:

Resolving patch:
diff --git a/master/buildbot/schedulers/basic.py b/master/buildbot/schedulers/basic.py
--- a/master/buildbot/schedulers/basic.py
+++ b/master/buildbot/schedulers/basic.py
@@ -96,14 +96,12 @@ def startService(self, _returnDeferred=False):
     def stopService(self):
         # the base stopService will unsubscribe from new changes
         d = base.BaseScheduler.stopService(self)
-        d.addCallback(lambda _ :
-                self._stable_timers_lock.acquire())
+        @util.deferredLocked(self._stable_timers_lock)
         def cancel_timers(_):
             for timer in self._stable_timers.values():
                 if timer:
                     timer.cancel()
-            self._stable_timers = {}
-            self._stable_timers_lock.release()
+            self._stable_timers.clear()
         d.addCallback(cancel_timers)
         return d
 
@@ -195,6 +193,11 @@ def stableTimerFired(self, timer_name):
         yield self.master.db.schedulers.flushChangeClassifications(
                             self.objectid, less_than=max_changeid+1)
 
+    def getPendingBuildTimes(self):
+        # This isn't locked, since the caller expects and immediate value,
+        # and in any case, this is only an estimate.
+        return [timer.getTime() for timer in self._stable_timers.values() if timer and timer.active()]
+
 class SingleBranchScheduler(BaseBasicScheduler):
     def getChangeFilter(self, branch, branches, change_filter, categories):
         if branch is NotABranch and not change_filter and self.codebases is not None:


Test patch:
diff --git a/master/buildbot/test/unit/test_schedulers_basic.py b/master/buildbot/test/unit/test_schedulers_basic.py
--- a/master/buildbot/test/unit/test_schedulers_basic.py
+++ b/master/buildbot/test/unit/test_schedulers_basic.py
@@ -129,6 +129,9 @@ def check(_):
                                         onlyImportant=False)
             self.db.schedulers.assertClassifications(self.OBJECTID, { 20 : True })
             self.assertTrue(sched.timer_started)
+            self.assertEqual(sched.getPendingBuildTimes(), [ 10 ])
+            self.clock.advance(10)
+            self.assertEqual(sched.getPendingBuildTimes(), [])
         d.addCallback(check)
         d.addCallback(lambda _ : sched.stopService())
         return d
@@ -207,6 +210,7 @@ def test_gotChange_treeStableTimer_sequence(self):
                 self.makeFakeChange(branch='master', number=1, when=2220),
                 True)
         self.assertEqual(self.events, [])
+        self.assertEqual(sched.getPendingBuildTimes(), [2229])
         self.db.schedulers.assertClassifications(self.OBJECTID, { 1 : True })
 
         # but another (unimportant) change arrives before then
@@ -217,6 +221,7 @@ def test_gotChange_treeStableTimer_sequence(self):
                 self.makeFakeChange(branch='master', number=2, when=2226),
                 False)
         self.assertEqual(self.events, [])
+        self.assertEqual(sched.getPendingBuildTimes(), [2235])
         self.db.schedulers.assertClassifications(self.OBJECTID, { 1 : True, 2 : False })
 
         self.clock.advance(3) # to 2229
@@ -230,6 +235,7 @@ def test_gotChange_treeStableTimer_sequence(self):
                 self.makeFakeChange(branch='master', number=3, when=2232),
                 True)
         self.assertEqual(self.events, [])
+        self.assertEqual(sched.getPendingBuildTimes(), [2241])
         self.db.schedulers.assertClassifications(self.OBJECTID, { 1 : True, 2 : False, 3 : True })
 
         self.clock.advance(3) # to 2235
@@ -238,6 +244,7 @@ def test_gotChange_treeStableTimer_sequence(self):
         # finally, time to start the build!
         self.clock.advance(6) # to 2241
         self.assertEqual(self.events, [ 'B[1,2,3]@2241' ])
+        self.assertEqual(sched.getPendingBuildTimes(), [])
         self.db.schedulers.assertClassifications(self.OBJECTID, { })
 
         yield sched.stopService()
@@ -314,16 +321,22 @@ def mkch(**kwargs):
         d = defer.succeed(None)
         d.addCallback(lambda _ :
                 sched.gotChange(mkch(branch='master', number=13), True))
+        d.addCallback(lambda _ :
+                self.assertEqual(sched.getPendingBuildTimes(), [10]))
         d.addCallback(lambda _ :
                 self.clock.advance(1)) # time is now 1
         d.addCallback(lambda _ :
                 sched.gotChange(mkch(branch='master', number=14), False))
+        d.addCallback(lambda _ :
+                self.assertEqual(sched.getPendingBuildTimes(), [11]))
         d.addCallback(lambda _ :
                 sched.gotChange(mkch(branch='boring', number=15), False))
         d.addCallback(lambda _ :
                 self.clock.pump([1]*4)) # time is now 5
         d.addCallback(lambda _ :
                 sched.gotChange(mkch(branch='devel', number=16), True))
+        d.addCallback(lambda _ :
+                self.assertEqual(sched.getPendingBuildTimes(), [11,15]))
         d.addCallback(lambda _ :
                 self.clock.pump([1]*10)) # time is now 15
         def check(_):