Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test server fails rest #611

Open
wants to merge 3 commits into
base: 5.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ repos:
- flake8-bugbear
- flake8-builtins
- flake8-docstrings
- flake8-picky-parentheses
- flake8-picky-parentheses >= 0.5.3
- flake8-quotes
- pep8-naming
- repo: https://github.com/pycqa/isort
Expand Down
2 changes: 1 addition & 1 deletion tests/stub/retry/scripts/commit_disconnect.script
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
*: RESET
Expand Down
2 changes: 1 addition & 1 deletion tests/stub/retry/scripts/read.script
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
*: RESET
Expand Down
2 changes: 1 addition & 1 deletion tests/stub/retry/scripts/read_syntax_error.script
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
*: RESET
Expand Down
58 changes: 58 additions & 0 deletions tests/stub/retry/scripts/reset_fails_after_pull.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
!: BOLT 4.4
!: ALLOW RESTART
!: PY invalid_responses = round = 0

A: HELLO {"{}": "*"}

IF: round == 0
{{
PY: round += 1
*: RESET

{?
# Optionally a transaction
C: BEGIN {"{}": "*"}
S: SUCCESS {}
?}
C: RUN {"U": "*"} {"{}": "*"} {"{}": "*"}
S: SUCCESS {"t_first": 2, "fields": ["n"], "qid": 0}
C: PULL {"n": {"Z": "*"}}
S: FAILURE {"code": "Neo.TransientError.Statement.RemoteExecutionTransientError", "message": "Remote execution failed with code N/A and message 'Failed to obtain connection towards READ server. Known routing table is: Ttl 1703005857129, currentTime 1703005847132, routers [], writers [], readers [], database 'neo4j''"}
{*
C: RESET
#INVALID_RESPONSE#
PY: invalid_responses += 1
*}
}}
ELIF: round == 1
{{
PY: round += 1
*: RESET

{{
C: BEGIN {"{}": "*"}
S: SUCCESS {}
C: RUN {"U": "*"} {"{}": "*"} {"{}": "*"}
S: SUCCESS {"t_first": 2, "fields": ["n"], "qid": 0}
C: PULL {"n": {"Z": "*"}}
S: RECORD [1]
S: SUCCESS {"type": "r"}
C: COMMIT
S: SUCCESS {}
----
C: RUN {"U": "*"} {"{}": "*"} {"{}": "*"}
S: SUCCESS {"t_first": 2, "fields": ["n"], "qid": 0}
C: PULL {"n": {"Z": "*"}}
S: RECORD [1]
S: SUCCESS {"type": "r"}
}}

*: RESET
}}
ELSE:
{{
PY: round += 1
S: <EXIT>
}}

?: GOODBYE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
C: BEGIN {}
Expand Down
2 changes: 1 addition & 1 deletion tests/stub/retry/scripts/retry_with_fail_after_pull.script
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
C: BEGIN {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
C: BEGIN {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
C: BEGIN {}
Expand Down
2 changes: 1 addition & 1 deletion tests/stub/retry/scripts/tx_pull_yielding_failure.script
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
C: BEGIN {}
Expand Down
2 changes: 1 addition & 1 deletion tests/stub/retry/scripts/write_syntax_error.script
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!: BOLT 4.3
!: BOLT 4.4

A: HELLO {"{}": "*"}
*: RESET
Expand Down
105 changes: 103 additions & 2 deletions tests/stub/retry/test_retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class TestRetry(TestkitTestCase):

required_features = types.Feature.BOLT_4_3,
required_features = types.Feature.BOLT_4_4,

def setUp(self):
super().setUp()
Expand Down Expand Up @@ -222,4 +222,105 @@ def once(tx):
for failure in failures:
with self.subTest(failure=failure):
_test()
self._server.reset()

def test_reset_fails_after_pull(self):
def _test(invalid_response_, api_):
def check_exception(exc):
self.assertEqual(
exc.exception.code,
"Neo.TransientError.Statement."
"RemoteExecutionTransientError"
)
if self.driver_supports_features(
types.Feature.API_RETRYABLE_EXCEPTION
):
self.assertTrue(exc.exception.retryable)

def api_call(session_):
if api_ == "session":
with self.assertRaises(types.DriverError) as exc:
result = session_.run("RETURN 1 AS n")
list(result)
check_exception(exc)
elif api_ == "explicit_tx":
tx = session_.begin_transaction()
try:
with self.assertRaises(types.DriverError) as exc:
result = tx.run("RETURN 1 AS n")
list(result)
check_exception(exc)
finally:
tx.close()
elif api_ == "managed_tx":
run = 0

def work(tx):
nonlocal run
run += 1
if run == 1:
with self.assertRaises(types.DriverError) as exc:
result = tx.run("RETURN 1 AS n")
list(result)
check_exception(exc)
raise exc.exception
else:
result = tx.run("RETURN 1 AS n")
return list(result)

records = session_.execute_write(work)
assert len(records) == 1
self.assertEqual(records, [
types.Record(values=[types.CypherInt(1)])
])
else:
raise ValueError(f"Unknown API: {api_}")

self._server.start(
path=self.script_path("reset_fails_after_pull.script"),
vars_={
"#INVALID_RESPONSE#": invalid_response_,
}
)
auth = types.AuthorizationToken("basic", principal="",
credentials="")
driver = Driver(self._backend,
"bolt://%s" % self._server.address, auth)
try:
session = driver.session("r")
try:
api_call(session)

finally:
session.close()
# driver should've killed the misbehaving connection
try:
self.assertEqual(
self._server.count_responses("<HANGUP>"), 1
)
finally:
self._server._dump()
finally:
driver.close()
self._server.done()

invalid_responses = (
(
'S: FAILURE {"code": "Neo.ClientError.General.Unknown", '
'"message": "The driver should ignore this error!"}'
),
"S: IGNORED",
(
"# MIXED \n"
"IF: invalid_responses <= 1\n"
' S: FAILURE {"code": "Neo.ClientError.General.Unknown", '
'"message": "The driver should ignore this error!"}\n'
"ELSE:\n"
" S: IGNORED\n"
)
)
for invalid_response in invalid_responses:
for api in ("session", "explicit_tx", "managed_tx"):
with self.subTest(response=invalid_response[2:10].strip(),
api=api):
_test(invalid_response, api)
self._server.reset()
4 changes: 2 additions & 2 deletions tests/stub/retry/test_retry_clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class TestRetryClustering(TestkitTestCase):

required_features = types.Feature.BOLT_4_3,
required_features = types.Feature.BOLT_4_4,

def setUp(self):
super().setUp()
Expand Down Expand Up @@ -283,7 +283,7 @@ def twice(tx):
def get_vars(self):
host = self._routingServer.host
v = {
"#VERSION#": "4.3",
"#VERSION#": "4.4",
"#HOST#": host,
"#ROUTINGCTX#":
'{"address": "' + host
Expand Down