Skip to content

Commit 76afa48

Browse files
author
Zhen Li
committed
Added the server side packing logic for node, rel, and path back in test util
Some tests needs this server side packer to serialize such types.
1 parent af8c5b7 commit 76afa48

File tree

9 files changed

+293
-44
lines changed

9 files changed

+293
-44
lines changed

driver/src/main/java/org/neo4j/driver/internal/messaging/PackStreamMessageFormatV2.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public MessageFormat.Reader newReader( PackInput input )
8686
return new ReaderV2( input );
8787
}
8888

89-
private static class WriterV2 extends WriterV1
89+
static class WriterV2 extends WriterV1
9090
{
9191
WriterV2( PackOutput output )
9292
{
@@ -226,7 +226,7 @@ private void packPoint3D( Point point ) throws IOException
226226
}
227227
}
228228

229-
private static class ReaderV2 extends ReaderV1
229+
static class ReaderV2 extends ReaderV1
230230
{
231231
ReaderV2( PackInput input )
232232
{

driver/src/test/java/org/neo4j/driver/internal/ValuesTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
import static org.junit.Assert.assertThat;
6969
import static org.neo4j.driver.internal.util.ValueFactory.emptyNodeValue;
7070
import static org.neo4j.driver.internal.util.ValueFactory.emptyRelationshipValue;
71-
import static org.neo4j.driver.internal.util.ValueFactory.pathValue;
71+
import static org.neo4j.driver.internal.util.ValueFactory.filledPathValue;
7272
import static org.neo4j.driver.v1.Values.isoDuration;
7373
import static org.neo4j.driver.v1.Values.ofDouble;
7474
import static org.neo4j.driver.v1.Values.ofFloat;
@@ -549,7 +549,7 @@ public void shouldComplainAboutPathValueType() throws Throwable
549549
exception.expectMessage( "Paths can't be used as parameters." );
550550

551551
// When
552-
PathValue path = pathValue();
552+
PathValue path = filledPathValue();
553553
value( path );
554554
}
555555

@@ -561,7 +561,7 @@ public void shouldComplainAboutPathType() throws Throwable
561561
exception.expectMessage( "Paths can't be used as parameters." );
562562

563563
// When
564-
Path path = pathValue().asPath();
564+
Path path = filledPathValue().asPath();
565565
value( path );
566566
}
567567
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright (c) 2002-2018 "Neo Technology,"
3+
* Network Engine for Objects in Lund AB [http://neotechnology.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver.internal.messaging;
20+
21+
import java.io.IOException;
22+
import java.util.Map;
23+
24+
import org.neo4j.driver.internal.packstream.PackOutput;
25+
import org.neo4j.driver.internal.types.TypeConstructor;
26+
import org.neo4j.driver.internal.util.Iterables;
27+
import org.neo4j.driver.internal.value.InternalValue;
28+
import org.neo4j.driver.v1.types.Entity;
29+
import org.neo4j.driver.v1.types.Node;
30+
import org.neo4j.driver.v1.types.Path;
31+
import org.neo4j.driver.v1.types.Relationship;
32+
33+
/**
34+
* This class provides the missing server side packing methods to serialize Node, Relationship and Path.
35+
*/
36+
public class KnowledgeablePackStreamMessageFormat extends PackStreamMessageFormatV2
37+
{
38+
@Override
39+
public MessageFormat.Writer newWriter( PackOutput output, boolean byteArraySupportEnabled )
40+
{
41+
return new KnowledgeablePackStreamMessageFormat.Writer( output );
42+
}
43+
44+
private static class Writer extends WriterV2
45+
{
46+
Writer( PackOutput output )
47+
{
48+
super( output );
49+
}
50+
51+
@Override
52+
void packInternalValue( InternalValue value ) throws IOException
53+
{
54+
TypeConstructor typeConstructor = value.typeConstructor();
55+
switch ( typeConstructor )
56+
{
57+
case NODE:
58+
Node node = value.asNode();
59+
packNode( node );
60+
break;
61+
62+
case RELATIONSHIP:
63+
Relationship rel = value.asRelationship();
64+
packRelationship( rel );
65+
break;
66+
67+
case PATH:
68+
Path path = value.asPath();
69+
packPath( path );
70+
break;
71+
default:
72+
super.packInternalValue( value );
73+
}
74+
}
75+
76+
private void packPath( Path path ) throws IOException
77+
{
78+
packer.packStructHeader( 3, PATH );
79+
80+
// Unique nodes
81+
Map<Node,Integer> nodeIdx = Iterables.newLinkedHashMapWithSize( path.length() + 1 );
82+
for ( Node node : path.nodes() )
83+
{
84+
if ( !nodeIdx.containsKey( node ) )
85+
{
86+
nodeIdx.put( node, nodeIdx.size() );
87+
}
88+
}
89+
packer.packListHeader( nodeIdx.size() );
90+
for ( Node node : nodeIdx.keySet() )
91+
{
92+
packNode( node );
93+
}
94+
95+
// Unique rels
96+
Map<Relationship,Integer> relIdx = Iterables.newLinkedHashMapWithSize( path.length() );
97+
for ( Relationship rel : path.relationships() )
98+
{
99+
if ( !relIdx.containsKey( rel ) )
100+
{
101+
relIdx.put( rel, relIdx.size() + 1 );
102+
}
103+
}
104+
packer.packListHeader( relIdx.size() );
105+
for ( Relationship rel : relIdx.keySet() )
106+
{
107+
packer.packStructHeader( 3, UNBOUND_RELATIONSHIP );
108+
packer.pack( rel.id() );
109+
packer.pack( rel.type() );
110+
packProperties( rel );
111+
}
112+
113+
// Sequence
114+
packer.packListHeader( path.length() * 2 );
115+
for ( Path.Segment seg : path )
116+
{
117+
Relationship rel = seg.relationship();
118+
long relEndId = rel.endNodeId();
119+
long segEndId = seg.end().id();
120+
int size = relEndId == segEndId ? relIdx.get( rel ) : -relIdx.get( rel );
121+
packer.pack( size );
122+
packer.pack( nodeIdx.get( seg.end() ) );
123+
}
124+
}
125+
126+
private void packRelationship( Relationship rel ) throws IOException
127+
{
128+
packer.packStructHeader( 5, RELATIONSHIP );
129+
packer.pack( rel.id() );
130+
packer.pack( rel.startNodeId() );
131+
packer.pack( rel.endNodeId() );
132+
133+
packer.pack( rel.type() );
134+
135+
packProperties( rel );
136+
}
137+
138+
private void packNode( Node node ) throws IOException
139+
{
140+
packer.packStructHeader( NODE_FIELDS, NODE );
141+
packer.pack( node.id() );
142+
143+
Iterable<String> labels = node.labels();
144+
packer.packListHeader( Iterables.count( labels ) );
145+
for ( String label : labels )
146+
{
147+
packer.pack( label );
148+
}
149+
150+
packProperties( node );
151+
}
152+
153+
private void packProperties( Entity entity ) throws IOException
154+
{
155+
Iterable<String> keys = entity.keys();
156+
packer.packMapHeader( entity.size() );
157+
for ( String propKey : keys )
158+
{
159+
packer.pack( propKey );
160+
packInternalValue( (InternalValue) entity.get( propKey ) );
161+
}
162+
}
163+
}
164+
}

driver/src/test/java/org/neo4j/driver/internal/messaging/MessageFormatTest.java

Lines changed: 103 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,15 @@
2121
import io.netty.buffer.ByteBuf;
2222
import io.netty.buffer.Unpooled;
2323
import io.netty.channel.embedded.EmbeddedChannel;
24+
import io.netty.handler.codec.EncoderException;
2425
import org.junit.Rule;
2526
import org.junit.Test;
2627
import org.junit.rules.ExpectedException;
2728

28-
import java.util.Collections;
29+
import java.io.IOException;
2930
import java.util.HashMap;
3031
import java.util.List;
3132

32-
import org.neo4j.driver.internal.InternalNode;
33-
import org.neo4j.driver.internal.InternalPath;
34-
import org.neo4j.driver.internal.InternalRelationship;
3533
import org.neo4j.driver.internal.async.BoltProtocolUtil;
3634
import org.neo4j.driver.internal.async.ChannelPipelineBuilderImpl;
3735
import org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher;
@@ -41,13 +39,22 @@
4139
import org.neo4j.driver.v1.exceptions.ClientException;
4240

4341
import static java.util.Arrays.asList;
42+
import static org.hamcrest.CoreMatchers.equalTo;
43+
import static org.hamcrest.CoreMatchers.instanceOf;
44+
import static org.hamcrest.MatcherAssert.assertThat;
4445
import static org.hamcrest.Matchers.startsWith;
4546
import static org.junit.Assert.assertEquals;
4647
import static org.junit.Assert.assertTrue;
48+
import static org.junit.Assert.fail;
4749
import static org.neo4j.driver.internal.async.ChannelAttributes.messageDispatcher;
4850
import static org.neo4j.driver.internal.async.ChannelAttributes.setMessageDispatcher;
4951
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;
50-
import static org.neo4j.driver.v1.Values.EmptyMap;
52+
import static org.neo4j.driver.internal.util.ValueFactory.emptyNodeValue;
53+
import static org.neo4j.driver.internal.util.ValueFactory.emptyPathValue;
54+
import static org.neo4j.driver.internal.util.ValueFactory.emptyRelationshipValue;
55+
import static org.neo4j.driver.internal.util.ValueFactory.filledNodeValue;
56+
import static org.neo4j.driver.internal.util.ValueFactory.filledPathValue;
57+
import static org.neo4j.driver.internal.util.ValueFactory.filledRelationshipValue;
5158
import static org.neo4j.driver.v1.Values.ofValue;
5259
import static org.neo4j.driver.v1.Values.parameters;
5360
import static org.neo4j.driver.v1.Values.value;
@@ -80,33 +87,51 @@ public void shouldUnpackAllResponses() throws Throwable
8087
}
8188

8289
@Test
83-
public void shouldUnpackAllValues() throws Throwable
90+
public void shouldPackUnpackValidValues() throws Throwable
8491
{
8592
assertSerializesValue( value( parameters( "cat", null, "dog", null ) ) );
8693
assertSerializesValue( value( parameters( "k", 12, "a", "banana" ) ) );
8794
assertSerializesValue( value( asList( "k", 12, "a", "banana" ) ) );
88-
assertSerializesValue( value(
89-
new InternalNode( 1, Collections.singletonList( "User" ), parameters( "name", "Bob", "age", 45 ).asMap(
90-
ofValue() ) )
91-
) );
92-
assertSerializesValue( value( new InternalNode( 1 ) ) );
93-
assertSerializesValue( value(
94-
new InternalRelationship( 1, 1, 1,
95-
"KNOWS",
96-
parameters( "name", "Bob", "age", 45 ).asMap( ofValue() ) ) ) );
97-
assertSerializesValue( value(
98-
new InternalPath(
99-
new InternalNode( 1 ),
100-
new InternalRelationship( 2, 1, 3,
101-
"KNOWS", EmptyMap.asMap( ofValue() ) ),
102-
new InternalNode( 3 ),
103-
new InternalRelationship( 4, 3, 5,
104-
"LIKES", EmptyMap.asMap( ofValue() ) ),
105-
new InternalNode( 5 )
106-
) ) );
107-
assertSerializesValue( value( new InternalPath( new InternalNode( 1 ) ) ) );
10895
}
10996

97+
@Test
98+
public void shouldUnpackNodeRelationshipAndPath() throws Throwable
99+
{
100+
// Given
101+
assertOnlyDeserializesValue( emptyNodeValue() );
102+
assertOnlyDeserializesValue( filledNodeValue() );
103+
assertOnlyDeserializesValue( emptyRelationshipValue() );
104+
assertOnlyDeserializesValue( filledRelationshipValue() );
105+
assertOnlyDeserializesValue( emptyPathValue() );
106+
assertOnlyDeserializesValue( filledPathValue() );
107+
}
108+
109+
110+
@Test
111+
public void shouldErrorPackingNode() throws Throwable
112+
{
113+
// Given
114+
Value value = filledNodeValue();
115+
expectIOExceptionWithMessage( value, "Unknown type: NODE" );
116+
}
117+
118+
@Test
119+
public void shouldErrorPackingRelationship() throws Throwable
120+
{
121+
// Given
122+
Value value = filledRelationshipValue();
123+
expectIOExceptionWithMessage( value, "Unknown type: RELATIONSHIP" );
124+
}
125+
126+
@Test
127+
public void shouldErrorPackingPath() throws Throwable
128+
{
129+
// Given
130+
Value value = filledPathValue();
131+
expectIOExceptionWithMessage( value, "Unknown type: PATH" );
132+
}
133+
134+
110135
@Test
111136
public void shouldGiveHelpfulErrorOnMalformedNodeStruct() throws Throwable
112137
{
@@ -149,6 +174,11 @@ private void assertSerializes( Message message ) throws Throwable
149174
}
150175

151176
private EmbeddedChannel newEmbeddedChannel()
177+
{
178+
return newEmbeddedChannel( format );
179+
}
180+
181+
private EmbeddedChannel newEmbeddedChannel( MessageFormat format )
152182
{
153183
EmbeddedChannel channel = new EmbeddedChannel();
154184
setMessageDispatcher( channel, new MemorizingInboundMessageDispatcher( channel, DEV_NULL_LOGGING ) );
@@ -186,4 +216,51 @@ private Message unpack( ByteBuf packed, EmbeddedChannel channel ) throws Throwab
186216
assertEquals( 1, unpackedMessages.size() );
187217
return unpackedMessages.get( 0 );
188218
}
219+
220+
private void assertOnlyDeserializesValue( Value value ) throws Throwable
221+
{
222+
RecordMessage message = new RecordMessage( new Value[]{value} );
223+
ByteBuf packed = knowledgeablePack( message );
224+
225+
EmbeddedChannel channel = newEmbeddedChannel();
226+
Message unpackedMessage = unpack( packed, channel );
227+
228+
assertEquals( message, unpackedMessage );
229+
}
230+
231+
private ByteBuf knowledgeablePack( Message message ) throws IOException
232+
{
233+
EmbeddedChannel channel = newEmbeddedChannel( new KnowledgeablePackStreamMessageFormat() );
234+
assertTrue( channel.writeOutbound( message ) );
235+
236+
ByteBuf[] packedMessages = channel.outboundMessages()
237+
.stream()
238+
.map( msg -> (ByteBuf) msg )
239+
.toArray( ByteBuf[]::new );
240+
241+
return Unpooled.wrappedBuffer( packedMessages );
242+
}
243+
244+
private void expectIOExceptionWithMessage( Value value, String errorMessage )
245+
{
246+
RecordMessage message = new RecordMessage( new Value[]{value} );
247+
EmbeddedChannel channel = newEmbeddedChannel();
248+
249+
try
250+
{
251+
pack( message, channel );
252+
fail( "Expecting a EncoderException" );
253+
}
254+
catch ( EncoderException e )
255+
{
256+
Throwable cause = e.getCause();
257+
assertThat( cause, instanceOf( IOException.class ) );
258+
assertThat( cause.getMessage(), equalTo( errorMessage ) );
259+
}
260+
catch ( Exception e )
261+
{
262+
fail( "Expecting a EncoderException but got " + e );
263+
}
264+
}
265+
189266
}

0 commit comments

Comments
 (0)