This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit d0d32fa00dfe7430d806e313f6e00155c02de3c4 Merge: e8de6e9 1f7e0e1 Author: Stephen Mallette <sp...@genoprime.com> AuthorDate: Tue Jun 25 15:29:13 2019 -0400 Merge branch 'tp33' into tp34 .../dev/developer/development-environment.asciidoc | 1 + docs/src/dev/provider/index.asciidoc | 8 +- .../traversal/step/sideEffect/SubgraphStep.java | 17 +- .../structure/io/graphml/GraphMLWriter.java | 179 +++++++++++---------- .../tinkerpop/gremlin/AbstractGremlinTest.java | 8 +- .../tinkerpop/gremlin/IgnoreIteratorLeak.java | 41 ----- .../algorithm/generator/AbstractGeneratorTest.java | 21 ++- .../generator/CommunityGeneratorTest.java | 3 - .../generator/DistributionGeneratorTest.java | 5 +- .../process/computer/GraphComputerTest.java | 9 +- .../bulkloading/BulkLoaderVertexProgramTest.java | 9 +- .../traversal/TraversalInterruptionTest.java | 2 - .../traversal/step/sideEffect/SubgraphTest.java | 2 - .../decoration/SubgraphStrategyProcessTest.java | 4 +- .../tinkerpop/gremlin/structure/io/IoTest.java | 3 - .../tinkergraph/structure/TinkerGraphIterator.java | 12 +- 16 files changed, 153 insertions(+), 171 deletions(-) diff --cc docs/src/dev/provider/index.asciidoc index 162e907,1185d0c..54e5f98 --- a/docs/src/dev/provider/index.asciidoc +++ b/docs/src/dev/provider/index.asciidoc @@@ -773,12 -813,15 +774,15 @@@ the query is finished TinkerPop provides you with the ability to test for such resource leaks by checking for leaks when you run the Gremlin-Test suites against your implementation. To enable this leak detection, providers should increment the - `StoreIteratorCounter` whenever a reource is opened and decrement it when it is closed. A reference implementation + `StoreIteratorCounter` whenever a resource is opened and decrement it when it is closed. A reference implementation is provided with TinkerGraph as `TinkerGraphIterator.java`. + Assertions for leak detection are enabled by default when running the test suite. They can be temporarily disabled + by way of a system property - simply set `-DtestIteratorLeaks=false". + === Accessibility via GremlinPlugin -image:gremlin-plugin.png[width=100,float=left] The applications distributed with TinkerPop3 do not distribute with +image:gremlin-plugin.png[width=100,float=left] The applications distributed with TinkerPop do not distribute with any graph system implementations besides TinkerGraph. If your implementation is stored in a Maven repository (e.g. Maven Central Repository), then it is best to provide a <<gremlin-plugins,`GremlinPlugin`>> implementation so the respective jars can be downloaded according and when required by the user. Neo4j's GremlinPlugin is provided below for reference. diff --cc gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java index 59812f0,6d31cc8..8f0d1e0 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java @@@ -214,24 -213,16 +215,24 @@@ public final class GraphMLWriter implem return writer; } else return utf8Writer; - } + } private void writeTypes(final Map<String, String> identifiedVertexKeyTypes, - final Map<String, String> identifiedEdgeKeyTypes, - final XMLStreamWriter writer) throws XMLStreamException { + final Map<String, String> identifiedEdgeKeyTypes, + final XMLStreamWriter writer) throws XMLStreamException { // <key id="weight" for="edge" attr.name="weight" attr.type="float"/> - final Collection<String> vertexKeySet = getVertexKeysAndNormalizeIfRequired(identifiedVertexKeyTypes); - final Collection<String> edgeKeySet = getEdgeKeysAndNormalizeIfRequired(identifiedEdgeKeyTypes); + final Collection<String> vertexKeySet = getKeysAndNormalizeIfRequired(identifiedVertexKeyTypes); ++ final Collection<String> edgeKeySet = getKeysAndNormalizeIfRequired(identifiedEdgeKeyTypes); + // in case vertex and edge may have the same attribute name, the key id in graphml have to be different + intersection = CollectionUtils.intersection(vertexKeySet, edgeKeySet); + for (String key : vertexKeySet) { writer.writeStartElement(GraphMLTokens.KEY); - writer.writeAttribute(GraphMLTokens.ID, key); + if (intersection.contains(key)) { + writer.writeAttribute(GraphMLTokens.ID, key.concat(GraphMLTokens.VERTEX_SUFFIX)); + } else { + writer.writeAttribute(GraphMLTokens.ID, key); + } writer.writeAttribute(GraphMLTokens.FOR, GraphMLTokens.NODE); writer.writeAttribute(GraphMLTokens.ATTR_NAME, key); writer.writeAttribute(GraphMLTokens.ATTR_TYPE, identifiedVertexKeyTypes.get(key)); @@@ -252,66 -241,62 +253,70 @@@ } private void writeEdges(final XMLStreamWriter writer, final Graph graph) throws XMLStreamException { - if (normalize) { - final List<Edge> edges = IteratorUtils.list(graph.edges()); - Collections.sort(edges, Comparators.ELEMENT_COMPARATOR); - - for (Edge edge : edges) { - writer.writeStartElement(GraphMLTokens.EDGE); - writer.writeAttribute(GraphMLTokens.ID, edge.id().toString()); - writer.writeAttribute(GraphMLTokens.SOURCE, edge.outVertex().id().toString()); - writer.writeAttribute(GraphMLTokens.TARGET, edge.inVertex().id().toString()); - - writer.writeStartElement(GraphMLTokens.DATA); - writer.writeAttribute(GraphMLTokens.KEY, this.edgeLabelKey); - writer.writeCharacters(edge.label()); - writer.writeEndElement(); + final Iterator<Edge> iterator = graph.edges(); + try { + if (normalize) { + final List<Edge> edges = IteratorUtils.list(iterator); + Collections.sort(edges, Comparators.ELEMENT_COMPARATOR); - final List<String> keys = new ArrayList<>(edge.keys()); - Collections.sort(keys); + for (Edge edge : edges) { + writer.writeStartElement(GraphMLTokens.EDGE); + writer.writeAttribute(GraphMLTokens.ID, edge.id().toString()); + writer.writeAttribute(GraphMLTokens.SOURCE, edge.outVertex().id().toString()); + writer.writeAttribute(GraphMLTokens.TARGET, edge.inVertex().id().toString()); - for (String key : keys) { writer.writeStartElement(GraphMLTokens.DATA); - if (intersection != null && intersection.contains(key)) { - writer.writeAttribute(GraphMLTokens.KEY, key + GraphMLTokens.EDGE_SUFFIX); - } else { - writer.writeAttribute(GraphMLTokens.KEY, key); + writer.writeAttribute(GraphMLTokens.KEY, this.edgeLabelKey); + writer.writeCharacters(edge.label()); + writer.writeEndElement(); + + final List<String> keys = new ArrayList<>(edge.keys()); + Collections.sort(keys); + + for (String key : keys) { + writer.writeStartElement(GraphMLTokens.DATA); - writer.writeAttribute(GraphMLTokens.KEY, key); ++ if (intersection != null && intersection.contains(key)) { ++ writer.writeAttribute(GraphMLTokens.KEY, key + GraphMLTokens.EDGE_SUFFIX); ++ } else { ++ writer.writeAttribute(GraphMLTokens.KEY, key); ++ } + // technically there can't be a null here as gremlin structure forbids that occurrence even if Graph + // implementations support it, but out to empty string just in case. + writer.writeCharacters(edge.property(key).orElse("").toString()); + writer.writeEndElement(); } - // technically there can't be a null here as gremlin structure forbids that occurrence even if Graph - // implementations support it, but out to empty string just in case. - writer.writeCharacters(edge.property(key).orElse("").toString()); writer.writeEndElement(); } - writer.writeEndElement(); - } - } else { - final Iterator<Edge> iterator = graph.edges(); - while (iterator.hasNext()) { - final Edge edge = iterator.next(); - writer.writeStartElement(GraphMLTokens.EDGE); - writer.writeAttribute(GraphMLTokens.ID, edge.id().toString()); - writer.writeAttribute(GraphMLTokens.SOURCE, edge.outVertex().id().toString()); - writer.writeAttribute(GraphMLTokens.TARGET, edge.inVertex().id().toString()); - - writer.writeStartElement(GraphMLTokens.DATA); - writer.writeAttribute(GraphMLTokens.KEY, this.edgeLabelKey); - writer.writeCharacters(edge.label()); - writer.writeEndElement(); + } else { + while (iterator.hasNext()) { + final Edge edge = iterator.next(); + writer.writeStartElement(GraphMLTokens.EDGE); + writer.writeAttribute(GraphMLTokens.ID, edge.id().toString()); + writer.writeAttribute(GraphMLTokens.SOURCE, edge.outVertex().id().toString()); + writer.writeAttribute(GraphMLTokens.TARGET, edge.inVertex().id().toString()); - for (String key : edge.keys()) { writer.writeStartElement(GraphMLTokens.DATA); - if (intersection != null && intersection.contains(key)) { - writer.writeAttribute(GraphMLTokens.KEY, key + GraphMLTokens.EDGE_SUFFIX); - } else { - writer.writeAttribute(GraphMLTokens.KEY, key); + writer.writeAttribute(GraphMLTokens.KEY, this.edgeLabelKey); + writer.writeCharacters(edge.label()); + writer.writeEndElement(); + + for (String key : edge.keys()) { + writer.writeStartElement(GraphMLTokens.DATA); - writer.writeAttribute(GraphMLTokens.KEY, key); ++ if (intersection != null && intersection.contains(key)) { ++ writer.writeAttribute(GraphMLTokens.KEY, key + GraphMLTokens.EDGE_SUFFIX); ++ } else { ++ writer.writeAttribute(GraphMLTokens.KEY, key); ++ } + // technically there can't be a null here as gremlin structure forbids that occurrence even if Graph + // implementations support it, but out to empty string just in case. + writer.writeCharacters(edge.property(key).orElse("").toString()); + writer.writeEndElement(); } - // technically there can't be a null here as gremlin structure forbids that occurrence even if Graph - // implementations support it, but out to empty string just in case. - writer.writeCharacters(edge.property(key).orElse("").toString()); writer.writeEndElement(); } - writer.writeEndElement(); } + } finally { + CloseableIterator.closeIterator(iterator); } } diff --cc gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java index c2650c4,95cfbb4..933be7c --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java @@@ -31,7 -31,7 +31,6 @@@ import org.apache.tinkerpop.gremlin.str import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; import org.apache.tinkerpop.gremlin.util.iterator.StoreIteratorCounter; import org.junit.After; --import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestName; @@@ -79,18 -76,8 +77,16 @@@ public abstract class AbstractGremlinTe final LoadGraphWith[] loadGraphWiths = testMethod.getAnnotationsByType(LoadGraphWith.class); final LoadGraphWith loadGraphWith = loadGraphWiths.length == 0 ? null : loadGraphWiths[0]; final LoadGraphWith.GraphData loadGraphWithData = null == loadGraphWith ? null : loadGraphWith.value(); + final Set<FeatureRequirement> featureRequirementSet = getFeatureRequirementsForTest(testMethod, loadGraphWiths); - this.shouldTestIteratorLeak = !this.getClass().isAnnotationPresent(IgnoreIteratorLeak.class); - graphProvider = GraphManager.getGraphProvider(); + + // pre-check if available from graph provider to avoid graph creation + final Optional<Graph.Features> staticFeatures = graphProvider.getStaticFeatures(); + if (staticFeatures.isPresent()) { + assumeRequirementsAreMetForTest(featureRequirementSet, staticFeatures.get(), true); + } + graphProvider.getTestListener().ifPresent(l -> l.onTestStart(this.getClass(), name.getMethodName())); // Reset the counter for open iterators by this test diff --cc gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java index 89e7b4e,9152655..cf1c790 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java @@@ -20,10 -20,9 +20,9 @@@ package org.apache.tinkerpop.gremlin.pr import org.apache.commons.configuration.MapConfiguration; import org.apache.tinkerpop.gremlin.LoadGraphWith; - import org.apache.tinkerpop.gremlin.IgnoreIteratorLeak; import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest; import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner; -import org.apache.tinkerpop.gremlin.process.remote.RemoteGraph; +import org.apache.tinkerpop.gremlin.structure.RemoteGraph; import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; diff --cc gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java index 796de31,64bc361..af73ada --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoTest.java @@@ -21,7 -21,7 +21,6 @@@ package org.apache.tinkerpop.gremlin.st import org.apache.commons.configuration.Configuration; import org.apache.tinkerpop.gremlin.AbstractGremlinTest; import org.apache.tinkerpop.gremlin.FeatureRequirement; --import org.apache.tinkerpop.gremlin.IgnoreIteratorLeak; import org.apache.tinkerpop.gremlin.LoadGraphWith; import org.apache.tinkerpop.gremlin.TestHelper; import org.apache.tinkerpop.gremlin.structure.Direction; @@@ -110,90 -110,7 +109,88 @@@ import static org.junit.Assume.assumeTh public class IoTest { private static final Logger logger = LoggerFactory.getLogger(IoTest.class); + private static final String CLASSIC_GRAPH_WITH_COLOR = "<?xml version=\"1.0\" ?>\n" + + "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.1/graphml.xsd\">\n" + + " <key id=\"age\" for=\"node\" attr.name=\"age\" attr.type=\"int\"></key>\n" + + " <key id=\"colorV\" for=\"node\" attr.name=\"color\" attr.type=\"string\"></key>\n" + + " <key id=\"labelV\" for=\"node\" attr.name=\"labelV\" attr.type=\"string\"></key>\n" + + " <key id=\"lang\" for=\"node\" attr.name=\"lang\" attr.type=\"string\"></key>\n" + + " <key id=\"name\" for=\"node\" attr.name=\"name\" attr.type=\"string\"></key>\n" + + " <key id=\"colorE\" for=\"edge\" attr.name=\"color\" attr.type=\"string\"></key>\n" + + " <key id=\"labelE\" for=\"edge\" attr.name=\"labelE\" attr.type=\"string\"></key>\n" + + " <key id=\"weight\" for=\"edge\" attr.name=\"weight\" attr.type=\"float\"></key>\n" + + " <graph id=\"G\" edgedefault=\"directed\">\n" + + " <node id=\"1\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">29</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">marko</data>\n" + + " </node>\n" + + " <node id=\"2\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">27</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">vadas</data>\n" + + " </node>\n" + + " <node id=\"3\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"lang\">java</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">lop</data>\n" + + " </node>\n" + + " <node id=\"4\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">32</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">josh</data>\n" + + " </node>\n" + + " <node id=\"5\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"lang\">java</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">ripple</data>\n" + + " </node>\n" + + " <node id=\"6\">\n" + + " <data key=\"labelV\">vertex</data>\n" + + " <data key=\"age\">35</data>\n" + + " <data key=\"colorV\">#6495ed</data>\n" + + " <data key=\"name\">peter</data>\n" + + " </node>\n" + + " <edge id=\"10\" source=\"4\" target=\"5\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">1.0</data>\n" + + " </edge>\n" + + " <edge id=\"11\" source=\"4\" target=\"3\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.4</data>\n" + + " </edge>\n" + + " <edge id=\"12\" source=\"6\" target=\"3\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.2</data>\n" + + " </edge>\n" + + " <edge id=\"7\" source=\"1\" target=\"2\">\n" + + " <data key=\"labelE\">knows</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.5</data>\n" + + " </edge>\n" + + " <edge id=\"8\" source=\"1\" target=\"4\">\n" + + " <data key=\"labelE\">knows</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">1.0</data>\n" + + " </edge>\n" + + " <edge id=\"9\" source=\"1\" target=\"3\">\n" + + " <data key=\"labelE\">created</data>\n" + + " <data key=\"colorE\">#ee0000</data>\n" + + " <data key=\"weight\">0.4</data>\n" + + " </edge>\n" + + " </graph>\n" + + "</graphml>"; + - @IgnoreIteratorLeak public static class GraphMLTest extends AbstractGremlinTest { + @Test @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES) @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)