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 2017/01/03 15:44:47 UTC

[38/50] [abbrv] tinkerpop git commit: TINKERPOP-1130 Add Compatiblities helper class

TINKERPOP-1130 Add Compatiblities helper class

Makes it easier to express ranges of versions for defining compatiblity in the Model.


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

Branch: refs/heads/TINKERPOP-1130
Commit: c5c9517f2eef67b41d51b699ae68966d0be6ffc4
Parents: 86e04c6
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Dec 29 13:20:53 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Tue Jan 3 10:34:56 2017 -0500

----------------------------------------------------------------------
 .../gremlin/structure/io/Compatibilities.java   | 165 +++++++++++++++++++
 .../gremlin/structure/io/Compatibility.java     |  10 ++
 .../tinkerpop/gremlin/structure/io/Model.java   |  48 +++---
 .../io/graphson/GraphSONCompatibility.java      |  12 ++
 .../structure/io/gryo/GryoCompatibility.java    |  10 ++
 .../structure/io/CompatibilitiesTest.java       |  76 +++++++++
 6 files changed, 297 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c5c9517f/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibilities.java
----------------------------------------------------------------------
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibilities.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibilities.java
new file mode 100644
index 0000000..5b66cd1
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibilities.java
@@ -0,0 +1,165 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class Compatibilities {
+
+    private final Class<? extends Enum<? extends Compatibility>> compatibility;
+
+    /**
+     * Initialized to 4.0.0 which is non-existent, but obviously the high-end of whatever would be tested.
+     */
+    private String releaseVersionBefore = "4.0.0";
+
+    /**
+     * Initialized to 3.0.0 which is non-existent, but obviously the low-end of whatever would be tested.
+     */
+    private String releaseVersionAfter = "3.0.0";
+
+    /**
+     * Initialized to 0.0 which is non-existent, but obviously the low-end of whatever would be tested.
+     */
+    private String ioVersionBefore = "4.0";
+
+    /**
+     * Initialized to 3.0 which is non-existent, but obviously the high-end of whatever would be tested.
+     */
+    private String ioVersionAfter = "0.0";
+
+    private Compatibilities(final Class<? extends Enum<? extends Compatibility>> c) {
+        this.compatibility = c;
+    }
+
+    public static Compatibilities with(final Class<? extends Enum<? extends Compatibility>> c) {
+        return new Compatibilities(c);
+    }
+
+    /**
+     * Finds {@link Compatibility} instances before (and not inclusive of) the specified version.
+     */
+    public Compatibilities beforeRelease(final String before) {
+        this.releaseVersionBefore = before;
+        return this;
+    }
+
+    /**
+     * Finds {@link Compatibility} instances after (and not inclusive of) the specified version.
+     */
+    public Compatibilities afterRelease(final String after) {
+        this.releaseVersionAfter = after;
+        return this;
+    }
+
+    /**
+     * Finds {@link Compatibility} instances between (and not inclusive of) the specified versions.
+     */
+    public Compatibilities betweenReleases(final String start, final String end) {
+        return beforeRelease(end).afterRelease(start);
+    }
+
+    /**
+     * Finds {@link Compatibility} instances before (and not inclusive of) the specified version.
+     */
+    public Compatibilities before(final String before) {
+        this.ioVersionBefore = before;
+        return this;
+    }
+
+    /**
+     * Finds {@link Compatibility} instances after (and not inclusive of) the specified version.
+     */
+    public Compatibilities after(final String after) {
+        this.ioVersionAfter = after;
+        return this;
+    }
+
+    /**
+     * Finds {@link Compatibility} instances between (and not inclusive of) the specified versions.
+     */
+    public Compatibilities between(final String start, final String end) {
+        return before(end).after(start);
+    }
+
+    public List<Compatibility> match() {
+        final Compatibility[] enumArray = (Compatibility[]) compatibility.getEnumConstants();
+        final List<Compatibility> enums = Arrays.asList(enumArray);
+        return enums.stream()
+                .filter(c -> beforeRelease(c, releaseVersionBefore))
+                .filter(c -> afterRelease(c, releaseVersionAfter))
+                .filter(c -> beforeIo(c, ioVersionBefore))
+                .filter(c -> afterIo(c, ioVersionAfter))
+                .collect(Collectors.toList());
+    }
+
+    public Compatibility[] matchToArray() {
+        final List<Compatibility> list = match();
+        final Compatibility [] compatibilities = new Compatibility[list.size()];
+        list.toArray(compatibilities);
+        return compatibilities;
+    }
+
+    private static boolean afterRelease(final Compatibility version, final String after) {
+        return versionCompare(version.getReleaseVersion(), after) > 0;
+    }
+
+    private static boolean beforeRelease(final Compatibility version, final String before) {
+        return versionCompare(version.getReleaseVersion(), before) < 0;
+    }
+
+    private static boolean afterIo(final Compatibility version, final String after) {
+        return versionCompare(version.getVersion(), after) > 0;
+    }
+
+    private static boolean beforeIo(final Compatibility version, final String before) {
+        return versionCompare(version.getVersion(), before) < 0;
+    }
+
+    /**
+     * @return The result is a negative integer if v1 is less than v2.
+     *         The result is a positive integer if v1 is greater than v2.
+     *         The result is zero if the strings are equal.
+     */
+    private static int versionCompare(final String v1, final String v2) {
+        final String[] vals1 = v1.split("\\.");
+        final String[] vals2 = v2.split("\\.");
+        int i = 0;
+
+        // set index to first non-equal ordinal or length of shortest version string
+        while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
+            i++;
+        }
+
+        // compare first non-equal ordinal number
+        if (i < vals1.length && i < vals2.length) {
+            int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
+            return Integer.signum(diff);
+        }
+
+        // the strings are equal or one string is a substring of the other
+        // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4"
+        return Integer.signum(vals1.length - vals2.length);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c5c9517f/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibility.java
----------------------------------------------------------------------
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibility.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibility.java
index 2bbe7b5..8dce869 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibility.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Compatibility.java
@@ -29,4 +29,14 @@ public interface Compatibility {
     public default Class resolve(final Class clazz) {
         return clazz;
     }
+
+    /**
+     * Gets the TinkerPop version.
+     */
+    public String getReleaseVersion();
+
+    /**
+     * Gets the version of the IO type (i.e. GraphSON 2.0)
+     */
+    public String getVersion();
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c5c9517f/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
----------------------------------------------------------------------
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
index 3bf7770..2640e6c 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
@@ -176,43 +176,35 @@ public class Model {
         requestMessage = RequestMessage.build("authentication").
                 overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
                 add("saslMechanism", "PLAIN", "sasl", "AHN0ZXBocGhlbgBwYXNzd29yZA==").create();
-        addRequestMessageEntry(requestMessage, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge.",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addRequestMessageEntry(requestMessage, "Authentication Response", "The following `RequestMessage` is an example of the response that should be made to a SASL-based authentication challenge.");
         requestMessage = RequestMessage.build("eval").processor("session").
                 overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
                 add("gremlin", "g.V(x)", "bindings", requestBindings, "language", "gremlin-groovy", "session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create();
-        addRequestMessageEntry(requestMessage, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters.",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addRequestMessageEntry(requestMessage, "Session Eval", "The following `RequestMessage` is an example of a simple session request for a script evaluation with parameters.");
         requestMessage = RequestMessage.build("eval").processor("session").
                 overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
                 add("gremlin", "social.V(x)", "bindings", requestBindings, "language", "gremlin-groovy", "aliases", requestAliases, "session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create();
-        addRequestMessageEntry(requestMessage, "Session Eval Aliased", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addRequestMessageEntry(requestMessage, "Session Eval Aliased", "The following `RequestMessage` is an example of a session request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".");
         requestMessage = RequestMessage.build("close").processor("session").
                 overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
                 add("session", UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).create();
-        addRequestMessageEntry(requestMessage, "Session Close", "The following `RequestMessage` is an example of a request to close a session.",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addRequestMessageEntry(requestMessage, "Session Close", "The following `RequestMessage` is an example of a request to close a session.");
         requestMessage = RequestMessage.build("eval").
                 overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
                 add("gremlin", "g.V(x)", "bindings", requestBindings, "language", "gremlin-groovy").create();
-        addRequestMessageEntry(requestMessage, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters.",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addRequestMessageEntry(requestMessage, "Sessionless Eval", "The following `RequestMessage` is an example of a simple sessionless request for a script evaluation with parameters.");
         requestMessage = RequestMessage.build("eval").
                 overrideRequestId(UUID.fromString("cb682578-9d92-4499-9ebc-5c6aa73c5397")).
                 add("gremlin", "social.V(x)", "bindings", requestBindings, "language", "gremlin-groovy", "aliases", requestAliases).create();
-        addRequestMessageEntry(requestMessage, "Sessionless Eval Aliased", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addRequestMessageEntry(requestMessage, "Sessionless Eval Aliased", "The following `RequestMessage` is an example of a sessionless request for a script evaluation with an alias that binds the `TraversalSource` of \"g\" to \"social\".");
 
         ResponseMessage responseMessage = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
                 code(org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode.AUTHENTICATE).create();
-        addResponseMessageEntry(responseMessage, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different depending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server).",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GraphSONCompatibility.V2D0_PARTIAL_3_2_4, GraphSONCompatibility.V2D0_PARTIAL_3_3_0, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addResponseMessageEntry(responseMessage, "Authentication Challenge", "When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different depending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server).");
         responseMessage = ResponseMessage.build(UUID.fromString("41d2e28a-20a4-4ab0-b379-d810dede3786")).
                 code(org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode.SUCCESS).
                 result(Collections.singletonList(graph.vertices().next())).create();
-        addResponseMessageEntry(responseMessage, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script.",
-                GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GraphSONCompatibility.V2D0_PARTIAL_3_2_4, GraphSONCompatibility.V2D0_PARTIAL_3_3_0, GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0);
+        addResponseMessageEntry(responseMessage, "Standard Result", "The following `ResponseMessage` is a typical example of the typical successful response Gremlin Server will return when returning results from a script.");
         
         addExtendedEntry(new BigDecimal(new java.math.BigInteger("123456789987654321123456789987654321")), "BigDecimal", "", UNTYPED_GRAPHSON_ONLY.toArray(new Compatibility[UNTYPED_GRAPHSON_ONLY.size()]));
         addExtendedEntry(new BigInteger("123456789987654321123456789987654321"), "BigInteger", "", UNTYPED_GRAPHSON_ONLY.toArray(new Compatibility[UNTYPED_GRAPHSON_ONLY.size()]));
@@ -336,18 +328,26 @@ public class Model {
         addEntry("Graph Process", obj, title, description, incompatibilityNotes, incompatibleWith);
     }
 
-    private void addRequestMessageEntry(final Object obj, final String title, final String description, final Compatibility... incompatibleWith) {
+    private void addRequestMessageEntry(final Object obj, final String title, final String description) {
+        final List<Compatibility> incompatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .before("3.0")
+                .match();
+        incompatibilityList.addAll(Arrays.asList(GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GraphSONCompatibility.V2D0_PARTIAL_3_2_4, GraphSONCompatibility.V2D0_PARTIAL_3_3_0));
+        final Compatibility[] incompatibilities = new Compatibility[incompatibilityList.size()];
+        incompatibilityList.toArray(incompatibilities);
         addEntry("RequestMessage", obj, title, description,
-                createIncompatibilityMap("RequestMessage is not testable prior to Gryo 3.0 as serialization was handled by an intermediate component (MessageSerializer) that doesn't fit the test model.",
-                        GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0),
-                incompatibleWith);
+                createIncompatibilityMap("RequestMessage is not testable prior to Gryo 3.0 as serialization was handled by an intermediate component (MessageSerializer) that doesn't fit the test model.",  incompatibilities), incompatibilities);
     }
 
-    private void addResponseMessageEntry(final Object obj, final String title, final String description, final Compatibility... incompatibleWith) {
+    private void addResponseMessageEntry(final Object obj, final String title, final String description) {
+        final List<Compatibility> incompatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .before("3.0")
+                .match();
+        incompatibilityList.addAll(Arrays.asList(GraphSONCompatibility.V2D0_PARTIAL_3_2_3, GraphSONCompatibility.V2D0_PARTIAL_3_2_4, GraphSONCompatibility.V2D0_PARTIAL_3_3_0));
+        final Compatibility[] incompatibilities = new Compatibility[incompatibilityList.size()];
+        incompatibilityList.toArray(incompatibilities);
         addEntry("ResponseMessage", obj, title, description,
-                createIncompatibilityMap("ResponseMessage is not testable prior to Gryo 3.0 as serialization was handled by an intermediate component (MessageSerializer) that doesn't fit the test model.",
-                        GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0),
-                incompatibleWith);
+                createIncompatibilityMap("ResponseMessage is not testable prior to Gryo 3.0 as serialization was handled by an intermediate component (MessageSerializer) that doesn't fit the test model.", incompatibilities), incompatibilities);
     }
 
     private void addExtendedEntry(final Object obj, final String title) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c5c9517f/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java
----------------------------------------------------------------------
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java
index 08a1c13..f267bcc 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONCompatibility.java
@@ -50,12 +50,24 @@ public enum GraphSONCompatibility implements Compatibility {
         this.graphSONVersion = graphSONVersion;
     }
 
+
+
     public byte[] readFromResource(final String resource) throws IOException {
         final String testResource = "_" + tinkerpopVersion.replace(".", "_") + SEP + resource + "-" + configuration + ".json";
         return IOUtils.toByteArray(getClass().getResourceAsStream(testResource));
     }
 
     @Override
+    public String getReleaseVersion() {
+        return tinkerpopVersion;
+    }
+
+    @Override
+    public String getVersion() {
+        return graphSONVersion;
+    }
+
+    @Override
     public String toString() {
         return tinkerpopVersion + "-" + configuration;
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c5c9517f/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java
----------------------------------------------------------------------
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java
index 003df23..013779a 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoCompatibility.java
@@ -90,6 +90,16 @@ public enum GryoCompatibility implements Compatibility {
     }
 
     @Override
+    public String getReleaseVersion() {
+        return tinkerpopVersion;
+    }
+
+    @Override
+    public String getVersion() {
+        return gryoVersion;
+    }
+
+    @Override
     public String toString() {
         return tinkerpopVersion + "-" + configuration;
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c5c9517f/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/CompatibilitiesTest.java
----------------------------------------------------------------------
diff --git a/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/CompatibilitiesTest.java b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/CompatibilitiesTest.java
new file mode 100644
index 0000000..2e82e22
--- /dev/null
+++ b/gremlin-tools/gremlin-io-test/src/test/java/org/apache/tinkerpop/gremlin/structure/io/CompatibilitiesTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.structure.io.gryo.GryoCompatibility;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class CompatibilitiesTest {
+    @Test
+    public void shouldFindGryoVersionsBeforeRelease3_2_4() {
+        final List<Compatibility> compatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .beforeRelease("3.2.4").match();
+        assertThat(compatibilityList, containsInAnyOrder(GryoCompatibility.V1D0_3_2_3));
+    }
+
+    @Test
+    public void shouldFindGryoVersionsAfterRelease3_2_4() {
+        final List<Compatibility> compatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .afterRelease("3.2.4").match();
+        assertThat(compatibilityList, containsInAnyOrder(GryoCompatibility.V1D0_3_3_0, GryoCompatibility.V3D0_3_3_0));
+    }
+
+    @Test
+    public void shouldFindGryoVersionsBetweenReleases3_2_3And3_3_0() {
+        final List<Compatibility> compatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .betweenReleases("3.2.3", "3.3.0").match();
+        assertThat(compatibilityList, containsInAnyOrder(GryoCompatibility.V1D0_3_2_4));
+    }
+
+    @Test
+    public void shouldFindGryoVersionsBefore3_0() {
+        final List<Compatibility> compatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .before("3.0").match();
+        assertThat(compatibilityList, containsInAnyOrder(GryoCompatibility.V1D0_3_2_3, GryoCompatibility.V1D0_3_2_4, GryoCompatibility.V1D0_3_3_0));
+    }
+
+    @Test
+    public void shouldFindGryoVersionsAfter1_0() {
+        final List<Compatibility> compatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .after("1.0").match();
+        assertThat(compatibilityList, containsInAnyOrder(GryoCompatibility.V3D0_3_3_0));
+    }
+
+    @Test
+    public void shouldFindGryoVersionsAfterRelease3_2_4AndAfter1_0() {
+        final List<Compatibility> compatibilityList = Compatibilities.with(GryoCompatibility.class)
+                .afterRelease("3.2.4")
+                .after("1.0")
+                .match();
+        assertThat(compatibilityList, containsInAnyOrder(GryoCompatibility.V3D0_3_3_0));
+    }
+}