From 0897ebce2347db21b2e74fe3161ccdaf90f37f0e Mon Sep 17 00:00:00 2001 From: fickludd Date: Thu, 18 Jan 2018 15:49:45 +0100 Subject: [PATCH] Refactor relationship tests in Kernel API - Add framework for testing all traversal combinations with tx-state changes --- .../neo4j/internal/kernel/api/TokenRead.java | 9 + .../kernel/api/{Node.java => NodeData.java} | 4 +- .../kernel/api/RelationshipTestSupport.java | 268 ++++++++++++++++++ .../RelationshipTransactionStateTestBase.java | 113 ++++++++ .../RelationshipTraversalCursorTestBase.java | 200 +++---------- .../internal/kernel/api/StubNodeCursor.java | 10 +- .../kernel/impl/newapi/AllStoreHolder.java | 1 + .../neo4j/kernel/impl/newapi/KernelToken.java | 7 + 8 files changed, 438 insertions(+), 174 deletions(-) rename community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/{Node.java => NodeData.java} (95%) create mode 100644 community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTestSupport.java diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/TokenRead.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/TokenRead.java index 17c2fcee9a4ed..bf99f0c003954 100644 --- a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/TokenRead.java +++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/TokenRead.java @@ -19,6 +19,7 @@ */ package org.neo4j.internal.kernel.api; +import org.neo4j.internal.kernel.api.exceptions.KernelException; import org.neo4j.internal.kernel.api.exceptions.LabelNotFoundKernelException; import org.neo4j.internal.kernel.api.exceptions.PropertyKeyIdNotFoundKernelException; @@ -54,6 +55,14 @@ public interface TokenRead */ int relationshipType( String name ); + /** + * Returns the name of a relationship type given its id + * + * @param relationshipTypeId The id of the relationship type + * @return The name of the relationship type + */ + String relationshipTypeName( int relationshipTypeId ) throws KernelException; + /** * Return the id of the provided property key, or NO_TOKEN if the property isn't known to the graph. * diff --git a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/Node.java b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/NodeData.java similarity index 95% rename from community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/Node.java rename to community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/NodeData.java index aea1b3d026419..79b1eb3c945c3 100644 --- a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/Node.java +++ b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/NodeData.java @@ -23,13 +23,13 @@ import org.neo4j.values.storable.Value; -class Node +class NodeData { final long id; private final long[] labels; final Map properties; - Node( long id, long[] labels, Map properties ) + NodeData( long id, long[] labels, Map properties ) { this.id = id; this.labels = labels; diff --git a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTestSupport.java b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTestSupport.java new file mode 100644 index 0000000000000..5ecc450747cfe --- /dev/null +++ b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTestSupport.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2002-2018 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.internal.kernel.api; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.neo4j.graphdb.*; +import org.neo4j.graphdb.Transaction; +import org.neo4j.helpers.collection.Iterators; +import org.neo4j.internal.kernel.api.exceptions.KernelException; + +import static org.junit.Assert.assertEquals; +import static org.neo4j.graphdb.RelationshipType.withName; + +public class RelationshipTestSupport +{ + private RelationshipTestSupport() + { + } + + static void someGraph( GraphDatabaseService graphDb ) + { + Relationship dead; + try ( org.neo4j.graphdb.Transaction tx = graphDb.beginTx() ) + { + Node a = graphDb.createNode(), + b = graphDb.createNode(), + c = graphDb.createNode(), + d = graphDb.createNode(); + + a.createRelationshipTo( a, withName( "ALPHA" ) ); + a.createRelationshipTo( b, withName( "BETA" ) ); + a.createRelationshipTo( c, withName( "GAMMA" ) ); + a.createRelationshipTo( d, withName( "DELTA" ) ); + + graphDb.createNode().createRelationshipTo( a, withName( "BETA" ) ); + a.createRelationshipTo( graphDb.createNode(), withName( "BETA" ) ); + dead = a.createRelationshipTo( graphDb.createNode(), withName( "BETA" ) ); + a.createRelationshipTo( graphDb.createNode(), withName( "BETA" ) ); + + Node clump = graphDb.createNode(); + clump.createRelationshipTo( clump, withName( "REL" ) ); + clump.createRelationshipTo( clump, withName( "REL" ) ); + clump.createRelationshipTo( clump, withName( "REL" ) ); + clump.createRelationshipTo( graphDb.createNode(), withName( "REL" ) ); + clump.createRelationshipTo( graphDb.createNode(), withName( "REL" ) ); + clump.createRelationshipTo( graphDb.createNode(), withName( "REL" ) ); + graphDb.createNode().createRelationshipTo( clump, withName( "REL" ) ); + graphDb.createNode().createRelationshipTo( clump, withName( "REL" ) ); + graphDb.createNode().createRelationshipTo( clump, withName( "REL" ) ); + + tx.success(); + } + + try ( org.neo4j.graphdb.Transaction tx = graphDb.beginTx() ) + { + Node node = dead.getEndNode(); + dead.delete(); + node.delete(); + + tx.success(); + } + } + + static Function[] sparseDenseRels = Iterators.array( + outgoing( "FOO" ), + outgoing( "BAR" ), + outgoing( "BAR" ), + incoming( "FOO" ), + outgoing( "FOO" ), + incoming( "BAZ" ), + incoming( "BAR" ), + outgoing( "BAZ" ) + ); + + static StartNode sparse( GraphDatabaseService graphDb ) + { + Node node; + Map> relationshipMap; + try ( Transaction tx = graphDb.beginTx() ) + { + node = graphDb.createNode(); + relationshipMap = buildSparseDenseRels( node ); + tx.success(); + } + return new StartNode( node.getId(), relationshipMap ); + } + + static StartNode dense( GraphDatabaseService graphDb ) + { + Node node; + Map> relationshipMap; + try ( Transaction tx = graphDb.beginTx() ) + { + node = graphDb.createNode(); + relationshipMap = buildSparseDenseRels( node ); + + for ( int i = 0; i < 200; i++ ) + { + node.createRelationshipTo( graphDb.createNode(), withName( "BULK" ) ); + } + + tx.success(); + } + return new StartNode( node.getId(), relationshipMap ); + } + + static void count( + Session session, + RelationshipTraversalCursor relationship, + Map counts, + boolean expectSameType ) throws KernelException + { + Integer type = null; + while ( relationship.next() ) + { + if ( expectSameType ) + { + if ( type != null ) + { + assertEquals( "same type", type.intValue(), relationship.label() ); + } + else + { + type = relationship.label(); + } + } + + String key = computeKey( session, relationship ); + + counts.compute( key, ( k, value ) -> value == null ? 1 : value + 1 ); + } + } + + static class R + { + public final long id; + public final Direction direction; + public final RelationshipType type; + + R( long id, Direction direction, RelationshipType type ) + { + this.id = id; + this.type = type; + this.direction = direction; + } + } + + static class StartNode + { + public final long id; + public final Map> relationships; + + StartNode( long id, Map> relationships ) + { + this.id = id; + this.relationships = relationships; + } + + Map expectedCounts() + { + Map expectedCounts = new HashMap<>(); + for ( Map.Entry> kv : relationships.entrySet() ) + { + expectedCounts.put( kv.getKey(), relationships.get( kv.getKey() ).size() ); + } + return expectedCounts; + } + } + + static void assertCounts( Map expectedCounts, Map counts ) + { + for ( Map.Entry expected : expectedCounts.entrySet() ) + { + assertEquals( + String.format( "counts for relationship key '%s' are equal", expected.getKey() ), + expected.getValue(), counts.get( expected.getKey()) ); + } + } + + private static Map> buildSparseDenseRels( Node node ) + { + Map> relationshipMap = new HashMap<>(); + for ( Function rel : sparseDenseRels ) + { + R r = rel.apply( node ); + List relsOfType = relationshipMap.computeIfAbsent( computeKey( r ), key -> new ArrayList<>() ); + relsOfType.add( r ); + } + return relationshipMap; + } + + private static String computeKey( R r ) + { + return computeKey( r.type.name(), r.direction ); + } + + private static String computeKey( Session session, RelationshipTraversalCursor r ) throws KernelException + { + Direction d; + if ( r.sourceNodeReference() == r.targetNodeReference() ) + { + d = Direction.BOTH; + } + else if ( r.sourceNodeReference() == r.originNodeReference() ) + { + d = Direction.OUTGOING; + } + else + { + d = Direction.INCOMING; + } + + return computeKey( session.token().relationshipTypeName( r.label() ), d ); + } + + private static String computeKey( String type, Direction direction ) + { + return type.toString() + "-" + direction.toString(); + } + + private static Function outgoing( String type ) + { + return node -> + { + GraphDatabaseService db = node.getGraphDatabase(); + RelationshipType relType = withName( type ); + return new R( + node.createRelationshipTo( db.createNode(), relType ).getId(), + Direction.OUTGOING, + relType ); + }; + } + + private static Function incoming( String type ) + { + return node -> + { + GraphDatabaseService db = node.getGraphDatabase(); + RelationshipType relType = withName( type ); + return new R( + db.createNode().createRelationshipTo( node, relType ).getId(), + Direction.INCOMING, + relType ); + }; + } +} diff --git a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTransactionStateTestBase.java b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTransactionStateTestBase.java index aaaa89dee9cf3..478e7d87cb32e 100644 --- a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTransactionStateTestBase.java +++ b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTransactionStateTestBase.java @@ -21,9 +21,15 @@ import org.junit.Test; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.neo4j.internal.kernel.api.RelationshipTestSupport.assertCounts; +import static org.neo4j.internal.kernel.api.RelationshipTestSupport.count; @SuppressWarnings( "Duplicates" ) public abstract class RelationshipTransactionStateTestBase extends KernelAPIWriteTestBase @@ -187,4 +193,111 @@ public void shouldSeeRelationshipInTransactionBeforeCursorInitialization() throw tx.success(); } } + +// @Test +// public void shouldTraverseSparseNodeViaGroups() throws Exception +// { +// traverseViaGroups( RelationshipTestSupport.sparse( graphDb ), false ); +// } +// +// @Test +// public void shouldTraverseDenseNodeViaGroups() throws Exception +// { +// traverseViaGroups( RelationshipTestSupport.dense( graphDb ), false ); +// } +// +// @Test +// public void shouldTraverseSparseNodeViaGroupsWithDetachedReferences() throws Exception +// { +// traverseViaGroups( RelationshipTestSupport.sparse( graphDb ), true ); +// } +// +// @Test +// public void shouldTraverseDenseNodeViaGroupsWithDetachedReferences() throws Exception +// { +// traverseViaGroups( RelationshipTestSupport.dense( graphDb ), true ); +// } + + @Test + public void shouldTraverseSparseNodeWithoutGroups() throws Exception + { + traverseWithoutGroups( RelationshipTestSupport.sparse( graphDb ), false ); + } + + @Test + public void shouldTraverseDenseNodeWithoutGroups() throws Exception + { + traverseWithoutGroups( RelationshipTestSupport.dense( graphDb ), false ); + } + + @Test + public void shouldTraverseSparseNodeWithoutGroupsWithDetachedReferences() throws Exception + { + traverseWithoutGroups( RelationshipTestSupport.sparse( graphDb ), true ); + } + + @Test + public void shouldTraverseDenseNodeWithoutGroupsWithDetachedReferences() throws Exception + { + traverseWithoutGroups( RelationshipTestSupport.dense( graphDb ), true ); + } + + private void traverseWithoutGroups( RelationshipTestSupport.StartNode start, boolean detached ) throws Exception + { + try ( Transaction tx = session.beginTransaction() ) + { + Map expectedCounts = new HashMap<>(); + for ( Map.Entry> kv : start.relationships.entrySet() ) + { + List r = kv.getValue(); + RelationshipTestSupport.R head = r.get( 0 ); + int label = session.token().relationshipType( head.type.name() ); + switch ( head.direction ) + { + case INCOMING: + tx.dataWrite().relationshipCreate( tx.dataWrite().nodeCreate(), label, start.id ); + tx.dataWrite().relationshipCreate( tx.dataWrite().nodeCreate(), label, start.id ); + break; + case OUTGOING: + tx.dataWrite().relationshipCreate( start.id, label, tx.dataWrite().nodeCreate() ); + tx.dataWrite().relationshipCreate( start.id, label, tx.dataWrite().nodeCreate() ); + break; + case BOTH: + tx.dataWrite().relationshipCreate( start.id, label, start.id ); + tx.dataWrite().relationshipCreate( start.id, label, start.id ); + break; + default: + throw new IllegalStateException( "Oh ye be cursed, foul checkstyle!" ); + } + tx.dataWrite().relationshipDelete( head.id ); + expectedCounts.put( kv.getKey(), r.size() + 1 ); + } + + // given + try ( NodeCursor node = cursors.allocateNodeCursor(); + RelationshipTraversalCursor relationship = cursors.allocateRelationshipTraversalCursor() ) + { + // when + tx.dataRead().singleNode( start.id, node ); + + assertTrue( "access node", node.next() ); + if ( detached ) + { + tx.dataRead().relationships( start.id, node.allRelationshipsReference(), relationship ); + } + else + { + node.allRelationships( relationship ); + } + + Map counts = new HashMap<>(); + count( session, relationship, counts, false ); + + // then + assertCounts( expectedCounts, counts ); + } + + tx.failure(); + } + } } diff --git a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTraversalCursorTestBase.java b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTraversalCursorTestBase.java index 55866249a6e44..a51822d4ddea7 100644 --- a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTraversalCursorTestBase.java +++ b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/RelationshipTraversalCursorTestBase.java @@ -24,24 +24,24 @@ import java.util.HashMap; import java.util.Map; -import java.util.function.Consumer; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.Relationship; -import org.neo4j.graphdb.Transaction; +import org.neo4j.internal.kernel.api.exceptions.KernelException; -import static java.util.Arrays.sort; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.neo4j.graphdb.RelationshipType.withName; +import static org.neo4j.internal.kernel.api.RelationshipTestSupport.assertCounts; +import static org.neo4j.internal.kernel.api.RelationshipTestSupport.count; public abstract class RelationshipTraversalCursorTestBase extends KernelAPIReadTestBase { - private static long bare, start, end, sparse, dense; + private static long bare, start, end; + private static RelationshipTestSupport.StartNode sparse, dense; protected boolean supportsDirectTraversal() { @@ -53,22 +53,10 @@ protected boolean supportsSparseNodes() return true; } - @Override - void createTestGraph( GraphDatabaseService graphDb ) + private static void bareStartAndEnd( GraphDatabaseService graphDb ) { - Relationship dead; - try ( Transaction tx = graphDb.beginTx() ) + try ( org.neo4j.graphdb.Transaction tx = graphDb.beginTx() ) { - Node a = graphDb.createNode(), - b = graphDb.createNode(), - c = graphDb.createNode(), - d = graphDb.createNode(); - - a.createRelationshipTo( a, withName( "ALPHA" ) ); - a.createRelationshipTo( b, withName( "BETA" ) ); - a.createRelationshipTo( c, withName( "GAMMA" ) ); - a.createRelationshipTo( d, withName( "DELTA" ) ); - bare = graphDb.createNode().getId(); Node x = graphDb.createNode(), y = graphDb.createNode(); @@ -76,111 +64,18 @@ void createTestGraph( GraphDatabaseService graphDb ) end = y.getId(); x.createRelationshipTo( y, withName( "GEN" ) ); - graphDb.createNode().createRelationshipTo( a, withName( "BETA" ) ); - a.createRelationshipTo( graphDb.createNode(), withName( "BETA" ) ); - dead = a.createRelationshipTo( graphDb.createNode(), withName( "BETA" ) ); - a.createRelationshipTo( graphDb.createNode(), withName( "BETA" ) ); - - Node clump = graphDb.createNode(); - clump.createRelationshipTo( clump, withName( "REL" ) ); - clump.createRelationshipTo( clump, withName( "REL" ) ); - clump.createRelationshipTo( clump, withName( "REL" ) ); - clump.createRelationshipTo( graphDb.createNode(), withName( "REL" ) ); - clump.createRelationshipTo( graphDb.createNode(), withName( "REL" ) ); - clump.createRelationshipTo( graphDb.createNode(), withName( "REL" ) ); - graphDb.createNode().createRelationshipTo( clump, withName( "REL" ) ); - graphDb.createNode().createRelationshipTo( clump, withName( "REL" ) ); - graphDb.createNode().createRelationshipTo( clump, withName( "REL" ) ); - - tx.success(); - } - - try ( Transaction tx = graphDb.beginTx() ) - { - Node node = dead.getEndNode(); - dead.delete(); - node.delete(); - - tx.success(); - } - - Node sparseNode = node( - graphDb, - outgoing( "FOO" ), - outgoing( "BAR" ), - outgoing( "BAR" ), - incoming( "FOO" ), - outgoing( "FOO" ), - incoming( "BAZ" ), - incoming( "BAR" ), - outgoing( "BAZ" ) ); - Node denseNode; - // dense node - try ( Transaction tx = graphDb.beginTx() ) - { - denseNode = graphDb.createNode(); - for ( Relationship rel : sparseNode.getRelationships() ) - { - if ( sparseNode.equals( rel.getStartNode() ) ) - { - denseNode.createRelationshipTo( graphDb.createNode(), rel.getType() ); - } - else - { - graphDb.createNode().createRelationshipTo( denseNode, rel.getType() ); - } - } - for ( int i = 0; i < 200; i++ ) - { - denseNode.createRelationshipTo( graphDb.createNode(), withName( "BULK" ) ); - } - tx.success(); } - sparse = sparseNode.getId(); - dense = denseNode.getId(); } - @SafeVarargs - private static Node node( GraphDatabaseService db, Consumer... changes ) - { - Node node; - try ( Transaction tx = db.beginTx() ) - { - node = db.createNode(); - tx.success(); - } - for ( int i = changes.length; i-- > 0; ) - { - changes[i].accept( node ); - } - return node; - } - - private static Consumer outgoing( String type ) + @Override + void createTestGraph( GraphDatabaseService graphDb ) { - return node -> - { - GraphDatabaseService db = node.getGraphDatabase(); - try ( Transaction tx = db.beginTx() ) - { - node.createRelationshipTo( db.createNode(), withName( type ) ); - tx.success(); - } - }; - } + RelationshipTestSupport.someGraph( graphDb ); + bareStartAndEnd( graphDb ); - private static Consumer incoming( String type ) - { - return node -> - { - GraphDatabaseService db = node.getGraphDatabase(); - try ( Transaction tx = db.beginTx() ) - { - db.createNode().createRelationshipTo( node, withName( type ) ); - tx.success(); - } - }; + sparse = RelationshipTestSupport.sparse( graphDb ); + dense = RelationshipTestSupport.dense( graphDb ); } @Test @@ -339,11 +234,11 @@ public void shouldHaveBeenAbleToCreateDenseAndSparseNodes() throws Exception // given try ( NodeCursor node = cursors.allocateNodeCursor() ) { - read.singleNode( dense, node ); + read.singleNode( dense.id, node ); assertTrue( "access dense node", node.next() ); assertTrue( "dense node", node.isDense() ); - read.singleNode( sparse, node ); + read.singleNode( sparse.id, node ); assertTrue( "access sparse node", node.next() ); assertFalse( "sparse node", node.isDense() && supportsSparseNodes() ); } @@ -401,7 +296,7 @@ public void shouldTraverseDenseNodeWithoutGroupsWithDetachedReferences() throws traverseWithoutGroups( dense, true ); } - private void traverseViaGroups( long start, boolean detached ) + private void traverseViaGroups( RelationshipTestSupport.StartNode start, boolean detached ) throws KernelException { // given try ( NodeCursor node = cursors.allocateNodeCursor(); @@ -409,113 +304,84 @@ private void traverseViaGroups( long start, boolean detached ) RelationshipTraversalCursor relationship = cursors.allocateRelationshipTraversalCursor() ) { // when - read.singleNode( start, node ); + read.singleNode( start.id, node ); assertTrue( "access node", node.next() ); if ( detached ) { - read.relationshipGroups( start, node.relationshipGroupReference(), group ); + read.relationshipGroups( start.id, node.relationshipGroupReference(), group ); } else { node.relationships( group ); } - Map counts = new HashMap<>(); + Map counts = new HashMap<>(); while ( group.next() ) { // outgoing if ( detached ) { - read.relationships( start, group.outgoingReference(), relationship ); + read.relationships( start.id, group.outgoingReference(), relationship ); } else { group.outgoing( relationship ); } - count( relationship, counts, true ); + count( session, relationship, counts, true ); // incoming if ( detached ) { - read.relationships( start, group.incomingReference(), relationship ); + read.relationships( start.id, group.incomingReference(), relationship ); } else { group.incoming( relationship ); } - count( relationship, counts, true ); + count( session, relationship, counts, true ); // loops if ( detached ) { - read.relationships( start, group.loopsReference(), relationship ); + read.relationships( start.id, group.loopsReference(), relationship ); } else { group.loops( relationship ); } - count( relationship, counts, true ); + count( session, relationship, counts, true ); } // then - assertCounts( counts ); + assertCounts( start.expectedCounts(), counts ); } } - private void traverseWithoutGroups( long start, boolean detached ) + private void traverseWithoutGroups( RelationshipTestSupport.StartNode start, boolean detached ) + throws KernelException { // given try ( NodeCursor node = cursors.allocateNodeCursor(); RelationshipTraversalCursor relationship = cursors.allocateRelationshipTraversalCursor() ) { // when - read.singleNode( start, node ); + read.singleNode( start.id, node ); assertTrue( "access node", node.next() ); if ( detached ) { - read.relationships( start, node.allRelationshipsReference(), relationship ); + read.relationships( start.id, node.allRelationshipsReference(), relationship ); } else { node.allRelationships( relationship ); } - Map counts = new HashMap<>(); - count( relationship, counts, false ); + Map counts = new HashMap<>(); + count( session, relationship, counts, false ); // then - assertCounts( counts ); + assertCounts( start.expectedCounts(), counts ); } } - private void count( RelationshipTraversalCursor relationship, Map counts, boolean expectSameType ) - { - Integer type = null; - while ( relationship.next() ) - { - if ( expectSameType ) - { - if ( type != null ) - { - assertEquals( "same type", type.intValue(), relationship.label() ); - } - else - { - type = relationship.label(); - } - } - counts.compute( relationship.label(), ( key, value ) -> value == null ? 1 : value + 1 ); - } - } - - private void assertCounts( Map counts ) - { - Integer[] values = counts.values().toArray( new Integer[0] ); - assertTrue( values.length >= 3 ); - sort( values ); - assertEquals( 2, values[0].intValue() ); - assertEquals( 3, values[1].intValue() ); - assertEquals( 3, values[2].intValue() ); - } - private static class Sizes { int incoming, outgoing, loop; diff --git a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/StubNodeCursor.java b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/StubNodeCursor.java index ef9ababdc8f13..1af351ec71037 100644 --- a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/StubNodeCursor.java +++ b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/StubNodeCursor.java @@ -29,7 +29,7 @@ public class StubNodeCursor implements NodeCursor { private int offset = -1; - private List nodes = new ArrayList<>(); + private List nodes = new ArrayList<>(); void single( long reference ) { @@ -50,19 +50,19 @@ void scan() public StubNodeCursor withNode( long id ) { - nodes.add( new Node( id, new long[]{}, Collections.emptyMap() ) ); + nodes.add( new NodeData( id, new long[]{}, Collections.emptyMap() ) ); return this; } public StubNodeCursor withNode( long id, long... labels ) { - nodes.add( new Node( id, labels, Collections.emptyMap() ) ); + nodes.add( new NodeData( id, labels, Collections.emptyMap() ) ); return this; } public StubNodeCursor withNode( long id, long[] labels, Map properties ) { - nodes.add( new Node( id, labels, properties ) ); + nodes.add( new NodeData( id, labels, properties ) ); return this; } @@ -119,7 +119,7 @@ public long propertiesReference() { if ( offset >= 0 && offset < nodes.size() ) { - Node node = nodes.get( offset ); + NodeData node = nodes.get( offset ); if ( !node.properties.isEmpty() ) { return node.id; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java index a1022ff8071fc..af4c3637b831c 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java @@ -35,6 +35,7 @@ import org.neo4j.internal.kernel.api.schema.constraints.ConstraintDescriptor; import org.neo4j.io.pagecache.PageCursor; import org.neo4j.kernel.api.ExplicitIndex; +import org.neo4j.kernel.api.exceptions.RelationshipTypeIdNotFoundKernelException; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; import org.neo4j.kernel.api.schema.LabelSchemaDescriptor; import org.neo4j.kernel.api.schema.index.IndexDescriptor; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/KernelToken.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/KernelToken.java index 579575c282206..4ee98cba32144 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/KernelToken.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/KernelToken.java @@ -24,6 +24,7 @@ import org.neo4j.internal.kernel.api.exceptions.PropertyKeyIdNotFoundKernelException; import org.neo4j.internal.kernel.api.exceptions.schema.IllegalTokenNameException; import org.neo4j.internal.kernel.api.exceptions.schema.TooManyLabelsException; +import org.neo4j.kernel.api.exceptions.RelationshipTypeIdNotFoundKernelException; import org.neo4j.storageengine.api.StoreReadLayer; public class KernelToken implements Token @@ -71,6 +72,12 @@ public int relationshipType( String name ) return store.relationshipTypeGetForName( name ); } + @Override + public String relationshipTypeName( int relationshipTypeId ) throws RelationshipTypeIdNotFoundKernelException + { + return store.relationshipTypeGetName( relationshipTypeId ); + } + @Override public int propertyKey( String name ) {