Repository: buildbot/buildbot

Issue:
change_hook/poller not working for ReconfigurablePollingChangeSource
In [poller.py](https://github.com/buildbot/buildbot/blob/a0e1d8840e8856ead136a1ad6e2021931355af15/master/buildbot/www/hooks/poller.py#L40), the change sources are filtered like this:

```python
        for source in change_svc:
            if not isinstance(source, PollingChangeSource):
                continue
```

This means that any pollers derived from the super-class `ReconfigurablePollingChangeSource` will not be found. Since [new code is supposed to use `ReconfigurablePollingChangeSource`](https://docs.buildbot.net/current/developer/cls-changesources.html?highlight=reconfigurablepollingchangesource#pollingchangesource), the code should probably read:

```python
        for source in change_svc:
            if not isinstance(source, ReconfigurablePollingChangeSource):
                continue
```



Discussion:
@stoklund Thanks a lot for the bug report. It seems that your observation is correct. Could you maybe submit a pull request with a correction? Tests are in `master/buildbot/test/unit/www/test_hooks_poller.py`, there we would need maybe just a single additional test to check whether ReconfigurablePollingChangeSource behaves correctly.
Sure! Let me check if I'm able to run buildbot tests. Then I can make a PR.
@stoklund [This part of the documentation](http://docs.buildbot.net/latest/developer/quickstart.html) should get you started for unit tests quickly. You only need to create a Python environment, ignore the section on Javascript. Thanks a lot!

Resolving patch:
diff --git a/master/buildbot/www/hooks/poller.py b/master/buildbot/www/hooks/poller.py
--- a/master/buildbot/www/hooks/poller.py
+++ b/master/buildbot/www/hooks/poller.py
@@ -17,7 +17,7 @@
 # the door" and trigger a change source to poll.
 
 
-from buildbot.changes.base import PollingChangeSource
+from buildbot.changes.base import ReconfigurablePollingChangeSource
 from buildbot.util import bytes2unicode
 from buildbot.util import unicode2bytes
 from buildbot.www.hooks.base import BaseHookHandler
@@ -38,7 +38,7 @@ def getChanges(self, req):
         pollers = []
 
         for source in change_svc:
-            if not isinstance(source, PollingChangeSource):
+            if not isinstance(source, ReconfigurablePollingChangeSource):
                 continue
             if not hasattr(source, "name"):
                 continue


Test patch:
diff --git a/master/buildbot/test/unit/www/test_hooks_poller.py b/master/buildbot/test/unit/www/test_hooks_poller.py
--- a/master/buildbot/test/unit/www/test_hooks_poller.py
+++ b/master/buildbot/test/unit/www/test_hooks_poller.py
@@ -28,7 +28,17 @@
 
 class TestPollingChangeHook(TestReactorMixin, unittest.TestCase):
 
-    class Subclass(base.PollingChangeSource):
+    # New sources should derive from ReconfigurablePollingChangeSource,
+    # but older sources will be using PollingChangeSource.
+    # Both must work.
+    class Subclass(base.ReconfigurablePollingChangeSource):
+        pollInterval = None
+        called = False
+
+        def poll(self):
+            self.called = True
+
+    class OldstyleSubclass(base.PollingChangeSource):
         pollInterval = None
         called = False
 
@@ -39,7 +49,8 @@ def setUp(self):
         self.setUpTestReactor()
 
     @defer.inlineCallbacks
-    def setUpRequest(self, args, options=True, activate=True):
+    def setUpRequest(self, args, options=True, activate=True,
+                     poller_cls=Subclass):
         self.request = FakeRequest(args=args)
         self.request.uri = b"/change_hook/poller"
         self.request.method = b"GET"
@@ -52,10 +63,10 @@ def setUpRequest(self, args, options=True, activate=True):
             dialects={'poller': options}, master=master)
         master.change_svc = ChangeManager()
         yield master.change_svc.setServiceParent(master)
-        self.changesrc = self.Subclass(21, name=b'example')
+        self.changesrc = poller_cls(21, name=b'example')
         yield self.changesrc.setServiceParent(master.change_svc)
 
-        self.otherpoller = self.Subclass(22, name=b"otherpoller")
+        self.otherpoller = poller_cls(22, name=b"otherpoller")
         yield self.otherpoller.setServiceParent(master.change_svc)
 
         anotherchangesrc = base.ChangeSource(name=b'notapoller')
@@ -122,3 +133,11 @@ def test_allowlist_all(self):
         self.assertEqual(self.request.written, b"no change found")
         self.assertEqual(self.changesrc.called, True)
         self.assertEqual(self.otherpoller.called, False)
+
+    @defer.inlineCallbacks
+    def test_trigger_old_poller(self):
+        yield self.setUpRequest({b"poller": [b"example"]},
+                                poller_cls=self.OldstyleSubclass)
+        self.assertEqual(self.request.written, b"no change found")
+        self.assertEqual(self.changesrc.called, True)
+        self.assertEqual(self.otherpoller.called, False)