Repository: fedora-infra/bodhi

Issue:
bodhi occasionally fails to publish to fedora-messaging when it ought to (`update.request.testing`, `update.edit` at least)
I noticed that openQA tested a 389-ds-base update for Fedora 31, but not an update for the same package for Fedora 30 that was submitted a few minutes later. Looking into it, it seems we got a [bodhi.update.request.testing message for the F31 update](https://apps.fedoraproject.org/datagrepper/id?id=2020-87b4ee60-1e32-4b6b-ac6f-02f043aa9c8a&is_raw=true&size=extra-large), but none was published for [the F30 update](https://bodhi.fedoraproject.org/updates/FEDORA-2020-fb48098a19). I can't see any reason why a message should not have been published, so I'm filing this bug.

openQA won't test updates unless it sees a message for them, so this is restricting test coverage.


Discussion:
This wasn't a one-off. [Here's another case](https://bodhi.fedoraproject.org/updates/FEDORA-2020-4f5299af86). That update was submitted to testing on 2020-02-10 at 07:23:38 according to the web UI, but there is no `bodhi.update.request.testing` message logged in datagrepper, and openQA did not test it.

This is a serious problem, please take a look at it.
One more problem: https://bodhi.fedoraproject.org/updates/FEDORA-2020-62c54952b9 wasn't getting any OpenQA tests due to this bug.
[Here's another case](https://bodhi.fedoraproject.org/updates/FEDORA-2020-62c54952b9#comment-1263796). No `bodhi.update.edit` message is [logged in datagrepper](https://apps.fedoraproject.org/datagrepper/raw?topic=org.fedoraproject.prod.bodhi.update.edit) for the edit @abbra made recently.

Resolving patch:
diff --git a/bodhi/server/models.py b/bodhi/server/models.py
--- a/bodhi/server/models.py
+++ b/bodhi/server/models.py
@@ -2444,12 +2444,12 @@ def edit(cls, request, data):
         # Store the update alias so Celery doesn't have to emit SQL
         update_alias = up.alias
 
-        # Commit the changes in the db before calling a celery task.
-        db.commit()
-
         notifications.publish(update_schemas.UpdateEditV1.from_dict(
             message={'update': up, 'agent': request.user.name, 'new_bugs': new_bugs}))
 
+        # Commit the changes in the db before calling a celery task.
+        db.commit()
+
         handle_update.delay(
             api_version=2, action='edit',
             update_alias=update_alias,
@@ -2891,9 +2891,6 @@ def set_request(self, db, action, username):
         # Store the update alias so Celery doesn't have to emit SQL
         alias = self.alias
 
-        # Commit the changes in the db before calling a celery task.
-        db.commit()
-
         action_message_map = {
             UpdateRequest.revoke: update_schemas.UpdateRequestRevokeV1,
             UpdateRequest.stable: update_schemas.UpdateRequestStableV1,
@@ -2903,6 +2900,9 @@ def set_request(self, db, action, username):
         notifications.publish(action_message_map[action].from_dict(
             dict(update=self, agent=username)))
 
+        # Commit the changes in the db before calling a celery task.
+        db.commit()
+
         if action == UpdateRequest.testing:
             handle_update.delay(
                 api_version=2, action="testing",


Test patch:
diff --git a/bodhi/tests/server/services/test_updates.py b/bodhi/tests/server/services/test_updates.py
--- a/bodhi/tests/server/services/test_updates.py
+++ b/bodhi/tests/server/services/test_updates.py
@@ -1507,7 +1507,7 @@ def test_provenpackager_request_privs(self, *args):
         update = Build.query.filter_by(nvr=nvr).one().update
         assert update.karma == 2
         assert update.request is None
-        with fml_testing.mock_sends(api.Message, api.Message):
+        with fml_testing.mock_sends(api.Message, api.Message, api.Message):
             update.comment(self.db, "foo", 1, 'biz')
         update = Build.query.filter_by(nvr=nvr).one().update
         assert update.karma == 3
@@ -3351,7 +3351,7 @@ def test_pending_update_on_stable_karma_reached_autopush_enabled(self, *args):
         up.comment(self.db, 'WFM', author='dustymabe', karma=1)
         up = self.db.query(Build).filter_by(nvr=nvr).one().update
 
-        with fml_testing.mock_sends(api.Message):
+        with fml_testing.mock_sends(api.Message, api.Message):
             up.comment(self.db, 'LGTM', author='bowlofeggs', karma=1)
         up = self.db.query(Build).filter_by(nvr=nvr).one().update
 
@@ -3383,7 +3383,7 @@ def test_pending_urgent_update_on_stable_karma_reached_autopush_enabled(self, *a
         up.comment(self.db, 'WFM', author='dustymabe', karma=1)
         up = self.db.query(Build).filter_by(nvr=nvr).one().update
 
-        with fml_testing.mock_sends(api.Message):
+        with fml_testing.mock_sends(api.Message, api.Message):
             up.comment(self.db, 'LGTM', author='bowlofeggs', karma=1)
         up = self.db.query(Build).filter_by(nvr=nvr).one().update
 
@@ -4710,7 +4710,7 @@ def test_autopush_critical_update_with_no_negative_karma(self, *args):
         up.comment(self.db, 'LGTM', author='ralph', karma=1)
         up = self.db.query(Update).filter_by(alias=resp.json['alias']).one()
 
-        with fml_testing.mock_sends(api.Message):
+        with fml_testing.mock_sends(api.Message, api.Message):
             up.comment(self.db, 'LGTM', author='bowlofeggs', karma=1)
         up = self.db.query(Update).filter_by(alias=resp.json['alias']).one()
         assert up.karma == 2
@@ -4908,7 +4908,7 @@ def test_autopush_non_critical_update_with_no_negative_karma(self, *args):
         up.comment(self.db, 'LGTM Now', author='ralph', karma=1)
         up = self.db.query(Update).filter_by(alias=resp.json['alias']).one()
 
-        with fml_testing.mock_sends(api.Message):
+        with fml_testing.mock_sends(api.Message, api.Message):
             up.comment(self.db, 'WFM', author='puiterwijk', karma=1)
         up = self.db.query(Update).filter_by(alias=resp.json['alias']).one()
 
@@ -5414,7 +5414,7 @@ def test_submit_older_build_to_stable(self, *args):
                         stable_karma=3, unstable_karma=-3)
         update.comment(self.db, "foo1", 1, 'foo1')
         update.comment(self.db, "foo2", 1, 'foo2')
-        with fml_testing.mock_sends(api.Message, api.Message):
+        with fml_testing.mock_sends(api.Message, api.Message, api.Message):
             update.comment(self.db, "foo3", 1, 'foo3')
         self.db.add(update)
         # Let's clear any messages that might get sent
diff --git a/bodhi/tests/server/tasks/test_approve_testing.py b/bodhi/tests/server/tasks/test_approve_testing.py
--- a/bodhi/tests/server/tasks/test_approve_testing.py
+++ b/bodhi/tests/server/tasks/test_approve_testing.py
@@ -822,8 +822,8 @@ def test_autotime_update_with_autokarma_met_karma_and_time_requirements_get_push
         # Clear pending messages
         self.db.info['messages'] = []
 
-        update.comment(self.db, u'Works great', author=u'luke', karma=1)
         with fml_testing.mock_sends(api.Message, api.Message, api.Message):
+            update.comment(self.db, u'Works great', author=u'luke', karma=1)
             self.db.commit()
 
         approve_testing_main()
diff --git a/bodhi/tests/server/test_models.py b/bodhi/tests/server/test_models.py
--- a/bodhi/tests/server/test_models.py
+++ b/bodhi/tests/server/test_models.py
@@ -1720,7 +1720,8 @@ def test_new_builds_log_when_release_has_no_signing_tag(self, warning):
         update.release.pending_signing_tag = ''
         self.db.flush()
 
-        model.Update.edit(request, data)
+        with mock_sends(Message):
+            model.Update.edit(request, data)
 
         warning.assert_called_once_with('F17 has no pending_signing_tag')
         update = model.Update.query.first()
@@ -1749,8 +1750,8 @@ def test_empty_display_name(self):
         request = mock.MagicMock()
         request.db = self.db
         request.user.name = 'tester'
-
-        model.Update.edit(request, data)
+        with mock_sends(Message):
+            model.Update.edit(request, data)
 
         update = model.Update.query.first()
         assert update.display_name == ''
@@ -1790,7 +1791,8 @@ def test_version_hash(self):
         request.db = self.db
         request.user.name = 'tester'
         self.db.flush()
-        model.Update.edit(request, data)
+        with mock_sends(Message):
+            model.Update.edit(request, data)
 
         # now, with two builds, check the hash has changed
         updated_expected_hash = "d89b54971b965505179438481d761f8b5ee64e8c"
@@ -2217,7 +2219,7 @@ def test_autokarma_update_reaching_stable_karma(self):
         update.status = UpdateStatus.testing
         update.stable_karma = 1
         # Now let's add some karma to get it to the required threshold
-        with mock_sends(Message):
+        with mock_sends(Message, Message):
             update.comment(self.db, 'testing', author='hunter2', karma=1)
 
         # meets_testing_requirement() should return True since the karma threshold has been reached
@@ -2255,7 +2257,7 @@ def test_critpath_karma_2_met(self):
         update.critpath = True
         update.stable_karma = 1
         with mock.patch('bodhi.server.models.handle_update'):
-            with mock_sends(Message, Message, Message, Message):
+            with mock_sends(Message, Message, Message, Message, Message):
                 update.comment(self.db, 'testing', author='enemy', karma=-1)
                 update.comment(self.db, 'testing', author='bro', karma=1)
                 # Despite meeting the stable_karma, the function should still not
@@ -3366,7 +3368,8 @@ def test_set_request_pending_stable(self):
         req.koji = buildsys.get_session()
         assert self.obj.status == UpdateStatus.pending
         self.obj.stable_karma = 1
-        self.obj.comment(self.db, 'works', karma=1, author='bowlofeggs')
+        with mock_sends(Message):
+            self.obj.comment(self.db, 'works', karma=1, author='bowlofeggs')
 
         self.obj.set_request(self.db, UpdateRequest.stable, req.user.name)
 
@@ -3583,7 +3586,8 @@ def test_set_request_string_action(self):
         req.koji = buildsys.get_session()
         assert self.obj.status == UpdateStatus.pending
         self.obj.stable_karma = 1
-        self.obj.comment(self.db, 'works', karma=1, author='bowlofeggs')
+        with mock_sends(Message):
+            self.obj.comment(self.db, 'works', karma=1, author='bowlofeggs')
 
         self.obj.set_request(self.db, 'stable', req.user.name)