blob: eac7db2f92000edb00ffb03b9e5cde51f311f531 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tinkerpop.gremlin.tinkergraph.structure;
import org.apache.tinkerpop.gremlin.process.traversal.Path;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Property;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
import org.apache.tinkerpop.gremlin.structure.io.GraphReader;
import org.apache.tinkerpop.gremlin.structure.io.GraphWriter;
import org.apache.tinkerpop.gremlin.structure.io.IoTest;
import org.apache.tinkerpop.gremlin.structure.io.Mapper;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONReader;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0;
import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Year;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class TinkerGraphGraphSONSerializerV2d0Test {
// As of TinkerPop 3.2.1 default for GraphSON 2.0 means types enabled.
private final Mapper defaultMapperV2d0 = GraphSONMapper.build()
.version(GraphSONVersion.V2_0)
.addCustomModule(GraphSONXModuleV2d0.build().create(false))
.addRegistry(TinkerIoRegistryV2d0.instance())
.create();
private final Mapper noTypesMapperV2d0 = GraphSONMapper.build()
.version(GraphSONVersion.V2_0)
.addCustomModule(GraphSONXModuleV2d0.build().create(false))
.typeInfo(TypeInfo.NO_TYPES)
.addRegistry(TinkerIoRegistryV2d0.instance())
.create();
/**
* Checks that the graph has been fully ser/deser with types.
*/
@Test
public void shouldDeserializeGraphSONIntoTinkerGraphWithPartialTypes() throws IOException {
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final TinkerGraph baseModern = TinkerFactory.createModern();
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeGraph(out, baseModern);
final String json = out.toString();
final TinkerGraph read = TinkerGraph.open();
reader.readGraph(new ByteArrayInputStream(json.getBytes()), read);
IoTest.assertModernGraph(read, true, false);
}
}
/**
* Checks that the graph has been fully ser/deser without types.
*/
@Test
public void shouldDeserializeGraphSONIntoTinkerGraphWithoutTypes() throws IOException {
final GraphWriter writer = getWriter(noTypesMapperV2d0);
final GraphReader reader = getReader(noTypesMapperV2d0);
final TinkerGraph baseModern = TinkerFactory.createModern();
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeGraph(out, baseModern);
final String json = out.toString();
final TinkerGraph read = TinkerGraph.open();
reader.readGraph(new ByteArrayInputStream(json.getBytes()), read);
IoTest.assertModernGraph(read, true, false);
}
}
/**
* Thorough types verification for Vertex ids, Vertex props, Edge ids, Edge props
*/
@Test
public void shouldDeserializeGraphSONIntoTinkerGraphKeepingTypes() throws IOException {
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final Graph sampleGraph1 = TinkerFactory.createModern();
final Vertex v1 = sampleGraph1.addVertex(T.id, 100, "name", "kevin", "theUUID", UUID.randomUUID());
final Vertex v2 = sampleGraph1.addVertex(T.id, 101L, "name", "henri", "theUUID", UUID.randomUUID());
v1.addEdge("hello", v2, T.id, 101L,
"uuid", UUID.randomUUID());
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, sampleGraph1);
final String json = out.toString();
final TinkerGraph read = reader.readObject(new ByteArrayInputStream(json.getBytes()), TinkerGraph.class);
assertTrue(approximateGraphsCheck(sampleGraph1, read));
}
}
/**
* Asserts the approximateGraphsChecks function fails when expected. Vertex ids.
*/
@Test
public void shouldLoseTypesWithGraphSONNoTypesForVertexIds() throws IOException {
final GraphWriter writer = getWriter(noTypesMapperV2d0);
final GraphReader reader = getReader(noTypesMapperV2d0);
final TinkerGraph sampleGraph1 = TinkerGraph.open();
TinkerFactory.generateModern(sampleGraph1);
sampleGraph1.addVertex(T.id, 100L, "name", "kevin");
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeGraph(out, sampleGraph1);
final String json = out.toString();
final TinkerGraph read = TinkerGraph.open();
reader.readGraph(new ByteArrayInputStream(json.getBytes()), read);
// Should fail on deserialized vertex Id.
assertFalse(approximateGraphsCheck(sampleGraph1, read));
}
}
/**
* Asserts the approximateGraphsChecks function fails when expected. Vertex props.
*/
@Test
public void shouldLoseTypesWithGraphSONNoTypesForVertexProps() throws IOException {
final GraphWriter writer = getWriter(noTypesMapperV2d0);
final GraphReader reader = getReader(noTypesMapperV2d0);
final TinkerGraph sampleGraph1 = TinkerGraph.open();
TinkerFactory.generateModern(sampleGraph1);
sampleGraph1.addVertex(T.id, 100, "name", "kevin", "uuid", UUID.randomUUID());
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeGraph(out, sampleGraph1);
final String json = out.toString();
final TinkerGraph read = TinkerGraph.open();
reader.readGraph(new ByteArrayInputStream(json.getBytes()), read);
// Should fail on deserialized vertex prop.
assertFalse(approximateGraphsCheck(sampleGraph1, read));
}
}
/**
* Asserts the approximateGraphsChecks function fails when expected. Edge ids.
*/
@Test
public void shouldLoseTypesWithGraphSONNoTypesForEdgeIds() throws IOException {
final GraphWriter writer = getWriter(noTypesMapperV2d0);
final GraphReader reader = getReader(noTypesMapperV2d0);
final TinkerGraph sampleGraph1 = TinkerGraph.open();
TinkerFactory.generateModern(sampleGraph1);
final Vertex v1 = sampleGraph1.addVertex(T.id, 100, "name", "kevin");
v1.addEdge("hello", sampleGraph1.traversal().V().has("name", "marko").next(), T.id, 101L);
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeGraph(out, sampleGraph1);
final String json = out.toString();
final TinkerGraph read = TinkerGraph.open();
reader.readGraph(new ByteArrayInputStream(json.getBytes()), read);
// Should fail on deserialized edge Id.
assertFalse(approximateGraphsCheck(sampleGraph1, read));
}
}
/**
* Asserts the approximateGraphsChecks function fails when expected. Edge props.
*/
@Test
public void shouldLoseTypesWithGraphSONNoTypesForEdgeProps() throws IOException {
final GraphWriter writer = getWriter(noTypesMapperV2d0);
final GraphReader reader = getReader(noTypesMapperV2d0);
final Graph sampleGraph1 = TinkerFactory.createModern();
final Vertex v1 = sampleGraph1.addVertex(T.id, 100, "name", "kevin");
v1.addEdge("hello", sampleGraph1.traversal().V().has("name", "marko").next(), T.id, 101,
"uuid", UUID.randomUUID());
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeGraph(out, sampleGraph1);
final String json = out.toString();
final TinkerGraph read = TinkerGraph.open();
reader.readGraph(new ByteArrayInputStream(json.getBytes()), read);
// Should fail on deserialized edge prop.
assertFalse(approximateGraphsCheck(sampleGraph1, read));
}
}
/**
* Those kinds of types are declared differently in the GraphSON type deserializer, check that all are handled
* properly.
*/
@Test
public void shouldKeepTypesWhenDeserializingSerializedTinkerGraph() throws IOException {
final TinkerGraph tg = TinkerGraph.open();
final Vertex v = tg.addVertex("vertexTest");
final UUID uuidProp = UUID.randomUUID();
final Duration durationProp = Duration.ofHours(3);
final Long longProp = 2L;
final ByteBuffer byteBufferProp = ByteBuffer.wrap("testbb".getBytes());
final InetAddress inetAddressProp = InetAddress.getByName("10.10.10.10");
// One Java util type natively supported by Jackson
v.property("uuid", uuidProp);
// One custom time type added by the GraphSON module
v.property("duration", durationProp);
// One Java native type not handled by JSON natively
v.property("long", longProp);
// One Java util type added by GraphSON
v.property("bytebuffer", byteBufferProp);
v.property("inetaddress", inetAddressProp);
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeGraph(out, tg);
final String json = out.toString();
final TinkerGraph read = TinkerGraph.open();
reader.readGraph(new ByteArrayInputStream(json.getBytes()), read);
final Vertex vRead = read.traversal().V().hasLabel("vertexTest").next();
assertEquals(vRead.property("uuid").value(), uuidProp);
assertEquals(vRead.property("duration").value(), durationProp);
assertEquals(vRead.property("long").value(), longProp);
assertEquals(vRead.property("bytebuffer").value(), byteBufferProp);
assertEquals(vRead.property("inetaddress").value(), inetAddressProp);
}
}
@Test
public void deserializersTestsVertex() {
final TinkerGraph tg = TinkerGraph.open();
final Vertex v = tg.addVertex("vertexTest");
v.property("born", LocalDateTime.of(1971, 1, 2, 20, 50));
v.property("dead", LocalDateTime.of(1971, 1, 7, 20, 50));
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, v);
final String json = out.toString();
// Object works, because there's a type in the payload now
// Vertex.class would work as well
// Anything else would not because we check the type in param here with what's in the JSON, for safety.
final Vertex vRead = (Vertex)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
assertEquals(v, vRead);
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
public void deserializersTestsEdge() {
final TinkerGraph tg = TinkerGraph.open();
final Vertex v = tg.addVertex("vertexTest");
final Vertex v2 = tg.addVertex("vertexTest");
final Edge ed = v.addEdge("knows", v2, "time", LocalDateTime.now());
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, ed);
final String json = out.toString();
// Object works, because there's a type in the payload now
// Edge.class would work as well
// Anything else would not because we check the type in param here with what's in the JSON, for safety.
final Edge eRead = (Edge)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
assertEquals(ed, eRead);
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
public void deserializersTestsTinkerGraph() {
final TinkerGraph tg = TinkerGraph.open();
final Vertex v = tg.addVertex("vertexTest");
final Vertex v2 = tg.addVertex("vertexTest");
v.addEdge("knows", v2);
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, tg);
final String json = out.toString();
final Graph gRead = (Graph)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
assertTrue(approximateGraphsCheck(tg, gRead));
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
public void deserializersTestsProperty() {
final TinkerGraph tg = TinkerGraph.open();
final Vertex v = tg.addVertex("vertexTest");
final Vertex v2 = tg.addVertex("vertexTest");
final Edge ed = v.addEdge("knows", v2);
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final Property prop = ed.property("since", Year.parse("1993"));
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, prop);
final String json = out.toString();
final Property pRead = (Property)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
//can't use equals here, because pRead is detached, its parent element has not been intentionally
//serialized and "equals()" checks that.
assertTrue(prop.key().equals(pRead.key()) && prop.value().equals(pRead.value()));
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
public void deserializersTestsVertexProperty() {
final TinkerGraph tg = TinkerGraph.open();
final Vertex v = tg.addVertex("vertexTest");
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final VertexProperty prop = v.property("born", LocalDateTime.of(1971, 1, 2, 20, 50));
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, prop);
final String json = out.toString();
final VertexProperty vPropRead = (VertexProperty)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
//only classes and ids are checked, that's ok, full vertex property ser/de
//is checked elsewhere.
assertEquals(prop, vPropRead);
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
public void deserializersTestsPath() {
final TinkerGraph tg = TinkerFactory.createModern();
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final Path p = tg.traversal().V(1).as("a").has("name").as("b").
out("knows").out("created").as("c").
has("name", "ripple").values("name").as("d").
identity().as("e").path().next();
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, p);
final String json = out.toString();
final Path pathRead = (Path)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
for (int i = 0; i < p.objects().size(); i++) {
final Object o = p.objects().get(i);
final Object oRead = pathRead.objects().get(i);
assertEquals(o, oRead);
}
for (int i = 0; i < p.labels().size(); i++) {
final Set<String> o = p.labels().get(i);
final Set<String> oRead = pathRead.labels().get(i);
assertEquals(o, oRead);
}
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
public void deserializersTestsMetrics() {
final TinkerGraph tg = TinkerFactory.createModern();
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final TraversalMetrics tm = tg.traversal().V(1).as("a").has("name").as("b").
out("knows").out("created").as("c").
has("name", "ripple").values("name").as("d").
identity().as("e").profile().next();
final MutableMetrics m = new MutableMetrics(tm.getMetrics(0));
// making sure nested metrics are included in serde
m.addNested(new MutableMetrics(tm.getMetrics(1)));
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, m);
final String json = out.toString();
final Metrics metricsRead = (Metrics)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
// toString should be enough to compare Metrics
assertTrue(m.toString().equals(metricsRead.toString()));
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
public void deserializersTestsTraversalMetrics() {
final TinkerGraph tg = TinkerFactory.createModern();
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final TraversalMetrics tm = tg.traversal().V(1).as("a").has("name").as("b").
out("knows").out("created").as("c").
has("name", "ripple").values("name").as("d").
identity().as("e").profile().next();
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, tm);
final String json = out.toString();
final TraversalMetrics traversalMetricsRead = (TraversalMetrics)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
// toString should be enough to compare TraversalMetrics
assertTrue(tm.toString().equals(traversalMetricsRead.toString()));
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
@Test
@org.junit.Ignore("https://issues.apache.org/jira/browse/TINKERPOP-1509")
public void deserializersTestsTree() {
final TinkerGraph tg = TinkerFactory.createModern();
final GraphWriter writer = getWriter(defaultMapperV2d0);
final GraphReader reader = getReader(defaultMapperV2d0);
final Tree t = tg.traversal().V().out().out().tree().next();
try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
writer.writeObject(out, t);
final String json = out.toString();
final Tree treeRead = (Tree)reader.readObject(new ByteArrayInputStream(json.getBytes()), Object.class);
//Map's equals should check each component of the tree recursively
//on each it will call "equals()" which for Vertices will compare ids, which
//is ok. Complete vertex deser is checked elsewhere.
assertEquals(t, treeRead);
} catch (IOException e) {
e.printStackTrace();
fail("Should not have thrown exception: " + e.getMessage());
}
}
private GraphWriter getWriter(Mapper paramMapper) {
return GraphSONWriter.build().mapper(paramMapper).create();
}
private GraphReader getReader(Mapper paramMapper) {
return GraphSONReader.build().mapper(paramMapper).create();
}
/**
* Checks sequentially vertices and edges of both graphs. Will check sequentially Vertex IDs, Vertex Properties IDs
* and values and classes. Then same for edges. To use when serializing a Graph and deserializing the supposedly
* same Graph.
*/
private boolean approximateGraphsCheck(Graph g1, Graph g2) {
final Iterator<Vertex> itV = g1.vertices();
final Iterator<Vertex> itVRead = g2.vertices();
while (itV.hasNext()) {
final Vertex v = itV.next();
final Vertex vRead = itVRead.next();
// Will only check IDs but that's 'good' enough.
if (!v.equals(vRead)) {
return false;
}
final Iterator itVP = v.properties();
final Iterator itVPRead = vRead.properties();
while (itVP.hasNext()) {
final VertexProperty vp = (VertexProperty) itVP.next();
final VertexProperty vpRead = (VertexProperty) itVPRead.next();
if (!vp.value().equals(vpRead.value())
|| !vp.equals(vpRead)) {
return false;
}
}
}
final Iterator<Edge> itE = g1.edges();
final Iterator<Edge> itERead = g2.edges();
while (itE.hasNext()) {
final Edge e = itE.next();
final Edge eRead = itERead.next();
// Will only check IDs but that's good enough.
if (!e.equals(eRead)) {
return false;
}
final Iterator itEP = e.properties();
final Iterator itEPRead = eRead.properties();
while (itEP.hasNext()) {
final Property ep = (Property) itEP.next();
final Property epRead = (Property) itEPRead.next();
if (!ep.value().equals(epRead.value())
|| !ep.equals(epRead)) {
return false;
}
}
}
return true;
}
}