diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java index 237be062aa8..4ce7e1add9f 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java @@ -281,6 +281,22 @@ public Configuration configuration() { protected abstract void addInEdge(final TinkerVertex vertex, final String label, final Edge edge); + protected TinkerVertex createTinkerVertex(final Object id, final String label, final AbstractTinkerGraph graph) { + return new TinkerVertex(id, label, graph); + } + + protected TinkerVertex createTinkerVertex(final Object id, final String label, final AbstractTinkerGraph graph, final long currentVersion) { + return new TinkerVertex(id, label, graph, currentVersion); + } + + protected TinkerEdge createTinkerEdge(final Object id, final Vertex outVertex, final String label, final Vertex inVertex) { + return new TinkerEdge(id, outVertex, label, inVertex); + } + + protected TinkerEdge createTinkerEdge(final Object id, final Vertex outVertex, final String label, final Vertex inVertex, final long currentVersion) { + return new TinkerEdge(id, outVertex, label, inVertex, currentVersion); + } + ///////////// Features /////////////// public class TinkerGraphVertexFeatures implements Features.VertexFeatures { diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java index 93dcf594d7c..43fcc29d131 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java @@ -38,7 +38,7 @@ /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class TinkerEdge extends TinkerElement implements Edge { +public class TinkerEdge extends TinkerElement implements Edge { protected Map properties; diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java index 40e23253a99..acf540a613a 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java @@ -59,7 +59,7 @@ @Graph.OptIn(Graph.OptIn.SUITE_PROCESS_COMPUTER) @Graph.OptIn(Graph.OptIn.SUITE_PROCESS_LIMITED_STANDARD) @Graph.OptIn(Graph.OptIn.SUITE_PROCESS_LIMITED_COMPUTER) -public final class TinkerGraph extends AbstractTinkerGraph { +public class TinkerGraph extends AbstractTinkerGraph { static { TraversalStrategies.GlobalCache.registerStrategies(TinkerGraph.class, TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone().addStrategies( @@ -79,7 +79,7 @@ public final class TinkerGraph extends AbstractTinkerGraph { /** * An empty private constructor that initializes {@link TinkerGraph}. */ - private TinkerGraph(final Configuration configuration) { + TinkerGraph(final Configuration configuration) { this.configuration = configuration; vertexIdManager = selectIdManager(configuration, GREMLIN_TINKERGRAPH_VERTEX_ID_MANAGER, Vertex.class); edgeIdManager = selectIdManager(configuration, GREMLIN_TINKERGRAPH_EDGE_ID_MANAGER, Edge.class); @@ -146,7 +146,7 @@ public Vertex addVertex(final Object... keyValues) { idValue = vertexIdManager.getNextId(this); } - final Vertex vertex = new TinkerVertex(idValue, label, this); + final Vertex vertex = createTinkerVertex(idValue, label, this); ElementHelper.attachProperties(vertex, VertexProperty.Cardinality.list, keyValues); this.vertices.put(vertex.id(), vertex); diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java index 3e1f131e89e..80a0f806427 100644 --- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java +++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java @@ -41,7 +41,7 @@ /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ -public final class TinkerVertex extends TinkerElement implements Vertex { +public class TinkerVertex extends TinkerElement implements Vertex { protected Map> properties; // Edges should be used by non-transaction Graph due to performance @@ -50,7 +50,7 @@ public final class TinkerVertex extends TinkerElement implements Vertex { // Edge ids are for transactional Graph protected Map> outEdgesId; protected Map> inEdgesId; - private final AbstractTinkerGraph graph; + protected final AbstractTinkerGraph graph; private boolean allowNullPropertyValues; private final boolean isTxMode; @@ -160,7 +160,7 @@ public VertexProperty property(final VertexProperty.Cardinality cardinali graph.vertexPropertyIdManager.convert(optionalId.get()) : graph.vertexPropertyIdManager.getNextId(graph); - final VertexProperty vertexProperty = new TinkerVertexProperty(idValue, this, key, value); + final VertexProperty vertexProperty = createTinkerVertexProperty(idValue, this, key, value); if (null == this.properties) this.properties = new ConcurrentHashMap<>(); final List list = this.properties.getOrDefault(key, new ArrayList<>()); @@ -230,6 +230,14 @@ public Iterator vertices(final Direction direction, final String... edge : (Iterator) TinkerHelper.getVertices(this, direction, edgeLabels); } + protected TinkerVertexProperty createTinkerVertexProperty(final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) { + return new TinkerVertexProperty(vertex, key, value, propertyKeyValues); + } + + protected TinkerVertexProperty createTinkerVertexProperty(final Object id, final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) { + return new TinkerVertexProperty(id, vertex, key, value, propertyKeyValues); + } + @Override public Iterator> properties(final String... propertyKeys) { if (this.removed) return Collections.emptyIterator(); diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerShuffleGraphFeatureTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerShuffleGraphFeatureTest.java new file mode 100644 index 00000000000..6b86ecc4527 --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerShuffleGraphFeatureTest.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tinkerpop.gremlin.tinkergraph; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Stage; +import io.cucumber.guice.CucumberModules; +import io.cucumber.junit.Cucumber; +import io.cucumber.junit.CucumberOptions; +import org.apache.tinkerpop.gremlin.features.AbstractGuiceFactory; +import org.apache.tinkerpop.gremlin.features.World; +import org.junit.runner.RunWith; + +@RunWith(Cucumber.class) +@CucumberOptions( + tags = "not @RemoteOnly and not @GraphComputerOnly and not @AllowNullPropertyValues", + glue = { "org.apache.tinkerpop.gremlin.features" }, + objectFactory = TinkerShuffleGraphFeatureTest.TinkerShuffleGraphGuiceFactory.class, + features = { "classpath:/org/apache/tinkerpop/gremlin/test/features" }, + plugin = {"progress", "junit:target/cucumber.xml"}) +public class TinkerShuffleGraphFeatureTest { + + public static class TinkerShuffleGraphGuiceFactory extends AbstractGuiceFactory { + public TinkerShuffleGraphGuiceFactory() { + super(Guice.createInjector(Stage.PRODUCTION, CucumberModules.createScenarioModule(), new ServiceModule())); + } + } + + public static final class ServiceModule extends AbstractModule { + @Override + protected void configure() { + bind(World.class).to(TinkerWorld.TinkerShuffleGraphWorld.class); + } + } +} diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java index b0abbdef752..eb7e981e219 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java @@ -36,6 +36,7 @@ import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerTransactionGraph; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerShuffleGraph; import org.junit.AssumptionViolatedException; import java.io.File; @@ -149,6 +150,61 @@ public AbstractTinkerGraph open(final Configuration configuration) { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * The {@link World} implementation for TinkerShuffleGraph that provides the {@link GraphTraversalSource} + * instances required by the Gherkin test suite. + */ + public static class TinkerShuffleGraphWorld extends TinkerWorld { + private static final TinkerGraph modern; + private static final TinkerGraph classic; + private static final TinkerGraph crew; + private static final TinkerGraph sink; + private static final TinkerGraph grateful; + + static { + modern = TinkerShuffleGraph.open(); + TinkerFactory.generateModern(modern); + registerTestServices(modern); + classic = TinkerShuffleGraph.open(); + TinkerFactory.generateClassic(classic); + registerTestServices(classic); + crew = TinkerShuffleGraph.open(); + TinkerFactory.generateTheCrew(crew); + registerTestServices(crew); + sink = TinkerShuffleGraph.open(); + TinkerFactory.generateKitchenSink(sink); + registerTestServices(sink); + grateful = TinkerShuffleGraph.open(); + TinkerFactory.generateGratefulDead(grateful); + registerTestServices(grateful); + } + + @Override + public GraphTraversalSource getGraphTraversalSource(final LoadGraphWith.GraphData graphData) { + if (null == graphData) + return registerTestServices(TinkerGraph.open(getNumberIdManagerConfiguration())).traversal(); + else if (graphData == LoadGraphWith.GraphData.CLASSIC) + return classic.traversal(); + else if (graphData == LoadGraphWith.GraphData.CREW) + return crew.traversal(); + else if (graphData == LoadGraphWith.GraphData.MODERN) + return modern.traversal(); + else if (graphData == LoadGraphWith.GraphData.SINK) + return sink.traversal(); + else if (graphData == LoadGraphWith.GraphData.GRATEFUL) + return grateful.traversal(); + else + throw new UnsupportedOperationException("GraphData not supported: " + graphData.name()); + } + + @Override + public AbstractTinkerGraph open(final Configuration configuration) { + return TinkerShuffleGraph.open(configuration); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** * Enables the storing of {@code null} property values when testing. This is a terminal decorator and shouldn't be * used as an input into another decorator. diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleEdge.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleEdge.java new file mode 100644 index 00000000000..48e20e499a1 --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleEdge.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tinkerpop.gremlin.tinkergraph.structure; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Property; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import java.util.Iterator; + +import static org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerShuffleGraph.shuffleIterator; + +/** + * @author Cole Greer (https://github.com/Cole-Greer) + */ +public final class TinkerShuffleEdge extends TinkerEdge { + protected TinkerShuffleEdge(final Object id, final Vertex outVertex, final String label, final Vertex inVertex) { + this(id, outVertex, label, inVertex, 0); + } + + protected TinkerShuffleEdge(final Object id, final Vertex outVertex, final String label, final Vertex inVertex, final long currentVersion) { + super(id, outVertex, label, inVertex, currentVersion); + } + + @Override + public Iterator vertices(final Direction direction) { + return shuffleIterator(super.vertices(direction)); + } + + @Override + public Iterator> properties(final String... propertyKeys) { + return shuffleIterator(super.properties(propertyKeys)); + } +} diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleGraph.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleGraph.java new file mode 100644 index 00000000000..f12a156f65c --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleGraph.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tinkerpop.gremlin.tinkergraph.structure; + +import org.apache.commons.collections.IteratorUtils; +import org.apache.commons.configuration2.BaseConfiguration; +import org.apache.commons.configuration2.Configuration; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * @author Cole Greer (https://github.com/Cole-Greer) + */ +public class TinkerShuffleGraph extends TinkerGraph { + + private static final Configuration EMPTY_CONFIGURATION = new BaseConfiguration() {{ + this.setProperty(Graph.GRAPH, TinkerShuffleGraph.class.getName()); + }}; + + private TinkerShuffleGraph(Configuration configuration) { + super(configuration); + } + + public static TinkerShuffleGraph open() { + return open(EMPTY_CONFIGURATION); + } + + public static TinkerShuffleGraph open(Configuration configuration) { + return new TinkerShuffleGraph(configuration); + } + + @Override + public Iterator vertices(final Object... vertexIds) { + return shuffleIterator(super.vertices(vertexIds)); + } + + @Override + public Iterator edges(final Object... edgeIds) { + return shuffleIterator(super.edges(edgeIds)); + } + + @Override + protected TinkerVertex createTinkerVertex(final Object id, final String label, final AbstractTinkerGraph graph) { + return new TinkerShuffleVertex(id, label, graph); + } + + protected TinkerVertex createTinkerVertex(final Object id, final String label, final AbstractTinkerGraph graph, final long currentVersion) { + return new TinkerShuffleVertex(id, label, graph, currentVersion); + } + + protected TinkerEdge createTinkerEdge(final Object id, final Vertex outVertex, final String label, final Vertex inVertex) { + return new TinkerShuffleEdge(id, outVertex, label, inVertex); + } + + protected TinkerEdge createTinkerEdge(final Object id, final Vertex outVertex, final String label, final Vertex inVertex, final long currentVersion) { + return new TinkerShuffleEdge(id, outVertex, label, inVertex, currentVersion); + } + + static Iterator shuffleIterator(Iterator iter) { + List list = IteratorUtils.toList(iter); + Collections.shuffle(list); + return list.iterator(); + } + +} diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleGraphTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleGraphTest.java new file mode 100644 index 00000000000..577b824898f --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleGraphTest.java @@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tinkerpop.gremlin.tinkergraph.structure; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Property; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; + +/** + * @author Cole Greer (https://github.com/Cole-Greer) + */ +public class TinkerShuffleGraphTest { + + Logger logger = LoggerFactory.getLogger(TinkerShuffleGraphTest.class); + + // Tests are checking for random shuffling of results. If random shuffling happens to return sorted order, the test + // will fail. Worst case scenario are the tests which only return 2 results as these have a 50% chance of a failure. + // Tests are configured with up to 50 retries to drive the failure probability down to the order of 10^-16. + @Rule + public RetryRule retryRule = new RetryRule(); + + @Test + public void shouldShuffleVertices() { + GraphTraversalSource gShuff = createShuffleModern(); + GraphTraversalSource gReg = TinkerFactory.createModern().traversal(); + + List resultRegular = gReg.V().toList(); + Object[] resultShuffle = gShuff.V().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffleEdges() { + GraphTraversalSource gShuff = createShuffleModern(); + GraphTraversalSource gReg = TinkerFactory.createModern().traversal(); + + List resultRegular = gReg.E().toList(); + Object[] resultShuffle = gShuff.E().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffle_g_V_both() { + GraphTraversalSource gShuff = createShuffleModern(); + GraphTraversalSource gReg = TinkerFactory.createModern().traversal(); + + List resultRegular = gReg.V(1).both().toList(); + Object[] resultShuffle = gShuff.V(1).both().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffle_g_V_bothE() { + GraphTraversalSource gShuff = createShuffleModern(); + GraphTraversalSource gReg = TinkerFactory.createModern().traversal(); + + List resultRegular = gReg.V(1).bothE().toList(); + Object[] resultShuffle = gShuff.V(1).bothE().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffle_g_E_bothV() { + GraphTraversalSource gShuff = createShuffleModern(); + GraphTraversalSource gReg = TinkerFactory.createModern().traversal(); + + List resultRegular = gReg.V(1).outE("knows").bothV().toList(); + Object[] resultShuffle = gShuff.V(1).outE("knows").bothV().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffleVertexProperties() { + GraphTraversalSource gShuff = createShuffleModern(); + GraphTraversalSource gReg = TinkerFactory.createModern().traversal(); + + List> resultRegular = (List>) gReg.V(1).properties().toList(); + Object[] resultShuffle = gShuff.V(1).properties().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffleEdgeProperties() { + GraphTraversalSource gShuff = createShuffleModern(); + GraphTraversalSource gReg = TinkerFactory.createModern().traversal(); + + gShuff.V(1).outE("knows").property("extraProp", "no toy graph has 2 props on an edge"); + gReg.V(1).outE("knows").property("extraProp", "no toy graph has 2 props on an edge"); + + List> resultRegular = (List>) gReg.V(1).outE("knows").properties().toList(); + Object[] resultShuffle = gShuff.V(1).outE("knows").properties().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffleMetaProperties() { + GraphTraversalSource gShuff = createShuffleTheCrew(); + GraphTraversalSource gReg = TinkerFactory.createTheCrew().traversal(); + + List> resultRegular = (List>) gReg.V(1).properties("location").hasValue("san diego").properties().toList(); + Object[] resultShuffle = gShuff.V(1).properties("location").hasValue("san diego").properties().toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + @Test + public void shouldShuffleMultiProperties() { + GraphTraversalSource gShuff = createShuffleTheCrew(); + GraphTraversalSource gReg = TinkerFactory.createTheCrew().traversal(); + + List> resultRegular = (List>) gReg.V(1).properties("location").toList(); + Object[] resultShuffle = gShuff.V(1).properties("location").toList().toArray(); + + //Assert contents are correct + assertThat(resultRegular, containsInAnyOrder(resultShuffle)); + //Assert order is shuffled + assertThat(resultRegular, not(contains(resultShuffle))); + } + + private GraphTraversalSource createShuffleModern() { + TinkerShuffleGraph graph = TinkerShuffleGraph.open(); + TinkerFactory.generateModern(graph); + return traversal().withEmbedded(graph); + } + + private GraphTraversalSource createShuffleTheCrew() { + TinkerShuffleGraph graph = TinkerShuffleGraph.open(); + TinkerFactory.generateTheCrew(graph); + return traversal().withEmbedded(graph); + } + + private class RetryRule implements TestRule { + final int maxRetries = 50; + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + for(int i = 1; i <= maxRetries; i++) { + try{ + base.evaluate(); + return; + } + catch(AssertionError e){ + String msg = String.format("Failed test %s.%s (attempt %s/%s): ", description.getClassName(), description.getMethodName(), i, maxRetries); + if(i == maxRetries) { + logger.warn(msg, e); + } else { + logger.debug(msg, e); + } + } + } + } + }; + } + } + +} diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleVertex.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleVertex.java new file mode 100644 index 00000000000..b7ab5b6ef99 --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleVertex.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tinkerpop.gremlin.tinkergraph.structure; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; + +import java.util.Iterator; + +import static org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerShuffleGraph.shuffleIterator; + +/** + * @author Cole Greer (https://github.com/Cole-Greer) + */ +public final class TinkerShuffleVertex extends TinkerVertex { + protected TinkerShuffleVertex(final Object id, final String label, final AbstractTinkerGraph graph) { + super(id, label, graph); + } + + protected TinkerShuffleVertex(final Object id, final String label, final AbstractTinkerGraph graph, final long currentVersion) { + super(id, label, graph, currentVersion); + } + + @Override + public Iterator edges(final Direction direction, final String... edgeLabels) { + return shuffleIterator(super.edges(direction, edgeLabels)); + } + + @Override + public Iterator vertices(final Direction direction, final String... edgeLabels) { + return shuffleIterator(super.vertices(direction, edgeLabels)); + } + + @Override + public Iterator> properties(final String... propertyKeys) { + return shuffleIterator(super.properties(propertyKeys)); + } + + @Override + protected TinkerVertexProperty createTinkerVertexProperty(final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) { + return new TinkerShuffleVertexProperty(vertex, key, value, propertyKeyValues); + } + + @Override + protected TinkerVertexProperty createTinkerVertexProperty(final Object id, final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) { + return new TinkerShuffleVertexProperty(id, vertex, key, value, propertyKeyValues); + } +} diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleVertexProperty.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleVertexProperty.java new file mode 100644 index 00000000000..6c6128ec836 --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerShuffleVertexProperty.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tinkerpop.gremlin.tinkergraph.structure; + +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Property; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; +import org.apache.tinkerpop.gremlin.tinkergraph.process.computer.TinkerGraphComputerView; +import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; + +import java.util.Collections; +import java.util.Iterator; +import java.util.stream.Collectors; + +import static org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerShuffleGraph.shuffleIterator; + +/** + * @author Cole Greer (https://github.com/Cole-Greer) + */ +public class TinkerShuffleVertexProperty extends TinkerVertexProperty { + + + /** + * This constructor will not validate the ID type against the {@link Graph}. It will always just use a + * {@code Long} for its identifier. This is useful for constructing a {@link VertexProperty} for usage + * with {@link TinkerGraphComputerView}. + */ + public TinkerShuffleVertexProperty(final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) { + super(vertex, key, value, propertyKeyValues); + } + + /** + * Use this constructor to construct {@link VertexProperty} instances for {@link TinkerGraph} where the {@code id} + * can be explicitly set and validated against the expected data type. + */ + public TinkerShuffleVertexProperty(final Object id, final TinkerVertex vertex, final String key, final V value, final Object... propertyKeyValues) { + super(id, vertex, key, value, propertyKeyValues); + } + + @Override + public Iterator> properties(final String... propertyKeys) { + return shuffleIterator(super.properties(propertyKeys)); + } +} diff --git a/tinkergraph-gremlin/src/test/resources/META-INF/services/io.cucumber.core.backend.ObjectFactory b/tinkergraph-gremlin/src/test/resources/META-INF/services/io.cucumber.core.backend.ObjectFactory index 9eb15f9a66a..1e9b622ffb9 100644 --- a/tinkergraph-gremlin/src/test/resources/META-INF/services/io.cucumber.core.backend.ObjectFactory +++ b/tinkergraph-gremlin/src/test/resources/META-INF/services/io.cucumber.core.backend.ObjectFactory @@ -3,4 +3,5 @@ org.apache.tinkerpop.gremlin.tinkergraph.TinkerGraphComputerFeatureTest$TinkerGr org.apache.tinkerpop.gremlin.tinkergraph.TinkerGraphAllowNullFeatureTest$TinkerGraphGuiceFactory org.apache.tinkerpop.gremlin.tinkergraph.TinkerTransactionGraphFeatureTest$TinkerGraphGuiceFactory org.apache.tinkerpop.gremlin.tinkergraph.TinkerTransactionGraphComputerFeatureTest$TinkerGraphGuiceFactory -org.apache.tinkerpop.gremlin.tinkergraph.TinkerTransactionGraphAllowNullFeatureTest$TinkerGraphGuiceFactory \ No newline at end of file +org.apache.tinkerpop.gremlin.tinkergraph.TinkerTransactionGraphAllowNullFeatureTest$TinkerGraphGuiceFactory +org.apache.tinkerpop.gremlin.tinkergraph.TinkerShuffleGraphFeatureTest$TinkerShuffleGraphGuiceFactory