From 2ac65635da333cb8a5cd784ab7bcf21cfe3a20ba Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov <11927660+injectives@users.noreply.github.com> Date: Fri, 20 Aug 2021 16:54:56 +0100 Subject: [PATCH 1/5] Add support for Resolver and DomainNameResolver to async Testkit backend (#992) --- .../org/testkit/backend/TestkitState.java | 20 +++++-- .../TestkitRequestProcessorHandler.java | 34 +++++++----- .../DomainNameResolutionCompleted.java | 37 ++----------- .../backend/messages/requests/NewDriver.java | 54 ++++++++++++++++--- .../requests/ResolverResolutionCompleted.java | 22 ++------ .../backend/messages/requests/StartTest.java | 8 +-- .../requests/TestkitCallbackResult.java | 49 +++++++++++++++++ .../DomainNameResolutionRequired.java | 8 ++- .../responses/ResolverResolutionRequired.java | 8 ++- .../messages/responses/TestkitCallback.java | 30 +++++++++++ 10 files changed, 183 insertions(+), 87 deletions(-) create mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java create mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitCallback.java diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java index 2d14850180..07850519e4 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java @@ -19,12 +19,14 @@ package neo4j.org.testkit.backend; import lombok.Getter; +import neo4j.org.testkit.backend.messages.requests.TestkitCallbackResult; +import neo4j.org.testkit.backend.messages.responses.TestkitCallback; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.net.InetAddress; import java.util.HashMap; import java.util.Map; -import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.function.Consumer; import java.util.function.Supplier; @@ -35,7 +37,6 @@ import org.neo4j.driver.async.ResultCursor; import org.neo4j.driver.exceptions.Neo4jException; import org.neo4j.driver.internal.cluster.RoutingTableRegistry; -import org.neo4j.driver.net.ServerAddress; @Getter public class TestkitState @@ -52,8 +53,7 @@ public class TestkitState private int idGenerator = 0; private final Consumer responseWriter; private final Supplier processor; - private final Map> idToServerAddresses = new HashMap<>(); - private final Map idToResolvedAddresses = new HashMap<>(); + private final Map> callbackIdToFuture = new HashMap<>(); public TestkitState( Consumer responseWriter, Supplier processor ) { @@ -61,6 +61,16 @@ public TestkitState( Consumer responseWriter, Supplier this.processor = processor; } + public CompletionStage dispatchTestkitCallback( TestkitCallback response ) + { + CompletableFuture future = new CompletableFuture<>(); + callbackIdToFuture.put( response.getCallbackId(), future ); + responseWriter.accept( response ); + // This is required for sync backend, but should be removed during migration to Netty implementation. + processor.get(); + return future; + } + public String newId() { return String.valueOf( idGenerator++ ); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java index ccac59c4fb..2a9e188148 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java @@ -27,6 +27,7 @@ import neo4j.org.testkit.backend.messages.responses.DriverError; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import org.neo4j.driver.exceptions.Neo4jException; @@ -49,20 +50,25 @@ public void channelRegistered( ChannelHandlerContext ctx ) throws Exception public void channelRead( ChannelHandlerContext ctx, Object msg ) { TestkitRequest testkitRequest = (TestkitRequest) msg; - try - { - testkitRequest.processAsync( testkitState ) - .thenAccept( responseOpt -> responseOpt.ifPresent( ctx::writeAndFlush ) ) - .exceptionally( throwable -> - { - ctx.writeAndFlush( createErrorResponse( throwable ) ); - return null; - } ); - } - catch ( Throwable throwable ) - { - ctx.writeAndFlush( createErrorResponse( throwable ) ); - } + // Processing is done in a separate thread to avoid blocking EventLoop because some testing logic, like resolvers support, is blocking. + CompletableFuture.runAsync( + () -> + { + try + { + testkitRequest.processAsync( testkitState ) + .thenAccept( responseOpt -> responseOpt.ifPresent( ctx::writeAndFlush ) ) + .exceptionally( throwable -> + { + ctx.writeAndFlush( createErrorResponse( throwable ) ); + return null; + } ); + } + catch ( Throwable throwable ) + { + ctx.writeAndFlush( createErrorResponse( throwable ) ); + } + } ); } private TestkitResponse createErrorResponse( Throwable throwable ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java index cde9a111b3..7878fa749a 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java @@ -21,55 +21,26 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import neo4j.org.testkit.backend.TestkitState; -import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletionStage; @Setter @Getter @NoArgsConstructor -public class DomainNameResolutionCompleted implements TestkitRequest +public class DomainNameResolutionCompleted implements TestkitCallbackResult { private DomainNameResolutionCompletedBody data; @Override - public TestkitResponse process( TestkitState testkitState ) + public String getCallbackId() { - testkitState.getIdToResolvedAddresses().put( - data.getRequestId(), - data.getAddresses() - .stream() - .map( - addr -> - { - try - { - return InetAddress.getByName( addr ); - } - catch ( UnknownHostException e ) - { - throw new RuntimeException( e ); - } - } ) - .toArray( InetAddress[]::new ) ); - return null; - } - - @Override - public CompletionStage> processAsync( TestkitState testkitState ) - { - throw new UnsupportedOperationException(); + return data.getRequestId(); } @Setter @Getter @NoArgsConstructor - private static class DomainNameResolutionCompletedBody + public static class DomainNameResolutionCompletedBody { private String requestId; private List addresses; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java index 86ab421d19..51890a6f74 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java @@ -30,15 +30,20 @@ import neo4j.org.testkit.backend.messages.responses.ResolverResolutionRequired; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import java.net.InetAddress; import java.net.URI; +import java.net.UnknownHostException; +import java.util.LinkedHashSet; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.neo4j.driver.AuthToken; import org.neo4j.driver.AuthTokens; import org.neo4j.driver.Config; +import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.DefaultDomainNameResolver; import org.neo4j.driver.internal.DomainNameResolver; import org.neo4j.driver.internal.DriverFactory; @@ -128,9 +133,20 @@ private ServerAddressResolver callbackResolver( TestkitState testkitState ) ResolverResolutionRequired.builder() .data( body ) .build(); - testkitState.getResponseWriter().accept( response ); - testkitState.getProcessor().get(); - return testkitState.getIdToServerAddresses().remove( callbackId ); + CompletionStage c = testkitState.dispatchTestkitCallback( response ); + ResolverResolutionCompleted resolutionCompleted; + try + { + resolutionCompleted = (ResolverResolutionCompleted) c.toCompletableFuture().get(); + } + catch ( Exception e ) + { + throw new RuntimeException( e ); + } + return resolutionCompleted.getData().getAddresses() + .stream() + .map( BoltServerAddress::new ) + .collect( Collectors.toCollection( LinkedHashSet::new ) ); }; } @@ -144,13 +160,37 @@ private DomainNameResolver callbackDomainNameResolver( TestkitState testkitState .id( callbackId ) .name( address ) .build(); - DomainNameResolutionRequired response = + DomainNameResolutionRequired callback = DomainNameResolutionRequired.builder() .data( body ) .build(); - testkitState.getResponseWriter().accept( response ); - testkitState.getProcessor().get(); - return testkitState.getIdToResolvedAddresses().remove( callbackId ); + + CompletionStage callbackStage = testkitState.dispatchTestkitCallback( callback ); + DomainNameResolutionCompleted resolutionCompleted; + try + { + resolutionCompleted = (DomainNameResolutionCompleted) callbackStage.toCompletableFuture().get(); + } + catch ( Exception e ) + { + throw new RuntimeException( "Unexpected failure during Testkit callback", e ); + } + + return resolutionCompleted.getData().getAddresses() + .stream() + .map( + addr -> + { + try + { + return InetAddress.getByName( addr ); + } + catch ( UnknownHostException e ) + { + throw new RuntimeException( e ); + } + } ) + .toArray( InetAddress[]::new ); }; } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java index 86810f63f2..2a64e22911 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java @@ -21,36 +21,20 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import neo4j.org.testkit.backend.TestkitState; -import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletionStage; -import java.util.stream.Collectors; - -import org.neo4j.driver.internal.BoltServerAddress; @Setter @Getter @NoArgsConstructor -public class ResolverResolutionCompleted implements TestkitRequest +public class ResolverResolutionCompleted implements TestkitCallbackResult { private ResolverResolutionCompletedBody data; @Override - public TestkitResponse process( TestkitState testkitState ) - { - testkitState.getIdToServerAddresses().put( data.getRequestId(), data.getAddresses().stream().map( BoltServerAddress::new ) - .collect( Collectors.toCollection( LinkedHashSet::new ) ) ); - return null; - } - - @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public String getCallbackId() { - throw new UnsupportedOperationException(); + return data.getRequestId(); } @Setter diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java index af45836492..dea1551ff1 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java @@ -41,13 +41,7 @@ public class StartTest implements TestkitRequest static { - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_fail_when_driver_closed_using_session_run$", "Does not throw error" ); - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_read_successfully_on_empty_discovery_result_using_session_run$", "Resolver not implemented" ); - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_request_rt_from_all_initial_routers_until_successful", "Resolver not implemented" ); - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_revert_to_initial_router_if_known_router_throws_protocol_errors", "Resolver not implemented" ); - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_successfully_acquire_rt_when_router_ip_changes$", "Resolver not implemented" ); - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_use_resolver_during_rediscovery_when_existing_routers_fail$", "Resolver not implemented" ); - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_reject_server_using_verify_connectivity_bolt_3x0", "Does not error as expected" ); + ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_reject_server_using_verify_connectivity_bolt_3x0$", "Does not error as expected" ); } private StartTestBody data; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java new file mode 100644 index 0000000000..7a4cfbba6a --- /dev/null +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package neo4j.org.testkit.backend.messages.requests; + +import neo4j.org.testkit.backend.TestkitState; +import neo4j.org.testkit.backend.messages.responses.TestkitCallback; +import neo4j.org.testkit.backend.messages.responses.TestkitResponse; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +/** + * This request is sent by Testkit in response to previously sent {@link TestkitCallback}. + */ +public interface TestkitCallbackResult extends TestkitRequest +{ + String getCallbackId(); + + @Override + default TestkitResponse process( TestkitState testkitState ) + { + testkitState.getCallbackIdToFuture().get( getCallbackId() ).complete( this ); + return null; + } + + @Override + default CompletionStage> processAsync( TestkitState testkitState ) + { + testkitState.getCallbackIdToFuture().get( getCallbackId() ).complete( this ); + return CompletableFuture.completedFuture( Optional.empty() ); + } +} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java index 3f803cc021..06fc58d674 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java @@ -25,7 +25,7 @@ @Setter @Getter @Builder -public class DomainNameResolutionRequired implements TestkitResponse +public class DomainNameResolutionRequired implements TestkitCallback { private DomainNameResolutionRequiredBody data; @@ -35,6 +35,12 @@ public String testkitName() return "DomainNameResolutionRequired"; } + @Override + public String getCallbackId() + { + return data.getId(); + } + @Setter @Getter @Builder diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java index 685e3a3742..d39eda8c5b 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java @@ -25,7 +25,7 @@ @Setter @Getter @Builder -public class ResolverResolutionRequired implements TestkitResponse +public class ResolverResolutionRequired implements TestkitCallback { private ResolverResolutionRequiredBody data; @@ -35,6 +35,12 @@ public String testkitName() return "ResolverResolutionRequired"; } + @Override + public String getCallbackId() + { + return data.getId(); + } + @Setter @Getter @Builder diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitCallback.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitCallback.java new file mode 100644 index 0000000000..f43e37ccf8 --- /dev/null +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitCallback.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package neo4j.org.testkit.backend.messages.responses; + +import neo4j.org.testkit.backend.messages.requests.TestkitCallbackResult; + +/** + * This is a special type of {@link TestkitResponse} that is typically sent during driver action processing to request some action or data from Testkit, which + * must respond with {@link TestkitCallbackResult}. + */ +public interface TestkitCallback extends TestkitResponse +{ + String getCallbackId(); +} From 9810ba20afa04e9f24135c9fc4fa2eef5c5c0683 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Mon, 23 Aug 2021 15:23:03 +0200 Subject: [PATCH 2/5] Decouple TestkitState from CommandProcessor. (#993) This commit remoces the command processor from the TestKit state. The processor is supposed to use that state, not to be part of it. However, some requests, like `NewDriver` need the processor to trigger further state. Therefor the processor is now provided as injectable value via Jackson, so that any request can indicate that it needs a processor via a constructor argument. --- .../org/testkit/backend/BackendServer.java | 2 +- .../org/testkit/backend/CommandProcessor.java | 241 ++---------------- .../backend/DefaultCommandProcessor.java | 235 +++++++++++++++++ .../org/testkit/backend/TestkitState.java | 24 +- .../TestkitRequestProcessorHandler.java | 2 +- .../TestkitRequestResponseMapperHandler.java | 13 +- .../backend/messages/requests/NewDriver.java | 30 ++- .../requests/SessionReadTransaction.java | 13 +- .../requests/SessionWriteTransaction.java | 12 +- .../messages/requests/TestkitRequest.java | 3 +- .../backend/MessageDeserializerTest.java | 16 +- .../backend/MessageSerializerTest.java | 14 +- 12 files changed, 324 insertions(+), 281 deletions(-) create mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java index d35f955705..c095517a8e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java @@ -50,7 +50,7 @@ private void handleClient( Socket clientSocket ) System.out.println( "Handling connection from: " + clientSocket.getRemoteSocketAddress() ); BufferedReader in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) ); BufferedWriter out = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream() ) ); - CommandProcessor commandProcessor = new CommandProcessor( in, out ); + CommandProcessor commandProcessor = new DefaultCommandProcessor( in, out ); boolean cont = true; while ( cont ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java index de35a37305..2669ec718d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java @@ -18,227 +18,42 @@ */ package neo4j.org.testkit.backend; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.InjectableValues; import com.fasterxml.jackson.databind.ObjectMapper; import neo4j.org.testkit.backend.messages.TestkitModule; -import neo4j.org.testkit.backend.messages.requests.TestkitRequest; -import neo4j.org.testkit.backend.messages.responses.BackendError; -import neo4j.org.testkit.backend.messages.responses.DriverError; -import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.UncheckedIOException; +import java.util.Collections; -import org.neo4j.driver.exceptions.Neo4jException; -import org.neo4j.driver.exceptions.UntrustedServerException; -import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; - -public class CommandProcessor +public interface CommandProcessor { - private final TestkitState testkitState; - - private final ObjectMapper objectMapper = new ObjectMapper(); + /** + * Used in ObjectMapper's injectable values. + */ + String COMMAND_PROCESSOR_ID = "commandProcessor"; + + /** + * Reads one request and writes the response. Returns false when not able to read anymore. + * + * @return False when there's nothing to read anymore. + */ + boolean process(); + + /** + * Create a new {@link ObjectMapper} configured with the appropriate testkit module and an injectable {@link CommandProcessor}. + * @param processor The processor supposed to be injectable + * @return A reusable object mapper instance + */ + static ObjectMapper newObjectMapperFor(CommandProcessor processor) { + + final ObjectMapper objectMapper = new ObjectMapper(); - private final BufferedReader in; - private final BufferedWriter out; - - public CommandProcessor( BufferedReader in, BufferedWriter out ) - { - this.in = in; - this.out = out; - configureObjectMapper(); - this.testkitState = new TestkitState( this::writeResponse, this::process ); - } - - private void configureObjectMapper() - { TestkitModule testkitModule = new TestkitModule(); - this.objectMapper.registerModule( testkitModule ); - this.objectMapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); - } - - private String readLine() - { - try - { - return this.in.readLine(); - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - private void write( String s ) - { - try - { - this.out.write( s ); - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - // Logs to frontend - private void log( String s ) - { - try - { - this.out.write( s + "\n" ); - this.out.flush(); - } - catch ( IOException e ) - { - } - System.out.println( s ); - } - - private void flush() - { - try - { - this.out.flush(); - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - // Reads one request and writes the response. Returns false when not able to read anymore. - public boolean process() - { - boolean inRequest = false; - StringBuilder request = new StringBuilder(); - - log( "Waiting for request" ); - - while ( true ) - { - String currentLine = readLine(); - // End of stream - if ( currentLine == null ) - { - return false; - } - - if ( currentLine.equals( "#request begin" ) ) - { - inRequest = true; - } - else if ( currentLine.equals( "#request end" ) ) - { - if ( !inRequest ) - { - throw new RuntimeException( "Request end not expected" ); - } - try - { - processRequest( request.toString() ); - } - catch ( Exception e ) - { - if ( e instanceof Neo4jException ) - { - // Error to track - String id = testkitState.newId(); - testkitState.getErrors().put( id, (Neo4jException) e ); - writeResponse( driverError( id, (Neo4jException) e ) ); - System.out.println( "Neo4jException: " + e ); - } - else if ( isConnectionPoolClosedException( e ) || e instanceof UntrustedServerException ) - { - String id = testkitState.newId(); - DriverError driverError = DriverError.builder() - .data( - DriverError.DriverErrorBody.builder() - .id( id ) - .errorType( e.getClass().getName() ) - .msg( e.getMessage() ) - .build() - ) - .build(); - writeResponse( driverError ); - } - else - { - // Unknown error, interpret this as a backend error. - // Report to frontend and rethrow, note that if socket been - // closed the writing will throw itself... - writeResponse( BackendError.builder().data( BackendError.BackendErrorBody.builder().msg( e.toString() ).build() ).build() ); - // This won't print if there was an IO exception since line above will rethrow - e.printStackTrace(); - throw e; - } - } - return true; - } - else - { - if ( !inRequest ) - { - throw new RuntimeException( "Command Received whilst not in request" ); - } - request.append( currentLine ); - } - } - } - - private DriverError driverError( String id, Neo4jException e ) - { - return DriverError.builder().data( - DriverError.DriverErrorBody.builder() - .id( id ) - .errorType( e.getClass().getName() ) - .code( e.code() ) - .msg( e.getMessage() ) - .build() ) - .build(); - } - - public void processRequest( String request ) - { - System.out.println( "request = " + request + ", in = " + in + ", out = " + out ); - try - { - TestkitRequest testkitMessage = objectMapper.readValue( request, TestkitRequest.class ); - TestkitResponse response = testkitMessage.process( testkitState ); - if ( response != null ) - { - writeResponse( response ); - } - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - private void writeResponse( TestkitResponse response ) - { - try - { - String responseStr = objectMapper.writeValueAsString( response ); - System.out.println("response = " + responseStr + ", in = " + in + ", out = " + out); - write( "#response begin\n" ); - write( responseStr + "\n" ); - write( "#response end\n" ); - flush(); - } - catch ( JsonProcessingException ex ) - { - throw new RuntimeException( "Error writing response", ex ); - } - } + objectMapper.registerModule( testkitModule ); + objectMapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); - private boolean isConnectionPoolClosedException( Exception e ) - { - return e instanceof IllegalStateException && e.getMessage() != null && - e.getMessage().equals( ConnectionPoolImpl.CONNECTION_POOL_CLOSED_ERROR_MESSAGE ); + InjectableValues injectableValues = new InjectableValues.Std( Collections.singletonMap( COMMAND_PROCESSOR_ID, processor ) ); + objectMapper.setInjectableValues( injectableValues ); + return objectMapper; } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java new file mode 100644 index 0000000000..292f1c2fbc --- /dev/null +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package neo4j.org.testkit.backend; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import neo4j.org.testkit.backend.messages.requests.TestkitRequest; +import neo4j.org.testkit.backend.messages.responses.BackendError; +import neo4j.org.testkit.backend.messages.responses.DriverError; +import neo4j.org.testkit.backend.messages.responses.TestkitResponse; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.UncheckedIOException; + +import org.neo4j.driver.exceptions.Neo4jException; +import org.neo4j.driver.exceptions.UntrustedServerException; +import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; + +class DefaultCommandProcessor implements CommandProcessor +{ + private final TestkitState testkitState; + + private final ObjectMapper objectMapper; + + private final BufferedReader in; + private final BufferedWriter out; + + DefaultCommandProcessor( BufferedReader in, BufferedWriter out ) + { + this.in = in; + this.out = out; + this.objectMapper = CommandProcessor.newObjectMapperFor( this ); + this.testkitState = new TestkitState( this::writeResponse ); + } + + private String readLine() + { + try + { + return this.in.readLine(); + } + catch ( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + + private void write( String s ) + { + try + { + this.out.write( s ); + } + catch ( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + + // Logs to frontend + private void log( String s ) + { + try + { + this.out.write( s + "\n" ); + this.out.flush(); + } + catch ( IOException e ) + { + } + System.out.println( s ); + } + + private void flush() + { + try + { + this.out.flush(); + } + catch ( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + + @Override + public boolean process() + { + boolean inRequest = false; + StringBuilder request = new StringBuilder(); + + log( "Waiting for request" ); + + while ( true ) + { + String currentLine = readLine(); + // End of stream + if ( currentLine == null ) + { + return false; + } + + if ( currentLine.equals( "#request begin" ) ) + { + inRequest = true; + } + else if ( currentLine.equals( "#request end" ) ) + { + if ( !inRequest ) + { + throw new RuntimeException( "Request end not expected" ); + } + try + { + processRequest( request.toString() ); + } + catch ( Exception e ) + { + if ( e instanceof Neo4jException ) + { + // Error to track + String id = testkitState.newId(); + testkitState.getErrors().put( id, (Neo4jException) e ); + writeResponse( driverError( id, (Neo4jException) e ) ); + System.out.println( "Neo4jException: " + e ); + } + else if ( isConnectionPoolClosedException( e ) || e instanceof UntrustedServerException ) + { + String id = testkitState.newId(); + DriverError driverError = DriverError.builder() + .data( + DriverError.DriverErrorBody.builder() + .id( id ) + .errorType( e.getClass().getName() ) + .msg( e.getMessage() ) + .build() + ) + .build(); + writeResponse( driverError ); + } + else + { + // Unknown error, interpret this as a backend error. + // Report to frontend and rethrow, note that if socket been + // closed the writing will throw itself... + writeResponse( BackendError.builder().data( BackendError.BackendErrorBody.builder().msg( e.toString() ).build() ).build() ); + // This won't print if there was an IO exception since line above will rethrow + e.printStackTrace(); + throw e; + } + } + return true; + } + else + { + if ( !inRequest ) + { + throw new RuntimeException( "Command Received whilst not in request" ); + } + request.append( currentLine ); + } + } + } + + private DriverError driverError( String id, Neo4jException e ) + { + return DriverError.builder().data( + DriverError.DriverErrorBody.builder() + .id( id ) + .errorType( e.getClass().getName() ) + .code( e.code() ) + .msg( e.getMessage() ) + .build() ) + .build(); + } + + public void processRequest( String request ) + { + System.out.println( "request = " + request + ", in = " + in + ", out = " + out ); + try + { + TestkitRequest testkitMessage = objectMapper.readValue( request, TestkitRequest.class ); + TestkitResponse response = testkitMessage.process( testkitState ); + if ( response != null ) + { + writeResponse( response ); + } + } + catch ( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + + private void writeResponse( TestkitResponse response ) + { + try + { + String responseStr = objectMapper.writeValueAsString( response ); + System.out.println("response = " + responseStr + ", in = " + in + ", out = " + out); + write( "#response begin\n" ); + write( responseStr + "\n" ); + write( "#response end\n" ); + flush(); + } + catch ( JsonProcessingException ex ) + { + throw new RuntimeException( "Error writing response", ex ); + } + } + + private boolean isConnectionPoolClosedException( Exception e ) + { + return e instanceof IllegalStateException && e.getMessage() != null && + e.getMessage().equals( ConnectionPoolImpl.CONNECTION_POOL_CLOSED_ERROR_MESSAGE ); + } +} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java index 07850519e4..0b2184f553 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java @@ -18,17 +18,16 @@ */ package neo4j.org.testkit.backend; +import lombok.AccessLevel; import lombok.Getter; import neo4j.org.testkit.backend.messages.requests.TestkitCallbackResult; -import neo4j.org.testkit.backend.messages.responses.TestkitCallback; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; -import java.util.function.Supplier; import org.neo4j.driver.Driver; import org.neo4j.driver.Result; @@ -50,29 +49,18 @@ public class TestkitState private final Map transactions = new HashMap<>(); private final Map asyncTransactions = new HashMap<>(); private final Map errors = new HashMap<>(); - private int idGenerator = 0; + @Getter( AccessLevel.NONE ) + private final AtomicInteger idGenerator = new AtomicInteger( 0 ); private final Consumer responseWriter; - private final Supplier processor; private final Map> callbackIdToFuture = new HashMap<>(); - public TestkitState( Consumer responseWriter, Supplier processor ) + public TestkitState( Consumer responseWriter ) { this.responseWriter = responseWriter; - this.processor = processor; - } - - public CompletionStage dispatchTestkitCallback( TestkitCallback response ) - { - CompletableFuture future = new CompletableFuture<>(); - callbackIdToFuture.put( response.getCallbackId(), future ); - responseWriter.accept( response ); - // This is required for sync backend, but should be removed during migration to Netty implementation. - processor.get(); - return future; } public String newId() { - return String.valueOf( idGenerator++ ); + return String.valueOf( idGenerator.getAndIncrement() ); } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java index 2a9e188148..99027e36e3 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java @@ -36,7 +36,7 @@ public class TestkitRequestProcessorHandler extends ChannelInboundHandlerAdapter { - private final TestkitState testkitState = new TestkitState( this::writeAndFlush, () -> true ); + private final TestkitState testkitState = new TestkitState( this::writeAndFlush ); private Channel channel; @Override diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java index f627bc546b..9556e4b5a6 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java @@ -19,26 +19,17 @@ package neo4j.org.testkit.backend.channel.handler; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; -import neo4j.org.testkit.backend.messages.TestkitModule; +import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.messages.requests.TestkitRequest; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; public class TestkitRequestResponseMapperHandler extends ChannelDuplexHandler { - private final ObjectMapper objectMapper; - - public TestkitRequestResponseMapperHandler() - { - objectMapper = new ObjectMapper(); - TestkitModule testkitModule = new TestkitModule(); - this.objectMapper.registerModule( testkitModule ); - this.objectMapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); - } + private final ObjectMapper objectMapper = CommandProcessor.newObjectMapperFor( () -> true ); @Override public void channelRead( ChannelHandlerContext ctx, Object msg ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java index 51890a6f74..eda99632fe 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java @@ -18,16 +18,19 @@ */ package neo4j.org.testkit.backend.messages.requests; +import com.fasterxml.jackson.annotation.JacksonInject; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.Setter; +import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.BackendError; import neo4j.org.testkit.backend.messages.responses.DomainNameResolutionRequired; import neo4j.org.testkit.backend.messages.responses.Driver; import neo4j.org.testkit.backend.messages.responses.DriverError; import neo4j.org.testkit.backend.messages.responses.ResolverResolutionRequired; +import neo4j.org.testkit.backend.messages.responses.TestkitCallback; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import java.net.InetAddress; @@ -56,9 +59,15 @@ @Setter @Getter -@NoArgsConstructor public class NewDriver implements TestkitRequest { + private final CommandProcessor commandProcessor; + + public NewDriver( @JacksonInject(CommandProcessor.COMMAND_PROCESSOR_ID) CommandProcessor commandProcessor ) + { + this.commandProcessor = commandProcessor; + } + private NewDriverBody data; @Override @@ -92,7 +101,7 @@ public TestkitResponse process( TestkitState testkitState ) DomainNameResolver domainNameResolver = DefaultDomainNameResolver.getInstance(); if ( data.isDomainNameResolverRegistered() ) { - domainNameResolver = callbackDomainNameResolver( testkitState ); + domainNameResolver = callbackDomainNameResolver( commandProcessor, testkitState ); } Optional.ofNullable( data.userAgent ).ifPresent( configBuilder::withUserAgent ); Optional.ofNullable( data.connectionTimeoutMs ).ifPresent( timeout -> configBuilder.withConnectionTimeout( timeout, TimeUnit.MILLISECONDS ) ); @@ -133,7 +142,7 @@ private ServerAddressResolver callbackResolver( TestkitState testkitState ) ResolverResolutionRequired.builder() .data( body ) .build(); - CompletionStage c = testkitState.dispatchTestkitCallback( response ); + CompletionStage c = dispatchTestkitCallback( commandProcessor, testkitState, response ); ResolverResolutionCompleted resolutionCompleted; try { @@ -150,7 +159,7 @@ private ServerAddressResolver callbackResolver( TestkitState testkitState ) }; } - private DomainNameResolver callbackDomainNameResolver( TestkitState testkitState ) + private DomainNameResolver callbackDomainNameResolver( CommandProcessor commandProcessor, TestkitState testkitState ) { return address -> { @@ -165,7 +174,7 @@ private DomainNameResolver callbackDomainNameResolver( TestkitState testkitState .data( body ) .build(); - CompletionStage callbackStage = testkitState.dispatchTestkitCallback( callback ); + CompletionStage callbackStage = dispatchTestkitCallback( commandProcessor, testkitState, callback ); DomainNameResolutionCompleted resolutionCompleted; try { @@ -194,6 +203,17 @@ private DomainNameResolver callbackDomainNameResolver( TestkitState testkitState }; } + private CompletionStage dispatchTestkitCallback( CommandProcessor commandProcessor, TestkitState testkitState, + TestkitCallback response ) + { + CompletableFuture future = new CompletableFuture<>(); + testkitState.getCallbackIdToFuture().put( response.getCallbackId(), future ); + testkitState.getResponseWriter().accept( response ); + // This is required for sync backend, but should be removed during migration to Netty implementation. + commandProcessor.process(); + return future; + } + private org.neo4j.driver.Driver driver( URI uri, AuthToken authToken, Config config, RetrySettings retrySettings, DomainNameResolver domainNameResolver, TestkitState testkitState, String driverId ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java index 605fe247e3..504660ca7e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java @@ -18,10 +18,13 @@ */ package neo4j.org.testkit.backend.messages.requests; +import com.fasterxml.jackson.annotation.JacksonInject; +import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; +import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RetryableDone; @@ -39,11 +42,17 @@ @Setter @Getter -@NoArgsConstructor public class SessionReadTransaction implements TestkitRequest { + private final CommandProcessor commandProcessor; + private SessionReadTransactionBody data; + public SessionReadTransaction( @JacksonInject(CommandProcessor.COMMAND_PROCESSOR_ID) CommandProcessor commandProcessor ) + { + this.commandProcessor = commandProcessor; + } + @Override public TestkitResponse process( TestkitState testkitState ) { @@ -90,7 +99,7 @@ private TransactionWork handle( TestkitState testkitState, SessionState while ( true ) { // Process commands as usual but blocking in here - testkitState.getProcessor().get(); + commandProcessor.process(); // Check if state changed on session switch ( sessionState.retryableState ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java index 077a0076ce..1e60827d7d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java @@ -18,10 +18,12 @@ */ package neo4j.org.testkit.backend.messages.requests; +import com.fasterxml.jackson.annotation.JacksonInject; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; +import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RetryableDone; @@ -40,11 +42,17 @@ @Setter @Getter -@NoArgsConstructor public class SessionWriteTransaction implements TestkitRequest { + private final CommandProcessor commandProcessor; + private SessionWriteTransactionBody data; + public SessionWriteTransaction( @JacksonInject(CommandProcessor.COMMAND_PROCESSOR_ID) CommandProcessor commandProcessor ) + { + this.commandProcessor = commandProcessor; + } + @Override public TestkitResponse process( TestkitState testkitState ) { @@ -92,7 +100,7 @@ private TransactionWork handle( TestkitState testkitState, SessionState while ( true ) { // Process commands as usual but blocking in here - testkitState.getProcessor().get(); + commandProcessor.process(); // Check if state changed on session switch ( sessionState.retryableState ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java index e15e25054e..0569b00aa7 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java @@ -20,13 +20,14 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import java.util.Optional; import java.util.concurrent.CompletionStage; -@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "name" ) +@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, property = "name" ) @JsonSubTypes( { @JsonSubTypes.Type( NewDriver.class ), @JsonSubTypes.Type( NewSession.class ), @JsonSubTypes.Type( SessionRun.class ), @JsonSubTypes.Type( ResultNext.class ), diff --git a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java index 0346931217..477f7c4abf 100644 --- a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java +++ b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java @@ -19,14 +19,11 @@ package neo4j.org.testkit.backend; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import neo4j.org.testkit.backend.messages.TestkitModule; import neo4j.org.testkit.backend.messages.requests.NewDriver; import neo4j.org.testkit.backend.messages.requests.NewSession; -import neo4j.org.testkit.backend.messages.requests.TestkitRequest; import neo4j.org.testkit.backend.messages.requests.SessionRun; -import org.junit.jupiter.api.BeforeAll; +import neo4j.org.testkit.backend.messages.requests.TestkitRequest; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; @@ -35,16 +32,7 @@ class MessageDeserializerTest { - private static final ObjectMapper mapper = new ObjectMapper(); - - @BeforeAll - static void setUp() - { - TestkitModule tkm = new TestkitModule(); - - //mapper.registerModule( tkm ); - mapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); - } + private static final ObjectMapper mapper = CommandProcessor.newObjectMapperFor( () -> false ); @Test void testDeserializeNewDriver() throws JsonProcessingException diff --git a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java index e66f01db66..b898f44b21 100644 --- a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java +++ b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java @@ -19,11 +19,8 @@ package neo4j.org.testkit.backend; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import neo4j.org.testkit.backend.messages.TestkitModule; import neo4j.org.testkit.backend.messages.responses.Driver; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; @@ -31,16 +28,7 @@ public class MessageSerializerTest { - private static final ObjectMapper mapper = new ObjectMapper(); - - @BeforeAll - static void setUp() - { - TestkitModule tkm = new TestkitModule(); - - mapper.registerModule( tkm ); - mapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); - } + private static final ObjectMapper mapper = CommandProcessor.newObjectMapperFor( () -> false ); @Test void shouldSerializerNewDriverResponse() throws JsonProcessingException From ef80d798460cb12441dc81012bfd5b21feaaca8c Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Tue, 24 Aug 2021 11:49:08 +0200 Subject: [PATCH 3/5] Remove unnessary Lombok noise. (#995) --- .../backend/messages/requests/AuthorizationToken.java | 7 ++----- .../backend/messages/requests/CheckMultiDBSupport.java | 3 --- .../messages/requests/DomainNameResolutionCompleted.java | 3 --- .../org/testkit/backend/messages/requests/DriverClose.java | 3 --- .../org/testkit/backend/messages/requests/GetFeatures.java | 2 -- .../testkit/backend/messages/requests/GetRoutingTable.java | 3 --- .../org/testkit/backend/messages/requests/NewDriver.java | 4 +--- .../org/testkit/backend/messages/requests/NewSession.java | 3 --- .../messages/requests/ResolverResolutionCompleted.java | 3 --- .../testkit/backend/messages/requests/ResultConsume.java | 3 --- .../org/testkit/backend/messages/requests/ResultList.java | 3 --- .../org/testkit/backend/messages/requests/ResultNext.java | 3 --- .../backend/messages/requests/RetryableNegative.java | 3 --- .../backend/messages/requests/RetryablePositive.java | 3 --- .../backend/messages/requests/SessionBeginTransaction.java | 3 --- .../testkit/backend/messages/requests/SessionClose.java | 3 --- .../backend/messages/requests/SessionLastBookmarks.java | 3 --- .../backend/messages/requests/SessionReadTransaction.java | 5 +---- .../org/testkit/backend/messages/requests/SessionRun.java | 3 --- .../backend/messages/requests/SessionWriteTransaction.java | 4 +--- .../org/testkit/backend/messages/requests/StartTest.java | 3 --- .../testkit/backend/messages/requests/TestkitRequest.java | 1 - .../backend/messages/requests/TransactionClose.java | 3 --- .../backend/messages/requests/TransactionCommit.java | 4 +--- .../backend/messages/requests/TransactionRollback.java | 4 +--- .../testkit/backend/messages/requests/TransactionRun.java | 3 --- .../backend/messages/requests/VerifyConnectivity.java | 3 --- .../testkit/backend/messages/responses/BackendError.java | 3 --- .../org/testkit/backend/messages/responses/Bookmarks.java | 3 --- .../messages/responses/DomainNameResolutionRequired.java | 3 --- .../org/testkit/backend/messages/responses/Driver.java | 3 --- .../testkit/backend/messages/responses/DriverError.java | 3 --- .../testkit/backend/messages/responses/FeatureList.java | 3 --- .../testkit/backend/messages/responses/MultiDBSupport.java | 3 --- .../org/testkit/backend/messages/responses/NullRecord.java | 2 -- .../org/testkit/backend/messages/responses/Record.java | 3 --- .../org/testkit/backend/messages/responses/RecordList.java | 3 --- .../messages/responses/ResolverResolutionRequired.java | 3 --- .../org/testkit/backend/messages/responses/Result.java | 3 --- .../testkit/backend/messages/responses/RetryableDone.java | 2 -- .../testkit/backend/messages/responses/RetryableTry.java | 3 --- .../testkit/backend/messages/responses/RoutingTable.java | 3 --- .../org/testkit/backend/messages/responses/Session.java | 3 --- .../org/testkit/backend/messages/responses/SkipTest.java | 3 --- .../org/testkit/backend/messages/responses/Summary.java | 4 ---- .../backend/messages/responses/TestkitResponse.java | 2 +- .../testkit/backend/messages/responses/Transaction.java | 3 --- 47 files changed, 8 insertions(+), 138 deletions(-) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/AuthorizationToken.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/AuthorizationToken.java index 695a2a67dc..3d67af0441 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/AuthorizationToken.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/AuthorizationToken.java @@ -21,18 +21,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import java.util.Map; @Setter @Getter -@NoArgsConstructor -@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="name") +@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, property = "name" ) public class AuthorizationToken { - @JsonProperty("data") + @JsonProperty( "data" ) private Map tokens; - } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java index 9e75b62845..82557ee62b 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.MultiDBSupport; @@ -30,7 +29,6 @@ @Setter @Getter -@NoArgsConstructor public class CheckMultiDBSupport implements TestkitRequest { private CheckMultiDBSupportBody data; @@ -63,7 +61,6 @@ private MultiDBSupport createResponse( boolean available ) @Setter @Getter - @NoArgsConstructor public static class CheckMultiDBSupportBody { private String driverId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java index 7878fa749a..537456155f 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DomainNameResolutionCompleted.java @@ -19,14 +19,12 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import java.util.List; @Setter @Getter -@NoArgsConstructor public class DomainNameResolutionCompleted implements TestkitCallbackResult { private DomainNameResolutionCompletedBody data; @@ -39,7 +37,6 @@ public String getCallbackId() @Setter @Getter - @NoArgsConstructor public static class DomainNameResolutionCompletedBody { private String requestId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java index 16a4a0dfe4..a9aadc4b8a 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Driver; @@ -30,7 +29,6 @@ @Setter @Getter -@NoArgsConstructor public class DriverClose implements TestkitRequest { private DriverCloseBody data; @@ -58,7 +56,6 @@ private Driver createResponse() @Setter @Getter - @NoArgsConstructor private static class DriverCloseBody { private String driverId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java index c423500d61..d7eb69b8a9 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.FeatureList; @@ -35,7 +34,6 @@ @Setter @Getter -@NoArgsConstructor public class GetFeatures implements TestkitRequest { private static final Set COMMON_FEATURES = new HashSet<>( Arrays.asList( diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java index 9327a53895..bdcaf5eda1 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RoutingTable; @@ -42,7 +41,6 @@ @Setter @Getter -@NoArgsConstructor public class GetRoutingTable implements TestkitRequest { private GetRoutingTableBody data; @@ -86,7 +84,6 @@ public CompletionStage> processAsync( TestkitState tes @Setter @Getter - @NoArgsConstructor public static class GetRoutingTableBody { private String driverId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java index eda99632fe..1937ddfaf0 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.annotation.JacksonInject; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.CommandProcessor; @@ -63,7 +62,7 @@ public class NewDriver implements TestkitRequest { private final CommandProcessor commandProcessor; - public NewDriver( @JacksonInject(CommandProcessor.COMMAND_PROCESSOR_ID) CommandProcessor commandProcessor ) + public NewDriver( @JacksonInject( CommandProcessor.COMMAND_PROCESSOR_ID ) CommandProcessor commandProcessor ) { this.commandProcessor = commandProcessor; } @@ -242,7 +241,6 @@ private Optional handleExceptionAsErrorResponse( TestkitState t @Setter @Getter - @NoArgsConstructor public static class NewDriverBody { private String uri; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java index 4b4089f1e9..39d98a1bc2 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; import neo4j.org.testkit.backend.SessionState; @@ -42,7 +41,6 @@ @Setter @Getter -@NoArgsConstructor public class NewSession implements TestkitRequest { private NewSessionBody data; @@ -98,7 +96,6 @@ private AsyncSessionState createAsyncSessionState( Driver driver, SessionConfig @Setter @Getter - @NoArgsConstructor public static class NewSessionBody { private String driverId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java index 2a64e22911..38484e381d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResolverResolutionCompleted.java @@ -19,14 +19,12 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import java.util.List; @Setter @Getter -@NoArgsConstructor public class ResolverResolutionCompleted implements TestkitCallbackResult { private ResolverResolutionCompletedBody data; @@ -39,7 +37,6 @@ public String getCallbackId() @Setter @Getter - @NoArgsConstructor public static class ResolverResolutionCompletedBody { private String requestId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java index fe672b7d4c..1cc74f6d57 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.NullRecord; @@ -34,7 +33,6 @@ @Setter @Getter -@NoArgsConstructor public class ResultConsume implements TestkitRequest { private ResultConsumeBody data; @@ -78,7 +76,6 @@ private Summary createResponse( org.neo4j.driver.summary.ResultSummary summary ) @Setter @Getter - @NoArgsConstructor public static class ResultConsumeBody { private String resultId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java index 0e399b6cd9..b5a50730a2 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Record; @@ -33,7 +32,6 @@ @Setter @Getter -@NoArgsConstructor public class ResultList implements TestkitRequest { private ResultListBody data; @@ -65,7 +63,6 @@ private RecordList createResponse( List records ) @Setter @Getter - @NoArgsConstructor public static class ResultListBody { private String resultId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java index cbdaae3070..2d8026989e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.NullRecord; @@ -34,7 +33,6 @@ @Setter @Getter -@NoArgsConstructor public class ResultNext implements TestkitRequest { private ResultNextBody data; @@ -69,7 +67,6 @@ private Record createResponse( org.neo4j.driver.Record record ) @Setter @Getter - @NoArgsConstructor public static class ResultNextBody { private String resultId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java index e7c63c6d37..ef75acc530 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; import neo4j.org.testkit.backend.SessionState; @@ -32,7 +31,6 @@ @Setter @Getter -@NoArgsConstructor public class RetryableNegative implements TestkitRequest { private RetryableNegativeBody data; @@ -69,7 +67,6 @@ public CompletionStage> processAsync( TestkitState tes @Setter @Getter - @NoArgsConstructor public static class RetryableNegativeBody { private String sessionId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java index 474720251b..af04a8f290 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; @@ -31,7 +30,6 @@ @Setter @Getter -@NoArgsConstructor public class RetryablePositive implements TestkitRequest { private RetryablePositiveBody data; @@ -57,7 +55,6 @@ public CompletionStage> processAsync( TestkitState tes @Setter @Getter - @NoArgsConstructor public static class RetryablePositiveBody { private String sessionId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java index 66227f2b6f..064a9980b7 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; import neo4j.org.testkit.backend.SessionState; @@ -37,7 +36,6 @@ @Setter @Getter -@NoArgsConstructor public class SessionBeginTransaction implements TestkitRequest { private SessionBeginTransactionBody data; @@ -101,7 +99,6 @@ private Transaction transaction( String txId ) } @Getter - @NoArgsConstructor @Setter public static class SessionBeginTransactionBody { diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java index ba96189e05..433315453d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Session; @@ -30,7 +29,6 @@ @Setter @Getter -@NoArgsConstructor public class SessionClose implements TestkitRequest { private SessionCloseBody data; @@ -58,7 +56,6 @@ private Session createResponse() @Setter @Getter - @NoArgsConstructor private static class SessionCloseBody { private String sessionId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java index 0a69142894..14db5bf067 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; @@ -34,7 +33,6 @@ @Setter @Getter -@NoArgsConstructor public class SessionLastBookmarks implements TestkitRequest { private SessionLastBookmarksBody data; @@ -66,7 +64,6 @@ private Bookmarks createResponse( Bookmark bookmark ) @Setter @Getter - @NoArgsConstructor public static class SessionLastBookmarksBody { private String sessionId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java index 504660ca7e..d7ff9d0911 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java @@ -19,9 +19,7 @@ package neo4j.org.testkit.backend.messages.requests; import com.fasterxml.jackson.annotation.JacksonInject; -import lombok.Data; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; import neo4j.org.testkit.backend.CommandProcessor; @@ -48,7 +46,7 @@ public class SessionReadTransaction implements TestkitRequest private SessionReadTransactionBody data; - public SessionReadTransaction( @JacksonInject(CommandProcessor.COMMAND_PROCESSOR_ID) CommandProcessor commandProcessor ) + public SessionReadTransaction( @JacksonInject( CommandProcessor.COMMAND_PROCESSOR_ID ) CommandProcessor commandProcessor ) { this.commandProcessor = commandProcessor; } @@ -137,7 +135,6 @@ private RetryableDone retryableDone() @Setter @Getter - @NoArgsConstructor public static class SessionReadTransactionBody { private String sessionId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java index 2d2f0d0807..1ad46e4310 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.requests.deserializer.TestkitCypherParamDeserializer; @@ -39,7 +38,6 @@ @Setter @Getter -@NoArgsConstructor public class SessionRun implements TestkitRequest { private SessionRunBody data; @@ -84,7 +82,6 @@ public CompletionStage> processAsync( TestkitState tes @Setter @Getter - @NoArgsConstructor public static class SessionRunBody { @JsonDeserialize( using = TestkitCypherParamDeserializer.class ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java index 1e60827d7d..f7516f3eb4 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.annotation.JacksonInject; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; import neo4j.org.testkit.backend.CommandProcessor; @@ -48,7 +47,7 @@ public class SessionWriteTransaction implements TestkitRequest private SessionWriteTransactionBody data; - public SessionWriteTransaction( @JacksonInject(CommandProcessor.COMMAND_PROCESSOR_ID) CommandProcessor commandProcessor ) + public SessionWriteTransaction( @JacksonInject( CommandProcessor.COMMAND_PROCESSOR_ID ) CommandProcessor commandProcessor ) { this.commandProcessor = commandProcessor; } @@ -138,7 +137,6 @@ private RetryableDone retryableDone() @Setter @Getter - @NoArgsConstructor public static class SessionWriteTransactionBody { private String sessionId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java index dea1551ff1..0e70291144 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RunTest; @@ -34,7 +33,6 @@ @Setter @Getter -@NoArgsConstructor public class StartTest implements TestkitRequest { private static final Map ASYNC_SKIP_PATTERN_TO_REASON = new HashMap<>(); @@ -72,7 +70,6 @@ public CompletionStage> processAsync( TestkitState tes @Setter @Getter - @NoArgsConstructor public static class StartTestBody { private String testName; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java index 0569b00aa7..fb3c54c97d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java index 7bab055f97..906bf580e9 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; @@ -30,7 +29,6 @@ @Setter @Getter -@NoArgsConstructor public class TransactionClose implements TestkitRequest { private TransactionCloseBody data; @@ -60,7 +58,6 @@ private Transaction createResponse( String txId ) @Setter @Getter - @NoArgsConstructor private static class TransactionCloseBody { private String txId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java index ebe5c18c6a..a692c4d662 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; @@ -29,7 +28,7 @@ import java.util.concurrent.CompletionStage; @Getter -@NoArgsConstructor + @Setter public class TransactionCommit implements TestkitRequest { @@ -62,7 +61,6 @@ private Transaction createResponse( String txId ) } @Getter - @NoArgsConstructor @Setter public static class TransactionCommitBody { diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java index 75e24e2b57..e010942288 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; @@ -29,7 +28,7 @@ import java.util.concurrent.CompletionStage; @Getter -@NoArgsConstructor + @Setter public class TransactionRollback implements TestkitRequest { @@ -62,7 +61,6 @@ private Transaction createResponse( String txId ) } @Getter - @NoArgsConstructor @Setter public static class TransactionRollbackBody { diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java index 2e993e320f..029fb15a11 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.requests.deserializer.TestkitCypherParamDeserializer; @@ -34,7 +33,6 @@ @Setter @Getter -@NoArgsConstructor public class TransactionRun implements TestkitRequest { private TransactionRunBody data; @@ -75,7 +73,6 @@ private Result createResponse( String resultId ) @Setter @Getter - @NoArgsConstructor public static class TransactionRunBody { private String txId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java index acd3907aa4..b157907221 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java @@ -19,7 +19,6 @@ package neo4j.org.testkit.backend.messages.requests; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Driver; @@ -30,7 +29,6 @@ @Setter @Getter -@NoArgsConstructor public class VerifyConnectivity implements TestkitRequest { private VerifyConnectivityBody data; @@ -60,7 +58,6 @@ private Driver createResponse( String id ) @Setter @Getter - @NoArgsConstructor public static class VerifyConnectivityBody { private String driverId; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/BackendError.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/BackendError.java index 66fea5d2c8..703562939f 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/BackendError.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/BackendError.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class BackendError implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "BackendError"; } - @Setter @Getter @Builder public static class BackendErrorBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Bookmarks.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Bookmarks.java index 7c87182d61..2492aa25a7 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Bookmarks.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Bookmarks.java @@ -20,11 +20,9 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; import org.neo4j.driver.Bookmark; -@Setter @Getter @Builder public class Bookmarks implements TestkitResponse @@ -37,7 +35,6 @@ public String testkitName() return "Bookmarks"; } - @Setter @Getter @Builder public static class BookmarksBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java index 06fc58d674..61be8a5a83 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DomainNameResolutionRequired.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class DomainNameResolutionRequired implements TestkitCallback @@ -41,7 +39,6 @@ public String getCallbackId() return data.getId(); } - @Setter @Getter @Builder public static class DomainNameResolutionRequiredBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Driver.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Driver.java index 676eafa8c2..9407b92b0e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Driver.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Driver.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class Driver implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "Driver"; } - @Setter @Getter @Builder public static class DriverBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DriverError.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DriverError.java index d7d4a17697..9b07cebbf5 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DriverError.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/DriverError.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class DriverError implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "DriverError"; } - @Setter @Getter @Builder public static class DriverErrorBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/FeatureList.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/FeatureList.java index 31520d88a2..03d2fe96c4 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/FeatureList.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/FeatureList.java @@ -20,11 +20,9 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; import java.util.Set; -@Setter @Getter @Builder public class FeatureList implements TestkitResponse @@ -37,7 +35,6 @@ public String testkitName() return "FeatureList"; } - @Setter @Getter @Builder public static class FeatureListBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/MultiDBSupport.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/MultiDBSupport.java index 67b9cc7b83..0d126c011f 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/MultiDBSupport.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/MultiDBSupport.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class MultiDBSupport implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "MultiDBSupport"; } - @Setter @Getter @Builder public static class MultiDBSupportBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/NullRecord.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/NullRecord.java index 0c4e774007..1cfd546213 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/NullRecord.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/NullRecord.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class NullRecord implements TestkitResponse diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Record.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Record.java index aa60d8dcd9..4000c2dcd5 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Record.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Record.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class Record implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "Record"; } - @Setter @Getter @Builder public static class RecordBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RecordList.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RecordList.java index f3e531ead7..bad292f2b4 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RecordList.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RecordList.java @@ -20,11 +20,9 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; import java.util.List; -@Setter @Getter @Builder public class RecordList implements TestkitResponse @@ -37,7 +35,6 @@ public String testkitName() return "RecordList"; } - @Setter @Getter @Builder public static class RecordListBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java index d39eda8c5b..14961f3478 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/ResolverResolutionRequired.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class ResolverResolutionRequired implements TestkitCallback @@ -41,7 +39,6 @@ public String getCallbackId() return data.getId(); } - @Setter @Getter @Builder public static class ResolverResolutionRequiredBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Result.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Result.java index e33037f21f..5720f70edd 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Result.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Result.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class Result implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "Result"; } - @Setter @Getter @Builder public static class ResultBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableDone.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableDone.java index d235c3dadf..c2fa2a6e9f 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableDone.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableDone.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class RetryableDone implements TestkitResponse diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableTry.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableTry.java index 303a3c9b09..ce09a92c04 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableTry.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RetryableTry.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class RetryableTry implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "RetryableTry"; } - @Setter @Getter @Builder public static class RetryableTryBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RoutingTable.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RoutingTable.java index 2a802ec1c3..d13156a75b 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RoutingTable.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RoutingTable.java @@ -20,11 +20,9 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; import java.util.List; -@Setter @Getter @Builder public class RoutingTable implements TestkitResponse @@ -37,7 +35,6 @@ public String testkitName() return "RoutingTable"; } - @Setter @Getter @Builder public static class RoutingTableBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Session.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Session.java index 8878c55547..8fcde7fcde 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Session.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Session.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class Session implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "Session"; } - @Setter @Getter @Builder public static class SessionBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/SkipTest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/SkipTest.java index 7f2762c66a..6ccf9204ed 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/SkipTest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/SkipTest.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class SkipTest implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "SkipTest"; } - @Setter @Getter @Builder public static class SkipTestBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java index db32033abb..ac5e0421b0 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Summary.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class Summary implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "Summary"; } - @Setter @Getter @Builder public static class SummaryBody @@ -43,7 +40,6 @@ public static class SummaryBody private ServerInfo serverInfo; } - @Setter @Getter @Builder public static class ServerInfo diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitResponse.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitResponse.java index c10391d8d5..a9f7e07c00 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitResponse.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/TestkitResponse.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; -@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="name") +@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, property = "name" ) public interface TestkitResponse { String testkitName(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Transaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Transaction.java index f5b0975483..f5f65b8729 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Transaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/Transaction.java @@ -20,9 +20,7 @@ import lombok.Builder; import lombok.Getter; -import lombok.Setter; -@Setter @Getter @Builder public class Transaction implements TestkitResponse @@ -35,7 +33,6 @@ public String testkitName() return "Transaction"; } - @Setter @Getter @Builder public static class TransactionBody From 9c1f11995b34121db5a84002768f8f6ecdb1ffad Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov <11927660+injectives@users.noreply.github.com> Date: Tue, 24 Aug 2021 14:08:50 +0100 Subject: [PATCH 4/5] Migrate Testkit backend to Netty implementation (#994) * Migrate Testkit backend to Netty implementation * Remove unnessary Optional in processAsync. This brings both sync and asynchronous paths in TestKitState in symmetry. In addition, I noticed that the transaction related tests behaved differently in sync and async (when a tx is not found). I fixed that. * Remove redundant lines Co-authored-by: Michael Simons --- .../testkit/backend/AsyncBackendServer.java | 63 ----- .../org/testkit/backend/BackendServer.java | 75 ------ .../org/testkit/backend/CommandProcessor.java | 59 ----- .../backend/DefaultCommandProcessor.java | 235 ------------------ .../neo4j/org/testkit/backend/Runner.java | 40 ++- .../org/testkit/backend/SessionState.java | 7 +- .../org/testkit/backend/TestkitState.java | 38 +++ .../TestkitRequestProcessorHandler.java | 53 ++-- .../TestkitRequestResponseMapperHandler.java | 14 +- .../requests/CheckMultiDBSupport.java | 6 +- .../messages/requests/DriverClose.java | 6 +- .../messages/requests/GetFeatures.java | 5 +- .../messages/requests/GetRoutingTable.java | 5 +- .../backend/messages/requests/NewDriver.java | 26 +- .../backend/messages/requests/NewSession.java | 5 +- .../messages/requests/ResultConsume.java | 6 +- .../backend/messages/requests/ResultList.java | 6 +- .../backend/messages/requests/ResultNext.java | 6 +- .../messages/requests/RetryableNegative.java | 17 +- .../messages/requests/RetryablePositive.java | 7 +- .../requests/SessionBeginTransaction.java | 21 +- .../messages/requests/SessionClose.java | 6 +- .../requests/SessionLastBookmarks.java | 4 +- .../requests/SessionReadTransaction.java | 66 ++--- .../backend/messages/requests/SessionRun.java | 5 +- .../requests/SessionWriteTransaction.java | 66 ++--- .../backend/messages/requests/StartTest.java | 5 +- .../requests/TestkitCallbackResult.java | 5 +- .../messages/requests/TestkitRequest.java | 3 +- .../messages/requests/TransactionClose.java | 12 +- .../messages/requests/TransactionCommit.java | 18 +- .../requests/TransactionRollback.java | 18 +- .../messages/requests/TransactionRun.java | 35 ++- .../messages/requests/VerifyConnectivity.java | 6 +- .../backend/MessageDeserializerTest.java | 3 +- .../backend/MessageSerializerTest.java | 3 +- 36 files changed, 261 insertions(+), 694 deletions(-) delete mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/AsyncBackendServer.java delete mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java delete mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java delete mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/AsyncBackendServer.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/AsyncBackendServer.java deleted file mode 100644 index 495624e5a0..0000000000 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/AsyncBackendServer.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package neo4j.org.testkit.backend; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import neo4j.org.testkit.backend.channel.handler.TestkitMessageInboundHandler; -import neo4j.org.testkit.backend.channel.handler.TestkitMessageOutboundHandler; -import neo4j.org.testkit.backend.channel.handler.TestkitRequestProcessorHandler; -import neo4j.org.testkit.backend.channel.handler.TestkitRequestResponseMapperHandler; - -public class AsyncBackendServer -{ - public void run() throws InterruptedException - { - EventLoopGroup group = new NioEventLoopGroup(); - try - { - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group( group ) - .channel( NioServerSocketChannel.class ) - .localAddress( 9876 ) - .childHandler( new ChannelInitializer() - { - @Override - protected void initChannel( SocketChannel channel ) - { - channel.pipeline().addLast( new TestkitMessageInboundHandler() ); - channel.pipeline().addLast( new TestkitMessageOutboundHandler() ); - channel.pipeline().addLast( new TestkitRequestResponseMapperHandler() ); - channel.pipeline().addLast( new TestkitRequestProcessorHandler() ); - } - } ); - ChannelFuture server = bootstrap.bind().sync(); - server.channel().closeFuture().sync(); - } - finally - { - group.shutdownGracefully().sync(); - } - } -} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java deleted file mode 100644 index c095517a8e..0000000000 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/BackendServer.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package neo4j.org.testkit.backend; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.UncheckedIOException; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.concurrent.CompletableFuture; - -public class BackendServer -{ - public void run() throws IOException - { - ServerSocket serverSocket = new ServerSocket( 9876 ); - - System.out.println( "Java TestKit Backend Started on port: " + serverSocket.getLocalPort() ); - - while ( true ) - { - final Socket clientSocket = serverSocket.accept(); - CompletableFuture.runAsync( () -> handleClient( clientSocket ) ); - } - } - - private void handleClient( Socket clientSocket ) - { - try - { - System.out.println( "Handling connection from: " + clientSocket.getRemoteSocketAddress() ); - BufferedReader in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) ); - BufferedWriter out = new BufferedWriter( new OutputStreamWriter( clientSocket.getOutputStream() ) ); - CommandProcessor commandProcessor = new DefaultCommandProcessor( in, out ); - - boolean cont = true; - while ( cont ) - { - try - { - cont = commandProcessor.process(); - } - catch ( Exception e ) - { - e.printStackTrace(); - clientSocket.close(); - cont = false; - } - } - } - catch ( IOException ex ) - { - throw new UncheckedIOException( ex ); - } - } -} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java deleted file mode 100644 index 2669ec718d..0000000000 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/CommandProcessor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package neo4j.org.testkit.backend; - -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.InjectableValues; -import com.fasterxml.jackson.databind.ObjectMapper; -import neo4j.org.testkit.backend.messages.TestkitModule; - -import java.util.Collections; - -public interface CommandProcessor -{ - /** - * Used in ObjectMapper's injectable values. - */ - String COMMAND_PROCESSOR_ID = "commandProcessor"; - - /** - * Reads one request and writes the response. Returns false when not able to read anymore. - * - * @return False when there's nothing to read anymore. - */ - boolean process(); - - /** - * Create a new {@link ObjectMapper} configured with the appropriate testkit module and an injectable {@link CommandProcessor}. - * @param processor The processor supposed to be injectable - * @return A reusable object mapper instance - */ - static ObjectMapper newObjectMapperFor(CommandProcessor processor) { - - final ObjectMapper objectMapper = new ObjectMapper(); - - TestkitModule testkitModule = new TestkitModule(); - objectMapper.registerModule( testkitModule ); - objectMapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); - - InjectableValues injectableValues = new InjectableValues.Std( Collections.singletonMap( COMMAND_PROCESSOR_ID, processor ) ); - objectMapper.setInjectableValues( injectableValues ); - return objectMapper; - } -} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java deleted file mode 100644 index 292f1c2fbc..0000000000 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/DefaultCommandProcessor.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package neo4j.org.testkit.backend; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import neo4j.org.testkit.backend.messages.requests.TestkitRequest; -import neo4j.org.testkit.backend.messages.responses.BackendError; -import neo4j.org.testkit.backend.messages.responses.DriverError; -import neo4j.org.testkit.backend.messages.responses.TestkitResponse; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.UncheckedIOException; - -import org.neo4j.driver.exceptions.Neo4jException; -import org.neo4j.driver.exceptions.UntrustedServerException; -import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; - -class DefaultCommandProcessor implements CommandProcessor -{ - private final TestkitState testkitState; - - private final ObjectMapper objectMapper; - - private final BufferedReader in; - private final BufferedWriter out; - - DefaultCommandProcessor( BufferedReader in, BufferedWriter out ) - { - this.in = in; - this.out = out; - this.objectMapper = CommandProcessor.newObjectMapperFor( this ); - this.testkitState = new TestkitState( this::writeResponse ); - } - - private String readLine() - { - try - { - return this.in.readLine(); - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - private void write( String s ) - { - try - { - this.out.write( s ); - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - // Logs to frontend - private void log( String s ) - { - try - { - this.out.write( s + "\n" ); - this.out.flush(); - } - catch ( IOException e ) - { - } - System.out.println( s ); - } - - private void flush() - { - try - { - this.out.flush(); - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - @Override - public boolean process() - { - boolean inRequest = false; - StringBuilder request = new StringBuilder(); - - log( "Waiting for request" ); - - while ( true ) - { - String currentLine = readLine(); - // End of stream - if ( currentLine == null ) - { - return false; - } - - if ( currentLine.equals( "#request begin" ) ) - { - inRequest = true; - } - else if ( currentLine.equals( "#request end" ) ) - { - if ( !inRequest ) - { - throw new RuntimeException( "Request end not expected" ); - } - try - { - processRequest( request.toString() ); - } - catch ( Exception e ) - { - if ( e instanceof Neo4jException ) - { - // Error to track - String id = testkitState.newId(); - testkitState.getErrors().put( id, (Neo4jException) e ); - writeResponse( driverError( id, (Neo4jException) e ) ); - System.out.println( "Neo4jException: " + e ); - } - else if ( isConnectionPoolClosedException( e ) || e instanceof UntrustedServerException ) - { - String id = testkitState.newId(); - DriverError driverError = DriverError.builder() - .data( - DriverError.DriverErrorBody.builder() - .id( id ) - .errorType( e.getClass().getName() ) - .msg( e.getMessage() ) - .build() - ) - .build(); - writeResponse( driverError ); - } - else - { - // Unknown error, interpret this as a backend error. - // Report to frontend and rethrow, note that if socket been - // closed the writing will throw itself... - writeResponse( BackendError.builder().data( BackendError.BackendErrorBody.builder().msg( e.toString() ).build() ).build() ); - // This won't print if there was an IO exception since line above will rethrow - e.printStackTrace(); - throw e; - } - } - return true; - } - else - { - if ( !inRequest ) - { - throw new RuntimeException( "Command Received whilst not in request" ); - } - request.append( currentLine ); - } - } - } - - private DriverError driverError( String id, Neo4jException e ) - { - return DriverError.builder().data( - DriverError.DriverErrorBody.builder() - .id( id ) - .errorType( e.getClass().getName() ) - .code( e.code() ) - .msg( e.getMessage() ) - .build() ) - .build(); - } - - public void processRequest( String request ) - { - System.out.println( "request = " + request + ", in = " + in + ", out = " + out ); - try - { - TestkitRequest testkitMessage = objectMapper.readValue( request, TestkitRequest.class ); - TestkitResponse response = testkitMessage.process( testkitState ); - if ( response != null ) - { - writeResponse( response ); - } - } - catch ( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - - private void writeResponse( TestkitResponse response ) - { - try - { - String responseStr = objectMapper.writeValueAsString( response ); - System.out.println("response = " + responseStr + ", in = " + in + ", out = " + out); - write( "#response begin\n" ); - write( responseStr + "\n" ); - write( "#response end\n" ); - flush(); - } - catch ( JsonProcessingException ex ) - { - throw new RuntimeException( "Error writing response", ex ); - } - } - - private boolean isConnectionPoolClosedException( Exception e ) - { - return e instanceof IllegalStateException && e.getMessage() != null && - e.getMessage().equals( ConnectionPoolImpl.CONNECTION_POOL_CLOSED_ERROR_MESSAGE ); - } -} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java index 2c60fb8cd2..a35986683a 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java @@ -18,19 +18,47 @@ */ package neo4j.org.testkit.backend; -import java.io.IOException; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import neo4j.org.testkit.backend.channel.handler.TestkitMessageInboundHandler; +import neo4j.org.testkit.backend.channel.handler.TestkitMessageOutboundHandler; +import neo4j.org.testkit.backend.channel.handler.TestkitRequestProcessorHandler; +import neo4j.org.testkit.backend.channel.handler.TestkitRequestResponseMapperHandler; public class Runner { - public static void main( String[] args ) throws IOException, InterruptedException + public static void main( String[] args ) throws InterruptedException { - if ( args.length > 0 && args[0].equals( "async" ) ) + boolean asyncMode = args.length > 0 && args[0].equals( "async" ); + EventLoopGroup group = new NioEventLoopGroup(); + try { - new AsyncBackendServer().run(); + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group( group ) + .channel( NioServerSocketChannel.class ) + .localAddress( 9876 ) + .childHandler( new ChannelInitializer() + { + @Override + protected void initChannel( SocketChannel channel ) + { + channel.pipeline().addLast( new TestkitMessageInboundHandler() ); + channel.pipeline().addLast( new TestkitMessageOutboundHandler() ); + channel.pipeline().addLast( new TestkitRequestResponseMapperHandler() ); + channel.pipeline().addLast( new TestkitRequestProcessorHandler( asyncMode ) ); + } + } ); + ChannelFuture server = bootstrap.bind().sync(); + server.channel().closeFuture().sync(); } - else + finally { - new BackendServer().run(); + group.shutdownGracefully().sync(); } } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/SessionState.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/SessionState.java index d0bfe16733..9fc142b251 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/SessionState.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/SessionState.java @@ -21,6 +21,8 @@ import lombok.Getter; import lombok.Setter; +import java.util.concurrent.CompletableFuture; + import org.neo4j.driver.Session; @Getter @@ -28,12 +30,9 @@ public class SessionState { public Session session; - public int retryableState; - public String retryableErrorId; + public CompletableFuture txWorkFuture; public SessionState(Session session) { this.session = session; - this.retryableState = 0; - this.retryableErrorId = ""; } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java index 0b2184f553..535b177e2e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java @@ -40,13 +40,17 @@ @Getter public class TestkitState { + private static final String TRANSACTION_NOT_FOUND_MESSAGE = "Could not find transaction"; + private final Map drivers = new HashMap<>(); private final Map routingTableRegistry = new HashMap<>(); private final Map sessionStates = new HashMap<>(); private final Map asyncSessionStates = new HashMap<>(); private final Map results = new HashMap<>(); private final Map resultCursors = new HashMap<>(); + @Getter( AccessLevel.NONE ) private final Map transactions = new HashMap<>(); + @Getter( AccessLevel.NONE ) private final Map asyncTransactions = new HashMap<>(); private final Map errors = new HashMap<>(); @Getter( AccessLevel.NONE ) @@ -63,4 +67,38 @@ public String newId() { return String.valueOf( idGenerator.getAndIncrement() ); } + + public String addTransaction( Transaction transaction ) + { + String id = newId(); + this.transactions.put( id, transaction ); + return id; + } + + public Transaction getTransaction( String id ) + { + if ( !this.transactions.containsKey( id ) ) + { + throw new RuntimeException( TRANSACTION_NOT_FOUND_MESSAGE ); + } + return this.transactions.get( id ); + } + + public String addAsyncTransaction( AsyncTransaction transaction ) + { + String id = newId(); + this.asyncTransactions.put( id, transaction ); + return id; + } + + public CompletableFuture getAsyncTransaction( String id ) + { + if ( !this.asyncTransactions.containsKey( id ) ) + { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally( new RuntimeException( TRANSACTION_NOT_FOUND_MESSAGE ) ); + return future; + } + return CompletableFuture.completedFuture( asyncTransactions.get( id ) ); + } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java index 99027e36e3..5060bf5428 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java @@ -29,6 +29,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.function.BiFunction; import org.neo4j.driver.exceptions.Neo4jException; import org.neo4j.driver.exceptions.UntrustedServerException; @@ -37,8 +39,18 @@ public class TestkitRequestProcessorHandler extends ChannelInboundHandlerAdapter { private final TestkitState testkitState = new TestkitState( this::writeAndFlush ); + private final BiFunction> processorImpl; private Channel channel; + public TestkitRequestProcessorHandler( boolean asyncMode ) + { + if (asyncMode) { + processorImpl = (request, state) -> request.processAsync( state ); + } else { + processorImpl = TestkitRequestProcessorHandler::wrapSyncRequest; + } + } + @Override public void channelRegistered( ChannelHandlerContext ctx ) throws Exception { @@ -49,26 +61,35 @@ public void channelRegistered( ChannelHandlerContext ctx ) throws Exception @Override public void channelRead( ChannelHandlerContext ctx, Object msg ) { - TestkitRequest testkitRequest = (TestkitRequest) msg; // Processing is done in a separate thread to avoid blocking EventLoop because some testing logic, like resolvers support, is blocking. - CompletableFuture.runAsync( - () -> + CompletableFuture.supplyAsync( () -> (TestkitRequest) msg ) + .thenCompose( request -> processorImpl.apply( request, testkitState ) ) + .thenApply( response -> { - try + if ( response != null ) { - testkitRequest.processAsync( testkitState ) - .thenAccept( responseOpt -> responseOpt.ifPresent( ctx::writeAndFlush ) ) - .exceptionally( throwable -> - { - ctx.writeAndFlush( createErrorResponse( throwable ) ); - return null; - } ); + ctx.writeAndFlush( response ); } - catch ( Throwable throwable ) - { - ctx.writeAndFlush( createErrorResponse( throwable ) ); - } - } ); + return null; + } ).exceptionally( throwable -> + { + ctx.writeAndFlush( createErrorResponse( throwable ) ); + return null; + } ); + } + + private static CompletionStage wrapSyncRequest( TestkitRequest testkitRequest, TestkitState testkitState ) + { + CompletableFuture result = new CompletableFuture<>(); + try + { + result.complete( testkitRequest.process( testkitState ) ); + } + catch ( Throwable t ) + { + result.completeExceptionally( t ); + } + return result; } private TestkitResponse createErrorResponse( Throwable throwable ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java index 9556e4b5a6..d599257a76 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestResponseMapperHandler.java @@ -19,17 +19,18 @@ package neo4j.org.testkit.backend.channel.handler; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; -import neo4j.org.testkit.backend.CommandProcessor; +import neo4j.org.testkit.backend.messages.TestkitModule; import neo4j.org.testkit.backend.messages.requests.TestkitRequest; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; public class TestkitRequestResponseMapperHandler extends ChannelDuplexHandler { - private final ObjectMapper objectMapper = CommandProcessor.newObjectMapperFor( () -> true ); + private final ObjectMapper objectMapper = newObjectMapper(); @Override public void channelRead( ChannelHandlerContext ctx, Object msg ) @@ -54,4 +55,13 @@ public void write( ChannelHandlerContext ctx, Object msg, ChannelPromise promise String responseStr = objectMapper.writeValueAsString( testkitResponse ); ctx.writeAndFlush( responseStr, promise ); } + + public static ObjectMapper newObjectMapper() + { + ObjectMapper objectMapper = new ObjectMapper(); + TestkitModule testkitModule = new TestkitModule(); + objectMapper.registerModule( testkitModule ); + objectMapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES ); + return objectMapper; + } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java index 82557ee62b..7ecfecf886 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java @@ -24,7 +24,6 @@ import neo4j.org.testkit.backend.messages.responses.MultiDBSupport; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Setter @@ -42,12 +41,11 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { return testkitState.getDrivers().get( data.getDriverId() ) .supportsMultiDbAsync() - .thenApply( this::createResponse ) - .thenApply( Optional::of ); + .thenApply( this::createResponse ); } private MultiDBSupport createResponse( boolean available ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java index a9aadc4b8a..1017e159ec 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java @@ -24,7 +24,6 @@ import neo4j.org.testkit.backend.messages.responses.Driver; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Setter @@ -41,12 +40,11 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { return testkitState.getDrivers().get( data.getDriverId() ) .closeAsync() - .thenApply( ignored -> createResponse() ) - .thenApply( Optional::of ); + .thenApply( ignored -> createResponse() ); } private Driver createResponse() diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java index d7eb69b8a9..7389f69d8d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java @@ -27,7 +27,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -58,9 +57,9 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { - return CompletableFuture.completedFuture( Optional.of( createResponse( COMMON_FEATURES ) ) ); + return CompletableFuture.completedFuture( createResponse( COMMON_FEATURES ) ); } private FeatureList createResponse( Set features ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java index bdcaf5eda1..2448c1a45d 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java @@ -26,7 +26,6 @@ import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.function.Function; @@ -77,9 +76,9 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { - return CompletableFuture.completedFuture( Optional.of( process( testkitState ) ) ); + return CompletableFuture.completedFuture( process( testkitState ) ) ; } @Setter diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java index 1937ddfaf0..eaddb1f147 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java @@ -18,11 +18,9 @@ */ package neo4j.org.testkit.backend.messages.requests; -import com.fasterxml.jackson.annotation.JacksonInject; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; -import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.BackendError; import neo4j.org.testkit.backend.messages.responses.DomainNameResolutionRequired; @@ -60,13 +58,6 @@ @Getter public class NewDriver implements TestkitRequest { - private final CommandProcessor commandProcessor; - - public NewDriver( @JacksonInject( CommandProcessor.COMMAND_PROCESSOR_ID ) CommandProcessor commandProcessor ) - { - this.commandProcessor = commandProcessor; - } - private NewDriverBody data; @Override @@ -100,7 +91,7 @@ public TestkitResponse process( TestkitState testkitState ) DomainNameResolver domainNameResolver = DefaultDomainNameResolver.getInstance(); if ( data.isDomainNameResolverRegistered() ) { - domainNameResolver = callbackDomainNameResolver( commandProcessor, testkitState ); + domainNameResolver = callbackDomainNameResolver( testkitState ); } Optional.ofNullable( data.userAgent ).ifPresent( configBuilder::withUserAgent ); Optional.ofNullable( data.connectionTimeoutMs ).ifPresent( timeout -> configBuilder.withConnectionTimeout( timeout, TimeUnit.MILLISECONDS ) ); @@ -122,9 +113,9 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { - return CompletableFuture.completedFuture( Optional.of( process( testkitState ) ) ); + return CompletableFuture.completedFuture( process( testkitState ) ); } private ServerAddressResolver callbackResolver( TestkitState testkitState ) @@ -141,7 +132,7 @@ private ServerAddressResolver callbackResolver( TestkitState testkitState ) ResolverResolutionRequired.builder() .data( body ) .build(); - CompletionStage c = dispatchTestkitCallback( commandProcessor, testkitState, response ); + CompletionStage c = dispatchTestkitCallback( testkitState, response ); ResolverResolutionCompleted resolutionCompleted; try { @@ -158,7 +149,7 @@ private ServerAddressResolver callbackResolver( TestkitState testkitState ) }; } - private DomainNameResolver callbackDomainNameResolver( CommandProcessor commandProcessor, TestkitState testkitState ) + private DomainNameResolver callbackDomainNameResolver( TestkitState testkitState ) { return address -> { @@ -173,7 +164,7 @@ private DomainNameResolver callbackDomainNameResolver( CommandProcessor commandP .data( body ) .build(); - CompletionStage callbackStage = dispatchTestkitCallback( commandProcessor, testkitState, callback ); + CompletionStage callbackStage = dispatchTestkitCallback( testkitState, callback ); DomainNameResolutionCompleted resolutionCompleted; try { @@ -202,14 +193,11 @@ private DomainNameResolver callbackDomainNameResolver( CommandProcessor commandP }; } - private CompletionStage dispatchTestkitCallback( CommandProcessor commandProcessor, TestkitState testkitState, - TestkitCallback response ) + private CompletionStage dispatchTestkitCallback( TestkitState testkitState, TestkitCallback response ) { CompletableFuture future = new CompletableFuture<>(); testkitState.getCallbackIdToFuture().put( response.getCallbackId(), future ); testkitState.getResponseWriter().accept( response ); - // This is required for sync backend, but should be removed during migration to Netty implementation. - commandProcessor.process(); return future; } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java index 39d98a1bc2..889d18377c 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java @@ -52,10 +52,9 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { - return CompletableFuture.completedFuture( - Optional.of( createSessionStateAndResponse( testkitState, this::createAsyncSessionState, testkitState.getAsyncSessionStates() ) ) ); + return CompletableFuture.completedFuture( createSessionStateAndResponse( testkitState, this::createAsyncSessionState, testkitState.getAsyncSessionStates() ) ); } private TestkitResponse createSessionStateAndResponse( TestkitState testkitState, BiFunction sessionStateProducer, diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java index 1cc74f6d57..11778a077b 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java @@ -25,7 +25,6 @@ import neo4j.org.testkit.backend.messages.responses.Summary; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletionStage; import org.neo4j.driver.Result; @@ -52,12 +51,11 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { return testkitState.getResultCursors().get( data.getResultId() ) .consumeAsync() - .thenApply( this::createResponse ) - .thenApply( Optional::of ); + .thenApply( this::createResponse ); } private Summary createResponse( org.neo4j.driver.summary.ResultSummary summary ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java index b5a50730a2..07a3e62e2e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java @@ -26,7 +26,6 @@ import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletionStage; import java.util.stream.Collectors; @@ -43,12 +42,11 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { return testkitState.getResultCursors().get( data.getResultId() ) .listAsync() - .thenApply( this::createResponse ) - .thenApply( Optional::of ); + .thenApply( this::createResponse ); } private RecordList createResponse( List records ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java index 2d8026989e..d79e422f53 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java @@ -25,7 +25,6 @@ import neo4j.org.testkit.backend.messages.responses.Record; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletionStage; import org.neo4j.driver.Result; @@ -52,12 +51,11 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { return testkitState.getResultCursors().get( data.getResultId() ) .nextAsync() - .thenApply( record -> record != null ? createResponse( record ) : NullRecord.builder().build() ) - .thenApply( Optional::of ); + .thenApply( record -> record != null ? createResponse( record ) : NullRecord.builder().build() ); } private Record createResponse( org.neo4j.driver.Record record ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java index ef75acc530..bde0bff0ac 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java @@ -25,7 +25,6 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -43,13 +42,21 @@ public TestkitResponse process( TestkitState testkitState ) { throw new RuntimeException( "Could not find session" ); } - sessionState.setRetryableState( -1 ); - sessionState.setRetryableErrorId( data.errorId ); + Throwable throwable; + if ( !"".equals( data.getErrorId() ) ) + { + throwable = testkitState.getErrors().get( data.getErrorId() ); + } + else + { + throwable = new RuntimeException( "Error from client in retryable tx" ); + } + sessionState.getTxWorkFuture().completeExceptionally( throwable ); return null; } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { AsyncSessionState sessionState = testkitState.getAsyncSessionStates().get( data.getSessionId() ); Throwable throwable; @@ -62,7 +69,7 @@ public CompletionStage> processAsync( TestkitState tes throwable = new RuntimeException( "Error from client in retryable tx" ); } sessionState.getTxWorkFuture().completeExceptionally( throwable ); - return CompletableFuture.completedFuture( Optional.empty() ); + return CompletableFuture.completedFuture( null ); } @Setter diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java index af04a8f290..2f0676ea91 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java @@ -24,7 +24,6 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -42,15 +41,15 @@ public TestkitResponse process( TestkitState testkitState ) { throw new RuntimeException( "Could not find session" ); } - sessionState.setRetryableState( 1 ); + sessionState.getTxWorkFuture().complete( null ); return null; } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { testkitState.getAsyncSessionStates().get( data.getSessionId() ).getTxWorkFuture().complete( null ); - return CompletableFuture.completedFuture( Optional.empty() ); + return CompletableFuture.completedFuture( null ); } @Setter diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java index 064a9980b7..c9a75aaa5e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java @@ -29,6 +29,7 @@ import java.time.Duration; import java.util.Map; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import org.neo4j.driver.TransactionConfig; @@ -55,16 +56,13 @@ public TestkitResponse process( TestkitState testkitState ) builder.withTimeout( Duration.ofMillis( data.getTimeout() ) ); } - String txId = testkitState.newId(); - org.neo4j.driver.Transaction tx = session.beginTransaction( builder.build() ); - testkitState.getTransactions().put( txId, tx ); - return transaction( txId ); + return transaction( testkitState.addTransaction( session.beginTransaction( builder.build() ) ) ); } ) .orElseThrow( () -> new RuntimeException( "Could not find session" ) ); } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { AsyncSessionState sessionState = testkitState.getAsyncSessionStates().get( data.getSessionId() ); if ( sessionState != null ) @@ -78,18 +76,13 @@ public CompletionStage> processAsync( TestkitState tes builder.withTimeout( Duration.ofMillis( data.getTimeout() ) ); } - String txId = testkitState.newId(); - return session.beginTransactionAsync( builder.build() ) - .thenApply( tx -> - { - testkitState.getAsyncTransactions().put( txId, tx ); - return transaction( txId ); - } ) - .thenApply( Optional::of ); + return session.beginTransactionAsync( builder.build() ).thenApply( tx -> transaction( testkitState.addAsyncTransaction( tx ) ) ); } else { - return null; + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally( new RuntimeException( "Could not find session" ) ); + return future; } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java index 433315453d..d942a2cff5 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java @@ -24,7 +24,6 @@ import neo4j.org.testkit.backend.messages.responses.Session; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Setter @@ -41,12 +40,11 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { return testkitState.getAsyncSessionStates().get( data.getSessionId() ).getSession() .closeAsync() - .thenApply( ignored -> createResponse() ) - .thenApply( Optional::of ); + .thenApply( ignored -> createResponse() ); } private Session createResponse() diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java index 14db5bf067..1016a3ca41 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java @@ -51,10 +51,10 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { Bookmark bookmark = testkitState.getAsyncSessionStates().get( data.getSessionId() ).getSession().lastBookmark(); - return CompletableFuture.completedFuture( Optional.of( createResponse( bookmark ) ) ); + return CompletableFuture.completedFuture( createResponse( bookmark ) ); } private Bookmarks createResponse( Bookmark bookmark ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java index d7ff9d0911..134dfd83bd 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java @@ -18,11 +18,9 @@ */ package neo4j.org.testkit.backend.messages.requests; -import com.fasterxml.jackson.annotation.JacksonInject; import lombok.Getter; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; -import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RetryableDone; @@ -32,25 +30,20 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; import org.neo4j.driver.Session; import org.neo4j.driver.TransactionWork; import org.neo4j.driver.async.AsyncSession; import org.neo4j.driver.async.AsyncTransactionWork; +import org.neo4j.driver.exceptions.Neo4jException; @Setter @Getter public class SessionReadTransaction implements TestkitRequest { - private final CommandProcessor commandProcessor; - private SessionReadTransactionBody data; - public SessionReadTransaction( @JacksonInject( CommandProcessor.COMMAND_PROCESSOR_ID ) CommandProcessor commandProcessor ) - { - this.commandProcessor = commandProcessor; - } - @Override public TestkitResponse process( TestkitState testkitState ) { @@ -64,15 +57,14 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { AsyncSessionState sessionState = testkitState.getAsyncSessionStates().get( data.getSessionId() ); AsyncSession session = sessionState.getSession(); AsyncTransactionWork> workWrapper = tx -> { - String txId = testkitState.newId(); - testkitState.getAsyncTransactions().put( txId, tx ); + String txId = testkitState.addAsyncTransaction( tx ); testkitState.getResponseWriter().accept( retryableTry( txId ) ); CompletableFuture txWorkFuture = new CompletableFuture<>(); sessionState.setTxWorkFuture( txWorkFuture ); @@ -80,44 +72,36 @@ public CompletionStage> processAsync( TestkitState tes }; return session.readTransactionAsync( workWrapper ) - .thenApply( nothing -> retryableDone() ) - .thenApply( Optional::of ); + .thenApply( nothing -> retryableDone() ); } - private TransactionWork handle( TestkitState testkitState, SessionState sessionState ) + private TransactionWork handle( TestkitState testkitState, SessionState sessionState ) { return tx -> { - System.out.println( "Start" ); - sessionState.setRetryableState( 0 ); - String txId = testkitState.newId(); - testkitState.getTransactions().put( txId, tx ); + String txId = testkitState.addTransaction( tx ); testkitState.getResponseWriter().accept( retryableTry( txId ) ); + CompletableFuture txWorkFuture = new CompletableFuture<>(); + sessionState.setTxWorkFuture( txWorkFuture ); - while ( true ) + try { - // Process commands as usual but blocking in here - commandProcessor.process(); - - // Check if state changed on session - switch ( sessionState.retryableState ) + return txWorkFuture.get(); + } + catch ( Throwable throwable ) + { + Throwable workThrowable = throwable; + if ( workThrowable instanceof ExecutionException ) + { + workThrowable = workThrowable.getCause(); + } + if ( workThrowable instanceof Neo4jException ) + { + throw (Neo4jException) workThrowable; + } + else { - case 0: - // Nothing happened to session state while processing command - break; - case 1: - // Client is happy to commit - return 0; - case -1: - // Client wants to rollback - if ( !"".equals( sessionState.retryableErrorId ) ) - { - throw testkitState.getErrors().get( sessionState.retryableErrorId ); - } - else - { - throw new RuntimeException( "Error from client in retryable tx" ); - } + throw new RuntimeException( "Unexpected exception occurred in transaction work function", workThrowable ); } } }; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java index 1ad46e4310..5122793911 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java @@ -60,7 +60,7 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { AsyncSession session = testkitState.getAsyncSessionStates().get( data.getSessionId() ).getSession(); Query query = Optional.ofNullable( data.params ) @@ -76,8 +76,7 @@ public CompletionStage> processAsync( TestkitState tes String newId = testkitState.newId(); testkitState.getResultCursors().put( newId, resultCursor ); return Result.builder().data( Result.ResultBody.builder().id( newId ).build() ).build(); - } ) - .thenApply( Optional::of ); + } ); } @Setter diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java index f7516f3eb4..4ceeac6a29 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java @@ -18,11 +18,9 @@ */ package neo4j.org.testkit.backend.messages.requests; -import com.fasterxml.jackson.annotation.JacksonInject; import lombok.Getter; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; -import neo4j.org.testkit.backend.CommandProcessor; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RetryableDone; @@ -33,25 +31,20 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; import org.neo4j.driver.Session; import org.neo4j.driver.TransactionWork; import org.neo4j.driver.async.AsyncSession; import org.neo4j.driver.async.AsyncTransactionWork; +import org.neo4j.driver.exceptions.Neo4jException; @Setter @Getter public class SessionWriteTransaction implements TestkitRequest { - private final CommandProcessor commandProcessor; - private SessionWriteTransactionBody data; - public SessionWriteTransaction( @JacksonInject( CommandProcessor.COMMAND_PROCESSOR_ID ) CommandProcessor commandProcessor ) - { - this.commandProcessor = commandProcessor; - } - @Override public TestkitResponse process( TestkitState testkitState ) { @@ -65,7 +58,7 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { AsyncSessionState sessionState = testkitState.getAsyncSessionStates().get( data.getSessionId() ); AsyncSession session = sessionState.getSession(); @@ -73,8 +66,7 @@ public CompletionStage> processAsync( TestkitState tes AsyncTransactionWork> workWrapper = tx -> { - String txId = testkitState.newId(); - testkitState.getAsyncTransactions().put( txId, tx ); + String txId = testkitState.addAsyncTransaction( tx ); testkitState.getResponseWriter().accept( retryableTry( txId ) ); CompletableFuture tryResult = new CompletableFuture<>(); sessionState.setTxWorkFuture( tryResult ); @@ -82,44 +74,36 @@ public CompletionStage> processAsync( TestkitState tes }; return session.writeTransactionAsync( workWrapper ) - .thenApply( nothing -> retryableDone() ) - .thenApply( Optional::of ); + .thenApply( nothing -> retryableDone() ); } - private TransactionWork handle( TestkitState testkitState, SessionState sessionState ) + private TransactionWork handle( TestkitState testkitState, SessionState sessionState ) { return tx -> { - System.out.println( "Start" ); - sessionState.setRetryableState( 0 ); - String txId = testkitState.newId(); - testkitState.getTransactions().put( txId, tx ); + String txId = testkitState.addTransaction( tx ); testkitState.getResponseWriter().accept( retryableTry( txId ) ); + CompletableFuture txWorkFuture = new CompletableFuture<>(); + sessionState.setTxWorkFuture( txWorkFuture ); - while ( true ) + try { - // Process commands as usual but blocking in here - commandProcessor.process(); - - // Check if state changed on session - switch ( sessionState.retryableState ) + return txWorkFuture.get(); + } + catch ( Throwable throwable ) + { + Throwable workThrowable = throwable; + if ( workThrowable instanceof ExecutionException ) + { + workThrowable = workThrowable.getCause(); + } + if ( workThrowable instanceof Neo4jException ) + { + throw (Neo4jException) workThrowable; + } + else { - case 0: - // Nothing happened to session state while processing command - break; - case 1: - // Client is happy to commit - return 0; - case -1: - // Client wants to rollback - if ( !"".equals( sessionState.retryableErrorId ) ) - { - throw testkitState.getErrors().get( sessionState.retryableErrorId ); - } - else - { - throw new RuntimeException( "Error from client in retryable tx" ); - } + throw new RuntimeException( "Unexpected exception occurred in transaction work function", workThrowable ); } } }; diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java index 0e70291144..ed701746c8 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java @@ -27,7 +27,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -51,7 +50,7 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { TestkitResponse testkitResponse = ASYNC_SKIP_PATTERN_TO_REASON .entrySet() @@ -65,7 +64,7 @@ public CompletionStage> processAsync( TestkitState tes .build() ) .orElseGet( () -> RunTest.builder().build() ); - return CompletableFuture.completedFuture( Optional.of( testkitResponse ) ); + return CompletableFuture.completedFuture( testkitResponse ); } @Setter diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java index 7a4cfbba6a..b622c21b97 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java @@ -22,7 +22,6 @@ import neo4j.org.testkit.backend.messages.responses.TestkitCallback; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -41,9 +40,9 @@ default TestkitResponse process( TestkitState testkitState ) } @Override - default CompletionStage> processAsync( TestkitState testkitState ) + default CompletionStage processAsync( TestkitState testkitState ) { testkitState.getCallbackIdToFuture().get( getCallbackId() ).complete( this ); - return CompletableFuture.completedFuture( Optional.empty() ); + return CompletableFuture.completedFuture( null ); } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java index fb3c54c97d..e9348fd94e 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java @@ -23,7 +23,6 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletionStage; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, property = "name" ) @@ -46,5 +45,5 @@ public interface TestkitRequest { TestkitResponse process( TestkitState testkitState ); - CompletionStage> processAsync( TestkitState testkitState ); + CompletionStage processAsync( TestkitState testkitState ); } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java index 906bf580e9..649d69cbe3 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java @@ -24,7 +24,6 @@ import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import neo4j.org.testkit.backend.messages.responses.Transaction; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Setter @@ -36,17 +35,12 @@ public class TransactionClose implements TestkitRequest @Override public TestkitResponse process( TestkitState testkitState ) { - return Optional.ofNullable( testkitState.getTransactions().get( data.getTxId() ) ) - .map( tx -> - { - tx.close(); - return createResponse( data.getTxId() ); - } ) - .orElseThrow( () -> new RuntimeException( "Could not find transaction" ) ); + testkitState.getTransaction( data.getTxId() ).close(); + return createResponse( data.getTxId() ); } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { throw new UnsupportedOperationException(); } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java index a692c4d662..7cbc704157 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java @@ -24,11 +24,9 @@ import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import neo4j.org.testkit.backend.messages.responses.Transaction; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Getter - @Setter public class TransactionCommit implements TestkitRequest { @@ -37,22 +35,14 @@ public class TransactionCommit implements TestkitRequest @Override public TestkitResponse process( TestkitState testkitState ) { - return Optional.ofNullable( testkitState.getTransactions().get( data.getTxId() ) ) - .map( tx -> - { - tx.commit(); - return createResponse( data.getTxId() ); - } ) - .orElseThrow( () -> new RuntimeException( "Could not find transaction" ) ); + testkitState.getTransaction( data.getTxId() ).commit(); + return createResponse( data.getTxId() ); } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { - return testkitState.getAsyncTransactions().get( data.getTxId() ) - .commitAsync() - .thenApply( ignored -> createResponse( data.getTxId() ) ) - .thenApply( Optional::of ); + return testkitState.getAsyncTransaction( data.getTxId() ).thenCompose( tx -> tx.commitAsync() ).thenApply( ignored -> createResponse( data.getTxId() ) ); } private Transaction createResponse( String txId ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java index e010942288..f9be772df5 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java @@ -24,11 +24,9 @@ import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import neo4j.org.testkit.backend.messages.responses.Transaction; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Getter - @Setter public class TransactionRollback implements TestkitRequest { @@ -37,22 +35,14 @@ public class TransactionRollback implements TestkitRequest @Override public TestkitResponse process( TestkitState testkitState ) { - return Optional.ofNullable( testkitState.getTransactions().get( data.getTxId() ) ) - .map( tx -> - { - tx.rollback(); - return createResponse( data.getTxId() ); - } ) - .orElseThrow( () -> new RuntimeException( "Could not find transaction" ) ); + testkitState.getTransaction( data.getTxId() ).rollback(); + return createResponse( data.getTxId() ); } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { - return testkitState.getAsyncTransactions().get( data.getTxId() ) - .rollbackAsync() - .thenApply( ignored -> createResponse( data.getTxId() ) ) - .thenApply( Optional::of ); + return testkitState.getAsyncTransaction( data.getTxId() ).thenCompose( tx -> tx.rollbackAsync() ).thenApply( ignored -> createResponse( data.getTxId() ) ); } private Transaction createResponse( String txId ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java index 029fb15a11..d25bb2cbaa 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java @@ -28,7 +28,6 @@ import java.util.Collections; import java.util.Map; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Setter @@ -40,30 +39,24 @@ public class TransactionRun implements TestkitRequest @Override public TestkitResponse process( TestkitState testkitState ) { - return Optional.ofNullable( testkitState.getTransactions().get( data.getTxId() ) ) - .map( tx -> - tx.run( data.getCypher(), data.getParams() != null ? data.getParams() : Collections.emptyMap() ) ) - .map( result -> - { - String resultId = testkitState.newId(); - testkitState.getResults().put( resultId, result ); - return createResponse( resultId ); - } ) - .orElseThrow( () -> new RuntimeException( "Could not find transaction" ) ); + org.neo4j.driver.Result result = + testkitState.getTransaction( data.getTxId() ).run( data.getCypher(), data.getParams() != null ? data.getParams() : Collections.emptyMap() ); + String resultId = testkitState.newId(); + testkitState.getResults().put( resultId, result ); + return createResponse( resultId ); } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { - return testkitState.getAsyncTransactions().get( data.getTxId() ) - .runAsync( data.getCypher(), data.getParams() != null ? data.getParams() : Collections.emptyMap() ) - .thenApply( resultCursor -> - { - String resultId = testkitState.newId(); - testkitState.getResultCursors().put( resultId, resultCursor ); - return createResponse( resultId ); - } ) - .thenApply( Optional::of ); + return testkitState.getAsyncTransaction( data.getTxId() ) + .thenCompose( tx -> tx.runAsync( data.getCypher(), data.getParams() != null ? data.getParams() : Collections.emptyMap() )) + .thenApply( resultCursor -> + { + String resultId = testkitState.newId(); + testkitState.getResultCursors().put( resultId, resultCursor ); + return createResponse( resultId ); + } ) ; } private Result createResponse( String resultId ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java index b157907221..3cc2ba28ba 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java @@ -24,7 +24,6 @@ import neo4j.org.testkit.backend.messages.responses.Driver; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; -import java.util.Optional; import java.util.concurrent.CompletionStage; @Setter @@ -42,13 +41,12 @@ public TestkitResponse process( TestkitState testkitState ) } @Override - public CompletionStage> processAsync( TestkitState testkitState ) + public CompletionStage processAsync( TestkitState testkitState ) { String id = data.getDriverId(); return testkitState.getDrivers().get( id ) .verifyConnectivityAsync() - .thenApply( ignored -> createResponse( id ) ) - .thenApply( Optional::of ); + .thenApply( ignored -> createResponse( id ) ); } private Driver createResponse( String id ) diff --git a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java index 477f7c4abf..81f309d469 100644 --- a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java +++ b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageDeserializerTest.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import neo4j.org.testkit.backend.channel.handler.TestkitRequestResponseMapperHandler; import neo4j.org.testkit.backend.messages.requests.NewDriver; import neo4j.org.testkit.backend.messages.requests.NewSession; import neo4j.org.testkit.backend.messages.requests.SessionRun; @@ -32,7 +33,7 @@ class MessageDeserializerTest { - private static final ObjectMapper mapper = CommandProcessor.newObjectMapperFor( () -> false ); + private static final ObjectMapper mapper = TestkitRequestResponseMapperHandler.newObjectMapper(); @Test void testDeserializeNewDriver() throws JsonProcessingException diff --git a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java index b898f44b21..6e0311d784 100644 --- a/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java +++ b/testkit-backend/src/test/java/neo4j/org/testkit/backend/MessageSerializerTest.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import neo4j.org.testkit.backend.channel.handler.TestkitRequestResponseMapperHandler; import neo4j.org.testkit.backend.messages.responses.Driver; import org.junit.jupiter.api.Test; @@ -28,7 +29,7 @@ public class MessageSerializerTest { - private static final ObjectMapper mapper = CommandProcessor.newObjectMapperFor( () -> false ); + private static final ObjectMapper mapper = TestkitRequestResponseMapperHandler.newObjectMapper(); @Test void shouldSerializerNewDriverResponse() throws JsonProcessingException From 8414154e2ed494bb39309f9be01f2b49d9878bb1 Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov <11927660+injectives@users.noreply.github.com> Date: Mon, 6 Sep 2021 09:40:46 +0100 Subject: [PATCH 5/5] Add reactive backend support (#998) This update brings reactive backend support. Its scope is limited to providing partial transparent support for existing test cases. More updates are expected in future PRs. --- .../neo4j/org/testkit/backend/Runner.java | 19 +++- .../testkit/backend/RxBlockingSubscriber.java | 77 ++++++++++++++++ .../org/testkit/backend/RxSessionState.java | 39 ++++++++ .../org/testkit/backend/TestkitState.java | 25 ++++++ .../TestkitRequestProcessorHandler.java | 65 ++++++++++---- .../requests/CheckMultiDBSupport.java | 7 ++ .../messages/requests/DriverClose.java | 7 ++ .../messages/requests/GetFeatures.java | 7 ++ .../messages/requests/GetRoutingTable.java | 9 +- .../backend/messages/requests/NewDriver.java | 7 ++ .../backend/messages/requests/NewSession.java | 20 ++++- .../messages/requests/ResultConsume.java | 10 +++ .../backend/messages/requests/ResultList.java | 7 ++ .../backend/messages/requests/ResultNext.java | 43 +++++++++ .../messages/requests/RetryableNegative.java | 19 ++++ .../messages/requests/RetryablePositive.java | 8 ++ .../requests/SessionBeginTransaction.java | 27 ++++++ .../messages/requests/SessionClose.java | 8 ++ .../requests/SessionLastBookmarks.java | 8 ++ .../requests/SessionReadTransaction.java | 21 +++++ .../backend/messages/requests/SessionRun.java | 41 +++++++-- .../requests/SessionWriteTransaction.java | 21 +++++ .../backend/messages/requests/StartTest.java | 88 ++++++++++++++++++- .../requests/TestkitCallbackResult.java | 8 ++ .../messages/requests/TestkitRequest.java | 3 + .../messages/requests/TransactionClose.java | 7 ++ .../messages/requests/TransactionCommit.java | 14 ++- .../requests/TransactionRollback.java | 14 ++- .../messages/requests/TransactionRun.java | 37 ++++++-- .../messages/requests/VerifyConnectivity.java | 7 ++ testkit-tests/pom.xml | 32 +++++++ 31 files changed, 662 insertions(+), 43 deletions(-) create mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/RxBlockingSubscriber.java create mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/RxSessionState.java diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java index a35986683a..b1f09baeea 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/Runner.java @@ -34,9 +34,24 @@ public class Runner { public static void main( String[] args ) throws InterruptedException { - boolean asyncMode = args.length > 0 && args[0].equals( "async" ); + TestkitRequestProcessorHandler.BackendMode backendMode; + String modeArg = args.length > 0 ? args[0] : null; + if ( "async".equals( modeArg ) ) + { + backendMode = TestkitRequestProcessorHandler.BackendMode.ASYNC; + } + else if ( "reactive".equals( modeArg ) ) + { + backendMode = TestkitRequestProcessorHandler.BackendMode.REACTIVE; + } + else + { + backendMode = TestkitRequestProcessorHandler.BackendMode.SYNC; + } + EventLoopGroup group = new NioEventLoopGroup(); try + { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group( group ) @@ -50,7 +65,7 @@ protected void initChannel( SocketChannel channel ) channel.pipeline().addLast( new TestkitMessageInboundHandler() ); channel.pipeline().addLast( new TestkitMessageOutboundHandler() ); channel.pipeline().addLast( new TestkitRequestResponseMapperHandler() ); - channel.pipeline().addLast( new TestkitRequestProcessorHandler( asyncMode ) ); + channel.pipeline().addLast( new TestkitRequestProcessorHandler( backendMode ) ); } } ); ChannelFuture server = bootstrap.bind().sync(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/RxBlockingSubscriber.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/RxBlockingSubscriber.java new file mode 100644 index 0000000000..7658123cf0 --- /dev/null +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/RxBlockingSubscriber.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package neo4j.org.testkit.backend; + +import lombok.Getter; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import java.util.concurrent.CompletableFuture; + +public class RxBlockingSubscriber implements Subscriber +{ + @Getter + private final CompletableFuture subscriptionFuture = new CompletableFuture<>(); + private CompletableFuture> nextSignalConsumerFuture; + + public void setNextSignalConsumer( CompletableFuture nextSignalConsumer ) + { + nextSignalConsumerFuture.complete( nextSignalConsumer ); + } + + @Override + public void onSubscribe( Subscription s ) + { + nextSignalConsumerFuture = new CompletableFuture<>(); + subscriptionFuture.complete( s ); + } + + @Override + public void onNext( T t ) + { + blockUntilNextSignalConsumer().complete( t ); + } + + @Override + public void onError( Throwable t ) + { + blockUntilNextSignalConsumer().completeExceptionally( t ); + } + + @Override + public void onComplete() + { + blockUntilNextSignalConsumer().complete( null ); + } + + private CompletableFuture blockUntilNextSignalConsumer() + { + CompletableFuture nextSignalConsumer; + try + { + nextSignalConsumer = nextSignalConsumerFuture.get(); + } + catch ( Throwable throwable ) + { + throw new RuntimeException( "Failed waiting for next signal consumer", throwable ); + } + nextSignalConsumerFuture = new CompletableFuture<>(); + return nextSignalConsumer; + } +} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/RxSessionState.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/RxSessionState.java new file mode 100644 index 0000000000..0dfe5524e9 --- /dev/null +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/RxSessionState.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package neo4j.org.testkit.backend; + +import lombok.Getter; +import lombok.Setter; + +import java.util.concurrent.CompletableFuture; + +import org.neo4j.driver.reactive.RxSession; + +@Getter +@Setter +public class RxSessionState +{ + public RxSession session; + public CompletableFuture txWorkFuture; + + public RxSessionState( RxSession session ) + { + this.session = session; + } +} diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java index 535b177e2e..33671d533a 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/TestkitState.java @@ -22,6 +22,7 @@ import lombok.Getter; import neo4j.org.testkit.backend.messages.requests.TestkitCallbackResult; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.HashMap; import java.util.Map; @@ -30,12 +31,15 @@ import java.util.function.Consumer; import org.neo4j.driver.Driver; +import org.neo4j.driver.Record; import org.neo4j.driver.Result; import org.neo4j.driver.Transaction; import org.neo4j.driver.async.AsyncTransaction; import org.neo4j.driver.async.ResultCursor; import org.neo4j.driver.exceptions.Neo4jException; import org.neo4j.driver.internal.cluster.RoutingTableRegistry; +import org.neo4j.driver.reactive.RxResult; +import org.neo4j.driver.reactive.RxTransaction; @Getter public class TestkitState @@ -46,12 +50,17 @@ public class TestkitState private final Map routingTableRegistry = new HashMap<>(); private final Map sessionStates = new HashMap<>(); private final Map asyncSessionStates = new HashMap<>(); + private final Map rxSessionStates = new HashMap<>(); private final Map results = new HashMap<>(); private final Map resultCursors = new HashMap<>(); + private final Map rxResults = new HashMap<>(); + private final Map> rxResultIdToRecordSubscriber = new HashMap<>(); @Getter( AccessLevel.NONE ) private final Map transactions = new HashMap<>(); @Getter( AccessLevel.NONE ) private final Map asyncTransactions = new HashMap<>(); + @Getter( AccessLevel.NONE ) + private final Map rxTransactions = new HashMap<>(); private final Map errors = new HashMap<>(); @Getter( AccessLevel.NONE ) private final AtomicInteger idGenerator = new AtomicInteger( 0 ); @@ -101,4 +110,20 @@ public CompletableFuture getAsyncTransaction( String id ) } return CompletableFuture.completedFuture( asyncTransactions.get( id ) ); } + + public String addRxTransaction( RxTransaction transaction ) + { + String id = newId(); + this.rxTransactions.put( id, transaction ); + return id; + } + + public Mono getRxTransaction( String id ) + { + if ( !this.rxTransactions.containsKey( id ) ) + { + return Mono.error( new RuntimeException( TRANSACTION_NOT_FOUND_MESSAGE ) ); + } + return Mono.just( rxTransactions.get( id ) ); + } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java index 5060bf5428..83b97b85be 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/channel/handler/TestkitRequestProcessorHandler.java @@ -30,6 +30,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.function.BiFunction; import org.neo4j.driver.exceptions.Neo4jException; @@ -39,15 +41,24 @@ public class TestkitRequestProcessorHandler extends ChannelInboundHandlerAdapter { private final TestkitState testkitState = new TestkitState( this::writeAndFlush ); - private final BiFunction> processorImpl; + private final BiFunction> processorImpl; + // Some requests require multiple threads + private final Executor requestExecutorService = Executors.newFixedThreadPool( 10 ); private Channel channel; - public TestkitRequestProcessorHandler( boolean asyncMode ) + public TestkitRequestProcessorHandler( BackendMode backendMode ) { - if (asyncMode) { - processorImpl = (request, state) -> request.processAsync( state ); - } else { + switch ( backendMode ) + { + case ASYNC: processorImpl = TestkitRequestProcessorHandler::wrapSyncRequest; + break; + case REACTIVE: + processorImpl = ( request, state ) -> request.processRx( state ).toFuture(); + break; + default: + processorImpl = TestkitRequest::processAsync; + break; } } @@ -62,20 +73,29 @@ public void channelRegistered( ChannelHandlerContext ctx ) throws Exception public void channelRead( ChannelHandlerContext ctx, Object msg ) { // Processing is done in a separate thread to avoid blocking EventLoop because some testing logic, like resolvers support, is blocking. - CompletableFuture.supplyAsync( () -> (TestkitRequest) msg ) - .thenCompose( request -> processorImpl.apply( request, testkitState ) ) - .thenApply( response -> - { - if ( response != null ) - { - ctx.writeAndFlush( response ); - } - return null; - } ).exceptionally( throwable -> - { - ctx.writeAndFlush( createErrorResponse( throwable ) ); - return null; - } ); + requestExecutorService.execute( () -> + { + try + { + TestkitRequest request = (TestkitRequest) msg; + CompletionStage responseStage = processorImpl.apply( request, testkitState ); + responseStage.whenComplete( ( response, throwable ) -> + { + if ( throwable != null ) + { + ctx.writeAndFlush( createErrorResponse( throwable ) ); + } + else if ( response != null ) + { + ctx.writeAndFlush( response ); + } + } ); + } + catch ( Throwable throwable ) + { + ctx.writeAndFlush( createErrorResponse( throwable ) ); + } + } ); } private static CompletionStage wrapSyncRequest( TestkitRequest testkitRequest, TestkitState testkitState ) @@ -145,4 +165,11 @@ private void writeAndFlush( TestkitResponse response ) } channel.writeAndFlush( response ); } + + public enum BackendMode + { + SYNC, + ASYNC, + REACTIVE + } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java index 7ecfecf886..332280064f 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/CheckMultiDBSupport.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.MultiDBSupport; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; @@ -48,6 +49,12 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( this::createResponse ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.fromCompletionStage( processAsync( testkitState ) ); + } + private MultiDBSupport createResponse( boolean available ) { return MultiDBSupport.builder() diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java index 1017e159ec..2ba3e2f762 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/DriverClose.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Driver; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; @@ -47,6 +48,12 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( ignored -> createResponse() ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.fromCompletionStage( processAsync( testkitState ) ); + } + private Driver createResponse() { return Driver.builder().data( Driver.DriverBody.builder().id( data.getDriverId() ).build() ).build(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java index 7389f69d8d..ffed5b782c 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetFeatures.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.FeatureList; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.Arrays; import java.util.Collections; @@ -62,6 +63,12 @@ public CompletionStage processAsync( TestkitState testkitState return CompletableFuture.completedFuture( createResponse( COMMON_FEATURES ) ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.just( createResponse( COMMON_FEATURES ) ); + } + private FeatureList createResponse( Set features ) { return FeatureList.builder().data( FeatureList.FeatureListBody.builder().features( features ).build() ).build(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java index 2448c1a45d..41d2bf0d66 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/GetRoutingTable.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RoutingTable; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.Arrays; import java.util.List; @@ -78,7 +79,13 @@ public TestkitResponse process( TestkitState testkitState ) @Override public CompletionStage processAsync( TestkitState testkitState ) { - return CompletableFuture.completedFuture( process( testkitState ) ) ; + return CompletableFuture.completedFuture( process( testkitState ) ); + } + + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.just( process( testkitState ) ); } @Setter diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java index eaddb1f147..a919a10b85 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewDriver.java @@ -29,6 +29,7 @@ import neo4j.org.testkit.backend.messages.responses.ResolverResolutionRequired; import neo4j.org.testkit.backend.messages.responses.TestkitCallback; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.net.InetAddress; import java.net.URI; @@ -118,6 +119,12 @@ public CompletionStage processAsync( TestkitState testkitState return CompletableFuture.completedFuture( process( testkitState ) ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.fromCompletionStage( processAsync( testkitState ) ); + } + private ServerAddressResolver callbackResolver( TestkitState testkitState ) { return address -> diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java index 889d18377c..0f21cbd287 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/NewSession.java @@ -21,10 +21,12 @@ import lombok.Getter; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; +import neo4j.org.testkit.backend.RxSessionState; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Session; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.List; import java.util.Map; @@ -54,11 +56,18 @@ public TestkitResponse process( TestkitState testkitState ) @Override public CompletionStage processAsync( TestkitState testkitState ) { - return CompletableFuture.completedFuture( createSessionStateAndResponse( testkitState, this::createAsyncSessionState, testkitState.getAsyncSessionStates() ) ); + return CompletableFuture.completedFuture( + createSessionStateAndResponse( testkitState, this::createAsyncSessionState, testkitState.getAsyncSessionStates() ) ); } - private TestkitResponse createSessionStateAndResponse( TestkitState testkitState, BiFunction sessionStateProducer, - Map sessionStateContainer ) + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.just( createSessionStateAndResponse( testkitState, this::createRxSessionState, testkitState.getRxSessionStates() ) ); + } + + protected TestkitResponse createSessionStateAndResponse( TestkitState testkitState, BiFunction sessionStateProducer, + Map sessionStateContainer ) { Driver driver = testkitState.getDrivers().get( data.getDriverId() ); AccessMode formattedAccessMode = data.getAccessMode().equals( "r" ) ? AccessMode.READ : AccessMode.WRITE; @@ -93,6 +102,11 @@ private AsyncSessionState createAsyncSessionState( Driver driver, SessionConfig return new AsyncSessionState( driver.asyncSession( sessionConfig ) ); } + private RxSessionState createRxSessionState( Driver driver, SessionConfig sessionConfig ) + { + return new RxSessionState( driver.rxSession( sessionConfig ) ); + } + @Setter @Getter public static class NewSessionBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java index 11778a077b..fe65bbd8cc 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultConsume.java @@ -24,11 +24,13 @@ import neo4j.org.testkit.backend.messages.responses.NullRecord; import neo4j.org.testkit.backend.messages.responses.Summary; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; import org.neo4j.driver.Result; import org.neo4j.driver.exceptions.NoSuchRecordException; +import org.neo4j.driver.reactive.RxResult; @Setter @Getter @@ -58,6 +60,14 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( this::createResponse ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + RxResult result = testkitState.getRxResults().get( data.getResultId() ); + return Mono.fromDirect( result.consume() ) + .map( this::createResponse ); + } + private Summary createResponse( org.neo4j.driver.summary.ResultSummary summary ) { Summary.ServerInfo serverInfo = Summary.ServerInfo.builder() diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java index 07a3e62e2e..f0ec4d563c 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java @@ -24,6 +24,7 @@ import neo4j.org.testkit.backend.messages.responses.Record; import neo4j.org.testkit.backend.messages.responses.RecordList; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.List; import java.util.concurrent.CompletionStage; @@ -49,6 +50,12 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( this::createResponse ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + throw new UnsupportedOperationException( "Operation not supported" ); + } + private RecordList createResponse( List records ) { List mappedRecords = records.stream() diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java index d79e422f53..012d84a715 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultNext.java @@ -20,15 +20,20 @@ import lombok.Getter; import lombok.Setter; +import neo4j.org.testkit.backend.RxBlockingSubscriber; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.NullRecord; import neo4j.org.testkit.backend.messages.responses.Record; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.function.Function; import org.neo4j.driver.Result; import org.neo4j.driver.exceptions.NoSuchRecordException; +import org.neo4j.driver.reactive.RxResult; @Setter @Getter @@ -58,6 +63,44 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( record -> record != null ? createResponse( record ) : NullRecord.builder().build() ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + CompletableFuture> subscriberFuture; + String resultId = data.getResultId(); + RxBlockingSubscriber currentSubscriber = testkitState.getRxResultIdToRecordSubscriber().get( resultId ); + + if ( currentSubscriber == null ) + { + RxBlockingSubscriber subscriber = new RxBlockingSubscriber<>(); + subscriberFuture = subscriber.getSubscriptionFuture().thenApply( subscription -> + { + subscription.request( 1000 ); + return subscriber; + } ); + testkitState.getRxResultIdToRecordSubscriber().put( resultId, subscriber ); + RxResult result = testkitState.getRxResults().get( resultId ); + result.records().subscribe( subscriber ); + } + else + { + subscriberFuture = CompletableFuture.completedFuture( currentSubscriber ); + } + + CompletableFuture responseFuture = subscriberFuture + .thenApply( recordsSubscriber -> + { + CompletableFuture recordConsumer = + new CompletableFuture<>(); + recordsSubscriber.setNextSignalConsumer( recordConsumer ); + return recordConsumer; + } ) + .thenCompose( Function.identity() ) + .thenApply( record -> record != null ? createResponse( record ) : NullRecord.builder().build() ); + + return Mono.fromCompletionStage( responseFuture ); + } + private Record createResponse( org.neo4j.driver.Record record ) { return Record.builder().data( Record.RecordBody.builder().values( record ).build() ).build(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java index bde0bff0ac..c412b358ba 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryableNegative.java @@ -21,9 +21,11 @@ import lombok.Getter; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; +import neo4j.org.testkit.backend.RxSessionState; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -72,6 +74,23 @@ public CompletionStage processAsync( TestkitState testkitState return CompletableFuture.completedFuture( null ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + RxSessionState sessionState = testkitState.getRxSessionStates().get( data.getSessionId() ); + Throwable throwable; + if ( !"".equals( data.getErrorId() ) ) + { + throwable = testkitState.getErrors().get( data.getErrorId() ); + } + else + { + throwable = new RuntimeException( "Error from client in retryable tx" ); + } + sessionState.getTxWorkFuture().completeExceptionally( throwable ); + return Mono.empty(); + } + @Setter @Getter public static class RetryableNegativeBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java index 2f0676ea91..d4f5b28b70 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/RetryablePositive.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -52,6 +53,13 @@ public CompletionStage processAsync( TestkitState testkitState return CompletableFuture.completedFuture( null ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + testkitState.getRxSessionStates().get( data.getSessionId() ).getTxWorkFuture().complete( null ); + return Mono.empty(); + } + @Setter @Getter public static class RetryablePositiveBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java index c9a75aaa5e..0c12a6f61a 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionBeginTransaction.java @@ -21,10 +21,12 @@ import lombok.Getter; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; +import neo4j.org.testkit.backend.RxSessionState; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import neo4j.org.testkit.backend.messages.responses.Transaction; +import reactor.core.publisher.Mono; import java.time.Duration; import java.util.Map; @@ -34,6 +36,7 @@ import org.neo4j.driver.TransactionConfig; import org.neo4j.driver.async.AsyncSession; +import org.neo4j.driver.reactive.RxSession; @Setter @Getter @@ -86,6 +89,30 @@ public CompletionStage processAsync( TestkitState testkitState } } + @Override + public Mono processRx( TestkitState testkitState ) + { + RxSessionState sessionState = testkitState.getRxSessionStates().get( data.getSessionId() ); + if ( sessionState != null ) + { + RxSession session = sessionState.getSession(); + TransactionConfig.Builder builder = TransactionConfig.builder(); + Optional.ofNullable( data.txMeta ).ifPresent( builder::withMetadata ); + + if ( data.getTimeout() != null ) + { + builder.withTimeout( Duration.ofMillis( data.getTimeout() ) ); + } + + return Mono.fromDirect( session.beginTransaction( builder.build() ) ) + .map( tx -> transaction( testkitState.addRxTransaction( tx ) ) ); + } + else + { + return Mono.error( new RuntimeException( "Could not find session" ) ); + } + } + private Transaction transaction( String txId ) { return Transaction.builder().data( Transaction.TransactionBody.builder().id( txId ).build() ).build(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java index d942a2cff5..0bbc94e1a7 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionClose.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Session; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; @@ -47,6 +48,13 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( ignored -> createResponse() ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.fromDirect( testkitState.getRxSessionStates().get( data.getSessionId() ).getSession().close() ) + .then( Mono.just( createResponse() ) ); + } + private Session createResponse() { return Session.builder().data( Session.SessionBody.builder().id( data.getSessionId() ).build() ).build(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java index 1016a3ca41..5d4bedd22f 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionLastBookmarks.java @@ -24,6 +24,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Bookmarks; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -57,6 +58,13 @@ public CompletionStage processAsync( TestkitState testkitState return CompletableFuture.completedFuture( createResponse( bookmark ) ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + Bookmark bookmark = testkitState.getRxSessionStates().get( data.getSessionId() ).getSession().lastBookmark(); + return Mono.just( createResponse( bookmark ) ); + } + private Bookmarks createResponse( Bookmark bookmark ) { return Bookmarks.builder().data( Bookmarks.BookmarksBody.builder().bookmarks( bookmark ).build() ).build(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java index 134dfd83bd..284f7a1f56 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionReadTransaction.java @@ -21,11 +21,14 @@ import lombok.Getter; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; +import neo4j.org.testkit.backend.RxSessionState; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RetryableDone; import neo4j.org.testkit.backend.messages.responses.RetryableTry; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -37,6 +40,7 @@ import org.neo4j.driver.async.AsyncSession; import org.neo4j.driver.async.AsyncTransactionWork; import org.neo4j.driver.exceptions.Neo4jException; +import org.neo4j.driver.reactive.RxTransactionWork; @Setter @Getter @@ -75,6 +79,23 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( nothing -> retryableDone() ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + RxSessionState sessionState = testkitState.getRxSessionStates().get( data.getSessionId() ); + RxTransactionWork> workWrapper = tx -> + { + String txId = testkitState.addRxTransaction( tx ); + testkitState.getResponseWriter().accept( retryableTry( txId ) ); + CompletableFuture tryResult = new CompletableFuture<>(); + sessionState.setTxWorkFuture( tryResult ); + return Mono.fromCompletionStage( tryResult ); + }; + + return Mono.fromDirect( sessionState.getSession().readTransaction( workWrapper ) ) + .then( Mono.just( retryableDone() ) ); + } + private TransactionWork handle( TestkitState testkitState, SessionState sessionState ) { return tx -> diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java index 5122793911..3928c5b44c 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionRun.java @@ -25,6 +25,7 @@ import neo4j.org.testkit.backend.messages.requests.deserializer.TestkitCypherParamDeserializer; import neo4j.org.testkit.backend.messages.responses.Result; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.time.Duration; import java.util.Map; @@ -35,6 +36,8 @@ import org.neo4j.driver.Session; import org.neo4j.driver.TransactionConfig; import org.neo4j.driver.async.AsyncSession; +import org.neo4j.driver.reactive.RxResult; +import org.neo4j.driver.reactive.RxSession; @Setter @Getter @@ -53,10 +56,10 @@ public TestkitResponse process( TestkitState testkitState ) Optional.ofNullable( data.getTxMeta() ).ifPresent( transactionConfig::withMetadata ); Optional.ofNullable( data.getTimeout() ).ifPresent( to -> transactionConfig.withTimeout( Duration.ofMillis( to ) ) ); org.neo4j.driver.Result result = session.run( query, transactionConfig.build() ); - String newId = testkitState.newId(); - testkitState.getResults().put( newId, result ); + String id = testkitState.newId(); + testkitState.getResults().put( id, result ); - return Result.builder().data( Result.ResultBody.builder().id( newId ).build() ).build(); + return createResponse( id ); } @Override @@ -73,12 +76,38 @@ public CompletionStage processAsync( TestkitState testkitState return session.runAsync( query, transactionConfig.build() ) .thenApply( resultCursor -> { - String newId = testkitState.newId(); - testkitState.getResultCursors().put( newId, resultCursor ); - return Result.builder().data( Result.ResultBody.builder().id( newId ).build() ).build(); + String id = testkitState.newId(); + testkitState.getResultCursors().put( id, resultCursor ); + return createResponse( id ); } ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + RxSession session = testkitState.getRxSessionStates().get( data.getSessionId() ).getSession(); + Query query = Optional.ofNullable( data.params ) + .map( params -> new Query( data.cypher, data.params ) ) + .orElseGet( () -> new Query( data.cypher ) ); + TransactionConfig.Builder transactionConfig = TransactionConfig.builder(); + Optional.ofNullable( data.getTxMeta() ).ifPresent( transactionConfig::withMetadata ); + Optional.ofNullable( data.getTimeout() ).ifPresent( to -> transactionConfig.withTimeout( Duration.ofMillis( to ) ) ); + + RxResult result = session.run( query, transactionConfig.build() ); + String id = testkitState.newId(); + testkitState.getRxResults().put( id, result ); + + // The keys() method causes RUN message exchange. + // However, it does not currently report errors. + return Mono.fromDirect( result.keys() ) + .map( ignored -> createResponse( id ) ); + } + + private Result createResponse( String resultId ) + { + return Result.builder().data( Result.ResultBody.builder().id( resultId ).build() ).build(); + } + @Setter @Getter public static class SessionRunBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java index 4ceeac6a29..fda177afbd 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/SessionWriteTransaction.java @@ -21,11 +21,14 @@ import lombok.Getter; import lombok.Setter; import neo4j.org.testkit.backend.AsyncSessionState; +import neo4j.org.testkit.backend.RxSessionState; import neo4j.org.testkit.backend.SessionState; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.RetryableDone; import neo4j.org.testkit.backend.messages.responses.RetryableTry; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; import java.util.Map; import java.util.Optional; @@ -38,6 +41,7 @@ import org.neo4j.driver.async.AsyncSession; import org.neo4j.driver.async.AsyncTransactionWork; import org.neo4j.driver.exceptions.Neo4jException; +import org.neo4j.driver.reactive.RxTransactionWork; @Setter @Getter @@ -77,6 +81,23 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( nothing -> retryableDone() ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + RxSessionState sessionState = testkitState.getRxSessionStates().get( data.getSessionId() ); + RxTransactionWork> workWrapper = tx -> + { + String txId = testkitState.addRxTransaction( tx ); + testkitState.getResponseWriter().accept( retryableTry( txId ) ); + CompletableFuture tryResult = new CompletableFuture<>(); + sessionState.setTxWorkFuture( tryResult ); + return Mono.fromCompletionStage( tryResult ); + }; + + return Mono.fromDirect( sessionState.getSession().writeTransaction( workWrapper ) ) + .then( Mono.just( retryableDone() ) ); + } + private TransactionWork handle( TestkitState testkitState, SessionState sessionState ) { return tx -> diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java index ed701746c8..788464a749 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/StartTest.java @@ -24,6 +24,7 @@ import neo4j.org.testkit.backend.messages.responses.RunTest; import neo4j.org.testkit.backend.messages.responses.SkipTest; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.HashMap; import java.util.Map; @@ -35,10 +36,77 @@ public class StartTest implements TestkitRequest { private static final Map ASYNC_SKIP_PATTERN_TO_REASON = new HashMap<>(); + private static final Map REACTIVE_SKIP_PATTERN_TO_REASON = new HashMap<>(); static { - ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*.test_should_reject_server_using_verify_connectivity_bolt_3x0$", "Does not error as expected" ); + ASYNC_SKIP_PATTERN_TO_REASON.put( "^.*\\.test_should_reject_server_using_verify_connectivity_bolt_3x0$", "Does not error as expected" ); + + // V3 tests + String skipMessage = "v3 is not applicable to reactive"; + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestAuthorizationV3\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestBookmarksV3\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.NoRoutingV3\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.RoutingV3\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestProtocolVersions\\.test_should_reject_server_using_verify_connectivity_bolt_3x0$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestProtocolVersions\\.test_supports_bolt_3x0", skipMessage ); + + // Current limitations (require further investigation or bug fixing) + skipMessage = "Does not report RUN FAILURE"; + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_write_successfully_on_leader_switch_using_tx_function$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestDisconnects\\.test_disconnect_after_hello$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestDisconnects\\.test_disconnect_session_on_run$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestDisconnects\\.test_disconnect_on_tx_run$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestRetry\\..*$", "Unfinished results consumption" ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestRetryClustering\\..*$", "Unfinished results consumption" ); + skipMessage = "Does not support PULL pipelining"; + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_retry_read_tx_and_rediscovery_until_success$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_retry_read_tx_until_success_on_error$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_retry_write_tx_and_rediscovery_until_success$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_retry_write_tx_until_success_on_error$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_fail_when_reading_from_unexpectedly_interrupting_reader_using_session_run$", + skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_fail_when_reading_from_unexpectedly_interrupting_reader_using_tx_run$", + skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_fail_when_writing_on_unexpectedly_interrupting_writer_using_session_run$", + skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_fail_when_reading_from_unexpectedly_interrupting_readers_using_tx_function$", + skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_fail_when_writing_to_unexpectedly_interrupting_writers_using_tx_function$", + skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_retry_write_until_success_with_leader_change_using_tx_function$", + skipMessage ); + skipMessage = "Custom fetch size not supported"; + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.NoRouting[^.]+\\.test_should_accept_custom_fetch_size_using_driver_configuration$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.NoRouting[^.]+\\.test_should_pull_all_when_fetch_is_minus_one_using_driver_configuration", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.NoRouting[^.]+\\.test_should_pull_custom_size_and_then_all_using_session_configuration$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.NoRouting[^.]+\\.test_should_accept_custom_fetch_size_using_session_configuration$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestIterationSessionRun\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestIterationTxRun\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestSessionRun\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestTxRun\\.test_rollback_tx_on_session_close_consumed_result$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.NoRouting[^.]+\\.test_should_error_on_database_shutdown_using_tx_run$", "Session close throws error" ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_retry_write_until_success_with_leader_shutdown_during_tx_using_tx_function$", + "Commit failure leaks outside function" ); + skipMessage = "Requires investigation"; + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestProtocolVersions\\.test_server_agent", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestProtocolVersions\\.test_server_version", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestProtocolVersions\\.test_supports_bolt_[^.]+$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestAuthorizationV4x1\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestAuthorizationV4x3\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestNoRoutingAuthorization\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestOptimizations\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestDirectConnectionRecvTimeout\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestRoutingConnectionRecvTimeout\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_successfully_acquire_rt_when_router_ip_changes$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.Routing[^.]+\\.test_should_revert_to_initial_router_if_known_router_throws_protocol_errors$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestRoutingConnectionRecvTimeout\\.test_timeout$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestRoutingConnectionRecvTimeout\\.test_timeout_unmanaged_tx$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestDisconnects\\.test_disconnect_session_on_tx_commit$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestDisconnects\\.test_fail_on_reset$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestSessionRunParameters\\..*$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestTxRun\\.test_rollback_tx_on_session_close_unfinished_result$", skipMessage ); + REACTIVE_SKIP_PATTERN_TO_REASON.put( "^.*\\.TestTxRun\\.test_rollback_tx_on_session_close_untouched_result$", skipMessage ); } private StartTestBody data; @@ -67,6 +135,24 @@ public CompletionStage processAsync( TestkitState testkitState return CompletableFuture.completedFuture( testkitResponse ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + TestkitResponse testkitResponse = REACTIVE_SKIP_PATTERN_TO_REASON + .entrySet() + .stream() + .filter( entry -> data.getTestName().matches( entry.getKey() ) ) + .findFirst() + .map( entry -> (TestkitResponse) SkipTest.builder() + .data( SkipTest.SkipTestBody.builder() + .reason( entry.getValue() ) + .build() ) + .build() ) + .orElseGet( () -> RunTest.builder().build() ); + + return Mono.fromCompletionStage( CompletableFuture.completedFuture( testkitResponse ) ); + } + @Setter @Getter public static class StartTestBody diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java index b622c21b97..0a9d0ca0ba 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitCallbackResult.java @@ -21,6 +21,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitCallback; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -45,4 +46,11 @@ default CompletionStage processAsync( TestkitState testkitState testkitState.getCallbackIdToFuture().get( getCallbackId() ).complete( this ); return CompletableFuture.completedFuture( null ); } + + @Override + default Mono processRx( TestkitState testkitState ) + { + testkitState.getCallbackIdToFuture().get( getCallbackId() ).complete( this ); + return Mono.empty(); + } } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java index e9348fd94e..96ba563352 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TestkitRequest.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; @@ -46,4 +47,6 @@ public interface TestkitRequest TestkitResponse process( TestkitState testkitState ); CompletionStage processAsync( TestkitState testkitState ); + + Mono processRx( TestkitState testkitState ); } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java index 649d69cbe3..ef2ccddf13 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionClose.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import neo4j.org.testkit.backend.messages.responses.Transaction; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; @@ -45,6 +46,12 @@ public CompletionStage processAsync( TestkitState testkitState throw new UnsupportedOperationException(); } + @Override + public Mono processRx( TestkitState testkitState ) + { + throw new UnsupportedOperationException( "Operation not supported" ); + } + private Transaction createResponse( String txId ) { return Transaction.builder().data( Transaction.TransactionBody.builder().id( txId ).build() ).build(); diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java index 7cbc704157..eb76d4b650 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionCommit.java @@ -23,9 +23,12 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import neo4j.org.testkit.backend.messages.responses.Transaction; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; +import org.neo4j.driver.async.AsyncTransaction; + @Getter @Setter public class TransactionCommit implements TestkitRequest @@ -42,7 +45,16 @@ public TestkitResponse process( TestkitState testkitState ) @Override public CompletionStage processAsync( TestkitState testkitState ) { - return testkitState.getAsyncTransaction( data.getTxId() ).thenCompose( tx -> tx.commitAsync() ).thenApply( ignored -> createResponse( data.getTxId() ) ); + return testkitState.getAsyncTransaction( data.getTxId() ).thenCompose( AsyncTransaction::commitAsync ) + .thenApply( ignored -> createResponse( data.getTxId() ) ); + } + + @Override + public Mono processRx( TestkitState testkitState ) + { + return testkitState.getRxTransaction( data.getTxId() ) + .flatMap( tx -> Mono.fromDirect( tx.commit() ) ) + .then( Mono.just( createResponse( data.getTxId() ) ) ); } private Transaction createResponse( String txId ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java index f9be772df5..c695f1d870 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRollback.java @@ -23,9 +23,12 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; import neo4j.org.testkit.backend.messages.responses.Transaction; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; +import org.neo4j.driver.async.AsyncTransaction; + @Getter @Setter public class TransactionRollback implements TestkitRequest @@ -42,7 +45,16 @@ public TestkitResponse process( TestkitState testkitState ) @Override public CompletionStage processAsync( TestkitState testkitState ) { - return testkitState.getAsyncTransaction( data.getTxId() ).thenCompose( tx -> tx.rollbackAsync() ).thenApply( ignored -> createResponse( data.getTxId() ) ); + return testkitState.getAsyncTransaction( data.getTxId() ).thenCompose( AsyncTransaction::rollbackAsync ) + .thenApply( ignored -> createResponse( data.getTxId() ) ); + } + + @Override + public Mono processRx( TestkitState testkitState ) + { + return testkitState.getRxTransaction( data.getTxId() ) + .flatMap( tx -> Mono.fromDirect( tx.rollback() ) ) + .then( Mono.just( createResponse( data.getTxId() ) ) ); } private Transaction createResponse( String txId ) diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java index d25bb2cbaa..f61b2d7824 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/TransactionRun.java @@ -25,16 +25,19 @@ import neo4j.org.testkit.backend.messages.requests.deserializer.TestkitCypherParamDeserializer; import neo4j.org.testkit.backend.messages.responses.Result; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.Collections; import java.util.Map; import java.util.concurrent.CompletionStage; +import org.neo4j.driver.reactive.RxResult; + @Setter @Getter public class TransactionRun implements TestkitRequest { - private TransactionRunBody data; + protected TransactionRunBody data; @Override public TestkitResponse process( TestkitState testkitState ) @@ -50,16 +53,32 @@ public TestkitResponse process( TestkitState testkitState ) public CompletionStage processAsync( TestkitState testkitState ) { return testkitState.getAsyncTransaction( data.getTxId() ) - .thenCompose( tx -> tx.runAsync( data.getCypher(), data.getParams() != null ? data.getParams() : Collections.emptyMap() )) - .thenApply( resultCursor -> - { - String resultId = testkitState.newId(); - testkitState.getResultCursors().put( resultId, resultCursor ); - return createResponse( resultId ); - } ) ; + .thenCompose( tx -> tx.runAsync( data.getCypher(), data.getParams() != null ? data.getParams() : Collections.emptyMap() ) ) + .thenApply( resultCursor -> + { + String resultId = testkitState.newId(); + testkitState.getResultCursors().put( resultId, resultCursor ); + return createResponse( resultId ); + } ); + } + + @Override + public Mono processRx( TestkitState testkitState ) + { + String resultId = testkitState.newId(); + return testkitState.getRxTransaction( data.getTxId() ) + .flatMap( tx -> + { + RxResult result = tx.run( data.getCypher(), data.getParams() != null ? data.getParams() : Collections.emptyMap() ); + testkitState.getRxResults().put( resultId, result ); + // The keys() method causes RUN message exchange. + // However, it does not currently report errors. + return Mono.fromDirect( result.keys() ); + } ) + .map( ignored -> createResponse( resultId ) ); } - private Result createResponse( String resultId ) + protected Result createResponse( String resultId ) { return Result.builder().data( Result.ResultBody.builder().id( resultId ).build() ).build(); } diff --git a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java index 3cc2ba28ba..7a03d43ae8 100644 --- a/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/VerifyConnectivity.java @@ -23,6 +23,7 @@ import neo4j.org.testkit.backend.TestkitState; import neo4j.org.testkit.backend.messages.responses.Driver; import neo4j.org.testkit.backend.messages.responses.TestkitResponse; +import reactor.core.publisher.Mono; import java.util.concurrent.CompletionStage; @@ -49,6 +50,12 @@ public CompletionStage processAsync( TestkitState testkitState .thenApply( ignored -> createResponse( id ) ); } + @Override + public Mono processRx( TestkitState testkitState ) + { + return Mono.fromCompletionStage( processAsync( testkitState ) ); + } + private Driver createResponse( String id ) { return Driver.builder().data( Driver.DriverBody.builder().id( id ).build() ).build(); diff --git a/testkit-tests/pom.xml b/testkit-tests/pom.xml index da3c9ae51f..0804f3702b 100644 --- a/testkit-tests/pom.xml +++ b/testkit-tests/pom.xml @@ -24,6 +24,9 @@ --tests TESTKIT_TESTS INTEGRATION_TESTS STUB_TESTS STRESS_TESTS TLS_TESTS 7200000 %a-async + %a-rx + + 0.36.1 true @@ -73,6 +76,7 @@ java ${rootDir} true + ${testkit.debug.reqres} @@ -137,6 +141,34 @@ + + + run-testkit-rx + integration-test + + + start + + + + + tklnchr + + ${testkit.rx.name.pattern} + + ${project.build.directory}/testkit-rx + reactive + + --configs 4.2-cluster,4.0-community,4.1-enterprise ${testkit.args} + + + ${testkit.rx.name.pattern}> + + + + + + remove-testkit-launcher post-integration-test