From 999b17107d9a99cc84debc547492cc51b94a5410 Mon Sep 17 00:00:00 2001 From: lutovich Date: Wed, 25 Jul 2018 16:35:17 +0200 Subject: [PATCH 1/6] Messaging part of Bolt V3 Added new messages and ability to write them into a network channel. Introduced Bolt V3 abstraction that uses new messages to execute execute queries, begin/commit/rollback transactions. Code does not yet use new metadata. --- .../org/neo4j/driver/internal/Bookmark.java | 5 + .../internal/async/BoltProtocolUtil.java | 3 +- .../internal/async/NettyConnection.java | 89 +++++++--- .../internal/async/RoutingConnection.java | 12 ++ .../handlers/HelloResponseHandler.java | 80 +++++++++ .../messaging/AbstractMessageWriter.java | 2 +- .../internal/messaging/BoltProtocol.java | 14 +- .../messaging/encode/BeginMessageEncoder.java | 40 +++++ .../encode/CommitMessageEncoder.java | 38 ++++ .../encode/GoodbyeMessageEncoder.java | 38 ++++ .../messaging/encode/HelloMessageEncoder.java | 40 +++++ .../encode/RollbackMessageEncoder.java | 38 ++++ .../encode/RunWithMetadataMessageEncoder.java | 42 +++++ .../messaging/request/BeginMessage.java | 69 ++++++++ .../messaging/request/CommitMessage.java | 44 +++++ .../messaging/request/GoodbyeMessage.java | 44 +++++ .../messaging/request/HelloMessage.java | 90 ++++++++++ .../messaging/request/RollbackMessage.java | 44 +++++ .../request/RunWithMetadataMessage.java | 86 +++++++++ .../request/TransactionStartingMessage.java | 70 ++++++++ .../internal/messaging/v3/BoltProtocolV3.java | 163 ++++++++++++++++++ .../messaging/v3/MessageFormatV3.java | 39 +++++ .../messaging/v3/MessageWriterV3.java | 68 ++++++++ .../internal/security/InternalAuthToken.java | 10 +- .../neo4j/driver/internal/spi/Connection.java | 4 + .../java/org/neo4j/driver/v1/AuthTokens.java | 31 ++-- .../neo4j/driver/internal/BookmarkTest.java | 13 ++ .../internal/async/BoltProtocolUtilTest.java | 5 +- .../internal/async/NettyConnectionTest.java | 154 ++++++++++++++--- .../internal/async/RoutingConnectionTest.java | 75 ++++++-- .../handlers/HelloResponseHandlerTest.java | 117 +++++++++++++ .../AbstractMessageWriterTestBase.java | 59 +++---- .../internal/messaging/BoltProtocolTest.java | 4 +- .../encode/BeginMessageEncoderTest.java | 55 ++++++ .../encode/CommitMessageEncoderTest.java | 50 ++++++ .../encode/GoodbyeMessageEncoderTest.java | 50 ++++++ .../encode/HelloMessageEncoderTest.java | 46 +++++ .../encode/RollbackMessageEncoderTest.java | 50 ++++++ .../RunWithMetadataMessageEncoderTest.java | 79 +++++++++ .../messaging/request/BeginMessageTest.java | 39 +++++ .../messaging/request/HelloMessageTest.java | 45 +++++ .../request/RunWithMetadataMessageTest.java | 41 +++++ .../messaging/v1/MessageWriterV1Test.java | 51 ++++-- .../messaging/v2/MessageWriterV2Test.java | 46 +++-- .../messaging/v3/MessageFormatV3Test.java | 35 ++++ .../messaging/v3/MessageWriterV3Test.java | 72 ++++++++ .../util/FailingConnectionDriverFactory.java | 29 +++- 47 files changed, 2156 insertions(+), 162 deletions(-) create mode 100644 driver/src/main/java/org/neo4j/driver/internal/handlers/HelloResponseHandler.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoder.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoder.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoder.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoder.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoder.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoder.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/request/CommitMessage.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/request/GoodbyeMessage.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/request/RollbackMessage.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoderTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoderTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoderTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java diff --git a/driver/src/main/java/org/neo4j/driver/internal/Bookmark.java b/driver/src/main/java/org/neo4j/driver/internal/Bookmark.java index 440c3d3642..3de6d1ff92 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/Bookmark.java +++ b/driver/src/main/java/org/neo4j/driver/internal/Bookmark.java @@ -82,6 +82,11 @@ public String maxBookmarkAsString() return maxValue; } + public Iterable values() + { + return values; + } + public Map asBeginTransactionParameters() { if ( isEmpty() ) diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/BoltProtocolUtil.java b/driver/src/main/java/org/neo4j/driver/internal/async/BoltProtocolUtil.java index 6ba07b6ced..414ef7480b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/BoltProtocolUtil.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/BoltProtocolUtil.java @@ -22,6 +22,7 @@ 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 static io.netty.buffer.Unpooled.copyInt; import static io.netty.buffer.Unpooled.unreleasableBuffer; @@ -40,9 +41,9 @@ public final class BoltProtocolUtil private static final ByteBuf HANDSHAKE_BUF = unreleasableBuffer( copyInt( BOLT_MAGIC_PREAMBLE, + BoltProtocolV3.VERSION, BoltProtocolV2.VERSION, BoltProtocolV1.VERSION, - NO_PROTOCOL_VERSION, NO_PROTOCOL_VERSION ) ).asReadOnly(); private static final String HANDSHAKE_STRING = createHandshakeString(); diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/NettyConnection.java b/driver/src/main/java/org/neo4j/driver/internal/async/NettyConnection.java index f9d9924f30..dcc40796b8 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/NettyConnection.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/NettyConnection.java @@ -96,6 +96,15 @@ public void disableAutoRead() } } + @Override + public void write( Message message, ResponseHandler handler ) + { + if ( verifyOpen( handler, null ) ) + { + writeMessageInEventLoop( message, handler, false ); + } + } + @Override public void write( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ) { @@ -105,6 +114,15 @@ public void write( Message message1, ResponseHandler handler1, Message message2, } } + @Override + public void writeAndFlush( Message message, ResponseHandler handler ) + { + if ( verifyOpen( handler, null ) ) + { + writeMessageInEventLoop( message, handler, true ); + } + } + @Override public void writeAndFlush( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ) { @@ -180,39 +198,48 @@ private void writeResetMessageIfNeeded( ResponseHandler resetHandler, boolean is { // auto-read could've been disabled, re-enable it to automatically receive response for RESET setAutoRead( true ); - writeAndFlushMessage( ResetMessage.RESET, resetHandler ); + + messageDispatcher.queue( resetHandler ); + channel.writeAndFlush( ResetMessage.RESET, channel.voidPromise() ); } } ); } - private void writeMessagesInEventLoop( Message message1, ResponseHandler handler1, Message message2, - ResponseHandler handler2, boolean flush ) + private void writeMessageInEventLoop( Message message, ResponseHandler handler, boolean flush ) { - channel.eventLoop().execute( () -> writeMessages( message1, handler1, message2, handler2, flush ) ); + channel.eventLoop().execute( () -> + { + messageDispatcher.queue( handler ); + + if ( flush ) + { + channel.writeAndFlush( message, channel.voidPromise() ); + } + else + { + channel.write( message, channel.voidPromise() ); + } + } ); } - private void writeMessages( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2, - boolean flush ) + private void writeMessagesInEventLoop( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2, boolean flush ) { - messageDispatcher.queue( handler1 ); - messageDispatcher.queue( handler2 ); - - channel.write( message1, channel.voidPromise() ); - - if ( flush ) - { - channel.writeAndFlush( message2, channel.voidPromise() ); - } - else + channel.eventLoop().execute( () -> { - channel.write( message2, channel.voidPromise() ); - } - } + messageDispatcher.queue( handler1 ); + messageDispatcher.queue( handler2 ); - private void writeAndFlushMessage( Message message, ResponseHandler handler ) - { - messageDispatcher.queue( handler ); - channel.writeAndFlush( message, channel.voidPromise() ); + channel.write( message1, channel.voidPromise() ); + + if ( flush ) + { + channel.writeAndFlush( message2, channel.voidPromise() ); + } + else + { + channel.write( message2, channel.voidPromise() ); + } + } ); } private void setAutoRead( boolean value ) @@ -220,7 +247,7 @@ private void setAutoRead( boolean value ) channel.config().setAutoRead( value ); } - private boolean verifyOpen( ResponseHandler runHandler, ResponseHandler pullAllHandler ) + private boolean verifyOpen( ResponseHandler handler1, ResponseHandler handler2 ) { Status connectionStatus = this.status.get(); switch ( connectionStatus ) @@ -229,13 +256,19 @@ private boolean verifyOpen( ResponseHandler runHandler, ResponseHandler pullAllH return true; case RELEASED: Exception error = new IllegalStateException( "Connection has been released to the pool and can't be used" ); - runHandler.onFailure( error ); - pullAllHandler.onFailure( error ); + handler1.onFailure( error ); + if ( handler2 != null ) + { + handler2.onFailure( error ); + } return false; case TERMINATED: Exception terminatedError = new IllegalStateException( "Connection has been terminated and can't be used" ); - runHandler.onFailure( terminatedError ); - pullAllHandler.onFailure( terminatedError ); + handler1.onFailure( terminatedError ); + if ( handler2 != null ) + { + handler2.onFailure( terminatedError ); + } return false; default: throw new IllegalStateException( "Unknown status: " + connectionStatus ); diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/RoutingConnection.java b/driver/src/main/java/org/neo4j/driver/internal/async/RoutingConnection.java index b548cd41a3..610dd92fe2 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/RoutingConnection.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/RoutingConnection.java @@ -55,12 +55,24 @@ public void disableAutoRead() delegate.disableAutoRead(); } + @Override + public void write( Message message, ResponseHandler handler ) + { + delegate.write( message, newRoutingResponseHandler( handler ) ); + } + @Override public void write( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ) { delegate.write( message1, newRoutingResponseHandler( handler1 ), message2, newRoutingResponseHandler( handler2 ) ); } + @Override + public void writeAndFlush( Message message, ResponseHandler handler ) + { + delegate.writeAndFlush( message, newRoutingResponseHandler( handler ) ); + } + @Override public void writeAndFlush( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ) { diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/HelloResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/HelloResponseHandler.java new file mode 100644 index 0000000000..c243d52a89 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/HelloResponseHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2002-2018 "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.handlers; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelPromise; + +import java.util.Map; + +import org.neo4j.driver.internal.spi.ResponseHandler; +import org.neo4j.driver.internal.util.ServerVersion; +import org.neo4j.driver.v1.Value; + +import static org.neo4j.driver.internal.async.ChannelAttributes.setServerVersion; + +public class HelloResponseHandler implements ResponseHandler +{ + private final ChannelPromise connectionInitializedPromise; + private final Channel channel; + + public HelloResponseHandler( ChannelPromise connectionInitializedPromise ) + { + this.connectionInitializedPromise = connectionInitializedPromise; + this.channel = connectionInitializedPromise.channel(); + } + + @Override + public void onSuccess( Map metadata ) + { + try + { + ServerVersion serverVersion = extractServerVersion( metadata ); + setServerVersion( channel, serverVersion ); + connectionInitializedPromise.setSuccess(); + } + catch ( Throwable error ) + { + onFailure( error ); + throw error; + } + } + + @Override + public void onFailure( Throwable error ) + { + channel.close().addListener( future -> connectionInitializedPromise.setFailure( error ) ); + } + + @Override + public void onRecord( Value[] fields ) + { + throw new UnsupportedOperationException(); + } + + private static ServerVersion extractServerVersion( Map metadata ) + { + Value versionValue = metadata.get( "server" ); + if ( versionValue == null || versionValue.isNull() ) + { + throw new IllegalStateException( "Unable to get server version from a response to HELLO message. Metadata: " + metadata ); + } + return ServerVersion.version( versionValue.asString() ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/AbstractMessageWriter.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/AbstractMessageWriter.java index f1adb9c4fe..10198ceb3b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/AbstractMessageWriter.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/AbstractMessageWriter.java @@ -41,7 +41,7 @@ public final void write( Message msg ) throws IOException MessageEncoder encoder = encodersByMessageSignature.get( signature ); if ( encoder == null ) { - throw new IllegalArgumentException( "No encoder found for message " + msg + " with signature " + signature ); + throw new IOException( "No encoder found for message " + msg + " with signature " + signature ); } encoder.encode( msg, packer ); } 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 b2db86e7fa..ac588ea334 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 @@ -29,6 +29,7 @@ import org.neo4j.driver.internal.InternalStatementResultCursor; 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.spi.Connection; import org.neo4j.driver.v1.Session; import org.neo4j.driver.v1.Statement; @@ -129,16 +130,15 @@ static BoltProtocol forChannel( Channel channel ) */ static BoltProtocol forVersion( int version ) { - if ( version == BoltProtocolV1.VERSION ) + switch ( version ) { + case BoltProtocolV1.VERSION: return BoltProtocolV1.INSTANCE; - } - else if ( version == BoltProtocolV2.VERSION ) - { + case BoltProtocolV2.VERSION: return BoltProtocolV2.INSTANCE; - } - else - { + case BoltProtocolV3.VERSION: + return BoltProtocolV3.INSTANCE; + default: throw new ClientException( "Unknown protocol version: " + version ); } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoder.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoder.java new file mode 100644 index 0000000000..4064c62d8c --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoder.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import java.io.IOException; + +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageEncoder; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.BeginMessage; + +import static org.neo4j.driver.internal.util.Preconditions.checkArgument; + +public class BeginMessageEncoder implements MessageEncoder +{ + @Override + public void encode( Message message, ValuePacker packer ) throws IOException + { + checkArgument( message, BeginMessage.class ); + BeginMessage beginMessage = (BeginMessage) message; + packer.packStructHeader( 1, beginMessage.signature() ); + packer.pack( beginMessage.metadata() ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoder.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoder.java new file mode 100644 index 0000000000..0d067592a8 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoder.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import java.io.IOException; + +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageEncoder; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.CommitMessage; + +import static org.neo4j.driver.internal.util.Preconditions.checkArgument; + +public class CommitMessageEncoder implements MessageEncoder +{ + @Override + public void encode( Message message, ValuePacker packer ) throws IOException + { + checkArgument( message, CommitMessage.class ); + packer.packStructHeader( 0, CommitMessage.SIGNATURE ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoder.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoder.java new file mode 100644 index 0000000000..b6397f882d --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoder.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import java.io.IOException; + +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageEncoder; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.GoodbyeMessage; + +import static org.neo4j.driver.internal.util.Preconditions.checkArgument; + +public class GoodbyeMessageEncoder implements MessageEncoder +{ + @Override + public void encode( Message message, ValuePacker packer ) throws IOException + { + checkArgument( message, GoodbyeMessage.class ); + packer.packStructHeader( 0, GoodbyeMessage.SIGNATURE ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoder.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoder.java new file mode 100644 index 0000000000..001fab20cc --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoder.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import java.io.IOException; + +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageEncoder; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.HelloMessage; + +import static org.neo4j.driver.internal.util.Preconditions.checkArgument; + +public class HelloMessageEncoder implements MessageEncoder +{ + @Override + public void encode( Message message, ValuePacker packer ) throws IOException + { + checkArgument( message, HelloMessage.class ); + HelloMessage helloMessage = (HelloMessage) message; + packer.packStructHeader( 1, helloMessage.signature() ); + packer.pack( helloMessage.metadata() ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoder.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoder.java new file mode 100644 index 0000000000..a73ad609b2 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoder.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import java.io.IOException; + +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageEncoder; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.RollbackMessage; + +import static org.neo4j.driver.internal.util.Preconditions.checkArgument; + +public class RollbackMessageEncoder implements MessageEncoder +{ + @Override + public void encode( Message message, ValuePacker packer ) throws IOException + { + checkArgument( message, RollbackMessage.class ); + packer.packStructHeader( 0, RollbackMessage.SIGNATURE ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoder.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoder.java new file mode 100644 index 0000000000..659f74a97d --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoder.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import java.io.IOException; + +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageEncoder; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage; + +import static org.neo4j.driver.internal.util.Preconditions.checkArgument; + +public class RunWithMetadataMessageEncoder implements MessageEncoder +{ + @Override + public void encode( Message message, ValuePacker packer ) throws IOException + { + checkArgument( message, RunWithMetadataMessage.class ); + RunWithMetadataMessage runMessage = (RunWithMetadataMessage) message; + packer.packStructHeader( 3, runMessage.signature() ); + packer.pack( runMessage.statement() ); + packer.pack( runMessage.parameters() ); + packer.pack( runMessage.metadata() ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java new file mode 100644 index 0000000000..d1f86891e7 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2002-2018 "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.request; + +import java.time.Duration; +import java.util.Map; +import java.util.Objects; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.v1.Value; + +public class BeginMessage extends TransactionStartingMessage +{ + public static final byte SIGNATURE = 0x11; + + public BeginMessage( Bookmark bookmark, Duration txTimeout, Map txMetadata ) + { + super( bookmark, txTimeout, txMetadata ); + } + + @Override + public byte signature() + { + return SIGNATURE; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + BeginMessage that = (BeginMessage) o; + return Objects.equals( metadata, that.metadata ); + } + + @Override + public int hashCode() + { + return Objects.hash( metadata ); + } + + @Override + public String toString() + { + return "BEGIN " + metadata; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/CommitMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/CommitMessage.java new file mode 100644 index 0000000000..4ff761c6e5 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/CommitMessage.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2018 "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.request; + +import org.neo4j.driver.internal.messaging.Message; + +public class CommitMessage implements Message +{ + public static final byte SIGNATURE = 0x12; + + public static final Message COMMIT = new CommitMessage(); + + private CommitMessage() + { + } + + @Override + public byte signature() + { + return SIGNATURE; + } + + @Override + public String toString() + { + return "COMMIT"; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/GoodbyeMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/GoodbyeMessage.java new file mode 100644 index 0000000000..c921397c3d --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/GoodbyeMessage.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2018 "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.request; + +import org.neo4j.driver.internal.messaging.Message; + +public class GoodbyeMessage implements Message +{ + public final static byte SIGNATURE = 0x02; + + public static final Message GOODBYE = new GoodbyeMessage(); + + private GoodbyeMessage() + { + } + + @Override + public byte signature() + { + return SIGNATURE; + } + + @Override + public String toString() + { + return "GOODBYE"; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java new file mode 100644 index 0000000000..afd52b809c --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/HelloMessage.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2002-2018 "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.request; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.v1.Value; + +import static org.neo4j.driver.internal.security.InternalAuthToken.CREDENTIALS_KEY; +import static org.neo4j.driver.v1.Values.value; + +public class HelloMessage implements Message +{ + public final static byte SIGNATURE = 0x01; + + private static final String USER_AGENT_METADATA_KEY = "user_agent"; + + private final Map metadata; + + public HelloMessage( String userAgent, Map authToken ) + { + this.metadata = buildMetadata( userAgent, authToken ); + } + + public Map metadata() + { + return metadata; + } + + @Override + public byte signature() + { + return SIGNATURE; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + HelloMessage that = (HelloMessage) o; + return Objects.equals( metadata, that.metadata ); + } + + @Override + public int hashCode() + { + return Objects.hash( metadata ); + } + + @Override + public String toString() + { + Map metadataCopy = new HashMap<>( metadata ); + metadataCopy.replace( CREDENTIALS_KEY, value( "******" ) ); + return "HELLO " + metadataCopy; + } + + private static Map buildMetadata( String userAgent, Map authToken ) + { + Map result = new HashMap<>( authToken ); + result.put( USER_AGENT_METADATA_KEY, value( userAgent ) ); + return result; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RollbackMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RollbackMessage.java new file mode 100644 index 0000000000..5b14827067 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RollbackMessage.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2018 "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.request; + +import org.neo4j.driver.internal.messaging.Message; + +public class RollbackMessage implements Message +{ + public static final byte SIGNATURE = 0x13; + + public static final Message ROLLBACK = new RollbackMessage(); + + private RollbackMessage() + { + } + + @Override + public byte signature() + { + return SIGNATURE; + } + + @Override + public String toString() + { + return "ROLLBACK"; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java new file mode 100644 index 0000000000..608e7662c7 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2018 "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.request; + +import java.time.Duration; +import java.util.Map; +import java.util.Objects; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.v1.Value; + +public class RunWithMetadataMessage extends TransactionStartingMessage +{ + public final static byte SIGNATURE = 0x10; + + private final String statement; + private final Map parameters; + + public RunWithMetadataMessage( String statement, Map parameters, Bookmark bookmark, Duration txTimeout, Map txMetadata ) + { + super( bookmark, txTimeout, txMetadata ); + this.statement = statement; + this.parameters = parameters; + } + + public String statement() + { + return statement; + } + + public Map parameters() + { + return parameters; + } + + @Override + public byte signature() + { + return SIGNATURE; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + RunWithMetadataMessage that = (RunWithMetadataMessage) o; + return Objects.equals( statement, that.statement ) && + Objects.equals( parameters, that.parameters ) && + Objects.equals( metadata, that.metadata ); + } + + @Override + public int hashCode() + { + return Objects.hash( statement, parameters, metadata ); + } + + @Override + public String toString() + { + return "RUN \"" + statement + "\" " + parameters + " " + metadata; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java new file mode 100644 index 0000000000..5d0d4183dd --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2002-2018 "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.request; + +import java.time.Duration; +import java.util.Map; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.util.Iterables; +import org.neo4j.driver.v1.Value; + +import static org.neo4j.driver.v1.Values.value; + +abstract class TransactionStartingMessage implements Message +{ + private static final String BOOKMARKS_METADATA_KEY = "bookmarks"; + private static final String TX_TIMEOUT_METADATA_KEY = "tx_timeout"; + private static final String TX_METADATA_METADATA_KEY = "tx_metadata"; + + final Map metadata; + + TransactionStartingMessage( Bookmark bookmark, Duration txTimeout, Map txMetadata ) + { + this.metadata = buildMetadata( bookmark, txTimeout, txMetadata ); + } + + public final Map metadata() + { + return metadata; + } + + private static Map buildMetadata( Bookmark bookmark, Duration txTimeout, Map txMetadata ) + { + Map result = Iterables.newHashMapWithSize( 3 ); + + if ( bookmark != null && !bookmark.isEmpty() ) + { + result.put( BOOKMARKS_METADATA_KEY, value( bookmark.values() ) ); + } + + if ( txTimeout != null ) + { + result.put( TX_TIMEOUT_METADATA_KEY, value( txTimeout.toMillis() ) ); + } + + if ( txMetadata != null && !txMetadata.isEmpty() ) + { + result.put( TX_METADATA_METADATA_KEY, value( txMetadata ) ); + } + + return result; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java new file mode 100644 index 0000000000..6741aceb25 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2002-2018 "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.v3; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelPromise; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.ExplicitTransaction; +import org.neo4j.driver.internal.InternalStatementResultCursor; +import org.neo4j.driver.internal.handlers.BeginTxResponseHandler; +import org.neo4j.driver.internal.handlers.CommitTxResponseHandler; +import org.neo4j.driver.internal.handlers.HelloResponseHandler; +import org.neo4j.driver.internal.handlers.NoOpResponseHandler; +import org.neo4j.driver.internal.handlers.PullAllResponseHandler; +import org.neo4j.driver.internal.handlers.RollbackTxResponseHandler; +import org.neo4j.driver.internal.handlers.RunResponseHandler; +import org.neo4j.driver.internal.handlers.SessionPullAllResponseHandler; +import org.neo4j.driver.internal.handlers.TransactionPullAllResponseHandler; +import org.neo4j.driver.internal.messaging.BoltProtocol; +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageFormat; +import org.neo4j.driver.internal.messaging.request.BeginMessage; +import org.neo4j.driver.internal.messaging.request.HelloMessage; +import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage; +import org.neo4j.driver.internal.spi.Connection; +import org.neo4j.driver.internal.util.Futures; +import org.neo4j.driver.v1.Statement; +import org.neo4j.driver.v1.Value; + +import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.neo4j.driver.internal.async.ChannelAttributes.messageDispatcher; +import static org.neo4j.driver.internal.messaging.request.CommitMessage.COMMIT; +import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL; +import static org.neo4j.driver.internal.messaging.request.RollbackMessage.ROLLBACK; +import static org.neo4j.driver.v1.Values.ofValue; + +public class BoltProtocolV3 implements BoltProtocol +{ + public static final int VERSION = 3; + + public static final BoltProtocol INSTANCE = new BoltProtocolV3(); + + @Override + public MessageFormat createMessageFormat() + { + return new MessageFormatV3(); + } + + @Override + public void initializeChannel( String userAgent, Map authToken, ChannelPromise channelInitializedPromise ) + { + Channel channel = channelInitializedPromise.channel(); + + HelloMessage message = new HelloMessage( userAgent, authToken ); + HelloResponseHandler handler = new HelloResponseHandler( channelInitializedPromise ); + + messageDispatcher( channel ).queue( handler ); + channel.writeAndFlush( message, channel.voidPromise() ); + } + + @Override + public CompletionStage beginTransaction( Connection connection, Bookmark bookmark ) + { + BeginMessage beginMessage = new BeginMessage( bookmark, null, null ); + + if ( bookmark.isEmpty() ) + { + connection.write( beginMessage, NoOpResponseHandler.INSTANCE ); + return Futures.completedWithNull(); + } + else + { + CompletableFuture beginTxFuture = new CompletableFuture<>(); + connection.writeAndFlush( beginMessage, new BeginTxResponseHandler( beginTxFuture ) ); + return beginTxFuture; + } + } + + @Override + public CompletionStage commitTransaction( Connection connection, ExplicitTransaction tx ) + { + CompletableFuture commitFuture = new CompletableFuture<>(); + connection.writeAndFlush( COMMIT, new CommitTxResponseHandler( commitFuture, tx ) ); + return commitFuture; + } + + @Override + public CompletionStage rollbackTransaction( Connection connection ) + { + CompletableFuture rollbackFuture = new CompletableFuture<>(); + connection.writeAndFlush( ROLLBACK, new RollbackTxResponseHandler( rollbackFuture ) ); + return rollbackFuture; + } + + @Override + public CompletionStage runInAutoCommitTransaction( Connection connection, Statement statement, boolean waitForRunResponse ) + { + return runStatement( connection, statement, null, waitForRunResponse ); + } + + @Override + public CompletionStage runInExplicitTransaction( Connection connection, Statement statement, ExplicitTransaction tx, + boolean waitForRunResponse ) + { + return runStatement( connection, statement, tx, waitForRunResponse ); + } + + private static CompletionStage runStatement( Connection connection, Statement statement, + ExplicitTransaction tx, boolean waitForRunResponse ) + { + String query = statement.text(); + Map params = statement.parameters().asMap( ofValue() ); + + CompletableFuture runCompletedFuture = new CompletableFuture<>(); + Message runMessage = new RunWithMetadataMessage( query, params, null, null, null ); + RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture ); + PullAllResponseHandler pullAllHandler = newPullAllHandler( statement, runHandler, connection, tx ); + + connection.writeAndFlush( runMessage, runHandler, PULL_ALL, pullAllHandler ); + + if ( waitForRunResponse ) + { + // wait for response of RUN before proceeding + return runCompletedFuture.thenApply( ignore -> + new InternalStatementResultCursor( runHandler, pullAllHandler ) ); + } + else + { + return completedFuture( new InternalStatementResultCursor( runHandler, pullAllHandler ) ); + } + } + + private static PullAllResponseHandler newPullAllHandler( Statement statement, RunResponseHandler runHandler, + Connection connection, ExplicitTransaction tx ) + { + if ( tx != null ) + { + return new TransactionPullAllResponseHandler( statement, runHandler, connection, tx ); + } + return new SessionPullAllResponseHandler( statement, runHandler, connection ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3.java new file mode 100644 index 0000000000..816a2e604b --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002-2018 "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.v3; + +import org.neo4j.driver.internal.messaging.MessageFormat; +import org.neo4j.driver.internal.messaging.v2.MessageReaderV2; +import org.neo4j.driver.internal.packstream.PackInput; +import org.neo4j.driver.internal.packstream.PackOutput; + +public class MessageFormatV3 implements MessageFormat +{ + @Override + public Writer newWriter( PackOutput output, boolean byteArraySupportEnabled ) + { + return new MessageWriterV3( output ); + } + + @Override + public Reader newReader( PackInput input ) + { + return new MessageReaderV2( input ); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3.java new file mode 100644 index 0000000000..3666ba5ccb --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2002-2018 "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.v3; + +import java.util.Map; + +import org.neo4j.driver.internal.messaging.AbstractMessageWriter; +import org.neo4j.driver.internal.messaging.MessageEncoder; +import org.neo4j.driver.internal.messaging.encode.BeginMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.CommitMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.DiscardAllMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.GoodbyeMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.HelloMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.PullAllMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.ResetMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.RollbackMessageEncoder; +import org.neo4j.driver.internal.messaging.encode.RunWithMetadataMessageEncoder; +import org.neo4j.driver.internal.messaging.request.BeginMessage; +import org.neo4j.driver.internal.messaging.request.CommitMessage; +import org.neo4j.driver.internal.messaging.request.DiscardAllMessage; +import org.neo4j.driver.internal.messaging.request.GoodbyeMessage; +import org.neo4j.driver.internal.messaging.request.HelloMessage; +import org.neo4j.driver.internal.messaging.request.PullAllMessage; +import org.neo4j.driver.internal.messaging.request.ResetMessage; +import org.neo4j.driver.internal.messaging.request.RollbackMessage; +import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage; +import org.neo4j.driver.internal.messaging.v2.ValuePackerV2; +import org.neo4j.driver.internal.packstream.PackOutput; +import org.neo4j.driver.internal.util.Iterables; + +public class MessageWriterV3 extends AbstractMessageWriter +{ + public MessageWriterV3( PackOutput output ) + { + super( new ValuePackerV2( output ), buildEncoders() ); + } + + private static Map buildEncoders() + { + Map result = Iterables.newHashMapWithSize( 9 ); + result.put( HelloMessage.SIGNATURE, new HelloMessageEncoder() ); + result.put( GoodbyeMessage.SIGNATURE, new GoodbyeMessageEncoder() ); + result.put( RunWithMetadataMessage.SIGNATURE, new RunWithMetadataMessageEncoder() ); + result.put( DiscardAllMessage.SIGNATURE, new DiscardAllMessageEncoder() ); + result.put( PullAllMessage.SIGNATURE, new PullAllMessageEncoder() ); + result.put( BeginMessage.SIGNATURE, new BeginMessageEncoder() ); + result.put( CommitMessage.SIGNATURE, new CommitMessageEncoder() ); + result.put( RollbackMessage.SIGNATURE, new RollbackMessageEncoder() ); + result.put( ResetMessage.SIGNATURE, new ResetMessageEncoder() ); + return result; + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/security/InternalAuthToken.java b/driver/src/main/java/org/neo4j/driver/internal/security/InternalAuthToken.java index 4d05602c83..8499ebde88 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/security/InternalAuthToken.java +++ b/driver/src/main/java/org/neo4j/driver/internal/security/InternalAuthToken.java @@ -18,17 +18,23 @@ */ package org.neo4j.driver.internal.security; +import java.util.Map; + import org.neo4j.driver.v1.AuthToken; import org.neo4j.driver.v1.Value; -import java.util.Map; - /** * A simple common token for authentication schemes that easily convert to * an auth token map */ public class InternalAuthToken implements AuthToken { + public static final String SCHEME_KEY = "scheme"; + public static final String PRINCIPAL_KEY = "principal"; + public static final String CREDENTIALS_KEY = "credentials"; + public static final String REALM_KEY = "realm"; + public static final String PARAMETERS_KEY = "parameters"; + private final Map content; public InternalAuthToken( Map content ) diff --git a/driver/src/main/java/org/neo4j/driver/internal/spi/Connection.java b/driver/src/main/java/org/neo4j/driver/internal/spi/Connection.java index a95c5da889..70267e69ec 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/spi/Connection.java +++ b/driver/src/main/java/org/neo4j/driver/internal/spi/Connection.java @@ -33,8 +33,12 @@ public interface Connection void disableAutoRead(); + void write( Message message, ResponseHandler handler ); + void write( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ); + void writeAndFlush( Message message, ResponseHandler handler ); + void writeAndFlush( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ); CompletionStage reset(); diff --git a/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java b/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java index 3862f24176..8d9731c221 100644 --- a/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java +++ b/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java @@ -24,6 +24,11 @@ import org.neo4j.driver.internal.security.InternalAuthToken; import static java.util.Collections.singletonMap; +import static org.neo4j.driver.internal.security.InternalAuthToken.CREDENTIALS_KEY; +import static org.neo4j.driver.internal.security.InternalAuthToken.PARAMETERS_KEY; +import static org.neo4j.driver.internal.security.InternalAuthToken.PRINCIPAL_KEY; +import static org.neo4j.driver.internal.security.InternalAuthToken.REALM_KEY; +import static org.neo4j.driver.internal.security.InternalAuthToken.SCHEME_KEY; import static org.neo4j.driver.internal.util.Iterables.newHashMapWithSize; import static org.neo4j.driver.v1.Values.value; @@ -64,12 +69,12 @@ public static AuthToken basic( String username, String password, String realm ) Objects.requireNonNull( password, "Password can't be null" ); Map map = newHashMapWithSize( 4 ); - map.put( "scheme", value( "basic" ) ); - map.put( "principal", value( username ) ); - map.put( "credentials", value( password ) ); + map.put( SCHEME_KEY, value( "basic" ) ); + map.put( PRINCIPAL_KEY, value( username ) ); + map.put( CREDENTIALS_KEY, value( password ) ); if ( realm != null ) { - map.put( "realm", value( realm ) ); + map.put( REALM_KEY, value( realm ) ); } return new InternalAuthToken( map ); } @@ -87,9 +92,9 @@ public static AuthToken kerberos( String base64EncodedTicket ) Objects.requireNonNull( base64EncodedTicket, "Ticket can't be null" ); Map map = newHashMapWithSize( 3 ); - map.put( "scheme", value( "kerberos" ) ); - map.put( "principal", value( "" ) ); // This empty string is required for backwards compatibility. - map.put( "credentials", value( base64EncodedTicket ) ); + map.put( SCHEME_KEY, value( "kerberos" ) ); + map.put( PRINCIPAL_KEY, value( "" ) ); // This empty string is required for backwards compatibility. + map.put( CREDENTIALS_KEY, value( base64EncodedTicket ) ); return new InternalAuthToken( map ); } @@ -126,16 +131,16 @@ public static AuthToken custom( String principal, String credentials, String rea Objects.requireNonNull( scheme, "Scheme can't be null" ); Map map = newHashMapWithSize( 5 ); - map.put( "scheme", value( scheme ) ); - map.put( "principal", value( principal ) ); - map.put( "credentials", value( credentials ) ); + map.put( SCHEME_KEY, value( scheme ) ); + map.put( PRINCIPAL_KEY, value( principal ) ); + map.put( CREDENTIALS_KEY, value( credentials ) ); if ( realm != null ) { - map.put( "realm", value( realm ) ); + map.put( REALM_KEY, value( realm ) ); } if ( parameters != null ) { - map.put( "parameters", value( parameters ) ); + map.put( PARAMETERS_KEY, value( parameters ) ); } return new InternalAuthToken( map ); } @@ -148,6 +153,6 @@ public static AuthToken custom( String principal, String credentials, String rea */ public static AuthToken none() { - return new InternalAuthToken( singletonMap( "scheme", value( "none" ) ) ); + return new InternalAuthToken( singletonMap( SCHEME_KEY, value( "none" ) ) ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/BookmarkTest.java b/driver/src/test/java/org/neo4j/driver/internal/BookmarkTest.java index 88600afdb1..07116d3ac5 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/BookmarkTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/BookmarkTest.java @@ -28,9 +28,12 @@ import org.neo4j.driver.v1.Value; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.neo4j.driver.v1.Values.value; @@ -150,6 +153,16 @@ void asBeginTransactionParametersForBookmarkWithNullValue() asList( "neo4j:bookmark:v1:tx41", null, "neo4j:bookmark:v1:tx42" ) ); } + @Test + void shouldReturnAllBookmarks() + { + assertIterableEquals( emptyList(), Bookmark.empty().values() ); + assertIterableEquals( singletonList( "neo4j:bookmark:v1:tx42" ), Bookmark.from( "neo4j:bookmark:v1:tx42" ).values() ); + + List bookmarks = asList( "neo4j:bookmark:v1:tx1", "neo4j:bookmark:v1:tx2", "neo4j:bookmark:v1:tx3" ); + assertIterableEquals( bookmarks, Bookmark.from( bookmarks ).values() ); + } + private static void verifyParameters( Bookmark bookmark, String expectedMaxValue, String... expectedValues ) { verifyParameters( bookmark, expectedMaxValue, asList( expectedValues ) ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/BoltProtocolUtilTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/BoltProtocolUtilTest.java index 51eb2e7b9a..bfd442e219 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/BoltProtocolUtilTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/BoltProtocolUtilTest.java @@ -24,6 +24,7 @@ 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 static org.junit.jupiter.api.Assertions.assertEquals; import static org.neo4j.driver.internal.async.BoltProtocolUtil.BOLT_MAGIC_PREAMBLE; @@ -42,14 +43,14 @@ void shouldReturnHandshakeBuf() { assertByteBufContains( handshakeBuf(), - BOLT_MAGIC_PREAMBLE, BoltProtocolV2.VERSION, BoltProtocolV1.VERSION, NO_PROTOCOL_VERSION, NO_PROTOCOL_VERSION + BOLT_MAGIC_PREAMBLE, BoltProtocolV3.VERSION, BoltProtocolV2.VERSION, BoltProtocolV1.VERSION, NO_PROTOCOL_VERSION ); } @Test void shouldReturnHandshakeString() { - assertEquals( "[0x6060b017, 2, 1, 0, 0]", handshakeString() ); + assertEquals( "[0x6060b017, 3, 2, 1, 0]", handshakeString() ); } @Test diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/NettyConnectionTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/NettyConnectionTest.java index 74ca75da00..fed223f391 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/NettyConnectionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/NettyConnectionTest.java @@ -39,7 +39,6 @@ import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher; import org.neo4j.driver.internal.handlers.NoOpResponseHandler; -import org.neo4j.driver.internal.messaging.request.PullAllMessage; import org.neo4j.driver.internal.messaging.request.RunMessage; import org.neo4j.driver.internal.spi.ResponseHandler; import org.neo4j.driver.internal.util.FakeClock; @@ -60,6 +59,7 @@ import static org.neo4j.driver.internal.async.ChannelAttributes.messageDispatcher; import static org.neo4j.driver.internal.async.ChannelAttributes.terminationReason; import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING; +import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL; import static org.neo4j.driver.internal.messaging.request.ResetMessage.RESET; import static org.neo4j.driver.internal.metrics.InternalAbstractMetrics.DEV_NULL_METRICS; import static org.neo4j.driver.internal.util.Iterables.single; @@ -108,17 +108,23 @@ void shouldSendResetOnRelease() } @Test - void shouldEnqueueHandlersFromEventLoopThread() throws Exception + void shouldWriteInEventLoopThread() throws Exception { - testWriteInEventLoop( "RunTestEventLoop", - connection -> connection.write( new RunMessage( "RETURN 1" ), NO_OP_HANDLER, PullAllMessage.PULL_ALL, NO_OP_HANDLER ) ); + testWriteInEventLoop( "WriteSingleMessage", + connection -> connection.write( new RunMessage( "RETURN 1" ), NO_OP_HANDLER ) ); + + testWriteInEventLoop( "WriteMultipleMessages", + connection -> connection.write( new RunMessage( "RETURN 1" ), NO_OP_HANDLER, PULL_ALL, NO_OP_HANDLER ) ); } @Test - void shouldWriteRunAndFlushInEventLoopThread() throws Exception + void shouldWriteAndFlushInEventLoopThread() throws Exception { - testWriteInEventLoop( "RunAndFlushTestEventLoop", - connection -> connection.writeAndFlush( new RunMessage( "RETURN 1" ), NO_OP_HANDLER, PullAllMessage.PULL_ALL, NO_OP_HANDLER ) ); + testWriteInEventLoop( "WriteAndFlushSingleMessage", + connection -> connection.writeAndFlush( new RunMessage( "RETURN 1" ), NO_OP_HANDLER ) ); + + testWriteInEventLoop( "WriteAndFlushMultipleMessages", + connection -> connection.writeAndFlush( new RunMessage( "RETURN 1" ), NO_OP_HANDLER, PULL_ALL, NO_OP_HANDLER ) ); } @Test @@ -155,14 +161,82 @@ void shouldNotDisableAutoReadWhenReleased() } @Test - void shouldNotRunWhenReleased() + void shouldWriteSingleMessage() + { + EmbeddedChannel channel = newChannel(); + NettyConnection connection = newConnection( channel ); + + connection.write( PULL_ALL, NO_OP_HANDLER ); + + assertEquals( 0, channel.outboundMessages().size() ); + channel.flushOutbound(); + assertEquals( 1, channel.outboundMessages().size() ); + assertEquals( PULL_ALL, single( channel.outboundMessages() ) ); + } + + @Test + void shouldWriteMultipleMessage() + { + EmbeddedChannel channel = newChannel(); + NettyConnection connection = newConnection( channel ); + + connection.write( PULL_ALL, NO_OP_HANDLER, RESET, NO_OP_HANDLER ); + + assertEquals( 0, channel.outboundMessages().size() ); + channel.flushOutbound(); + assertEquals( 2, channel.outboundMessages().size() ); + assertEquals( PULL_ALL, channel.outboundMessages().poll() ); + assertEquals( RESET, channel.outboundMessages().poll() ); + } + + @Test + void shouldWriteAndFlushSingleMessage() + { + EmbeddedChannel channel = newChannel(); + NettyConnection connection = newConnection( channel ); + + connection.writeAndFlush( PULL_ALL, NO_OP_HANDLER ); + + assertEquals( 1, channel.outboundMessages().size() ); + assertEquals( PULL_ALL, single( channel.outboundMessages() ) ); + } + + @Test + void shouldWriteAndFlushMultipleMessage() + { + EmbeddedChannel channel = newChannel(); + NettyConnection connection = newConnection( channel ); + + connection.writeAndFlush( PULL_ALL, NO_OP_HANDLER, RESET, NO_OP_HANDLER ); + + assertEquals( 2, channel.outboundMessages().size() ); + assertEquals( PULL_ALL, channel.outboundMessages().poll() ); + assertEquals( RESET, channel.outboundMessages().poll() ); + } + + @Test + void shouldNotWriteSingleMessageWhenReleased() + { + ResponseHandler handler = mock( ResponseHandler.class ); + NettyConnection connection = newConnection( newChannel() ); + + connection.release(); + connection.write( new RunMessage( "RETURN 1" ), handler ); + + ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); + verify( handler ).onFailure( failureCaptor.capture() ); + assertConnectionReleasedError( failureCaptor.getValue() ); + } + + @Test + void shouldNotWriteMultipleMessagesWhenReleased() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); NettyConnection connection = newConnection( newChannel() ); connection.release(); - connection.write( new RunMessage( "RETURN 1" ), runHandler, PullAllMessage.PULL_ALL, pullAllHandler ); + connection.write( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); verify( runHandler ).onFailure( failureCaptor.capture() ); @@ -170,14 +244,28 @@ void shouldNotRunWhenReleased() } @Test - void shouldNotRunAndFlushWhenReleased() + void shouldNotWriteAndFlushSingleMessageWhenReleased() + { + ResponseHandler handler = mock( ResponseHandler.class ); + NettyConnection connection = newConnection( newChannel() ); + + connection.release(); + connection.writeAndFlush( new RunMessage( "RETURN 1" ), handler ); + + ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); + verify( handler ).onFailure( failureCaptor.capture() ); + assertConnectionReleasedError( failureCaptor.getValue() ); + } + + @Test + void shouldNotWriteAndFlushMultipleMessagesWhenReleased() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); NettyConnection connection = newConnection( newChannel() ); connection.release(); - connection.writeAndFlush( new RunMessage( "RETURN 1" ), runHandler, PullAllMessage.PULL_ALL, pullAllHandler ); + connection.writeAndFlush( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); verify( runHandler ).onFailure( failureCaptor.capture() ); @@ -185,14 +273,28 @@ void shouldNotRunAndFlushWhenReleased() } @Test - void shouldNotRunWhenTerminated() + void shouldNotWriteSingleMessageWhenTerminated() + { + ResponseHandler handler = mock( ResponseHandler.class ); + NettyConnection connection = newConnection( newChannel() ); + + connection.terminateAndRelease( "42" ); + connection.write( new RunMessage( "RETURN 1" ), handler ); + + ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); + verify( handler ).onFailure( failureCaptor.capture() ); + assertConnectionTerminatedError( failureCaptor.getValue() ); + } + + @Test + void shouldNotWriteMultipleMessagesWhenTerminated() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); NettyConnection connection = newConnection( newChannel() ); connection.terminateAndRelease( "42" ); - connection.write( new RunMessage( "RETURN 1" ), runHandler, PullAllMessage.PULL_ALL, pullAllHandler ); + connection.write( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); verify( runHandler ).onFailure( failureCaptor.capture() ); @@ -200,14 +302,28 @@ void shouldNotRunWhenTerminated() } @Test - void shouldNotRunAndFlushWhenTerminated() + void shouldNotWriteAndFlushSingleMessageWhenTerminated() + { + ResponseHandler handler = mock( ResponseHandler.class ); + NettyConnection connection = newConnection( newChannel() ); + + connection.terminateAndRelease( "42" ); + connection.writeAndFlush( new RunMessage( "RETURN 1" ), handler ); + + ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); + verify( handler ).onFailure( failureCaptor.capture() ); + assertConnectionTerminatedError( failureCaptor.getValue() ); + } + + @Test + void shouldNotWriteAndFlushMultipleMessagesWhenTerminated() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); NettyConnection connection = newConnection( newChannel() ); connection.terminateAndRelease( "42" ); - connection.writeAndFlush( new RunMessage( "RETURN 1" ), runHandler, PullAllMessage.PULL_ALL, pullAllHandler ); + connection.writeAndFlush( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); ArgumentCaptor failureCaptor = ArgumentCaptor.forClass( IllegalStateException.class ); verify( runHandler ).onFailure( failureCaptor.capture() ); @@ -475,14 +591,6 @@ private static EmbeddedChannel newChannel() return channel; } - private static EmbeddedChannel newChannel( InboundMessageDispatcher messageDispatcher ) - { - EmbeddedChannel channel = new EmbeddedChannel(); - ChannelAttributes.setProtocolVersion( channel, DEFAULT_TEST_PROTOCOL_VERSION ); - ChannelAttributes.setMessageDispatcher( channel, messageDispatcher ); - return channel; - } - private static NettyConnection newConnection( Channel channel ) { return newConnection( channel, mock( ChannelPool.class ) ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/RoutingConnectionTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/RoutingConnectionTest.java index 832f2dcb8c..d8a04f84fe 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/RoutingConnectionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/RoutingConnectionTest.java @@ -23,8 +23,6 @@ import org.neo4j.driver.internal.RoutingErrorHandler; import org.neo4j.driver.internal.handlers.RoutingResponseHandler; -import org.neo4j.driver.internal.messaging.request.PullAllMessage; -import org.neo4j.driver.internal.messaging.request.RunMessage; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.spi.ResponseHandler; @@ -33,23 +31,66 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.neo4j.driver.internal.messaging.request.DiscardAllMessage.DISCARD_ALL; +import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL; import static org.neo4j.driver.v1.AccessMode.READ; class RoutingConnectionTest { @Test - void shouldWrapGivenHandlersInRun() + void shouldWrapHandlersWhenWritingSingleMessage() { - testHandlersWrapping( false ); + testHandlersWrappingWithSingleMessage( false ); } @Test - void shouldWrapGivenHandlersInRunAndFlush() + void shouldWrapHandlersWhenWritingAndFlushingSingleMessage() { - testHandlersWrapping( true ); + testHandlersWrappingWithSingleMessage( true ); } - private static void testHandlersWrapping( boolean flush ) + @Test + void shouldWrapHandlersWhenWritingMultipleMessages() + { + testHandlersWrappingWithMultipleMessages( false ); + } + + @Test + void shouldWrapHandlersWhenWritingAndFlushingMultipleMessages() + { + testHandlersWrappingWithMultipleMessages( true ); + } + + private static void testHandlersWrappingWithSingleMessage( boolean flush ) + { + Connection connection = mock( Connection.class ); + RoutingErrorHandler errorHandler = mock( RoutingErrorHandler.class ); + RoutingConnection routingConnection = new RoutingConnection( connection, READ, errorHandler ); + + if ( flush ) + { + routingConnection.writeAndFlush( PULL_ALL, mock( ResponseHandler.class ) ); + } + else + { + routingConnection.write( PULL_ALL, mock( ResponseHandler.class ) ); + } + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass( ResponseHandler.class ); + + if ( flush ) + { + verify( connection ).writeAndFlush( eq( PULL_ALL ), handlerCaptor.capture() ); + } + else + { + verify( connection ).write( eq( PULL_ALL ), handlerCaptor.capture() ); + } + + assertThat( handlerCaptor.getValue(), instanceOf( RoutingResponseHandler.class ) ); + } + + private static void testHandlersWrappingWithMultipleMessages( boolean flush ) { Connection connection = mock( Connection.class ); RoutingErrorHandler errorHandler = mock( RoutingErrorHandler.class ); @@ -57,30 +98,26 @@ private static void testHandlersWrapping( boolean flush ) if ( flush ) { - routingConnection.writeAndFlush( new RunMessage( "RETURN 1" ), mock( ResponseHandler.class ), - PullAllMessage.PULL_ALL, mock( ResponseHandler.class ) ); + routingConnection.writeAndFlush( PULL_ALL, mock( ResponseHandler.class ), DISCARD_ALL, mock( ResponseHandler.class ) ); } else { - routingConnection.write( new RunMessage( "RETURN 1" ), mock( ResponseHandler.class ), - PullAllMessage.PULL_ALL, mock( ResponseHandler.class ) ); + routingConnection.write( PULL_ALL, mock( ResponseHandler.class ), DISCARD_ALL, mock( ResponseHandler.class ) ); } - ArgumentCaptor runHandlerCaptor = ArgumentCaptor.forClass( ResponseHandler.class ); - ArgumentCaptor pullAllHandlerCaptor = ArgumentCaptor.forClass( ResponseHandler.class ); + ArgumentCaptor handlerCaptor1 = ArgumentCaptor.forClass( ResponseHandler.class ); + ArgumentCaptor handlerCaptor2 = ArgumentCaptor.forClass( ResponseHandler.class ); if ( flush ) { - verify( connection ).writeAndFlush( eq( new RunMessage( "RETURN 1" ) ), runHandlerCaptor.capture(), - eq( PullAllMessage.PULL_ALL ), pullAllHandlerCaptor.capture() ); + verify( connection ).writeAndFlush( eq( PULL_ALL ), handlerCaptor1.capture(), eq( DISCARD_ALL ), handlerCaptor2.capture() ); } else { - verify( connection ).write( eq( new RunMessage( "RETURN 1" ) ), runHandlerCaptor.capture(), - eq( PullAllMessage.PULL_ALL ), pullAllHandlerCaptor.capture() ); + verify( connection ).write( eq( PULL_ALL ), handlerCaptor1.capture(), eq( DISCARD_ALL ), handlerCaptor2.capture() ); } - assertThat( runHandlerCaptor.getValue(), instanceOf( RoutingResponseHandler.class ) ); - assertThat( pullAllHandlerCaptor.getValue(), instanceOf( RoutingResponseHandler.class ) ); + assertThat( handlerCaptor1.getValue(), instanceOf( RoutingResponseHandler.class ) ); + assertThat( handlerCaptor2.getValue(), instanceOf( RoutingResponseHandler.class ) ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java new file mode 100644 index 0000000000..f49298b6e8 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java @@ -0,0 +1,117 @@ +package org.neo4j.driver.internal.handlers; + +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPromise; +import io.netty.channel.embedded.EmbeddedChannel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.neo4j.driver.internal.async.inbound.ChannelErrorHandler; +import org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher; +import org.neo4j.driver.internal.async.outbound.OutboundMessageHandler; +import org.neo4j.driver.internal.messaging.v1.MessageFormatV1; +import org.neo4j.driver.internal.util.ServerVersion; +import org.neo4j.driver.v1.Value; +import org.neo4j.driver.v1.Values; + +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.neo4j.driver.internal.async.ChannelAttributes.serverVersion; +import static org.neo4j.driver.internal.async.ChannelAttributes.setMessageDispatcher; +import static org.neo4j.driver.internal.async.outbound.OutboundMessageHandler.NAME; +import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING; +import static org.neo4j.driver.v1.Values.value; + +class HelloResponseHandlerTest +{ + private final EmbeddedChannel channel = new EmbeddedChannel(); + + @BeforeEach + void setUp() + { + setMessageDispatcher( channel, new InboundMessageDispatcher( channel, DEV_NULL_LOGGING ) ); + ChannelPipeline pipeline = channel.pipeline(); + pipeline.addLast( NAME, new OutboundMessageHandler( new MessageFormatV1(), DEV_NULL_LOGGING ) ); + pipeline.addLast( new ChannelErrorHandler( DEV_NULL_LOGGING ) ); + } + + @AfterEach + void tearDown() + { + channel.finishAndReleaseAll(); + } + + @Test + void shouldSetServerVersionOnChannel() + { + ChannelPromise channelPromise = channel.newPromise(); + HelloResponseHandler handler = new HelloResponseHandler( channelPromise ); + + Map metadata = singletonMap( "server", value( ServerVersion.v3_2_0.toString() ) ); + handler.onSuccess( metadata ); + + assertTrue( channelPromise.isSuccess() ); + assertEquals( ServerVersion.v3_2_0, serverVersion( channel ) ); + } + + @Test + void shouldThrowWhenServerVersionNotReturned() + { + ChannelPromise channelPromise = channel.newPromise(); + HelloResponseHandler handler = new HelloResponseHandler( channelPromise ); + + assertThrows( IllegalStateException.class, () -> handler.onSuccess( singletonMap( "server", null ) ) ); + + assertFalse( channelPromise.isSuccess() ); // initialization failed + assertTrue( channel.closeFuture().isDone() ); // channel was closed + } + + @Test + void shouldThrowWhenServerVersionInNull() + { + ChannelPromise channelPromise = channel.newPromise(); + HelloResponseHandler handler = new HelloResponseHandler( channelPromise ); + + assertThrows( IllegalStateException.class, () -> handler.onSuccess( singletonMap( "server", Values.NULL ) ) ); + + assertFalse( channelPromise.isSuccess() ); // initialization failed + assertTrue( channel.closeFuture().isDone() ); // channel was closed + } + + @Test + void shouldThrowWhenServerVersionCantBeParsed() + { + ChannelPromise channelPromise = channel.newPromise(); + HelloResponseHandler handler = new HelloResponseHandler( channelPromise ); + + assertThrows( IllegalArgumentException.class, () -> handler.onSuccess( singletonMap( "server", value( "WrongServerVersion" ) ) ) ); + + assertFalse( channelPromise.isSuccess() ); // initialization failed + assertTrue( channel.closeFuture().isDone() ); // channel was closed + } + + @Test + void shouldCloseChannelOnFailure() throws Exception + { + ChannelPromise channelPromise = channel.newPromise(); + HelloResponseHandler handler = new HelloResponseHandler( channelPromise ); + + RuntimeException error = new RuntimeException( "Hi!" ); + handler.onFailure( error ); + + ChannelFuture channelCloseFuture = channel.closeFuture(); + channelCloseFuture.await( 5, TimeUnit.SECONDS ); + + assertTrue( channelCloseFuture.isSuccess() ); + assertTrue( channelPromise.isDone() ); + assertEquals( error, channelPromise.cause() ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/AbstractMessageWriterTestBase.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/AbstractMessageWriterTestBase.java index 4f2b3a9ba2..63998490ae 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/AbstractMessageWriterTestBase.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/AbstractMessageWriterTestBase.java @@ -20,58 +20,47 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.TestFactory; import java.io.IOException; +import java.util.stream.Stream; import org.neo4j.driver.internal.async.inbound.ByteBufInput; -import org.neo4j.driver.internal.messaging.request.DiscardAllMessage; -import org.neo4j.driver.internal.messaging.request.InitMessage; -import org.neo4j.driver.internal.messaging.request.PullAllMessage; -import org.neo4j.driver.internal.messaging.request.ResetMessage; -import org.neo4j.driver.internal.messaging.request.RunMessage; import org.neo4j.driver.internal.packstream.PackOutput; import org.neo4j.driver.internal.packstream.PackStream; import org.neo4j.driver.internal.util.ByteBufOutput; -import static java.util.Collections.emptyMap; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; +import static org.mockito.Mockito.mock; public abstract class AbstractMessageWriterTestBase { - @Test - void shouldWriteDiscardAllMessage() throws Exception + @TestFactory + Stream shouldWriteSupportedMessages() { - testMessageWriting( DiscardAllMessage.DISCARD_ALL, 0 ); + return supportedMessages().map( message -> + dynamicTest( message.toString(), () -> testSupportedMessageWriting( message ) ) ); } - @Test - void shouldWriteInitMessage() throws Exception + @TestFactory + Stream shouldFailToWriteUnsupportedMessages() { - testMessageWriting( new InitMessage( "MyDriver", emptyMap() ), 2 ); + return unsupportedMessages().map( message -> + dynamicTest( message.toString(), () -> testUnsupportedMessageWriting( message ) ) ); } - @Test - void shouldWritePullAllMessage() throws Exception - { - testMessageWriting( PullAllMessage.PULL_ALL, 0 ); - } - - @Test - void shouldWriteResetMessage() throws Exception - { - testMessageWriting( ResetMessage.RESET, 0 ); - } + protected abstract MessageFormat.Writer newWriter( PackOutput output ); - @Test - void shouldWriteRunMessage() throws Exception - { - testMessageWriting( new RunMessage( "RETURN 1", emptyMap() ), 2 ); - } + protected abstract Stream supportedMessages(); - protected abstract MessageFormat.Writer newWriter( PackOutput output ); + protected abstract Stream unsupportedMessages(); - protected void testMessageWriting( Message message, int expectedStructHeader ) throws IOException + private void testSupportedMessageWriting( Message message ) throws IOException { ByteBuf buffer = Unpooled.buffer(); PackOutput output = new ByteBufOutput( buffer ); @@ -84,9 +73,15 @@ protected void testMessageWriting( Message message, int expectedStructHeader ) t PackStream.Unpacker unpacker = new PackStream.Unpacker( input ); long structHeader = unpacker.unpackStructHeader(); - assertEquals( expectedStructHeader, structHeader ); + assertThat( structHeader, greaterThanOrEqualTo( 0L ) ); byte structSignature = unpacker.unpackStructSignature(); assertEquals( message.signature(), structSignature ); } + + private void testUnsupportedMessageWriting( Message message ) + { + MessageFormat.Writer writer = newWriter( mock( PackOutput.class ) ); + assertThrows( Exception.class, () -> writer.write( message ) ); + } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolTest.java index 394ca7e240..4dcf9295ea 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/BoltProtocolTest.java @@ -23,6 +23,7 @@ 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.v1.exceptions.ClientException; import static org.hamcrest.MatcherAssert.assertThat; @@ -38,7 +39,8 @@ void shouldCreateProtocolForKnownVersions() { assertAll( () -> assertThat( BoltProtocol.forVersion( BoltProtocolV1.VERSION ), instanceOf( BoltProtocolV1.class ) ), - () -> assertThat( BoltProtocol.forVersion( BoltProtocolV2.VERSION ), instanceOf( BoltProtocolV2.class ) ) + () -> assertThat( BoltProtocol.forVersion( BoltProtocolV2.VERSION ), instanceOf( BoltProtocolV2.class ) ), + () -> assertThat( BoltProtocol.forVersion( BoltProtocolV3.VERSION ), instanceOf( BoltProtocolV3.class ) ) ); } diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java new file mode 100644 index 0000000000..ca67435493 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java @@ -0,0 +1,55 @@ +package org.neo4j.driver.internal.messaging.encode; + +import org.junit.jupiter.api.Test; +import org.mockito.InOrder; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.BeginMessage; +import org.neo4j.driver.v1.Value; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.neo4j.driver.internal.messaging.request.ResetMessage.RESET; +import static org.neo4j.driver.v1.Values.value; + +class BeginMessageEncoderTest +{ + private final BeginMessageEncoder encoder = new BeginMessageEncoder(); + private final ValuePacker packer = mock( ValuePacker.class ); + + @Test + void shouldEncodeBeginMessage() throws Exception + { + Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx42" ); + + Map txMetadata = new HashMap<>(); + txMetadata.put( "hello", value( "world" ) ); + txMetadata.put( "answer", value( 42 ) ); + + Duration txTimeout = Duration.ofSeconds( 1 ); + + encoder.encode( new BeginMessage( bookmark, txTimeout, txMetadata ), packer ); + + InOrder order = inOrder( packer ); + order.verify( packer ).packStructHeader( 1, BeginMessage.SIGNATURE ); + + Map expectedMetadata = new HashMap<>(); + expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "tx_timeout", value( 1000 ) ); + expectedMetadata.put( "tx_metadata", value( txMetadata ) ); + + order.verify( packer ).pack( expectedMetadata ); + } + + @Test + void shouldFailToEncodeWrongMessage() + { + assertThrows( IllegalArgumentException.class, () -> encoder.encode( RESET, packer ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoderTest.java new file mode 100644 index 0000000000..f8a3f94f1d --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/CommitMessageEncoderTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import org.junit.jupiter.api.Test; + +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.CommitMessage; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.neo4j.driver.internal.messaging.request.CommitMessage.COMMIT; +import static org.neo4j.driver.internal.messaging.request.DiscardAllMessage.DISCARD_ALL; + +class CommitMessageEncoderTest +{ + private final CommitMessageEncoder encoder = new CommitMessageEncoder(); + private final ValuePacker packer = mock( ValuePacker.class ); + + @Test + void shouldEncodeCommitMessage() throws Exception + { + encoder.encode( COMMIT, packer ); + + verify( packer ).packStructHeader( 0, CommitMessage.SIGNATURE ); + } + + @Test + void shouldFailToEncodeWrongMessage() + { + assertThrows( IllegalArgumentException.class, () -> encoder.encode( DISCARD_ALL, packer ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoderTest.java new file mode 100644 index 0000000000..d81862b11f --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/GoodbyeMessageEncoderTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import org.junit.jupiter.api.Test; + +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.GoodbyeMessage; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.neo4j.driver.internal.messaging.request.DiscardAllMessage.DISCARD_ALL; +import static org.neo4j.driver.internal.messaging.request.GoodbyeMessage.GOODBYE; + +class GoodbyeMessageEncoderTest +{ + private final GoodbyeMessageEncoder encoder = new GoodbyeMessageEncoder(); + private final ValuePacker packer = mock( ValuePacker.class ); + + @Test + void shouldEncodeGoodbyeMessage() throws Exception + { + encoder.encode( GOODBYE, packer ); + + verify( packer ).packStructHeader( 0, GoodbyeMessage.SIGNATURE ); + } + + @Test + void shouldFailToEncodeWrongMessage() + { + assertThrows( IllegalArgumentException.class, () -> encoder.encode( DISCARD_ALL, packer ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java new file mode 100644 index 0000000000..7afb85df9c --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java @@ -0,0 +1,46 @@ +package org.neo4j.driver.internal.messaging.encode; + +import org.junit.jupiter.api.Test; +import org.mockito.InOrder; + +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.HelloMessage; +import org.neo4j.driver.v1.Value; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL; +import static org.neo4j.driver.v1.Values.value; + +class HelloMessageEncoderTest +{ + private final HelloMessageEncoder encoder = new HelloMessageEncoder(); + private final ValuePacker packer = mock( ValuePacker.class ); + + @Test + void shouldEncodeHelloMessage() throws Exception + { + Map authToken = new HashMap<>(); + authToken.put( "username", value( "bob" ) ); + authToken.put( "password", value( "secret" ) ); + + encoder.encode( new HelloMessage( "MyDriver", authToken ), packer ); + + InOrder order = inOrder( packer ); + order.verify( packer ).packStructHeader( 1, HelloMessage.SIGNATURE ); + + Map expectedMetadata = new HashMap<>( authToken ); + expectedMetadata.put( "user_agent", value( "MyDriver" ) ); + order.verify( packer ).pack( expectedMetadata ); + } + + @Test + void shouldFailToEncodeWrongMessage() + { + assertThrows( IllegalArgumentException.class, () -> encoder.encode( PULL_ALL, packer ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoderTest.java new file mode 100644 index 0000000000..47a6322df3 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RollbackMessageEncoderTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import org.junit.jupiter.api.Test; + +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.RollbackMessage; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.neo4j.driver.internal.messaging.request.ResetMessage.RESET; +import static org.neo4j.driver.internal.messaging.request.RollbackMessage.ROLLBACK; + +class RollbackMessageEncoderTest +{ + private final RollbackMessageEncoder encoder = new RollbackMessageEncoder(); + private final ValuePacker packer = mock( ValuePacker.class ); + + @Test + void shouldEncodeRollbackMessage() throws Exception + { + encoder.encode( ROLLBACK, packer ); + + verify( packer ).packStructHeader( 0, RollbackMessage.SIGNATURE ); + } + + @Test + void shouldFailToEncodeWrongMessage() + { + assertThrows( IllegalArgumentException.class, () -> encoder.encode( RESET, packer ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java new file mode 100644 index 0000000000..7d7135ee23 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2002-2018 "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.encode; + +import org.junit.jupiter.api.Test; +import org.mockito.InOrder; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.messaging.ValuePacker; +import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage; +import org.neo4j.driver.v1.Value; + +import static java.util.Collections.singletonMap; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.neo4j.driver.internal.messaging.request.DiscardAllMessage.DISCARD_ALL; +import static org.neo4j.driver.v1.Values.value; + +class RunWithMetadataMessageEncoderTest +{ + private final RunWithMetadataMessageEncoder encoder = new RunWithMetadataMessageEncoder(); + private final ValuePacker packer = mock( ValuePacker.class ); + + @Test + void shouldEncodeRunWithMetadataMessage() throws Exception + { + Map params = singletonMap( "answer", value( 42 ) ); + + Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx999" ); + + Map txMetadata = new HashMap<>(); + txMetadata.put( "key1", value( "value1" ) ); + txMetadata.put( "key2", value( 1, 2, 3, 4, 5 ) ); + txMetadata.put( "key3", value( true ) ); + + Duration txTimeout = Duration.ofMillis( 42 ); + + encoder.encode( new RunWithMetadataMessage( "RETURN $answer", params, bookmark, txTimeout, txMetadata ), packer ); + + InOrder order = inOrder( packer ); + order.verify( packer ).packStructHeader( 3, RunWithMetadataMessage.SIGNATURE ); + order.verify( packer ).pack( "RETURN $answer" ); + order.verify( packer ).pack( params ); + + Map expectedMetadata = new HashMap<>(); + expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "tx_timeout", value( 42 ) ); + expectedMetadata.put( "tx_metadata", value( txMetadata ) ); + + order.verify( packer ).pack( expectedMetadata ); + } + + @Test + void shouldFailToEncodeWrongMessage() + { + assertThrows( IllegalArgumentException.class, () -> encoder.encode( DISCARD_ALL, packer ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java new file mode 100644 index 0000000000..f1fc30f2bb --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java @@ -0,0 +1,39 @@ +package org.neo4j.driver.internal.messaging.request; + +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.v1.Value; + +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.neo4j.driver.v1.Values.value; + +class BeginMessageTest +{ + @Test + void shouldHaveCorrectMetadata() + { + Bookmark bookmark = Bookmark.from( asList( "neo4j:bookmark:v1:tx42", "neo4j:bookmark:v1:tx4242", "neo4j:bookmark:v1:tx424242" ) ); + + Map txMetadata = new HashMap<>(); + txMetadata.put( "hello", value( "world" ) ); + txMetadata.put( "answer", value( 4242 ) ); + txMetadata.put( "true", value( false ) ); + + Duration txTimeout = Duration.ofSeconds( 13 ); + + BeginMessage message = new BeginMessage( bookmark, txTimeout, txMetadata ); + + Map expectedMetadata = new HashMap<>(); + expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "tx_timeout", value( 13_000 ) ); + expectedMetadata.put( "tx_metadata", value( txMetadata ) ); + + assertEquals( expectedMetadata, message.metadata() ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java new file mode 100644 index 0000000000..c498fb3ba7 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java @@ -0,0 +1,45 @@ +package org.neo4j.driver.internal.messaging.request; + +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.v1.Value; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.neo4j.driver.internal.security.InternalAuthToken.CREDENTIALS_KEY; +import static org.neo4j.driver.internal.security.InternalAuthToken.PRINCIPAL_KEY; +import static org.neo4j.driver.v1.Values.value; + +class HelloMessageTest +{ + @Test + void shouldHaveCorrectMetadata() + { + Map authToken = new HashMap<>(); + authToken.put( "user", value( "Alice" ) ); + authToken.put( "credentials", value( "SecretPassword" ) ); + + HelloMessage message = new HelloMessage( "MyDriver/1.0.2", authToken ); + + Map expectedMetadata = new HashMap<>( authToken ); + expectedMetadata.put( "user_agent", value( "MyDriver/1.0.2" ) ); + assertEquals( expectedMetadata, message.metadata() ); + } + + @Test + void shouldNotExposeCredentialsInToString() + { + Map authToken = new HashMap<>(); + authToken.put( PRINCIPAL_KEY, value( "Alice" ) ); + authToken.put( CREDENTIALS_KEY, value( "SecretPassword" ) ); + + HelloMessage message = new HelloMessage( "MyDriver/1.0.2", authToken ); + + assertThat( message.toString(), not( containsString( "SecretPassword" ) ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java new file mode 100644 index 0000000000..eed84a55c7 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java @@ -0,0 +1,41 @@ +package org.neo4j.driver.internal.messaging.request; + +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.v1.Value; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.neo4j.driver.v1.Values.value; + +class RunWithMetadataMessageTest +{ + @Test + void shouldHaveCorrectMetadata() + { + Bookmark bookmark = Bookmark.from( asList( "neo4j:bookmark:v1:tx11", "neo4j:bookmark:v1:tx52" ) ); + + Map txMetadata = new HashMap<>(); + txMetadata.put( "foo", value( "bar" ) ); + txMetadata.put( "baz", value( 111 ) ); + txMetadata.put( "time", value( LocalDateTime.now() ) ); + + Duration txTimeout = Duration.ofSeconds( 7 ); + + RunWithMetadataMessage message = new RunWithMetadataMessage( "RETURN 1", emptyMap(), bookmark, txTimeout, txMetadata ); + + Map expectedMetadata = new HashMap<>(); + expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "tx_timeout", value( 7000 ) ); + expectedMetadata.put( "tx_metadata", value( txMetadata ) ); + + assertEquals( expectedMetadata, message.metadata() ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/MessageWriterV1Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/MessageWriterV1Test.java index 43acaec537..dd8c10805f 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/MessageWriterV1Test.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/MessageWriterV1Test.java @@ -18,42 +18,61 @@ */ package org.neo4j.driver.internal.messaging.v1; -import org.junit.jupiter.api.Test; - -import java.io.IOException; import java.time.LocalDateTime; +import java.util.stream.Stream; import org.neo4j.driver.internal.messaging.AbstractMessageWriterTestBase; +import org.neo4j.driver.internal.messaging.Message; import org.neo4j.driver.internal.messaging.MessageFormat.Writer; +import org.neo4j.driver.internal.messaging.request.HelloMessage; +import org.neo4j.driver.internal.messaging.request.InitMessage; import org.neo4j.driver.internal.messaging.request.RunMessage; import org.neo4j.driver.internal.packstream.PackOutput; +import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.neo4j.driver.internal.messaging.request.CommitMessage.COMMIT; +import static org.neo4j.driver.internal.messaging.request.DiscardAllMessage.DISCARD_ALL; +import static org.neo4j.driver.internal.messaging.request.GoodbyeMessage.GOODBYE; +import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL; +import static org.neo4j.driver.internal.messaging.request.ResetMessage.RESET; +import static org.neo4j.driver.internal.messaging.request.RollbackMessage.ROLLBACK; import static org.neo4j.driver.v1.Values.point; import static org.neo4j.driver.v1.Values.value; class MessageWriterV1Test extends AbstractMessageWriterTestBase { - @Test - void shouldFailToWriteMessageWithTemporalValue() + @Override + protected Writer newWriter( PackOutput output ) { - RunMessage message = new RunMessage( "RETURN $now", singletonMap( "now", value( LocalDateTime.now() ) ) ); - - assertThrows( IOException.class, () -> testMessageWriting( message, 0 ) ); + return new MessageWriterV1( output, true ); } - @Test - void shouldFailToWriteMessageWithSpatialValue() + @Override + protected Stream supportedMessages() { - RunMessage message = new RunMessage( "RETURN $here", singletonMap( "now", point( 42, 1, 1 ) ) ); - - assertThrows( IOException.class, () -> testMessageWriting( message, 0 ) ); + return Stream.of( + new InitMessage( "MyDriver/1.2.3", singletonMap( "password", value( "hello" ) ) ), + new RunMessage( "RETURN 1", singletonMap( "key", value( 42 ) ) ), + PULL_ALL, + DISCARD_ALL, + RESET + ); } @Override - protected Writer newWriter( PackOutput output ) + protected Stream unsupportedMessages() { - return new MessageWriterV1( output, true ); + return Stream.of( + // Bolt V1 messages with Bolt V2 structs + new RunMessage( "RETURN $now", singletonMap( "now", value( LocalDateTime.now() ) ) ), + new RunMessage( "RETURN $here", singletonMap( "now", point( 42, 1, 1 ) ) ), + + // Bolt V3 messages + new HelloMessage( "Driver/2.3.4", emptyMap() ), + GOODBYE, + COMMIT, + ROLLBACK + ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v2/MessageWriterV2Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v2/MessageWriterV2Test.java index 8d22cb8846..a20ab383dd 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v2/MessageWriterV2Test.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v2/MessageWriterV2Test.java @@ -18,40 +18,58 @@ */ package org.neo4j.driver.internal.messaging.v2; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; +import java.util.stream.Stream; import org.neo4j.driver.internal.messaging.AbstractMessageWriterTestBase; +import org.neo4j.driver.internal.messaging.Message; import org.neo4j.driver.internal.messaging.MessageFormat.Writer; +import org.neo4j.driver.internal.messaging.request.HelloMessage; +import org.neo4j.driver.internal.messaging.request.InitMessage; import org.neo4j.driver.internal.messaging.request.RunMessage; import org.neo4j.driver.internal.packstream.PackOutput; +import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; +import static org.neo4j.driver.internal.messaging.request.CommitMessage.COMMIT; +import static org.neo4j.driver.internal.messaging.request.DiscardAllMessage.DISCARD_ALL; +import static org.neo4j.driver.internal.messaging.request.GoodbyeMessage.GOODBYE; +import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL; +import static org.neo4j.driver.internal.messaging.request.ResetMessage.RESET; +import static org.neo4j.driver.internal.messaging.request.RollbackMessage.ROLLBACK; import static org.neo4j.driver.v1.Values.point; import static org.neo4j.driver.v1.Values.value; class MessageWriterV2Test extends AbstractMessageWriterTestBase { - @Test - void shouldWriteMessageWithTemporalValue() throws Exception + @Override + protected Writer newWriter( PackOutput output ) { - RunMessage message = new RunMessage( "RETURN $now", singletonMap( "now", value( LocalDateTime.now() ) ) ); - - testMessageWriting( message, 2 ); + return new MessageWriterV2( output ); } - @Test - void shouldWriteMessageWithSpatialValue() throws Exception + @Override + protected Stream supportedMessages() { - RunMessage message = new RunMessage( "RETURN $here", singletonMap( "now", point( 42, 1, 1 ) ) ); - - testMessageWriting( message, 2 ); + return Stream.of( + new InitMessage( "MyDriver/1.2.3", singletonMap( "password", value( "hello" ) ) ), + new RunMessage( "RETURN 1", singletonMap( "key", value( 42 ) ) ), + new RunMessage( "RETURN $now", singletonMap( "now", value( LocalDateTime.now() ) ) ), // RUN with temporal value + new RunMessage( "RETURN $here", singletonMap( "now", point( 42, 1, 1 ) ) ), // RUN with spatial value + PULL_ALL, + DISCARD_ALL, + RESET + ); } @Override - protected Writer newWriter( PackOutput output ) + protected Stream unsupportedMessages() { - return new MessageWriterV2( output ); + return Stream.of( + new HelloMessage( "JavaDriver/1.1.0", emptyMap() ), + GOODBYE, + COMMIT, + ROLLBACK + ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java new file mode 100644 index 0000000000..394c20f1ab --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java @@ -0,0 +1,35 @@ +package org.neo4j.driver.internal.messaging.v3; + +import org.junit.jupiter.api.Test; + +import org.neo4j.driver.internal.messaging.MessageFormat; +import org.neo4j.driver.internal.messaging.v2.MessageReaderV2; +import org.neo4j.driver.internal.packstream.PackInput; +import org.neo4j.driver.internal.packstream.PackOutput; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.mockito.Mockito.mock; + +class MessageFormatV3Test +{ + @Test + void shouldCreateCorrectWriter() + { + MessageFormatV3 format = new MessageFormatV3(); + + MessageFormat.Writer writer = format.newWriter( mock( PackOutput.class ), true ); + + assertThat( writer, instanceOf( MessageWriterV3.class ) ); + } + + @Test + void shouldCreateCorrectReader() + { + MessageFormatV3 format = new MessageFormatV3(); + + MessageFormat.Reader reader = format.newReader( mock( PackInput.class ) ); + + assertThat( reader, instanceOf( MessageReaderV2.class ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java new file mode 100644 index 0000000000..8fba751279 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java @@ -0,0 +1,72 @@ +package org.neo4j.driver.internal.messaging.v3; + +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.stream.Stream; + +import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.messaging.AbstractMessageWriterTestBase; +import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.MessageFormat; +import org.neo4j.driver.internal.messaging.request.BeginMessage; +import org.neo4j.driver.internal.messaging.request.HelloMessage; +import org.neo4j.driver.internal.messaging.request.InitMessage; +import org.neo4j.driver.internal.messaging.request.RunMessage; +import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage; +import org.neo4j.driver.internal.packstream.PackOutput; +import org.neo4j.driver.internal.security.InternalAuthToken; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static org.neo4j.driver.internal.messaging.request.CommitMessage.COMMIT; +import static org.neo4j.driver.internal.messaging.request.DiscardAllMessage.DISCARD_ALL; +import static org.neo4j.driver.internal.messaging.request.GoodbyeMessage.GOODBYE; +import static org.neo4j.driver.internal.messaging.request.PullAllMessage.PULL_ALL; +import static org.neo4j.driver.internal.messaging.request.ResetMessage.RESET; +import static org.neo4j.driver.internal.messaging.request.RollbackMessage.ROLLBACK; +import static org.neo4j.driver.v1.AuthTokens.basic; +import static org.neo4j.driver.v1.Values.point; +import static org.neo4j.driver.v1.Values.value; + +class MessageWriterV3Test extends AbstractMessageWriterTestBase +{ + @Override + protected MessageFormat.Writer newWriter( PackOutput output ) + { + return new MessageWriterV3( output ); + } + + @Override + protected Stream supportedMessages() + { + return Stream.of( + // Bolt V3 messages + new HelloMessage( "MyDriver/1.2.3", ((InternalAuthToken) basic( "neo4j", "neo4j" )).toMap() ), + GOODBYE, + new BeginMessage( Bookmark.from( "neo4j:bookmark:v1:tx123" ), Duration.ofSeconds( 5 ), singletonMap( "key", value( 42 ) ) ), + COMMIT, + ROLLBACK, + new RunWithMetadataMessage( "RETURN 1", emptyMap(), Bookmark.from( "neo4j:bookmark:v1:tx1" ), Duration.ofSeconds( 5 ), + singletonMap( "key", value( 42 ) ) ), + PULL_ALL, + DISCARD_ALL, + RESET, + + // Bolt V3 messages with struct values + new RunWithMetadataMessage( "RETURN $x", singletonMap( "x", value( ZonedDateTime.now() ) ), Bookmark.empty(), + Duration.ofSeconds( 1 ), emptyMap() ), + new RunWithMetadataMessage( "RETURN $x", singletonMap( "x", point( 42, 1, 2, 3 ) ), Bookmark.empty(), + Duration.ofSeconds( 1 ), emptyMap() ) + ); + } + + @Override + protected Stream unsupportedMessages() + { + return Stream.of( + // Bolt V1 and V2 messages + new InitMessage( "Apa", emptyMap() ), + new RunMessage( "RETURN 1" ) + ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java b/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java index 2b2101610d..2223209684 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/FailingConnectionDriverFactory.java @@ -130,6 +130,16 @@ public void disableAutoRead() delegate.disableAutoRead(); } + @Override + public void write( Message message, ResponseHandler handler ) + { + if ( tryFail( handler, null ) ) + { + return; + } + delegate.write( message, handler ); + } + @Override public void write( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ) { @@ -140,6 +150,16 @@ public void write( Message message1, ResponseHandler handler1, Message message2, delegate.write( message1, handler1, message2, handler2 ); } + @Override + public void writeAndFlush( Message message, ResponseHandler handler ) + { + if ( tryFail( handler, null ) ) + { + return; + } + delegate.writeAndFlush( message, handler ); + } + @Override public void writeAndFlush( Message message1, ResponseHandler handler1, Message message2, ResponseHandler handler2 ) { @@ -186,13 +206,16 @@ public BoltProtocol protocol() return delegate.protocol(); } - private boolean tryFail( ResponseHandler runHandler, ResponseHandler pullAllHandler ) + private boolean tryFail( ResponseHandler handler1, ResponseHandler handler2 ) { Throwable failure = nextRunFailure.getAndSet( null ); if ( failure != null ) { - runHandler.onFailure( failure ); - pullAllHandler.onFailure( failure ); + handler1.onFailure( failure ); + if ( handler2 != null ) + { + handler2.onFailure( failure ); + } return true; } return false; From 1468d202920fc16a640d853687344aa74b3efa2f Mon Sep 17 00:00:00 2001 From: lutovich Date: Wed, 25 Jul 2018 16:37:46 +0200 Subject: [PATCH 2/6] Rename NettyConnection to DirectConnection --- ...yConnection.java => DirectConnection.java} | 4 +- .../async/pool/ConnectionPoolImpl.java | 8 +- .../internal/metrics/MetricsListener.java | 6 +- ...ionTest.java => DirectConnectionTest.java} | 78 +++++++++---------- 4 files changed, 48 insertions(+), 48 deletions(-) rename driver/src/main/java/org/neo4j/driver/internal/async/{NettyConnection.java => DirectConnection.java} (98%) rename driver/src/test/java/org/neo4j/driver/internal/async/{NettyConnectionTest.java => DirectConnectionTest.java} (88%) diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/NettyConnection.java b/driver/src/main/java/org/neo4j/driver/internal/async/DirectConnection.java similarity index 98% rename from driver/src/main/java/org/neo4j/driver/internal/async/NettyConnection.java rename to driver/src/main/java/org/neo4j/driver/internal/async/DirectConnection.java index dcc40796b8..25b7b57031 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/NettyConnection.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/DirectConnection.java @@ -42,7 +42,7 @@ import static java.util.Collections.emptyMap; import static org.neo4j.driver.internal.async.ChannelAttributes.setTerminationReason; -public class NettyConnection implements Connection +public class DirectConnection implements Connection { private final Channel channel; private final InboundMessageDispatcher messageDispatcher; @@ -57,7 +57,7 @@ public class NettyConnection implements Connection private final MetricsListener metricsListener; private final ListenerEvent inUseEvent; - public NettyConnection( Channel channel, ChannelPool channelPool, Clock clock, MetricsListener metricsListener ) + public DirectConnection( Channel channel, ChannelPool channelPool, Clock clock, MetricsListener metricsListener ) { this.channel = channel; this.messageDispatcher = ChannelAttributes.messageDispatcher( channel ); diff --git a/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java b/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java index 398d2be434..23e5a773eb 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java +++ b/driver/src/main/java/org/neo4j/driver/internal/async/pool/ConnectionPoolImpl.java @@ -35,7 +35,7 @@ import org.neo4j.driver.internal.BoltServerAddress; import org.neo4j.driver.internal.async.ChannelConnector; -import org.neo4j.driver.internal.async.NettyConnection; +import org.neo4j.driver.internal.async.DirectConnection; import org.neo4j.driver.internal.metrics.ListenerEvent; import org.neo4j.driver.internal.metrics.MetricsListener; import org.neo4j.driver.internal.spi.Connection; @@ -55,7 +55,7 @@ public class ConnectionPoolImpl implements ConnectionPool private final PoolSettings settings; private final Clock clock; private final Logger log; - private MetricsListener metricsListener; + private final MetricsListener metricsListener; private final ConcurrentMap pools = new ConcurrentHashMap<>(); private final AtomicBoolean closed = new AtomicBoolean(); @@ -97,10 +97,10 @@ public CompletionStage acquire( BoltServerAddress address ) { processAcquisitionError( address, error ); assertNotClosed( address, channel, pool ); - NettyConnection nettyConnection = new NettyConnection( channel, pool, clock, metricsListener ); + Connection connection = new DirectConnection( channel, pool, clock, metricsListener ); metricsListener.afterAcquiredOrCreated( address, acquireEvent ); - return nettyConnection; + return connection; } finally { diff --git a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java index 9816565e02..1d50c91ee4 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java +++ b/driver/src/main/java/org/neo4j/driver/internal/metrics/MetricsListener.java @@ -21,7 +21,7 @@ import java.util.concurrent.TimeUnit; import org.neo4j.driver.internal.BoltServerAddress; -import org.neo4j.driver.internal.async.NettyConnection; +import org.neo4j.driver.internal.async.DirectConnection; import org.neo4j.driver.internal.async.pool.ConnectionPoolImpl; import org.neo4j.driver.v1.Config; @@ -82,14 +82,14 @@ public interface MetricsListener /** * After acquiring or creating a new netty channel from pool successfully. * @param serverAddress the server the netty channel binds to - * @param inUseEvent a connection listener registered with a {@link NettyConnection} when created + * @param inUseEvent a connection listener registered with a {@link DirectConnection} when created */ void afterConnectionCreated( BoltServerAddress serverAddress, ListenerEvent inUseEvent ); /** * After releasing a netty channel back to pool successfully * @param serverAddress the server the netty channel binds to - * @param inUseEvent a connection listener registered with a {@link NettyConnection} when destroyed + * @param inUseEvent a connection listener registered with a {@link DirectConnection} when destroyed */ void afterConnectionReleased( BoltServerAddress serverAddress, ListenerEvent inUseEvent ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/NettyConnectionTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/DirectConnectionTest.java similarity index 88% rename from driver/src/test/java/org/neo4j/driver/internal/async/NettyConnectionTest.java rename to driver/src/test/java/org/neo4j/driver/internal/async/DirectConnectionTest.java index fed223f391..3464df7d86 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/NettyConnectionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/DirectConnectionTest.java @@ -66,7 +66,7 @@ import static org.neo4j.driver.v1.util.DaemonThreadFactory.daemon; import static org.neo4j.driver.v1.util.TestUtil.DEFAULT_TEST_PROTOCOL_VERSION; -class NettyConnectionTest +class DirectConnectionTest { private static final NoOpResponseHandler NO_OP_HANDLER = NoOpResponseHandler.INSTANCE; @@ -82,14 +82,14 @@ void tearDown() throws Exception @Test void shouldBeOpenAfterCreated() { - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); assertTrue( connection.isOpen() ); } @Test void shouldNotBeOpenAfterRelease() { - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.release(); assertFalse( connection.isOpen() ); } @@ -98,7 +98,7 @@ void shouldNotBeOpenAfterRelease() void shouldSendResetOnRelease() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.release(); channel.runPendingTasks(); @@ -130,7 +130,7 @@ void shouldWriteAndFlushInEventLoopThread() throws Exception @Test void shouldWriteForceReleaseInEventLoopThread() throws Exception { - testWriteInEventLoop( "ReleaseTestEventLoop", NettyConnection::release ); + testWriteInEventLoop( "ReleaseTestEventLoop", DirectConnection::release ); } @Test @@ -139,7 +139,7 @@ void shouldEnableAutoReadWhenReleased() EmbeddedChannel channel = newChannel(); channel.config().setAutoRead( false ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.release(); channel.runPendingTasks(); @@ -153,7 +153,7 @@ void shouldNotDisableAutoReadWhenReleased() EmbeddedChannel channel = newChannel(); channel.config().setAutoRead( true ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.release(); connection.disableAutoRead(); // does nothing on released connection @@ -164,7 +164,7 @@ void shouldNotDisableAutoReadWhenReleased() void shouldWriteSingleMessage() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.write( PULL_ALL, NO_OP_HANDLER ); @@ -178,7 +178,7 @@ void shouldWriteSingleMessage() void shouldWriteMultipleMessage() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.write( PULL_ALL, NO_OP_HANDLER, RESET, NO_OP_HANDLER ); @@ -193,7 +193,7 @@ void shouldWriteMultipleMessage() void shouldWriteAndFlushSingleMessage() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.writeAndFlush( PULL_ALL, NO_OP_HANDLER ); @@ -205,7 +205,7 @@ void shouldWriteAndFlushSingleMessage() void shouldWriteAndFlushMultipleMessage() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.writeAndFlush( PULL_ALL, NO_OP_HANDLER, RESET, NO_OP_HANDLER ); @@ -218,7 +218,7 @@ void shouldWriteAndFlushMultipleMessage() void shouldNotWriteSingleMessageWhenReleased() { ResponseHandler handler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.release(); connection.write( new RunMessage( "RETURN 1" ), handler ); @@ -233,7 +233,7 @@ void shouldNotWriteMultipleMessagesWhenReleased() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.release(); connection.write( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); @@ -247,7 +247,7 @@ void shouldNotWriteMultipleMessagesWhenReleased() void shouldNotWriteAndFlushSingleMessageWhenReleased() { ResponseHandler handler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.release(); connection.writeAndFlush( new RunMessage( "RETURN 1" ), handler ); @@ -262,7 +262,7 @@ void shouldNotWriteAndFlushMultipleMessagesWhenReleased() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.release(); connection.writeAndFlush( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); @@ -276,7 +276,7 @@ void shouldNotWriteAndFlushMultipleMessagesWhenReleased() void shouldNotWriteSingleMessageWhenTerminated() { ResponseHandler handler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.terminateAndRelease( "42" ); connection.write( new RunMessage( "RETURN 1" ), handler ); @@ -291,7 +291,7 @@ void shouldNotWriteMultipleMessagesWhenTerminated() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.terminateAndRelease( "42" ); connection.write( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); @@ -305,7 +305,7 @@ void shouldNotWriteMultipleMessagesWhenTerminated() void shouldNotWriteAndFlushSingleMessageWhenTerminated() { ResponseHandler handler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.terminateAndRelease( "42" ); connection.writeAndFlush( new RunMessage( "RETURN 1" ), handler ); @@ -320,7 +320,7 @@ void shouldNotWriteAndFlushMultipleMessagesWhenTerminated() { ResponseHandler runHandler = mock( ResponseHandler.class ); ResponseHandler pullAllHandler = mock( ResponseHandler.class ); - NettyConnection connection = newConnection( newChannel() ); + DirectConnection connection = newConnection( newChannel() ); connection.terminateAndRelease( "42" ); connection.writeAndFlush( new RunMessage( "RETURN 1" ), runHandler, PULL_ALL, pullAllHandler ); @@ -337,7 +337,7 @@ void shouldReturnServerAddressWhenReleased() BoltServerAddress address = new BoltServerAddress( "host", 4242 ); ChannelAttributes.setServerAddress( channel, address ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.release(); assertEquals( address, connection.serverAddress() ); @@ -350,7 +350,7 @@ void shouldReturnServerVersionWhenReleased() ServerVersion version = ServerVersion.v3_2_0; ChannelAttributes.setServerVersion( channel, version ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.release(); assertEquals( version, connection.serverVersion() ); @@ -360,7 +360,7 @@ void shouldReturnServerVersionWhenReleased() void shouldReturnSameCompletionStageFromRelease() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); CompletionStage releaseStage1 = connection.release(); CompletionStage releaseStage2 = connection.release(); @@ -382,7 +382,7 @@ void shouldEnableAutoRead() { EmbeddedChannel channel = newChannel(); channel.config().setAutoRead( false ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.enableAutoRead(); @@ -394,7 +394,7 @@ void shouldDisableAutoRead() { EmbeddedChannel channel = newChannel(); channel.config().setAutoRead( true ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.disableAutoRead(); @@ -405,7 +405,7 @@ void shouldDisableAutoRead() void shouldSetTerminationReasonOnChannelWhenTerminated() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); String reason = "Something really bad has happened"; connection.terminateAndRelease( reason ); @@ -417,7 +417,7 @@ void shouldSetTerminationReasonOnChannelWhenTerminated() void shouldCloseChannelWhenTerminated() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); assertTrue( channel.isActive() ); connection.terminateAndRelease( "test" ); @@ -430,7 +430,7 @@ void shouldReleaseChannelWhenTerminated() { EmbeddedChannel channel = newChannel(); ChannelPool pool = mock( ChannelPool.class ); - NettyConnection connection = newConnection( channel, pool ); + DirectConnection connection = newConnection( channel, pool ); verify( pool, never() ).release( any() ); connection.terminateAndRelease( "test" ); @@ -443,7 +443,7 @@ void shouldNotReleaseChannelMultipleTimesWhenTerminatedMultipleTimes() { EmbeddedChannel channel = newChannel(); ChannelPool pool = mock( ChannelPool.class ); - NettyConnection connection = newConnection( channel, pool ); + DirectConnection connection = newConnection( channel, pool ); verify( pool, never() ).release( any() ); connection.terminateAndRelease( "reason 1" ); @@ -461,7 +461,7 @@ void shouldNotReleaseAfterTermination() { EmbeddedChannel channel = newChannel(); ChannelPool pool = mock( ChannelPool.class ); - NettyConnection connection = newConnection( channel, pool ); + DirectConnection connection = newConnection( channel, pool ); verify( pool, never() ).release( any() ); connection.terminateAndRelease( "test" ); @@ -477,7 +477,7 @@ void shouldNotReleaseAfterTermination() void shouldSendResetMessageWhenReset() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.reset(); channel.runPendingTasks(); @@ -490,7 +490,7 @@ void shouldSendResetMessageWhenReset() void shouldCompleteResetFutureWhenSuccessResponseArrives() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); CompletableFuture resetFuture = connection.reset().toCompletableFuture(); channel.runPendingTasks(); @@ -505,7 +505,7 @@ void shouldCompleteResetFutureWhenSuccessResponseArrives() void shouldCompleteResetFutureWhenFailureResponseArrives() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); CompletableFuture resetFuture = connection.reset().toCompletableFuture(); channel.runPendingTasks(); @@ -520,7 +520,7 @@ void shouldCompleteResetFutureWhenFailureResponseArrives() void shouldDoNothingInResetWhenClosed() { EmbeddedChannel channel = newChannel(); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.release(); channel.runPendingTasks(); @@ -539,7 +539,7 @@ void shouldEnableAutoReadWhenDoingReset() { EmbeddedChannel channel = newChannel(); channel.config().setAutoRead( false ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); connection.reset(); channel.runPendingTasks(); @@ -547,7 +547,7 @@ void shouldEnableAutoReadWhenDoingReset() assertTrue( channel.config().isAutoRead() ); } - private void testWriteInEventLoop( String threadName, Consumer action ) throws Exception + private void testWriteInEventLoop( String threadName, Consumer action ) throws Exception { EmbeddedChannel channel = spy( new EmbeddedChannel() ); initializeEventLoop( channel, threadName ); @@ -555,7 +555,7 @@ private void testWriteInEventLoop( String threadName, Consumer ChannelAttributes.setProtocolVersion( channel, DEFAULT_TEST_PROTOCOL_VERSION ); ChannelAttributes.setMessageDispatcher( channel, dispatcher ); - NettyConnection connection = newConnection( channel ); + DirectConnection connection = newConnection( channel ); action.accept( connection ); shutdownEventLoop(); @@ -591,14 +591,14 @@ private static EmbeddedChannel newChannel() return channel; } - private static NettyConnection newConnection( Channel channel ) + private static DirectConnection newConnection( Channel channel ) { return newConnection( channel, mock( ChannelPool.class ) ); } - private static NettyConnection newConnection( Channel channel, ChannelPool pool ) + private static DirectConnection newConnection( Channel channel, ChannelPool pool ) { - return new NettyConnection( channel, pool, new FakeClock(), DEV_NULL_METRICS ); + return new DirectConnection( channel, pool, new FakeClock(), DEV_NULL_METRICS ); } private static void assertConnectionReleasedError( IllegalStateException e ) From 5ae9780542bfb616fdc8264718841781b35d3714 Mon Sep 17 00:00:00 2001 From: lutovich Date: Wed, 25 Jul 2018 17:08:11 +0200 Subject: [PATCH 3/6] Rename Bookmark to Bookmarks This is a better name because class holds a collection of bookmarks, not just a single one. --- .../{Bookmark.java => Bookmarks.java} | 22 ++--- .../driver/internal/ExplicitTransaction.java | 18 ++-- .../neo4j/driver/internal/InternalDriver.java | 10 +-- .../neo4j/driver/internal/NetworkSession.java | 14 +-- .../neo4j/driver/internal/SessionFactory.java | 2 +- .../driver/internal/SessionFactoryImpl.java | 4 +- .../handlers/CommitTxResponseHandler.java | 4 +- .../internal/messaging/BoltProtocol.java | 6 +- .../messaging/request/BeginMessage.java | 6 +- .../request/RunWithMetadataMessage.java | 6 +- .../request/TransactionStartingMessage.java | 12 +-- .../internal/messaging/v1/BoltProtocolV1.java | 8 +- .../internal/messaging/v3/BoltProtocolV3.java | 8 +- .../{BookmarkTest.java => BookmarksTest.java} | 82 ++++++++--------- .../internal/ExplicitTransactionTest.java | 33 ++++--- .../driver/internal/NetworkSessionTest.java | 88 +++++++++---------- .../encode/BeginMessageEncoderTest.java | 8 +- .../RunWithMetadataMessageEncoderTest.java | 8 +- .../messaging/request/BeginMessageTest.java | 8 +- .../request/RunWithMetadataMessageTest.java | 8 +- .../messaging/v1/BoltProtocolV1Test.java | 10 +-- .../messaging/v3/MessageWriterV3Test.java | 10 +-- 22 files changed, 187 insertions(+), 188 deletions(-) rename driver/src/main/java/org/neo4j/driver/internal/{Bookmark.java => Bookmarks.java} (88%) rename driver/src/test/java/org/neo4j/driver/internal/{BookmarkTest.java => BookmarksTest.java} (57%) diff --git a/driver/src/main/java/org/neo4j/driver/internal/Bookmark.java b/driver/src/main/java/org/neo4j/driver/internal/Bookmarks.java similarity index 88% rename from driver/src/main/java/org/neo4j/driver/internal/Bookmark.java rename to driver/src/main/java/org/neo4j/driver/internal/Bookmarks.java index 3de6d1ff92..92b20c2f59 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/Bookmark.java +++ b/driver/src/main/java/org/neo4j/driver/internal/Bookmarks.java @@ -30,7 +30,7 @@ import static org.neo4j.driver.internal.util.Iterables.newHashMapWithSize; import static org.neo4j.driver.v1.Values.value; -public final class Bookmark +public final class Bookmarks { private static final String BOOKMARK_KEY = "bookmark"; private static final String BOOKMARKS_KEY = "bookmarks"; @@ -38,23 +38,23 @@ public final class Bookmark private static final long UNKNOWN_BOOKMARK_VALUE = -1; - private static final Bookmark EMPTY = new Bookmark( Collections.emptySet() ); + private static final Bookmarks EMPTY = new Bookmarks( Collections.emptySet() ); private final Iterable values; private final String maxValue; - private Bookmark( Iterable values ) + private Bookmarks( Iterable values ) { this.values = values; this.maxValue = maxBookmark( values ); } - public static Bookmark empty() + public static Bookmarks empty() { return EMPTY; } - public static Bookmark from( String value ) + public static Bookmarks from( String value ) { if ( value == null ) { @@ -63,13 +63,13 @@ public static Bookmark from( String value ) return from( singleton( value ) ); } - public static Bookmark from( Iterable values ) + public static Bookmarks from( Iterable values ) { if ( values == null ) { return empty(); } - return new Bookmark( values ); + return new Bookmarks( values ); } public boolean isEmpty() @@ -115,9 +115,9 @@ public boolean equals( Object o ) { return false; } - Bookmark bookmark = (Bookmark) o; - return Objects.equals( values, bookmark.values ) && - Objects.equals( maxValue, bookmark.maxValue ); + Bookmarks bookmarks = (Bookmarks) o; + return Objects.equals( values, bookmarks.values ) && + Objects.equals( maxValue, bookmarks.maxValue ); } @Override @@ -129,7 +129,7 @@ public int hashCode() @Override public String toString() { - return "Bookmark{values=" + values + "}"; + return "Bookmarks{values=" + values + "}"; } private static String maxBookmark( Iterable bookmarks ) diff --git a/driver/src/main/java/org/neo4j/driver/internal/ExplicitTransaction.java b/driver/src/main/java/org/neo4j/driver/internal/ExplicitTransaction.java index cd00e8aeea..2ac75c3e0f 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/ExplicitTransaction.java +++ b/driver/src/main/java/org/neo4j/driver/internal/ExplicitTransaction.java @@ -67,7 +67,7 @@ private enum State private final NetworkSession session; private final ResultCursorsHolder resultCursors; - private volatile Bookmark bookmark = Bookmark.empty(); + private volatile Bookmarks bookmarks = Bookmarks.empty(); private volatile State state = State.ACTIVE; public ExplicitTransaction( Connection connection, NetworkSession session ) @@ -78,9 +78,9 @@ public ExplicitTransaction( Connection connection, NetworkSession session ) this.resultCursors = new ResultCursorsHolder(); } - public CompletionStage beginAsync( Bookmark initialBookmark ) + public CompletionStage beginAsync( Bookmarks initialBookmarks ) { - return protocol.beginTransaction( connection, initialBookmark ) + return protocol.beginTransaction( connection, initialBookmarks ) .handle( ( ignore, beginError ) -> { if ( beginError != null ) @@ -228,16 +228,16 @@ public void markTerminated() state = State.TERMINATED; } - public Bookmark bookmark() + public Bookmarks bookmark() { - return bookmark; + return bookmarks; } - public void setBookmark( Bookmark bookmark ) + public void setBookmarks( Bookmarks bookmarks ) { - if ( bookmark != null && !bookmark.isEmpty() ) + if ( bookmarks != null && !bookmarks.isEmpty() ) { - this.bookmark = bookmark; + this.bookmarks = bookmarks; } } @@ -277,7 +277,7 @@ private void transactionClosed( State newState ) { state = newState; connection.release(); // release in background - session.setBookmark( bookmark ); + session.setBookmarks( bookmarks ); } private void terminateConnectionOnThreadInterrupt( String reason ) diff --git a/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java b/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java index ece1f1e872..63e50c3e5c 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java +++ b/driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java @@ -65,7 +65,7 @@ public Session session() @Override public Session session( AccessMode mode ) { - return newSession( mode, Bookmark.empty() ); + return newSession( mode, Bookmarks.empty() ); } @Override @@ -77,7 +77,7 @@ public Session session( String bookmark ) @Override public Session session( AccessMode mode, String bookmark ) { - return newSession( mode, Bookmark.from( bookmark ) ); + return newSession( mode, Bookmarks.from( bookmark ) ); } @Override @@ -89,13 +89,13 @@ public Session session( Iterable bookmarks ) @Override public Session session( AccessMode mode, Iterable bookmarks ) { - return newSession( mode, Bookmark.from( bookmarks ) ); + return newSession( mode, Bookmarks.from( bookmarks ) ); } - private Session newSession( AccessMode mode, Bookmark bookmark ) + private Session newSession( AccessMode mode, Bookmarks bookmarks ) { assertOpen(); - Session session = sessionFactory.newInstance( mode, bookmark ); + Session session = sessionFactory.newInstance( mode, bookmarks ); if ( closed.get() ) { // session does not immediately acquire connection, it is fine to just throw diff --git a/driver/src/main/java/org/neo4j/driver/internal/NetworkSession.java b/driver/src/main/java/org/neo4j/driver/internal/NetworkSession.java index 0845f3635a..c2be844bec 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/NetworkSession.java +++ b/driver/src/main/java/org/neo4j/driver/internal/NetworkSession.java @@ -52,7 +52,7 @@ public class NetworkSession extends AbstractStatementRunner implements Session private final RetryLogic retryLogic; protected final Logger logger; - private volatile Bookmark bookmark = Bookmark.empty(); + private volatile Bookmarks bookmarks = Bookmarks.empty(); private volatile CompletionStage transactionStage = completedWithNull(); private volatile CompletionStage connectionStage = completedWithNull(); private volatile CompletionStage resultCursorStage = completedWithNull(); @@ -138,7 +138,7 @@ public Transaction beginTransaction() @Override public Transaction beginTransaction( String bookmark ) { - setBookmark( Bookmark.from( bookmark ) ); + setBookmarks( Bookmarks.from( bookmark ) ); return beginTransaction(); } @@ -173,18 +173,18 @@ public CompletionStage writeTransactionAsync( TransactionWork beginTransactionAsync( AccessMode m .thenCompose( connection -> { ExplicitTransaction tx = new ExplicitTransaction( connection, NetworkSession.this ); - return tx.beginAsync( bookmark ); + return tx.beginAsync( bookmarks ); } ); // update the reference to the only known transaction diff --git a/driver/src/main/java/org/neo4j/driver/internal/SessionFactory.java b/driver/src/main/java/org/neo4j/driver/internal/SessionFactory.java index 713737aace..39445a910b 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/SessionFactory.java +++ b/driver/src/main/java/org/neo4j/driver/internal/SessionFactory.java @@ -25,7 +25,7 @@ public interface SessionFactory { - Session newInstance( AccessMode mode, Bookmark bookmark ); + Session newInstance( AccessMode mode, Bookmarks bookmarks ); CompletionStage verifyConnectivity(); diff --git a/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java b/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java index b2af91c2ef..99ad4dd1ba 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java +++ b/driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java @@ -43,10 +43,10 @@ public class SessionFactoryImpl implements SessionFactory } @Override - public Session newInstance( AccessMode mode, Bookmark bookmark ) + public Session newInstance( AccessMode mode, Bookmarks bookmarks ) { NetworkSession session = createSession( connectionProvider, retryLogic, mode, logging ); - session.setBookmark( bookmark ); + session.setBookmarks( bookmarks ); return session; } diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/CommitTxResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/CommitTxResponseHandler.java index 904907afb5..432ded406e 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/CommitTxResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/CommitTxResponseHandler.java @@ -22,7 +22,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.ExplicitTransaction; import org.neo4j.driver.internal.spi.ResponseHandler; import org.neo4j.driver.v1.Value; @@ -48,7 +48,7 @@ public void onSuccess( Map metadata ) { if ( tx != null ) { - tx.setBookmark( Bookmark.from( bookmarkValue.asString() ) ); + tx.setBookmarks( Bookmarks.from( bookmarkValue.asString() ) ); } } 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 ac588ea334..dfcc85d82a 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 @@ -24,7 +24,7 @@ import java.util.Map; import java.util.concurrent.CompletionStage; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.ExplicitTransaction; import org.neo4j.driver.internal.InternalStatementResultCursor; import org.neo4j.driver.internal.messaging.v1.BoltProtocolV1; @@ -61,10 +61,10 @@ public interface BoltProtocol * Begin an explicit transaction. * * @param connection the connection to use. - * @param bookmark the bookmark. Never null, should be {@link Bookmark#empty()} when absent. + * @param bookmarks the bookmarks. Never null, should be {@link Bookmarks#empty()} when absent. * @return a completion stage completed when transaction is started or completed exceptionally when there was a failure. */ - CompletionStage beginTransaction( Connection connection, Bookmark bookmark ); + CompletionStage beginTransaction( Connection connection, Bookmarks bookmarks ); /** * Commit the explicit transaction. diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java index d1f86891e7..2d10961f30 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/BeginMessage.java @@ -22,16 +22,16 @@ import java.util.Map; import java.util.Objects; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.v1.Value; public class BeginMessage extends TransactionStartingMessage { public static final byte SIGNATURE = 0x11; - public BeginMessage( Bookmark bookmark, Duration txTimeout, Map txMetadata ) + public BeginMessage( Bookmarks bookmarks, Duration txTimeout, Map txMetadata ) { - super( bookmark, txTimeout, txMetadata ); + super( bookmarks, txTimeout, txMetadata ); } @Override diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java index 608e7662c7..fa34a4bd29 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessage.java @@ -22,7 +22,7 @@ import java.util.Map; import java.util.Objects; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.v1.Value; public class RunWithMetadataMessage extends TransactionStartingMessage @@ -32,9 +32,9 @@ public class RunWithMetadataMessage extends TransactionStartingMessage private final String statement; private final Map parameters; - public RunWithMetadataMessage( String statement, Map parameters, Bookmark bookmark, Duration txTimeout, Map txMetadata ) + public RunWithMetadataMessage( String statement, Map parameters, Bookmarks bookmarks, Duration txTimeout, Map txMetadata ) { - super( bookmark, txTimeout, txMetadata ); + super( bookmarks, txTimeout, txMetadata ); this.statement = statement; this.parameters = parameters; } diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java index 5d0d4183dd..6d3407f490 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/request/TransactionStartingMessage.java @@ -21,7 +21,7 @@ import java.time.Duration; import java.util.Map; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.messaging.Message; import org.neo4j.driver.internal.util.Iterables; import org.neo4j.driver.v1.Value; @@ -36,9 +36,9 @@ abstract class TransactionStartingMessage implements Message final Map metadata; - TransactionStartingMessage( Bookmark bookmark, Duration txTimeout, Map txMetadata ) + TransactionStartingMessage( Bookmarks bookmarks, Duration txTimeout, Map txMetadata ) { - this.metadata = buildMetadata( bookmark, txTimeout, txMetadata ); + this.metadata = buildMetadata( bookmarks, txTimeout, txMetadata ); } public final Map metadata() @@ -46,13 +46,13 @@ public final Map metadata() return metadata; } - private static Map buildMetadata( Bookmark bookmark, Duration txTimeout, Map txMetadata ) + private static Map buildMetadata( Bookmarks bookmarks, Duration txTimeout, Map txMetadata ) { Map result = Iterables.newHashMapWithSize( 3 ); - if ( bookmark != null && !bookmark.isEmpty() ) + if ( bookmarks != null && !bookmarks.isEmpty() ) { - result.put( BOOKMARKS_METADATA_KEY, value( bookmark.values() ) ); + result.put( BOOKMARKS_METADATA_KEY, value( bookmarks.values() ) ); } if ( txTimeout != null ) diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java index ca10cbcae5..53b1bbd704 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java @@ -25,7 +25,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.ExplicitTransaction; import org.neo4j.driver.internal.InternalStatementResultCursor; import org.neo4j.driver.internal.handlers.BeginTxResponseHandler; @@ -83,9 +83,9 @@ public void initializeChannel( String userAgent, Map authToken, Ch } @Override - public CompletionStage beginTransaction( Connection connection, Bookmark bookmark ) + public CompletionStage beginTransaction( Connection connection, Bookmarks bookmarks ) { - if ( bookmark.isEmpty() ) + if ( bookmarks.isEmpty() ) { connection.write( BEGIN_MESSAGE, NoOpResponseHandler.INSTANCE, @@ -97,7 +97,7 @@ public CompletionStage beginTransaction( Connection connection, Bookmark b { CompletableFuture beginTxFuture = new CompletableFuture<>(); connection.writeAndFlush( - new RunMessage( BEGIN_QUERY, bookmark.asBeginTransactionParameters() ), NoOpResponseHandler.INSTANCE, + new RunMessage( BEGIN_QUERY, bookmarks.asBeginTransactionParameters() ), NoOpResponseHandler.INSTANCE, PullAllMessage.PULL_ALL, new BeginTxResponseHandler( beginTxFuture ) ); return beginTxFuture; diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java index 6741aceb25..6664c36125 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java @@ -25,7 +25,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.ExplicitTransaction; import org.neo4j.driver.internal.InternalStatementResultCursor; import org.neo4j.driver.internal.handlers.BeginTxResponseHandler; @@ -80,11 +80,11 @@ public void initializeChannel( String userAgent, Map authToken, Ch } @Override - public CompletionStage beginTransaction( Connection connection, Bookmark bookmark ) + public CompletionStage beginTransaction( Connection connection, Bookmarks bookmarks ) { - BeginMessage beginMessage = new BeginMessage( bookmark, null, null ); + BeginMessage beginMessage = new BeginMessage( bookmarks, null, null ); - if ( bookmark.isEmpty() ) + if ( bookmarks.isEmpty() ) { connection.write( beginMessage, NoOpResponseHandler.INSTANCE ); return Futures.completedWithNull(); diff --git a/driver/src/test/java/org/neo4j/driver/internal/BookmarkTest.java b/driver/src/test/java/org/neo4j/driver/internal/BookmarksTest.java similarity index 57% rename from driver/src/test/java/org/neo4j/driver/internal/BookmarkTest.java rename to driver/src/test/java/org/neo4j/driver/internal/BookmarksTest.java index 07116d3ac5..829ff11f2b 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/BookmarkTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/BookmarksTest.java @@ -38,72 +38,72 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.neo4j.driver.v1.Values.value; -class BookmarkTest +class BookmarksTest { @Test void isEmptyForEmptyBookmark() { - Bookmark bookmark = Bookmark.empty(); - assertTrue( bookmark.isEmpty() ); + Bookmarks bookmarks = Bookmarks.empty(); + assertTrue( bookmarks.isEmpty() ); } @Test void maxBookmarkAsStringForEmptyBookmark() { - Bookmark bookmark = Bookmark.empty(); - assertNull( bookmark.maxBookmarkAsString() ); + Bookmarks bookmarks = Bookmarks.empty(); + assertNull( bookmarks.maxBookmarkAsString() ); } @Test void asBeginTransactionParametersForEmptyBookmark() { - Bookmark bookmark = Bookmark.empty(); - assertEquals( emptyMap(), bookmark.asBeginTransactionParameters() ); + Bookmarks bookmarks = Bookmarks.empty(); + assertEquals( emptyMap(), bookmarks.asBeginTransactionParameters() ); } @Test void isEmptyForNonEmptyBookmark() { - Bookmark bookmark = Bookmark.from( "SomeBookmark" ); - assertFalse( bookmark.isEmpty() ); + Bookmarks bookmarks = Bookmarks.from( "SomeBookmark" ); + assertFalse( bookmarks.isEmpty() ); } @Test void maxBookmarkAsStringForNonEmptyBookmark() { - Bookmark bookmark = Bookmark.from( "SomeBookmark" ); - assertEquals( "SomeBookmark", bookmark.maxBookmarkAsString() ); + Bookmarks bookmarks = Bookmarks.from( "SomeBookmark" ); + assertEquals( "SomeBookmark", bookmarks.maxBookmarkAsString() ); } @Test void asBeginTransactionParametersForNonEmptyBookmark() { - Bookmark bookmark = Bookmark.from( "SomeBookmark" ); - verifyParameters( bookmark, "SomeBookmark", "SomeBookmark" ); + Bookmarks bookmarks = Bookmarks.from( "SomeBookmark" ); + verifyParameters( bookmarks, "SomeBookmark", "SomeBookmark" ); } @Test void bookmarkFromString() { - Bookmark bookmark = Bookmark.from( "Cat" ); - assertEquals( "Cat", bookmark.maxBookmarkAsString() ); - verifyParameters( bookmark, "Cat", "Cat" ); + Bookmarks bookmarks = Bookmarks.from( "Cat" ); + assertEquals( "Cat", bookmarks.maxBookmarkAsString() ); + verifyParameters( bookmarks, "Cat", "Cat" ); } @Test void bookmarkFromNullString() { - Bookmark bookmark = Bookmark.from( (String) null ); - assertTrue( bookmark.isEmpty() ); + Bookmarks bookmarks = Bookmarks.from( (String) null ); + assertTrue( bookmarks.isEmpty() ); } @Test void bookmarkFromIterable() { - Bookmark bookmark = Bookmark.from( asList( + Bookmarks bookmarks = Bookmarks.from( asList( "neo4j:bookmark:v1:tx42", "neo4j:bookmark:v1:tx10", "neo4j:bookmark:v1:tx12" ) ); - assertEquals( "neo4j:bookmark:v1:tx42", bookmark.maxBookmarkAsString() ); - verifyParameters( bookmark, + assertEquals( "neo4j:bookmark:v1:tx42", bookmarks.maxBookmarkAsString() ); + verifyParameters( bookmarks, "neo4j:bookmark:v1:tx42", "neo4j:bookmark:v1:tx42", "neo4j:bookmark:v1:tx10", "neo4j:bookmark:v1:tx12" ); } @@ -111,24 +111,24 @@ void bookmarkFromIterable() @Test void bookmarkFromNullIterable() { - Bookmark bookmark = Bookmark.from( (Iterable) null ); - assertTrue( bookmark.isEmpty() ); + Bookmarks bookmarks = Bookmarks.from( (Iterable) null ); + assertTrue( bookmarks.isEmpty() ); } @Test void bookmarkFromEmptyIterable() { - Bookmark bookmark = Bookmark.from( Collections.emptyList() ); - assertTrue( bookmark.isEmpty() ); + Bookmarks bookmarks = Bookmarks.from( Collections.emptyList() ); + assertTrue( bookmarks.isEmpty() ); } @Test void asBeginTransactionParametersForBookmarkWithInvalidValue() { - Bookmark bookmark = Bookmark.from( asList( + Bookmarks bookmarks = Bookmarks.from( asList( "neo4j:bookmark:v1:tx1", "neo4j:bookmark:v1:txcat", "neo4j:bookmark:v1:tx3" ) ); - assertEquals( "neo4j:bookmark:v1:tx3", bookmark.maxBookmarkAsString() ); - verifyParameters( bookmark, + assertEquals( "neo4j:bookmark:v1:tx3", bookmarks.maxBookmarkAsString() ); + verifyParameters( bookmarks, "neo4j:bookmark:v1:tx3", "neo4j:bookmark:v1:tx1", "neo4j:bookmark:v1:txcat", "neo4j:bookmark:v1:tx3" ); } @@ -136,9 +136,9 @@ void asBeginTransactionParametersForBookmarkWithInvalidValue() @Test void asBeginTransactionParametersForBookmarkWithEmptyStringValue() { - Bookmark bookmark = Bookmark.from( asList( "neo4j:bookmark:v1:tx9", "", "neo4j:bookmark:v1:tx3" ) ); - assertEquals( "neo4j:bookmark:v1:tx9", bookmark.maxBookmarkAsString() ); - verifyParameters( bookmark, + Bookmarks bookmarks = Bookmarks.from( asList( "neo4j:bookmark:v1:tx9", "", "neo4j:bookmark:v1:tx3" ) ); + assertEquals( "neo4j:bookmark:v1:tx9", bookmarks.maxBookmarkAsString() ); + verifyParameters( bookmarks, "neo4j:bookmark:v1:tx9", "neo4j:bookmark:v1:tx9", "", "neo4j:bookmark:v1:tx3" ); } @@ -146,9 +146,9 @@ void asBeginTransactionParametersForBookmarkWithEmptyStringValue() @Test void asBeginTransactionParametersForBookmarkWithNullValue() { - Bookmark bookmark = Bookmark.from( asList( "neo4j:bookmark:v1:tx41", null, "neo4j:bookmark:v1:tx42" ) ); - assertEquals( "neo4j:bookmark:v1:tx42", bookmark.maxBookmarkAsString() ); - verifyParameters( bookmark, + Bookmarks bookmarks = Bookmarks.from( asList( "neo4j:bookmark:v1:tx41", null, "neo4j:bookmark:v1:tx42" ) ); + assertEquals( "neo4j:bookmark:v1:tx42", bookmarks.maxBookmarkAsString() ); + verifyParameters( bookmarks, "neo4j:bookmark:v1:tx42", asList( "neo4j:bookmark:v1:tx41", null, "neo4j:bookmark:v1:tx42" ) ); } @@ -156,23 +156,23 @@ void asBeginTransactionParametersForBookmarkWithNullValue() @Test void shouldReturnAllBookmarks() { - assertIterableEquals( emptyList(), Bookmark.empty().values() ); - assertIterableEquals( singletonList( "neo4j:bookmark:v1:tx42" ), Bookmark.from( "neo4j:bookmark:v1:tx42" ).values() ); + assertIterableEquals( emptyList(), Bookmarks.empty().values() ); + assertIterableEquals( singletonList( "neo4j:bookmark:v1:tx42" ), Bookmarks.from( "neo4j:bookmark:v1:tx42" ).values() ); List bookmarks = asList( "neo4j:bookmark:v1:tx1", "neo4j:bookmark:v1:tx2", "neo4j:bookmark:v1:tx3" ); - assertIterableEquals( bookmarks, Bookmark.from( bookmarks ).values() ); + assertIterableEquals( bookmarks, Bookmarks.from( bookmarks ).values() ); } - private static void verifyParameters( Bookmark bookmark, String expectedMaxValue, String... expectedValues ) + private static void verifyParameters( Bookmarks bookmarks, String expectedMaxValue, String... expectedValues ) { - verifyParameters( bookmark, expectedMaxValue, asList( expectedValues ) ); + verifyParameters( bookmarks, expectedMaxValue, asList( expectedValues ) ); } - private static void verifyParameters( Bookmark bookmark, String expectedMaxValue, List expectedValues ) + private static void verifyParameters( Bookmarks bookmarks, String expectedMaxValue, List expectedValues ) { Map expectedParameters = new HashMap<>(); expectedParameters.put( "bookmark", value( expectedMaxValue ) ); expectedParameters.put( "bookmarks", value( expectedValues ) ); - assertEquals( expectedParameters, bookmark.asBeginTransactionParameters() ); + assertEquals( expectedParameters, bookmarks.asBeginTransactionParameters() ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/ExplicitTransactionTest.java b/driver/src/test/java/org/neo4j/driver/internal/ExplicitTransactionTest.java index c116fe9876..f1b440dbee 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/ExplicitTransactionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/ExplicitTransactionTest.java @@ -110,7 +110,7 @@ void shouldOnlyQueueMessagesWhenNoBookmarkGiven() { Connection connection = connectionMock(); - beginTx( connection, Bookmark.empty() ); + beginTx( connection, Bookmarks.empty() ); verify( connection ).write( eq( new RunMessage( "BEGIN" ) ), any(), eq( PullAllMessage.PULL_ALL ), any() ); verify( connection, never() ).writeAndFlush( any(), any(), any(), any() ); @@ -119,12 +119,12 @@ void shouldOnlyQueueMessagesWhenNoBookmarkGiven() @Test void shouldFlushWhenBookmarkGiven() { - Bookmark bookmark = Bookmark.from( "hi, I'm bookmark" ); + Bookmarks bookmarks = Bookmarks.from( "hi, I'm bookmark" ); Connection connection = connectionMock(); - beginTx( connection, bookmark ); + beginTx( connection, bookmarks ); - RunMessage expectedRunMessage = new RunMessage( "BEGIN", bookmark.asBeginTransactionParameters() ); + RunMessage expectedRunMessage = new RunMessage( "BEGIN", bookmarks.asBeginTransactionParameters() ); verify( connection ).writeAndFlush( eq( expectedRunMessage ), any(), eq( PullAllMessage.PULL_ALL ), any() ); verify( connection, never() ).write( any(), any(), any(), any() ); } @@ -210,7 +210,7 @@ void shouldHaveEmptyBookmarkInitially() @Test void shouldNotKeepInitialBookmark() { - ExplicitTransaction tx = beginTx( connectionMock(), Bookmark.from( "Dog" ) ); + ExplicitTransaction tx = beginTx( connectionMock(), Bookmarks.from( "Dog" ) ); assertTrue( tx.bookmark().isEmpty() ); } @@ -218,9 +218,9 @@ void shouldNotKeepInitialBookmark() void shouldNotOverwriteBookmarkWithNull() { ExplicitTransaction tx = beginTx( connectionMock() ); - tx.setBookmark( Bookmark.from( "Cat" ) ); + tx.setBookmarks( Bookmarks.from( "Cat" ) ); assertEquals( "Cat", tx.bookmark().maxBookmarkAsString() ); - tx.setBookmark( null ); + tx.setBookmarks( null ); assertEquals( "Cat", tx.bookmark().maxBookmarkAsString() ); } @@ -228,9 +228,9 @@ void shouldNotOverwriteBookmarkWithNull() void shouldNotOverwriteBookmarkWithEmptyBookmark() { ExplicitTransaction tx = beginTx( connectionMock() ); - tx.setBookmark( Bookmark.from( "Cat" ) ); + tx.setBookmarks( Bookmarks.from( "Cat" ) ); assertEquals( "Cat", tx.bookmark().maxBookmarkAsString() ); - tx.setBookmark( Bookmark.empty() ); + tx.setBookmarks( Bookmarks.empty() ); assertEquals( "Cat", tx.bookmark().maxBookmarkAsString() ); } @@ -241,7 +241,7 @@ void shouldReleaseConnectionWhenBeginFails() Connection connection = connectionWithBegin( handler -> handler.onFailure( error ) ); ExplicitTransaction tx = new ExplicitTransaction( connection, mock( NetworkSession.class ) ); - RuntimeException e = assertThrows( RuntimeException.class, () -> await( tx.beginAsync( Bookmark.from( "SomeBookmark" ) ) ) ); + RuntimeException e = assertThrows( RuntimeException.class, () -> await( tx.beginAsync( Bookmarks.from( "SomeBookmark" ) ) ) ); assertEquals( error, e ); verify( connection ).release(); @@ -252,7 +252,7 @@ void shouldNotReleaseConnectionWhenBeginSucceeds() { Connection connection = connectionWithBegin( handler -> handler.onSuccess( emptyMap() ) ); ExplicitTransaction tx = new ExplicitTransaction( connection, mock( NetworkSession.class ) ); - await( tx.beginAsync( Bookmark.from( "SomeBookmark" ) ) ); + await( tx.beginAsync( Bookmarks.from( "SomeBookmark" ) ) ); verify( connection, never() ).release(); } @@ -285,19 +285,18 @@ void shouldReleaseConnectionWhenTerminatedAndRolledBack() private static ExplicitTransaction beginTx( Connection connection ) { - return beginTx( connection, Bookmark.empty() ); + return beginTx( connection, Bookmarks.empty() ); } - private static ExplicitTransaction beginTx( Connection connection, Bookmark initialBookmark ) + private static ExplicitTransaction beginTx( Connection connection, Bookmarks initialBookmarks ) { - return beginTx( connection, mock( NetworkSession.class ), initialBookmark ); + return beginTx( connection, mock( NetworkSession.class ), initialBookmarks ); } - private static ExplicitTransaction beginTx( Connection connection, NetworkSession session, - Bookmark initialBookmark ) + private static ExplicitTransaction beginTx( Connection connection, NetworkSession session, Bookmarks initialBookmarks ) { ExplicitTransaction tx = new ExplicitTransaction( connection, session ); - return await( tx.beginAsync( initialBookmark ) ); + return await( tx.beginAsync( initialBookmarks ) ); } private static Connection connectionWithBegin( Consumer beginBehaviour ) diff --git a/driver/src/test/java/org/neo4j/driver/internal/NetworkSessionTest.java b/driver/src/test/java/org/neo4j/driver/internal/NetworkSessionTest.java index 7e41117b61..93b4f416ad 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/NetworkSessionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/NetworkSessionTest.java @@ -244,7 +244,7 @@ void acquiresNewConnectionForBeginTx() void updatesBookmarkWhenTxIsClosed() { Transaction tx = session.beginTransaction(); - setBookmark( tx, Bookmark.from( "TheBookmark" ) ); + setBookmarks( tx, Bookmarks.from( "TheBookmark" ) ); assertNull( session.lastBookmark() ); @@ -271,58 +271,58 @@ void releasesConnectionWhenTxIsClosed() @Test void bookmarkCanBeSet() { - Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx100" ); + Bookmarks bookmarks = Bookmarks.from( "neo4j:bookmark:v1:tx100" ); - session.setBookmark( bookmark ); + session.setBookmarks( bookmarks ); - assertEquals( bookmark.maxBookmarkAsString(), session.lastBookmark() ); + assertEquals( bookmarks.maxBookmarkAsString(), session.lastBookmark() ); } @Test void bookmarkIsPropagatedFromSession() { - Bookmark bookmark = Bookmark.from( "Bookmark" ); - NetworkSession session = newSession( connectionProvider, READ, bookmark ); + Bookmarks bookmarks = Bookmarks.from( "Bookmarks" ); + NetworkSession session = newSession( connectionProvider, READ, bookmarks ); Transaction tx = session.beginTransaction(); assertNotNull( tx ); - verifyBeginTx( connection, bookmark ); + verifyBeginTx( connection, bookmarks ); } @Test void bookmarkIsPropagatedInBeginTransaction() { - Bookmark bookmark = Bookmark.from( "Bookmark" ); + Bookmarks bookmarks = Bookmarks.from( "Bookmarks" ); NetworkSession session = newSession( connectionProvider, READ ); - session.setBookmark( bookmark ); + session.setBookmarks( bookmarks ); Transaction tx = session.beginTransaction(); assertNotNull( tx ); - verifyBeginTx( connection, bookmark ); + verifyBeginTx( connection, bookmarks ); } @Test void bookmarkIsPropagatedBetweenTransactions() { - Bookmark bookmark1 = Bookmark.from( "Bookmark1" ); - Bookmark bookmark2 = Bookmark.from( "Bookmark2" ); + Bookmarks bookmarks1 = Bookmarks.from( "Bookmark1" ); + Bookmarks bookmarks2 = Bookmarks.from( "Bookmark2" ); NetworkSession session = newSession( connectionProvider, READ ); try ( Transaction tx = session.beginTransaction() ) { - setBookmark( tx, bookmark1 ); + setBookmarks( tx, bookmarks1 ); } - assertEquals( bookmark1, Bookmark.from( session.lastBookmark() ) ); + assertEquals( bookmarks1, Bookmarks.from( session.lastBookmark() ) ); try ( Transaction tx = session.beginTransaction() ) { - verifyBeginTx( connection, bookmark1 ); - assertTrue( getBookmark( tx ).isEmpty() ); - setBookmark( tx, bookmark2 ); + verifyBeginTx( connection, bookmarks1 ); + assertTrue( getBookmarks( tx ).isEmpty() ); + setBookmarks( tx, bookmarks2 ); } - assertEquals( bookmark2, Bookmark.from( session.lastBookmark() ) ); + assertEquals( bookmarks2, Bookmarks.from( session.lastBookmark() ) ); } @Test @@ -342,7 +342,7 @@ void setLastBookmark() { NetworkSession session = newSession( mock( ConnectionProvider.class ), WRITE ); - session.setBookmark( Bookmark.from( "TheBookmark" ) ); + session.setBookmarks( Bookmarks.from( "TheBookmark" ) ); assertEquals( "TheBookmark", session.lastBookmark() ); } @@ -351,7 +351,7 @@ void setLastBookmark() void testPassingNoBookmarkShouldRetainBookmark() { NetworkSession session = newSession( connectionProvider, READ ); - session.setBookmark( Bookmark.from( "X" ) ); + session.setBookmarks( Bookmarks.from( "X" ) ); session.beginTransaction(); assertThat( session.lastBookmark(), equalTo( "X" ) ); } @@ -361,7 +361,7 @@ void testPassingNoBookmarkShouldRetainBookmark() void testPassingNullBookmarkShouldRetainBookmark() { NetworkSession session = newSession( connectionProvider, READ ); - session.setBookmark( Bookmark.from( "X" ) ); + session.setBookmarks( Bookmarks.from( "X" ) ); session.beginTransaction( null ); assertThat( session.lastBookmark(), equalTo( "X" ) ); } @@ -498,18 +498,18 @@ void shouldHaveNullLastBookmarkInitially() @Test void shouldNotOverwriteBookmarkWithNull() { - NetworkSession session = newSession( mock( ConnectionProvider.class ), READ, Bookmark.from( "Cat" ) ); + NetworkSession session = newSession( mock( ConnectionProvider.class ), READ, Bookmarks.from( "Cat" ) ); assertEquals( "Cat", session.lastBookmark() ); - session.setBookmark( null ); + session.setBookmarks( null ); assertEquals( "Cat", session.lastBookmark() ); } @Test void shouldNotOverwriteBookmarkWithEmptyBookmark() { - NetworkSession session = newSession( mock( ConnectionProvider.class ), READ, Bookmark.from( "Cat" ) ); + NetworkSession session = newSession( mock( ConnectionProvider.class ), READ, Bookmarks.from( "Cat" ) ); assertEquals( "Cat", session.lastBookmark() ); - session.setBookmark( Bookmark.empty() ); + session.setBookmarks( Bookmarks.empty() ); assertEquals( "Cat", session.lastBookmark() ); } @@ -552,8 +552,8 @@ void shouldRunAfterBeginTxFailureOnBookmark() when( connectionProvider.acquireConnection( READ ) ) .thenReturn( completedFuture( connection1 ) ).thenReturn( completedFuture( connection2 ) ); - Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx42" ); - session.setBookmark( bookmark ); + Bookmarks bookmarks = Bookmarks.from( "neo4j:bookmark:v1:tx42" ); + session.setBookmarks( bookmarks ); Exception e = assertThrows( Exception.class, session::beginTransaction ); assertEquals( error, e ); @@ -561,7 +561,7 @@ void shouldRunAfterBeginTxFailureOnBookmark() session.run( "RETURN 2" ); verify( connectionProvider, times( 2 ) ).acquireConnection( READ ); - verifyBeginTx( connection1, bookmark ); + verifyBeginTx( connection1, bookmarks ); verifyRunAndFlush( connection2, "RETURN 2", times( 1 ) ); } @@ -576,8 +576,8 @@ void shouldBeginTxAfterBeginTxFailureOnBookmark() when( connectionProvider.acquireConnection( READ ) ) .thenReturn( completedFuture( connection1 ) ).thenReturn( completedFuture( connection2 ) ); - Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx42" ); - session.setBookmark( bookmark ); + Bookmarks bookmarks = Bookmarks.from( "neo4j:bookmark:v1:tx42" ); + session.setBookmarks( bookmarks ); Exception e = assertThrows( Exception.class, session::beginTransaction ); assertEquals( error, e ); @@ -585,8 +585,8 @@ void shouldBeginTxAfterBeginTxFailureOnBookmark() session.beginTransaction(); verify( connectionProvider, times( 2 ) ).acquireConnection( READ ); - verifyBeginTx( connection1, bookmark ); - verifyBeginTx( connection2, bookmark ); + verifyBeginTx( connection1, bookmarks ); + verifyBeginTx( connection2, bookmarks ); } @Test @@ -807,25 +807,25 @@ else if ( mode == WRITE ) private static NetworkSession newSession( ConnectionProvider connectionProvider, AccessMode mode ) { - return newSession( connectionProvider, mode, Bookmark.empty() ); + return newSession( connectionProvider, mode, Bookmarks.empty() ); } private static NetworkSession newSession( ConnectionProvider connectionProvider, RetryLogic retryLogic ) { - return newSession( connectionProvider, WRITE, retryLogic, Bookmark.empty() ); + return newSession( connectionProvider, WRITE, retryLogic, Bookmarks.empty() ); } private static NetworkSession newSession( ConnectionProvider connectionProvider, AccessMode mode, - Bookmark bookmark ) + Bookmarks bookmarks ) { - return newSession( connectionProvider, mode, new FixedRetryLogic( 0 ), bookmark ); + return newSession( connectionProvider, mode, new FixedRetryLogic( 0 ), bookmarks ); } private static NetworkSession newSession( ConnectionProvider connectionProvider, AccessMode mode, - RetryLogic retryLogic, Bookmark bookmark ) + RetryLogic retryLogic, Bookmarks bookmarks ) { NetworkSession session = new NetworkSession( connectionProvider, mode, retryLogic, DEV_NULL_LOGGING ); - session.setBookmark( bookmark ); + session.setBookmarks( bookmarks ); return session; } @@ -839,15 +839,15 @@ private static void verifyBeginTx( Connection connectionMock, VerificationMode m verify( connectionMock, mode ).write( eq( new RunMessage( "BEGIN" ) ), any(), any(), any() ); } - private static void verifyBeginTx( Connection connectionMock, Bookmark bookmark ) + private static void verifyBeginTx( Connection connectionMock, Bookmarks bookmarks ) { - if ( bookmark.isEmpty() ) + if ( bookmarks.isEmpty() ) { verify( connectionMock ).write( eq( new RunMessage( "BEGIN" ) ), any(), any(), any() ); } else { - Map params = bookmark.asBeginTransactionParameters(); + Map params = bookmarks.asBeginTransactionParameters(); verify( connectionMock ).writeAndFlush( eq( new RunMessage( "BEGIN", params ) ), any(), eq( PullAllMessage.PULL_ALL ), any() ); } } @@ -867,14 +867,14 @@ private static void verifyRunAndFlush( Connection connectionMock, String stateme verify( connectionMock, mode ).writeAndFlush( eq( new RunMessage( statement ) ), any(), eq( PullAllMessage.PULL_ALL ), any() ); } - private static Bookmark getBookmark( Transaction tx ) + private static Bookmarks getBookmarks( Transaction tx ) { return ((ExplicitTransaction) tx).bookmark(); } - private static void setBookmark( Transaction tx, Bookmark bookmark ) + private static void setBookmarks( Transaction tx, Bookmarks bookmarks ) { - ((ExplicitTransaction) tx).setBookmark( bookmark ); + ((ExplicitTransaction) tx).setBookmarks( bookmarks ); } private static void setupFailingCommit( Connection connection, int times ) diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java index ca67435493..42e83a3ab1 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java @@ -7,7 +7,7 @@ import java.util.HashMap; import java.util.Map; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.messaging.ValuePacker; import org.neo4j.driver.internal.messaging.request.BeginMessage; import org.neo4j.driver.v1.Value; @@ -26,7 +26,7 @@ class BeginMessageEncoderTest @Test void shouldEncodeBeginMessage() throws Exception { - Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx42" ); + Bookmarks bookmarks = Bookmarks.from( "neo4j:bookmark:v1:tx42" ); Map txMetadata = new HashMap<>(); txMetadata.put( "hello", value( "world" ) ); @@ -34,13 +34,13 @@ void shouldEncodeBeginMessage() throws Exception Duration txTimeout = Duration.ofSeconds( 1 ); - encoder.encode( new BeginMessage( bookmark, txTimeout, txMetadata ), packer ); + encoder.encode( new BeginMessage( bookmarks, txTimeout, txMetadata ), packer ); InOrder order = inOrder( packer ); order.verify( packer ).packStructHeader( 1, BeginMessage.SIGNATURE ); Map expectedMetadata = new HashMap<>(); - expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "bookmarks", value( bookmarks.values() ) ); expectedMetadata.put( "tx_timeout", value( 1000 ) ); expectedMetadata.put( "tx_metadata", value( txMetadata ) ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java index 7d7135ee23..e5e0320519 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/RunWithMetadataMessageEncoderTest.java @@ -25,7 +25,7 @@ import java.util.HashMap; import java.util.Map; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.messaging.ValuePacker; import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage; import org.neo4j.driver.v1.Value; @@ -47,7 +47,7 @@ void shouldEncodeRunWithMetadataMessage() throws Exception { Map params = singletonMap( "answer", value( 42 ) ); - Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx999" ); + Bookmarks bookmarks = Bookmarks.from( "neo4j:bookmark:v1:tx999" ); Map txMetadata = new HashMap<>(); txMetadata.put( "key1", value( "value1" ) ); @@ -56,7 +56,7 @@ void shouldEncodeRunWithMetadataMessage() throws Exception Duration txTimeout = Duration.ofMillis( 42 ); - encoder.encode( new RunWithMetadataMessage( "RETURN $answer", params, bookmark, txTimeout, txMetadata ), packer ); + encoder.encode( new RunWithMetadataMessage( "RETURN $answer", params, bookmarks, txTimeout, txMetadata ), packer ); InOrder order = inOrder( packer ); order.verify( packer ).packStructHeader( 3, RunWithMetadataMessage.SIGNATURE ); @@ -64,7 +64,7 @@ void shouldEncodeRunWithMetadataMessage() throws Exception order.verify( packer ).pack( params ); Map expectedMetadata = new HashMap<>(); - expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "bookmarks", value( bookmarks.values() ) ); expectedMetadata.put( "tx_timeout", value( 42 ) ); expectedMetadata.put( "tx_metadata", value( txMetadata ) ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java index f1fc30f2bb..e35513b962 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java @@ -6,7 +6,7 @@ import java.util.HashMap; import java.util.Map; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.v1.Value; import static java.util.Arrays.asList; @@ -18,7 +18,7 @@ class BeginMessageTest @Test void shouldHaveCorrectMetadata() { - Bookmark bookmark = Bookmark.from( asList( "neo4j:bookmark:v1:tx42", "neo4j:bookmark:v1:tx4242", "neo4j:bookmark:v1:tx424242" ) ); + Bookmarks bookmarks = Bookmarks.from( asList( "neo4j:bookmark:v1:tx42", "neo4j:bookmark:v1:tx4242", "neo4j:bookmark:v1:tx424242" ) ); Map txMetadata = new HashMap<>(); txMetadata.put( "hello", value( "world" ) ); @@ -27,10 +27,10 @@ void shouldHaveCorrectMetadata() Duration txTimeout = Duration.ofSeconds( 13 ); - BeginMessage message = new BeginMessage( bookmark, txTimeout, txMetadata ); + BeginMessage message = new BeginMessage( bookmarks, txTimeout, txMetadata ); Map expectedMetadata = new HashMap<>(); - expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "bookmarks", value( bookmarks.values() ) ); expectedMetadata.put( "tx_timeout", value( 13_000 ) ); expectedMetadata.put( "tx_metadata", value( txMetadata ) ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java index eed84a55c7..c5b5e5b009 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java @@ -7,7 +7,7 @@ import java.util.HashMap; import java.util.Map; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.v1.Value; import static java.util.Arrays.asList; @@ -20,7 +20,7 @@ class RunWithMetadataMessageTest @Test void shouldHaveCorrectMetadata() { - Bookmark bookmark = Bookmark.from( asList( "neo4j:bookmark:v1:tx11", "neo4j:bookmark:v1:tx52" ) ); + Bookmarks bookmarks = Bookmarks.from( asList( "neo4j:bookmark:v1:tx11", "neo4j:bookmark:v1:tx52" ) ); Map txMetadata = new HashMap<>(); txMetadata.put( "foo", value( "bar" ) ); @@ -29,10 +29,10 @@ void shouldHaveCorrectMetadata() Duration txTimeout = Duration.ofSeconds( 7 ); - RunWithMetadataMessage message = new RunWithMetadataMessage( "RETURN 1", emptyMap(), bookmark, txTimeout, txMetadata ); + RunWithMetadataMessage message = new RunWithMetadataMessage( "RETURN 1", emptyMap(), bookmarks, txTimeout, txMetadata ); Map expectedMetadata = new HashMap<>(); - expectedMetadata.put( "bookmarks", value( bookmark.values() ) ); + expectedMetadata.put( "bookmarks", value( bookmarks.values() ) ); expectedMetadata.put( "tx_timeout", value( 7000 ) ); expectedMetadata.put( "tx_metadata", value( txMetadata ) ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1Test.java index 7a1091b41e..7e18f519ab 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1Test.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1Test.java @@ -30,7 +30,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.ExplicitTransaction; import org.neo4j.driver.internal.InternalStatementResultCursor; import org.neo4j.driver.internal.async.ChannelAttributes; @@ -141,7 +141,7 @@ void shouldBeginTransactionWithoutBookmark() { Connection connection = connectionMock(); - CompletionStage stage = protocol.beginTransaction( connection, Bookmark.empty() ); + CompletionStage stage = protocol.beginTransaction( connection, Bookmarks.empty() ); verify( connection ).write( new RunMessage( "BEGIN" ), NoOpResponseHandler.INSTANCE, @@ -154,12 +154,12 @@ void shouldBeginTransactionWithoutBookmark() void shouldBeginTransactionWithBookmark() { Connection connection = connectionMock(); - Bookmark bookmark = Bookmark.from( "neo4j:bookmark:v1:tx100" ); + Bookmarks bookmarks = Bookmarks.from( "neo4j:bookmark:v1:tx100" ); - CompletionStage stage = protocol.beginTransaction( connection, bookmark ); + CompletionStage stage = protocol.beginTransaction( connection, bookmarks ); verify( connection ).writeAndFlush( - eq( new RunMessage( "BEGIN", bookmark.asBeginTransactionParameters() ) ), eq( NoOpResponseHandler.INSTANCE ), + eq( new RunMessage( "BEGIN", bookmarks.asBeginTransactionParameters() ) ), eq( NoOpResponseHandler.INSTANCE ), eq( PullAllMessage.PULL_ALL ), any( BeginTxResponseHandler.class ) ); assertNull( Futures.blockingGet( stage ) ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java index 8fba751279..499139dc26 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java @@ -4,7 +4,7 @@ import java.time.ZonedDateTime; import java.util.stream.Stream; -import org.neo4j.driver.internal.Bookmark; +import org.neo4j.driver.internal.Bookmarks; import org.neo4j.driver.internal.messaging.AbstractMessageWriterTestBase; import org.neo4j.driver.internal.messaging.Message; import org.neo4j.driver.internal.messaging.MessageFormat; @@ -43,19 +43,19 @@ protected Stream supportedMessages() // Bolt V3 messages new HelloMessage( "MyDriver/1.2.3", ((InternalAuthToken) basic( "neo4j", "neo4j" )).toMap() ), GOODBYE, - new BeginMessage( Bookmark.from( "neo4j:bookmark:v1:tx123" ), Duration.ofSeconds( 5 ), singletonMap( "key", value( 42 ) ) ), + new BeginMessage( Bookmarks.from( "neo4j:bookmark:v1:tx123" ), Duration.ofSeconds( 5 ), singletonMap( "key", value( 42 ) ) ), COMMIT, ROLLBACK, - new RunWithMetadataMessage( "RETURN 1", emptyMap(), Bookmark.from( "neo4j:bookmark:v1:tx1" ), Duration.ofSeconds( 5 ), + new RunWithMetadataMessage( "RETURN 1", emptyMap(), Bookmarks.from( "neo4j:bookmark:v1:tx1" ), Duration.ofSeconds( 5 ), singletonMap( "key", value( 42 ) ) ), PULL_ALL, DISCARD_ALL, RESET, // Bolt V3 messages with struct values - new RunWithMetadataMessage( "RETURN $x", singletonMap( "x", value( ZonedDateTime.now() ) ), Bookmark.empty(), + new RunWithMetadataMessage( "RETURN $x", singletonMap( "x", value( ZonedDateTime.now() ) ), Bookmarks.empty(), Duration.ofSeconds( 1 ), emptyMap() ), - new RunWithMetadataMessage( "RETURN $x", singletonMap( "x", point( 42, 1, 2, 3 ) ), Bookmark.empty(), + new RunWithMetadataMessage( "RETURN $x", singletonMap( "x", point( 42, 1, 2, 3 ) ), Bookmarks.empty(), Duration.ofSeconds( 1 ), emptyMap() ) ); } From 0494c9eecb995f47f8113f6a032c0d220736aea9 Mon Sep 17 00:00:00 2001 From: lutovich Date: Wed, 25 Jul 2018 17:40:52 +0200 Subject: [PATCH 4/6] Fix ErrorIT to use correct message format It always used V1 message format before. --- ...pelineBuilderWithFailingMessageFormat.java} | 18 +++++++++++------- ...DriverFactoryWithFailingMessageFormat.java} | 18 +++++++++--------- .../internal/util/FailingMessageFormat.java | 6 ------ .../neo4j/driver/v1/integration/ErrorIT.java | 9 +++------ 4 files changed, 23 insertions(+), 28 deletions(-) rename driver/src/test/java/org/neo4j/driver/internal/util/{ChannelPipelineBuilderWithMessageFormat.java => ChannelPipelineBuilderWithFailingMessageFormat.java} (64%) rename driver/src/test/java/org/neo4j/driver/internal/util/{ChannelTrackingDriverFactoryWithMessageFormat.java => ChannelTrackingDriverFactoryWithFailingMessageFormat.java} (66%) diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/ChannelPipelineBuilderWithMessageFormat.java b/driver/src/test/java/org/neo4j/driver/internal/util/ChannelPipelineBuilderWithFailingMessageFormat.java similarity index 64% rename from driver/src/test/java/org/neo4j/driver/internal/util/ChannelPipelineBuilderWithMessageFormat.java rename to driver/src/test/java/org/neo4j/driver/internal/util/ChannelPipelineBuilderWithFailingMessageFormat.java index 694c8d283f..d1de1e34c3 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/ChannelPipelineBuilderWithMessageFormat.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/ChannelPipelineBuilderWithFailingMessageFormat.java @@ -25,18 +25,22 @@ import org.neo4j.driver.internal.messaging.MessageFormat; import org.neo4j.driver.v1.Logging; -public class ChannelPipelineBuilderWithMessageFormat implements ChannelPipelineBuilder +public class ChannelPipelineBuilderWithFailingMessageFormat implements ChannelPipelineBuilder { - private final MessageFormat messageFormat; + private volatile FailingMessageFormat failingMessageFormat; - public ChannelPipelineBuilderWithMessageFormat( MessageFormat messageFormat ) + @Override + public void build( MessageFormat messageFormat, ChannelPipeline pipeline, Logging logging ) { - this.messageFormat = messageFormat; + if ( failingMessageFormat == null ) + { + failingMessageFormat = new FailingMessageFormat( messageFormat ); + } + new ChannelPipelineBuilderImpl().build( failingMessageFormat, pipeline, logging ); } - @Override - public void build( MessageFormat ignored, ChannelPipeline pipeline, Logging logging ) + FailingMessageFormat getFailingMessageFormat() { - new ChannelPipelineBuilderImpl().build( messageFormat, pipeline, logging ); + return failingMessageFormat; } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/ChannelTrackingDriverFactoryWithMessageFormat.java b/driver/src/test/java/org/neo4j/driver/internal/util/ChannelTrackingDriverFactoryWithFailingMessageFormat.java similarity index 66% rename from driver/src/test/java/org/neo4j/driver/internal/util/ChannelTrackingDriverFactoryWithMessageFormat.java rename to driver/src/test/java/org/neo4j/driver/internal/util/ChannelTrackingDriverFactoryWithFailingMessageFormat.java index 16a28db0cc..50dbe61dc4 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/ChannelTrackingDriverFactoryWithMessageFormat.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/ChannelTrackingDriverFactoryWithFailingMessageFormat.java @@ -21,27 +21,27 @@ import org.neo4j.driver.internal.ConnectionSettings; import org.neo4j.driver.internal.async.ChannelConnector; import org.neo4j.driver.internal.async.ChannelConnectorImpl; -import org.neo4j.driver.internal.async.ChannelPipelineBuilder; -import org.neo4j.driver.internal.messaging.MessageFormat; import org.neo4j.driver.internal.security.SecurityPlan; import org.neo4j.driver.v1.Config; -public class ChannelTrackingDriverFactoryWithMessageFormat extends ChannelTrackingDriverFactory +public class ChannelTrackingDriverFactoryWithFailingMessageFormat extends ChannelTrackingDriverFactory { - private final MessageFormat messageFormat; + private final ChannelPipelineBuilderWithFailingMessageFormat pipelineBuilder = new ChannelPipelineBuilderWithFailingMessageFormat(); - public ChannelTrackingDriverFactoryWithMessageFormat( MessageFormat messageFormat, Clock clock ) + public ChannelTrackingDriverFactoryWithFailingMessageFormat( Clock clock ) { super( clock ); - this.messageFormat = messageFormat; } @Override - protected ChannelConnector createRealConnector( ConnectionSettings settings, SecurityPlan securityPlan, - Config config, Clock clock ) + protected ChannelConnector createRealConnector( ConnectionSettings settings, SecurityPlan securityPlan, Config config, Clock clock ) { - ChannelPipelineBuilder pipelineBuilder = new ChannelPipelineBuilderWithMessageFormat( messageFormat ); return new ChannelConnectorImpl( settings, securityPlan, pipelineBuilder, config.logging(), clock ); } + + public FailingMessageFormat getFailingMessageFormat() + { + return pipelineBuilder.getFailingMessageFormat(); + } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/FailingMessageFormat.java b/driver/src/test/java/org/neo4j/driver/internal/util/FailingMessageFormat.java index cc79f822a8..fe23ef6e7e 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/FailingMessageFormat.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/FailingMessageFormat.java @@ -27,7 +27,6 @@ import org.neo4j.driver.internal.messaging.MessageFormat; import org.neo4j.driver.internal.messaging.ResponseMessageHandler; import org.neo4j.driver.internal.messaging.response.FailureMessage; -import org.neo4j.driver.internal.messaging.v1.MessageFormatV1; import org.neo4j.driver.internal.packstream.PackInput; import org.neo4j.driver.internal.packstream.PackOutput; @@ -38,11 +37,6 @@ public class FailingMessageFormat implements MessageFormat private final AtomicReference readerThrowableRef = new AtomicReference<>(); private final AtomicReference readerFailureRef = new AtomicReference<>(); - public FailingMessageFormat() - { - this( new MessageFormatV1() ); - } - public FailingMessageFormat( MessageFormat delegate ) { this.delegate = delegate; diff --git a/driver/src/test/java/org/neo4j/driver/v1/integration/ErrorIT.java b/driver/src/test/java/org/neo4j/driver/v1/integration/ErrorIT.java index afb508cd55..18427b9b68 100644 --- a/driver/src/test/java/org/neo4j/driver/v1/integration/ErrorIT.java +++ b/driver/src/test/java/org/neo4j/driver/v1/integration/ErrorIT.java @@ -32,7 +32,7 @@ import org.neo4j.driver.internal.messaging.response.FailureMessage; import org.neo4j.driver.internal.retry.RetrySettings; import org.neo4j.driver.internal.util.ChannelTrackingDriverFactory; -import org.neo4j.driver.internal.util.ChannelTrackingDriverFactoryWithMessageFormat; +import org.neo4j.driver.internal.util.ChannelTrackingDriverFactoryWithFailingMessageFormat; import org.neo4j.driver.internal.util.FailingMessageFormat; import org.neo4j.driver.internal.util.FakeClock; import org.neo4j.driver.v1.AuthToken; @@ -231,10 +231,7 @@ void shouldCloseChannelOnInboundFatalFailureMessage() throws InterruptedExceptio private Throwable testChannelErrorHandling( Consumer messageFormatSetup ) throws InterruptedException { - FailingMessageFormat messageFormat = new FailingMessageFormat(); - - ChannelTrackingDriverFactoryWithMessageFormat driverFactory = new ChannelTrackingDriverFactoryWithMessageFormat( - messageFormat, new FakeClock() ); + ChannelTrackingDriverFactoryWithFailingMessageFormat driverFactory = new ChannelTrackingDriverFactoryWithFailingMessageFormat( new FakeClock() ); URI uri = session.uri(); AuthToken authToken = session.authToken(); @@ -246,7 +243,7 @@ private Throwable testChannelErrorHandling( Consumer messa try ( Driver driver = driverFactory.newInstance( uri, authToken, routingSettings, retrySettings, config ); Session session = driver.session() ) { - messageFormatSetup.accept( messageFormat ); + messageFormatSetup.accept( driverFactory.getFailingMessageFormat() ); try { From bb31f06f461b4030295ebd635a69a844d4304670 Mon Sep 17 00:00:00 2001 From: lutovich Date: Thu, 26 Jul 2018 12:29:54 +0200 Subject: [PATCH 5/6] Fix handing of response metadata in Bolt V3 Metadata keys are different in previous versions of the protocol. This commit makes it possible for keys to be defined by each Bolt protocol implementation. Also fixed couple unit tests and added license headers. --- .../handlers/PullAllResponseHandler.java | 6 ++- .../internal/handlers/RunResponseHandler.java | 6 ++- .../SessionPullAllResponseHandler.java | 4 +- .../TransactionPullAllResponseHandler.java | 4 +- .../internal/messaging/v1/BoltProtocolV1.java | 9 +++-- .../internal/messaging/v3/BoltProtocolV3.java | 9 +++-- .../driver/internal/util/MetadataUtil.java | 12 +++--- .../InternalStatementResultCursorTest.java | 13 +++++-- .../internal/InternalStatementResultTest.java | 6 ++- .../internal/async/DirectConnectionTest.java | 2 + .../async/HandshakeCompletedListenerTest.java | 9 +++++ .../handlers/HelloResponseHandlerTest.java | 18 +++++++++ .../handlers/PullAllResponseHandlerTest.java | 11 ++++-- .../handlers/RunResponseHandlerTest.java | 5 ++- .../SessionPullAllResponseHandlerTest.java | 6 ++- ...TransactionPullAllResponseHandlerTest.java | 7 +++- .../encode/BeginMessageEncoderTest.java | 18 +++++++++ .../encode/HelloMessageEncoderTest.java | 18 +++++++++ .../messaging/request/BeginMessageTest.java | 18 +++++++++ .../messaging/request/HelloMessageTest.java | 18 +++++++++ .../request/RunWithMetadataMessageTest.java | 18 +++++++++ .../messaging/v3/MessageFormatV3Test.java | 18 +++++++++ .../messaging/v3/MessageWriterV3Test.java | 18 +++++++++ .../internal/util/MetadataUtilTest.java | 39 ++++++++++--------- 24 files changed, 238 insertions(+), 54 deletions(-) diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java index 2ec7e87b65..b6a34300e1 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java @@ -53,6 +53,7 @@ public abstract class PullAllResponseHandler implements ResponseHandler private final Statement statement; private final RunResponseHandler runResponseHandler; + private final String resultConsumedAfterMetadataKey; protected final Connection connection; // initialized lazily when first record arrives @@ -66,10 +67,11 @@ public abstract class PullAllResponseHandler implements ResponseHandler private CompletableFuture recordFuture; private CompletableFuture failureFuture; - public PullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, Connection connection ) + public PullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, String resultConsumedAfterMetadataKey, Connection connection ) { this.statement = requireNonNull( statement ); this.runResponseHandler = requireNonNull( runResponseHandler ); + this.resultConsumedAfterMetadataKey = requireNonNull( resultConsumedAfterMetadataKey ); this.connection = requireNonNull( connection ); } @@ -317,6 +319,6 @@ private boolean completeFailureFuture( Throwable error ) private ResultSummary extractResultSummary( Map metadata ) { long resultAvailableAfter = runResponseHandler.resultAvailableAfter(); - return MetadataUtil.extractSummary( statement, connection, resultAvailableAfter, metadata ); + return MetadataUtil.extractSummary( statement, connection, resultAvailableAfter, metadata, resultConsumedAfterMetadataKey ); } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java index 69bac83174..487e0b1762 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java @@ -32,20 +32,22 @@ public class RunResponseHandler implements ResponseHandler { private final CompletableFuture runCompletedFuture; + private final String resultAvailableAfterMetadataKey; private List statementKeys = emptyList(); private long resultAvailableAfter = -1; - public RunResponseHandler( CompletableFuture runCompletedFuture ) + public RunResponseHandler( CompletableFuture runCompletedFuture, String resultAvailableAfterMetadataKey ) { this.runCompletedFuture = runCompletedFuture; + this.resultAvailableAfterMetadataKey = resultAvailableAfterMetadataKey; } @Override public void onSuccess( Map metadata ) { statementKeys = extractStatementKeys( metadata ); - resultAvailableAfter = extractResultAvailableAfter( metadata ); + resultAvailableAfter = extractResultAvailableAfter( metadata, resultAvailableAfterMetadataKey ); completeRunFuture(); } diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java index feaf8eb30d..5b69686995 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java @@ -24,9 +24,9 @@ public class SessionPullAllResponseHandler extends PullAllResponseHandler { public SessionPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, - Connection connection ) + String resultConsumedAfterMetadataKey, Connection connection ) { - super( statement, runResponseHandler, connection ); + super( statement, runResponseHandler, resultConsumedAfterMetadataKey, connection ); } @Override diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java index 0e4b95a587..cf169e53e8 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java @@ -28,10 +28,10 @@ public class TransactionPullAllResponseHandler extends PullAllResponseHandler { private final ExplicitTransaction tx; - public TransactionPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, + public TransactionPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, String resultConsumedAfterMetadataKey, Connection connection, ExplicitTransaction tx ) { - super( statement, runResponseHandler, connection ); + super( statement, runResponseHandler, resultConsumedAfterMetadataKey, connection ); this.tx = requireNonNull( tx ); } diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java index 53b1bbd704..35cda56ef6 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java @@ -59,6 +59,9 @@ public class BoltProtocolV1 implements BoltProtocol public static final BoltProtocol INSTANCE = new BoltProtocolV1(); + public static final String RESULT_AVAILABLE_AFTER_METADATA_KEY = "result_available_after"; + public static final String RESULT_CONSUMED_AFTER_METADATA_KEY = "result_consumed_after"; + private static final String BEGIN_QUERY = "BEGIN"; private static final Message BEGIN_MESSAGE = new RunMessage( BEGIN_QUERY ); private static final Message COMMIT_MESSAGE = new RunMessage( "COMMIT" ); @@ -150,7 +153,7 @@ private static CompletionStage runStatement( Conn Map params = statement.parameters().asMap( ofValue() ); CompletableFuture runCompletedFuture = new CompletableFuture<>(); - RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture ); + RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture, RESULT_AVAILABLE_AFTER_METADATA_KEY ); PullAllResponseHandler pullAllHandler = newPullAllHandler( statement, runHandler, connection, tx ); connection.writeAndFlush( @@ -174,8 +177,8 @@ private static PullAllResponseHandler newPullAllHandler( Statement statement, Ru { if ( tx != null ) { - return new TransactionPullAllResponseHandler( statement, runHandler, connection, tx ); + return new TransactionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection, tx ); } - return new SessionPullAllResponseHandler( statement, runHandler, connection ); + return new SessionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java index 6664c36125..bbd33cc6bf 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java @@ -61,6 +61,9 @@ public class BoltProtocolV3 implements BoltProtocol public static final BoltProtocol INSTANCE = new BoltProtocolV3(); + public static final String RESULT_AVAILABLE_AFTER_METADATA_KEY = "t_first"; + public static final String RESULT_CONSUMED_AFTER_METADATA_KEY = "t_last"; + @Override public MessageFormat createMessageFormat() { @@ -134,7 +137,7 @@ private static CompletionStage runStatement( Conn CompletableFuture runCompletedFuture = new CompletableFuture<>(); Message runMessage = new RunWithMetadataMessage( query, params, null, null, null ); - RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture ); + RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture, RESULT_AVAILABLE_AFTER_METADATA_KEY ); PullAllResponseHandler pullAllHandler = newPullAllHandler( statement, runHandler, connection, tx ); connection.writeAndFlush( runMessage, runHandler, PULL_ALL, pullAllHandler ); @@ -156,8 +159,8 @@ private static PullAllResponseHandler newPullAllHandler( Statement statement, Ru { if ( tx != null ) { - return new TransactionPullAllResponseHandler( statement, runHandler, connection, tx ); + return new TransactionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection, tx ); } - return new SessionPullAllResponseHandler( statement, runHandler, connection ); + return new SessionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataUtil.java b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataUtil.java index fbf4c8cc23..953f78ef3c 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataUtil.java +++ b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataUtil.java @@ -66,9 +66,9 @@ public static List extractStatementKeys( Map metadata ) return emptyList(); } - public static long extractResultAvailableAfter( Map metadata ) + public static long extractResultAvailableAfter( Map metadata, String key ) { - Value resultAvailableAfterValue = metadata.get( "result_available_after" ); + Value resultAvailableAfterValue = metadata.get( key ); if ( resultAvailableAfterValue != null ) { return resultAvailableAfterValue.asLong(); @@ -77,12 +77,12 @@ public static long extractResultAvailableAfter( Map metadata ) } public static ResultSummary extractSummary( Statement statement, Connection connection, long resultAvailableAfter, - Map metadata ) + Map metadata, String resultConsumedAfterMetadataKey ) { ServerInfo serverInfo = new InternalServerInfo( connection.serverAddress(), connection.serverVersion() ); return new InternalResultSummary( statement, serverInfo, extractStatementType( metadata ), extractCounters( metadata ), extractPlan( metadata ), extractProfiledPlan( metadata ), - extractNotifications( metadata ), resultAvailableAfter, extractResultConsumedAfter( metadata ) ); + extractNotifications( metadata ), resultAvailableAfter, extractResultConsumedAfter( metadata, resultConsumedAfterMetadataKey ) ); } private static StatementType extractStatementType( Map metadata ) @@ -153,9 +153,9 @@ private static List extractNotifications( Map metada return Collections.emptyList(); } - private static long extractResultConsumedAfter( Map metadata ) + private static long extractResultConsumedAfter( Map metadata, String key ) { - Value resultConsumedAfterValue = metadata.get( "result_consumed_after" ); + Value resultConsumedAfterValue = metadata.get( key ); if ( resultConsumedAfterValue != null ) { return resultConsumedAfterValue.asLong(); diff --git a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java index db7e783d18..8f13148979 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java @@ -28,6 +28,7 @@ import org.neo4j.driver.internal.handlers.PullAllResponseHandler; import org.neo4j.driver.internal.handlers.RunResponseHandler; +import org.neo4j.driver.internal.messaging.v1.BoltProtocolV1; import org.neo4j.driver.internal.summary.InternalResultSummary; import org.neo4j.driver.internal.summary.InternalServerInfo; import org.neo4j.driver.internal.summary.InternalSummaryCounters; @@ -66,7 +67,7 @@ class InternalStatementResultCursorTest @Test void shouldReturnStatementKeys() { - RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>() ); + RunResponseHandler runHandler = newRunResponseHandler(); PullAllResponseHandler pullAllHandler = mock( PullAllResponseHandler.class ); List keys = asList( "key1", "key2", "key3" ); @@ -395,12 +396,16 @@ void shouldPropagateFailureInConsumeAsync() private static InternalStatementResultCursor newCursor( PullAllResponseHandler pullAllHandler ) { - return new InternalStatementResultCursor( new RunResponseHandler( new CompletableFuture<>() ), pullAllHandler ); + return new InternalStatementResultCursor( newRunResponseHandler(), pullAllHandler ); } - private static InternalStatementResultCursor newCursor( RunResponseHandler runHandler, - PullAllResponseHandler pullAllHandler ) + private static InternalStatementResultCursor newCursor( RunResponseHandler runHandler, PullAllResponseHandler pullAllHandler ) { return new InternalStatementResultCursor( runHandler, pullAllHandler ); } + + private static RunResponseHandler newRunResponseHandler() + { + return new RunResponseHandler( new CompletableFuture<>(), BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY ); + } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java index 6d9ecfaf9d..29075c5250 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java @@ -52,6 +52,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.neo4j.driver.internal.BoltServerAddress.LOCAL_DEFAULT; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; import static org.neo4j.driver.v1.Records.column; import static org.neo4j.driver.v1.Values.ofString; import static org.neo4j.driver.v1.Values.value; @@ -348,14 +350,14 @@ void shouldNotPeekIntoTheFutureWhenResultIsEmpty() private StatementResult createResult( int numberOfRecords ) { - RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>() ); + RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); runHandler.onSuccess( singletonMap( "fields", value( Arrays.asList( "k1", "k2" ) ) ) ); Statement statement = new Statement( "" ); Connection connection = mock( Connection.class ); when( connection.serverAddress() ).thenReturn( LOCAL_DEFAULT ); when( connection.serverVersion() ).thenReturn( ServerVersion.v3_2_0 ); - PullAllResponseHandler pullAllHandler = new SessionPullAllResponseHandler( statement, runHandler, connection ); + PullAllResponseHandler pullAllHandler = new SessionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); for ( int i = 1; i <= numberOfRecords; i++ ) { diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/DirectConnectionTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/DirectConnectionTest.java index 3464df7d86..f5ac495b98 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/DirectConnectionTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/DirectConnectionTest.java @@ -196,6 +196,7 @@ void shouldWriteAndFlushSingleMessage() DirectConnection connection = newConnection( channel ); connection.writeAndFlush( PULL_ALL, NO_OP_HANDLER ); + channel.runPendingTasks(); // writeAndFlush is scheduled to execute in the event loop thread, trigger its execution assertEquals( 1, channel.outboundMessages().size() ); assertEquals( PULL_ALL, single( channel.outboundMessages() ) ); @@ -208,6 +209,7 @@ void shouldWriteAndFlushMultipleMessage() DirectConnection connection = newConnection( channel ); connection.writeAndFlush( PULL_ALL, NO_OP_HANDLER, RESET, NO_OP_HANDLER ); + channel.runPendingTasks(); // writeAndFlush is scheduled to execute in the event loop thread, trigger its execution assertEquals( 2, channel.outboundMessages().size() ); assertEquals( PULL_ALL, channel.outboundMessages().poll() ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/async/HandshakeCompletedListenerTest.java b/driver/src/test/java/org/neo4j/driver/internal/async/HandshakeCompletedListenerTest.java index cff61a4cfb..46f74398b9 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/async/HandshakeCompletedListenerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/async/HandshakeCompletedListenerTest.java @@ -28,11 +28,14 @@ import java.util.Map; import org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher; +import org.neo4j.driver.internal.handlers.HelloResponseHandler; import org.neo4j.driver.internal.handlers.InitResponseHandler; import org.neo4j.driver.internal.messaging.Message; +import org.neo4j.driver.internal.messaging.request.HelloMessage; import org.neo4j.driver.internal.messaging.request.InitMessage; 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.spi.ResponseHandler; import org.neo4j.driver.v1.Value; @@ -88,6 +91,12 @@ void shouldWriteInitializationMessageInBoltV2WhenHandshakeCompleted() testWritingOfInitializationMessage( BoltProtocolV2.VERSION, new InitMessage( USER_AGENT, authToken() ), InitResponseHandler.class ); } + @Test + void shouldWriteInitializationMessageInBoltV3WhenHandshakeCompleted() + { + testWritingOfInitializationMessage( BoltProtocolV3.VERSION, new HelloMessage( USER_AGENT, authToken() ), HelloResponseHandler.class ); + } + private void testWritingOfInitializationMessage( int protocolVersion, Message expectedMessage, Class handlerType ) { InboundMessageDispatcher messageDispatcher = mock( InboundMessageDispatcher.class ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java index f49298b6e8..bec961dfec 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/HelloResponseHandlerTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.handlers; import io.netty.channel.ChannelFuture; diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java index bf67099b7b..2532564767 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java @@ -54,6 +54,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; import static org.neo4j.driver.v1.Values.value; import static org.neo4j.driver.v1.Values.values; import static org.neo4j.driver.v1.util.TestUtil.await; @@ -1067,9 +1069,9 @@ private static PullAllResponseHandler newHandler( List statementKeys, Co private static PullAllResponseHandler newHandler( Statement statement, List statementKeys, Connection connection ) { - RunResponseHandler runResponseHandler = new RunResponseHandler( new CompletableFuture<>() ); + RunResponseHandler runResponseHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); runResponseHandler.onSuccess( singletonMap( "fields", value( statementKeys ) ) ); - return new TestPullAllResponseHandler( statement, runResponseHandler, connection ); + return new TestPullAllResponseHandler( statement, runResponseHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); } private static Connection connectionMock() @@ -1089,9 +1091,10 @@ private static void assertNoRecordsCanBeFetched( PullAllResponseHandler handler private static class TestPullAllResponseHandler extends PullAllResponseHandler { - TestPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, Connection connection ) + public TestPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, String resultConsumedAfterMetadataKey, + Connection connection ) { - super( statement, runResponseHandler, connection ); + super( statement, runResponseHandler, resultConsumedAfterMetadataKey, connection ); } @Override diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java index 630a95ccee..25e57fea37 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java @@ -32,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; import static org.neo4j.driver.v1.Values.value; import static org.neo4j.driver.v1.Values.values; @@ -114,11 +115,11 @@ void shouldReturnResultAvailableAfterWhenSucceeded() private static RunResponseHandler newHandler() { - return new RunResponseHandler( new CompletableFuture<>() ); + return newHandler( new CompletableFuture<>() ); } private static RunResponseHandler newHandler( CompletableFuture runCompletedFuture ) { - return new RunResponseHandler( runCompletedFuture ); + return new RunResponseHandler( runCompletedFuture, RESULT_AVAILABLE_AFTER_METADATA_KEY ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java index d5d24aa197..9b6528b4b1 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java @@ -31,6 +31,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; class SessionPullAllResponseHandlerTest { @@ -58,8 +60,8 @@ void shouldReleaseConnectionOnFailure() private SessionPullAllResponseHandler newHandler( Connection connection ) { - return new SessionPullAllResponseHandler( new Statement( "RETURN 1" ), - new RunResponseHandler( new CompletableFuture<>() ), connection ); + RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); + return new SessionPullAllResponseHandler( new Statement( "RETURN 1" ), runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); } private static Connection newConnectionMock() diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java index 39edf755d9..5403542d55 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java @@ -36,6 +36,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; class TransactionPullAllResponseHandlerTest { @@ -61,8 +63,9 @@ private static void testErrorHandling( Throwable error ) when( connection.serverAddress() ).thenReturn( BoltServerAddress.LOCAL_DEFAULT ); when( connection.serverVersion() ).thenReturn( ServerVersion.v3_2_0 ); ExplicitTransaction tx = mock( ExplicitTransaction.class ); - TransactionPullAllResponseHandler handler = new TransactionPullAllResponseHandler( new Statement( "RETURN 1" ), - new RunResponseHandler( new CompletableFuture<>() ), connection, tx ); + RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); + PullAllResponseHandler handler = new TransactionPullAllResponseHandler( new Statement( "RETURN 1" ), runHandler, + RESULT_CONSUMED_AFTER_METADATA_KEY, connection, tx ); handler.onFailure( error ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java index 42e83a3ab1..c6a843ee61 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/BeginMessageEncoderTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.encode; import org.junit.jupiter.api.Test; diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java index 7afb85df9c..fbc64073ef 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/encode/HelloMessageEncoderTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.encode; import org.junit.jupiter.api.Test; diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java index e35513b962..8851186f34 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/BeginMessageTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.request; import org.junit.jupiter.api.Test; diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java index c498fb3ba7..4cd6d9fece 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/HelloMessageTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.request; import org.junit.jupiter.api.Test; diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java index c5b5e5b009..5eecf920d1 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/request/RunWithMetadataMessageTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.request; import org.junit.jupiter.api.Test; diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java index 394c20f1ab..b62de27bd8 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageFormatV3Test.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.v3; import org.junit.jupiter.api.Test; diff --git a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java index 499139dc26..22255c53cb 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java +++ b/driver/src/test/java/org/neo4j/driver/internal/messaging/v3/MessageWriterV3Test.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2002-2018 "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.v3; import java.time.Duration; diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataUtilTest.java b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataUtilTest.java index fa8b041b9d..c1df724d9a 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataUtilTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataUtilTest.java @@ -58,6 +58,9 @@ class MetadataUtilTest { + private static final String RESULT_AVAILABLE_AFTER_KEY = "available_after"; + private static final String RESULT_CONSUMED_AFTER_KEY = "consumed_after"; + @Test void shouldExtractStatementKeys() { @@ -76,15 +79,15 @@ void shouldExtractEmptyStatementKeysWhenNoneInMetadata() @Test void shouldExtractResultAvailableAfter() { - long extractedResultAvailableAfter = extractResultAvailableAfter( - singletonMap( "result_available_after", value( 424242 ) ) ); + Map metadata = singletonMap( RESULT_AVAILABLE_AFTER_KEY, value( 424242 ) ); + long extractedResultAvailableAfter = extractResultAvailableAfter( metadata, RESULT_AVAILABLE_AFTER_KEY ); assertEquals( 424242L, extractedResultAvailableAfter ); } @Test void shouldExtractNoResultAvailableAfterWhenNoneInMetadata() { - long extractedResultAvailableAfter = extractResultAvailableAfter( emptyMap() ); + long extractedResultAvailableAfter = extractResultAvailableAfter( emptyMap(), RESULT_AVAILABLE_AFTER_KEY ); assertEquals( -1, extractedResultAvailableAfter ); } @@ -94,7 +97,7 @@ void shouldBuildResultSummaryWithStatement() Statement statement = new Statement( "UNWIND range(10, 100) AS x CREATE (:Node {name: $name, x: x})", singletonMap( "name", "Apa" ) ); - ResultSummary summary = extractSummary( statement, connectionMock(), 42, emptyMap() ); + ResultSummary summary = extractSummary( statement, connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertEquals( statement, summary.statement() ); } @@ -104,7 +107,7 @@ void shouldBuildResultSummaryWithServerInfo() { Connection connection = connectionMock( new BoltServerAddress( "server:42" ), ServerVersion.v3_2_0 ); - ResultSummary summary = extractSummary( statement(), connection, 42, emptyMap() ); + ResultSummary summary = extractSummary( statement(), connection, 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertEquals( "server:42", summary.server().address() ); assertEquals( "Neo4j/3.2.0", summary.server().version() ); @@ -140,7 +143,7 @@ void shouldBuildResultSummaryWithCounters() Map metadata = singletonMap( "stats", stats ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); assertEquals( 42, summary.counters().nodesCreated() ); assertEquals( 4242, summary.counters().nodesDeleted() ); @@ -158,7 +161,7 @@ void shouldBuildResultSummaryWithCounters() @Test void shouldBuildResultSummaryWithoutCounters() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap() ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertEquals( EMPTY_STATS, summary.counters() ); } @@ -179,7 +182,7 @@ void shouldBuildResultSummaryWithPlan() ) ); Map metadata = singletonMap( "plan", plan ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); assertTrue( summary.hasPlan() ); assertEquals( "Projection", summary.plan().operatorType() ); @@ -199,7 +202,7 @@ void shouldBuildResultSummaryWithPlan() @Test void shouldBuildResultSummaryWithoutPlan() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap() ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertFalse( summary.hasPlan() ); assertNull( summary.plan() ); } @@ -225,7 +228,7 @@ void shouldBuildResultSummaryWithProfiledPlan() ) ); Map metadata = singletonMap( "profile", profile ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); assertTrue( summary.hasPlan() ); assertTrue( summary.hasProfile() ); @@ -249,7 +252,7 @@ void shouldBuildResultSummaryWithProfiledPlan() @Test void shouldBuildResultSummaryWithoutProfiledPlan() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap() ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertFalse( summary.hasProfile() ); assertNull( summary.profile() ); } @@ -282,7 +285,7 @@ void shouldBuildResultSummaryWithNotifications() Value notifications = value( notification1, notification2 ); Map metadata = singletonMap( "notifications", notifications ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); assertEquals( 2, summary.notifications().size() ); Notification firstNotification = summary.notifications().get( 0 ); @@ -304,7 +307,7 @@ void shouldBuildResultSummaryWithNotifications() @Test void shouldBuildResultSummaryWithoutNotifications() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap() ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertEquals( 0, summary.notifications().size() ); } @@ -313,7 +316,7 @@ void shouldBuildResultSummaryWithResultAvailableAfter() { int value = 42_000; - ResultSummary summary = extractSummary( statement(), connectionMock(), value, emptyMap() ); + ResultSummary summary = extractSummary( statement(), connectionMock(), value, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertEquals( 42, summary.resultAvailableAfter( TimeUnit.SECONDS ) ); assertEquals( value, summary.resultAvailableAfter( TimeUnit.MILLISECONDS ) ); @@ -323,9 +326,9 @@ void shouldBuildResultSummaryWithResultAvailableAfter() void shouldBuildResultSummaryWithResultConsumedAfter() { int value = 42_000; - Map metadata = singletonMap( "result_consumed_after", value( value ) ); + Map metadata = singletonMap( RESULT_CONSUMED_AFTER_KEY, value( value ) ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); assertEquals( 42, summary.resultConsumedAfter( TimeUnit.SECONDS ) ); assertEquals( value, summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) ); @@ -334,7 +337,7 @@ void shouldBuildResultSummaryWithResultConsumedAfter() @Test void shouldBuildResultSummaryWithoutResultConsumedAfter() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap() ); + ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); assertEquals( -1, summary.resultConsumedAfter( TimeUnit.SECONDS ) ); assertEquals( -1, summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) ); } @@ -342,7 +345,7 @@ void shouldBuildResultSummaryWithoutResultConsumedAfter() private static ResultSummary createWithStatementType( Value typeValue ) { Map metadata = singletonMap( "type", typeValue ); - return extractSummary( statement(), connectionMock(), 42, metadata ); + return extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); } private static Statement statement() From 0f7ce4a771c16670cb226129718fb869812013e4 Mon Sep 17 00:00:00 2001 From: lutovich Date: Fri, 27 Jul 2018 14:17:19 +0200 Subject: [PATCH 6/6] Version metadata extraction utility Instead of passing string metadata keys around. This is needed because some metadata keys have changed in Bolt V3 compared to Bolt V1. --- .../handlers/PullAllResponseHandler.java | 10 ++--- .../internal/handlers/RunResponseHandler.java | 13 +++--- .../SessionPullAllResponseHandler.java | 5 ++- .../TransactionPullAllResponseHandler.java | 7 +-- .../internal/messaging/v1/BoltProtocolV1.java | 10 ++--- .../internal/messaging/v3/BoltProtocolV3.java | 10 ++--- ...tadataUtil.java => MetadataExtractor.java} | 18 +++++--- .../InternalStatementResultCursorTest.java | 2 +- .../internal/InternalStatementResultTest.java | 7 ++- .../handlers/PullAllResponseHandlerTest.java | 12 +++-- .../handlers/RunResponseHandlerTest.java | 36 ++++++++++++--- .../SessionPullAllResponseHandlerTest.java | 9 ++-- ...TransactionPullAllResponseHandlerTest.java | 7 ++- ...ilTest.java => MetadataExtractorTest.java} | 45 +++++++++---------- 14 files changed, 107 insertions(+), 84 deletions(-) rename driver/src/main/java/org/neo4j/driver/internal/util/{MetadataUtil.java => MetadataExtractor.java} (87%) rename driver/src/test/java/org/neo4j/driver/internal/util/{MetadataUtilTest.java => MetadataExtractorTest.java} (84%) diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java index b6a34300e1..11a400a8d4 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/PullAllResponseHandler.java @@ -31,7 +31,7 @@ import org.neo4j.driver.internal.spi.ResponseHandler; import org.neo4j.driver.internal.util.Futures; import org.neo4j.driver.internal.util.Iterables; -import org.neo4j.driver.internal.util.MetadataUtil; +import org.neo4j.driver.internal.util.MetadataExtractor; import org.neo4j.driver.v1.Record; import org.neo4j.driver.v1.Statement; import org.neo4j.driver.v1.Value; @@ -53,7 +53,7 @@ public abstract class PullAllResponseHandler implements ResponseHandler private final Statement statement; private final RunResponseHandler runResponseHandler; - private final String resultConsumedAfterMetadataKey; + private final MetadataExtractor metadataExtractor; protected final Connection connection; // initialized lazily when first record arrives @@ -67,11 +67,11 @@ public abstract class PullAllResponseHandler implements ResponseHandler private CompletableFuture recordFuture; private CompletableFuture failureFuture; - public PullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, String resultConsumedAfterMetadataKey, Connection connection ) + public PullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, Connection connection, MetadataExtractor metadataExtractor ) { this.statement = requireNonNull( statement ); this.runResponseHandler = requireNonNull( runResponseHandler ); - this.resultConsumedAfterMetadataKey = requireNonNull( resultConsumedAfterMetadataKey ); + this.metadataExtractor = requireNonNull( metadataExtractor ); this.connection = requireNonNull( connection ); } @@ -319,6 +319,6 @@ private boolean completeFailureFuture( Throwable error ) private ResultSummary extractResultSummary( Map metadata ) { long resultAvailableAfter = runResponseHandler.resultAvailableAfter(); - return MetadataUtil.extractSummary( statement, connection, resultAvailableAfter, metadata, resultConsumedAfterMetadataKey ); + return metadataExtractor.extractSummary( statement, connection, resultAvailableAfter, metadata ); } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java index 487e0b1762..c6e3a1ebe5 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/RunResponseHandler.java @@ -23,31 +23,30 @@ import java.util.concurrent.CompletableFuture; import org.neo4j.driver.internal.spi.ResponseHandler; +import org.neo4j.driver.internal.util.MetadataExtractor; import org.neo4j.driver.v1.Value; import static java.util.Collections.emptyList; -import static org.neo4j.driver.internal.util.MetadataUtil.extractResultAvailableAfter; -import static org.neo4j.driver.internal.util.MetadataUtil.extractStatementKeys; public class RunResponseHandler implements ResponseHandler { private final CompletableFuture runCompletedFuture; - private final String resultAvailableAfterMetadataKey; + private final MetadataExtractor metadataExtractor; private List statementKeys = emptyList(); private long resultAvailableAfter = -1; - public RunResponseHandler( CompletableFuture runCompletedFuture, String resultAvailableAfterMetadataKey ) + public RunResponseHandler( CompletableFuture runCompletedFuture, MetadataExtractor metadataExtractor ) { this.runCompletedFuture = runCompletedFuture; - this.resultAvailableAfterMetadataKey = resultAvailableAfterMetadataKey; + this.metadataExtractor = metadataExtractor; } @Override public void onSuccess( Map metadata ) { - statementKeys = extractStatementKeys( metadata ); - resultAvailableAfter = extractResultAvailableAfter( metadata, resultAvailableAfterMetadataKey ); + statementKeys = metadataExtractor.extractStatementKeys( metadata ); + resultAvailableAfter = metadataExtractor.extractResultAvailableAfter( metadata ); completeRunFuture(); } diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java index 5b69686995..3097ba4f06 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandler.java @@ -19,14 +19,15 @@ package org.neo4j.driver.internal.handlers; import org.neo4j.driver.internal.spi.Connection; +import org.neo4j.driver.internal.util.MetadataExtractor; import org.neo4j.driver.v1.Statement; public class SessionPullAllResponseHandler extends PullAllResponseHandler { public SessionPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, - String resultConsumedAfterMetadataKey, Connection connection ) + Connection connection, MetadataExtractor metadataExtractor ) { - super( statement, runResponseHandler, resultConsumedAfterMetadataKey, connection ); + super( statement, runResponseHandler, connection, metadataExtractor ); } @Override diff --git a/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java b/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java index cf169e53e8..64729fe0c0 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java +++ b/driver/src/main/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandler.java @@ -20,6 +20,7 @@ import org.neo4j.driver.internal.ExplicitTransaction; import org.neo4j.driver.internal.spi.Connection; +import org.neo4j.driver.internal.util.MetadataExtractor; import org.neo4j.driver.v1.Statement; import static java.util.Objects.requireNonNull; @@ -28,10 +29,10 @@ public class TransactionPullAllResponseHandler extends PullAllResponseHandler { private final ExplicitTransaction tx; - public TransactionPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, String resultConsumedAfterMetadataKey, - Connection connection, ExplicitTransaction tx ) + public TransactionPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, + Connection connection, ExplicitTransaction tx, MetadataExtractor metadataExtractor ) { - super( statement, runResponseHandler, resultConsumedAfterMetadataKey, connection ); + super( statement, runResponseHandler, connection, metadataExtractor ); this.tx = requireNonNull( tx ); } diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java index 35cda56ef6..219de4af16 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java @@ -46,6 +46,7 @@ import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.spi.ResponseHandler; import org.neo4j.driver.internal.util.Futures; +import org.neo4j.driver.internal.util.MetadataExtractor; import org.neo4j.driver.v1.Statement; import org.neo4j.driver.v1.Value; @@ -59,8 +60,7 @@ public class BoltProtocolV1 implements BoltProtocol public static final BoltProtocol INSTANCE = new BoltProtocolV1(); - public static final String RESULT_AVAILABLE_AFTER_METADATA_KEY = "result_available_after"; - public static final String RESULT_CONSUMED_AFTER_METADATA_KEY = "result_consumed_after"; + public static final MetadataExtractor METADATA_EXTRACTOR = new MetadataExtractor( "result_available_after", "result_consumed_after" ); private static final String BEGIN_QUERY = "BEGIN"; private static final Message BEGIN_MESSAGE = new RunMessage( BEGIN_QUERY ); @@ -153,7 +153,7 @@ private static CompletionStage runStatement( Conn Map params = statement.parameters().asMap( ofValue() ); CompletableFuture runCompletedFuture = new CompletableFuture<>(); - RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture, RESULT_AVAILABLE_AFTER_METADATA_KEY ); + RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture, METADATA_EXTRACTOR ); PullAllResponseHandler pullAllHandler = newPullAllHandler( statement, runHandler, connection, tx ); connection.writeAndFlush( @@ -177,8 +177,8 @@ private static PullAllResponseHandler newPullAllHandler( Statement statement, Ru { if ( tx != null ) { - return new TransactionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection, tx ); + return new TransactionPullAllResponseHandler( statement, runHandler, connection, tx, METADATA_EXTRACTOR ); } - return new SessionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); + return new SessionPullAllResponseHandler( statement, runHandler, connection, METADATA_EXTRACTOR ); } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java index bbd33cc6bf..3b18627c67 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java +++ b/driver/src/main/java/org/neo4j/driver/internal/messaging/v3/BoltProtocolV3.java @@ -45,6 +45,7 @@ import org.neo4j.driver.internal.messaging.request.RunWithMetadataMessage; import org.neo4j.driver.internal.spi.Connection; import org.neo4j.driver.internal.util.Futures; +import org.neo4j.driver.internal.util.MetadataExtractor; import org.neo4j.driver.v1.Statement; import org.neo4j.driver.v1.Value; @@ -61,8 +62,7 @@ public class BoltProtocolV3 implements BoltProtocol public static final BoltProtocol INSTANCE = new BoltProtocolV3(); - public static final String RESULT_AVAILABLE_AFTER_METADATA_KEY = "t_first"; - public static final String RESULT_CONSUMED_AFTER_METADATA_KEY = "t_last"; + public static final MetadataExtractor METADATA_EXTRACTOR = new MetadataExtractor( "t_first", "t_last" ); @Override public MessageFormat createMessageFormat() @@ -137,7 +137,7 @@ private static CompletionStage runStatement( Conn CompletableFuture runCompletedFuture = new CompletableFuture<>(); Message runMessage = new RunWithMetadataMessage( query, params, null, null, null ); - RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture, RESULT_AVAILABLE_AFTER_METADATA_KEY ); + RunResponseHandler runHandler = new RunResponseHandler( runCompletedFuture, METADATA_EXTRACTOR ); PullAllResponseHandler pullAllHandler = newPullAllHandler( statement, runHandler, connection, tx ); connection.writeAndFlush( runMessage, runHandler, PULL_ALL, pullAllHandler ); @@ -159,8 +159,8 @@ private static PullAllResponseHandler newPullAllHandler( Statement statement, Ru { if ( tx != null ) { - return new TransactionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection, tx ); + return new TransactionPullAllResponseHandler( statement, runHandler, connection, tx, METADATA_EXTRACTOR ); } - return new SessionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); + return new SessionPullAllResponseHandler( statement, runHandler, connection, METADATA_EXTRACTOR ); } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataUtil.java b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java similarity index 87% rename from driver/src/main/java/org/neo4j/driver/internal/util/MetadataUtil.java rename to driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java index 953f78ef3c..6a3895c5e0 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/util/MetadataUtil.java +++ b/driver/src/main/java/org/neo4j/driver/internal/util/MetadataExtractor.java @@ -41,13 +41,18 @@ import static java.util.Collections.emptyList; -public final class MetadataUtil +public class MetadataExtractor { - private MetadataUtil() + private final String resultAvailableAfterMetadataKey; + private final String resultConsumedAfterMetadataKey; + + public MetadataExtractor( String resultAvailableAfterMetadataKey, String resultConsumedAfterMetadataKey ) { + this.resultAvailableAfterMetadataKey = resultAvailableAfterMetadataKey; + this.resultConsumedAfterMetadataKey = resultConsumedAfterMetadataKey; } - public static List extractStatementKeys( Map metadata ) + public List extractStatementKeys( Map metadata ) { Value keysValue = metadata.get( "fields" ); if ( keysValue != null ) @@ -66,9 +71,9 @@ public static List extractStatementKeys( Map metadata ) return emptyList(); } - public static long extractResultAvailableAfter( Map metadata, String key ) + public long extractResultAvailableAfter( Map metadata ) { - Value resultAvailableAfterValue = metadata.get( key ); + Value resultAvailableAfterValue = metadata.get( resultAvailableAfterMetadataKey ); if ( resultAvailableAfterValue != null ) { return resultAvailableAfterValue.asLong(); @@ -76,8 +81,7 @@ public static long extractResultAvailableAfter( Map metadata, Stri return -1; } - public static ResultSummary extractSummary( Statement statement, Connection connection, long resultAvailableAfter, - Map metadata, String resultConsumedAfterMetadataKey ) + public ResultSummary extractSummary( Statement statement, Connection connection, long resultAvailableAfter, Map metadata ) { ServerInfo serverInfo = new InternalServerInfo( connection.serverAddress(), connection.serverVersion() ); return new InternalResultSummary( statement, serverInfo, extractStatementType( metadata ), diff --git a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java index 8f13148979..b6cf135544 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultCursorTest.java @@ -406,6 +406,6 @@ private static InternalStatementResultCursor newCursor( RunResponseHandler runHa private static RunResponseHandler newRunResponseHandler() { - return new RunResponseHandler( new CompletableFuture<>(), BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY ); + return new RunResponseHandler( new CompletableFuture<>(), BoltProtocolV1.METADATA_EXTRACTOR ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java index 29075c5250..a8b172b5f0 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/InternalStatementResultTest.java @@ -52,8 +52,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.neo4j.driver.internal.BoltServerAddress.LOCAL_DEFAULT; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.METADATA_EXTRACTOR; import static org.neo4j.driver.v1.Records.column; import static org.neo4j.driver.v1.Values.ofString; import static org.neo4j.driver.v1.Values.value; @@ -350,14 +349,14 @@ void shouldNotPeekIntoTheFutureWhenResultIsEmpty() private StatementResult createResult( int numberOfRecords ) { - RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); + RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), METADATA_EXTRACTOR ); runHandler.onSuccess( singletonMap( "fields", value( Arrays.asList( "k1", "k2" ) ) ) ); Statement statement = new Statement( "" ); Connection connection = mock( Connection.class ); when( connection.serverAddress() ).thenReturn( LOCAL_DEFAULT ); when( connection.serverVersion() ).thenReturn( ServerVersion.v3_2_0 ); - PullAllResponseHandler pullAllHandler = new SessionPullAllResponseHandler( statement, runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); + PullAllResponseHandler pullAllHandler = new SessionPullAllResponseHandler( statement, runHandler, connection, METADATA_EXTRACTOR ); for ( int i = 1; i <= numberOfRecords; i++ ) { diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java index 2532564767..7901ddf24e 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/PullAllResponseHandlerTest.java @@ -54,8 +54,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.METADATA_EXTRACTOR; import static org.neo4j.driver.v1.Values.value; import static org.neo4j.driver.v1.Values.values; import static org.neo4j.driver.v1.util.TestUtil.await; @@ -1069,9 +1068,9 @@ private static PullAllResponseHandler newHandler( List statementKeys, Co private static PullAllResponseHandler newHandler( Statement statement, List statementKeys, Connection connection ) { - RunResponseHandler runResponseHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); + RunResponseHandler runResponseHandler = new RunResponseHandler( new CompletableFuture<>(), METADATA_EXTRACTOR ); runResponseHandler.onSuccess( singletonMap( "fields", value( statementKeys ) ) ); - return new TestPullAllResponseHandler( statement, runResponseHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); + return new TestPullAllResponseHandler( statement, runResponseHandler, connection ); } private static Connection connectionMock() @@ -1091,10 +1090,9 @@ private static void assertNoRecordsCanBeFetched( PullAllResponseHandler handler private static class TestPullAllResponseHandler extends PullAllResponseHandler { - public TestPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, String resultConsumedAfterMetadataKey, - Connection connection ) + public TestPullAllResponseHandler( Statement statement, RunResponseHandler runResponseHandler, Connection connection ) { - super( statement, runResponseHandler, resultConsumedAfterMetadataKey, connection ); + super( statement, runResponseHandler, connection, METADATA_EXTRACTOR ); } @Override diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java index 25e57fea37..b17202f3a3 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/RunResponseHandlerTest.java @@ -23,6 +23,10 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +import org.neo4j.driver.internal.messaging.v1.BoltProtocolV1; +import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3; +import org.neo4j.driver.internal.util.MetadataExtractor; + import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; @@ -32,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; import static org.neo4j.driver.v1.Values.value; import static org.neo4j.driver.v1.Values.values; @@ -104,22 +107,43 @@ void shouldReturnKeysWhenSucceeded() } @Test - void shouldReturnResultAvailableAfterWhenSucceeded() + void shouldReturnResultAvailableAfterWhenSucceededV1() { - RunResponseHandler handler = newHandler(); + testResultAvailableAfterOnSuccess( "result_available_after", BoltProtocolV1.METADATA_EXTRACTOR ); + } + + @Test + void shouldReturnResultAvailableAfterWhenSucceededV3() + { + testResultAvailableAfterOnSuccess( "t_first", BoltProtocolV3.METADATA_EXTRACTOR ); + } - handler.onSuccess( singletonMap( "result_available_after", value( 42 ) ) ); + private static void testResultAvailableAfterOnSuccess( String key, MetadataExtractor metadataExtractor ) + { + RunResponseHandler handler = newHandler( metadataExtractor ); + + handler.onSuccess( singletonMap( key, value( 42 ) ) ); assertEquals( 42L, handler.resultAvailableAfter() ); } private static RunResponseHandler newHandler() { - return newHandler( new CompletableFuture<>() ); + return newHandler( BoltProtocolV1.METADATA_EXTRACTOR ); } private static RunResponseHandler newHandler( CompletableFuture runCompletedFuture ) { - return new RunResponseHandler( runCompletedFuture, RESULT_AVAILABLE_AFTER_METADATA_KEY ); + return newHandler( runCompletedFuture, BoltProtocolV1.METADATA_EXTRACTOR ); + } + + private static RunResponseHandler newHandler( MetadataExtractor metadataExtractor ) + { + return newHandler( new CompletableFuture<>(), metadataExtractor ); + } + + private static RunResponseHandler newHandler( CompletableFuture runCompletedFuture, MetadataExtractor metadataExtractor ) + { + return new RunResponseHandler( runCompletedFuture, metadataExtractor ); } } diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java index 9b6528b4b1..6f74959f65 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/SessionPullAllResponseHandlerTest.java @@ -31,8 +31,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.METADATA_EXTRACTOR; class SessionPullAllResponseHandlerTest { @@ -58,10 +57,10 @@ void shouldReleaseConnectionOnFailure() verify( connection ).release(); } - private SessionPullAllResponseHandler newHandler( Connection connection ) + private static SessionPullAllResponseHandler newHandler( Connection connection ) { - RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); - return new SessionPullAllResponseHandler( new Statement( "RETURN 1" ), runHandler, RESULT_CONSUMED_AFTER_METADATA_KEY, connection ); + RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), METADATA_EXTRACTOR ); + return new SessionPullAllResponseHandler( new Statement( "RETURN 1" ), runHandler, connection, METADATA_EXTRACTOR ); } private static Connection newConnectionMock() diff --git a/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java b/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java index 5403542d55..35a9515e23 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/handlers/TransactionPullAllResponseHandlerTest.java @@ -36,8 +36,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_AVAILABLE_AFTER_METADATA_KEY; -import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.RESULT_CONSUMED_AFTER_METADATA_KEY; +import static org.neo4j.driver.internal.messaging.v1.BoltProtocolV1.METADATA_EXTRACTOR; class TransactionPullAllResponseHandlerTest { @@ -63,9 +62,9 @@ private static void testErrorHandling( Throwable error ) when( connection.serverAddress() ).thenReturn( BoltServerAddress.LOCAL_DEFAULT ); when( connection.serverVersion() ).thenReturn( ServerVersion.v3_2_0 ); ExplicitTransaction tx = mock( ExplicitTransaction.class ); - RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), RESULT_AVAILABLE_AFTER_METADATA_KEY ); + RunResponseHandler runHandler = new RunResponseHandler( new CompletableFuture<>(), METADATA_EXTRACTOR ); PullAllResponseHandler handler = new TransactionPullAllResponseHandler( new Statement( "RETURN 1" ), runHandler, - RESULT_CONSUMED_AFTER_METADATA_KEY, connection, tx ); + connection, tx, METADATA_EXTRACTOR ); handler.onFailure( error ); diff --git a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataUtilTest.java b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java similarity index 84% rename from driver/src/test/java/org/neo4j/driver/internal/util/MetadataUtilTest.java rename to driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java index c1df724d9a..0186066dc9 100644 --- a/driver/src/test/java/org/neo4j/driver/internal/util/MetadataUtilTest.java +++ b/driver/src/test/java/org/neo4j/driver/internal/util/MetadataExtractorTest.java @@ -45,9 +45,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.neo4j.driver.internal.summary.InternalSummaryCounters.EMPTY_STATS; -import static org.neo4j.driver.internal.util.MetadataUtil.extractResultAvailableAfter; -import static org.neo4j.driver.internal.util.MetadataUtil.extractStatementKeys; -import static org.neo4j.driver.internal.util.MetadataUtil.extractSummary; import static org.neo4j.driver.v1.Values.parameters; import static org.neo4j.driver.v1.Values.value; import static org.neo4j.driver.v1.Values.values; @@ -56,23 +53,25 @@ import static org.neo4j.driver.v1.summary.StatementType.SCHEMA_WRITE; import static org.neo4j.driver.v1.summary.StatementType.WRITE_ONLY; -class MetadataUtilTest +class MetadataExtractorTest { private static final String RESULT_AVAILABLE_AFTER_KEY = "available_after"; private static final String RESULT_CONSUMED_AFTER_KEY = "consumed_after"; + private final MetadataExtractor extractor = new MetadataExtractor( RESULT_AVAILABLE_AFTER_KEY, RESULT_CONSUMED_AFTER_KEY ); + @Test void shouldExtractStatementKeys() { List keys = asList( "hello", " ", "world", "!" ); - List extractedKeys = extractStatementKeys( singletonMap( "fields", value( keys ) ) ); + List extractedKeys = extractor.extractStatementKeys( singletonMap( "fields", value( keys ) ) ); assertEquals( keys, extractedKeys ); } @Test void shouldExtractEmptyStatementKeysWhenNoneInMetadata() { - List extractedKeys = extractStatementKeys( emptyMap() ); + List extractedKeys = extractor.extractStatementKeys( emptyMap() ); assertEquals( emptyList(), extractedKeys ); } @@ -80,14 +79,14 @@ void shouldExtractEmptyStatementKeysWhenNoneInMetadata() void shouldExtractResultAvailableAfter() { Map metadata = singletonMap( RESULT_AVAILABLE_AFTER_KEY, value( 424242 ) ); - long extractedResultAvailableAfter = extractResultAvailableAfter( metadata, RESULT_AVAILABLE_AFTER_KEY ); + long extractedResultAvailableAfter = extractor.extractResultAvailableAfter( metadata ); assertEquals( 424242L, extractedResultAvailableAfter ); } @Test void shouldExtractNoResultAvailableAfterWhenNoneInMetadata() { - long extractedResultAvailableAfter = extractResultAvailableAfter( emptyMap(), RESULT_AVAILABLE_AFTER_KEY ); + long extractedResultAvailableAfter = extractor.extractResultAvailableAfter( emptyMap() ); assertEquals( -1, extractedResultAvailableAfter ); } @@ -97,7 +96,7 @@ void shouldBuildResultSummaryWithStatement() Statement statement = new Statement( "UNWIND range(10, 100) AS x CREATE (:Node {name: $name, x: x})", singletonMap( "name", "Apa" ) ); - ResultSummary summary = extractSummary( statement, connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement, connectionMock(), 42, emptyMap() ); assertEquals( statement, summary.statement() ); } @@ -107,7 +106,7 @@ void shouldBuildResultSummaryWithServerInfo() { Connection connection = connectionMock( new BoltServerAddress( "server:42" ), ServerVersion.v3_2_0 ); - ResultSummary summary = extractSummary( statement(), connection, 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connection, 42, emptyMap() ); assertEquals( "server:42", summary.server().address() ); assertEquals( "Neo4j/3.2.0", summary.server().version() ); @@ -143,7 +142,7 @@ void shouldBuildResultSummaryWithCounters() Map metadata = singletonMap( "stats", stats ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, metadata ); assertEquals( 42, summary.counters().nodesCreated() ); assertEquals( 4242, summary.counters().nodesDeleted() ); @@ -161,7 +160,7 @@ void shouldBuildResultSummaryWithCounters() @Test void shouldBuildResultSummaryWithoutCounters() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, emptyMap() ); assertEquals( EMPTY_STATS, summary.counters() ); } @@ -182,7 +181,7 @@ void shouldBuildResultSummaryWithPlan() ) ); Map metadata = singletonMap( "plan", plan ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, metadata ); assertTrue( summary.hasPlan() ); assertEquals( "Projection", summary.plan().operatorType() ); @@ -202,7 +201,7 @@ void shouldBuildResultSummaryWithPlan() @Test void shouldBuildResultSummaryWithoutPlan() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, emptyMap() ); assertFalse( summary.hasPlan() ); assertNull( summary.plan() ); } @@ -228,7 +227,7 @@ void shouldBuildResultSummaryWithProfiledPlan() ) ); Map metadata = singletonMap( "profile", profile ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, metadata ); assertTrue( summary.hasPlan() ); assertTrue( summary.hasProfile() ); @@ -252,7 +251,7 @@ void shouldBuildResultSummaryWithProfiledPlan() @Test void shouldBuildResultSummaryWithoutProfiledPlan() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, emptyMap() ); assertFalse( summary.hasProfile() ); assertNull( summary.profile() ); } @@ -285,7 +284,7 @@ void shouldBuildResultSummaryWithNotifications() Value notifications = value( notification1, notification2 ); Map metadata = singletonMap( "notifications", notifications ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, metadata ); assertEquals( 2, summary.notifications().size() ); Notification firstNotification = summary.notifications().get( 0 ); @@ -307,7 +306,7 @@ void shouldBuildResultSummaryWithNotifications() @Test void shouldBuildResultSummaryWithoutNotifications() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, emptyMap() ); assertEquals( 0, summary.notifications().size() ); } @@ -316,7 +315,7 @@ void shouldBuildResultSummaryWithResultAvailableAfter() { int value = 42_000; - ResultSummary summary = extractSummary( statement(), connectionMock(), value, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), value, emptyMap() ); assertEquals( 42, summary.resultAvailableAfter( TimeUnit.SECONDS ) ); assertEquals( value, summary.resultAvailableAfter( TimeUnit.MILLISECONDS ) ); @@ -328,7 +327,7 @@ void shouldBuildResultSummaryWithResultConsumedAfter() int value = 42_000; Map metadata = singletonMap( RESULT_CONSUMED_AFTER_KEY, value( value ) ); - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, metadata ); assertEquals( 42, summary.resultConsumedAfter( TimeUnit.SECONDS ) ); assertEquals( value, summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) ); @@ -337,15 +336,15 @@ void shouldBuildResultSummaryWithResultConsumedAfter() @Test void shouldBuildResultSummaryWithoutResultConsumedAfter() { - ResultSummary summary = extractSummary( statement(), connectionMock(), 42, emptyMap(), RESULT_CONSUMED_AFTER_KEY ); + ResultSummary summary = extractor.extractSummary( statement(), connectionMock(), 42, emptyMap() ); assertEquals( -1, summary.resultConsumedAfter( TimeUnit.SECONDS ) ); assertEquals( -1, summary.resultConsumedAfter( TimeUnit.MILLISECONDS ) ); } - private static ResultSummary createWithStatementType( Value typeValue ) + private ResultSummary createWithStatementType( Value typeValue ) { Map metadata = singletonMap( "type", typeValue ); - return extractSummary( statement(), connectionMock(), 42, metadata, RESULT_CONSUMED_AFTER_KEY ); + return extractor.extractSummary( statement(), connectionMock(), 42, metadata ); } private static Statement statement()