-
Notifications
You must be signed in to change notification settings - Fork 789
/
GraphTraversalSourceTest.java
154 lines (139 loc) · 7.58 KB
/
GraphTraversalSourceTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* 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.process.traversal.dsl.graph;
import org.apache.commons.configuration2.MapConfiguration;
import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
import org.apache.tinkerpop.gremlin.util.tools.CollectionFactory;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
public class GraphTraversalSourceTest {
private static final GraphTraversalSource g = traversal().withEmbedded(EmptyGraph.instance());
@Test
public void shouldCloseRemoteConnectionOnWithRemote() throws Exception {
final RemoteConnection mock = mock(RemoteConnection.class);
final GraphTraversalSource g = traversal().withRemote(mock);
g.close();
verify(mock, times(1)).close();
}
@Test
public void shouldSupportMapBasedStrategies() throws Exception {
GraphTraversalSource g = EmptyGraph.instance().traversal();
assertFalse(g.getStrategies().getStrategy(SubgraphStrategy.class).isPresent());
g = g.withStrategies(SubgraphStrategy.create(new MapConfiguration(new HashMap<String, Object>() {{
put("vertices", __.hasLabel("person"));
put("vertexProperties", __.limit(0));
put("edges", __.hasLabel("knows"));
}})));
assertTrue(g.getStrategies().getStrategy(SubgraphStrategy.class).isPresent());
g = g.withoutStrategies(SubgraphStrategy.class);
assertFalse(g.getStrategies().getStrategy(SubgraphStrategy.class).isPresent());
//
assertFalse(g.getStrategies().getStrategy(ReadOnlyStrategy.class).isPresent());
g = g.withStrategies(ReadOnlyStrategy.instance());
assertTrue(g.getStrategies().getStrategy(ReadOnlyStrategy.class).isPresent());
g = g.withoutStrategies(ReadOnlyStrategy.class);
assertFalse(g.getStrategies().getStrategy(ReadOnlyStrategy.class).isPresent());
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailAddVWithNullVertexLabel() {
g.addV((String) null);
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailAddVWithNullVertexLabelTraversal() {
g.addV((Traversal<?, String>) null);
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailMergeEForBadInput() {
g.mergeE(CollectionFactory.asMap(T.value, "nope"));
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailMergeVForBadInput() {
g.mergeV(CollectionFactory.asMap(T.value, "nope"));
}
/**
* This test demonstrates how one method for using Mockito to mock {@code g} to help with unit testing
* applications where the logic of the query itself does not need to be validated, but rather surrounding
* logic of the application. It is really important to note that all internal processing of the query is
* ignored under this model and no TinkerPop code is executed so even invalid queries that are incorrect
* will return the static data encoded to the mock.
*/
@Test
public void shouldDemonstrateMocking() {
// intercept the terminating step of toList() and return whatever results needed for the nature of
// the test. you could just have easily mocked next() or other terminators. they key to this model lies
// in all other methods simply returning the mock itself so that the chaining aspect of hooking steps
// together continues to return the mock GraphTraversal. be sure to mock whatever terminator that you
// intend to use or it will fall into that default path and there will likely be an error or other
// unexpected behavior
final GraphTraversal<?,?> mockTraversal = mock(GraphTraversal.class, invocation -> {
if (invocation.getMethod().getName().equals("toList"))
return Arrays.asList("peter", "lop", "josh");
else
return invocation.getMock();
});
// the mock of GraphTraversalSource is basically "g". Your test would want to inject this "g" to your
// application logic to use rather than a real one that is probably produced by traversal().withRemote(...).
// the mock returns either itself or the mock of GraphTraversal depending on the return type of the method
// called. all other calls go to the real method. that could result in errors but if you're just testing the
// Gremlin language (and that's the use case here) this configuration should be sufficient.
//
// as an aside, it may be tempting to try to mock Graph so that it can be given directly to
// traversal().withEmbedded(...) but that turns out to be hard based on how the construction happens in there
// with reflection that seems to bypass the mock attempts. this approach seems simpler but just requires your
// application logic to take the mock "g" somehow.
final GraphTraversalSource mockG = mock(GraphTraversalSource.class, invocation -> {
final Class<?> returnType = invocation.getMethod().getReturnType();
if (returnType.isAssignableFrom(GraphTraversalSource.class)) {
return invocation.getMock();
} else if (returnType.isAssignableFrom(GraphTraversal.class)) {
return mockTraversal;
} else {
return invocation.callRealMethod();
}
});
final GraphTraversalSource g = mockG; // traversal().withRemote(...)
final List<Object> l = g.V().values("name").order().by(Order.shuffle).limit(3).toList();
assertThat(l, containsInAnyOrder("peter", "lop", "josh"));
}
}