Repository: fedora-infra/bodhi

Issue:
bodhi randomly throws "NoSuchColumnError testcases.id" server errors for various queries
This looks like a continuation of the https://github.com/fedora-infra/bodhi/issues/4287 saga but with a different database table / column involved:

```
{
    errors: [
        {
            "name": "NoSuchColumnError",
            "location": "body",
            "description": "Could not locate column in row for column 'testcases.id'"
        },
    ],
    status: "error"
}
```

This seems to happen at about the same frequency as the "bugs.id" problem that happened before bodhi 5.7.2 was deployed.


Discussion:
Damn it. I never see problems like this when I test on staging. Looking into it.
@AdamSaleh can you please deploy this commit as a hotfix in prod:

```
diff --git a/bodhi/server/models.py b/bodhi/server/models.py
index c2506cc2..7f669904 100644
--- a/bodhi/server/models.py
+++ b/bodhi/server/models.py
@@ -1918,8 +1918,8 @@ class Update(Base):
 
     # One-to-many relationships
     comments = relationship('Comment', backref='update', cascade="all,delete,delete-orphan",
-                            order_by='Comment.timestamp')
-    builds = relationship('Build', backref='update', order_by='Build.nvr')
+                            order_by='Comment.timestamp', lazy='joined')
+    builds = relationship('Build', backref='update', order_by='Build.nvr', lazy='joined')
 
     # Many-to-many relationships
     bugs = relationship('Bug', secondary=update_bug_table, backref='updates', order_by='Bug.bug_id')
```

It partially reverts what I've done in #4048 , let's see if it can help... otherwise we'll need someone with a lot of experience in sqlalchemy to review our relationship joins...
ok, and I definitely need to add something like this to my pre-release checklist. Because while I will try to deploy the fix asap, I am very annoyed that I can't reliably reproduce the damn thing.

Resolving patch:
diff --git a/bodhi/server/models.py b/bodhi/server/models.py
--- a/bodhi/server/models.py
+++ b/bodhi/server/models.py
@@ -1918,8 +1918,8 @@ class Update(Base):
 
     # One-to-many relationships
     comments = relationship('Comment', backref='update', cascade="all,delete,delete-orphan",
-                            order_by='Comment.timestamp')
-    builds = relationship('Build', backref='update', order_by='Build.nvr')
+                            order_by='Comment.timestamp', lazy='joined')
+    builds = relationship('Build', backref='update', order_by='Build.nvr', lazy='joined')
 
     # Many-to-many relationships
     bugs = relationship('Bug', secondary=update_bug_table, backref='updates', order_by='Bug.bug_id')


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
@@ -2938,8 +2938,9 @@ def test_list_updates_with_multiple_statuses(self):
         res = self.app.get('/updates/', {"status": ["pending", "testing"]})
         body = res.json_body
         assert len(body['updates']) == 2
-        assert body['updates'][0]['title'] == 'bodhi-2.0-1.fc17'
-        assert body['updates'][1]['title'] == 'python-nose-1.3.7-11.fc17'
+        expected = ['bodhi-2.0-1.fc17', 'python-nose-1.3.7-11.fc17']
+        actual = sorted(update['title'] for update in body['updates'])
+        assert expected == actual
 
     def test_list_updates_by_suggest(self):
         res = self.app.get('/updates/', {"suggest": "unspecified"})
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
@@ -188,7 +188,8 @@ def test__to_json_no_seen(self):
 
     def test_grid_columns(self):
         """Assert correct return value from the grid_columns() method."""
-        assert model.Build.grid_columns() == ['nvr', 'signed', 'release_id', 'type', 'epoch']
+        assert sorted(model.Build.grid_columns()) == sorted(['nvr', 'signed', 'release_id',
+                                                             'type', 'epoch'])
 
     def test_find_child_for_rpm(self):
         subclass = model.Package.find_polymorphic_child(model.ContentType.rpm)
diff --git a/bodhi/tests/server/test_push.py b/bodhi/tests/server/test_push.py
--- a/bodhi/tests/server/test_push.py
+++ b/bodhi/tests/server/test_push.py
@@ -202,9 +202,9 @@ def test_archived_release(self):
 
 ===== <Compose: F17 testing> =====
 
-bodhi-2.0-1.fc17
 python-nose-1.3.7-11.fc17
 python-paste-deploy-1.5.2-8.fc17
+bodhi-2.0-1.fc17
 
 
 Push these 3 updates? [y/N]: n
@@ -215,8 +215,8 @@ def test_archived_release(self):
 
 ===== <Compose: F17 testing> =====
 
-python-nose-1.3.7-11.fc17
 ejabberd-16.09-4.fc17
+python-nose-1.3.7-11.fc17
 
 
 Push these 2 updates? [y/N]: y
@@ -230,9 +230,9 @@ def test_archived_release(self):
 
 ===== <Compose: F17 testing> =====
 
-bodhi-2.0-1.fc17
 python-nose-1.3.7-11.fc17
 python-paste-deploy-1.5.2-8.fc17
+bodhi-2.0-1.fc17
 
 
 Pushing 3 updates.
@@ -295,8 +295,8 @@ def test_archived_release(self):
 
 ===== <Compose: F17 testing> =====
 
-bodhi-2.0-1.fc17
 python-paste-deploy-1.5.2-8.fc17
+bodhi-2.0-1.fc17
 
 
 Push these 2 updates? [y/N]: y