Repository: fedora-infra/bodhi

Issue:
Bodhi pushed obsoleted package to testing
Hello,

I originally opened ticket, https://fedorahosted.org/fedora-infrastructure/ticket/5427, but I was redirected here :)

So my issue is: I set negative karma to package (threshold for negative karma was set to -1) during pending state, so I reach obsoleted threshold, but package had been pushed to updates-testing, and obsoleted later (6 seconds later). But because the broken package is in updates-testing it already caused troubles for us.

I'm not sure if this is caused by bodhi too, but this package is in updates-testing for 3 days (I would expect only one)

For reference please see: https://bodhi.fedoraproject.org/updates/FEDORA-2016-86434d618d



Discussion:

Resolving patch:
diff --git a/bodhi/server/models/models.py b/bodhi/server/models/models.py
--- a/bodhi/server/models/models.py
+++ b/bodhi/server/models/models.py
@@ -1400,6 +1400,18 @@ def get_pushed_color(self):
             color = '#00ff00'  # green
         return color
 
+    def obsolete_if_unstable(self, db):
+        """
+        If an update with pending status(autopush enabled) reaches unstable karma
+        threshold, make sure it gets obsoleted.
+        """
+        if self.autokarma and self.status is UpdateStatus.pending and self.request is UpdateRequest.testing \
+                and self.unstable_karma not in (0, None) and self.karma <= self.unstable_karma:
+            log.info("%s has reached unstable karma thresholds" % self.title)
+            self.obsolete(db)
+            flash_log("%s has been obsoleted." % self.title)
+        return
+
     def comment(self, session, text, karma=0, author=None, anonymous=False,
                 karma_critpath=0, bug_feedback=None, testcase_feedback=None,
                 check_karma=True):
@@ -1465,6 +1477,9 @@ def comment(self, session, text, karma=0, author=None, anonymous=False,
                         caveats.append({
                             'name': 'karma', 'description': str(e),
                         })
+
+                # Obsolete pending update if it reaches unstable karma threshold
+                self.obsolete_if_unstable(session)
             else:
                 log.debug('Ignoring duplicate %d karma from %s on %s' % (karma, author, self.title))
 


Test patch:
diff --git a/bodhi/tests/server/functional/test_updates.py b/bodhi/tests/server/functional/test_updates.py
--- a/bodhi/tests/server/functional/test_updates.py
+++ b/bodhi/tests/server/functional/test_updates.py
@@ -1956,6 +1956,108 @@ def test_revoke_action_for_testing_request(self, publish, *args):
         publish.assert_called_with(
                 topic='update.request.revoke', msg=mock.ANY)
 
+    @mock.patch(**mock_valid_requirements)
+    @mock.patch('bodhi.server.notifications.publish')
+    def test_obsolete_if_unstable_with_autopush_enabled_when_pending(self, publish, *args):
+        """
+        Send update to obsolete state if it reaches unstable karma on
+        pending state where request is testing when Autopush is enabled. Make sure that it
+        does not go to update-testing state.
+        """
+        nvr = u'bodhi-2.0.0-2.fc17'
+        args = self.get_update(nvr)
+        args['autokarma'] = True
+        args['stable_karma'] = 1
+        args['unstable_karma'] = -1
+
+        resp = self.app.post_json('/updates/', args)
+        up = Update.get(nvr, self.db)
+        up.status = UpdateStatus.pending
+        up.request = UpdateRequest.testing
+        up.comment(self.db, u'Failed to work', author=u'ralph', karma=-1)
+        self.db.flush()
+
+        up = self.db.query(Update).filter_by(title=nvr).one()
+        self.assertEquals(up.karma, -1)
+        self.assertEquals(up.status, UpdateStatus.obsolete)
+        self.assertEquals(up.request, None)
+
+    @mock.patch(**mock_valid_requirements)
+    @mock.patch('bodhi.server.notifications.publish')
+    def test_obsolete_if_unstable_with_autopush_disabled_when_pending(self, publish, *args):
+        """
+        Don't automatically send update to obsolete state if it reaches unstable karma on
+        pending state when Autopush is disabled.
+        """
+        nvr = u'bodhi-2.0.0-2.fc17'
+        args = self.get_update(nvr)
+        args['autokarma'] = False
+        args['stable_karma'] = 1
+        args['unstable_karma'] = -1
+
+        resp = self.app.post_json('/updates/', args)
+        up = Update.get(nvr, self.db)
+        up.status = UpdateStatus.pending
+        up.request = UpdateRequest.testing
+        up.comment(self.db, u'Failed to work', author=u'ralph', karma=-1)
+        self.db.flush()
+
+        up = self.db.query(Update).filter_by(title=nvr).one()
+        self.assertEquals(up.karma, -1)
+        self.assertEquals(up.status, UpdateStatus.pending)
+        self.assertEquals(up.request, UpdateRequest.testing)
+
+    @mock.patch(**mock_valid_requirements)
+    @mock.patch('bodhi.server.notifications.publish')
+    def test_obsolete_if_unstable_karma_not_reached_with_autopush_enabled_when_pending(self, publish, *args):
+        """
+        Don't send update to obsolete state if it does not reach unstable karma threshold
+        on pending state when Autopush is enabled.
+        """
+        nvr = u'bodhi-2.0.0-2.fc17'
+        args = self.get_update(nvr)
+        args['autokarma'] = True
+        args['stable_karma'] = 2
+        args['unstable_karma'] = -2
+
+        resp = self.app.post_json('/updates/', args)
+        up = Update.get(nvr, self.db)
+        up.status = UpdateStatus.pending
+        up.request = UpdateRequest.testing
+        up.comment(self.db, u'Failed to work', author=u'ralph', karma=-1)
+        self.db.flush()
+
+        up = self.db.query(Update).filter_by(title=nvr).one()
+        self.assertEquals(up.karma, -1)
+        self.assertEquals(up.status, UpdateStatus.pending)
+        self.assertEquals(up.request, UpdateRequest.testing)
+
+    @mock.patch(**mock_valid_requirements)
+    @mock.patch('bodhi.server.notifications.publish')
+    def test_obsolete_if_unstable_with_autopush_enabled_when_testing(self, publish, *args):
+        """
+        Send update to obsolete state if it reaches unstable karma threshold on
+        testing state where request is stable when Autopush is enabled. Make sure that it
+        does not go to stable state.
+        """
+        nvr = u'bodhi-2.0.0-2.fc17'
+        args = self.get_update(nvr)
+        args['autokarma'] = True
+        args['stable_karma'] = 1
+        args['unstable_karma'] = -1
+
+        resp = self.app.post_json('/updates/', args)
+        up = Update.get(nvr, self.db)
+        up.status = UpdateStatus.testing
+        up.request = UpdateRequest.stable
+        up.comment(self.db, u'Failed to work', author=u'ralph', karma=-1)
+        self.db.flush()
+
+        up = self.db.query(Update).filter_by(title=nvr).one()
+        self.assertEquals(up.karma, -1)
+        self.assertEquals(up.status, UpdateStatus.obsolete)
+        self.assertEquals(up.request, None)
+
     @mock.patch(**mock_taskotron_results)
     @mock.patch(**mock_valid_requirements)
     @mock.patch('bodhi.server.notifications.publish')