From 81e78cf20c3f1f693243964f44d63d2997d3e3e0 Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Wed, 19 Feb 2020 11:07:55 +0100 Subject: [PATCH 1/7] Added unit test for exceptions --- tests/unit/test_exceptions.py | 91 +++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 tests/unit/test_exceptions.py diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py new file mode 100644 index 000000000..fabede2e8 --- /dev/null +++ b/tests/unit/test_exceptions.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2020 "Neo4j," +# Neo4j Sweden AB [http://neo4j.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import pytest + +from neo4j.exceptions import ( + Neo4jError, + ClientError, + CypherSyntaxError, + CypherTypeError, + ConstraintError, + AuthError, + Forbidden, + ForbiddenOnReadOnlyDatabase, + NotALeader, + DatabaseError, + TransientError, + DatabaseUnavailable, + DriverError, + TransactionError, + SessionExpired, + ServiceUnavailable, + RoutingServiceUnavailable, + WriteServiceUnavailable, + ReadServiceUnavailable, + # ConfigurationError, + # AuthConfigurationError, + # CertificateConfigurationError, +) + +from neo4j._exceptions import ( + BoltError, + BoltHandshakeError, + BoltRoutingError, + BoltConnectionError, + BoltSecurityError, + BoltConnectionBroken, + BoltConnectionClosed, + BoltFailure, + BoltIncompleteCommitError, + BoltProtocolError, +) + + +# python -m pytest tests/unit/test_exceptions.py -s -v + +def test_bolt_error(): + with pytest.raises(BoltError) as e: + error = BoltError("Error Message", address="localhost") + assert repr(error) == "BoltError('Error Message')" + assert str(error) == "Error Message" + assert error.args == ("Error Message",) + assert error.address == "localhost" + raise error + + # The regexp parameter of the match method is matched with the re.search function. + with pytest.raises(AssertionError): + e.match("FAIL!") + + assert e.match("Error Message") + + +def test_bolt_protocol_error(): + with pytest.raises(BoltProtocolError) as e: + error = BoltProtocolError("Driver does not support Bolt protocol version: 0x%06X%02X" % (2, 5), address="localhost") + assert error.address == "localhost" + raise error + + # The regexp parameter of the match method is matched with the re.search function. + with pytest.raises(AssertionError): + e.match("FAIL!") + + e.match("Driver does not support Bolt protocol version: 0x00000205") From 2cb65998a2080c7f7214a6a3cd181bd856bd618c Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Wed, 19 Feb 2020 14:43:22 +0100 Subject: [PATCH 2/7] Fixed Bolt.open error message --- neo4j/io/__init__.py | 9 ++++++--- tests/unit/test_exceptions.py | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/neo4j/io/__init__.py b/neo4j/io/__init__.py index 26a5010fa..d04e9d846 100644 --- a/neo4j/io/__init__.py +++ b/neo4j/io/__init__.py @@ -70,6 +70,7 @@ BoltRoutingError, BoltSecurityError, BoltProtocolError, + BoltHandshakeError, ) from neo4j.exceptions import ( ServiceUnavailable, @@ -168,7 +169,7 @@ def open(cls, address, *, auth=None, timeout=None, **config): :return: """ config = PoolConfig.consume(config) - s, config.protocol_version = connect(address, timeout=timeout, config=config) + s, config.protocol_version, handshake, data = connect(address, timeout=timeout, config=config) if config.protocol_version == (3, 0): from neo4j.io._bolt3 import Bolt3 @@ -180,7 +181,9 @@ def open(cls, address, *, auth=None, timeout=None, **config): log.debug("[#%04X] S: ", s.getpeername()[1]) s.shutdown(SHUT_RDWR) s.close() - raise BoltProtocolError("Driver does not support Bolt protocol version: 0x%06X%02X", config.protocol_version[0], config.protocol_version[1]) + + supported_versions = Bolt.protocol_handlers().keys() + raise BoltHandshakeError("The Neo4J server does not support communication with this driver. This driver have support for Bolt Protocols {}".format(supported_versions), address=address, request_data=handshake, response_data=data) connection.hello() return connection @@ -849,7 +852,7 @@ def _handshake(s, resolved_address): "(looks like HTTP)".format(resolved_address)) agreed_version = data[-1], data[-2] log.debug("[#%04X] S: 0x%06X%02X", local_port, agreed_version[1], agreed_version[0]) - return s, agreed_version + return s, agreed_version, handshake, data def connect(address, *, timeout=None, config): diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py index fabede2e8..617e5e8cd 100644 --- a/tests/unit/test_exceptions.py +++ b/tests/unit/test_exceptions.py @@ -59,6 +59,8 @@ BoltProtocolError, ) +from neo4j.io import Bolt + # python -m pytest tests/unit/test_exceptions.py -s -v @@ -89,3 +91,18 @@ def test_bolt_protocol_error(): e.match("FAIL!") e.match("Driver does not support Bolt protocol version: 0x00000205") + + +def test_bolt_handshake_error(): + handshake = b"\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00" + response = b"\x00\x00\x00\x00" + supported_versions = Bolt.protocol_handlers().keys() + + with pytest.raises(BoltHandshakeError) as e: + error = BoltHandshakeError("The Neo4J server does not support communication with this driver. Supported Bolt Protocols {}".format(supported_versions), address="localhost", request_data=handshake, response_data=response) + assert error.address == "localhost" + assert error.request_data == handshake + assert error.response_data == response + raise error + + e.match("The Neo4J server does not support communication with this driver. Supported Bolt Protocols ") From 7bff9cf6bc2cc23fa36957685bdd661722be2571 Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Wed, 19 Feb 2020 14:58:10 +0100 Subject: [PATCH 3/7] added stubtests for handshake negotiation of different bolt protocol versions --- .../v1/empty_explicit_hello_goodbye.script | 6 +++++ .../v2/empty_explicit_hello_goodbye.script | 6 +++++ .../v3/empty_explicit_hello_goodbye.script | 6 +++++ .../v4x0/empty_explicit_hello_goodbye.script | 6 +++++ tests/stub/test_directdriver.py | 22 +++++++++++++++++++ 5 files changed, 46 insertions(+) create mode 100644 tests/stub/scripts/v1/empty_explicit_hello_goodbye.script create mode 100644 tests/stub/scripts/v2/empty_explicit_hello_goodbye.script create mode 100644 tests/stub/scripts/v3/empty_explicit_hello_goodbye.script create mode 100644 tests/stub/scripts/v4x0/empty_explicit_hello_goodbye.script diff --git a/tests/stub/scripts/v1/empty_explicit_hello_goodbye.script b/tests/stub/scripts/v1/empty_explicit_hello_goodbye.script new file mode 100644 index 000000000..a3e3038c2 --- /dev/null +++ b/tests/stub/scripts/v1/empty_explicit_hello_goodbye.script @@ -0,0 +1,6 @@ +!: BOLT 1 + +C: INIT {"user_agent": "test", "scheme": "basic", "principal": "test", "credentials": "test"} +S: SUCCESS {server”: "Neo4j/3.3.0", "connection_id": "123e4567-e89b-12d3-a456-426655440000"} +C: RESET +S: \ No newline at end of file diff --git a/tests/stub/scripts/v2/empty_explicit_hello_goodbye.script b/tests/stub/scripts/v2/empty_explicit_hello_goodbye.script new file mode 100644 index 000000000..4b6913fe2 --- /dev/null +++ b/tests/stub/scripts/v2/empty_explicit_hello_goodbye.script @@ -0,0 +1,6 @@ +!: BOLT 2 + +C: INIT {"user_agent": "test", "scheme": "basic", "principal": "test", "credentials": "test"} +S: SUCCESS {server”: "Neo4j/3.4.0", "connection_id": "123e4567-e89b-12d3-a456-426655440000"} +C: RESET +S: \ No newline at end of file diff --git a/tests/stub/scripts/v3/empty_explicit_hello_goodbye.script b/tests/stub/scripts/v3/empty_explicit_hello_goodbye.script new file mode 100644 index 000000000..ed8dc2a93 --- /dev/null +++ b/tests/stub/scripts/v3/empty_explicit_hello_goodbye.script @@ -0,0 +1,6 @@ +!: BOLT 3 + +C: HELLO {"user_agent": "test", "scheme": "basic", "principal": "test", "credentials": "test"} +S: SUCCESS {server”: "Neo4j/3.5.0", "connection_id": "123e4567-e89b-12d3-a456-426655440000"} +C: GOODBYE +S: \ No newline at end of file diff --git a/tests/stub/scripts/v4x0/empty_explicit_hello_goodbye.script b/tests/stub/scripts/v4x0/empty_explicit_hello_goodbye.script new file mode 100644 index 000000000..ad14a3b51 --- /dev/null +++ b/tests/stub/scripts/v4x0/empty_explicit_hello_goodbye.script @@ -0,0 +1,6 @@ +!: BOLT 4 + +C: HELLO {"user_agent": "test", "scheme": "basic", "principal": "test", "credentials": "test"} +S: SUCCESS {server”: "Neo4j/4.0.0", "connection_id": "123e4567-e89b-12d3-a456-426655440000"} +C: GOODBYE +S: \ No newline at end of file diff --git a/tests/stub/test_directdriver.py b/tests/stub/test_directdriver.py index c0565cd85..f548437fc 100644 --- a/tests/stub/test_directdriver.py +++ b/tests/stub/test_directdriver.py @@ -50,6 +50,28 @@ def test_bolt_uri_constructs_bolt_driver(driver_info, test_script): assert isinstance(driver, BoltDriver) +@pytest.mark.parametrize( + "test_script, test_expected", + [ + ("v1/empty_explicit_hello_goodbye.script", ServiceUnavailable), + ("v2/empty_explicit_hello_goodbye.script", ServiceUnavailable), + ("v3/empty_explicit_hello_goodbye.script", None), + ("v4x0/empty_explicit_hello_goodbye.script", None), + ] +) +def test_direct_driver_handshake_negotiation(driver_info, test_script, test_expected): + # python -m pytest tests/stub/test_directdriver.py -s -v -k test_direct_driver_handshake_negotiation + with StubCluster(test_script): + uri = "bolt://127.0.0.1:9001" + if test_expected: + with pytest.raises(test_expected): + driver = GraphDatabase.driver(uri, auth=driver_info["auth_token"], user_agent="test") + else: + driver = GraphDatabase.driver(uri, auth=driver_info["auth_token"], user_agent="test") + assert isinstance(driver, BoltDriver) + driver.close() + + def test_direct_driver_with_wrong_port(driver_info): # python -m pytest tests/stub/test_directdriver.py -s -v -k test_direct_driver_with_wrong_port uri = "bolt://127.0.0.1:9002" From f47e39c7c8a8751e740010f6c0e8dca332fcbb1b Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Thu, 20 Feb 2020 12:38:59 +0100 Subject: [PATCH 4/7] integration tests are skipped if the bolt protocol version is not supported by the driver. --- tests/integration/aio/conftest.py | 26 +- tests/integration/aio/test_bolt.py | 474 ++++++++++-------- tests/integration/conftest.py | 14 +- .../integration/examples/test_auth_example.py | 12 +- .../test_autocommit_transaction_example.py | 4 +- .../test_config_connection_pool_example.py | 11 +- .../test_config_max_retry_time_example.py | 10 +- .../examples/test_config_secure_example.py | 12 +- .../examples/test_config_trust_example.py | 6 +- .../examples/test_custom_auth_example.py | 12 +- .../examples/test_custom_resolver_example.py | 13 +- .../examples/test_cypher_error_example.py | 4 +- .../examples/test_driver_lifecycle_example.py | 15 +- .../examples/test_hello_world_example.py | 22 +- .../examples/test_kerberos_auth_example.py | 8 +- .../examples/test_pass_bookmarks_example.py | 18 +- .../test_read_write_transaction_example.py | 2 +- .../examples/test_result_consume_example.py | 2 +- .../examples/test_result_retain_example.py | 2 +- .../test_service_unavailable_example.py | 7 +- .../examples/test_session_example.py | 2 +- .../examples/transaction_function_example.py | 2 +- tests/integration/test_bolt_driver.py | 60 ++- tests/integration/test_readme.py | 11 +- 24 files changed, 478 insertions(+), 271 deletions(-) diff --git a/tests/integration/aio/conftest.py b/tests/integration/aio/conftest.py index 09043b753..30d7099d5 100644 --- a/tests/integration/aio/conftest.py +++ b/tests/integration/aio/conftest.py @@ -18,21 +18,27 @@ # See the License for the specific language governing permissions and # limitations under the License. - -from pytest import fixture +import pytest from neo4j.aio import Bolt, BoltPool +from neo4j._exceptions import BoltHandshakeError -@fixture +@pytest.fixture async def bolt(address, auth): - bolt = await Bolt.open(address, auth=auth) - yield bolt - await bolt.close() + try: + bolt = await Bolt.open(address, auth=auth) + yield bolt + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) -@fixture +@pytest.fixture async def bolt_pool(address, auth): - pool = await BoltPool.open(address, auth=auth) - yield pool - await pool.close() + try: + pool = await BoltPool.open(address, auth=auth) + yield pool + await pool.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/aio/test_bolt.py b/tests/integration/aio/test_bolt.py index 6c2e12c63..594f3a05b 100644 --- a/tests/integration/aio/test_bolt.py +++ b/tests/integration/aio/test_bolt.py @@ -21,27 +21,40 @@ from asyncio import sleep, wait, wait_for, TimeoutError +import pytest from pytest import mark, raises + from neo4j import PoolConfig from neo4j.aio import Bolt, BoltPool -from neo4j._exceptions import BoltConnectionError, BoltTransactionError +from neo4j._exceptions import ( + BoltConnectionError, + BoltTransactionError, + BoltHandshakeError, +) from neo4j.exceptions import ClientError +# python -m pytest tests/integration/aio/test_bolt.py -s -v @mark.asyncio async def test_good_connectivity(address, auth): - bolt = await Bolt.open(address, auth=auth) - assert bolt.protocol_version - await bolt.close() + try: + bolt = await Bolt.open(address, auth=auth) + assert bolt.protocol_version + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) + @mark.asyncio async def test_connectivity_over_ipv4(address, auth): - bolt = await Bolt.open(("127.0.0.1", address[1]), auth=auth) - assert bolt.protocol_version - await bolt.close() - + try: + bolt = await Bolt.open(("127.0.0.1", address[1]), auth=auth) + assert bolt.protocol_version + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) # @mark.asyncio # async def test_connectivity_over_ipv6(address, auth): @@ -59,16 +72,21 @@ async def test_bad_connectivity(address, auth): @mark.asyncio async def test_security_none(address, auth): - bolt = await Bolt.open(address, auth=auth, secure=None) - assert not bolt.secure - await bolt.close() - + try: + bolt = await Bolt.open(address, auth=auth, secure=None) + assert not bolt.secure + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_security_false(address, auth): - bolt = await Bolt.open(address, auth=auth, secure=False) - assert not bolt.secure - await bolt.close() + try: + bolt = await Bolt.open(address, auth=auth, secure=False) + assert not bolt.secure + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) # TODO: re-enable when we have a way of testing against full certs @@ -103,142 +121,178 @@ async def test_bad_protocol_version_format(address, auth): @mark.asyncio async def test_bad_auth(address, auth): - with raises(ClientError) as e: - _ = await Bolt.open(address, auth=("sneaky", "hacker")) - error = e.value - assert error.category == "Security" - assert error.title == "Unauthorized" + try: + with raises(ClientError) as e: + _ = await Bolt.open(address, auth=("sneaky", "hacker")) + error = e.value + assert error.category == "Security" + assert error.title == "Unauthorized" + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_autocommit_transaction(address, auth): - bolt = await Bolt.open(address, auth=auth) - values = [] - async for record in await bolt.run("UNWIND [2, 3, 5] AS n RETURN n"): - values.append(record[0]) - await bolt.close() - assert values == [2, 3, 5] + try: + bolt = await Bolt.open(address, auth=auth) + values = [] + async for record in await bolt.run("UNWIND [2, 3, 5] AS n RETURN n"): + values.append(record[0]) + await bolt.close() + assert values == [2, 3, 5] + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_discarded_autocommit_transaction(address, auth): - bolt = await Bolt.open(address, auth=auth) - values = [] - async for record in await bolt.run("UNWIND [2, 3, 5] AS n RETURN n", discard=True): - values.append(record[0]) - await bolt.close() - assert values == [] + try: + bolt = await Bolt.open(address, auth=auth) + values = [] + async for record in await bolt.run("UNWIND [2, 3, 5] AS n RETURN n", discard=True): + values.append(record[0]) + await bolt.close() + assert values == [] + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_explicit_transaction_with_commit(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - assert not tx.closed - values = [] - async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): - values.append(record[0]) - bookmark = await tx.commit() - assert bookmark # We can't assert anything about the content - assert tx.closed - await bolt.close() - assert values == [2, 3, 5] + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + assert not tx.closed + values = [] + async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): + values.append(record[0]) + bookmark = await tx.commit() + assert bookmark # We can't assert anything about the content + assert tx.closed + await bolt.close() + assert values == [2, 3, 5] + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_explicit_transaction_with_rollback(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - assert not tx.closed - values = [] - async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): - values.append(record[0]) - await tx.rollback() - assert tx.closed - await bolt.close() - assert values == [2, 3, 5] + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + assert not tx.closed + values = [] + async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): + values.append(record[0]) + await tx.rollback() + assert tx.closed + await bolt.close() + assert values == [2, 3, 5] + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_autocommit_in_autocommit(address, auth): - bolt = await Bolt.open(address, auth=auth) - values = [] - async for r1 in await bolt.run("UNWIND [2, 3, 5] AS n RETURN n"): - async for r2 in await bolt.run("UNWIND [7, 11, 13] AS n RETURN n"): - values.append(r1[0] * r2[0]) - await bolt.close() - assert values == [14, 22, 26, 21, 33, 39, 35, 55, 65] + try: + bolt = await Bolt.open(address, auth=auth) + values = [] + async for r1 in await bolt.run("UNWIND [2, 3, 5] AS n RETURN n"): + async for r2 in await bolt.run("UNWIND [7, 11, 13] AS n RETURN n"): + values.append(r1[0] * r2[0]) + await bolt.close() + assert values == [14, 22, 26, 21, 33, 39, 35, 55, 65] + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_explicit_in_autocommit(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - with raises(BoltTransactionError): - _ = await bolt.run("UNWIND [2, 3, 5] AS n RETURN n") - await tx.rollback() - await bolt.close() + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + with raises(BoltTransactionError): + _ = await bolt.run("UNWIND [2, 3, 5] AS n RETURN n") + await tx.rollback() + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_autocommit_in_explicit(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - async for _ in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): - with raises(BoltTransactionError): - _ = await bolt.run("UNWIND [7, 11, 13] AS n RETURN n") - await tx.commit() - await bolt.close() + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + async for _ in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): + with raises(BoltTransactionError): + _ = await bolt.run("UNWIND [7, 11, 13] AS n RETURN n") + await tx.commit() + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_explicit_in_explicit(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - with raises(BoltTransactionError): - _ = await bolt.begin() - await tx.rollback() - await bolt.close() + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + with raises(BoltTransactionError): + _ = await bolt.begin() + await tx.rollback() + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_commit_is_non_idempotent(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - values = [] - async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): - values.append(record[0]) - await tx.commit() - with raises(BoltTransactionError): + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + values = [] + async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): + values.append(record[0]) await tx.commit() - await bolt.close() - assert values == [2, 3, 5] + with raises(BoltTransactionError): + await tx.commit() + await bolt.close() + assert values == [2, 3, 5] + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_rollback_is_non_idempotent(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - values = [] - async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): - values.append(record[0]) - await tx.rollback() - with raises(BoltTransactionError): + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + values = [] + async for record in await tx.run("UNWIND [2, 3, 5] AS n RETURN n"): + values.append(record[0]) await tx.rollback() - await bolt.close() - assert values == [2, 3, 5] + with raises(BoltTransactionError): + await tx.rollback() + await bolt.close() + assert values == [2, 3, 5] + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_cypher_error_in_autocommit_transaction(address, auth): - bolt = await Bolt.open(address, auth=auth) - with raises(ClientError) as e: - async for _ in await bolt.run("X"): - pass - error = e.value - assert isinstance(error, ClientError) - assert error.category == "Statement" - assert error.title == "SyntaxError" + try: + bolt = await Bolt.open(address, auth=auth) + with raises(ClientError) as e: + async for _ in await bolt.run("X"): + pass + error = e.value + assert isinstance(error, ClientError) + assert error.category == "Statement" + assert error.title == "SyntaxError" + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.skip(reason="TODO: fix correct error logic after error and exception refactoring") @@ -257,21 +311,24 @@ async def test_can_resume_after_error_in_autocommit_transaction(address, auth): @mark.asyncio async def test_cypher_error_in_explicit_transaction(address, auth): - bolt = await Bolt.open(address, auth=auth) - tx = await bolt.begin() - result1 = await tx.run("X") - result2 = await tx.run("RETURN 1") - with raises(ClientError) as e: - await tx.commit() - error = e.value - assert isinstance(error, ClientError) - assert error.category == "Statement" - assert error.title == "SyntaxError" - ok = await result1.consume() - assert not ok - ok = await result2.consume() - assert not ok - await bolt.close() + try: + bolt = await Bolt.open(address, auth=auth) + tx = await bolt.begin() + result1 = await tx.run("X") + result2 = await tx.run("RETURN 1") + with raises(ClientError) as e: + await tx.commit() + error = e.value + assert isinstance(error, ClientError) + assert error.category == "Statement" + assert error.title == "SyntaxError" + ok = await result1.consume() + assert not ok + ok = await result2.consume() + assert not ok + await bolt.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio @@ -312,48 +369,56 @@ async def count_nodes(tx): @mark.asyncio async def test_pool_exhaustion(address, auth): - pool = await BoltPool.open(address, auth=auth, max_size=3) - first = await pool.acquire() - second = await pool.acquire() - third = await pool.acquire() - assert isinstance(first, Bolt) - assert isinstance(second, Bolt) - assert isinstance(third, Bolt) - with raises(TimeoutError): - _ = await wait_for(pool.acquire(), timeout=1) + try: + pool = await BoltPool.open(address, auth=auth, max_size=3) + first = await pool.acquire() + second = await pool.acquire() + third = await pool.acquire() + assert isinstance(first, Bolt) + assert isinstance(second, Bolt) + assert isinstance(third, Bolt) + with raises(TimeoutError): + _ = await wait_for(pool.acquire(), timeout=1) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_pool_reuse(address, auth): - pool = await BoltPool.open(address, auth=auth, max_size=3) - first = await pool.acquire() - second = await pool.acquire() - third = await pool.acquire() - assert first is not second and second is not third and first is not third - await pool.release(second) - fourth = await pool.acquire() - assert fourth is second - + try: + pool = await BoltPool.open(address, auth=auth, max_size=3) + first = await pool.acquire() + second = await pool.acquire() + third = await pool.acquire() + assert first is not second and second is not third and first is not third + await pool.release(second) + fourth = await pool.acquire() + assert fourth is second + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_pool_release_notifies_acquire(address, auth): - pool = await BoltPool.open(address, auth=auth, max_size=1) - first = await pool.acquire() + try: + pool = await BoltPool.open(address, auth=auth, max_size=1) + first = await pool.acquire() - async def delayed_release(): - await sleep(1) - await pool.release(first) + async def delayed_release(): + await sleep(1) + await pool.release(first) - done, pending = await wait([ - delayed_release(), - pool.acquire(), - ]) - assert len(done) == 2 - assert len(pending) == 0 - assert pool.size == 1 - for future in done: - result = future.result() - assert result is None or result is first + done, pending = await wait([ + delayed_release(), + pool.acquire(), + ]) + assert len(done) == 2 + assert len(pending) == 0 + assert pool.size == 1 + for future in done: + result = future.result() + assert result is None or result is first + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio @@ -363,58 +428,68 @@ async def test_default_pool_open_and_close(bolt_pool, address): @mark.asyncio async def test_closing_pool_with_free_connections(address, auth): - pool = await BoltPool.open(address, auth=auth, max_size=3) - first = await pool.acquire() - second = await pool.acquire() - third = await pool.acquire() - await pool.release(first) - await pool.release(second) - await pool.release(third) - await pool.close() - assert first.closed - assert second.closed - assert third.closed - + try: + pool = await BoltPool.open(address, auth=auth, max_size=3) + first = await pool.acquire() + second = await pool.acquire() + third = await pool.acquire() + await pool.release(first) + await pool.release(second) + await pool.release(third) + await pool.close() + assert first.closed + assert second.closed + assert third.closed + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_closing_pool_with_in_use_connections(address, auth): - pool = await BoltPool.open(address, auth=auth, max_size=3) - first = await pool.acquire() - second = await pool.acquire() - third = await pool.acquire() - await pool.close() - assert first.closed - assert second.closed - assert third.closed - + try: + pool = await BoltPool.open(address, auth=auth, max_size=3) + first = await pool.acquire() + second = await pool.acquire() + third = await pool.acquire() + await pool.close() + assert first.closed + assert second.closed + assert third.closed + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_expired_connections_are_not_returned_to_pool(address, auth): - pool = await BoltPool.open(address, auth=auth, max_size=1, max_age=0.25) - assert pool.size == PoolConfig.init_size - assert pool.in_use == 0 - cx = await pool.acquire() - assert pool.size == 1 - assert pool.in_use == 1 - await sleep(0.5) - await pool.release(cx) - assert pool.size == 0 - assert pool.in_use == 0 - assert cx.closed + try: + pool = await BoltPool.open(address, auth=auth, max_size=1, max_age=0.25) + assert pool.size == PoolConfig.init_size + assert pool.in_use == 0 + cx = await pool.acquire() + assert pool.size == 1 + assert pool.in_use == 1 + await sleep(0.5) + await pool.release(cx) + assert pool.size == 0 + assert pool.in_use == 0 + assert cx.closed + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio async def test_closed_connections_are_not_returned_to_pool(address, auth): - pool = await BoltPool.open(address, auth=auth, max_size=1) - assert pool.size == PoolConfig.init_size - assert pool.in_use == 0 - cx = await pool.acquire() - assert pool.size == 1 - assert pool.in_use == 1 - await cx.close() - await pool.release(cx) - assert pool.size == 0 - assert pool.in_use == 0 + try: + pool = await BoltPool.open(address, auth=auth, max_size=1) + assert pool.size == PoolConfig.init_size + assert pool.in_use == 0 + cx = await pool.acquire() + assert pool.size == 1 + assert pool.in_use == 1 + await cx.close() + await pool.release(cx) + assert pool.size == 0 + assert pool.in_use == 0 + except BoltHandshakeError as error: + pytest.skip(error.args[0]) @mark.asyncio @@ -427,6 +502,9 @@ async def test_cannot_release_already_released_connection(bolt_pool): @mark.asyncio async def test_cannot_release_unowned_connection(bolt_pool, address, auth): - cx = await Bolt.open(address, auth=auth) - with raises(ValueError): - await bolt_pool.release(cx) + try: + cx = await Bolt.open(address, auth=auth) + with raises(ValueError): + await bolt_pool.release(cx) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) \ No newline at end of file diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 5ba095a44..4e3dd3e35 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -28,6 +28,7 @@ from neo4j import GraphDatabase from neo4j.exceptions import ServiceUnavailable +from neo4j._exceptions import BoltHandshakeError from neo4j.io import Bolt @@ -277,11 +278,14 @@ def auth(): @fixture(scope="session") def bolt_driver(target, auth): - driver = GraphDatabase.bolt_driver(target, auth=auth) try: - yield driver - finally: - driver.close() + driver = GraphDatabase.bolt_driver(target, auth=auth) + try: + yield driver + finally: + driver.close() + except BoltHandshakeError as error: + skip(error.args[0]) @fixture(scope="session") @@ -302,6 +306,8 @@ def neo4j_driver(target, auth): skip(error.args[0]) else: raise + except BoltHandshakeError as error: + skip(error.args[0]) else: try: yield driver diff --git a/tests/integration/examples/test_auth_example.py b/tests/integration/examples/test_auth_example.py index 6450f38b9..d8528ef53 100644 --- a/tests/integration/examples/test_auth_example.py +++ b/tests/integration/examples/test_auth_example.py @@ -19,13 +19,18 @@ # limitations under the License. +import pytest + # tag::basic-auth-import[] from neo4j import GraphDatabase # end::basic-auth-import[] +from neo4j._exceptions import BoltHandshakeError from tests.integration.examples import DriverSetupExample +# python -m pytest tests/integration/examples/test_auth_example.py -s -v + class BasicAuthExample(DriverSetupExample): # tag::basic-auth[] @@ -34,5 +39,8 @@ def __init__(self, uri, user, password): # end::basic-auth[] -def test(uri, auth): - BasicAuthExample.test(uri, user=auth[0], password=auth[1]) +def test_example(uri, auth): + try: + BasicAuthExample.test(uri, user=auth[0], password=auth[1]) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_autocommit_transaction_example.py b/tests/integration/examples/test_autocommit_transaction_example.py index 1a06c770f..96af6d078 100644 --- a/tests/integration/examples/test_autocommit_transaction_example.py +++ b/tests/integration/examples/test_autocommit_transaction_example.py @@ -24,6 +24,8 @@ # end::autocommit-transaction-import[] +# python -m pytest tests/integration/examples/test_autocommit_transaction_example.py -s -v + class AutocommitTransactionExample: def __init__(self, driver): @@ -41,7 +43,7 @@ def add_person_within_a_second(self, name): # end::autocommit-transaction[] -def test(driver): +def test_example(driver): eg = AutocommitTransactionExample(driver) with eg.driver.session() as session: session.run("MATCH (_) DETACH DELETE _") diff --git a/tests/integration/examples/test_config_connection_pool_example.py b/tests/integration/examples/test_config_connection_pool_example.py index 21d44f808..202518e6d 100644 --- a/tests/integration/examples/test_config_connection_pool_example.py +++ b/tests/integration/examples/test_config_connection_pool_example.py @@ -19,6 +19,10 @@ # limitations under the License. +import pytest + +from neo4j._exceptions import BoltHandshakeError + # tag::config-connection-pool-import[] from neo4j import GraphDatabase # end::config-connection-pool-import[] @@ -26,6 +30,8 @@ from tests.integration.examples import DriverSetupExample +# python -m pytest tests/integration/examples/test_config_connection_pool_example.py -s -v + class ConfigConnectionPoolExample(DriverSetupExample): # tag::config-connection-pool[] @@ -38,4 +44,7 @@ def __init__(self, uri, auth): def test(uri, auth): - ConfigConnectionPoolExample.test(uri, auth) + try: + ConfigConnectionPoolExample.test(uri, auth) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_config_max_retry_time_example.py b/tests/integration/examples/test_config_max_retry_time_example.py index 0f13ba71d..16f509528 100644 --- a/tests/integration/examples/test_config_max_retry_time_example.py +++ b/tests/integration/examples/test_config_max_retry_time_example.py @@ -19,13 +19,18 @@ # limitations under the License. +import pytest + # tag::config-max-retry-time-import[] from neo4j import GraphDatabase # end::config-max-retry-time-import[] +from neo4j._exceptions import BoltHandshakeError from tests.integration.examples import DriverSetupExample +# python -m pytest tests/integration/examples/test_config_max_retry_time_example.py -s -v + class ConfigMaxRetryTimeExample(DriverSetupExample): # tag::config-max-retry-time[] @@ -35,4 +40,7 @@ def __init__(self, uri, auth): def test(uri, auth): - ConfigMaxRetryTimeExample.test(uri, auth) + try: + ConfigMaxRetryTimeExample.test(uri, auth) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_config_secure_example.py b/tests/integration/examples/test_config_secure_example.py index ec6756e83..896daf398 100644 --- a/tests/integration/examples/test_config_secure_example.py +++ b/tests/integration/examples/test_config_secure_example.py @@ -19,13 +19,18 @@ # limitations under the License. +import pytest + # tag::config-secure-import[] from neo4j import GraphDatabase # end::config-secure-import[] +from neo4j._exceptions import BoltHandshakeError from tests.integration.examples import DriverSetupExample +# python -m pytest tests/integration/examples/test_config_secure_example.py -s -v + class ConfigSecureExample(DriverSetupExample): # tag::config-secure[] @@ -34,5 +39,8 @@ def __init__(self, uri, auth): # end::config-secure[] -def test(uri, auth): - ConfigSecureExample.test(uri, auth) +def test_example(uri, auth): + try: + ConfigSecureExample.test(uri, auth) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_config_trust_example.py b/tests/integration/examples/test_config_trust_example.py index 037cce63b..b6bc7fecc 100644 --- a/tests/integration/examples/test_config_trust_example.py +++ b/tests/integration/examples/test_config_trust_example.py @@ -19,6 +19,8 @@ # limitations under the License. +import pytest + # tag::config-trust-import[] from neo4j import GraphDatabase # end::config-trust-import[] @@ -34,7 +36,7 @@ def __init__(self, uri, auth): # end::config-trust[] -def test(uri, auth): +def test_example(uri, auth): # TODO: re-enable when we can test with secure=True on Docker # ConfigTrustExample.test(uri, auth) - pass + pytest.skip("re-enable when we can test with secure=True on Docker") diff --git a/tests/integration/examples/test_custom_auth_example.py b/tests/integration/examples/test_custom_auth_example.py index 6159dbca2..ec2ffa066 100644 --- a/tests/integration/examples/test_custom_auth_example.py +++ b/tests/integration/examples/test_custom_auth_example.py @@ -19,13 +19,18 @@ # limitations under the License. +import pytest + # tag::custom-auth-import[] from neo4j import GraphDatabase, custom_auth # end::custom-auth-import[] +from neo4j._exceptions import BoltHandshakeError from tests.integration.examples import DriverSetupExample +# python -m pytest tests/integration/examples/test_custom_auth_example.py -s -v + class CustomAuthExample(DriverSetupExample): # tag::custom-auth[] @@ -35,5 +40,8 @@ def __init__(self, uri, principal, credentials, realm, scheme, **parameters): # end::custom-auth[] -def test(uri, auth): - CustomAuthExample.test(uri, auth[0], auth[1], None, "basic", key="value") +def test_example(uri, auth): + try: + CustomAuthExample.test(uri, auth[0], auth[1], None, "basic", key="value") + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_custom_resolver_example.py b/tests/integration/examples/test_custom_resolver_example.py index 9eb277458..753bcb95c 100644 --- a/tests/integration/examples/test_custom_resolver_example.py +++ b/tests/integration/examples/test_custom_resolver_example.py @@ -19,13 +19,19 @@ # limitations under the License. +import pytest + # tag::custom-resolver-import[] from neo4j import GraphDatabase # end::custom-resolver-import[] +from neo4j._exceptions import BoltHandshakeError from tests.integration.examples import DriverSetupExample +# python -m pytest tests/integration/examples/test_custom_resolver_example.py -s -v + + class CustomResolverExample(DriverSetupExample): # tag::custom-resolver[] @@ -44,5 +50,8 @@ def resolve(address): # end::custom-resolver[] -def test(uri, auth): - CustomResolverExample.test(uri, auth) +def test_example(uri, auth): + try: + CustomResolverExample.test(uri, auth) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_cypher_error_example.py b/tests/integration/examples/test_cypher_error_example.py index 223102c2c..2b51c753e 100644 --- a/tests/integration/examples/test_cypher_error_example.py +++ b/tests/integration/examples/test_cypher_error_example.py @@ -17,6 +17,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + + from contextlib import redirect_stdout from io import StringIO @@ -46,7 +48,7 @@ def select_employee(tx, name): # end::cypher-error[] -def test(bolt_driver): +def test_example(bolt_driver): s = StringIO() with redirect_stdout(s): example = Neo4jErrorExample(bolt_driver) diff --git a/tests/integration/examples/test_driver_lifecycle_example.py b/tests/integration/examples/test_driver_lifecycle_example.py index 26d65281f..15072196f 100644 --- a/tests/integration/examples/test_driver_lifecycle_example.py +++ b/tests/integration/examples/test_driver_lifecycle_example.py @@ -19,10 +19,16 @@ # limitations under the License. +import pytest + # tag::driver-lifecycle-import[] from neo4j import GraphDatabase # end::driver-lifecycle-import[] +from neo4j._exceptions import BoltHandshakeError + + +# python -m pytest tests/integration/examples/test_driver_lifecycle_example.py -s -v # tag::driver-lifecycle[] class DriverLifecycleExample: @@ -34,6 +40,9 @@ def close(self): # end::driver-lifecycle[] -def test(uri, auth): - eg = DriverLifecycleExample(uri, auth) - eg.close() +def test_example(uri, auth): + try: + eg = DriverLifecycleExample(uri, auth) + eg.close() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_hello_world_example.py b/tests/integration/examples/test_hello_world_example.py index e1ca49657..8e673579c 100644 --- a/tests/integration/examples/test_hello_world_example.py +++ b/tests/integration/examples/test_hello_world_example.py @@ -19,6 +19,8 @@ # limitations under the License. +import pytest + from contextlib import redirect_stdout from io import StringIO @@ -26,6 +28,10 @@ from neo4j import GraphDatabase # end::hello-world-import[] +from neo4j._exceptions import BoltHandshakeError + + +# python -m pytest tests/integration/examples/test_hello_world_example.py -s -v # tag::hello-world[] class HelloWorldExample: @@ -55,10 +61,14 @@ def _create_and_return_greeting(tx, message): def test_hello_world_example(uri, auth): - s = StringIO() - with redirect_stdout(s): - example = HelloWorldExample(uri, auth) - example.print_greeting("hello, world") - example.close() + try: + s = StringIO() + with redirect_stdout(s): + example = HelloWorldExample(uri, auth) + example.print_greeting("hello, world") + example.close() + + assert s.getvalue().startswith("hello, world, from node ") + except BoltHandshakeError as error: + pytest.skip(error.args[0]) - assert s.getvalue().startswith("hello, world, from node ") diff --git a/tests/integration/examples/test_kerberos_auth_example.py b/tests/integration/examples/test_kerberos_auth_example.py index 56ec15c8b..960024243 100644 --- a/tests/integration/examples/test_kerberos_auth_example.py +++ b/tests/integration/examples/test_kerberos_auth_example.py @@ -19,7 +19,7 @@ # limitations under the License. -from pytest import skip +import pytest # tag::kerberos-auth-import[] from neo4j import GraphDatabase, kerberos_auth @@ -28,6 +28,8 @@ from tests.integration.examples import DriverSetupExample +# python -m pytest tests/integration/examples/test_kerberos_auth_example.py -s -v + class KerberosAuthExample(DriverSetupExample): # tag::kerberos-auth[] def __init__(self, uri, ticket): @@ -35,5 +37,5 @@ def __init__(self, uri, ticket): # end::kerberos-auth[] -def test(): - skip("Currently no way to test Kerberos auth") +def test_example(): + pytest.skip("Currently no way to test Kerberos auth") diff --git a/tests/integration/examples/test_pass_bookmarks_example.py b/tests/integration/examples/test_pass_bookmarks_example.py index 4d03a8a69..d7a4b8d6d 100644 --- a/tests/integration/examples/test_pass_bookmarks_example.py +++ b/tests/integration/examples/test_pass_bookmarks_example.py @@ -18,10 +18,17 @@ # See the License for the specific language governing permissions and # limitations under the License. + +import pytest + # tag:pass-bookmarks-import[] from neo4j import GraphDatabase # end::pass-bookmarks-import[] +from neo4j._exceptions import BoltHandshakeError + + +# python -m pytest tests/integration/examples/test_pass_bookmarks_example.py -s -v # tag::pass-bookmarks[] class BookmarksExample: @@ -85,7 +92,10 @@ def main(self): def test(uri, auth): - eg = BookmarksExample(uri, auth) - with eg.driver.session() as session: - session.run("MATCH (_) DETACH DELETE _") - eg.main() + try: + eg = BookmarksExample(uri, auth) + with eg.driver.session() as session: + session.run("MATCH (_) DETACH DELETE _") + eg.main() + except BoltHandshakeError as error: + pytest.skip(error.args[0]) diff --git a/tests/integration/examples/test_read_write_transaction_example.py b/tests/integration/examples/test_read_write_transaction_example.py index b5537c4ac..eddd14b47 100644 --- a/tests/integration/examples/test_read_write_transaction_example.py +++ b/tests/integration/examples/test_read_write_transaction_example.py @@ -46,7 +46,7 @@ def match_person_node(tx, name): # end::read-write-transaction[] -def test(driver): +def test_example(driver): eg = ReadWriteTransactionExample(driver) with eg.driver.session() as session: session.run("MATCH (_) DETACH DELETE _") diff --git a/tests/integration/examples/test_result_consume_example.py b/tests/integration/examples/test_result_consume_example.py index 6e83a6750..e7837339c 100644 --- a/tests/integration/examples/test_result_consume_example.py +++ b/tests/integration/examples/test_result_consume_example.py @@ -49,7 +49,7 @@ def match_person_nodes(tx): # end::result-consume[] -def test(driver): +def test_example(driver): eg = ResultConsumeExample(driver) eg.delete_all() eg.add_person("Alice") diff --git a/tests/integration/examples/test_result_retain_example.py b/tests/integration/examples/test_result_retain_example.py index fbb91173c..15e01cb44 100644 --- a/tests/integration/examples/test_result_retain_example.py +++ b/tests/integration/examples/test_result_retain_example.py @@ -68,7 +68,7 @@ def count_employees(self, company_name): "RETURN count(emp)", company_name=company_name).single().value() -def test(driver): +def test_example(driver): eg = ResultRetainExample(driver) eg.delete_all() eg.add_person("Alice") diff --git a/tests/integration/examples/test_service_unavailable_example.py b/tests/integration/examples/test_service_unavailable_example.py index 22a0d2207..9fe7dcb4d 100644 --- a/tests/integration/examples/test_service_unavailable_example.py +++ b/tests/integration/examples/test_service_unavailable_example.py @@ -19,7 +19,7 @@ # limitations under the License. -from pytest import skip +import pytest # tag::service-unavailable-import[] from neo4j.exceptions import ServiceUnavailable @@ -42,5 +42,6 @@ def add_item(self): # end::service-unavailable[] -def test(): - skip("TODO") +def test_example(): + # TODO: Better error messages for the user + pytest.skip("Fix better error messages for the user. Be able to kill the server.") diff --git a/tests/integration/examples/test_session_example.py b/tests/integration/examples/test_session_example.py index f9635a10e..1588720ae 100644 --- a/tests/integration/examples/test_session_example.py +++ b/tests/integration/examples/test_session_example.py @@ -35,7 +35,7 @@ def add_person(self, name): # end::session[] -def test(driver): +def test_example(driver): eg = SessionExample(driver) with eg.driver.session() as session: session.run("MATCH (_) DETACH DELETE _") diff --git a/tests/integration/examples/transaction_function_example.py b/tests/integration/examples/transaction_function_example.py index 3ff13a1cf..8365bbe09 100644 --- a/tests/integration/examples/transaction_function_example.py +++ b/tests/integration/examples/transaction_function_example.py @@ -52,7 +52,7 @@ def add_person(self, name): return add_person(self.driver, name) -def test(bolt_driver): +def test_example(bolt_driver): eg = TransactionFunctionExample(bolt_driver) with eg.driver.session() as session: session.run("MATCH (_) DETACH DELETE _") diff --git a/tests/integration/test_bolt_driver.py b/tests/integration/test_bolt_driver.py index ff06ad0e2..b7910bf08 100644 --- a/tests/integration/test_bolt_driver.py +++ b/tests/integration/test_bolt_driver.py @@ -23,14 +23,17 @@ from neo4j import GraphDatabase from neo4j.exceptions import ServiceUnavailable, AuthError +from neo4j._exceptions import BoltHandshakeError def test_bolt_uri(bolt_uri, auth): - with GraphDatabase.driver(bolt_uri, auth=auth) as driver: - with driver.session() as session: - value = session.run("RETURN 1").single().value() - assert value == 1 - + try: + with GraphDatabase.driver(bolt_uri, auth=auth) as driver: + with driver.session() as session: + value = session.run("RETURN 1").single().value() + assert value == 1 + except BoltHandshakeError as error: + skip(error.args[0]) # def test_readonly_bolt_uri(readonly_bolt_uri, auth): # with GraphDatabase.driver(readonly_bolt_uri, auth=auth) as driver: @@ -48,6 +51,8 @@ def test_neo4j_uri(neo4j_uri, auth): except ServiceUnavailable as error: if error.args[0] == "Server does not support routing": skip(error.args[0]) + except BoltHandshakeError as error: + skip(error.args[0]) # TODO @@ -70,16 +75,22 @@ def test_normal_use_case(bolt_driver): def test_invalid_url_scheme(service): address = service.addresses[0] uri = "x://{}:{}".format(address[0], address[1]) - with raises(ValueError): - _ = GraphDatabase.driver(uri, auth=service.auth) + try: + with raises(ValueError): + _ = GraphDatabase.driver(uri, auth=service.auth) + except BoltHandshakeError as error: + skip(error.args[0]) def test_fail_nicely_when_using_http_port(service): from tests.integration.conftest import NEO4J_PORTS address = service.addresses[0] uri = "bolt://{}:{}".format(address[0], NEO4J_PORTS["http"]) - with raises(ServiceUnavailable): - _ = GraphDatabase.driver(uri, auth=service.auth) + try: + with raises(ServiceUnavailable): + _ = GraphDatabase.driver(uri, auth=service.auth) + except BoltHandshakeError as error: + skip(error.args[0]) def test_custom_resolver(service): @@ -90,18 +101,24 @@ def my_resolver(socket_address): yield "99.99.99.99", port # should be rejected as unable to connect yield "127.0.0.1", port # should succeed - with GraphDatabase.driver("bolt://*", auth=service.auth, - connect_timeout=3, # enables rapid timeout - resolver=my_resolver) as driver: - with driver.session() as session: - summary = session.run("RETURN 1").summary() - assert summary.server.address == ("127.0.0.1", port) + try: + with GraphDatabase.driver("bolt://*", auth=service.auth, + connect_timeout=3, # enables rapid timeout + resolver=my_resolver) as driver: + with driver.session() as session: + summary = session.run("RETURN 1").summary() + assert summary.server.address == ("127.0.0.1", port) + except BoltHandshakeError as error: + skip(error.args[0]) def test_encrypted_arg_can_still_be_used(bolt_uri, auth): with warns(UserWarning): - with GraphDatabase.driver(bolt_uri, auth=auth, encrypted=False) as driver: - assert not driver.secure + try: + with GraphDatabase.driver(bolt_uri, auth=auth, encrypted=False) as driver: + assert not driver.secure + except BoltHandshakeError as error: + skip(error.args[0]) def test_insecure_by_default(bolt_driver): @@ -110,6 +127,9 @@ def test_insecure_by_default(bolt_driver): def test_should_fail_on_incorrect_password(bolt_uri): with raises(AuthError): - with GraphDatabase.driver(bolt_uri, auth=("neo4j", "wrong-password")) as driver: - with driver.session() as session: - _ = session.run("RETURN 1") + try: + with GraphDatabase.driver(bolt_uri, auth=("neo4j", "wrong-password")) as driver: + with driver.session() as session: + _ = session.run("RETURN 1") + except BoltHandshakeError as error: + skip(error.args[0]) diff --git a/tests/integration/test_readme.py b/tests/integration/test_readme.py index febb30e7c..19f9a1586 100644 --- a/tests/integration/test_readme.py +++ b/tests/integration/test_readme.py @@ -18,6 +18,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + +from neo4j._exceptions import BoltHandshakeError + +# python -m pytest tests/integration/test_readme.py -s -v + def test_should_run_readme(uri, auth): names = set() @@ -25,7 +31,10 @@ def test_should_run_readme(uri, auth): from neo4j import GraphDatabase - driver = GraphDatabase.driver(uri, auth=auth) + try: + driver = GraphDatabase.driver(uri, auth=auth) + except BoltHandshakeError as error: + pytest.skip(error.args[0]) def print_friends(tx, name): for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) " From 935109e1a608376cd6bae6507461114282ee7011 Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Thu, 20 Feb 2020 14:15:20 +0100 Subject: [PATCH 5/7] Removed unused import --- tests/integration/test_autocommit.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/integration/test_autocommit.py b/tests/integration/test_autocommit.py index ef3244d40..a0e3665e4 100644 --- a/tests/integration/test_autocommit.py +++ b/tests/integration/test_autocommit.py @@ -19,8 +19,6 @@ # limitations under the License. -from unittest import SkipTest - import pytest from pytest import raises From 2e653bc8736f609581b7927d9cd1033fc4d8314e Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Thu, 20 Feb 2020 14:16:05 +0100 Subject: [PATCH 6/7] Removed assert on repr of exception --- tests/unit/test_exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py index 617e5e8cd..c72d5bb2b 100644 --- a/tests/unit/test_exceptions.py +++ b/tests/unit/test_exceptions.py @@ -67,7 +67,7 @@ def test_bolt_error(): with pytest.raises(BoltError) as e: error = BoltError("Error Message", address="localhost") - assert repr(error) == "BoltError('Error Message')" + # assert repr(error) == "BoltError('Error Message')" This differs between python version 3.6 "BoltError('Error Message',)" and 3.7 assert str(error) == "Error Message" assert error.args == ("Error Message",) assert error.address == "localhost" From d91a15d7c91dcf96b5b7daefee26074f6da2b0ac Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Thu, 20 Feb 2020 14:17:03 +0100 Subject: [PATCH 7/7] Enabled python 3.8 in test --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 2fff4bafc..2112b15d7 100644 --- a/tox.ini +++ b/tox.ini @@ -2,6 +2,7 @@ envlist = py36 py37 + py38 [testenv] passenv =