← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~lgp171188/launchpad:fix-database-disconnection-error-view-integration-test-postgres-14 into launchpad:master

 

Guruprasad has proposed merging ~lgp171188/launchpad:fix-database-disconnection-error-view-integration-test-postgres-14 into launchpad:master.

Commit message:
Fix a DB disconnection error view integration test for Postgres 14

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/479907
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:fix-database-disconnection-error-view-integration-test-postgres-14 into launchpad:master.
diff --git a/lib/lp/services/webapp/errorlog.py b/lib/lp/services/webapp/errorlog.py
index f2cb950..cd7d642 100644
--- a/lib/lp/services/webapp/errorlog.py
+++ b/lib/lp/services/webapp/errorlog.py
@@ -424,9 +424,7 @@ class ErrorReportingUtility:
                 "database does not allow connections",
                 "pgbouncer database is disabled",
             ):
-                if message.startswith(ok) or message.startswith(
-                    "ERROR:  " + ok
-                ):
+                if ok in message or f"ERROR:  {ok}" in message:
                     return True
         return False
 
diff --git a/lib/lp/services/webapp/tests/test_error.py b/lib/lp/services/webapp/tests/test_error.py
index 0ebc506..af289b1 100644
--- a/lib/lp/services/webapp/tests/test_error.py
+++ b/lib/lp/services/webapp/tests/test_error.py
@@ -5,6 +5,7 @@
 
 import http.client
 import logging
+import re
 import socket
 import time
 from urllib.error import HTTPError
@@ -138,6 +139,28 @@ class TestDatabaseErrorViews(TestCase):
             def __init__(self, message):
                 super().__init__(("DisconnectionError", message))
 
+        class DisconnectsWithMessageRegex:
+            def __init__(self, message_regex):
+                self.message_regex = message_regex
+
+            def match(self, actual):
+                if "DisconnectionError" != actual[0] or not re.match(
+                    self.message_regex, actual[1]
+                ):
+
+                    class DisconnectsWithMessageRegexMismatch:
+                        def __init__(self, description):
+                            self.description = description
+
+                        def describe(self):
+                            return self.description
+
+                    return DisconnectsWithMessageRegexMismatch(
+                        "reference = ('DisconnectionError', "
+                        f"'{self.message_regex}')\n"
+                        f"actual    = ('{actual[0]}', '{actual[1]}')"
+                    )
+
         browser = Browser()
         browser.raiseHttpErrors = False
         with CaptureOops() as oopses:
@@ -146,6 +169,10 @@ class TestDatabaseErrorViews(TestCase):
         self.assertThat(
             browser.contents, Contains(DisconnectionErrorView.reason)
         )
+        libpq_14_connection_error_prefix_regex = (
+            r'connection to server at "localhost" \(127\.0\.0\.1\), '
+            r"port .* failed"
+        )
         self.assertThat(
             [
                 (oops["type"], oops["value"].split("\n")[0])
@@ -164,9 +191,17 @@ class TestDatabaseErrorViews(TestCase):
                 ]
                 * 2
                 + [
-                    Disconnects(
-                        "could not connect to server: Connection refused"
-                    )
+                    MatchesAny(
+                        # libpq < 14.0
+                        Disconnects(
+                            "could not connect to server: Connection refused"
+                        ),
+                        # libpq >= 14.0
+                        DisconnectsWithMessageRegex(
+                            libpq_14_connection_error_prefix_regex
+                            + ": Connection refused"
+                        ),
+                    ),
                 ]
                 * 6
             ),
@@ -186,14 +221,21 @@ class TestDatabaseErrorViews(TestCase):
             ],
             MatchesListwise(
                 [
-                    Disconnects(
-                        "could not connect to server: Connection refused"
+                    MatchesAny(
+                        # libpa < 14.0
+                        Disconnects(
+                            "could not connect to server: Connection refused"
+                        ),
+                        # libpq >= 14.0
+                        DisconnectsWithMessageRegex(
+                            libpq_14_connection_error_prefix_regex
+                            + ": Connection refused"
+                        ),
                     )
                 ]
                 * 8
             ),
         )
-
         # When the database is available again, requests succeed.
         bouncer.start()
         self.retryConnection(url, bouncer)
@@ -223,7 +265,19 @@ class TestDatabaseErrorViews(TestCase):
         ]
         self.assertNotEqual([], disconnection_oopses)
         self.assertThat(
-            disconnection_oopses, AllMatch(Disconnects("database removed"))
+            disconnection_oopses,
+            AllMatch(
+                MatchesAny(
+                    # libpq < 14.0
+                    Disconnects("database removed"),
+                    # libpq >= 14.0
+                    DisconnectsWithMessageRegex(
+                        libpq_14_connection_error_prefix_regex
+                        + ": ERROR: database does not allow connections: "
+                        r"launchpad_ftest_.*"
+                    ),
+                )
+            ),
         )
 
         # A second request doesn't log any OOPSes.