From acc9069e826e36b9fc7439282a330b44dd055b66 Mon Sep 17 00:00:00 2001 From: Robsdedude Date: Wed, 28 Jun 2023 15:02:19 +0200 Subject: [PATCH 1/2] Fix handling of sub-ms transaction timeouts Transaction timeouts are specified in seconds as float. However, the server expects it in milliseconds as int. This would lead to 1) rounding issues: previously, the driver would multiply by 1000 and then truncate to int. E.g., 256.4 seconds would be turned into 256399 ms because of float imprecision. Therefore, the built-in `round` is now used instead. 2) values below 1 ms (e.g., 0.0001) would be rounded down to 0. However, 0 is a special value that instructs the server to not apply any timeout. This is likely to surprise the user which specified a non-zero timeout. In this special case, the driver now rounds up to 1 ms. --- src/neo4j/_async/io/_bolt.py | 29 +++++++++++ src/neo4j/_async/io/_bolt3.py | 15 ++---- src/neo4j/_async/io/_bolt4.py | 29 ++--------- src/neo4j/_async/io/_bolt5.py | 29 ++--------- src/neo4j/_sync/io/_bolt.py | 29 +++++++++++ src/neo4j/_sync/io/_bolt3.py | 15 ++---- src/neo4j/_sync/io/_bolt4.py | 29 ++--------- src/neo4j/_sync/io/_bolt5.py | 29 ++--------- tests/unit/async_/io/test_class_bolt3.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt4x0.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt4x1.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt4x2.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt4x3.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt4x4.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt5x0.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt5x1.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt5x2.py | 58 ++++++++++++++++++++++ tests/unit/async_/io/test_class_bolt5x3.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt3.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt4x0.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt4x1.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt4x2.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt4x3.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt4x4.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt5x0.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt5x1.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt5x2.py | 58 ++++++++++++++++++++++ tests/unit/sync/io/test_class_bolt5x3.py | 58 ++++++++++++++++++++++ 28 files changed, 1244 insertions(+), 120 deletions(-) diff --git a/src/neo4j/_async/io/_bolt.py b/src/neo4j/_async/io/_bolt.py index fd4afbc69..b3a394232 100644 --- a/src/neo4j/_async/io/_bolt.py +++ b/src/neo4j/_async/io/_bolt.py @@ -947,3 +947,32 @@ def is_idle_for(self, timeout): AsyncBoltSocket.Bolt = AsyncBolt # type: ignore + + +def tx_timeout_as_ms(timeout: float) -> int: + """Round transaction timeout to milliseconds. + + Values in (0, 1], else values are rounded using the built-in round() + function (round n.5 values to nearest even). + + :param timeout: timeout in seconds (must be >= 0) + + :returns: timeout in milliseconds (rounded) + + :raise ValueError: if timeout is negative + """ + try: + timeout = float(timeout) + except (TypeError, ValueError) as e: + err_type = type(e) + msg = "Timeout must be specified as a number of seconds" + raise err_type(msg) from None + if timeout < 0: + raise ValueError("Timeout must be a positive number or 0.") + ms = int(round(1000 * timeout)) + if ms == 0 and timeout > 0: + # Special case for 0 < timeout < 0.5 ms. + # This would be rounded to 0 ms, but the server interprets this as + # infinite timeout. So we round to the smallest possible timeout: 1 ms. + ms = 1 + return ms diff --git a/src/neo4j/_async/io/_bolt3.py b/src/neo4j/_async/io/_bolt3.py index a3629c5ff..f12a887f0 100644 --- a/src/neo4j/_async/io/_bolt3.py +++ b/src/neo4j/_async/io/_bolt3.py @@ -39,6 +39,7 @@ from ._bolt import ( AsyncBolt, ServerStateManagerBase, + tx_timeout_as_ms, ) from ._common import ( check_supported_server_product, @@ -262,12 +263,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) self._append(b"\x10", fields, @@ -327,12 +323,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), diff --git a/src/neo4j/_async/io/_bolt4.py b/src/neo4j/_async/io/_bolt4.py index 2c5dfb785..12f7e1ae0 100644 --- a/src/neo4j/_async/io/_bolt4.py +++ b/src/neo4j/_async/io/_bolt4.py @@ -36,6 +36,7 @@ from ._bolt import ( AsyncBolt, ServerStateManagerBase, + tx_timeout_as_ms, ) from ._bolt3 import ( ServerStateManager, @@ -212,12 +213,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) self._append(b"\x10", fields, @@ -276,12 +272,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), @@ -555,12 +546,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) @@ -596,12 +582,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), diff --git a/src/neo4j/_async/io/_bolt5.py b/src/neo4j/_async/io/_bolt5.py index 4502a14a2..5d80bc7d0 100644 --- a/src/neo4j/_async/io/_bolt5.py +++ b/src/neo4j/_async/io/_bolt5.py @@ -38,6 +38,7 @@ from ._bolt import ( AsyncBolt, ServerStateManagerBase, + tx_timeout_as_ms, ) from ._bolt3 import ( ServerStateManager, @@ -209,12 +210,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) @@ -270,12 +266,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), @@ -567,12 +558,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) @@ -603,12 +589,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) if notifications_min_severity is not None: extra["notifications_minimum_severity"] = \ notifications_min_severity diff --git a/src/neo4j/_sync/io/_bolt.py b/src/neo4j/_sync/io/_bolt.py index abba0dce6..1253e8205 100644 --- a/src/neo4j/_sync/io/_bolt.py +++ b/src/neo4j/_sync/io/_bolt.py @@ -947,3 +947,32 @@ def is_idle_for(self, timeout): BoltSocket.Bolt = Bolt # type: ignore + + +def tx_timeout_as_ms(timeout: float) -> int: + """Round transaction timeout to milliseconds. + + Values in (0, 1], else values are rounded using the built-in round() + function (round n.5 values to nearest even). + + :param timeout: timeout in seconds (must be >= 0) + + :returns: timeout in milliseconds (rounded) + + :raise ValueError: if timeout is negative + """ + try: + timeout = float(timeout) + except (TypeError, ValueError) as e: + err_type = type(e) + msg = "Timeout must be specified as a number of seconds" + raise err_type(msg) from None + if timeout < 0: + raise ValueError("Timeout must be a positive number or 0.") + ms = int(round(1000 * timeout)) + if ms == 0 and timeout > 0: + # Special case for 0 < timeout < 0.5 ms. + # This would be rounded to 0 ms, but the server interprets this as + # infinite timeout. So we round to the smallest possible timeout: 1 ms. + ms = 1 + return ms diff --git a/src/neo4j/_sync/io/_bolt3.py b/src/neo4j/_sync/io/_bolt3.py index 4a125797f..00d8dcb58 100644 --- a/src/neo4j/_sync/io/_bolt3.py +++ b/src/neo4j/_sync/io/_bolt3.py @@ -39,6 +39,7 @@ from ._bolt import ( Bolt, ServerStateManagerBase, + tx_timeout_as_ms, ) from ._common import ( check_supported_server_product, @@ -262,12 +263,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) self._append(b"\x10", fields, @@ -327,12 +323,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), diff --git a/src/neo4j/_sync/io/_bolt4.py b/src/neo4j/_sync/io/_bolt4.py index 96cc8167f..ce763b239 100644 --- a/src/neo4j/_sync/io/_bolt4.py +++ b/src/neo4j/_sync/io/_bolt4.py @@ -36,6 +36,7 @@ from ._bolt import ( Bolt, ServerStateManagerBase, + tx_timeout_as_ms, ) from ._bolt3 import ( ServerStateManager, @@ -212,12 +213,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) self._append(b"\x10", fields, @@ -276,12 +272,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), @@ -555,12 +546,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) @@ -596,12 +582,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be specified as a number of seconds") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a positive number or 0.") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), diff --git a/src/neo4j/_sync/io/_bolt5.py b/src/neo4j/_sync/io/_bolt5.py index 1740d22d9..b89da8ba1 100644 --- a/src/neo4j/_sync/io/_bolt5.py +++ b/src/neo4j/_sync/io/_bolt5.py @@ -38,6 +38,7 @@ from ._bolt import ( Bolt, ServerStateManagerBase, + tx_timeout_as_ms, ) from ._bolt3 import ( ServerStateManager, @@ -209,12 +210,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) @@ -270,12 +266,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) log.debug("[#%04X] C: BEGIN %r", self.local_port, extra) self._append(b"\x11", (extra,), Response(self, "begin", hydration_hooks, **handlers), @@ -567,12 +558,7 @@ def run(self, query, parameters=None, mode=None, bookmarks=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) fields = (query, parameters, extra) log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields))) @@ -603,12 +589,7 @@ def begin(self, mode=None, bookmarks=None, metadata=None, timeout=None, except TypeError: raise TypeError("Metadata must be coercible to a dict") if timeout is not None: - try: - extra["tx_timeout"] = int(1000 * float(timeout)) - except TypeError: - raise TypeError("Timeout must be a number (in seconds)") - if extra["tx_timeout"] < 0: - raise ValueError("Timeout must be a number >= 0") + extra["tx_timeout"] = tx_timeout_as_ms(timeout) if notifications_min_severity is not None: extra["notifications_minimum_severity"] = \ notifications_min_severity diff --git a/tests/unit/async_/io/test_class_bolt3.py b/tests/unit/async_/io/test_class_bolt3.py index 56b400c68..99c6adc45 100644 --- a/tests/unit/async_/io/test_class_bolt3.py +++ b/tests/unit/async_/io/test_class_bolt3.py @@ -297,3 +297,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt3.PACKER_CLS, + unpacker_cls=AsyncBolt3.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt3(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt4x0.py b/tests/unit/async_/io/test_class_bolt4x0.py index d194f12a0..864c4fe7c 100644 --- a/tests/unit/async_/io/test_class_bolt4x0.py +++ b/tests/unit/async_/io/test_class_bolt4x0.py @@ -393,3 +393,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt4x0.PACKER_CLS, + unpacker_cls=AsyncBolt4x0.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt4x0(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt4x1.py b/tests/unit/async_/io/test_class_bolt4x1.py index 7a1fa2d24..16fb78b43 100644 --- a/tests/unit/async_/io/test_class_bolt4x1.py +++ b/tests/unit/async_/io/test_class_bolt4x1.py @@ -410,3 +410,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt4x1.PACKER_CLS, + unpacker_cls=AsyncBolt4x1.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt4x1(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt4x2.py b/tests/unit/async_/io/test_class_bolt4x2.py index f9af5ea20..390cd00cf 100644 --- a/tests/unit/async_/io/test_class_bolt4x2.py +++ b/tests/unit/async_/io/test_class_bolt4x2.py @@ -411,3 +411,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt4x2.PACKER_CLS, + unpacker_cls=AsyncBolt4x2.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt4x2(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt4x3.py b/tests/unit/async_/io/test_class_bolt4x3.py index f09e1f724..a4cff5376 100644 --- a/tests/unit/async_/io/test_class_bolt4x3.py +++ b/tests/unit/async_/io/test_class_bolt4x3.py @@ -438,3 +438,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt4x3.PACKER_CLS, + unpacker_cls=AsyncBolt4x3.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt4x3(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt4x4.py b/tests/unit/async_/io/test_class_bolt4x4.py index 135790540..4c037816c 100644 --- a/tests/unit/async_/io/test_class_bolt4x4.py +++ b/tests/unit/async_/io/test_class_bolt4x4.py @@ -451,3 +451,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt4x4.PACKER_CLS, + unpacker_cls=AsyncBolt4x4.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt4x4(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt5x0.py b/tests/unit/async_/io/test_class_bolt5x0.py index 30b42963c..bbbe8d753 100644 --- a/tests/unit/async_/io/test_class_bolt5x0.py +++ b/tests/unit/async_/io/test_class_bolt5x0.py @@ -451,3 +451,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt5x0.PACKER_CLS, + unpacker_cls=AsyncBolt5x0.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt5x0(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt5x1.py b/tests/unit/async_/io/test_class_bolt5x1.py index 831a7d9dd..00fda13fd 100644 --- a/tests/unit/async_/io/test_class_bolt5x1.py +++ b/tests/unit/async_/io/test_class_bolt5x1.py @@ -505,3 +505,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt5x1.PACKER_CLS, + unpacker_cls=AsyncBolt5x1.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt5x1(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt5x2.py b/tests/unit/async_/io/test_class_bolt5x2.py index 770e3016b..e9e0cac15 100644 --- a/tests/unit/async_/io/test_class_bolt5x2.py +++ b/tests/unit/async_/io/test_class_bolt5x2.py @@ -523,3 +523,61 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt5x2.PACKER_CLS, + unpacker_cls=AsyncBolt5x2.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt5x2(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/async_/io/test_class_bolt5x3.py b/tests/unit/async_/io/test_class_bolt5x3.py index ad671583c..f9ad1a984 100644 --- a/tests/unit/async_/io/test_class_bolt5x3.py +++ b/tests/unit/async_/io/test_class_bolt5x3.py @@ -434,3 +434,61 @@ async def test_sends_bolt_agent(fake_socket_pair, user_agent): tag, fields = await sockets.server.pop_message() extra = fields[0] assert extra["bolt_agent"] == BOLT_AGENT_DICT + + +@mark_async_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +async def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=AsyncBolt5x3.PACKER_CLS, + unpacker_cls=AsyncBolt5x3.UNPACKER_CLS) + await sockets.server.send_message(b"\x70", {}) + connection = AsyncBolt5x3(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + await connection.send_all() + tag, fields = await sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt3.py b/tests/unit/sync/io/test_class_bolt3.py index 8c209434b..f4ead4995 100644 --- a/tests/unit/sync/io/test_class_bolt3.py +++ b/tests/unit/sync/io/test_class_bolt3.py @@ -297,3 +297,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt3.PACKER_CLS, + unpacker_cls=Bolt3.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt3(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt4x0.py b/tests/unit/sync/io/test_class_bolt4x0.py index e1831cb2e..efd0058a4 100644 --- a/tests/unit/sync/io/test_class_bolt4x0.py +++ b/tests/unit/sync/io/test_class_bolt4x0.py @@ -393,3 +393,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt4x0.PACKER_CLS, + unpacker_cls=Bolt4x0.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt4x0(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt4x1.py b/tests/unit/sync/io/test_class_bolt4x1.py index 132212915..8f51b8114 100644 --- a/tests/unit/sync/io/test_class_bolt4x1.py +++ b/tests/unit/sync/io/test_class_bolt4x1.py @@ -410,3 +410,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt4x1.PACKER_CLS, + unpacker_cls=Bolt4x1.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt4x1(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt4x2.py b/tests/unit/sync/io/test_class_bolt4x2.py index ed19ee522..94ee53019 100644 --- a/tests/unit/sync/io/test_class_bolt4x2.py +++ b/tests/unit/sync/io/test_class_bolt4x2.py @@ -411,3 +411,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt4x2.PACKER_CLS, + unpacker_cls=Bolt4x2.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt4x2(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt4x3.py b/tests/unit/sync/io/test_class_bolt4x3.py index 0721172a0..adb94afb2 100644 --- a/tests/unit/sync/io/test_class_bolt4x3.py +++ b/tests/unit/sync/io/test_class_bolt4x3.py @@ -438,3 +438,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt4x3.PACKER_CLS, + unpacker_cls=Bolt4x3.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt4x3(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt4x4.py b/tests/unit/sync/io/test_class_bolt4x4.py index b33eaaf54..0ae2a30e5 100644 --- a/tests/unit/sync/io/test_class_bolt4x4.py +++ b/tests/unit/sync/io/test_class_bolt4x4.py @@ -451,3 +451,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt4x4.PACKER_CLS, + unpacker_cls=Bolt4x4.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt4x4(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt5x0.py b/tests/unit/sync/io/test_class_bolt5x0.py index 9ae410f18..c220372ad 100644 --- a/tests/unit/sync/io/test_class_bolt5x0.py +++ b/tests/unit/sync/io/test_class_bolt5x0.py @@ -451,3 +451,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt5x0.PACKER_CLS, + unpacker_cls=Bolt5x0.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt5x0(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt5x1.py b/tests/unit/sync/io/test_class_bolt5x1.py index 68eaf7b33..d94931e03 100644 --- a/tests/unit/sync/io/test_class_bolt5x1.py +++ b/tests/unit/sync/io/test_class_bolt5x1.py @@ -505,3 +505,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt5x1.PACKER_CLS, + unpacker_cls=Bolt5x1.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt5x1(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt5x2.py b/tests/unit/sync/io/test_class_bolt5x2.py index 69384b9c4..1588ff186 100644 --- a/tests/unit/sync/io/test_class_bolt5x2.py +++ b/tests/unit/sync/io/test_class_bolt5x2.py @@ -523,3 +523,61 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert "bolt_agent" not in extra + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt5x2.PACKER_CLS, + unpacker_cls=Bolt5x2.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt5x2(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res diff --git a/tests/unit/sync/io/test_class_bolt5x3.py b/tests/unit/sync/io/test_class_bolt5x3.py index f2a5fae4d..0b339c3bc 100644 --- a/tests/unit/sync/io/test_class_bolt5x3.py +++ b/tests/unit/sync/io/test_class_bolt5x3.py @@ -434,3 +434,61 @@ def test_sends_bolt_agent(fake_socket_pair, user_agent): tag, fields = sockets.server.pop_message() extra = fields[0] assert extra["bolt_agent"] == BOLT_AGENT_DICT + + +@mark_sync_test +@pytest.mark.parametrize( + ("func", "args", "extra_idx"), + ( + ("run", ("RETURN 1",), 2), + ("begin", (), 0), + ) +) +@pytest.mark.parametrize( + ("timeout", "res"), + ( + (None, None), + (0, 0), + (0.1, 100), + (0.001, 1), + (1e-15, 1), + (0.0005, 1), + (0.0001, 1), + (1.0015, 1002), + (1.000499, 1000), + (1.0025, 1002), + (3.0005, 3000), + (3.456, 3456), + (1, 1000), + ( + "foo", + ValueError("Timeout must be specified as a number of seconds") + ), + ( + [1, 2], + TypeError("Timeout must be specified as a number of seconds") + ) + ) +) +def test_tx_timeout( + fake_socket_pair, func, args, extra_idx, timeout, res +): + address = neo4j.Address(("127.0.0.1", 7687)) + sockets = fake_socket_pair(address, + packer_cls=Bolt5x3.PACKER_CLS, + unpacker_cls=Bolt5x3.UNPACKER_CLS) + sockets.server.send_message(b"\x70", {}) + connection = Bolt5x3(address, sockets.client, 0) + func = getattr(connection, func) + if isinstance(res, Exception): + with pytest.raises(type(res), match=str(res)): + func(*args, timeout=timeout) + else: + func(*args, timeout=timeout) + connection.send_all() + tag, fields = sockets.server.pop_message() + extra = fields[extra_idx] + if timeout is None: + assert "tx_timeout" not in extra + else: + assert extra["tx_timeout"] == res From f8ff735c931976891725569511dfb7081b3d7a25 Mon Sep 17 00:00:00 2001 From: Robsdedude Date: Thu, 29 Jun 2023 09:34:02 +0200 Subject: [PATCH 2/2] Add unit tests for negative timeout --- tests/unit/async_/io/test_class_bolt3.py | 4 ++++ tests/unit/async_/io/test_class_bolt4x0.py | 4 ++++ tests/unit/async_/io/test_class_bolt4x1.py | 4 ++++ tests/unit/async_/io/test_class_bolt4x2.py | 4 ++++ tests/unit/async_/io/test_class_bolt4x3.py | 4 ++++ tests/unit/async_/io/test_class_bolt4x4.py | 4 ++++ tests/unit/async_/io/test_class_bolt5x0.py | 4 ++++ tests/unit/async_/io/test_class_bolt5x1.py | 4 ++++ tests/unit/async_/io/test_class_bolt5x2.py | 4 ++++ tests/unit/async_/io/test_class_bolt5x3.py | 4 ++++ tests/unit/sync/io/test_class_bolt3.py | 4 ++++ tests/unit/sync/io/test_class_bolt4x0.py | 4 ++++ tests/unit/sync/io/test_class_bolt4x1.py | 4 ++++ tests/unit/sync/io/test_class_bolt4x2.py | 4 ++++ tests/unit/sync/io/test_class_bolt4x3.py | 4 ++++ tests/unit/sync/io/test_class_bolt4x4.py | 4 ++++ tests/unit/sync/io/test_class_bolt5x0.py | 4 ++++ tests/unit/sync/io/test_class_bolt5x1.py | 4 ++++ tests/unit/sync/io/test_class_bolt5x2.py | 4 ++++ tests/unit/sync/io/test_class_bolt5x3.py | 4 ++++ 20 files changed, 80 insertions(+) diff --git a/tests/unit/async_/io/test_class_bolt3.py b/tests/unit/async_/io/test_class_bolt3.py index 99c6adc45..2ae6e8402 100644 --- a/tests/unit/async_/io/test_class_bolt3.py +++ b/tests/unit/async_/io/test_class_bolt3.py @@ -323,6 +323,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt4x0.py b/tests/unit/async_/io/test_class_bolt4x0.py index 864c4fe7c..979f4fb24 100644 --- a/tests/unit/async_/io/test_class_bolt4x0.py +++ b/tests/unit/async_/io/test_class_bolt4x0.py @@ -419,6 +419,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt4x1.py b/tests/unit/async_/io/test_class_bolt4x1.py index 16fb78b43..4af0bddb9 100644 --- a/tests/unit/async_/io/test_class_bolt4x1.py +++ b/tests/unit/async_/io/test_class_bolt4x1.py @@ -436,6 +436,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt4x2.py b/tests/unit/async_/io/test_class_bolt4x2.py index 390cd00cf..6256edd52 100644 --- a/tests/unit/async_/io/test_class_bolt4x2.py +++ b/tests/unit/async_/io/test_class_bolt4x2.py @@ -437,6 +437,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt4x3.py b/tests/unit/async_/io/test_class_bolt4x3.py index a4cff5376..70a2e0d5d 100644 --- a/tests/unit/async_/io/test_class_bolt4x3.py +++ b/tests/unit/async_/io/test_class_bolt4x3.py @@ -464,6 +464,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt4x4.py b/tests/unit/async_/io/test_class_bolt4x4.py index 4c037816c..baa852603 100644 --- a/tests/unit/async_/io/test_class_bolt4x4.py +++ b/tests/unit/async_/io/test_class_bolt4x4.py @@ -477,6 +477,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt5x0.py b/tests/unit/async_/io/test_class_bolt5x0.py index bbbe8d753..8b2b9f0a8 100644 --- a/tests/unit/async_/io/test_class_bolt5x0.py +++ b/tests/unit/async_/io/test_class_bolt5x0.py @@ -477,6 +477,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt5x1.py b/tests/unit/async_/io/test_class_bolt5x1.py index 00fda13fd..8897ce708 100644 --- a/tests/unit/async_/io/test_class_bolt5x1.py +++ b/tests/unit/async_/io/test_class_bolt5x1.py @@ -531,6 +531,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt5x2.py b/tests/unit/async_/io/test_class_bolt5x2.py index e9e0cac15..0de7e3872 100644 --- a/tests/unit/async_/io/test_class_bolt5x2.py +++ b/tests/unit/async_/io/test_class_bolt5x2.py @@ -549,6 +549,10 @@ async def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/async_/io/test_class_bolt5x3.py b/tests/unit/async_/io/test_class_bolt5x3.py index f9ad1a984..0247bad16 100644 --- a/tests/unit/async_/io/test_class_bolt5x3.py +++ b/tests/unit/async_/io/test_class_bolt5x3.py @@ -460,6 +460,10 @@ async def test_sends_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt3.py b/tests/unit/sync/io/test_class_bolt3.py index f4ead4995..1527bd86b 100644 --- a/tests/unit/sync/io/test_class_bolt3.py +++ b/tests/unit/sync/io/test_class_bolt3.py @@ -323,6 +323,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt4x0.py b/tests/unit/sync/io/test_class_bolt4x0.py index efd0058a4..90af5f079 100644 --- a/tests/unit/sync/io/test_class_bolt4x0.py +++ b/tests/unit/sync/io/test_class_bolt4x0.py @@ -419,6 +419,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt4x1.py b/tests/unit/sync/io/test_class_bolt4x1.py index 8f51b8114..8df441f9e 100644 --- a/tests/unit/sync/io/test_class_bolt4x1.py +++ b/tests/unit/sync/io/test_class_bolt4x1.py @@ -436,6 +436,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt4x2.py b/tests/unit/sync/io/test_class_bolt4x2.py index 94ee53019..2a6ceee92 100644 --- a/tests/unit/sync/io/test_class_bolt4x2.py +++ b/tests/unit/sync/io/test_class_bolt4x2.py @@ -437,6 +437,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt4x3.py b/tests/unit/sync/io/test_class_bolt4x3.py index adb94afb2..58d9b01a2 100644 --- a/tests/unit/sync/io/test_class_bolt4x3.py +++ b/tests/unit/sync/io/test_class_bolt4x3.py @@ -464,6 +464,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt4x4.py b/tests/unit/sync/io/test_class_bolt4x4.py index 0ae2a30e5..6ac7d7923 100644 --- a/tests/unit/sync/io/test_class_bolt4x4.py +++ b/tests/unit/sync/io/test_class_bolt4x4.py @@ -477,6 +477,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt5x0.py b/tests/unit/sync/io/test_class_bolt5x0.py index c220372ad..a4416a97a 100644 --- a/tests/unit/sync/io/test_class_bolt5x0.py +++ b/tests/unit/sync/io/test_class_bolt5x0.py @@ -477,6 +477,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt5x1.py b/tests/unit/sync/io/test_class_bolt5x1.py index d94931e03..e6315df64 100644 --- a/tests/unit/sync/io/test_class_bolt5x1.py +++ b/tests/unit/sync/io/test_class_bolt5x1.py @@ -531,6 +531,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt5x2.py b/tests/unit/sync/io/test_class_bolt5x2.py index 1588ff186..9dec5bacb 100644 --- a/tests/unit/sync/io/test_class_bolt5x2.py +++ b/tests/unit/sync/io/test_class_bolt5x2.py @@ -549,6 +549,10 @@ def test_does_not_send_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds") diff --git a/tests/unit/sync/io/test_class_bolt5x3.py b/tests/unit/sync/io/test_class_bolt5x3.py index 0b339c3bc..9437a3487 100644 --- a/tests/unit/sync/io/test_class_bolt5x3.py +++ b/tests/unit/sync/io/test_class_bolt5x3.py @@ -460,6 +460,10 @@ def test_sends_bolt_agent(fake_socket_pair, user_agent): (3.0005, 3000), (3.456, 3456), (1, 1000), + ( + -1e-15, + ValueError("Timeout must be a positive number or 0") + ), ( "foo", ValueError("Timeout must be specified as a number of seconds")