From f0f0a4d7dd5abe35ce968ff36cf25e1a46cf6779 Mon Sep 17 00:00:00 2001 From: Gregory Woods Date: Mon, 21 Sep 2020 09:03:43 +0100 Subject: [PATCH] Adding bolt v4.2 handshake. --- .../async/connection/BoltProtocolUtil.java | 7 +- .../internal/messaging/BoltProtocol.java | 6 +- .../messaging/v42/BoltProtocolV42.java | 38 +++++++++ .../driver/internal/util/ServerVersion.java | 5 ++ .../connection/BoltProtocolUtilTest.java | 9 +-- .../connection/HandshakeHandlerTest.java | 77 ++++++++++--------- .../loadbalancing/LoadBalancerTest.java | 5 +- .../messaging/BoltProtocolVersionTest.java | 2 +- .../messaging/v42/BoltProtocolV42Test.java | 31 ++++++++ .../internal/util/ServerVersionTest.java | 2 + .../java/org/neo4j/driver/util/TestUtil.java | 3 +- 11 files changed, 133 insertions(+), 52 deletions(-) create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java b/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java index 065837b762..bc191a9434 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java @@ -21,11 +21,10 @@ import io.netty.buffer.ByteBuf; import org.neo4j.driver.internal.messaging.BoltProtocolVersion; -import org.neo4j.driver.internal.messaging.v1.BoltProtocolV1; -import org.neo4j.driver.internal.messaging.v2.BoltProtocolV2; import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3; import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import static io.netty.buffer.Unpooled.copyInt; import static io.netty.buffer.Unpooled.unreleasableBuffer; @@ -42,10 +41,10 @@ public final class BoltProtocolUtil private static final ByteBuf HANDSHAKE_BUF = unreleasableBuffer( copyInt( BOLT_MAGIC_PREAMBLE, + BoltProtocolV42.VERSION.toInt(), BoltProtocolV41.VERSION.toInt(), BoltProtocolV4.VERSION.toInt(), - BoltProtocolV3.VERSION.toInt(), - 0 ) ).asReadOnly(); + BoltProtocolV3.VERSION.toInt() ) ).asReadOnly(); private static final String HANDSHAKE_STRING = createHandshakeString(); diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java index 713123ffc9..7a75492b64 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java @@ -21,7 +21,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelPromise; -import java.util.Map; import java.util.concurrent.CompletionStage; import org.neo4j.driver.AuthToken; @@ -30,7 +29,6 @@ import org.neo4j.driver.Session; import org.neo4j.driver.Transaction; import org.neo4j.driver.TransactionConfig; -import org.neo4j.driver.Value; import org.neo4j.driver.exceptions.ClientException; import org.neo4j.driver.internal.BookmarkHolder; import org.neo4j.driver.internal.InternalBookmark; @@ -42,6 +40,7 @@ import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3; import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import org.neo4j.driver.internal.spi.Connection; import static org.neo4j.driver.internal.async.connection.ChannelAttributes.protocolVersion; @@ -173,6 +172,9 @@ else if ( BoltProtocolV4.VERSION.equals( version ) ) } else if ( BoltProtocolV41.VERSION.equals( version ) ) { return BoltProtocolV41.INSTANCE; + } else if ( BoltProtocolV42.VERSION.equals( version ) ) + { + return BoltProtocolV42.INSTANCE; } throw new ClientException( "Unknown protocol version: " + version ); } diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42.java new file mode 100644 index 0000000000..db9e603541 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2020 "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 org.neo4j.driver.internal.messaging.v42; + +import org.neo4j.driver.internal.messaging.BoltProtocol; +import org.neo4j.driver.internal.messaging.BoltProtocolVersion; +import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; + +/** + * Bolt V4.2 is identical to V4.1 + */ +public class BoltProtocolV42 extends BoltProtocolV41 +{ + public static final BoltProtocolVersion VERSION = new BoltProtocolVersion( 4, 2 ); + public static final BoltProtocol INSTANCE = new BoltProtocolV42(); + + @Override + public BoltProtocolVersion version() + { + return VERSION; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/util/ServerVersion.java b/driver/src/main/java/org/neo4j/driver/internal/util/ServerVersion.java index 245949a397..b5c3814922 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/util/ServerVersion.java +++ b/driver/src/main/java/org/neo4j/driver/internal/util/ServerVersion.java @@ -27,6 +27,7 @@ import org.neo4j.driver.internal.messaging.BoltProtocolVersion; import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import static java.lang.Integer.compare; @@ -34,6 +35,7 @@ public class ServerVersion { public static final String NEO4J_PRODUCT = "Neo4j"; + public static final ServerVersion v4_2_0 = new ServerVersion( NEO4J_PRODUCT, 4, 2, 0 ); public static final ServerVersion v4_1_0 = new ServerVersion( NEO4J_PRODUCT, 4, 1, 0 ); public static final ServerVersion v4_0_0 = new ServerVersion( NEO4J_PRODUCT, 4, 0, 0 ); public static final ServerVersion v3_5_0 = new ServerVersion( NEO4J_PRODUCT, 3, 5, 0 ); @@ -188,6 +190,9 @@ public static ServerVersion fromBoltProtocolVersion( BoltProtocolVersion protoco else if ( BoltProtocolV41.VERSION.equals( protocolVersion ) ) { return ServerVersion.v4_1_0; + } else if ( BoltProtocolV42.VERSION.equals( protocolVersion ) ) + { + return ServerVersion.v4_2_0; } return ServerVersion.vInDev; diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java index a37668bb69..4657e31fc8 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtilTest.java @@ -22,11 +22,10 @@ import io.netty.buffer.Unpooled; import org.junit.jupiter.api.Test; -import org.neo4j.driver.internal.messaging.v1.BoltProtocolV1; -import org.neo4j.driver.internal.messaging.v2.BoltProtocolV2; import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3; import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.neo4j.driver.internal.async.connection.BoltProtocolUtil.BOLT_MAGIC_PREAMBLE; @@ -44,15 +43,15 @@ void shouldReturnHandshakeBuf() { assertByteBufContains( handshakeBuf(), - BOLT_MAGIC_PREAMBLE, BoltProtocolV41.VERSION.toInt(), BoltProtocolV4.VERSION.toInt(), - BoltProtocolV3.VERSION.toInt(), 0 + BOLT_MAGIC_PREAMBLE, BoltProtocolV42.VERSION.toInt(), BoltProtocolV41.VERSION.toInt(), + BoltProtocolV4.VERSION.toInt(), BoltProtocolV3.VERSION.toInt() ); } @Test void shouldReturnHandshakeString() { - assertEquals( "[0x6060b017, 260, 4, 3, 0]", handshakeString() ); + assertEquals( "[0x6060b017, 516, 260, 4, 3]", handshakeString() ); } @Test diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeHandlerTest.java index b31513013d..90e3d5f0a2 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/connection/HandshakeHandlerTest.java @@ -25,8 +25,12 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.io.IOException; +import java.util.stream.Stream; import javax.net.ssl.SSLHandshakeException; import org.neo4j.driver.Logging; @@ -40,10 +44,12 @@ import org.neo4j.driver.internal.async.outbound.OutboundMessageHandler; import org.neo4j.driver.internal.messaging.BoltProtocolVersion; import org.neo4j.driver.internal.messaging.MessageFormat; -import org.neo4j.driver.internal.messaging.v1.BoltProtocolV1; -import org.neo4j.driver.internal.messaging.v1.MessageFormatV1; -import org.neo4j.driver.internal.messaging.v2.BoltProtocolV2; -import org.neo4j.driver.internal.messaging.v2.MessageFormatV2; +import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3; +import org.neo4j.driver.internal.messaging.v3.MessageFormatV3; +import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; +import org.neo4j.driver.internal.messaging.v4.MessageFormatV4; +import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import org.neo4j.driver.internal.util.ErrorUtil; import static io.netty.buffer.Unpooled.copyInt; @@ -54,6 +60,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.neo4j.driver.internal.async.connection.BoltProtocolUtil.NO_PROTOCOL_VERSION; import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setMessageDispatcher; import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING; @@ -187,16 +194,33 @@ void shouldTranslateSSLHandshakeException() assertNull( await( channel.closeFuture() ) ); } - @Test - void shouldSelectProtocolV1WhenServerSuggests() + @ParameterizedTest + @MethodSource( "protocolVersions" ) + public void testProtocolSelection( BoltProtocolVersion protocolVersion, Class expectedMessageFormatClass ) { - testProtocolSelection( BoltProtocolV1.VERSION, MessageFormatV1.class ); - } + ChannelPromise handshakeCompletedPromise = channel.newPromise(); + MemorizingChannelPipelineBuilder pipelineBuilder = new MemorizingChannelPipelineBuilder(); + HandshakeHandler handler = newHandler( pipelineBuilder, handshakeCompletedPromise ); + channel.pipeline().addLast( handler ); - @Test - void shouldSelectProtocolV2WhenServerSuggests() - { - testProtocolSelection( BoltProtocolV2.VERSION, MessageFormatV2.class ); + channel.pipeline().fireChannelRead( copyInt( protocolVersion.toInt() ) ); + + // expected message format should've been used + assertThat( pipelineBuilder.usedMessageFormat, instanceOf( expectedMessageFormatClass ) ); + + // handshake handler itself should be removed + assertNull( channel.pipeline().get( HandshakeHandler.class ) ); + + // all inbound handlers should be set + assertNotNull( channel.pipeline().get( ChunkDecoder.class ) ); + assertNotNull( channel.pipeline().get( MessageDecoder.class ) ); + assertNotNull( channel.pipeline().get( InboundMessageHandler.class ) ); + + // all outbound handlers should be set + assertNotNull( channel.pipeline().get( OutboundMessageHandler.class ) ); + + // promise should be successful + assertNull( await( handshakeCompletedPromise ) ); } @Test @@ -254,31 +278,12 @@ private void testFailure( BoltProtocolVersion serverSuggestedVersion, String exp assertNull( await( channel.closeFuture() ) ); } - private void testProtocolSelection( BoltProtocolVersion protocolVersion, Class expectedMessageFormatClass ) + private static Stream protocolVersions() { - ChannelPromise handshakeCompletedPromise = channel.newPromise(); - MemorizingChannelPipelineBuilder pipelineBuilder = new MemorizingChannelPipelineBuilder(); - HandshakeHandler handler = newHandler( pipelineBuilder, handshakeCompletedPromise ); - channel.pipeline().addLast( handler ); - - channel.pipeline().fireChannelRead( copyInt( protocolVersion.toInt() ) ); - - // expected message format should've been used - assertThat( pipelineBuilder.usedMessageFormat, instanceOf( expectedMessageFormatClass ) ); - - // handshake handler itself should be removed - assertNull( channel.pipeline().get( HandshakeHandler.class ) ); - - // all inbound handlers should be set - assertNotNull( channel.pipeline().get( ChunkDecoder.class ) ); - assertNotNull( channel.pipeline().get( MessageDecoder.class ) ); - assertNotNull( channel.pipeline().get( InboundMessageHandler.class ) ); - - // all outbound handlers should be set - assertNotNull( channel.pipeline().get( OutboundMessageHandler.class ) ); - - // promise should be successful - assertNull( await( handshakeCompletedPromise ) ); + return Stream.of( arguments( BoltProtocolV3.VERSION, MessageFormatV3.class ), + arguments( BoltProtocolV4.VERSION, MessageFormatV4.class ), + arguments( BoltProtocolV41.VERSION, MessageFormatV4.class ), + arguments( BoltProtocolV42.VERSION, MessageFormatV4.class ) ); } private static HandshakeHandler newHandler( ChannelPromise handshakeCompletedPromise ) diff --git a/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancerTest.java b/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancerTest.java index a780028d6f..0d911d7445 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/cluster/loadbalancing/LoadBalancerTest.java @@ -47,8 +47,7 @@ import org.neo4j.driver.internal.cluster.RoutingTableHandler; import org.neo4j.driver.internal.cluster.RoutingTableRegistry; import org.neo4j.driver.internal.messaging.BoltProtocol; -import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; -import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.spi.ConnectionPool; import org.neo4j.driver.internal.util.FakeClock; @@ -395,7 +394,7 @@ private static Connection newBoltV4Connection( BoltServerAddress address ) { Connection connection = mock( Connection.class ); when( connection.serverAddress() ).thenReturn( address ); - when( connection.protocol() ).thenReturn( BoltProtocol.forVersion( BoltProtocolV41.VERSION ) ); + when( connection.protocol() ).thenReturn( BoltProtocol.forVersion( BoltProtocolV42.VERSION ) ); when( connection.serverVersion() ).thenReturn( ServerVersion.v4_1_0 ); when( connection.release() ).thenReturn( completedWithNull() ); return connection; diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolVersionTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolVersionTest.java index 15c3998a71..6f9ddb0fe5 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolVersionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolVersionTest.java @@ -28,7 +28,7 @@ class BoltProtocolVersionTest { @ParameterizedTest( name = "V{0}.{1}" ) - @CsvSource( {"3, 0", "4, 0", "4, 1", "100, 100", "255, 255", "0, 0"} ) + @CsvSource( {"3, 0", "4, 0", "4, 1", "4, 2", "100, 100", "255, 255", "0, 0"} ) void shouldParseVersion( int major, int minor ) { BoltProtocolVersion protocolVersion = new BoltProtocolVersion( major, minor ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java new file mode 100644 index 0000000000..db6892c15d --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v42/BoltProtocolV42Test.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2002-2020 "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 org.neo4j.driver.internal.messaging.v42; + +import org.neo4j.driver.internal.messaging.BoltProtocol; +import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41Test; + +public class BoltProtocolV42Test extends BoltProtocolV41Test +{ + @Override + protected BoltProtocol createProtocol() + { + return BoltProtocolV42.INSTANCE; + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/ServerVersionTest.java b/driver/src/test/java/org/neo4j/driver/internal/util/ServerVersionTest.java index 2129023123..fe3dc549ce 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/ServerVersionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/ServerVersionTest.java @@ -23,6 +23,7 @@ import org.neo4j.driver.internal.messaging.BoltProtocolVersion; import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import static java.lang.Integer.MAX_VALUE; import static org.hamcrest.MatcherAssert.assertThat; @@ -71,6 +72,7 @@ void shouldReturnCorrectServerVersionFromBoltProtocolVersion() { assertEquals( ServerVersion.v4_0_0, ServerVersion.fromBoltProtocolVersion( BoltProtocolV4.VERSION ) ); assertEquals( ServerVersion.v4_1_0, ServerVersion.fromBoltProtocolVersion( BoltProtocolV41.VERSION ) ); + assertEquals( ServerVersion.v4_2_0, ServerVersion.fromBoltProtocolVersion( BoltProtocolV42.VERSION ) ); assertEquals( ServerVersion.vInDev, ServerVersion.fromBoltProtocolVersion( new BoltProtocolVersion( MAX_VALUE, MAX_VALUE ) ) ); } } diff --git a/driver/src/test/java/org/neo4j/driver/util/TestUtil.java b/driver/src/test/java/org/neo4j/driver/util/TestUtil.java index 8db61f8682..da0e4bf4c6 100644 --- a/driver/src/test/java/org/neo4j/driver/util/TestUtil.java +++ b/driver/src/test/java/org/neo4j/driver/util/TestUtil.java @@ -71,6 +71,7 @@ import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3; import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4; import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41; +import org.neo4j.driver.internal.messaging.v42.BoltProtocolV42; import org.neo4j.driver.internal.retry.RetryLogic; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.spi.ConnectionProvider; @@ -532,7 +533,7 @@ public static Connection connectionMock( String databaseName, AccessMode mode, B setupSuccessfulPullAll( connection, "BEGIN" ); } else if ( version.equals( BoltProtocolV3.VERSION ) || version.equals( BoltProtocolV4.VERSION ) || - version.equals( BoltProtocolV41.VERSION )) + version.equals( BoltProtocolV41.VERSION ) || version.equals( BoltProtocolV42.VERSION )) { setupSuccessResponse( connection, CommitMessage.class ); setupSuccessResponse( connection, RollbackMessage.class );