You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/06/12 20:16:52 UTC

[3/3] incubator-tinkerpop git commit: Restructure the IoTest into smaller test groups.

Restructure the IoTest into smaller test groups.

Improved coverage in the process by parameterizing tests.  Should be easier now to add additional tests for IO as gaps are found.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/3ca54a62
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/3ca54a62
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/3ca54a62

Branch: refs/heads/master
Commit: 3ca54a629f27b38ddda1140cd1d12d4620e700c5
Parents: 89d0ac5
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Jun 12 14:15:44 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Jun 12 14:15:44 2015 -0400

----------------------------------------------------------------------
 .../tinkerpop/gremlin/structure/GraphTest.java  |    3 +-
 .../structure/StructureStandardSuite.java       |   10 +
 .../tinkerpop/gremlin/structure/VertexTest.java |    3 +-
 .../gremlin/structure/io/IoCustomTest.java      |  143 ++
 .../gremlin/structure/io/IoEdgeTest.java        |  149 ++
 .../gremlin/structure/io/IoGraphTest.java       |  226 ++
 .../gremlin/structure/io/IoPropertyTest.java    |  150 ++
 .../tinkerpop/gremlin/structure/io/IoTest.java  | 2048 ++----------------
 .../gremlin/structure/io/IoVertexTest.java      |  485 +++++
 .../gremlin/structure/io/util/CustomId.java     |   92 +
 .../tinkergraph/TinkerGraphProvider.java        |   30 +-
 11 files changed, 1476 insertions(+), 1863 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3ca54a62/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
index ea5b9a3..b65ca4d 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/GraphTest.java
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
 import org.apache.tinkerpop.gremlin.GraphManager;
 import org.apache.tinkerpop.gremlin.GraphProvider;
 import org.apache.tinkerpop.gremlin.structure.io.IoTest;
+import org.apache.tinkerpop.gremlin.structure.io.util.CustomId;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.Test;
 
@@ -199,7 +200,7 @@ public class GraphTest extends AbstractGremlinTest {
 
         // this is different from "FEATURE_CUSTOM_IDS" as TinkerGraph does not define a specific id class
         // (i.e. TinkerId) for the identifier.
-        final IoTest.CustomId customId = new IoTest.CustomId("test", uuid);
+        final CustomId customId = new CustomId("test", uuid);
         graph.addVertex(T.id, customId);
         graph.addVertex();
         tryCommit(graph, graph -> {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3ca54a62/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/StructureStandardSuite.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/StructureStandardSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/StructureStandardSuite.java
index 2f452a0..b2e3494 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/StructureStandardSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/StructureStandardSuite.java
@@ -23,7 +23,12 @@ import org.apache.tinkerpop.gremlin.GraphProvider;
 import org.apache.tinkerpop.gremlin.algorithm.generator.CommunityGeneratorTest;
 import org.apache.tinkerpop.gremlin.algorithm.generator.DistributionGeneratorTest;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
+import org.apache.tinkerpop.gremlin.structure.io.IoCustomTest;
+import org.apache.tinkerpop.gremlin.structure.io.IoEdgeTest;
+import org.apache.tinkerpop.gremlin.structure.io.IoGraphTest;
 import org.apache.tinkerpop.gremlin.structure.io.IoTest;
+import org.apache.tinkerpop.gremlin.structure.io.IoPropertyTest;
+import org.apache.tinkerpop.gremlin.structure.io.IoVertexTest;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdgeTest;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedGraphTest;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedPropertyTest;
@@ -81,6 +86,11 @@ public class StructureStandardSuite extends AbstractGremlinSuite {
             DistributionGeneratorTest.class,
             EdgeTest.class,
             FeatureSupportTest.class,
+            IoCustomTest.class,
+            IoEdgeTest.class,
+            IoGraphTest.class,
+            IoVertexTest.class,
+            IoPropertyTest.class,
             GraphTest.class,
             GraphConstructionTest.class,
             IoTest.class,

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3ca54a62/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
index 6e7b02b..a958b07 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexTest.java
@@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.GraphManager;
 import org.apache.tinkerpop.gremlin.structure.Graph.Features.VertexFeatures;
 import org.apache.tinkerpop.gremlin.structure.Graph.Features.VertexPropertyFeatures;
 import org.apache.tinkerpop.gremlin.structure.io.IoTest;
+import org.apache.tinkerpop.gremlin.structure.io.util.CustomId;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.function.FunctionUtils;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
@@ -137,7 +138,7 @@ public class VertexTest {
 
             // this is different from "FEATURE_CUSTOM_IDS" as TinkerGraph does not define a specific id class
             // (i.e. TinkerId) for the identifier.
-            final IoTest.CustomId customId = new IoTest.CustomId("test", uuid);
+            final CustomId customId = new CustomId("test", uuid);
             final Vertex v = graph.addVertex();
             v.addEdge("self", v, T.id, customId);
             tryCommit(graph, graph -> {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3ca54a62/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java
new file mode 100644
index 0000000..5f9bc3b
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoCustomTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.structure.io;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.apache.commons.configuration.Configuration;
+import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
+import org.apache.tinkerpop.gremlin.FeatureRequirement;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.io.util.CustomId;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.ElementFeatures.FEATURE_ANY_IDS;
+import static org.apache.tinkerpop.gremlin.structure.Graph.Features.ElementFeatures.FEATURE_USER_SUPPLIED_IDS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(Parameterized.class)
+public class IoCustomTest extends AbstractGremlinTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        final SimpleModule module = new SimpleModule();
+        module.addSerializer(CustomId.class, new CustomId.CustomIdJacksonSerializer());
+
+        return Arrays.asList(new Object[][]{
+                {"graphson-embedded", true,
+                        (Function<Graph, GraphReader>) g -> g.io(IoCore.graphson()).reader().mapper(g.io(IoCore.graphson()).mapper().addCustomModule(module).embedTypes(true).create()).create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.graphson()).writer().mapper(g.io(IoCore.graphson()).mapper().addCustomModule(module).embedTypes(true).create()).create()},
+                {"gryo", true,
+                        (Function<Graph, GraphReader>) g -> g.io(IoCore.gryo()).reader().mapper(g.io(IoCore.gryo()).mapper().addCustom(CustomId.class).create()).create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.gryo()).writer().mapper(g.io(IoCore.gryo()).mapper().addCustom(CustomId.class).create()).create()}
+        });
+    }
+
+    @Parameterized.Parameter(value = 0)
+    public String ioType;
+
+    @Parameterized.Parameter(value = 1)
+    public boolean assertIdDirectly;
+
+    @Parameterized.Parameter(value = 2)
+    public Function<Graph, GraphReader> readerMaker;
+
+    @Parameterized.Parameter(value = 3)
+    public Function<Graph, GraphWriter> writerMaker;
+
+
+    @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)
+    @FeatureRequirement(featureClass = Graph.Features.EdgePropertyFeatures.class, feature = Graph.Features.EdgePropertyFeatures.FEATURE_SERIALIZABLE_VALUES)
+    public void shouldSupportUUID() throws Exception {
+        final UUID id = UUID.randomUUID();
+        final Vertex v1 = graph.addVertex(T.label, "person");
+        final Vertex v2 = graph.addVertex(T.label, "person");
+        final Edge e = v1.addEdge("friend", v2, "uuid", id);
+
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            final GraphWriter writer = writerMaker.apply(graph);
+            writer.writeEdge(os, e);
+
+            final AtomicBoolean called = new AtomicBoolean(false);
+            final GraphReader reader = readerMaker.apply(graph);
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readEdge(bais, edge -> {
+                    final Edge detachedEdge = (Edge) edge;
+                    assertEquals(e.id(), assertIdDirectly ? detachedEdge.id() : graph.edges(detachedEdge.id().toString()).next().id());
+                    assertEquals(v1.id(), assertIdDirectly ? detachedEdge.outVertex().id() : graph.vertices(detachedEdge.outVertex().id().toString()).next().id());
+                    assertEquals(v2.id(), assertIdDirectly ? detachedEdge.inVertex().id() : graph.vertices(detachedEdge.inVertex().id().toString()).next().id());
+                    assertEquals(v1.label(), detachedEdge.outVertex().label());
+                    assertEquals(v2.label(), detachedEdge.inVertex().label());
+                    assertEquals(e.label(), detachedEdge.label());
+                    assertEquals(e.keys().size(), IteratorUtils.count(detachedEdge.properties()));
+                    assertEquals(id, detachedEdge.value("uuid"));
+
+                    called.set(true);
+
+                    return null;
+                });
+            }
+
+            assertTrue(called.get());
+        }
+    }
+
+    @Test
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS)
+    @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = FEATURE_ANY_IDS)
+    public void shouldProperlySerializeCustomId() throws Exception {
+        graph.addVertex(T.id, new CustomId("vertex", UUID.fromString("AF4B5965-B176-4552-B3C1-FBBE2F52C305")));
+
+        final GraphWriter writer = writerMaker.apply(graph);
+        final GraphReader reader = readerMaker.apply(graph);
+
+        final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), null);
+        graphProvider.clear(configuration);
+        final Graph g1 = graphProvider.openTestGraph(configuration);
+
+        GraphMigrator.migrateGraph(graph, g1, reader, writer);
+
+        final Vertex onlyVertex = g1.traversal().V().next();
+        final CustomId id = (CustomId) onlyVertex.id();
+        assertEquals("vertex", id.getCluster());
+        assertEquals(UUID.fromString("AF4B5965-B176-4552-B3C1-FBBE2F52C305"), id.getElementId());
+
+        // need to manually close the "g1" instance
+        graphProvider.clear(g1, configuration);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3ca54a62/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoEdgeTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoEdgeTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoEdgeTest.java
new file mode 100644
index 0000000..e8db127
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoEdgeTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.structure.io;
+
+import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
+import org.apache.tinkerpop.gremlin.FeatureRequirement;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for all IO implementations that are specific to reading and writing of a {@link Edge}.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(Parameterized.class)
+public class IoEdgeTest extends AbstractGremlinTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {"graphson", false, false,
+                        (Function<Graph,GraphReader>) g -> g.io(IoCore.graphson()).reader().create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.graphson()).writer().create()},
+                {"graphson-embedded", true, true,
+                        (Function<Graph,GraphReader>) g -> g.io(IoCore.graphson()).reader().mapper(g.io(IoCore.graphson()).mapper().embedTypes(true).create()).create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.graphson()).writer().mapper(g.io(IoCore.graphson()).mapper().embedTypes(true).create()).create()},
+                {"gryo", true, true,
+                        (Function<Graph,GraphReader>) g -> g.io(IoCore.gryo()).reader().create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.gryo()).writer().create()}
+        });
+    }
+
+    @Parameterized.Parameter(value = 0)
+    public String ioType;
+
+    @Parameterized.Parameter(value = 1)
+    public boolean assertIdDirectly;
+
+    @Parameterized.Parameter(value = 2)
+    public boolean assertDouble;
+
+    @Parameterized.Parameter(value = 3)
+    public Function<Graph, GraphReader> readerMaker;
+
+    @Parameterized.Parameter(value = 4)
+    public Function<Graph, GraphWriter> writerMaker;
+
+    @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)
+    @FeatureRequirement(featureClass = Graph.Features.EdgePropertyFeatures.class, feature = Graph.Features.EdgePropertyFeatures.FEATURE_DOUBLE_VALUES)
+    public void shouldReadWriteEdge() throws Exception {
+        final Vertex v1 = graph.addVertex(T.label, "person");
+        final Vertex v2 = graph.addVertex(T.label, "person");
+        final Edge e = v1.addEdge("friend", v2, "weight", 0.5d, "acl", "rw");
+
+        assertEdge(v1, v2, e, true);
+    }
+
+    @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)
+    @FeatureRequirement(featureClass = Graph.Features.EdgePropertyFeatures.class, feature = Graph.Features.EdgePropertyFeatures.FEATURE_DOUBLE_VALUES)
+    public void shouldReadWriteDetachedEdge() throws Exception {
+        final Vertex v1 = graph.addVertex(T.label, "person");
+        final Vertex v2 = graph.addVertex(T.label, "person");
+        final Edge e = DetachedFactory.detach(v1.addEdge("friend", v2, "weight", 0.5d, "acl", "rw"), true);
+
+        assertEdge(v1, v2, e, true);
+    }
+
+    @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)
+    @FeatureRequirement(featureClass = Graph.Features.EdgePropertyFeatures.class, feature = Graph.Features.EdgePropertyFeatures.FEATURE_DOUBLE_VALUES)
+    public void shouldReadWriteDetachedEdgeAsReference() throws Exception {
+        final Vertex v1 = graph.addVertex(T.label, "person");
+        final Vertex v2 = graph.addVertex(T.label, "person");
+        final Edge e = DetachedFactory.detach(v1.addEdge("friend", v2, "weight", 0.5d, "acl", "rw"), false);
+
+        assertEdge(v1, v2, e, false);
+    }
+
+    private void assertEdge(final Vertex v1, final Vertex v2, final Edge e, final boolean assertProperties) throws IOException {
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            final GraphWriter writer = writerMaker.apply(graph);
+            writer.writeEdge(os, e);
+
+            final AtomicBoolean called = new AtomicBoolean(false);
+            final GraphReader reader = readerMaker.apply(graph);
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readEdge(bais, edge -> {
+                    final Edge detachedEdge = (Edge) edge;
+                    assertEquals(e.id(), assertIdDirectly ? detachedEdge.id() : graph.edges(detachedEdge.id().toString()).next().id());
+                    assertEquals(v1.id(), assertIdDirectly ? detachedEdge.outVertex().id() : graph.vertices(detachedEdge.outVertex().id().toString()).next().id());
+                    assertEquals(v2.id(), assertIdDirectly ? detachedEdge.inVertex().id() : graph.vertices(detachedEdge.inVertex().id().toString()).next().id());
+                    assertEquals(v1.label(), detachedEdge.outVertex().label());
+                    assertEquals(v2.label(), detachedEdge.inVertex().label());
+                    assertEquals(e.label(), detachedEdge.label());
+
+                    if (assertProperties) {
+                        assertEquals(assertDouble ? 0.5d : 0.5f, e.properties("weight").next().value());
+                        assertEquals("rw", e.properties("acl").next().value());
+                    } else {
+                        assertEquals(e.keys().size(), IteratorUtils.count(detachedEdge.properties()));
+                    }
+
+                    called.set(true);
+                    return null;
+                });
+            }
+
+            assertTrue(called.get());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3ca54a62/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java
new file mode 100644
index 0000000..bc1296a
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoGraphTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.structure.io;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
+import org.apache.tinkerpop.gremlin.FeatureRequirement;
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.TestHelper;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.Arrays;
+
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assume.assumeThat;
+
+/**
+ * Tests for all IO implementations that are specific to reading and writing of a {@link Graph}.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(Parameterized.class)
+public class IoGraphTest extends AbstractGremlinTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {"graphml", IoCore.graphml(), false, true, ".xml"},
+                {"graphson", IoCore.graphson(), true, true, ".json"},
+                {"gryo", IoCore.gryo(), false, false, ".kryo"}
+        });
+    }
+
+    @Parameterized.Parameter(value = 0)
+    public String ioType;
+
+    @Parameterized.Parameter(value = 1)
+    public Io.Builder ioBuilderToTest;
+
+    @Parameterized.Parameter(value = 2)
+    public boolean assertDouble;
+
+    @Parameterized.Parameter(value = 3)
+    public boolean lossyForId;
+
+    @Parameterized.Parameter(value = 4)
+    public String fileExtension;
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.CLASSIC)
+    @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)
+    public void shouldReadWriteClassic() throws Exception {
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            final GraphWriter writer = graph.io(ioBuilderToTest).writer().create();
+            writer.writeGraph(os, graph);
+
+            final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), LoadGraphWith.GraphData.CLASSIC);
+            graphProvider.clear(configuration);
+            final Graph g1 = graphProvider.openTestGraph(configuration);
+            final GraphReader reader = graph.io(ioBuilderToTest).reader().create();
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readGraph(bais, g1);
+            }
+
+            IoTest.assertClassicGraph(g1, assertDouble, lossyForId);
+
+            graphProvider.clear(g1, configuration);
+        }
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.CLASSIC)
+    @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)
+    public void shouldReadWriteClassicToFileWithHelpers() throws Exception {
+        final File f = TestHelper.generateTempFile(this.getClass(), name.getMethodName(), fileExtension);
+        try {
+            graph.io(ioBuilderToTest).writeGraph(f.getAbsolutePath());
+
+            final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), LoadGraphWith.GraphData.MODERN);
+            final Graph g1 = graphProvider.openTestGraph(configuration);
+            g1.io(ioBuilderToTest).readGraph(f.getAbsolutePath());
+
+            IoTest.assertClassicGraph(g1, assertDouble, lossyForId);
+
+            graphProvider.clear(g1, configuration);
+        } catch (Exception ex) {
+            f.delete();
+            throw ex;
+        }
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.CLASSIC)
+    @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)
+    public void shouldMigrateClassicGraph() throws Exception {
+        final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), null);
+        graphProvider.clear(configuration);
+        final Graph g1 = graphProvider.openTestGraph(configuration);
+
+        final GraphReader reader = graph.io(ioBuilderToTest).reader().create();
+        final GraphWriter writer = graph.io(ioBuilderToTest).writer().create();
+
+        GraphMigrator.migrateGraph(graph, g1, reader, writer);
+
+        IoTest.assertClassicGraph(g1, assertDouble, lossyForId);
+
+        graphProvider.clear(g1, configuration);
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+    @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)
+    public void shouldReadWriteModern() throws Exception {
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            final GraphWriter writer = graph.io(ioBuilderToTest).writer().create();
+            writer.writeGraph(os, graph);
+
+            final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), LoadGraphWith.GraphData.MODERN);
+            graphProvider.clear(configuration);
+            final Graph g1 = graphProvider.openTestGraph(configuration);
+            final GraphReader reader = graph.io(ioBuilderToTest).reader().create();
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readGraph(bais, g1);
+            }
+
+            // modern uses double natively so always assert as such
+            IoTest.assertModernGraph(g1, true, lossyForId);
+
+            graphProvider.clear(g1, configuration);
+        }
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+    @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)
+    public void shouldReadWriteModernToFileWithHelpers() throws Exception {
+        final File f = TestHelper.generateTempFile(this.getClass(), name.getMethodName(), fileExtension);
+        try {
+            graph.io(ioBuilderToTest).writeGraph(f.getAbsolutePath());
+
+            final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), LoadGraphWith.GraphData.MODERN);
+            final Graph g1 = graphProvider.openTestGraph(configuration);
+            g1.io(ioBuilderToTest).readGraph(f.getAbsolutePath());
+
+            // modern uses double natively so always assert as such
+            IoTest.assertModernGraph(g1, true, lossyForId);
+
+            graphProvider.clear(g1, configuration);
+        } catch (Exception ex) {
+            f.delete();
+            throw ex;
+        }
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+    @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)
+    public void shouldMigrateModernGraph() throws Exception {
+        final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), LoadGraphWith.GraphData.MODERN);
+        graphProvider.clear(configuration);
+        final Graph g1 = graphProvider.openTestGraph(configuration);
+
+        final GraphReader reader = graph.io(ioBuilderToTest).reader().create();
+        final GraphWriter writer = graph.io(ioBuilderToTest).writer().create();
+
+        GraphMigrator.migrateGraph(graph, g1, reader, writer);
+
+        IoTest.assertModernGraph(g1, true, lossyForId);
+
+        graphProvider.clear(g1, configuration);
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.CREW)
+    @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)
+    public void shouldReadWriteCrewToGryo() throws Exception {
+        assumeThat("GraphML does not suppport multi/metaproperties", ioType, not("graphml"));
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+
+            final GraphWriter writer = graph.io(ioBuilderToTest).writer().create();
+            writer.writeGraph(os, graph);
+
+            final Configuration configuration = graphProvider.newGraphConfiguration("readGraph", this.getClass(), name.getMethodName(), LoadGraphWith.GraphData.CREW);
+            graphProvider.clear(configuration);
+            final Graph g1 = graphProvider.openTestGraph(configuration);
+
+            final GraphReader reader = graph.io(ioBuilderToTest).reader().create();
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readGraph(bais, g1);
+            }
+
+            IoTest.assertCrewGraph(g1, lossyForId);
+
+            graphProvider.clear(g1, configuration);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3ca54a62/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoPropertyTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoPropertyTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoPropertyTest.java
new file mode 100644
index 0000000..4077f23
--- /dev/null
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/IoPropertyTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.structure.io;
+
+import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+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.util.iterator.IteratorUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(Parameterized.class)
+public class IoPropertyTest extends AbstractGremlinTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {"graphson", false, false,
+                        (Function<Graph, GraphReader>) g -> g.io(IoCore.graphson()).reader().create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.graphson()).writer().create()},
+                {"graphson-embedded", true, true,
+                        (Function<Graph, GraphReader>) g -> g.io(IoCore.graphson()).reader().mapper(g.io(IoCore.graphson()).mapper().embedTypes(true).create()).create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.graphson()).writer().mapper(g.io(IoCore.graphson()).mapper().embedTypes(true).create()).create()},
+                {"gryo", true, true,
+                        (Function<Graph, GraphReader>) g -> g.io(IoCore.gryo()).reader().create(),
+                        (Function<Graph, GraphWriter>) g -> g.io(IoCore.gryo()).writer().create()}
+        });
+    }
+
+    @Parameterized.Parameter(value = 0)
+    public String ioType;
+
+    @Parameterized.Parameter(value = 1)
+    public boolean assertIdDirectly;
+
+    @Parameterized.Parameter(value = 2)
+    public boolean assertDouble;
+
+    @Parameterized.Parameter(value = 3)
+    public Function<Graph, GraphReader> readerMaker;
+
+    @Parameterized.Parameter(value = 4)
+    public Function<Graph, GraphWriter> writerMaker;
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.CREW)
+    public void shouldReadWriteVertexPropertyWithMetaProperties() throws Exception {
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            final GraphWriter writer = writerMaker.apply(graph);
+
+            // select any vertexproperty that has both start/end time
+            final VertexProperty p = (VertexProperty) g.V(convertToVertexId("marko")).properties("location").as("p").has("endTime").select("p").next();
+            writer.writeVertexProperty(os, p);
+
+            final AtomicBoolean called = new AtomicBoolean(false);
+            final GraphReader reader = readerMaker.apply(graph);
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readVertexProperty(bais, propertyAttachable -> {
+                    assertEquals(p.value(), propertyAttachable.get().value());
+                    assertEquals(p.key(), propertyAttachable.get().key());
+                    assertEquals(IteratorUtils.count(p.properties()), IteratorUtils.count(propertyAttachable.get().properties()));
+                    assertEquals(p.property("startTime").value(), ((Property) propertyAttachable.get().properties("startTime").next()).value());
+                    assertEquals(p.property("endTime").value(), ((Property) propertyAttachable.get().properties("endTime").next()).value());
+                    called.set(true);
+                    return propertyAttachable.get();
+                });
+            }
+
+            assertTrue(called.get());
+        }
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+    public void shouldReadWriteVertexPropertyNoMetaProperties() throws Exception {
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            final GraphWriter writer = writerMaker.apply(graph);
+            final VertexProperty p = g.V(convertToVertexId("marko")).next().property("name");
+            writer.writeVertexProperty(os, p);
+
+            final AtomicBoolean called = new AtomicBoolean(false);
+            final GraphReader reader = readerMaker.apply(graph);
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readVertexProperty(bais, propertyAttachable -> {
+                    assertEquals(p.value(), propertyAttachable.get().value());
+                    assertEquals(p.key(), propertyAttachable.get().key());
+                    assertEquals(0, IteratorUtils.count(propertyAttachable.get().properties()));
+                    called.set(true);
+                    return propertyAttachable.get();
+                });
+            }
+
+            assertTrue(called.get());
+        }
+    }
+
+    @Test
+    @LoadGraphWith(LoadGraphWith.GraphData.MODERN)
+    public void shouldReadWritePropertyGraphSON() throws Exception {
+        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            final GraphWriter writer = writerMaker.apply(graph);
+            final Property p = g.E(convertToEdgeId("marko", "knows", "vadas")).next().property("weight");
+            writer.writeProperty(os, p);
+
+            final AtomicBoolean called = new AtomicBoolean(false);
+            final GraphReader reader = readerMaker.apply(graph);
+            try (final ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) {
+                reader.readProperty(bais, propertyAttachable -> {
+                    assertEquals(p.value(), propertyAttachable.get().value());
+                    assertEquals(p.key(), propertyAttachable.get().key());
+                    called.set(true);
+                    return propertyAttachable.get();
+                });
+            }
+
+            assertTrue(called.get());
+        }
+    }
+}