From 98eb844b17ea34eab695a4ae983622aa4796803b Mon Sep 17 00:00:00 2001
From: SeH <1s1e1h1@gmail.com>
Date: Sun, 7 Jun 2015 21:35:30 -0400
Subject: [PATCH] passes vertex test suite, edge and properties remaining

---
 pom.xml                                       |   7 +
 .../spangraph/ConcurrentHashMapGraph.java     |  30 +++++
 .../com/syncleus/spangraph/HashMapGraph.java  |  30 +++++
 .../java/com/syncleus/spangraph/MapGraph.java | 122 +++++++++++-------
 .../spangraph/SpanGraphBlueprintsTest.java    |  89 +++++++++++++
 .../com/syncleus/spangraph/SpanGraphTest.java |  12 +-
 6 files changed, 240 insertions(+), 50 deletions(-)
 create mode 100644 src/main/java/com/syncleus/spangraph/ConcurrentHashMapGraph.java
 create mode 100644 src/main/java/com/syncleus/spangraph/HashMapGraph.java
 create mode 100644 src/test/java/com/syncleus/spangraph/SpanGraphBlueprintsTest.java

diff --git a/pom.xml b/pom.xml
index 25de644..e559587 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,13 @@
             <version>2.6.0</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.tinkerpop.blueprints</groupId>
+            <artifactId>blueprints-test</artifactId>
+            <version>2.6.0</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 
diff --git a/src/main/java/com/syncleus/spangraph/ConcurrentHashMapGraph.java b/src/main/java/com/syncleus/spangraph/ConcurrentHashMapGraph.java
new file mode 100644
index 0000000..79ac655
--- /dev/null
+++ b/src/main/java/com/syncleus/spangraph/ConcurrentHashMapGraph.java
@@ -0,0 +1,30 @@
+package com.syncleus.spangraph;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Uses java.util.LinkedHashMap to implement adjacency
+ */
+public class ConcurrentHashMapGraph extends MapGraph {
+
+    protected ConcurrentHashMapGraph() {
+        super();
+
+        init();
+    }
+
+    protected ConcurrentHashMapGraph(String globalGraphID) {
+        super(globalGraphID);
+    }
+
+    @Override
+    protected Map newEdgeMap() {
+        return new ConcurrentHashMap<>();
+    }
+
+    @Override
+    protected Map newVertexMap() {
+        return new ConcurrentHashMap<>();
+    }
+}
diff --git a/src/main/java/com/syncleus/spangraph/HashMapGraph.java b/src/main/java/com/syncleus/spangraph/HashMapGraph.java
new file mode 100644
index 0000000..50a975f
--- /dev/null
+++ b/src/main/java/com/syncleus/spangraph/HashMapGraph.java
@@ -0,0 +1,30 @@
+package com.syncleus.spangraph;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Uses java.util.LinkedHashMap to implement adjacency
+ */
+public class HashMapGraph extends MapGraph {
+
+    protected HashMapGraph() {
+        super();
+
+        init();
+    }
+
+    protected HashMapGraph(String globalGraphID) {
+        super(globalGraphID);
+    }
+
+    @Override
+    protected Map newEdgeMap() {
+        return new LinkedHashMap<>();
+    }
+
+    @Override
+    protected Map newVertexMap() {
+        return new LinkedHashMap<>();
+    }
+}
diff --git a/src/main/java/com/syncleus/spangraph/MapGraph.java b/src/main/java/com/syncleus/spangraph/MapGraph.java
index b82a725..ad896d1 100644
--- a/src/main/java/com/syncleus/spangraph/MapGraph.java
+++ b/src/main/java/com/syncleus/spangraph/MapGraph.java
@@ -2,6 +2,8 @@ package com.syncleus.spangraph;
 
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
+import com.google.common.primitives.Bytes;
+import com.google.common.primitives.Longs;
 import com.tinkerpop.blueprints.*;
 import com.tinkerpop.blueprints.util.*;
 import org.infinispan.commons.util.InfinispanCollections;
@@ -9,6 +11,7 @@ import org.infinispan.commons.util.WeakValueHashMap;
 
 import java.io.*;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Blueprints Graph interface with adjacency implemented by some Map implementation.
@@ -84,6 +87,10 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
         GRAPHSON
     }
 
+    protected MapGraph() {
+        super();
+        this.id = this.globalID = null;
+    }
 
     protected MapGraph(String id) {
         this(id, id);
@@ -110,15 +117,31 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
 
     protected abstract Map<X, Vertex> newVertexMap();
 
-    public MVertex<X> addVertex(final Object id) {
 
+    public String newID() {
+        String r;
+        do {
+            long low = UUID.randomUUID().getLeastSignificantBits();
+            long high = UUID.randomUUID().getMostSignificantBits();
+            r = new String(Base64.getEncoder().encode(
+                    Bytes.concat(
+                            Longs.toByteArray(low),
+                            Longs.toByteArray(high)
+                    )
+            ));
+        } while (this.vertices.containsKey(r));
+        return r;
+    }
 
-        if (null != id) {
-            if (this.vertices.containsKey(id)) {
-                throw ExceptionFactory.vertexWithIdAlreadyExists(id);
-            }
-        } else {
-            throw new RuntimeException("id must be non-null");
+    public MVertex<X> addVertex(Object id) {
+
+
+        if (null == id) {
+            id = newID();
+        }
+        else {
+
+            //throw new RuntimeException("id must be non-null");
 //            boolean done = false;
 //            while (!done) {
 //                idString = this.getNextId();
@@ -126,6 +149,10 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
 //                if (null == vertex)
 //                    done = true;
 //            }
+
+            if (this.vertices.containsKey(id)) {
+                throw ExceptionFactory.vertexWithIdAlreadyExists(id);
+            }
         }
 
         MVertex<X> vertex = new MVertex<X>((X) id, this);
@@ -153,9 +180,6 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
         if (!(obj instanceof MapGraph))
             return false;
         MapGraph m = (MapGraph)obj;
-
-
-
         if ((vertices.size() != m.vertices.size()) ||
             (edges.size() != m.edges.size()))
                 return false;
@@ -241,7 +265,7 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
         return addEdge(edgeID, o, i, null);
     }
 
-    public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVertex, final String label) {
+    public Edge addEdge(Object id, final Vertex outVertex, final Vertex inVertex, final String label) {
         /*if (label == null)
             throw ExceptionFactory.edgeLabelCanNotBeNull();*/
 
@@ -252,14 +276,7 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
                 throw ExceptionFactory.edgeWithIdAlreadyExist(id);
             }
         } else {
-            throw new RuntimeException("ID must be non-null");
-//            boolean done = false;
-//            while (!done) {
-//                idString = this.getNextId();
-//                edge = this.edges.get(idString);
-//                if (null == edge)
-//                    done = true;
-//            }
+            id = newID();
         }
 
         MEdge<X> edge = new MEdge<X>((X)id,
@@ -405,8 +422,12 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
 
         public Map<String, Serializable> prop(final boolean createIfMissing) {
             if (properties == null) {
-                if  (createIfMissing)
-                    properties = new LinkedHashMap(2);
+                if  (createIfMissing) {
+
+                    //TODO make this an abstract method of MapGraph
+                    //properties = new LinkedHashMap(2);
+                    properties = new ConcurrentHashMap(2);
+                }
                 else
                     return InfinispanCollections.emptyMap();
             }
@@ -458,19 +479,24 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
 
 
 
+        public boolean isGlobal() {
+            return graphID != null;
+        }
+
         public String global() {
-            if (graphID == null) return null;
+            if (!isGlobal()) return null;
 
-            if (globalID == null)
-                globalID = graphID.substring(0, graphID.indexOf(':'));
-            return globalID;
+            return globalID = graphID.substring(0, graphID.indexOf(':'));
         }
+
         abstract protected void beforeRemove(final String key, final Serializable oldValue);
 
         final static int PRIME = 31;
         final static int PRIME2 = 92821;
 
         public int hashCode() {
+            if (graphID == null) return id.hashCode();
+
             return hashL(this.id.hashCode(), global().hashCode()) ;
         }
 
@@ -490,7 +516,12 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
         public boolean equals(final Object object) {
             if (object.getClass()!=getClass()) return false;
             MElement o = (MElement)object;
-            return o.getId().equals(getId()) && o.global().equals(global());
+            if (o.getId().equals(getId())) {
+                if (isGlobal())
+                    return o.global().equals(global());
+                return true;
+            }
+            return false;
         }
 
         /** also includes properties in the equality test */
@@ -510,14 +541,14 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
 
     public static class MVertex<X extends Serializable> extends MElement<X> implements Vertex, Serializable {
 
-        public final Map<X, Set<Edge>> outEdges = new LinkedHashMap();
-        public final Map<X, Set<Edge>> inEdges = new LinkedHashMap();
+        public final Map<String, Set<Edge>> outEdges = new LinkedHashMap();
+        public final Map<String, Set<Edge>> inEdges = new LinkedHashMap();
 
-        protected MVertex(final X id, final MapGraph graph) {
+        protected MVertex(final X id, final MapGraph<X> graph) {
             super(id, graph);
         }
 
-        public Iterable<Edge> getEdges(final Direction direction, final X... labels) {
+        public Iterable<Edge> getEdges(final Direction direction, final String... labels) {
             if (direction.equals(Direction.OUT)) {
                 return this.getOutEdges(labels);
             } else if (direction.equals(Direction.IN))
@@ -527,16 +558,13 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
             }
         }
 
-        @Override
-        public Iterable<Edge> getEdges(Direction direction, String... strings) {
-            return null;
-        }
+
 
         public Iterable<Vertex> getVertices(final Direction direction, final String... labels) {
             return new VerticesFromEdgesIterable(this, direction, labels);
         }
 
-        private Iterable<Edge> getEdges(final Map<X, Set<Edge>> e, final X... labels) {
+        public Iterable<Edge> getEdges(final Map<String, Set<Edge>> e, final String... labels) {
             if (labels.length == 0) {
                 return Iterables.concat(e.values());
             } else if (labels.length == 1) {
@@ -547,7 +575,7 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
                     return edges;
                 }
             } else {
-                final Set<X> labelSet = Sets.newHashSet(labels);
+                final Set<String> labelSet = Sets.newHashSet(labels);
                 return Iterables.concat(Iterables.transform(e.entrySet(), x -> {
                     if (labelSet.contains(x.getKey()))
                         return x.getValue();
@@ -556,10 +584,11 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
             }
         }
 
-        private Iterable<Edge> getInEdges(final X... labels) {
+
+        private Iterable<Edge> getInEdges(final String... labels) {
             return getEdges(inEdges, labels);
         }
-        private Iterable<Edge> getOutEdges(final X... labels) {
+        private Iterable<Edge> getOutEdges(final String... labels) {
             return getEdges(outEdges, labels);
         }
 
@@ -568,7 +597,11 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
         }
 
         public String toString() {
-            return new StringBuilder().append("v[").append(global()).append(':').append(getId()).append("]").toString();
+            if (isGlobal())
+                return new StringBuilder().append("v[").append(global()).append(':').append(getId()).append("]").toString();
+            else
+                return new StringBuilder().append("v[").append(getId()).append("]").toString();
+
         }
 
         public Edge addEdge(final String label, final Vertex vertex) {
@@ -603,7 +636,7 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
 
 
         public boolean remove(Object edgeID, boolean incoming) {
-            Map<X, Set<Edge>> target = incoming ? inEdges : outEdges;
+            Map<String, Set<Edge>> target = incoming ? outEdges : inEdges;
             if (target.remove(edgeID)!=null) {
                 graph().update(this);
                 return true;
@@ -613,11 +646,12 @@ abstract public class MapGraph<X extends Serializable> implements Graph {
         }
 
         public boolean add(MEdge<X> edge, boolean incoming) {
-            Map<X, Set<Edge>> target = incoming ? inEdges : outEdges;
-            X e = edge.id;
-            Set<Edge> edges = target.get(e);
+            Map<String, Set<Edge>> target = incoming ? outEdges : inEdges;
+
+            String label = edge.getLabel();
+            Set<Edge> edges = target.get(label);
             if (null == edges) {
-                target.put(e, edges = newEdgeSet(1));
+                target.put(label, edges = newEdgeSet(1));
             }
             if (edges.add(edge)) {
                 graph().update(this);
diff --git a/src/test/java/com/syncleus/spangraph/SpanGraphBlueprintsTest.java b/src/test/java/com/syncleus/spangraph/SpanGraphBlueprintsTest.java
new file mode 100644
index 0000000..f3df7f3
--- /dev/null
+++ b/src/test/java/com/syncleus/spangraph/SpanGraphBlueprintsTest.java
@@ -0,0 +1,89 @@
+package com.syncleus.spangraph;
+
+import com.tinkerpop.blueprints.*;
+import com.tinkerpop.blueprints.impls.GraphTest;
+
+import java.lang.reflect.Method;
+
+/**
+ * https://github.com/tinkerpop/blueprints/wiki/Property-Graph-Model-Test-Suite
+ */
+public class SpanGraphBlueprintsTest extends GraphTest {
+
+    public void testVertexTestSuite() throws Exception {
+        this.stopWatch();
+        doTestSuite(new VertexTestSuite(this));
+        printTestPerformance("VertexTestSuite", this.stopWatch());
+    }
+
+    public void testEdgeTestSuite() throws Exception {
+        this.stopWatch();
+        doTestSuite(new EdgeTestSuite(this));
+        printTestPerformance("EdgeTestSuite", this.stopWatch());
+    }
+
+    public void testGraphTestSuite() throws Exception {
+        this.stopWatch();
+        doTestSuite(new GraphTestSuite(this));
+        printTestPerformance("GraphTestSuite", this.stopWatch());
+    }
+
+//    public void testKeyIndexableGraphTestSuite() throws Exception {
+//        this.stopWatch();
+//        doTestSuite(new KeyIndexableGraphTestSuite(this));
+//        printTestPerformance("KeyIndexableGraphTestSuite", this.stopWatch());
+//    }
+//
+//    public void testIndexableGraphTestSuite() throws Exception {
+//        this.stopWatch();
+//        doTestSuite(new IndexableGraphTestSuite(this));
+//        printTestPerformance("IndexableGraphTestSuite", this.stopWatch());
+//    }
+//
+//    public void testIndexTestSuite() throws Exception {
+//        this.stopWatch();
+//        doTestSuite(new IndexTestSuite(this));
+//        printTestPerformance("IndexTestSuite", this.stopWatch());
+//    }
+//
+//    public void testGraphMLReaderTestSuite() throws Exception {
+//        this.stopWatch();
+//        doTestSuite(new GraphMLReaderTestSuite(this));
+//        printTestPerformance("GraphMLReaderTestSuite", this.stopWatch());
+//    }
+//
+//    public void testGMLReaderTestSuite() throws Exception {
+//        this.stopWatch();
+//        doTestSuite(new GMLReaderTestSuite(this));
+//        printTestPerformance("GMLReaderTestSuite", this.stopWatch());
+//    }
+//
+//    public void testGraphSONReaderTestSuite() throws Exception {
+//        this.stopWatch();
+//        doTestSuite(new GraphSONReaderTestSuite(this));
+//        printTestPerformance("GraphSONReaderTestSuite", this.stopWatch());
+//    }
+
+    public Graph generateGraph() {
+        return new ConcurrentHashMapGraph();
+    }
+
+    @Override
+    public Graph generateGraph(String s) {
+        System.err.println("generateGraph(String ??):  " + s);
+        return null;
+    }
+
+    public void doTestSuite(final TestSuite testSuite) throws Exception {
+        String doTest = System.getProperty("testTinkerGraph");
+        if (doTest == null || doTest.equals("true")) {
+            for (Method method : testSuite.getClass().getDeclaredMethods()) {
+                if (method.getName().startsWith("test")) {
+                    System.out.println(method);
+                    System.out.println("Testing " + method.getName() + "...");
+                    method.invoke(testSuite);
+                }
+            }
+        }
+    }
+}
diff --git a/src/test/java/com/syncleus/spangraph/SpanGraphTest.java b/src/test/java/com/syncleus/spangraph/SpanGraphTest.java
index c2cf3d8..d919666 100644
--- a/src/test/java/com/syncleus/spangraph/SpanGraphTest.java
+++ b/src/test/java/com/syncleus/spangraph/SpanGraphTest.java
@@ -13,12 +13,12 @@ import static org.junit.Assert.assertTrue;
 public class SpanGraphTest {
 
 
-//    @Test
-//    public void testVertexEdgePropagationMemory() throws InterruptedException {
-//        testVertexPropagation(x ->
-//                        new SpanGraph("memory", InfiniPeer.cluster(x))
-//        );
-//    }
+    @Test
+    public void testVertexEdgePropagationMemory() throws InterruptedException {
+        testVertexPropagation(x ->
+                        new SpanGraph("local", InfiniPeer.local(x))
+        );
+    }
 
     @Test
     public void testVertexEdgePropagationNetwork() throws InterruptedException {
-- 
GitLab