def test_should_serve_read_when_missing_writer(self): with StubCluster({9001: "router_no_writers.script", 9005: "return_1.script"}): uri = "bolt+routing://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session(access_mode=READ_ACCESS) as session: result = session.run("RETURN $x", {"x": 1}) for record in result: assert record["x"] == 1 assert result.summary().server.address == ('127.0.0.1', 9005)
def test_should_call_get_routing_table_with_context(self): with StubCluster({9001: "get_routing_table_with_context.script", 9002: "return_1.script"}): uri = "neo4j://127.0.0.1:9001/?name=molly&age=1" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session(access_mode=READ_ACCESS) as session: result = session.run("RETURN $x", {"x": 1}) for record in result: assert record["x"] == 1 assert result.summary().server.address == ('127.0.0.1', 9002)
def test_connection_error_on_explicit_commit(self): with StubCluster({9001: "connection_error_on_commit.script"}): uri = "bolt://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False, max_retry_time=0) as driver: with driver.session() as session: tx = session.begin_transaction() tx.run("CREATE (n {name:'Bob'})").data() with self.assertRaises(ServiceUnavailable): tx.commit()
def test_should_discover_servers_on_driver_construction(self): with StubCluster({9001: "router.script"}): uri = "neo4j://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: table = driver._pool.routing_table assert table.routers == {('127.0.0.1', 9001), ('127.0.0.1', 9002), ('127.0.0.1', 9003)} assert table.readers == {('127.0.0.1', 9004), ('127.0.0.1', 9005)} assert table.writers == {('127.0.0.1', 9006)}
def test_can_select_round_robin_load_balancing_strategy(self): from neobolt.routing import RoutingConnectionPool with StubCluster({9001: "router.script"}): uri = "neo4j://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False, load_balancing_strategy=LOAD_BALANCING_STRATEGY_ROUND_ROBIN) as driver: self.assertIsInstance(driver, RoutingDriver) self.assertIsInstance(driver._pool, RoutingConnectionPool) self.assertIsInstance(driver._pool.load_balancing_strategy, RoundRobinLoadBalancingStrategy)
def test_should_connect_to_read_in_absent_of_writer(self): with StubCluster({9001: "v1/router_no_writers.script", 9004: "v1/empty.script"}): address = ("127.0.0.1", 9001) with RoutingPool(address) as pool: assert not pool.routing_table.is_fresh(READ_ACCESS) connection = pool.acquire(access_mode=READ_ACCESS) assert connection.server.address in pool.routing_table.readers assert not pool.routing_table.is_fresh(WRITE_ACCESS) assert pool.missing_writer
def test_should_remove_writer_from_routing_table_if_present(self): with StubCluster({9001: "router.script"}): address = ("127.0.0.1", 9001) with RoutingPool(address) as pool: pool.ensure_routing_table_is_fresh(WRITE_ACCESS) target = ("127.0.0.1", 9006) assert target in pool.routing_table.writers pool.deactivate(target) assert target not in pool.routing_table.writers
def test_should_be_able_to_read(self): with StubCluster({9001: "router.script", 9004: "return_1.script"}): uri = "neo4j://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session(access_mode=READ_ACCESS) as session: result = session.run("RETURN $x", {"x": 1}) for record in result: assert record["x"] == 1 assert result.summary().server.address == ('127.0.0.1', 9004)
def test_disconnect_after_init(): with StubCluster({9001: "v3/disconnect_after_init.script"}): address = ("127.0.0.1", 9001) with connect(address) as cx: with raises(ServiceUnavailable): metadata = {} cx.run("RETURN $x", {"x": 1}, on_success=metadata.update) cx.send_all() cx.fetch_all()
def test_direct_disconnect_on_run(self): with StubCluster({9001: "disconnect_on_run.script"}): uri = "bolt://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with self.assertRaises(ServiceUnavailable): with driver.session() as session: session.run("RETURN $x", {"x": 1}).consume()
def test_should_disconnect_after_fetching_autocommit_result(self): with StubCluster({9001: "router.script", 9004: "return_1.script"}): uri = "neo4j://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session(access_mode=READ_ACCESS) as session: result = session.run("RETURN $x", {"x": 1}) assert session._connection is not None result.consume() assert session._connection is None
def test_should_retry_if_first_writer_fails(self): with StubCluster({9001: "v1/router_with_multiple_writers.script", 9006: "v1/fail_on_init.script", 9007: "v1/empty.script"}): address = ("127.0.0.1", 9001) with RoutingPool(address) as pool: assert not pool.routing_table.is_fresh(WRITE_ACCESS) _ = pool.acquire(access_mode=WRITE_ACCESS) assert ("127.0.0.1", 9006) not in pool.routing_table.writers assert ("127.0.0.1", 9007) in pool.routing_table.writers
def test_should_retry_if_first_reader_fails(self): with StubCluster({9001: "v1/router.script", 9004: "v1/fail_on_init.script", 9005: "v1/empty.script"}): address = ("127.0.0.1", 9001) with RoutingPool(address) as pool: assert not pool.routing_table.is_fresh(READ_ACCESS) _ = pool.acquire(access_mode=READ_ACCESS) assert ("127.0.0.1", 9004) not in pool.routing_table.readers assert ("127.0.0.1", 9005) in pool.routing_table.readers
def test_default_load_balancing_strategy_is_least_connected(self): with StubCluster({9001: "router.script"}): uri = "bolt+routing://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: self.assertIsInstance(driver, RoutingDriver) self.assertIsInstance(driver._pool, RoutingConnectionPool) self.assertIsInstance(driver._pool.load_balancing_strategy, LeastConnectedLoadBalancingStrategy)
def test_should_not_update_if_fresh(self): with StubCluster({9001: "router.script"}): address = ("127.0.0.1", 9001) with RoutingPool(address) as pool: pool.ensure_routing_table_is_fresh(WRITE_ACCESS) first_updated_time = pool.routing_table.last_updated_time pool.ensure_routing_table_is_fresh(WRITE_ACCESS) second_updated_time = pool.routing_table.last_updated_time assert second_updated_time == first_updated_time assert not pool.missing_writer
def test_should_error_to_writer_in_absent_of_reader(self): with StubCluster({9001: "router_no_readers.script"}): address = ("127.0.0.1", 9001) with RoutingPool(address) as pool: assert not pool.routing_table.is_fresh(WRITE_ACCESS) with self.assertRaises(ProtocolError): _ = pool.acquire(access_mode=WRITE_ACCESS) assert not pool.routing_table.is_fresh(READ_ACCESS) assert not pool.routing_table.is_fresh(WRITE_ACCESS) assert not pool.missing_writer
def test_no_retry_write_on_user_canceled_tx(self): with StubCluster({9001: "router.script", 9006: "user_canceled_tx.script.script"}): uri = "bolt+routing://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session() as session: def unit_of_work(tx): tx.run("RETURN 1") with self.assertRaises(TransientError): _ = session.write_transaction(unit_of_work)
def test_disconnect_on_pull_all(self): with StubCluster({9001: "v1/disconnect_on_pull_all.script"}): address = ("127.0.0.1", 9001) with connect(address, auth=self.auth_token, encrypted=False) as cx: with self.assertRaises(ServiceUnavailable): metadata = {} records = [] cx.run("RETURN $x", {"x": 1}, on_success=metadata.update) cx.pull_all(on_success=metadata.update, on_records=records.extend) cx.sync()
def test_return_1_as_read(): with StubCluster({9001: "v3/return_1_as_read.script"}): address = ("127.0.0.1", 9001) with connect(address) as cx: metadata = {} records = [] cx.run("RETURN $x", {"x": 1}, mode="r", on_success=metadata.update) cx.pull_all(on_success=metadata.update, on_records=records.extend) cx.send_all() cx.fetch_all() assert records == [[1]]
def test_no_writers_should_return_table_with_no_writer(self): with StubCluster({9001: "v1/router_no_writers.script"}): address = ("127.0.0.1", 9001) with RoutingPool() as pool: table = pool.fetch_routing_table(address) assert table.routers == {("127.0.0.1", 9001), ("127.0.0.1", 9002), ("127.0.0.1", 9003)} assert table.readers == {("127.0.0.1", 9004), ("127.0.0.1", 9005)} assert not table.writers assert table.ttl == 300 assert pool.missing_writer
def test_write_transaction_with_error(self): with StubCluster({9001: "router.script", 9006: "error_in_tx.script"}): uri = "bolt+routing://localhost:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session() as session: def unit_of_work(tx): tx.run("X") with self.assertRaises(CypherError): _ = session.write_transaction(unit_of_work)
def test_return_1(self): with StubCluster({9001: "v3/return_1.script"}): address = ("127.0.0.1", 9001) with connect(address, auth=self.auth_token, encrypted=False) as cx: metadata = {} records = [] cx.run("RETURN $x", {"x": 1}, on_success=metadata.update) cx.pull_all(on_success=metadata.update, on_records=records.extend) cx.sync() self.assertEqual([[1]], records)
def test_should_automatically_chain_bookmarks(self): with StubCluster({9001: "router.script", 9004: "bookmark_chain.script"}): uri = "neo4j://localhost:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session(access_mode=READ_ACCESS, bookmarks=["bookmark:0", "bookmark:1"]) as session: with session.begin_transaction(): pass assert session.last_bookmark() == "bookmark:2" with session.begin_transaction(): pass assert session.last_bookmark() == "bookmark:3"
def test_should_get_table_from_router(): with StubCluster({9001: "v3/router.script"}): address = ("127.0.0.1", 9001) with RoutingPool() as pool: table = pool.fetch_routing_table(address) assert table.routers == {("127.0.0.1", 9001), ("127.0.0.1", 9002), ("127.0.0.1", 9003)} assert table.readers == {("127.0.0.1", 9004), ("127.0.0.1", 9005)} assert table.writers == {("127.0.0.1", 9006)} assert table.ttl == 300 assert not pool.missing_writer
def test_direct_session_close_after_server_close(self): with StubCluster({9001: "disconnect_after_init.script"}): uri = "bolt://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False, max_retry_time=0) as driver: with driver.session() as session: with self.assertRaises(ServiceUnavailable): session.write_transaction( lambda tx: tx.run("CREATE (a:Item)"))
def test_routing_disconnect_on_pull_all(self): with StubCluster({ 9001: "router.script", 9004: "disconnect_on_pull_all.script" }): uri = "bolt+routing://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with self.assertRaises(SessionExpired): with driver.session(access_mode=READ_ACCESS) as session: session.run("RETURN $x", {"x": 1}).consume()
def test_disconnect_on_pull_all(): with StubCluster({9001: "v3/disconnect_on_pull_all.script"}): address = ("127.0.0.1", 9001) with connect(address) as cx: with raises(ServiceUnavailable): metadata = {} records = [] cx.run("RETURN $x", {"x": 1}, on_success=metadata.update) cx.pull_all(on_success=metadata.update, on_records=records.extend) cx.send_all() cx.fetch_all()
def test_address_deactivation_on_database_unavailable_error(): with StubCluster({9001: "v3/database_unavailable.script"}): address = ("127.0.0.1", 9001) with connect(address) as cx: cx.pool = FakeConnectionPool() with raises(DatabaseUnavailableError): metadata = {} cx.run("RETURN 1", {}, on_success=metadata.update) cx.pull_all() cx.send_all() cx.fetch_all() assert ("127.0.0.1", 9001) in cx.pool.deactivated_addresses
def test_roll_back_to_initial_server_if_failed_update_with_existing_routers(self): with StubCluster({9001: "v1/router.script"}): initial_address = ("127.0.0.1", 9001) # roll back addresses routers = [("127.0.0.1", 9002), ("127.0.0.1", 9003)] # not reachable servers with RoutingConnectionPool(connector, initial_address, {}, *routers) as pool: pool.update_routing_table() table = pool.routing_table assert table.routers == {("127.0.0.1", 9001), ("127.0.0.1", 9002), ("127.0.0.1", 9003)} assert table.readers == {("127.0.0.1", 9004), ("127.0.0.1", 9005)} assert table.writers == {("127.0.0.1", 9006)} assert table.ttl == 300
def test_should_retain_connection_if_fetching_multiple_results(self): with StubCluster({9001: "router.script", 9004: "return_1_twice.script"}): uri = "neo4j://127.0.0.1:9001" with GraphDatabase.driver(uri, auth=self.auth_token, encrypted=False) as driver: with driver.session(access_mode=READ_ACCESS) as session: result_1 = session.run("RETURN $x", {"x": 1}) result_2 = session.run("RETURN $x", {"x": 1}) assert session._connection is not None result_1.consume() assert session._connection is not None result_2.consume() assert session._connection is None