diff --git a/tests/stub/optimizations/scripts/v3/failure_on_begin.script b/tests/stub/optimizations/scripts/v3/failure_on_begin.script new file mode 100644 index 000000000..37b970ddd --- /dev/null +++ b/tests/stub/optimizations/scripts/v3/failure_on_begin.script @@ -0,0 +1,26 @@ +!: BOLT 3 +!: AUTO HELLO + +{* + C: RESET + S: SUCCESS {} +*} +C: BEGIN "*" +S: FAILURE {"code": "Neo.ClientError.MadeUp.Code", "message": "Something went wrong..."} +{? + # for pipelining driver + C: RUN "*" "*" "*" + S: IGNORED + {? + C: PULL_ALL + S: IGNORED + ?} +?} +{+ + C: RESET + S: SUCCESS {} ++} +{? + C: GOODBYE + S: +?} diff --git a/tests/stub/optimizations/scripts/v3/failure_on_pull.script b/tests/stub/optimizations/scripts/v3/failure_on_pull.script new file mode 100644 index 000000000..0f720244e --- /dev/null +++ b/tests/stub/optimizations/scripts/v3/failure_on_pull.script @@ -0,0 +1,23 @@ +!: BOLT 3 +!: AUTO HELLO + +{* + C: RESET + S: SUCCESS {} +*} +{? + C: BEGIN "*" + S: SUCCESS {} +?} +C: RUN "*" "*" "*" +S: SUCCESS {"fields": ["n"]} +C: PULL_ALL +S: FAILURE {"code": "Neo.ClientError.MadeUp.Code", "message": "Something went wrong..."} +{+ + C: RESET + S: SUCCESS {} ++} +{? + C: GOODBYE + S: +?} diff --git a/tests/stub/optimizations/scripts/v3/failure_on_run.script b/tests/stub/optimizations/scripts/v3/failure_on_run.script new file mode 100644 index 000000000..ef1002d62 --- /dev/null +++ b/tests/stub/optimizations/scripts/v3/failure_on_run.script @@ -0,0 +1,26 @@ +!: BOLT 3 +!: AUTO HELLO + +{* + C: RESET + S: SUCCESS {} +*} +{? + C: BEGIN "*" + S: SUCCESS {} +?} +C: RUN "*" "*" "*" +S: FAILURE {"code": "Neo.ClientError.Statement.SyntaxError", "message": "Git gud!"} +{? + # for pipelining driver + C: PULL_ALL + S: IGNORED +?} +{+ + C: RESET + S: SUCCESS {} ++} +{? + C: GOODBYE + S: +?} diff --git a/tests/stub/optimizations/scripts/v4x3/failure_on_begin.script b/tests/stub/optimizations/scripts/v4x3/failure_on_begin.script new file mode 100644 index 000000000..cb2107f2d --- /dev/null +++ b/tests/stub/optimizations/scripts/v4x3/failure_on_begin.script @@ -0,0 +1,26 @@ +!: BOLT 4.3 +!: AUTO HELLO + +{* + C: RESET + S: SUCCESS {} +*} +C: BEGIN "*" +S: FAILURE {"code": "Neo.ClientError.MadeUp.Code", "message": "Something went wrong..."} +{? + # for pipelining driver + C: RUN "*" "*" "*" + S: IGNORED + {? + C: PULL "*" + S: IGNORED + ?} +?} +{+ + C: RESET + S: SUCCESS {} ++} +{? + C: GOODBYE + S: +?} diff --git a/tests/stub/optimizations/scripts/v4x3/failure_on_pull.script b/tests/stub/optimizations/scripts/v4x3/failure_on_pull.script new file mode 100644 index 000000000..b400ccfc7 --- /dev/null +++ b/tests/stub/optimizations/scripts/v4x3/failure_on_pull.script @@ -0,0 +1,23 @@ +!: BOLT 4.3 +!: AUTO HELLO + +{* + C: RESET + S: SUCCESS {} +*} +{? + C: BEGIN "*" + S: SUCCESS {} +?} +C: RUN "*" "*" "*" +S: SUCCESS {"fields": ["n"]} +C: PULL "*" +S: FAILURE {"code": "Neo.ClientError.MadeUp.Code", "message": "Something went wrong..."} +{+ + C: RESET + S: SUCCESS {} ++} +{? + C: GOODBYE + S: +?} diff --git a/tests/stub/optimizations/scripts/v4x3/failure_on_run.script b/tests/stub/optimizations/scripts/v4x3/failure_on_run.script new file mode 100644 index 000000000..cf35858f7 --- /dev/null +++ b/tests/stub/optimizations/scripts/v4x3/failure_on_run.script @@ -0,0 +1,26 @@ +!: BOLT 4.3 +!: AUTO HELLO + +{* + C: RESET + S: SUCCESS {} +*} +{? + C: BEGIN "*" + S: SUCCESS {} +?} +C: RUN "*" "*" "*" +S: FAILURE {"code": "Neo.ClientError.Statement.SyntaxError", "message": "Git gud!"} +{? + # for pipelining driver + C: PULL "*" + S: IGNORED +?} +{+ + C: RESET + S: SUCCESS {} ++} +{? + C: GOODBYE + S: +?} diff --git a/tests/stub/optimizations/test_optimizations.py b/tests/stub/optimizations/test_optimizations.py index 30a4789e4..a79be35d4 100644 --- a/tests/stub/optimizations/test_optimizations.py +++ b/tests/stub/optimizations/test_optimizations.py @@ -173,6 +173,44 @@ def test_no_reset_on_clean_connection(self): check_no_reset=True) self._server.reset() + @driver_feature(types.Feature.OPT_MINIMAL_RESETS) + def test_exactly_one_reset_on_failure(self): + def test(): + script_path = self.script_path( + version, "failure_on_{}.script".format(fail_on) + ) + self._server.start(path=script_path) + auth = types.AuthorizationToken(scheme="basic", principal="neo4j", + credentials="pass") + driver = Driver(self._backend, "bolt://%s" % self._server.address, + auth) + session = driver.session("w") + if use_tx: + with self.assertRaises(types.DriverError): + tx = session.beginTransaction() + res = tx.run("CYPHER") + res.next() + else: + with self.assertRaises(types.DriverError): + res = session.run("CYPHER") + res.next() + session.close() + driver.close() + self._server.done() + reset_count = self._server.count_requests("RESET") + self.assertEqual(reset_count, 1) + + for version in ("v3", "v4x3"): + for use_tx in (False, True): + for fail_on in ("pull", "run", "begin"): + if fail_on == "begin" and not use_tx: + continue + with self.subTest(version + + ("_tx" if use_tx else "_autocommit") + + "_{}".format(fail_on)): + test() + self._server.reset() + @driver_feature(types.Feature.OPT_IMPLICIT_DEFAULT_ARGUMENTS) def test_uses_implicit_default_arguments(self): def test():