]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix(crdb): pq tests adapted
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sun, 5 Jun 2022 21:27:10 +0000 (23:27 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 12 Jul 2022 11:58:34 +0000 (12:58 +0100)
tests/fix_crdb.py
tests/pq/test_async.py
tests/pq/test_copy.py
tests/pq/test_escaping.py
tests/pq/test_exec.py
tests/pq/test_misc.py
tests/pq/test_pgconn.py
tests/pq/test_pgresult.py
tests/test_sql.py

index b9e8373f11db1ddb47463a0372f425a8f7fc18fb..d989582c87acda8eff39d246f8c939bdf0c611e9 100644 (file)
@@ -77,6 +77,10 @@ def crdb_time_precision(*args):
     return skip_crdb(*args, reason="time precision")
 
 
+def crdb_scs_off(*args):
+    return skip_crdb(*args, reason="standard_conforming_strings=off")
+
+
 # mapping from reason description to ticket number
 _crdb_reasons = {
     "2-phase commit": 22329,
@@ -86,8 +90,8 @@ _crdb_reasons = {
     "cast adds tz": 51692,
     "cidr": 18846,
     "composite": 27792,
-    "copy": 41608,
     "copy canceled": 81559,
+    "copy": 41608,
     "cursor with hold": 77101,
     "deferrable": 48307,
     "do": 17511,
@@ -96,13 +100,14 @@ _crdb_reasons = {
     "infinity date": 41564,
     "interval style": 35807,
     "large objects": 243,
-    "server-side cursor": 41412,
     "negative interval": 81577,
     "nested array": 32552,
     "notify": 41522,
     "password_encryption": 42519,
     "pg_terminate_backend": 35897,
     "range": 41282,
+    "severity_nonlocalized": 81794,
     "scroll cursor": 77102,
+    "server-side cursor": 41412,
     "stored procedure": 1751,
 }
index fee58f0755c812733c39d7f60eea02fd182cfe2c..113b548445ace178369b1ac0956ab48c9f426e0d 100644 (file)
@@ -1,5 +1,7 @@
-import pytest
 from select import select
+
+import pytest
+
 import psycopg
 from psycopg import pq
 from psycopg.generators import execute
@@ -15,7 +17,8 @@ def test_send_query(pgconn):
 
     # Long query to make sure we have to wait on send
     pgconn.send_query(
-        b"/* %s */ select pg_sleep(0.01); select 1 as foo;" % (b"x" * 1_000_000)
+        b"/* %s */ select 'x' as f from pg_sleep(0.01); select 1 as foo;"
+        % (b"x" * 1_000_000)
     )
 
     # send loop
@@ -53,8 +56,8 @@ def test_send_query(pgconn):
 
     assert len(results) == 2
     assert results[0].nfields == 1
-    assert results[0].fname(0) == b"pg_sleep"
-    assert results[0].get_value(0, 0) == b""
+    assert results[0].fname(0) == b"f"
+    assert results[0].get_value(0, 0) == b"x"
     assert results[1].nfields == 1
     assert results[1].fname(0) == b"foo"
     assert results[1].get_value(0, 0) == b"1"
@@ -63,14 +66,15 @@ def test_send_query(pgconn):
 def test_send_query_compact_test(pgconn):
     # Like the above test but use psycopg facilities for compactness
     pgconn.send_query(
-        b"/* %s */ select pg_sleep(0.01); select 1 as foo;" % (b"x" * 1_000_000)
+        b"/* %s */ select 'x' as f from pg_sleep(0.01); select 1 as foo;"
+        % (b"x" * 1_000_000)
     )
     results = execute_wait(pgconn)
 
     assert len(results) == 2
     assert results[0].nfields == 1
-    assert results[0].fname(0) == b"pg_sleep"
-    assert results[0].get_value(0, 0) == b""
+    assert results[0].fname(0) == b"f"
+    assert results[0].get_value(0, 0) == b"x"
     assert results[1].nfields == 1
     assert results[1].fname(0) == b"foo"
     assert results[1].get_value(0, 0) == b"1"
@@ -169,7 +173,7 @@ def test_send_prepared_binary_out(pgconn, fmt, out):
 
 
 def test_send_describe_prepared(pgconn):
-    pgconn.send_prepare(b"prep", b"select $1::int + $2::int as fld")
+    pgconn.send_prepare(b"prep", b"select $1::int8 + $2::int8 as fld")
     (res,) = execute_wait(pgconn)
     assert res.status == pq.ExecStatus.COMMAND_OK, res.error_message
 
@@ -178,13 +182,14 @@ def test_send_describe_prepared(pgconn):
     assert res.nfields == 1
     assert res.ntuples == 0
     assert res.fname(0) == b"fld"
-    assert res.ftype(0) == 23
+    assert res.ftype(0) == 20
 
     pgconn.finish()
     with pytest.raises(psycopg.OperationalError):
         pgconn.send_describe_prepared(b"prep")
 
 
+@pytest.mark.crdb("skip", reason="server-side cursor")
 def test_send_describe_portal(pgconn):
     res = pgconn.exec_(
         b"""
index d45416d27a5d9f184ea86b10b75db511a7e8b8de..cec848b2a5bd5a5e0a9c9c2741124412e80dd779 100644 (file)
@@ -3,6 +3,8 @@ import pytest
 import psycopg
 from psycopg import pq
 
+pytestmark = pytest.mark.crdb("skip", reason="copy")
+
 sample_values = "values (10::int, 20::int, 'hello'::text), (40, NULL, 'world')"
 
 sample_tabledef = "col1 int primary key, col2 int, data text"
index 59259c9b15925a781e4c91f4c41fcae2533f8c38..ad88d8a037c1715eb50554899e82390178c8305f 100644 (file)
@@ -3,6 +3,8 @@ import pytest
 import psycopg
 from psycopg import pq
 
+from ..fix_crdb import crdb_scs_off
+
 
 @pytest.mark.parametrize(
     "data, want",
@@ -19,7 +21,7 @@ def test_escape_literal(pgconn, data, want):
     assert out == want
 
 
-@pytest.mark.parametrize("scs", ["on", "off"])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
 def test_escape_literal_1char(pgconn, scs):
     res = pgconn.exec_(f"set standard_conforming_strings to {scs}".encode("ascii"))
     assert res.status == pq.ExecStatus.COMMAND_OK
@@ -58,7 +60,7 @@ def test_escape_identifier(pgconn, data, want):
     assert out == want
 
 
-@pytest.mark.parametrize("scs", ["on", "off"])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
 def test_escape_identifier_1char(pgconn, scs):
     res = pgconn.exec_(f"set standard_conforming_strings to {scs}".encode("ascii"))
     assert res.status == pq.ExecStatus.COMMAND_OK
@@ -97,7 +99,7 @@ def test_escape_string(pgconn, data, want):
     assert out == want
 
 
-@pytest.mark.parametrize("scs", ["on", "off"])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
 def test_escape_string_1char(pgconn, scs):
     esc = pq.Escaping(pgconn)
     res = pgconn.exec_(f"set standard_conforming_strings to {scs}".encode("ascii"))
index 136879317defa00f2cf730e0037e6597af27265e..3ae4eeb165350f072a3ad6394c045d7728784c77 100644 (file)
@@ -126,6 +126,7 @@ def test_exec_prepared_binary_out(pgconn, fmt, out):
     assert res.get_value(0, 0) == out
 
 
+@pytest.mark.crdb("skip", reason="server-side cursor")
 def test_describe_portal(pgconn):
     res = pgconn.exec_(
         b"""
index ca809a8564ea2a1225f5aa85be72466e86c5d02d..eef4d2dac95ad75afffc99c259968b918cfcd632 100644 (file)
@@ -22,6 +22,7 @@ def test_error_message(pgconn):
     assert "NULL" in pq.error_message(pgconn)
 
 
+@pytest.mark.crdb("skip", reason="encoding")
 def test_error_message_encoding(pgconn):
     res = pgconn.exec_(b"set client_encoding to latin9")
     assert res.status == pq.ExecStatus.COMMAND_OK
index 4545ed59ad6e1149d0e2e5d9186ca179611758f5..6f339617b35eb79f32cb7273d6c3c8a13f730ab6 100644 (file)
@@ -51,6 +51,7 @@ def test_connect_async(dsn):
         conn.connect_poll()
 
 
+@pytest.mark.crdb("skip", reason="connects to any db name")
 def test_connect_async_bad(dsn):
     parsed_dsn = {e.keyword: e.val for e in pq.Conninfo.parse(dsn.encode()) if e.val}
     parsed_dsn[b"dbname"] = b"psycopg_test_not_for_real"
@@ -130,6 +131,7 @@ def test_info(dsn, pgconn):
         pgconn.info
 
 
+@pytest.mark.crdb("skip", reason="pg_terminate_backend")
 def test_reset(pgconn):
     assert pgconn.status == pq.ConnStatus.OK
     pgconn.exec_(b"select pg_terminate_backend(pg_backend_pid())")
@@ -144,6 +146,7 @@ def test_reset(pgconn):
     assert pgconn.status == pq.ConnStatus.BAD
 
 
+@pytest.mark.crdb("skip", reason="pg_terminate_backend")
 def test_reset_async(pgconn):
     assert pgconn.status == pq.ConnStatus.OK
     pgconn.exec_(b"select pg_terminate_backend(pg_backend_pid())")
@@ -269,6 +272,7 @@ def test_parameter_status(dsn, monkeypatch):
         pgconn.parameter_status(b"application_name")
 
 
+@pytest.mark.crdb("skip", reason="encoding")
 def test_encoding(pgconn):
     res = pgconn.exec_(b"set client_encoding to latin1")
     assert res.status == pq.ExecStatus.COMMAND_OK
@@ -398,6 +402,7 @@ def test_cancel_free(pgconn):
     cancel.free()
 
 
+@pytest.mark.crdb("skip", reason="notify")
 def test_notify(pgconn):
     assert pgconn.notifies() is None
 
@@ -425,6 +430,7 @@ def test_notify(pgconn):
     assert pgconn.notifies() is None
 
 
+@pytest.mark.crdb("skip", reason="do")
 def test_notice_nohandler(pgconn):
     pgconn.exec_(b"set client_min_messages to notice")
     res = pgconn.exec_(
@@ -433,6 +439,7 @@ def test_notice_nohandler(pgconn):
     assert res.status == pq.ExecStatus.COMMAND_OK
 
 
+@pytest.mark.crdb("skip", reason="do")
 def test_notice(pgconn):
     msgs = []
 
@@ -450,6 +457,7 @@ def test_notice(pgconn):
     assert msgs and msgs[0] == b"hello notice"
 
 
+@pytest.mark.crdb("skip", reason="do")
 def test_notice_error(pgconn, caplog):
     caplog.set_level(logging.WARNING, logger="psycopg")
 
@@ -492,13 +500,13 @@ def test_trace(pgconn, tmp_path):
     with tracef.open("w") as f:
         pgconn.trace(f.fileno())
         pgconn.set_trace_flags(pq.Trace.SUPPRESS_TIMESTAMPS | pq.Trace.REGRESS_MODE)
-        pgconn.exec_(b"select 1")
+        pgconn.exec_(b"select 1::int4 as foo")
         pgconn.untrace()
-        pgconn.exec_(b"select 2")
+        pgconn.exec_(b"select 2::int4 as foo")
     traces = [line.split("\t") for line in tracef.read_text().splitlines()]
     assert traces == [
-        ["F", "13", "Query", ' "select 1"'],
-        ["B", "33", "RowDescription", ' 1 "?column?" NNNN 0 NNNN 4 -1 0'],
+        ["F", "26", "Query", ' "select 1::int4 as foo"'],
+        ["B", "28", "RowDescription", ' 1 "foo" NNNN 0 NNNN 4 -1 0'],
         ["B", "11", "DataRow", " 1 1 '1'"],
         ["B", "13", "CommandComplete", ' "SELECT 1"'],
         ["B", "5", "ReadyForQuery", " I"],
@@ -530,9 +538,10 @@ def test_encrypt_password_badalgo(pgconn):
 
 
 @pytest.mark.libpq(">= 10")
+@pytest.mark.crdb("skip", reason="password_encryption")
 def test_encrypt_password_query(pgconn):
     res = pgconn.exec_(b"set password_encryption to 'md5'")
-    assert res.status == pq.ExecStatus.COMMAND_OK
+    assert res.status == pq.ExecStatus.COMMAND_OK, pgconn.error_message.decode()
     enc = pgconn.encrypt_password(b"psycopg2", b"ashesh")
     assert enc == b"md594839d658c28a357126f105b9cb14cfc"
 
index 40ca336886e11ed5ea19b36fa5da14b463cb86f2..3ad818d099206257288e21be3a00ec2ec471a1a0 100644 (file)
@@ -52,7 +52,11 @@ def test_error_message(pgconn):
 
 def test_error_field(pgconn):
     res = pgconn.exec_(b"select wat")
-    assert res.error_field(pq.DiagnosticField.SEVERITY_NONLOCALIZED) == b"ERROR"
+    # https://github.com/cockroachdb/cockroach/issues/81794
+    assert (
+        res.error_field(pq.DiagnosticField.SEVERITY_NONLOCALIZED)
+        or res.error_field(pq.DiagnosticField.SEVERITY)
+    ) == b"ERROR"
     assert res.error_field(pq.DiagnosticField.SQLSTATE) == b"42703"
     assert b"wat" in res.error_field(pq.DiagnosticField.MESSAGE_PRIMARY)
     res.clear()
@@ -86,6 +90,7 @@ def test_fname(pgconn):
     assert res.fname(0) is None
 
 
+@pytest.mark.crdb("skip", reason="ftable")
 def test_ftable_and_col(pgconn):
     res = pgconn.exec_(
         b"""
@@ -122,7 +127,7 @@ def test_fformat(pgconn, fmt):
 
 
 def test_ftype(pgconn):
-    res = pgconn.exec_(b"select 1::int, 1::numeric, 1::text")
+    res = pgconn.exec_(b"select 1::int4, 1::numeric, 1::text")
     assert res.status == pq.ExecStatus.TUPLES_OK, res.error_message
     assert res.ftype(0) == 23
     assert res.ftype(1) == 1700
@@ -142,7 +147,7 @@ def test_fmod(pgconn):
 
 
 def test_fsize(pgconn):
-    res = pgconn.exec_(b"select 1::int, 1::bigint, 1::text")
+    res = pgconn.exec_(b"select 1::int4, 1::bigint, 1::text")
     assert res.status == pq.ExecStatus.TUPLES_OK, res.error_message
     assert res.fsize(0) == 4
     assert res.fsize(1) == 8
@@ -162,7 +167,7 @@ def test_get_value(pgconn):
 
 
 def test_nparams_types(pgconn):
-    res = pgconn.prepare(b"", b"select $1::int, $2::text")
+    res = pgconn.prepare(b"", b"select $1::int4, $2::text")
     assert res.status == pq.ExecStatus.COMMAND_OK, res.error_message
 
     res = pgconn.describe_prepared(b"")
@@ -180,7 +185,7 @@ def test_nparams_types(pgconn):
 def test_command_status(pgconn):
     res = pgconn.exec_(b"select 1")
     assert res.command_status == b"SELECT 1"
-    res = pgconn.exec_(b"set timezone to utf8")
+    res = pgconn.exec_(b"set timezone to utc")
     assert res.command_status == b"SET"
     res.clear()
     assert res.command_status is None
index 991e435007355f86eec7eb0b97906ef62d32697a..0f3cb23be2569dd88a30e51a295286f9c249beeb 100644 (file)
@@ -14,9 +14,7 @@ from psycopg.types import TypeInfo
 from psycopg.types.string import StrDumper
 
 from .utils import eur
-from .fix_crdb import crdb_encoding
-
-crdb_skip_scs = pytest.mark.crdb("skip", reason="standard_conforming_strings=off")
+from .fix_crdb import crdb_encoding, crdb_scs_off
 
 
 @pytest.mark.parametrize(
@@ -33,7 +31,7 @@ def test_quote(obj, quoted):
     assert sql.quote(obj) == quoted
 
 
-@pytest.mark.parametrize("scs", ["on", pytest.param("off", marks=crdb_skip_scs)])
+@pytest.mark.parametrize("scs", ["on", crdb_scs_off("off")])
 def test_quote_roundtrip(conn, scs):
     messages = []
     conn.add_notice_handler(lambda msg: messages.append(msg.message_primary))
@@ -49,8 +47,8 @@ def test_quote_roundtrip(conn, scs):
         assert not messages, f"error with {want!r}"
 
 
-@crdb_skip_scs
-def test_quote_stable_despite_deranged_libpq(conn):
+@pytest.mark.parametrize("dummy", [crdb_scs_off("off")])
+def test_quote_stable_despite_deranged_libpq(conn, dummy):
     # Verify the libpq behaviour of PQescapeString using the last setting seen.
     # Check that we are not affected by it.
     good_str = " E'\\\\'"