]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix: fix iteration resolving hosts with multiple IP addresses in async mode
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 12 Dec 2023 16:56:37 +0000 (17:56 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 12 Dec 2023 17:03:09 +0000 (18:03 +0100)
Fix #695 (not 100% sure, but probably).

docs/news.rst
psycopg/psycopg/conninfo.py
tests/test_conninfo.py

index b2d74212454651dca7e0129e6126b41b04835c25..17d5638ebe97e9872b0b167bb348914296c2c7bd 100644 (file)
@@ -7,6 +7,16 @@
 ``psycopg`` release notes
 =========================
 
+Future releases
+---------------
+
+Psycopg 3.1.15 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Fix async connection to hosts resolving to  multiple IP addresses
+  (:ticket:`#695`).
+
+
 Current release
 ---------------
 
index bdb5526d3ea3f000e2589dac5c7664bbdb687fe7..6c48da734de127126e49faa61444d6ccc7086914 100644 (file)
@@ -448,10 +448,8 @@ async def _split_attempts_and_resolve(params: ConnDict) -> AsyncIterator[ConnDic
         host, port, proto=socket.IPPROTO_TCP, type=socket.SOCK_STREAM
     )
 
-    attempt = params.copy()
     for item in ans:
-        attempt["hostaddr"] = item[4][0]
-    yield attempt
+        yield {**params, "hostaddr": item[4][0]}
 
 
 @cache
index 2ae1d142a3b281ea25a53d880082dc03a433bc1f..83174026f0004cf6a198699192248774477d95a6 100644 (file)
@@ -436,6 +436,11 @@ async def test_conninfo_attempts_async_no_resolve(
             "host=foo.com,qux.com hostaddr=1.1.1.1,2.2.2.2",
             {},
         ),
+        (
+            "host=dup.com",
+            "host=dup.com,dup.com hostaddr=3.3.3.3,3.3.3.4",
+            None,
+        ),
     ],
 )
 @pytest.mark.anyio
@@ -499,19 +504,26 @@ def test_conninfo_random(dsn, conn_cls):
 @pytest.fixture
 async def fake_resolve(monkeypatch):
     fake_hosts = {
-        "localhost": "127.0.0.1",
-        "foo.com": "1.1.1.1",
-        "qux.com": "2.2.2.2",
+        "localhost": ["127.0.0.1"],
+        "foo.com": ["1.1.1.1"],
+        "qux.com": ["2.2.2.2"],
+        "dup.com": ["3.3.3.3", "3.3.3.4"],
     }
 
+    def family(host):
+        return socket.AF_INET6 if ":" in host else socket.AF_INET
+
     async def fake_getaddrinfo(host, port, **kwargs):
         assert isinstance(port, int) or (isinstance(port, str) and port.isdigit())
         try:
-            addr = fake_hosts[host]
+            addrs = fake_hosts[host]
         except KeyError:
             raise OSError(f"unknown test host: {host}")
         else:
-            return [(socket.AF_INET, socket.SOCK_STREAM, 6, "", (addr, 432))]
+            return [
+                (family(addr), socket.SOCK_STREAM, 6, "", (addr, port))
+                for addr in addrs
+            ]
 
     monkeypatch.setattr(asyncio.get_running_loop(), "getaddrinfo", fake_getaddrinfo)