From 61e2706112dba543e9bbbdc03b207c3fba20337f Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov <11927660+injectives@users.noreply.github.com> Date: Thu, 19 Aug 2021 21:25:21 +0100 Subject: [PATCH] Migrate tests from Java Driver to Testkit (#990) (#991) New features: - `Temporary:ResultList` Migrated tests: - shouldHandleLeaderSwitchAndRetryWhenWritingInTxFunctionAsync -> test_should_write_successfully_on_leader_switch_using_tx_function (existing test, bolt bump to 4.1) - shouldOnlyPullRecordsWhenNeededAsyncSession -> test_should_accept_custom_fetch_size_using_session_configuration (existing test, bolt bump to 4.1) - shouldPullAllRecordsOnListAsyncWhenOverWatermark -> test_should_pull_custom_size_and_then_all_using_session_configuration --- .../integration/RoutingDriverBoltKitIT.java | 39 ---------- .../internal/DirectDriverBoltKitIT.java | 53 -------------- ...ble_to_write_server_tx_func_retries.script | 25 ------- .../streaming_records_v4_buffering.script | 19 ----- .../streaming_records_v4_list_async.script | 23 ------ .../messages/requests/GetFeatures.java | 3 +- .../backend/messages/requests/ResultList.java | 73 +++++++++++++++++++ .../messages/requests/TestkitRequest.java | 3 +- .../messages/responses/RecordList.java | 47 ++++++++++++ 9 files changed, 124 insertions(+), 161 deletions(-) delete mode 100644 driver/src/test/resources/not_able_to_write_server_tx_func_retries.script delete mode 100644 driver/src/test/resources/streaming_records_v4_buffering.script delete mode 100644 driver/src/test/resources/streaming_records_v4_list_async.script create mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java create mode 100644 testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RecordList.java diff --git a/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitIT.java b/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitIT.java index 196ec8bee6..ccad42b29f 100644 --- a/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitIT.java +++ b/driver/src/test/java/org/neo4j/driver/integration/RoutingDriverBoltKitIT.java @@ -27,15 +27,12 @@ import java.io.IOException; import java.net.URI; -import java.util.List; import java.util.concurrent.TimeUnit; import org.neo4j.driver.Config; import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; import org.neo4j.driver.Record; -import org.neo4j.driver.async.AsyncSession; -import org.neo4j.driver.internal.util.Futures; import org.neo4j.driver.net.ServerAddress; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.reactive.RxResult; @@ -43,7 +40,6 @@ import org.neo4j.driver.util.StubServer; import org.neo4j.driver.util.StubServerController; -import static java.util.Arrays.asList; import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.junit.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -79,41 +75,6 @@ public void killServers() stubController.reset(); } - // Async is not currently supported in testkit. - @Test - void shouldHandleLeaderSwitchAndRetryWhenWritingInTxFunctionAsync() throws IOException, InterruptedException - { - // Given - StubServer server = stubController.startStub( "acquire_endpoints_twice_v4.script", 9001 ); - - // START a write server that fails on the first write attempt but then succeeds on the second - StubServer writeServer = stubController.startStub( "not_able_to_write_server_tx_func_retries.script", 9007 ); - URI uri = URI.create( "neo4j://127.0.0.1:9001" ); - - Driver driver = GraphDatabase.driver( uri, Config.builder().withMaxTransactionRetryTime( 1, TimeUnit.MILLISECONDS ).build() ); - AsyncSession session = driver.asyncSession( builder().withDatabase( "mydatabase" ).build() ); - List names = Futures.blockingGet( session.writeTransactionAsync( - tx -> tx.runAsync( "RETURN 1" ) - .thenComposeAsync( ignored -> { - try - { - Thread.sleep( 100 ); - } - catch ( InterruptedException ex ) - { - } - return tx.runAsync( "MATCH (n) RETURN n.name" ); - } ) - .thenComposeAsync( cursor -> cursor.listAsync( RoutingDriverBoltKitIT::extractNameField ) ) ) ); - - assertEquals( asList( "Foo", "Bar" ), names ); - - // Finally - driver.close(); - assertThat( server.exitStatus(), equalTo( 0 ) ); - assertThat( writeServer.exitStatus(), equalTo( 0 ) ); - } - private static String extractNameField( Record record ) { return record.get( 0 ).asString(); diff --git a/driver/src/test/java/org/neo4j/driver/internal/DirectDriverBoltKitIT.java b/driver/src/test/java/org/neo4j/driver/internal/DirectDriverBoltKitIT.java index 3fb15a5d57..095d501dae 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/DirectDriverBoltKitIT.java +++ b/driver/src/test/java/org/neo4j/driver/internal/DirectDriverBoltKitIT.java @@ -25,24 +25,18 @@ import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import java.util.ArrayList; import java.util.List; import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; -import org.neo4j.driver.async.AsyncSession; -import org.neo4j.driver.async.ResultCursor; import org.neo4j.driver.reactive.RxResult; import org.neo4j.driver.reactive.RxSession; import org.neo4j.driver.util.StubServer; import org.neo4j.driver.util.StubServerController; -import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.neo4j.driver.SessionConfig.builder; import static org.neo4j.driver.util.StubServer.INSECURE_CONFIG; -import static org.neo4j.driver.util.TestUtil.await; class DirectDriverBoltKitIT { @@ -80,53 +74,6 @@ void shouldStreamingRecordsInBatchesRx() throws Exception } } - @Test - void shouldOnlyPullRecordsWhenNeededAsyncSession() throws Exception - { - StubServer server = stubController.startStub( "streaming_records_v4_buffering.script", 9001 ); - try - { - try ( Driver driver = GraphDatabase.driver( "bolt://localhost:9001", INSECURE_CONFIG ) ) - { - AsyncSession session = driver.asyncSession( builder().withFetchSize( 2 ).build() ); - - ArrayList resultList = new ArrayList<>(); - - await( session.runAsync( "MATCH (n) RETURN n.name" ) - .thenCompose( resultCursor -> - resultCursor.forEachAsync( record -> resultList.add( record.get( 0 ).asString() ) ) ) ); - - assertEquals( resultList, asList( "Bob", "Alice", "Tina", "Frank", "Daisy", "Clive" ) ); - } - } - finally - { - assertEquals( 0, server.exitStatus() ); - } - } - - @Test - void shouldPullAllRecordsOnListAsyncWhenOverWatermark() throws Exception - { - StubServer server = stubController.startStub( "streaming_records_v4_list_async.script", 9001 ); - try - { - try ( Driver driver = GraphDatabase.driver( "bolt://localhost:9001", INSECURE_CONFIG ) ) - { - AsyncSession session = driver.asyncSession( builder().withFetchSize( 10 ).build() ); - - ResultCursor cursor = await( session.runAsync( "MATCH (n) RETURN n.name" ) ); - List records = await( cursor.listAsync( record -> record.get( 0 ).asString() ) ); - - assertEquals( records, asList( "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L" ) ); - } - } - finally - { - assertEquals( 0, server.exitStatus() ); - } - } - @Test void shouldDiscardIfPullNotFinished() throws Throwable { diff --git a/driver/src/test/resources/not_able_to_write_server_tx_func_retries.script b/driver/src/test/resources/not_able_to_write_server_tx_func_retries.script deleted file mode 100644 index 447bcbf7fb..0000000000 --- a/driver/src/test/resources/not_able_to_write_server_tx_func_retries.script +++ /dev/null @@ -1,25 +0,0 @@ -!: BOLT 4 -!: AUTO RESET -!: AUTO BEGIN -!: AUTO HELLO -!: AUTO GOODBYE -!: AUTO ROLLBACK - -C: RUN "RETURN 1" {} {} - PULL {"n": 1000} -S: FAILURE {"code": "Neo.ClientError.Cluster.NotALeader", "message": "blabla"} - IGNORED -C: RUN "RETURN 1" {} {} - PULL {"n": 1000} -S: SUCCESS {"fields": ["1"]} - RECORD [1] - SUCCESS {} -C: RUN "MATCH (n) RETURN n.name" {} {} - PULL {"n": 1000} -S: SUCCESS {"fields": ["n.name"]} - RECORD ["Foo"] - RECORD ["Bar"] - SUCCESS {} -C: COMMIT -S: SUCCESS {"bookmark": "NewBookmark"} - diff --git a/driver/src/test/resources/streaming_records_v4_buffering.script b/driver/src/test/resources/streaming_records_v4_buffering.script deleted file mode 100644 index 2067657c16..0000000000 --- a/driver/src/test/resources/streaming_records_v4_buffering.script +++ /dev/null @@ -1,19 +0,0 @@ -!: BOLT 4 -!: AUTO RESET -!: AUTO HELLO -!: AUTO GOODBYE - -C: RUN "MATCH (n) RETURN n.name" {} {} - PULL { "n": 2 } -S: SUCCESS {"fields": ["n.name"]} - RECORD ["Bob"] - RECORD ["Alice"] - SUCCESS {"has_more": true} -C: PULL { "n": 2 } -S: RECORD ["Tina"] - RECORD ["Frank"] - SUCCESS {"has_more": true} -C: PULL { "n": 2 } -S: RECORD ["Daisy"] - RECORD ["Clive"] - SUCCESS {} \ No newline at end of file diff --git a/driver/src/test/resources/streaming_records_v4_list_async.script b/driver/src/test/resources/streaming_records_v4_list_async.script deleted file mode 100644 index 95ea02159f..0000000000 --- a/driver/src/test/resources/streaming_records_v4_list_async.script +++ /dev/null @@ -1,23 +0,0 @@ -!: BOLT 4 -!: AUTO RESET -!: AUTO HELLO -!: AUTO GOODBYE - -C: RUN "MATCH (n) RETURN n.name" {} {} - PULL { "n": 10 } -S: SUCCESS {"fields": ["n.name"]} - RECORD ["A"] - RECORD ["B"] - RECORD ["C"] - RECORD ["D"] - RECORD ["E"] - RECORD ["F"] - RECORD ["G"] - RECORD ["H"] - RECORD ["I"] - RECORD ["J"] - SUCCESS {"has_more": true} -C: PULL { "n": -1 } -S: RECORD ["K"] - RECORD ["L"] - SUCCESS {} \ No newline at end of file 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 c25313fb22..c423500d61 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 @@ -43,7 +43,8 @@ public class GetFeatures implements TestkitRequest "Optimization:PullPipelining", "ConfHint:connection.recv_timeout_seconds", "Temporary:DriverFetchSize", - "Temporary:DriverMaxTxRetryTime" + "Temporary:DriverMaxTxRetryTime", + "Temporary:ResultList" ) ); private static final Set SYNC_FEATURES = new HashSet<>( Collections.singletonList( 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 new file mode 100644 index 0000000000..0e399b6cd9 --- /dev/null +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/requests/ResultList.java @@ -0,0 +1,73 @@ +/* + * 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 lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import neo4j.org.testkit.backend.TestkitState; +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 java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletionStage; +import java.util.stream.Collectors; + +@Setter +@Getter +@NoArgsConstructor +public class ResultList implements TestkitRequest +{ + private ResultListBody data; + + @Override + public TestkitResponse process( TestkitState testkitState ) + { + return createResponse( testkitState.getResults().get( data.getResultId() ).list() ); + } + + @Override + public CompletionStage> processAsync( TestkitState testkitState ) + { + return testkitState.getResultCursors().get( data.getResultId() ) + .listAsync() + .thenApply( this::createResponse ) + .thenApply( Optional::of ); + } + + private RecordList createResponse( List records ) + { + List mappedRecords = records.stream() + .map( record -> Record.RecordBody.builder().values( record ).build() ) + .collect( Collectors.toList() ); + return RecordList.builder() + .data( RecordList.RecordListBody.builder().records( mappedRecords ).build() ) + .build(); + } + + @Setter + @Getter + @NoArgsConstructor + public static class ResultListBody + { + private String resultId; + } +} 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 52cd16590c..e15e25054e 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 @@ -39,7 +39,8 @@ @JsonSubTypes.Type( ResolverResolutionCompleted.class ), @JsonSubTypes.Type( CheckMultiDBSupport.class ), @JsonSubTypes.Type( DomainNameResolutionCompleted.class ), @JsonSubTypes.Type( StartTest.class ), @JsonSubTypes.Type( TransactionRollback.class ), @JsonSubTypes.Type( GetFeatures.class ), - @JsonSubTypes.Type( GetRoutingTable.class ), @JsonSubTypes.Type( TransactionClose.class ) + @JsonSubTypes.Type( GetRoutingTable.class ), @JsonSubTypes.Type( TransactionClose.class ), + @JsonSubTypes.Type( ResultList.class ) } ) public interface TestkitRequest { 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 new file mode 100644 index 0000000000..f3e531ead7 --- /dev/null +++ b/testkit-backend/src/main/java/neo4j/org/testkit/backend/messages/responses/RecordList.java @@ -0,0 +1,47 @@ +/* + * 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 lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Setter +@Getter +@Builder +public class RecordList implements TestkitResponse +{ + private final RecordListBody data; + + @Override + public String testkitName() + { + return "RecordList"; + } + + @Setter + @Getter + @Builder + public static class RecordListBody + { + private final List records; + } +}