From 8a8d25cfbf5b639983687d631cc9bd644954decc Mon Sep 17 00:00:00 2001 From: Praveena G Date: Thu, 1 Jun 2017 18:06:46 +0200 Subject: [PATCH 1/3] byte array support for .Net Driver --- .../DirectDriver/DriverIT.cs | 69 +++++++++-- .../Internals/IntegrationTestAttribute.cs | 54 +++++++++ .../PackStreamMessageFormatV1Tests.cs | 59 ++++++++- .../PackStream/PackerTests.cs | 14 --- .../Internal/Connector/ChunkedInputStream.cs | 2 +- .../Internal/Connector/ChunkedOutputStream.cs | 2 +- .../Internal/Connector/IChunkedInputStream.cs | 23 ++++ .../Connector/IChunkedOutputStream.cs | 23 ++++ .../Internal/Connector/ISocketClient.cs | 1 + .../Internal/Connector/SocketClient.cs | 23 +++- .../Internal/Connector/SocketConnection.cs | 1 + .../PackStream/PackStreamMessageFormatV1.cs | 114 +++++++++++++----- Neo4j.Driver/Neo4j.Driver/Neo4j.Driver.csproj | 2 + 13 files changed, 327 insertions(+), 60 deletions(-) create mode 100644 Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedInputStream.cs create mode 100644 Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedOutputStream.cs diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs index f369783b0..28567205c 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs @@ -16,12 +16,14 @@ // limitations under the License. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using FluentAssertions; using Neo4j.Driver.Internal; +using Neo4j.Driver.Internal.Packstream; using Neo4j.Driver.V1; using Xunit; using Xunit.Abstractions; @@ -34,6 +36,49 @@ public DriverIT(ITestOutputHelper output, StandAloneIntegrationTestFixture fixtu { } + [RequireServerVersionGreaterThanOrEqualToFact("3.2.0")] + public void ShouldPackAndUnpackBytes() + { + // Given + var converter = new BigEndianTargetBitConverter(); + byte[] byteArray = converter.GetBytes("hello, world"); + + // When + using (var driver = GraphDatabase.Driver("bolt://127.0.0.1:7687", AuthToken)) + using (var session = driver.Session()) + { + var result = session.Run( + "CREATE (a {value:{value}}) RETURN a.value", new Dictionary {{"value", byteArray}}); + // Then + foreach (var record in result) + { + var value = record["a.value"].ValueAs(); + value.Should().BeEquivalentTo(byteArray); + } + } + } + + [RequireServerVersionLessThanFact("3.2.0")] + public void ShouldNotPackBytes() + { + // Given + var converter = new BigEndianTargetBitConverter(); + byte[] byteArray = converter.GetBytes("hello, world"); + + // When + using (var driver = GraphDatabase.Driver("bolt://127.0.0.1:7687", AuthToken)) + using (var session = driver.Session()) + { + var exception = Record.Exception(() => + session.Run("CREATE (a {value:{value}})", + new Dictionary {{"value", byteArray}})); + + // Then + exception.Should().BeOfType(); + exception.Message.Should().Be("Cannot understand value with type System.Byte[]"); + } + } + [Require31ServerFact] public void ShouldConnectIPv6AddressIfEnabled() { @@ -51,7 +96,7 @@ public void ShouldNotConnectIPv6AddressIfDisabled() using (var driver = GraphDatabase.Driver("bolt://[::1]:7687", AuthToken)) using (var session = driver.Session()) { - var exception = Record.Exception(()=> session.Run("RETURN 1")); + var exception = Record.Exception(() => session.Run("RETURN 1")); exception.GetBaseException().Should().BeOfType(); exception.GetBaseException().Message.Should().Contain("This protocol version is not supported"); } @@ -71,7 +116,8 @@ public void ShouldConnectIPv4AddressIfIpv6Disabled() [RequireServerFact] public void ShouldConnectIPv4AddressIfIpv6Enabled() { - using (var driver = GraphDatabase.Driver("bolt://127.0.0.1:7687", AuthToken, new Config {Ipv6Enabled = true})) + using ( + var driver = GraphDatabase.Driver("bolt://127.0.0.1:7687", AuthToken, new Config {Ipv6Enabled = true})) using (var session = driver.Session()) { var ret = session.Run("RETURN 1").Single(); @@ -119,11 +165,11 @@ public void SoakRun(int threadCount) { var statisticsCollector = new StatisticsCollector(); var driver = GraphDatabase.Driver(ServerEndPoint, AuthToken, new Config - { - DriverStatisticsCollector = statisticsCollector, - ConnectionTimeout = Config.Infinite, - EncryptionLevel = EncryptionLevel.Encrypted - }); + { + DriverStatisticsCollector = statisticsCollector, + ConnectionTimeout = Config.Infinite, + EncryptionLevel = EncryptionLevel.Encrypted + }); Output.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.ffffff")}] Started"); @@ -134,7 +180,11 @@ public void SoakRun(int threadCount) Output.WriteLine(statisticsCollector.CollectStatistics().ToContentString()); } - string[] queries = { "RETURN 1295 + 42", "UNWIND range(1,10000) AS x CREATE (n {prop:x}) DELETE n RETURN sum(x)" }; + string[] queries = + { + "RETURN 1295 + 42", + "UNWIND range(1,10000) AS x CREATE (n {prop:x}) DELETE n RETURN sum(x)" + }; try { using (var session = driver.Session()) @@ -144,7 +194,8 @@ public void SoakRun(int threadCount) } catch (Exception e) { - Output.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.ffffff")}] Thread {i} failed to run query {queries[i%2]} due to {e.Message}"); + Output.WriteLine( + $"[{DateTime.Now.ToString("HH:mm:ss.ffffff")}] Thread {i} failed to run query {queries[i % 2]} due to {e.Message}"); } }); diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs index e50a73062..921dfdd22 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs @@ -50,6 +50,60 @@ public Require31ServerFactAttribute() } } + /// + /// Use `Require32ServerFact` tag for the tests that require a server with version equals to or greater than 3.2 + /// + public class Require32ServerFactAttribute : FactAttribute + { + public Require32ServerFactAttribute() + { + if (!IsBoltkitAvailable()) + { + Skip = TestRequireBoltkit; + } + if (!(Version(ServerVersion()) >= V3_2_0)) + { + Skip = $"Require server version >= 3.2, while current server version is {ServerVersion()}"; + } + } + } + + /// + /// Use `RequireServerVersionGreaterThanOrEqualToFactAttribute` tag for the tests that require a server with version equals to or greater than given version + /// + public class RequireServerVersionGreaterThanOrEqualToFactAttribute : FactAttribute + { + public RequireServerVersionGreaterThanOrEqualToFactAttribute(string version) + { + if (!IsBoltkitAvailable()) + { + Skip = TestRequireBoltkit; + } + if (!(Version(ServerVersion()) >= Version(version))) + { + Skip = $"Require server version >= {version}, while current server version is {ServerVersion()}"; + } + } + } + + /// + /// Use `RequireServerVersionLessThanFactAttribute` tag for the tests that require a server with version less than the given version + /// + public class RequireServerVersionLessThanFactAttribute : FactAttribute + { + public RequireServerVersionLessThanFactAttribute(string version) + { + if (!IsBoltkitAvailable()) + { + Skip = TestRequireBoltkit; + } + if (!(Version(version) >= Version(ServerVersion()))) + { + Skip = $"Require server version < {version}, while current server version is {ServerVersion()}"; + } + } + } + /// /// Use `RequireServerFact` tag for the tests that require a single instance /// diff --git a/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackStreamMessageFormatV1Tests.cs b/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackStreamMessageFormatV1Tests.cs index 793f735a5..82b8b5caf 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackStreamMessageFormatV1Tests.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackStreamMessageFormatV1Tests.cs @@ -32,8 +32,27 @@ namespace Neo4j.Driver.Tests { public class PackStreamMessageFormatV1Tests { - public class WriterV1 + public class WriterV1Tests { + public class PackValueMethod + { + [Fact] + public void ShouldPackBytes() + { + var outputStreamMock = new Mock(); + + var writer = new PackStreamMessageFormatV1.WriterV1(outputStreamMock.Object); + var converter = new BigEndianTargetBitConverter(); + var value = new byte[0]; + + outputStreamMock.Setup(x => x.Write(It.IsAny())).Callback((byte[] data)=>value = data); + + var byteArray = converter.GetBytes("hello, world"); + writer.PackValue(byteArray); + converter.ToString(value).Should().Be("hello, world"); + } + } + private class Mocks { public Mock MockStream { get; } @@ -278,10 +297,48 @@ public void PackRunMessageWithDictionaryMixedTypesParamCorrectly() } } + public class ReaderBytesIncompatibleV1Tests + { + public class UnpackValueMethod + { + [Fact] + public void ShouldThrowExceptionForUnpackingBytes() + { + var reader = new PackStreamMessageFormatV1.ReaderBytesIncompatibleV1(null); + var ex = Record.Exception(()=> reader.UnpackValue(PackStream.PackType.Bytes)); + ex.Should().BeOfType(); + } + } + } + + public class WriterBytesIncompatibleV2Tests + { + public class PackValueMethod + { + [Fact] + public void ShouldThrowExceptionForPackingBytes() + { + var writer = new PackStreamMessageFormatV1.WriterBytesIncompatibleV1(null); + var ex = Record.Exception(() => writer.PackValue(new byte[] {0xCB})); + ex.Should().BeOfType(); + } + } + } + public class ReaderV1Tests { public class UnpackValueMethod { + public void ShouldPackBytes() + { + var inputStreamMock = new Mock(); + inputStreamMock.SetupSequence(x => x.ReadByte()).Returns(PackStream.BYTES_8).Returns((byte)0x00); + var reader = new PackStreamMessageFormatV1.ReaderV1(inputStreamMock.Object); + + var unpackValue = reader.UnpackValue(PackStream.PackType.Bytes).ValueAs(); + unpackValue.Length.Should().Be(0); + } + [Theory] [InlineData(2147483648, new byte[] {0xCB, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00})] [InlineData(9223372036854775807, new byte[] {0xCB, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})] diff --git a/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackerTests.cs b/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackerTests.cs index 473a05376..dca58e8dd 100644 --- a/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackerTests.cs +++ b/Neo4j.Driver/Neo4j.Driver.Tests/PackStream/PackerTests.cs @@ -85,20 +85,6 @@ public void ShouldPackNullSuccessfully() } -// public class PackRawMethod -// { -// [Fact] -// public void ShouldUnpacPawBytesSuccessfully() -// { -// var mocks = new Mocks(); -// var u = new PackStream.Packer(mocks.OutputStream); -// -// var bytes = new byte[] { 1, 2, 3 }; -// u.PackRaw(bytes); -// mocks.VerifyWrite(bytes); -// } -// } - public class PackLongMethod { [Theory] diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedInputStream.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedInputStream.cs index d4622b65c..7781c1026 100644 --- a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedInputStream.cs +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedInputStream.cs @@ -20,7 +20,7 @@ namespace Neo4j.Driver.Internal.Connector { - internal class ChunkedInputStream : IInputStream + internal class ChunkedInputStream : IChunkedInputStream { private const int ChunkSize = 1024*8; public static readonly byte[] Tail = {0x00, 0x00}; diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedOutputStream.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedOutputStream.cs index afe06acce..26787c63c 100644 --- a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedOutputStream.cs +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ChunkedOutputStream.cs @@ -20,7 +20,7 @@ namespace Neo4j.Driver.Internal.Connector { - internal class ChunkedOutputStream : IOutputStream + internal class ChunkedOutputStream : IChunkedOutputStream { internal const int BufferSize = 1024*8; private const int ChunkHeaderBufferSize = 2; diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedInputStream.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedInputStream.cs new file mode 100644 index 000000000..3c2c61ce1 --- /dev/null +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedInputStream.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2002-2017 "Neo Technology," +// Network Engine for Objects in Lund AB [http://neotechnology.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. +namespace Neo4j.Driver.Internal.Connector +{ + internal interface IChunkedInputStream : IInputStream + { + void ReadMessageTail(); + } +} \ No newline at end of file diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedOutputStream.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedOutputStream.cs new file mode 100644 index 000000000..d2a884619 --- /dev/null +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/IChunkedOutputStream.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2002-2017 "Neo Technology," +// Network Engine for Objects in Lund AB [http://neotechnology.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. +namespace Neo4j.Driver.Internal.Connector +{ + internal interface IChunkedOutputStream : IOutputStream + { + IOutputStream WriteMessageTail(); + } +} \ No newline at end of file diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ISocketClient.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ISocketClient.cs index e1f7c8286..fc5377b7c 100644 --- a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ISocketClient.cs +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/ISocketClient.cs @@ -29,5 +29,6 @@ internal interface ISocketClient : IDisposable void Receive(IMessageResponseHandler responseHandler); void ReceiveOne(IMessageResponseHandler responseHandler); bool IsOpen { get; } + void UpdatePackStream(string serverVersion); } } \ No newline at end of file diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketClient.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketClient.cs index 6e01f2027..569abe7fd 100644 --- a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketClient.cs +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketClient.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using Neo4j.Driver.Internal.Messaging; using Neo4j.Driver.Internal.Packstream; +using Neo4j.Driver.Internal.Routing; using Neo4j.Driver.V1; namespace Neo4j.Driver.Internal.Connector @@ -65,9 +66,7 @@ public async Task Start() switch (version) { case ProtocolVersion.Version1: - var formatV1 = new PackStreamMessageFormatV1(_tcpSocketClient, _logger); - _writer = formatV1.Writer; - _reader = formatV1.Reader; + SetupPackStreamFormatWriterAndReader(); break; case ProtocolVersion.NoVersion: throw new NotSupportedException("The Neo4j server does not support any of the protocol versions supported by this client. " + @@ -81,6 +80,14 @@ public async Task Start() } } + private void SetupPackStreamFormatWriterAndReader(bool supportBytes = true) + { + var formatV1 = new PackStreamMessageFormatV1(_tcpSocketClient, _logger, supportBytes); + _writer = formatV1.Writer; + _reader = formatV1.Reader; + } + + private async Task Stop() { if (IsOpen && _tcpSocketClient != null) @@ -183,5 +190,15 @@ protected virtual void Dispose(bool isDisposing) Task.Run(() => Stop()).Wait(); } + + public void UpdatePackStream(string serverVersion) + { + var version = ServerVersion.Version(serverVersion); + if ( version >= ServerVersion.V3_2_0 ) + { + return; + } + SetupPackStreamFormatWriterAndReader(false); + } } } \ No newline at end of file diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketConnection.cs b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketConnection.cs index b855cd73d..febf97eda 100644 --- a/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketConnection.cs +++ b/Neo4j.Driver/Neo4j.Driver/Internal/Connector/SocketConnection.cs @@ -83,6 +83,7 @@ private void Init(IAuthToken authToken) Enqueue(new InitMessage(_userAgent, authToken.AsDictionary()), initCollector); Sync(); ((ServerInfo)Server).Version = initCollector.Server; + _client.UpdatePackStream(initCollector.Server); } public void Sync() diff --git a/Neo4j.Driver/Neo4j.Driver/Internal/PackStream/PackStreamMessageFormatV1.cs b/Neo4j.Driver/Neo4j.Driver/Internal/PackStream/PackStreamMessageFormatV1.cs index 949122506..b380f8683 100644 --- a/Neo4j.Driver/Neo4j.Driver/Internal/PackStream/PackStreamMessageFormatV1.cs +++ b/Neo4j.Driver/Neo4j.Driver/Internal/PackStream/PackStreamMessageFormatV1.cs @@ -14,6 +14,7 @@ // 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. + using System; using System.Collections.Generic; using System.IO; @@ -26,10 +27,51 @@ namespace Neo4j.Driver.Internal.Packstream { internal class PackStreamMessageFormatV1 { - public PackStreamMessageFormatV1(ITcpSocketClient tcpSocketClient, ILogger logger) + public PackStreamMessageFormatV1(ITcpSocketClient tcpSocketClient, ILogger logger, bool supportBytes=true) + { + var output = new ChunkedOutputStream(tcpSocketClient, logger); + var input = new ChunkedInputStream(tcpSocketClient, logger); + if (supportBytes) + { + Writer = new WriterV1(output); + Reader = new ReaderV1(input); + } + else + { + Writer = new WriterBytesIncompatibleV1(output); + Reader = new ReaderBytesIncompatibleV1(input); + } + } + + public class WriterBytesIncompatibleV1 : WriterV1 + { + public WriterBytesIncompatibleV1(IChunkedOutputStream outputStream) : base(outputStream) + { + } + public override void PackValue(object value) + { + if (value is byte[]) + { + throw new ProtocolException($"Cannot understand { nameof(value) } with type { value.GetType().FullName}"); + } + base.PackValue(value); + } + } + + public class ReaderBytesIncompatibleV1 : ReaderV1 { - Writer = new WriterV1(new ChunkedOutputStream(tcpSocketClient, logger)); - Reader = new ReaderV1(new ChunkedInputStream(tcpSocketClient, logger)); + public ReaderBytesIncompatibleV1(IChunkedInputStream inputStream) : base(inputStream) + { + } + + public override object UnpackValue(PackStream.PackType type) + { + if (type == PackStream.PackType.Bytes) + { + throw new ProtocolException($"Unsupported type {type}."); + } + return base.UnpackValue(type); + } } public IWriter Writer { get; } @@ -38,10 +80,10 @@ public PackStreamMessageFormatV1(ITcpSocketClient tcpSocketClient, ILogger logge public class ReaderV1 : IReader { private static readonly Dictionary EmptyStringValueMap = new Dictionary(); - private readonly ChunkedInputStream _inputStream; + private readonly IChunkedInputStream _inputStream; private readonly PackStream.Unpacker _unpacker; - public ReaderV1(ChunkedInputStream inputStream) + public ReaderV1(IChunkedInputStream inputStream) { _inputStream = inputStream; _unpacker = new PackStream.Unpacker(_inputStream); @@ -75,10 +117,15 @@ public void Read(IMessageResponseHandler responseHandler) public object UnpackValue() { var type = _unpacker.PeekNextType(); + return UnpackValue(type); + } + + public virtual object UnpackValue(PackStream.PackType type) + { switch (type) { case PackStream.PackType.Bytes: - break; + return _unpacker.UnpackBytes(); case PackStream.PackType.Null: return _unpacker.UnpackNull(); case PackStream.PackType.Boolean: @@ -101,7 +148,8 @@ public object UnpackValue() Throw.ProtocolException.IfNotEqual(NodeFields, size, nameof(NodeFields), nameof(size)); return UnpackNode(); case RELATIONSHIP: - Throw.ProtocolException.IfNotEqual(RelationshipFields, size, nameof(RelationshipFields), nameof(size)); + Throw.ProtocolException.IfNotEqual(RelationshipFields, size, nameof(RelationshipFields), + nameof(size)); return UnpackRelationship(); case PATH: Throw.ProtocolException.IfNotEqual(PathFields, size, nameof(PathFields), nameof(size)); @@ -113,30 +161,34 @@ public object UnpackValue() } private IPath UnpackPath() - { + { // List of unique nodes var uniqNodes = new INode[(int) _unpacker.UnpackListHeader()]; - for(int i = 0; i < uniqNodes.Length; i ++) + for (int i = 0; i < uniqNodes.Length; i++) { - Throw.ProtocolException.IfNotEqual(NodeFields, _unpacker.UnpackStructHeader(), nameof(NodeFields), $"received{nameof(NodeFields)}"); - Throw.ProtocolException.IfNotEqual(NODE, _unpacker.UnpackStructSignature(),nameof(NODE), $"received{nameof(NODE)}"); - uniqNodes[i]=UnpackNode(); + Throw.ProtocolException.IfNotEqual(NodeFields, _unpacker.UnpackStructHeader(), nameof(NodeFields), + $"received{nameof(NodeFields)}"); + Throw.ProtocolException.IfNotEqual(NODE, _unpacker.UnpackStructSignature(), nameof(NODE), + $"received{nameof(NODE)}"); + uniqNodes[i] = UnpackNode(); } // List of unique relationships, without start/end information - var uniqRels = new Relationship[(int)_unpacker.UnpackListHeader()]; + var uniqRels = new Relationship[(int) _unpacker.UnpackListHeader()]; for (int i = 0; i < uniqRels.Length; i++) { - Throw.ProtocolException.IfNotEqual( UnboundRelationshipFields, _unpacker.UnpackStructHeader(), nameof(UnboundRelationshipFields), $"received{nameof(UnboundRelationshipFields)}"); - Throw.ProtocolException.IfNotEqual(UNBOUND_RELATIONSHIP, _unpacker.UnpackStructSignature(), nameof(UNBOUND_RELATIONSHIP), $"received{nameof(UNBOUND_RELATIONSHIP)}"); + Throw.ProtocolException.IfNotEqual(UnboundRelationshipFields, _unpacker.UnpackStructHeader(), + nameof(UnboundRelationshipFields), $"received{nameof(UnboundRelationshipFields)}"); + Throw.ProtocolException.IfNotEqual(UNBOUND_RELATIONSHIP, _unpacker.UnpackStructSignature(), + nameof(UNBOUND_RELATIONSHIP), $"received{nameof(UNBOUND_RELATIONSHIP)}"); var urn = _unpacker.UnpackLong(); var relType = _unpacker.UnpackString(); var props = UnpackMap(); - uniqRels[i]=new Relationship(urn, -1, -1, relType, props); + uniqRels[i] = new Relationship(urn, -1, -1, relType, props); } // Path sequence - var length = (int)_unpacker.UnpackListHeader(); + var length = (int) _unpacker.UnpackListHeader(); // Knowing the sequence length, we can create the arrays that will represent the nodes, rels and segments in their "path order" var segments = new ISegment[length / 2]; @@ -149,8 +201,8 @@ private IPath UnpackPath() nodes[0] = prevNode; for (int i = 0; i < segments.Length; i++) { - int relIdx = (int)_unpacker.UnpackLong(); - nextNode = uniqNodes[(int)_unpacker.UnpackLong()]; + int relIdx = (int) _unpacker.UnpackLong(); + nextNode = uniqNodes[(int) _unpacker.UnpackLong()]; // Negative rel index means this rel was traversed "inversed" from its direction if (relIdx < 0) { @@ -168,7 +220,7 @@ private IPath UnpackPath() segments[i] = new Segment(prevNode, rel, nextNode); prevNode = nextNode; } - return new Path(segments.ToList(), nodes.ToList(),rels.ToList()); + return new Path(segments.ToList(), nodes.ToList(), rels.ToList()); } private IRelationship UnpackRelationship() @@ -186,13 +238,13 @@ private INode UnpackNode() { var urn = _unpacker.UnpackLong(); - var numLabels = (int)_unpacker.UnpackListHeader(); + var numLabels = (int) _unpacker.UnpackListHeader(); var labels = new List(numLabels); for (var i = 0; i < numLabels; i++) { labels.Add(_unpacker.UnpackString()); } - var numProps = (int)_unpacker.UnpackMapHeader(); + var numProps = (int) _unpacker.UnpackMapHeader(); var props = new Dictionary(numProps); for (var j = 0; j < numProps; j++) { @@ -219,7 +271,7 @@ private void UnpackFailureMessage(IMessageResponseHandler responseHandler) private void UnpackRecordMessage(IMessageResponseHandler responseHandler) { - var fieldCount = (int)_unpacker.UnpackListHeader(); + var fieldCount = (int) _unpacker.UnpackListHeader(); var fields = new object[fieldCount]; for (var i = 0; i < fieldCount; i++) { @@ -241,7 +293,7 @@ private void UnpackSuccessMessage(IMessageResponseHandler responseHandler) private Dictionary UnpackMap() { - var size = (int)_unpacker.UnpackMapHeader(); + var size = (int) _unpacker.UnpackMapHeader(); if (size == 0) { return EmptyStringValueMap; @@ -257,7 +309,7 @@ private Dictionary UnpackMap() private IList UnpackList() { - var size = (int)_unpacker.UnpackListHeader(); + var size = (int) _unpacker.UnpackListHeader(); var vals = new object[size]; for (var j = 0; j < size; j++) { @@ -269,11 +321,11 @@ private IList UnpackList() public class WriterV1 : IWriter, IMessageRequestHandler { - private readonly ChunkedOutputStream _outputStream; + private readonly IChunkedOutputStream _outputStream; private readonly PackStream.Packer _packer; - - public WriterV1(ChunkedOutputStream outputStream) + + public WriterV1(IChunkedOutputStream outputStream) { _outputStream = outputStream; _packer = new PackStream.Packer(_outputStream); @@ -309,13 +361,13 @@ public void HandleDiscardAllMessage() public void HandleResetMessage() { - _packer.PackStructHeader( 0, MSG_RESET ); + _packer.PackStructHeader(0, MSG_RESET); PackMessageTail(); } public void HandleAckFailureMessage() { - _packer.PackStructHeader(0, MSG_ACK_FAILURE ); + _packer.PackStructHeader(0, MSG_ACK_FAILURE); PackMessageTail(); } @@ -351,7 +403,7 @@ private void PackRawMap(IDictionary dictionary) } - private void PackValue(object value) + public virtual void PackValue(object value) { _packer.Pack(value); // the driver should never pack node, relationship or path diff --git a/Neo4j.Driver/Neo4j.Driver/Neo4j.Driver.csproj b/Neo4j.Driver/Neo4j.Driver/Neo4j.Driver.csproj index 7b2b68cbd..9d21db583 100644 --- a/Neo4j.Driver/Neo4j.Driver/Neo4j.Driver.csproj +++ b/Neo4j.Driver/Neo4j.Driver/Neo4j.Driver.csproj @@ -45,6 +45,8 @@ + + From 71720d9b94a4b07763445a9079d31a5e50a54b3f Mon Sep 17 00:00:00 2001 From: Praveena G Date: Mon, 5 Jun 2017 16:51:44 +0200 Subject: [PATCH 2/3] refactoring --- .../DirectDriver/BookmarkIT.cs | 12 +++---- .../DirectDriver/DriverIT.cs | 4 +-- .../Internals/IntegrationTestAttribute.cs | 36 ------------------- 3 files changed, 8 insertions(+), 44 deletions(-) diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs index 417bcae1d..17d668c55 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs @@ -34,7 +34,7 @@ public BookmarkIT(ITestOutputHelper output, StandAloneIntegrationTestFixture fix { } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void ShouldContainLastBookmarkAfterTx() { using (var session = Driver.Session()) @@ -48,7 +48,7 @@ public void ShouldContainLastBookmarkAfterTx() } } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void BookmarkUnchangedAfterRolledBackTx() { using (var session = Driver.Session()) @@ -66,7 +66,7 @@ public void BookmarkUnchangedAfterRolledBackTx() } } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void BookmarkUnchangedAfterTxFailure() { using (var session = Driver.Session()) @@ -84,7 +84,7 @@ public void BookmarkUnchangedAfterTxFailure() } } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void ShouldThrowForInvalidBookmark() { var invalidBookmark = "invalid bookmark format"; @@ -96,7 +96,7 @@ public void ShouldThrowForInvalidBookmark() } } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void ShouldThrowForUnreachableBookmark() { using (var session = (Session)Driver.Session()) @@ -111,7 +111,7 @@ public void ShouldThrowForUnreachableBookmark() } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void ShouldWaitOnBookmark() { using (var session = Driver.Session()) diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs index 28567205c..ebccc2fb6 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs @@ -79,7 +79,7 @@ public void ShouldNotPackBytes() } } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void ShouldConnectIPv6AddressIfEnabled() { using (var driver = GraphDatabase.Driver("bolt://[::1]:7687", AuthToken, new Config {Ipv6Enabled = true})) @@ -90,7 +90,7 @@ public void ShouldConnectIPv6AddressIfEnabled() } } - [Require31ServerFact] + [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] public void ShouldNotConnectIPv6AddressIfDisabled() { using (var driver = GraphDatabase.Driver("bolt://[::1]:7687", AuthToken)) diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs index 921dfdd22..eb1385c81 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs @@ -32,42 +32,6 @@ public RequireBoltStubServerFactAttribute() } } - /// - /// Use `Require31ServerFact` tag for the tests that require a server with version equals to or greater than 3.1 - /// - public class Require31ServerFactAttribute : FactAttribute - { - public Require31ServerFactAttribute() - { - if (!IsBoltkitAvailable()) - { - Skip = TestRequireBoltkit; - } - if (!(Version(ServerVersion()) >= V3_1_0)) - { - Skip = $"Require server version >= 3.1, while current server version is {ServerVersion()}"; - } - } - } - - /// - /// Use `Require32ServerFact` tag for the tests that require a server with version equals to or greater than 3.2 - /// - public class Require32ServerFactAttribute : FactAttribute - { - public Require32ServerFactAttribute() - { - if (!IsBoltkitAvailable()) - { - Skip = TestRequireBoltkit; - } - if (!(Version(ServerVersion()) >= V3_2_0)) - { - Skip = $"Require server version >= 3.2, while current server version is {ServerVersion()}"; - } - } - } - /// /// Use `RequireServerVersionGreaterThanOrEqualToFactAttribute` tag for the tests that require a server with version equals to or greater than given version /// From 82722aac54194ffae16e43d202c7b89e325c1390 Mon Sep 17 00:00:00 2001 From: Praveena G Date: Mon, 5 Jun 2017 17:23:21 +0200 Subject: [PATCH 3/3] renaming few facts --- .../DirectDriver/BookmarkIT.cs | 12 ++++++------ .../DirectDriver/DriverIT.cs | 4 ++-- .../Internals/IntegrationTestAttribute.cs | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs index 17d668c55..b7d206a9b 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/BookmarkIT.cs @@ -34,7 +34,7 @@ public BookmarkIT(ITestOutputHelper output, StandAloneIntegrationTestFixture fix { } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void ShouldContainLastBookmarkAfterTx() { using (var session = Driver.Session()) @@ -48,7 +48,7 @@ public void ShouldContainLastBookmarkAfterTx() } } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void BookmarkUnchangedAfterRolledBackTx() { using (var session = Driver.Session()) @@ -66,7 +66,7 @@ public void BookmarkUnchangedAfterRolledBackTx() } } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void BookmarkUnchangedAfterTxFailure() { using (var session = Driver.Session()) @@ -84,7 +84,7 @@ public void BookmarkUnchangedAfterTxFailure() } } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void ShouldThrowForInvalidBookmark() { var invalidBookmark = "invalid bookmark format"; @@ -96,7 +96,7 @@ public void ShouldThrowForInvalidBookmark() } } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void ShouldThrowForUnreachableBookmark() { using (var session = (Session)Driver.Session()) @@ -111,7 +111,7 @@ public void ShouldThrowForUnreachableBookmark() } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void ShouldWaitOnBookmark() { using (var session = Driver.Session()) diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs index ebccc2fb6..360e0b05e 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/DirectDriver/DriverIT.cs @@ -79,7 +79,7 @@ public void ShouldNotPackBytes() } } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void ShouldConnectIPv6AddressIfEnabled() { using (var driver = GraphDatabase.Driver("bolt://[::1]:7687", AuthToken, new Config {Ipv6Enabled = true})) @@ -90,7 +90,7 @@ public void ShouldConnectIPv6AddressIfEnabled() } } - [RequireServerVersionGreaterThanOrEqualToFactAttribute("3.1.0")] + [RequireServerVersionGreaterThanOrEqualToFact("3.1.0")] public void ShouldNotConnectIPv6AddressIfDisabled() { using (var driver = GraphDatabase.Driver("bolt://[::1]:7687", AuthToken)) diff --git a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs index eb1385c81..23e2fb2f4 100644 --- a/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs +++ b/Neo4j.Driver/Neo4j.Driver.IntegrationTests/Internals/IntegrationTestAttribute.cs @@ -33,11 +33,11 @@ public RequireBoltStubServerFactAttribute() } /// - /// Use `RequireServerVersionGreaterThanOrEqualToFactAttribute` tag for the tests that require a server with version equals to or greater than given version + /// Use `RequireServerVersionGreaterThanOrEqualToFact` tag for the tests that require a server with version equals to or greater than given version /// - public class RequireServerVersionGreaterThanOrEqualToFactAttribute : FactAttribute + public class RequireServerVersionGreaterThanOrEqualToFact : FactAttribute { - public RequireServerVersionGreaterThanOrEqualToFactAttribute(string version) + public RequireServerVersionGreaterThanOrEqualToFact(string version) { if (!IsBoltkitAvailable()) { @@ -51,11 +51,11 @@ public RequireServerVersionGreaterThanOrEqualToFactAttribute(string version) } /// - /// Use `RequireServerVersionLessThanFactAttribute` tag for the tests that require a server with version less than the given version + /// Use `RequireServerVersionLessThanFact` tag for the tests that require a server with version less than the given version /// - public class RequireServerVersionLessThanFactAttribute : FactAttribute + public class RequireServerVersionLessThanFact : FactAttribute { - public RequireServerVersionLessThanFactAttribute(string version) + public RequireServerVersionLessThanFact(string version) { if (!IsBoltkitAvailable()) {