Skip to content
Closed
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 nutkit/protocol/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,4 @@ def __init__(self, msg):
self.msg = msg

def __str__(self):
return "BackendError : " + self.msg
return "BackendError : %s" % self.msg
24 changes: 24 additions & 0 deletions tests/neo4j/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,30 @@ def testShouldEchoNestedLists(self):
self.createDriverAndSession()
self.verifyCanEcho(types.CypherList(test_lists))

def testShouldEchoListOfMaps(self):
test_list = [
types.CypherMap({
"a": types.CypherInt(1),
"b": types.CypherInt(2)
}),
types.CypherMap({
"c": types.CypherInt(3),
"d": types.CypherInt(4)
})
]

self.createDriverAndSession()
self.verifyCanEcho(types.CypherList(test_list))

def testShouldEchoMapOfLists(self):
test_map = {
'a': types.CypherList([types.CypherInt(1)]),
'b': types.CypherList([types.CypherInt(2)])
}

self.createDriverAndSession()
self.verifyCanEcho(types.CypherMap(test_map))

def testShouldEchoNode(self):
self.createDriverAndSession()

Expand Down
113 changes: 113 additions & 0 deletions tests/neo4j/txrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,116 @@ def test_does_not_update_last_bookmark_on_rollback(self):
tx.rollback()
bookmarks = self._session.lastBookmarks()
self.assertEqual(len(bookmarks), 0)

def test_does_not_update_last_bookmark_on_failure(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
self.assertThrows(Exception, lambda: tx.run("RETURN").next())
self.assertThrows(Exception, lambda: tx.commit())
bookmarks = self._session.lastBookmarks()
self.assertEqual(len(bookmarks), 0)

def test_should_be_able_to_rollback_a_failure(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
self.assertThrows(Exception, lambda: tx.run("RETURN").next())
tx.rollback()

def test_should_not_rollback_a_rollbacked_tx(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
tx.run('CREATE (:TXNode1)').consume()
tx.rollback()
self.assertThrows(
Exception,
lambda: tx.rollback()
)

def test_should_not_commit_a_rollbacked_tx(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
tx.run('CREATE (:TXNode1)').consume()
tx.rollback()
self.assertThrows(
Exception,
lambda: tx.commit()
)

def test_should_not_rollback_a_commited_tx(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
tx.run('CREATE (:TXNode1)').consume()
tx.commit()
self.assertThrows(
Exception,
lambda: tx.rollback()
)

def test_should_not_commit_a_commited_tx(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
tx.run('CREATE (:TXNode1)').consume()
tx.commit()
self.assertThrows(
Exception,
lambda: tx.commit()
)

def test_should_run_valid_query_in_invalid_tx(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
self.assertThrows(
Exception,
lambda: tx.run("NOT CYPHER").consume()
)
self.assertThrows(
Exception,
lambda: tx.run("RETURN 42").next()
)
tx.rollback()

def test_should_fail_run_in_a_commited_tx(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
tx.commit()
self.assertThrows(
Exception,
lambda: tx.run("RETURN 42").consume()
)

def test_should_fail_run_in_a_rollbacked_tx(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
tx.rollback()
self.assertThrows(
Exception,
lambda: tx.run("RETURN 42").consume()
)

def test_should_throws_exception_when_invalid_tx_params(self):
self._session = self._driver.session("w")
tx = self._session.beginTransaction()
self.assertThrows(
Exception,
lambda: tx.run("RETURN $value", "invalid").next()
)
tx.rollback()

def test_should_fail_to_run_query_for_unreacheable_bookmark(self):
self._session = self._driver.session("w")
tx1 = self._session.beginTransaction()
result = tx1.run('CREATE ()')
result.consume()
tx1.commit()
unreachableBookmark = self._session.lastBookmarks()[0] + "0"
self._session.close()
self._session = self._driver.session(
"w",
bookmarks=[unreachableBookmark]
)
tx2 = self._session.beginTransaction()
self.assertThrows(
Exception,
lambda: tx2.run("CREATE ()").consume()
)
tx2.rollback()
9 changes: 9 additions & 0 deletions tests/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,12 @@ def setUp(self):
except Exception:
self._backend.close()
raise

def assertThrows(self, exception, callable):
try:
callable()
except Exception as e:
if not isinstance(e, exception):
self.fail("%s is not instance of %s" % (e, exception))
else:
self.fail("Expect to throw an exception")
145 changes: 145 additions & 0 deletions tests/stub/bookmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,64 @@
S: SUCCESS {"bookmark": "bm"}
"""

send_and_receive_bookmark_read_tx = """
!: BOLT 4
!: AUTO HELLO
!: AUTO RESET
!: AUTO GOODBYE

C: BEGIN {"bookmarks": ["neo4j:bookmark:v1:tx42"], "mode": "r"}
C: RUN "MATCH (n) RETURN n.name AS name" {} {}
PULL {"n": 1000}
S: SUCCESS {}
SUCCESS {"fields": ["name"]}
SUCCESS {}
C: COMMIT
S: SUCCESS {"bookmark": "neo4j:bookmark:v1:tx4242"}

"""

send_and_receive_bookmark_write_tx = """
!: BOLT 4
!: AUTO HELLO
!: AUTO RESET
!: AUTO GOODBYE

C: BEGIN {"bookmarks": #BOOKMARKS# }
C: RUN "MATCH (n) RETURN n.name AS name" {} {}
PULL {"n": 1000}
S: SUCCESS {}
SUCCESS {"fields": ["name"]}
SUCCESS {}
C: COMMIT
S: SUCCESS {"bookmark": "neo4j:bookmark:v1:tx4242"}

"""

sequecing_writing_and_reading_tx = """
!: BOLT 4
!: AUTO HELLO
!: AUTO RESET
!: AUTO GOODBYE

C: BEGIN {"bookmarks": ["neo4j:bookmark:v1:tx42"]}
C: RUN "MATCH (n) RETURN n.name AS name" {} {}
PULL {"n": 1000}
S: SUCCESS {}
SUCCESS {"fields": ["name"]}
SUCCESS {}
C: COMMIT
S: SUCCESS {"bookmark": "neo4j:bookmark:v1:tx4242"}

C: BEGIN {"bookmarks": ["neo4j:bookmark:v1:tx4242"]}
C: RUN "MATCH (n) RETURN n.name AS name" {} {}
PULL {"n": 1000}
S: SUCCESS {}
SUCCESS {"fields": ["name"]}
SUCCESS {}
C: COMMIT
S: SUCCESS {"bookmark": "neo4j:bookmark:v1:tx424242"}
"""

# Tests bookmarks from transaction
class Tx(TestkitTestCase):
Expand Down Expand Up @@ -50,3 +108,90 @@ def test_last_bookmark(self):
self._server.done()

self.assertEqual(bookmarks, ["bm"])

def test_send_and_receive_bookmarks_read_tx(self):
self._server.start(
script=send_and_receive_bookmark_read_tx
)
session = self._driver.session(
accessMode="r",
bookmarks=["neo4j:bookmark:v1:tx42"]
)
tx = session.beginTransaction()
result = tx.run('MATCH (n) RETURN n.name AS name')
result.next()
tx.commit()
bookmarks = session.lastBookmarks()

self.assertEqual(bookmarks, ["neo4j:bookmark:v1:tx4242"])
self._server.done()

def test_send_and_receive_bookmarks_write_tx(self):
self._server.start(
script=send_and_receive_bookmark_write_tx,
vars={
"#BOOKMARKS#": '["neo4j:bookmark:v1:tx42"]'
}
)
session = self._driver.session(
accessMode="w",
bookmarks=["neo4j:bookmark:v1:tx42"]
)
tx = session.beginTransaction()
result = tx.run('MATCH (n) RETURN n.name AS name')
result.next()
tx.commit()
bookmarks = session.lastBookmarks()

self.assertEqual(bookmarks, ["neo4j:bookmark:v1:tx4242"])
self._server.done()

def test_sequece_of_writing_and_reading_tx(self):
self._server.start(
script=sequecing_writing_and_reading_tx
)
session = self._driver.session(
accessMode="w",
bookmarks=["neo4j:bookmark:v1:tx42"]
)
tx = session.beginTransaction()
result = tx.run('MATCH (n) RETURN n.name AS name')
result.next()
tx.commit()

bookmarks = session.lastBookmarks()
self.assertEqual(bookmarks, ["neo4j:bookmark:v1:tx4242"])

txRead = session.beginTransaction()
result = txRead.run('MATCH (n) RETURN n.name AS name')
result.next()
txRead.commit()

bookmarks = session.lastBookmarks()
self.assertEqual(bookmarks, ["neo4j:bookmark:v1:tx424242"])

self._server.done()

def test_send_and_receive_multiple_bookmarks_write_tx(self):
self._server.start(
script=send_and_receive_bookmark_write_tx,
vars={
"#BOOKMARKS#":
'["neo4j:bookmark:v1:tx42", "neo4j:bookmark:v1:tx43"]'
}
)
session = self._driver.session(
accessMode="w",
bookmarks=[
"neo4j:bookmark:v1:tx42",
"neo4j:bookmark:v1:tx43"
]
)
tx = session.beginTransaction()
result = tx.run('MATCH (n) RETURN n.name AS name')
result.next()
tx.commit()
bookmarks = session.lastBookmarks()

self.assertEqual(bookmarks, ["neo4j:bookmark:v1:tx4242"])
self._server.done()
27 changes: 27 additions & 0 deletions tests/stub/disconnected.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@
S: <EXIT>
"""

script_on_reset = """
!: BOLT 4
!: AUTO HELLO
!: AUTO GOODBYE

C: RUN "RETURN 1 as n" {} {}
PULL {"n": 1000}
S: SUCCESS {"fields": ["n"]}
RECORD [1]
SUCCESS {}
C: RESET
S: FAILURE {"code": "Neo.TransientError.General.DatabaseUnavailable", "message": "Unable to reset"}
"""

class SessionRunDisconnected(TestkitTestCase):
def setUp(self):
Expand Down Expand Up @@ -118,6 +131,20 @@ def test_disconnect_on_pull(self):
expected_step = "after run"
self.assertEqual(step, expected_step)

def test_fail_on_reset(self):
self._server.start(script=script_on_reset)
step = self._run()
self._session.close()
accept_count = self._server.count_responses("<ACCEPT>")
hangup_count = self._server.count_responses("<HANGUP>")
active_connections = accept_count - hangup_count
self._driver.close()
self._server.done()
self.assertEqual(step, "success")
self.assertEqual(accept_count, 1)
self.assertEqual(hangup_count, 1)
self.assertEqual(active_connections, 0)

def get_vars(self):
return {
"#EXTRA_HELLO_PARAMS#": self.get_extra_hello_props()
Expand Down
Loading