diff --git a/driver/src/main/java/org/neo4j/driver/Config.java b/driver/src/main/java/org/neo4j/driver/Config.java index a02a608899..d307ce7042 100644 --- a/driver/src/main/java/org/neo4j/driver/Config.java +++ b/driver/src/main/java/org/neo4j/driver/Config.java @@ -285,6 +285,9 @@ RetrySettings retrySettings() return retrySettings; } + /** + * @return if the metrics is enabled or not on this driver. + */ public boolean isMetricsEnabled() { return isMetricsEnabled; diff --git a/driver/src/main/java/org/neo4j/driver/Driver.java b/driver/src/main/java/org/neo4j/driver/Driver.java index 6b25ac5c60..40dc10bff1 100644 --- a/driver/src/main/java/org/neo4j/driver/Driver.java +++ b/driver/src/main/java/org/neo4j/driver/Driver.java @@ -164,4 +164,27 @@ public interface Driver extends AutoCloseable */ @Experimental TypeSystem defaultTypeSystem(); + + /** + * This verifies if the driver can connect to a remote server or a cluster + * by establishing a network connection with the remote and possibly exchanging a few data before closing the connection. + * + * It throws exception if fails to connect. Use the exception to further understand the cause of the connectivity problem. + * Note: Even if this method throws an exception, the driver still need to be closed via {@link #close()} to free up all resources. + */ + void verifyConnectivity(); + + /** + * This verifies if the driver can connect to a remote server or cluster + * by establishing a network connection with the remote and possibly exchanging a few data before closing the connection. + * + * This operation is asynchronous and returns a {@link CompletionStage}. This stage is completed with + * {@code null} when the driver connects to the remote server or cluster successfully. + * It is completed exceptionally if the driver failed to connect the remote server or cluster. + * This exception can be used to further understand the cause of the connectivity problem. + * Note: Even if this method complete exceptionally, the driver still need to be closed via {@link #closeAsync()} to free up all resources. + * + * @return a {@link CompletionStage completion stage} that represents the asynchronous verification. + */ + CompletionStage verifyConnectivityAsync(); } diff --git a/driver/src/main/java/org/neo4j/driver/GraphDatabase.java b/driver/src/main/java/org/neo4j/driver/GraphDatabase.java index 07b6207c66..1895ca40e5 100644 --- a/driver/src/main/java/org/neo4j/driver/GraphDatabase.java +++ b/driver/src/main/java/org/neo4j/driver/GraphDatabase.java @@ -154,19 +154,40 @@ public static Driver routingDriver( Iterable routingUris, AuthToken authTok for ( URI uri : routingUris ) { + final Driver driver = driver( uri, authToken, config ); try { - return driver( uri, authToken, config ); + driver.verifyConnectivity(); + return driver; } catch ( ServiceUnavailableException e ) { log.warn( "Unable to create routing driver for URI: " + uri, e ); + closeDriver( driver, uri, log ); + } + catch ( Throwable e ) + { + // for any other errors, we first close the driver and then rethrow the original error out. + closeDriver( driver, uri, log ); + throw e; } } throw new ServiceUnavailableException( "Failed to discover an available server" ); } + private static void closeDriver( Driver driver, URI uri, Logger log ) + { + try + { + driver.close(); + } + catch ( Throwable closeError ) + { + log.warn( "Unable to close driver towards URI: " + uri, closeError ); + } + } + private static void assertRoutingUris( Iterable uris ) { for ( URI uri : uris ) diff --git a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java index 0d3bca4022..24edb602df 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java +++ b/driver/src/main/java/org/neo4j/driver/internal/DriverFactory.java @@ -27,6 +27,13 @@ import java.net.URI; import java.security.GeneralSecurityException; +import org.neo4j.driver.AuthToken; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Logger; +import org.neo4j.driver.Logging; +import org.neo4j.driver.exceptions.ClientException; import org.neo4j.driver.internal.async.connection.BootstrapFactory; import org.neo4j.driver.internal.async.connection.ChannelConnector; import org.neo4j.driver.internal.async.connection.ChannelConnectorImpl; @@ -49,19 +56,11 @@ import org.neo4j.driver.internal.spi.ConnectionProvider; import org.neo4j.driver.internal.util.Clock; import org.neo4j.driver.internal.util.Futures; -import org.neo4j.driver.AuthToken; -import org.neo4j.driver.AuthTokens; -import org.neo4j.driver.Config; -import org.neo4j.driver.Driver; -import org.neo4j.driver.Logger; -import org.neo4j.driver.Logging; -import org.neo4j.driver.exceptions.ClientException; -import org.neo4j.driver.exceptions.ServiceUnavailableException; import org.neo4j.driver.net.ServerAddressResolver; import static java.lang.String.format; -import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER; import static org.neo4j.driver.internal.cluster.IdentityResolver.IDENTITY_RESOLVER; +import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER; import static org.neo4j.driver.internal.security.SecurityPlan.insecure; import static org.neo4j.driver.internal.util.ErrorUtil.addSuppressed; @@ -105,11 +104,7 @@ public final Driver newInstance ( URI uri, AuthToken authToken, RoutingSettings MetricsProvider metricsProvider = createDriverMetrics( config, createClock() ); ConnectionPool connectionPool = createConnectionPool( authToken, securityPlan, bootstrap, metricsProvider, config, ownsEventLoopGroup ); - InternalDriver driver = createDriver( uri, securityPlan, address, connectionPool, eventExecutorGroup, newRoutingSettings, retryLogic, metricsProvider, config ); - - verifyConnectivity( driver, connectionPool, config ); - - return driver; + return createDriver( uri, securityPlan, address, connectionPool, eventExecutorGroup, newRoutingSettings, retryLogic, metricsProvider, config ); } protected ConnectionPool createConnectionPool( AuthToken authToken, SecurityPlan securityPlan, Bootstrap bootstrap, @@ -366,30 +361,6 @@ private static void assertNoRoutingContext( URI uri, RoutingSettings routingSett } } - private static void verifyConnectivity( InternalDriver driver, ConnectionPool connectionPool, Config config ) - { - try - { - // block to verify connectivity, close connection pool if thread gets interrupted - Futures.blockingGet( driver.verifyConnectivity(), - () -> closeConnectionPoolOnThreadInterrupt( connectionPool, config.logging() ) ); - } - catch ( Throwable connectionError ) - { - if ( Thread.currentThread().isInterrupted() ) - { - // current thread has been interrupted while verifying connectivity - // connection pool should've been closed - throw new ServiceUnavailableException( "Unable to create driver. Thread has been interrupted.", - connectionError ); - } - - // we need to close the connection pool if driver creation threw exception - closeConnectionPoolAndSuppressError( connectionPool, connectionError ); - throw connectionError; - } - } - private static void closeConnectionPoolAndSuppressError( ConnectionPool connectionPool, Throwable mainError ) { try @@ -401,11 +372,4 @@ private static void closeConnectionPoolAndSuppressError( ConnectionPool connecti addSuppressed( mainError, closeError ); } } - - private static void closeConnectionPoolOnThreadInterrupt( ConnectionPool pool, Logging logging ) - { - Logger log = logging.getLog( Driver.class.getSimpleName() ); - log.warn( "Driver creation interrupted while verifying connectivity. Connection pool will be closed" ); - pool.close(); - } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java b/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java index 1e2b934a39..bfe2af94db 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java +++ b/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java @@ -128,11 +128,18 @@ public final TypeSystem defaultTypeSystem() return InternalTypeSystem.TYPE_SYSTEM; } - public CompletionStage verifyConnectivity() + @Override + public CompletionStage verifyConnectivityAsync() { return sessionFactory.verifyConnectivity(); } + @Override + public void verifyConnectivity() + { + Futures.blockingGet( verifyConnectivityAsync() ); + } + /** * Get the underlying session factory. *

diff --git a/driver/src/main/java/org/neo4j/driver/internal/cluster/RediscoveryImpl.java b/driver/src/main/java/org/neo4j/driver/internal/cluster/RediscoveryImpl.java index 8e29ef79d7..1d9449ae7b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/cluster/RediscoveryImpl.java +++ b/driver/src/main/java/org/neo4j/driver/internal/cluster/RediscoveryImpl.java @@ -53,7 +53,7 @@ */ public class RediscoveryImpl implements Rediscovery { - private static final String NO_ROUTERS_AVAILABLE = "Could not perform discovery for database '%s'. No routing servers available."; + private static final String NO_ROUTERS_AVAILABLE = "Could not perform discovery for database '%s'. No routing server available."; private final BoltServerAddress initialRouter; private final RoutingSettings settings; diff --git a/driver/src/main/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancer.java b/driver/src/main/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancer.java index 8eaa099975..c51583e259 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancer.java +++ b/driver/src/main/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancer.java @@ -87,7 +87,19 @@ public CompletionStage acquireConnection( String databaseName, Acces @Override public CompletionStage verifyConnectivity() { - return routingTables.refreshRoutingTable( ABSENT_DB_NAME, AccessMode.READ ).thenApply( ignored -> null ); + return routingTables.refreshRoutingTable( ABSENT_DB_NAME, AccessMode.READ ).handle( ( ignored, error ) -> { + if ( error != null ) + { + Throwable cause = Futures.completionExceptionCause( error ); + if ( cause instanceof ServiceUnavailableException ) + { + throw Futures.asCompletionException( new ServiceUnavailableException( + "Unable to connect to database, ensure the database is running and that there is a working network connection to it.", cause ) ); + } + throw Futures.asCompletionException( cause ); + } + return null; + } ); } @Override diff --git a/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java b/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java index d40974f7ae..91364dd0bd 100644 --- a/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java +++ b/driver/src/test/java/org/neo4j/driver/GraphDatabaseTest.java @@ -32,6 +32,7 @@ import static java.util.Arrays.asList; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.junit.MatcherAssert.assertThat; @@ -60,6 +61,7 @@ void boltSchemeShouldInstantiateDirectDriver() throws Exception // When Driver driver = GraphDatabase.driver( uri, INSECURE_CONFIG ); + driver.verifyConnectivity(); // Then assertThat( driver, is( directDriver() ) ); @@ -78,6 +80,7 @@ void boltPlusDiscoverySchemeShouldInstantiateClusterDriver() throws Exception // When Driver driver = GraphDatabase.driver( uri, INSECURE_CONFIG ); + driver.verifyConnectivity(); // Then assertThat( driver, is( clusterDriver() ) ); @@ -146,9 +149,10 @@ void shouldRespondToInterruptsWhenConnectingToUnresponsiveServer() throws Except // setup other thread to interrupt current thread when it blocks TestUtil.interruptWhenInWaitingState( Thread.currentThread() ); + final Driver driver = GraphDatabase.driver( "bolt://localhost:" + serverSocket.getLocalPort() ); try { - assertThrows( ServiceUnavailableException.class, () -> GraphDatabase.driver( "bolt://localhost:" + serverSocket.getLocalPort() ) ); + assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); } finally { @@ -158,6 +162,33 @@ void shouldRespondToInterruptsWhenConnectingToUnresponsiveServer() throws Except } } + @Test + void shouldPrintNiceErrorWhenConnectingToUnresponsiveServer() throws Exception + { + int localPort = -1; + try ( ServerSocket serverSocket = new ServerSocket( 0 ) ) + { + localPort = serverSocket.getLocalPort(); + } + final Driver driver = GraphDatabase.driver( "bolt://localhost:" + localPort, INSECURE_CONFIG ); + final ServiceUnavailableException error = assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); + assertThat( error.getMessage(), containsString( "Unable to connect to" ) ); + } + + @Test + void shouldPrintNiceRoutingErrorWhenConnectingToUnresponsiveServer() throws Exception + { + int localPort = -1; + try ( ServerSocket serverSocket = new ServerSocket( 0 ) ) + { + localPort = serverSocket.getLocalPort(); + } + final Driver driver = GraphDatabase.driver( "neo4j://localhost:" + localPort, INSECURE_CONFIG ); + final ServiceUnavailableException error = assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); + error.printStackTrace(); + assertThat( error.getMessage(), containsString( "Unable to connect to" ) ); + } + @Test void shouldFailToCreateUnencryptedDriverWhenServerDoesNotRespond() throws IOException { @@ -176,9 +207,9 @@ private static void testFailureWhenServerDoesNotRespond( boolean encrypted ) thr { int connectionTimeoutMillis = 1_000; Config config = createConfig( encrypted, connectionTimeoutMillis ); + final Driver driver = GraphDatabase.driver( URI.create( "bolt://localhost:" + server.getLocalPort() ), config ); - ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, - () -> GraphDatabase.driver( URI.create( "bolt://localhost:" + server.getLocalPort() ), config ) ); + ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); assertEquals( e.getMessage(), "Unable to establish connection in " + connectionTimeoutMillis + "ms" ); } } diff --git a/driver/src/test/java/org/neo4j/driver/integration/CredentialsIT.java b/driver/src/test/java/org/neo4j/driver/integration/CredentialsIT.java index d1768e4748..3e0fa0359a 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/CredentialsIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/CredentialsIT.java @@ -81,11 +81,11 @@ void shouldBePossibleToChangePassword() throws Exception } // verify old password does not work - assertThrows( AuthenticationException.class, - () -> GraphDatabase.driver( neo4j.uri(), AuthTokens.basic( "neo4j", PASSWORD ) ) ); + final Driver badDriver = GraphDatabase.driver( CredentialsIT.neo4j.uri(), basic( "neo4j", PASSWORD ) ); + assertThrows( AuthenticationException.class, badDriver::verifyConnectivity ); // verify new password works - try ( Driver driver = GraphDatabase.driver( neo4j.uri(), AuthTokens.basic( "neo4j", newPassword ) ); + try ( Driver driver = GraphDatabase.driver( CredentialsIT.neo4j.uri(), AuthTokens.basic( "neo4j", newPassword ) ); Session session = driver.session() ) { session.run( "RETURN 2" ).consume(); @@ -177,6 +177,7 @@ private void testDriverFailureOnWrongCredentials( String uri ) Config config = Config.builder().withLogging( DEV_NULL_LOGGING ).build(); AuthToken authToken = AuthTokens.basic( "neo4j", "wrongSecret" ); - assertThrows( AuthenticationException.class, () -> GraphDatabase.driver( uri, authToken, config ) ); + final Driver driver = GraphDatabase.driver( uri, authToken, config ); + assertThrows( AuthenticationException.class, driver::verifyConnectivity ); } } diff --git a/driver/src/test/java/org/neo4j/driver/integration/EncryptionIT.java b/driver/src/test/java/org/neo4j/driver/integration/EncryptionIT.java index 2c9bc16517..eac6b9f009 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/EncryptionIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/EncryptionIT.java @@ -119,7 +119,7 @@ private void testMismatchingEncryption( BoltTlsLevel tlsLevel, boolean driverEnc Config config = newConfig( driverEncrypted ); RuntimeException e = assertThrows( RuntimeException.class, - () -> GraphDatabase.driver( neo4j.uri(), neo4j.authToken(), config ).close() ); + () -> GraphDatabase.driver( neo4j.uri(), neo4j.authToken(), config ).verifyConnectivity() ); // pre 3.1 neo4j throws different exception when encryption required but not used if ( neo4jVersion.lessThan( v3_1_0 ) && tlsLevel == BoltTlsLevel.REQUIRED ) diff --git a/driver/src/test/java/org/neo4j/driver/integration/ErrorIT.java b/driver/src/test/java/org/neo4j/driver/integration/ErrorIT.java index 8537f9c9bb..27b7cfbff0 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/ErrorIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/ErrorIT.java @@ -33,13 +33,6 @@ import java.util.function.Consumer; import java.util.stream.Stream; -import org.neo4j.driver.internal.cluster.RoutingSettings; -import org.neo4j.driver.internal.messaging.response.FailureMessage; -import org.neo4j.driver.internal.retry.RetrySettings; -import org.neo4j.driver.internal.util.io.ChannelTrackingDriverFactory; -import org.neo4j.driver.internal.util.io.ChannelTrackingDriverFactoryWithFailingMessageFormat; -import org.neo4j.driver.internal.util.FailingMessageFormat; -import org.neo4j.driver.internal.util.FakeClock; import org.neo4j.driver.AuthToken; import org.neo4j.driver.Config; import org.neo4j.driver.Driver; @@ -49,6 +42,13 @@ import org.neo4j.driver.Transaction; import org.neo4j.driver.exceptions.ClientException; import org.neo4j.driver.exceptions.ServiceUnavailableException; +import org.neo4j.driver.internal.cluster.RoutingSettings; +import org.neo4j.driver.internal.messaging.response.FailureMessage; +import org.neo4j.driver.internal.retry.RetrySettings; +import org.neo4j.driver.internal.util.FailingMessageFormat; +import org.neo4j.driver.internal.util.FakeClock; +import org.neo4j.driver.internal.util.io.ChannelTrackingDriverFactory; +import org.neo4j.driver.internal.util.io.ChannelTrackingDriverFactoryWithFailingMessageFormat; import org.neo4j.driver.util.ParallelizableIT; import org.neo4j.driver.util.SessionExtension; @@ -143,7 +143,8 @@ void shouldAllowNewTransactionAfterRecoverableError() @Test void shouldExplainConnectionError() { - ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, () -> GraphDatabase.driver( "bolt://localhost:7777" ) ); + final Driver driver = GraphDatabase.driver( "bolt://localhost:7777" ); + ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); assertEquals( "Unable to connect to localhost:7777, ensure the database is running " + "and that there is a working network connection to it.", e.getMessage() ); @@ -179,7 +180,8 @@ void shouldGetHelpfulErrorWhenTryingToConnectToHttpPort() throws Throwable Config config = Config.builder().withoutEncryption().build(); - ClientException e = assertThrows( ClientException.class, () -> GraphDatabase.driver( "bolt://localhost:" + session.httpPort(), config ) ); + final Driver driver = GraphDatabase.driver( "bolt://localhost:" + session.httpPort(), config ); + ClientException e = assertThrows( ClientException.class, driver::verifyConnectivity ); assertEquals( "Server responded HTTP. Make sure you are not trying to connect to the http endpoint " + "(HTTP defaults to port 7474 whereas BOLT defaults to port 7687)", e.getMessage() ); } @@ -264,25 +266,29 @@ private Throwable testChannelErrorHandling( Consumer messa Config config = Config.builder().withLogging( DEV_NULL_LOGGING ).build(); Throwable queryError = null; - try ( Driver driver = driverFactory.newInstance( uri, authToken, routingSettings, retrySettings, config ); - Session session = driver.session() ) + try ( Driver driver = driverFactory.newInstance( uri, authToken, routingSettings, retrySettings, config ) ) { - messageFormatSetup.accept( driverFactory.getFailingMessageFormat() ); - - try + driver.verifyConnectivity(); + try(Session session = driver.session() ) { - session.run( "RETURN 1" ).consume(); - fail( "Exception expected" ); + messageFormatSetup.accept( driverFactory.getFailingMessageFormat() ); + + try + { + session.run( "RETURN 1" ).consume(); + fail( "Exception expected" ); + } + catch ( Throwable error ) + { + queryError = error; + } + + assertSingleChannelIsClosed( driverFactory ); + assertNewQueryCanBeExecuted( session, driverFactory ); } - catch ( Throwable error ) - { - queryError = error; - } - - assertSingleChannelIsClosed( driverFactory ); - assertNewQueryCanBeExecuted( session, driverFactory ); } + return queryError; } diff --git a/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitTest.java b/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitTest.java index 3825dae2fe..6b4f329925 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitTest.java +++ b/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitTest.java @@ -209,7 +209,7 @@ void shouldThrowSessionExpiredIfReadServerDisappears() throws IOException, Inter StubServer server = StubServer.start( "acquire_endpoints_v3.script", 9001 ); //START a read server - StubServer.start( "dead_read_server.script", 9005 ); + final StubServer readServer = StubServer.start( "dead_read_server.script", 9005 ); URI uri = URI.create( "neo4j://127.0.0.1:9001" ); //Expect @@ -221,6 +221,7 @@ void shouldThrowSessionExpiredIfReadServerDisappears() throws IOException, Inter } } ); assertThat( server.exitStatus(), equalTo( 0 ) ); + assertThat( readServer.exitStatus(), equalTo( 0 ) ); } @Test @@ -230,7 +231,7 @@ void shouldThrowSessionExpiredIfReadServerDisappearsWhenUsingTransaction() throw StubServer server = StubServer.start( "acquire_endpoints_v3.script", 9001 ); //START a read server - StubServer.start( "dead_read_server.script", 9005 ); + final StubServer readServer = StubServer.start( "dead_read_server_tx.script", 9005 ); URI uri = URI.create( "neo4j://127.0.0.1:9001" ); //Expect @@ -245,6 +246,7 @@ void shouldThrowSessionExpiredIfReadServerDisappearsWhenUsingTransaction() throw } ); assertEquals( "Server at 127.0.0.1:9005 is no longer available", e.getMessage() ); assertThat( server.exitStatus(), equalTo( 0 ) ); + assertThat( readServer.exitStatus(), equalTo( 0 ) ); } @Test @@ -253,19 +255,20 @@ void shouldThrowSessionExpiredIfWriteServerDisappears() throws IOException, Inte // Given StubServer server = StubServer.start( "acquire_endpoints_v3.script", 9001 ); - //START a dead write servers - StubServer.start( "dead_read_server.script", 9007 ); + //START a dead write server + final StubServer writeServer = StubServer.start( "dead_write_server.script", 9007 ); URI uri = URI.create( "neo4j://127.0.0.1:9001" ); //Expect try ( Driver driver = GraphDatabase.driver( uri, INSECURE_CONFIG ); Session session = driver.session( builder().withDefaultAccessMode( AccessMode.WRITE ).build() ) ) { - assertThrows( SessionExpiredException.class, () -> session.run( "MATCH (n) RETURN n.name" ).consume() ); + assertThrows( SessionExpiredException.class, () -> session.run( "CREATE (n {name:'Bob'})" ).consume() ); } finally { assertThat( server.exitStatus(), equalTo( 0 ) ); + assertThat( writeServer.exitStatus(), equalTo( 0 ) ); } } @@ -276,7 +279,7 @@ void shouldThrowSessionExpiredIfWriteServerDisappearsWhenUsingTransaction() thro StubServer server = StubServer.start( "acquire_endpoints_v3.script", 9001 ); //START a dead write servers - StubServer.start( "dead_read_server.script", 9007 ); + final StubServer writeServer = StubServer.start( "dead_read_server_tx.script", 9007 ); URI uri = URI.create( "neo4j://127.0.0.1:9001" ); //Expect @@ -290,6 +293,7 @@ void shouldThrowSessionExpiredIfWriteServerDisappearsWhenUsingTransaction() thro finally { assertThat( server.exitStatus(), equalTo( 0 ) ); + assertThat( writeServer.exitStatus(), equalTo( 0 ) ); } } @@ -410,9 +414,10 @@ void shouldFailOnNonDiscoverableServer() throws IOException, InterruptedExceptio // Given StubServer.start( "discover_not_supported.script", 9001 ); URI uri = URI.create( "neo4j://127.0.0.1:9001" ); + final Driver driver = GraphDatabase.driver( uri, INSECURE_CONFIG ); //Expect - assertThrows( ServiceUnavailableException.class, () -> GraphDatabase.driver( uri, INSECURE_CONFIG ) ); + assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); } @Test @@ -421,9 +426,10 @@ void shouldFailRandomFailureInGetServers() throws IOException, InterruptedExcept // Given StubServer.start( "discover_failed.script", 9001 ); URI uri = URI.create( "neo4j://127.0.0.1:9001" ); + final Driver driver = GraphDatabase.driver( uri, INSECURE_CONFIG ); //Expect - assertThrows( ServiceUnavailableException.class, () -> GraphDatabase.driver( uri, INSECURE_CONFIG ) ); + assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); } @Test @@ -612,7 +618,7 @@ void shouldPassBookmarkFromTransactionToTransaction() throws Exception void shouldRetryReadTransactionUntilSuccess() throws Exception { StubServer router = StubServer.start( "acquire_endpoints_v3.script", 9001 ); - StubServer brokenReader = StubServer.start( "dead_read_server.script", 9005 ); + StubServer brokenReader = StubServer.start( "dead_read_server_tx.script", 9005 ); StubServer reader = StubServer.start( "read_server_v3_read_tx.script", 9006 ); try ( Driver driver = newDriverWithSleeplessClock( "neo4j://127.0.0.1:9001" ); Session session = driver.session() ) @@ -727,10 +733,11 @@ void shouldRetryWriteTransactionUntilSuccessWithWhenLeaderIsRemovedV3() throws E void shouldRetryReadTransactionUntilFailure() throws Exception { StubServer router = StubServer.start( "acquire_endpoints_v3.script", 9001 ); - StubServer brokenReader1 = StubServer.start( "dead_read_server.script", 9005 ); - StubServer brokenReader2 = StubServer.start( "dead_read_server.script", 9006 ); + StubServer brokenReader1 = StubServer.start( "dead_read_server_tx.script", 9005 ); + StubServer brokenReader2 = StubServer.start( "dead_read_server_tx.script", 9006 ); - try ( Driver driver = newDriverWithFixedRetries( "neo4j://127.0.0.1:9001", 1 ); Session session = driver.session() ) + try ( Driver driver = newDriverWithFixedRetries( "neo4j://127.0.0.1:9001", 1 ); + Session session = driver.session() ) { AtomicInteger invocations = new AtomicInteger(); assertThrows( SessionExpiredException.class, () -> session.readTransaction( queryWork( "MATCH (n) RETURN n.name", invocations ) ) ); @@ -769,8 +776,8 @@ void shouldRetryWriteTransactionUntilFailure() throws Exception void shouldRetryReadTransactionAndPerformRediscoveryUntilSuccess() throws Exception { StubServer router1 = StubServer.start( "acquire_endpoints_v3.script", 9010 ); - StubServer brokenReader1 = StubServer.start( "dead_read_server.script", 9005 ); - StubServer brokenReader2 = StubServer.start( "dead_read_server.script", 9006 ); + StubServer brokenReader1 = StubServer.start( "dead_read_server_tx.script", 9005 ); + StubServer brokenReader2 = StubServer.start( "dead_read_server_tx.script", 9006 ); StubServer router2 = StubServer.start( "discover_servers.script", 9003 ); StubServer reader = StubServer.start( "read_server_v3_read_tx.script", 9004 ); @@ -827,6 +834,7 @@ void shouldUseInitialRouterForRediscoveryWhenAllOtherRoutersAreDead() throws Exc try ( Driver driver = GraphDatabase.driver( "neo4j://127.0.0.1:9010", INSECURE_CONFIG ) ) { + driver.verifyConnectivity(); try ( Session session = driver.session( builder().withDefaultAccessMode( AccessMode.READ ).build() ) ) { // restart router on the same port with different script that contains itself as reader @@ -913,15 +921,19 @@ void shouldAcceptRoutingTableWithoutWritersAndThenRediscover() throws Exception StubServer reader = StubServer.start( "read_server_v3_read_tx.script", 9003 ); StubServer writer = StubServer.start( "write_with_bookmarks.script", 9007 ); - try ( Driver driver = GraphDatabase.driver( "neo4j://127.0.0.1:9010", INSECURE_CONFIG ); Session session = driver.session() ) + try ( Driver driver = GraphDatabase.driver( "neo4j://127.0.0.1:9010", INSECURE_CONFIG ) ) { - // start another router which knows about writes, use same address as the initial router - router2 = StubServer.start( "acquire_endpoints_v3.script", 9010 ); + driver.verifyConnectivity(); + try ( Session session = driver.session() ) + { + // start another router which knows about writes, use same address as the initial router + router2 = StubServer.start( "acquire_endpoints_v3.script", 9010 ); - assertEquals( asList( "Bob", "Alice", "Tina" ), readStrings( "MATCH (n) RETURN n.name", session ) ); + assertEquals( asList( "Bob", "Alice", "Tina" ), readStrings( "MATCH (n) RETURN n.name", session ) ); - StatementResult createResult = session.run( "CREATE (n {name:'Bob'})" ); - assertFalse( createResult.hasNext() ); + StatementResult createResult = session.run( "CREATE (n {name:'Bob'})" ); + assertFalse( createResult.hasNext() ); + } } finally { @@ -1026,8 +1038,9 @@ void shouldFailInitialDiscoveryWhenConfiguredResolverThrows() when( resolver.resolve( any( ServerAddress.class ) ) ).thenThrow( new RuntimeException( "Resolution failure!" ) ); Config config = insecureBuilder().withResolver( resolver ).build(); + final Driver driver = GraphDatabase.driver( "neo4j://my.server.com:9001", config ); - RuntimeException error = assertThrows( RuntimeException.class, () -> GraphDatabase.driver( "neo4j://my.server.com:9001", config ) ); + RuntimeException error = assertThrows( RuntimeException.class, driver::verifyConnectivity ); assertEquals( "Resolution failure!", error.getMessage() ); verify( resolver ).resolve( ServerAddress.of( "my.server.com", 9001 ) ); } diff --git a/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverMultidatabaseBoltKitTest.java b/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverMultidatabaseBoltKitTest.java index 39898f4b3c..35aeee5461 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverMultidatabaseBoltKitTest.java +++ b/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverMultidatabaseBoltKitTest.java @@ -30,6 +30,7 @@ import org.neo4j.driver.Config; import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Record; import org.neo4j.driver.Session; import org.neo4j.driver.exceptions.FatalDiscoveryException; import org.neo4j.driver.exceptions.ServiceUnavailableException; @@ -42,6 +43,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.junit.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.neo4j.driver.internal.SessionConfig.builder; import static org.neo4j.driver.util.StubServer.INSECURE_CONFIG; @@ -80,7 +82,7 @@ void shouldRetryOnEmptyDiscoveryResult() throws IOException, InterruptedExceptio }; StubServer emptyRouter = StubServer.start( "acquire_endpoints_v4_empty.script", 9001 ); - StubServer realRouter = StubServer.start( "acquire_endpoints_v4_with_db.script", 9002 ); + StubServer realRouter = StubServer.start( "acquire_endpoints_v4.script", 9002 ); StubServer reader = StubServer.start( "read_server_v4_read.script", 9005 ); Config config = insecureBuilder().withResolver( resolver ).build(); @@ -148,4 +150,34 @@ void shouldBeAbleToServeReachableDatabase() throws IOException, InterruptedExcep assertThat( router.exitStatus(), equalTo( 0 ) ); assertThat( readServer.exitStatus(), equalTo( 0 ) ); } + + + @Test + void shouldVerifyConnectivityOnDriverCreation() throws Throwable + { + StubServer router = StubServer.start( "acquire_endpoints_v4_verify_connectivity.script", 9001 ); + StubServer readServer = StubServer.start( "read_server_v4_read.script", 9005 ); + + URI uri = URI.create( "neo4j://127.0.0.1:9001" ); + try ( Driver driver = GraphDatabase.driver( uri, INSECURE_CONFIG ) ) + { + driver.verifyConnectivity(); + try ( Session session = driver.session( builder().withDatabase( "myDatabase" ).withDefaultAccessMode( AccessMode.READ ).build() ) ) + { + List records = session.run( "MATCH (n) RETURN n.name" ).list(); + assertEquals( 3, records.size() ); + } + + Session session = driver.session( builder().withDefaultAccessMode( AccessMode.READ ).build() ); + + driver.close(); + + assertThrows( IllegalStateException.class, () -> session.run( "MATCH (n) RETURN n.name" ) ); + } + finally + { + assertEquals( 0, readServer.exitStatus() ); + assertEquals( 0, router.exitStatus() ); + } + } } diff --git a/driver/src/test/java/org/neo4j/driver/integration/SessionIT.java b/driver/src/test/java/org/neo4j/driver/integration/SessionIT.java index e9f37ccfbe..0d502cdf19 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/SessionIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/SessionIT.java @@ -154,7 +154,7 @@ void shouldHandleNullAuthToken() // null auth token should be interpreted as AuthTokens.none() and fail driver creation // because server expects basic auth - assertThrows( AuthenticationException.class, () -> GraphDatabase.driver( neo4j.uri(), token ) ); + assertThrows( AuthenticationException.class, () -> GraphDatabase.driver( neo4j.uri(), token ).verifyConnectivity() ); } @Test @@ -1293,7 +1293,7 @@ void shouldErrorDatabaseWhenDatabaseIsAbsent() throws Throwable result.consume(); } ); - assertThat( error.getMessage(), containsString( "Database does not exists. Database name: 'foo'" ) ); + assertThat( error.getMessage(), containsString( "Database does not exist. Database name: 'foo'" ) ); session.close(); } @@ -1310,7 +1310,7 @@ void shouldErrorDatabaseNameUsingTxWhenDatabaseIsAbsent() throws Throwable StatementResult result = transaction.run( "RETURN 1" ); result.consume(); }); - assertThat( error.getMessage(), containsString( "Database does not exists. Database name: 'foo'" ) ); + assertThat( error.getMessage(), containsString( "Database does not exist. Database name: 'foo'" ) ); session.close(); } @@ -1325,7 +1325,7 @@ void shouldErrorDatabaseNameUsingTxWithRetriesWhenDatabaseIsAbsent() throws Thro ClientException error = assertThrows( ClientException.class, () -> { session.readTransaction( tx -> tx.run( "RETURN 1" ).consume() ); }); - assertThat( error.getMessage(), containsString( "Database does not exists. Database name: 'foo'" ) ); + assertThat( error.getMessage(), containsString( "Database does not exist. Database name: 'foo'" ) ); session.close(); } diff --git a/driver/src/test/java/org/neo4j/driver/integration/TrustCustomCertificateIT.java b/driver/src/test/java/org/neo4j/driver/integration/TrustCustomCertificateIT.java index cab213a607..f15e4387aa 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/TrustCustomCertificateIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/TrustCustomCertificateIT.java @@ -75,7 +75,8 @@ void shouldRejectServerWithUntrustedCertificate() throws Throwable CertificateKeyPair certificateAndKey = createNewCertificateAndKey(); // When & Then - SecurityException error = assertThrows( SecurityException.class, () -> createDriverWithCustomCertificate( certificateAndKey.cert() ) ); + final Driver driver = createDriverWithCustomCertificate( certificateAndKey.cert() ); + SecurityException error = assertThrows( SecurityException.class, driver::verifyConnectivity ); } private void shouldBeAbleToRunCypher( Supplier driverSupplier ) diff --git a/driver/src/test/java/org/neo4j/driver/integration/TrustOnFirstUseIT.java b/driver/src/test/java/org/neo4j/driver/integration/TrustOnFirstUseIT.java index 164d99bba3..3446841ebf 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/TrustOnFirstUseIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/TrustOnFirstUseIT.java @@ -114,7 +114,8 @@ private Driver createDriverWithKnownHostsFile( File knownHostsFile ) private void shouldFailToRunCypherWithAMeaningfulError( Supplier driverSupplier ) { - SecurityException exception = assertThrows( SecurityException.class, driverSupplier::get ); + final Driver driver = driverSupplier.get(); + SecurityException exception = assertThrows( SecurityException.class, driver::verifyConnectivity ); Throwable rootCause = getRootCause( exception ); assertThat( rootCause.toString(), containsString( "Unable to connect to neo4j at `localhost:" + neo4j.boltPort() + "`, " + diff --git a/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java b/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java index ae1135e95f..a2b7189994 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/DriverFactoryTest.java @@ -31,9 +31,8 @@ import org.neo4j.driver.AuthTokens; import org.neo4j.driver.Config; import org.neo4j.driver.Driver; -import org.neo4j.driver.exceptions.ServiceUnavailableException; -import org.neo4j.driver.internal.async.NetworkSession; import org.neo4j.driver.internal.async.LeakLoggingNetworkSession; +import org.neo4j.driver.internal.async.NetworkSession; import org.neo4j.driver.internal.async.connection.BootstrapFactory; import org.neo4j.driver.internal.cluster.RoutingSettings; import org.neo4j.driver.internal.cluster.loadbalancing.LoadBalancer; @@ -52,11 +51,11 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.junit.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.neo4j.driver.Config.defaultConfig; @@ -126,7 +125,7 @@ void usesLeakLoggingSessionFactoryWhenConfigured( String uri ) @ParameterizedTest @MethodSource( "testUris" ) - void shouldVerifyConnectivity( String uri ) + void shouldNotVerifyConnectivity( String uri ) { SessionFactory sessionFactory = mock( SessionFactory.class ); when( sessionFactory.verifyConnectivity() ).thenReturn( completedWithNull() ); @@ -136,24 +135,10 @@ void shouldVerifyConnectivity( String uri ) try ( Driver driver = createDriver( uri, driverFactory ) ) { assertNotNull( driver ); - verify( sessionFactory ).verifyConnectivity(); + verify( sessionFactory, never() ).verifyConnectivity(); } } - @ParameterizedTest - @MethodSource( "testUris" ) - void shouldThrowWhenUnableToVerifyConnectivity( String uri ) - { - SessionFactory sessionFactory = mock( SessionFactory.class ); - ServiceUnavailableException error = new ServiceUnavailableException( "Hello" ); - when( sessionFactory.verifyConnectivity() ).thenReturn( failedFuture( error ) ); - when( sessionFactory.close() ).thenReturn( completedWithNull() ); - DriverFactoryWithSessions driverFactory = new DriverFactoryWithSessions( sessionFactory ); - - ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, () -> createDriver( uri, driverFactory ) ); - assertEquals( e.getMessage(), "Hello" ); - } - @Test void shouldNotCreateDriverMetrics() { @@ -237,7 +222,7 @@ private static class SessionFactoryCapturingDriverFactory extends DriverFactory protected InternalDriver createDriver( SecurityPlan securityPlan, SessionFactory sessionFactory, MetricsProvider metricsProvider, Config config ) { InternalDriver driver = mock( InternalDriver.class ); - when( driver.verifyConnectivity() ).thenReturn( completedWithNull() ); + when( driver.verifyConnectivityAsync() ).thenReturn( completedWithNull() ); return driver; } diff --git a/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java b/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java index 90048b83d7..28dae12505 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/InternalDriverTest.java @@ -22,13 +22,14 @@ import java.util.concurrent.CompletableFuture; +import org.neo4j.driver.Config; +import org.neo4j.driver.Metrics; +import org.neo4j.driver.exceptions.ClientException; +import org.neo4j.driver.exceptions.ServiceUnavailableException; import org.neo4j.driver.internal.metrics.InternalMetrics; import org.neo4j.driver.internal.metrics.MetricsProvider; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.internal.util.Clock; -import org.neo4j.driver.Config; -import org.neo4j.driver.Metrics; -import org.neo4j.driver.exceptions.ClientException; import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -40,6 +41,7 @@ import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING; import static org.neo4j.driver.internal.metrics.MetricsProvider.METRICS_DISABLED_PROVIDER; import static org.neo4j.driver.internal.util.Futures.completedWithNull; +import static org.neo4j.driver.internal.util.Futures.failedFuture; import static org.neo4j.driver.util.TestUtil.await; class InternalDriverTest @@ -76,7 +78,19 @@ void shouldVerifyConnectivity() InternalDriver driver = newDriver( sessionFactory ); - assertEquals( connectivityStage, driver.verifyConnectivity() ); + assertEquals( connectivityStage, driver.verifyConnectivityAsync() ); + } + + @Test + void shouldThrowWhenUnableToVerifyConnectivity() + { + SessionFactory sessionFactory = mock( SessionFactory.class ); + ServiceUnavailableException error = new ServiceUnavailableException( "Hello" ); + when( sessionFactory.verifyConnectivity() ).thenReturn( failedFuture( error ) ); + InternalDriver driver = newDriver( sessionFactory ); + + ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, () -> await( driver.verifyConnectivityAsync() ) ); + assertEquals( e.getMessage(), "Hello" ); } @Test diff --git a/driver/src/test/java/org/neo4j/driver/internal/TrustedServerProductTest.java b/driver/src/test/java/org/neo4j/driver/internal/TrustedServerProductTest.java index ed23af0092..cca815ce31 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/TrustedServerProductTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/TrustedServerProductTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test; import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; import org.neo4j.driver.exceptions.UntrustedServerException; import org.neo4j.driver.util.StubServer; @@ -42,7 +43,8 @@ class TrustedServerProductTest void shouldRejectConnectionsToNonNeo4jServers() throws Exception { StubServer server = StubServer.start( "untrusted_server.script", 9001 ); - assertThrows( UntrustedServerException.class, () -> GraphDatabase.driver( "bolt://127.0.0.1:9001", config )); + final Driver driver = GraphDatabase.driver( "bolt://127.0.0.1:9001", config ); + assertThrows( UntrustedServerException.class, driver::verifyConnectivity ); assertThat( server.exitStatus(), equalTo( 0 ) ); } diff --git a/driver/src/test/java/org/neo4j/driver/stress/CausalClusteringIT.java b/driver/src/test/java/org/neo4j/driver/stress/CausalClusteringIT.java index 107034845e..fd2928aa6d 100644 --- a/driver/src/test/java/org/neo4j/driver/stress/CausalClusteringIT.java +++ b/driver/src/test/java/org/neo4j/driver/stress/CausalClusteringIT.java @@ -167,8 +167,9 @@ void sessionCreationShouldFailIfCallingDiscoveryProcedureOnEdgeServer() Cluster cluster = clusterRule.getCluster(); ClusterMember readReplica = cluster.anyReadReplica(); - ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, () -> createDriver( readReplica.getRoutingUri() ) ); - assertThat( e.getMessage(), containsString( "Could not perform discovery" ) ); + final Driver driver = createDriver( readReplica.getRoutingUri() ); + ServiceUnavailableException e = assertThrows( ServiceUnavailableException.class, driver::verifyConnectivity ); + assertThat( e.getMessage(), containsString( "Unable to connect to database" ) ); } // Ensure that Bookmarks work with single instances using a driver created using a bolt[not+routing] URI. diff --git a/driver/src/test/java/org/neo4j/driver/stress/FailedAuth.java b/driver/src/test/java/org/neo4j/driver/stress/FailedAuth.java index 692f815f2a..6f884716f3 100644 --- a/driver/src/test/java/org/neo4j/driver/stress/FailedAuth.java +++ b/driver/src/test/java/org/neo4j/driver/stress/FailedAuth.java @@ -21,6 +21,7 @@ import java.net.URI; import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; import org.neo4j.driver.Logging; import org.neo4j.driver.exceptions.SecurityException; @@ -46,8 +47,9 @@ public void execute( C context ) { Config config = Config.builder().withLogging( logging ).build(); - SecurityException e = assertThrows( SecurityException.class, - () -> GraphDatabase.driver( clusterUri, basic( "wrongUsername", "wrongPassword" ), config ) ); + final Driver driver = GraphDatabase.driver( clusterUri, basic( "wrongUsername", "wrongPassword" ), config ); + SecurityException e = assertThrows( SecurityException.class, driver::verifyConnectivity ); assertThat( e.getMessage(), containsString( "authentication failure" ) ); + driver.close(); } } diff --git a/driver/src/test/resources/acquire_endpoints_v4.script b/driver/src/test/resources/acquire_endpoints_v4.script index f9fa055f14..cece16f684 100644 --- a/driver/src/test/resources/acquire_endpoints_v4.script +++ b/driver/src/test/resources/acquire_endpoints_v4.script @@ -3,11 +3,6 @@ !: AUTO HELLO !: AUTO GOODBYE -C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": null} {"mode": "r", "db": "system"} - PULL {"n": -1} -S: SUCCESS {"fields": ["ttl", "servers"]} - RECORD [9223372036854775807, [{"addresses": ["127.0.0.1:9007","127.0.0.1:9008"],"role": "WRITE"}, {"addresses": ["127.0.0.1:9005","127.0.0.1:9006"], "role": "READ"},{"addresses": ["127.0.0.1:9001","127.0.0.1:9002","127.0.0.1:9003"], "role": "ROUTE"}]] - SUCCESS {} C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "myDatabase"} {"mode": "r", "db": "system"} PULL {"n": -1} S: SUCCESS {"fields": ["ttl", "servers"]} diff --git a/driver/src/test/resources/acquire_endpoints_v4_database_not_found.script b/driver/src/test/resources/acquire_endpoints_v4_database_not_found.script index 91bd577d5f..29e8e0ba5e 100644 --- a/driver/src/test/resources/acquire_endpoints_v4_database_not_found.script +++ b/driver/src/test/resources/acquire_endpoints_v4_database_not_found.script @@ -3,11 +3,6 @@ !: AUTO HELLO !: AUTO GOODBYE -C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": null} {"mode": "r", "db": "system"} - PULL {"n": -1} -S: SUCCESS {"fields": ["ttl", "servers"]} - RECORD [9223372036854775807, [{"addresses": ["127.0.0.1:9007","127.0.0.1:9008"],"role": "WRITE"}, {"addresses": ["127.0.0.1:9005","127.0.0.1:9006"], "role": "READ"},{"addresses": ["127.0.0.1:9001","127.0.0.1:9002","127.0.0.1:9003"], "role": "ROUTE"}]] - SUCCESS {} C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "myDatabase"} {"mode": "r", "db": "system"} PULL {"n": -1} S: FAILURE {"code": "Neo.ClientError.Database.DatabaseNotFound", "message": "wut!"} diff --git a/driver/src/test/resources/acquire_endpoints_v4_empty.script b/driver/src/test/resources/acquire_endpoints_v4_empty.script index b28c19fe62..3bafae3745 100644 --- a/driver/src/test/resources/acquire_endpoints_v4_empty.script +++ b/driver/src/test/resources/acquire_endpoints_v4_empty.script @@ -3,11 +3,6 @@ !: AUTO HELLO !: AUTO GOODBYE -C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": null} {"mode": "r", "db": "system"} - PULL {"n": -1} -S: SUCCESS {"fields": ["ttl", "servers"]} - RECORD [9223372036854775807, [{"addresses": ["127.0.0.1:9007","127.0.0.1:9008"],"role": "WRITE"}, {"addresses": ["127.0.0.1:9005","127.0.0.1:9006"], "role": "READ"},{"addresses": ["127.0.0.1:9001","127.0.0.1:9002","127.0.0.1:9003"], "role": "ROUTE"}]] - SUCCESS {} C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "myDatabase"} {"mode": "r", "db": "system"} PULL {"n": -1} S: SUCCESS {"fields": ["ttl", "servers"]} diff --git a/driver/src/test/resources/acquire_endpoints_v4_multi_db.script b/driver/src/test/resources/acquire_endpoints_v4_multi_db.script index ac516aecc0..5b29ec5d7b 100644 --- a/driver/src/test/resources/acquire_endpoints_v4_multi_db.script +++ b/driver/src/test/resources/acquire_endpoints_v4_multi_db.script @@ -3,11 +3,6 @@ !: AUTO HELLO !: AUTO GOODBYE -C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": null} {"mode": "r", "db": "system"} - PULL {"n": -1} -S: SUCCESS {"fields": ["ttl", "servers"]} - RECORD [9223372036854775807, [{"addresses": ["127.0.0.1:9007","127.0.0.1:9008"],"role": "WRITE"}, {"addresses": ["127.0.0.1:9005","127.0.0.1:9006"], "role": "READ"},{"addresses": ["127.0.0.1:9001","127.0.0.1:9002","127.0.0.1:9003"], "role": "ROUTE"}]] - SUCCESS {} C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "Unreachable"} {"mode": "r", "db": "system"} PULL {"n": -1} S: SUCCESS {"fields": ["ttl", "servers"]} diff --git a/driver/src/test/resources/acquire_endpoints_v4_with_db.script b/driver/src/test/resources/acquire_endpoints_v4_verify_connectivity.script similarity index 53% rename from driver/src/test/resources/acquire_endpoints_v4_with_db.script rename to driver/src/test/resources/acquire_endpoints_v4_verify_connectivity.script index cece16f684..f9fa055f14 100644 --- a/driver/src/test/resources/acquire_endpoints_v4_with_db.script +++ b/driver/src/test/resources/acquire_endpoints_v4_verify_connectivity.script @@ -3,6 +3,11 @@ !: AUTO HELLO !: AUTO GOODBYE +C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": null} {"mode": "r", "db": "system"} + PULL {"n": -1} +S: SUCCESS {"fields": ["ttl", "servers"]} + RECORD [9223372036854775807, [{"addresses": ["127.0.0.1:9007","127.0.0.1:9008"],"role": "WRITE"}, {"addresses": ["127.0.0.1:9005","127.0.0.1:9006"], "role": "READ"},{"addresses": ["127.0.0.1:9001","127.0.0.1:9002","127.0.0.1:9003"], "role": "ROUTE"}]] + SUCCESS {} C: RUN "CALL dbms.routing.getRoutingTable($context, $database)" {"context": {}, "database": "myDatabase"} {"mode": "r", "db": "system"} PULL {"n": -1} S: SUCCESS {"fields": ["ttl", "servers"]} diff --git a/driver/src/test/resources/database_shutdown.script b/driver/src/test/resources/database_shutdown.script index ec565687d3..9d315be683 100644 --- a/driver/src/test/resources/database_shutdown.script +++ b/driver/src/test/resources/database_shutdown.script @@ -3,8 +3,6 @@ !: AUTO HELLO !: AUTO GOODBYE -C: RESET -S: SUCCESS {} C: BEGIN {"bookmarks": ["neo4j:bookmark:v1:tx0"]} S: SUCCESS {} C: RUN "RETURN 1" {} {} diff --git a/driver/src/test/resources/dead_read_server.script b/driver/src/test/resources/dead_read_server.script index 0451d49776..186d3d81fb 100644 --- a/driver/src/test/resources/dead_read_server.script +++ b/driver/src/test/resources/dead_read_server.script @@ -2,8 +2,7 @@ !: AUTO RESET !: AUTO HELLO !: AUTO GOODBYE -!: AUTO BEGIN -C: RUN "MATCH (n) RETURN n.name" {} {} +C: RUN "MATCH (n) RETURN n.name" {} {"mode": "r"} C: PULL_ALL S: