|
19 | 19 | # limitations under the License. |
20 | 20 |
|
21 | 21 | from mock import patch |
| 22 | +from unittest import skipUnless |
| 23 | +from uuid import uuid4 |
22 | 24 |
|
| 25 | +from neo4j.v1 import READ_ACCESS, WRITE_ACCESS |
23 | 26 | from neo4j.v1.exceptions import CypherError, ResultError |
24 | 27 | from neo4j.v1.session import GraphDatabase, basic_auth, Record |
25 | 28 | from neo4j.v1.types import Node, Relationship, Path |
|
31 | 34 | AUTH_TOKEN = basic_auth("neotest", "neotest") |
32 | 35 |
|
33 | 36 |
|
| 37 | +def get_server_version(): |
| 38 | + driver = GraphDatabase.driver(BOLT_URI, auth=AUTH_TOKEN, encrypted=False) |
| 39 | + with driver.session() as session: |
| 40 | + full_version = session.connection.server_version |
| 41 | + if full_version is None: |
| 42 | + return "Neo4j", (3, 0), () |
| 43 | + product, _, tagged_version = full_version.partition("/") |
| 44 | + tags = tagged_version.split("-") |
| 45 | + version = map(int, tags[0].split(".")) |
| 46 | + return product, tuple(version), tuple(tags[1:]) |
| 47 | + |
| 48 | + |
| 49 | +SERVER_PRODUCT, SERVER_VERSION, SERVER_TAGS = get_server_version() |
| 50 | + |
| 51 | + |
34 | 52 | class AutoCommitTransactionTestCase(ServerTestCase): |
35 | 53 |
|
36 | 54 | def setUp(self): |
@@ -415,17 +433,60 @@ def test_can_rollback_transaction_using_with_block(self): |
415 | 433 | tx.run("MATCH (a) WHERE id(a) = {n} " |
416 | 434 | "SET a.foo = {foo}", {"n": node_id, "foo": "bar"}) |
417 | 435 |
|
| 436 | + tx.success = False |
| 437 | + |
418 | 438 | # Check the property value |
419 | 439 | result = session.run("MATCH (a) WHERE id(a) = {n} " |
420 | 440 | "RETURN a.foo", {"n": node_id}) |
421 | 441 | assert len(list(result)) == 0 |
422 | 442 |
|
423 | 443 |
|
| 444 | +class BookmarkingTestCase(ServerTestCase): |
| 445 | + |
| 446 | + def setUp(self): |
| 447 | + self.driver = GraphDatabase.driver(BOLT_URI, auth=AUTH_TOKEN, encrypted=False) |
| 448 | + |
| 449 | + def tearDown(self): |
| 450 | + self.driver.close() |
| 451 | + |
| 452 | + @skipUnless(SERVER_VERSION >= (3, 1), "Bookmarking is not supported by this version of Neo4j") |
| 453 | + def test_can_obtain_bookmark_after_commit(self): |
| 454 | + with self.driver.session() as session: |
| 455 | + with session.begin_transaction() as tx: |
| 456 | + tx.run("RETURN 1") |
| 457 | + assert session.last_bookmark is not None |
| 458 | + |
| 459 | + @skipUnless(SERVER_VERSION >= (3, 1), "Bookmarking is not supported by this version of Neo4j") |
| 460 | + def test_can_pass_bookmark_into_next_transaction(self): |
| 461 | + unique_id = uuid4().hex |
| 462 | + |
| 463 | + with self.driver.session(WRITE_ACCESS) as session: |
| 464 | + with session.begin_transaction() as tx: |
| 465 | + tx.run("CREATE (a:Thing {uuid:$uuid})", uuid=unique_id) |
| 466 | + bookmark = session.last_bookmark |
| 467 | + |
| 468 | + assert bookmark is not None |
| 469 | + |
| 470 | + with self.driver.session(READ_ACCESS) as session: |
| 471 | + with session.begin_transaction(bookmark) as tx: |
| 472 | + result = tx.run("MATCH (a:Thing {uuid:$uuid}) RETURN a", uuid=unique_id) |
| 473 | + record_list = list(result) |
| 474 | + assert len(record_list) == 1 |
| 475 | + record = record_list[0] |
| 476 | + assert len(record) == 1 |
| 477 | + thing = record[0] |
| 478 | + assert isinstance(thing, Node) |
| 479 | + assert thing["uuid"] == unique_id |
| 480 | + |
| 481 | + |
424 | 482 | class ResultConsumptionTestCase(ServerTestCase): |
425 | 483 |
|
426 | 484 | def setUp(self): |
427 | 485 | self.driver = GraphDatabase.driver(BOLT_URI, auth=AUTH_TOKEN, encrypted=False) |
428 | 486 |
|
| 487 | + def tearDown(self): |
| 488 | + self.driver.close() |
| 489 | + |
429 | 490 | def test_can_consume_result_immediately(self): |
430 | 491 | session = self.driver.session() |
431 | 492 | tx = session.begin_transaction() |
@@ -564,3 +625,39 @@ def test_peek_at_different_stages(self): |
564 | 625 | # ...when none should follow |
565 | 626 | with self.assertRaises(ResultError): |
566 | 627 | result.peek() |
| 628 | + |
| 629 | + |
| 630 | +class SessionCommitTestCase(ServerTestCase): |
| 631 | + |
| 632 | + def setUp(self): |
| 633 | + self.driver = GraphDatabase.driver(BOLT_URI, auth=AUTH_TOKEN) |
| 634 | + |
| 635 | + def tearDown(self): |
| 636 | + self.driver.close() |
| 637 | + |
| 638 | + def test_should_sync_after_commit(self): |
| 639 | + with self.driver.session() as session: |
| 640 | + tx = session.begin_transaction() |
| 641 | + result = tx.run("RETURN 1") |
| 642 | + tx.commit() |
| 643 | + buffer = result._buffer |
| 644 | + assert len(buffer) == 1 |
| 645 | + assert buffer[0][0] == 1 |
| 646 | + |
| 647 | + |
| 648 | +class SessionRollbackTestCase(ServerTestCase): |
| 649 | + |
| 650 | + def setUp(self): |
| 651 | + self.driver = GraphDatabase.driver(BOLT_URI, auth=AUTH_TOKEN) |
| 652 | + |
| 653 | + def tearDown(self): |
| 654 | + self.driver.close() |
| 655 | + |
| 656 | + def test_should_sync_after_rollback(self): |
| 657 | + with self.driver.session() as session: |
| 658 | + tx = session.begin_transaction() |
| 659 | + result = tx.run("RETURN 1") |
| 660 | + tx.rollback() |
| 661 | + buffer = result._buffer |
| 662 | + assert len(buffer) == 1 |
| 663 | + assert buffer[0][0] == 1 |
0 commit comments