2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.aai.introspection.sideeffect;
23 import static org.hamcrest.MatcherAssert.assertThat;
24 import static org.hamcrest.Matchers.is;
25 import static org.hamcrest.Matchers.not;
26 import static org.junit.Assert.*;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.when;
30 import java.io.UnsupportedEncodingException;
32 import java.net.URISyntaxException;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.List;
36 import java.util.UUID;
38 import javax.ws.rs.core.MultivaluedMap;
40 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
41 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
42 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
43 import org.apache.tinkerpop.gremlin.structure.Graph;
44 import org.apache.tinkerpop.gremlin.structure.Vertex;
45 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
46 import org.janusgraph.core.Cardinality;
47 import org.janusgraph.core.JanusGraph;
48 import org.janusgraph.core.JanusGraphFactory;
49 import org.janusgraph.core.schema.JanusGraphManagement;
51 import org.junit.experimental.categories.Category;
52 import org.junit.rules.ExpectedException;
53 import org.junit.runner.RunWith;
54 import org.junit.runners.Parameterized;
55 import org.mockito.Mock;
56 import org.mockito.MockitoAnnotations;
57 import org.onap.aai.DataLinkSetup;
58 import org.onap.aai.TinkerpopUpgrade;
59 import org.onap.aai.db.props.AAIProperties;
60 import org.onap.aai.edges.enums.EdgeProperty;
61 import org.onap.aai.exceptions.AAIException;
62 import org.onap.aai.introspection.Introspector;
63 import org.onap.aai.introspection.Loader;
64 import org.onap.aai.introspection.LoaderUtil;
65 import org.onap.aai.introspection.ModelType;
66 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
67 import org.onap.aai.parsers.query.QueryParser;
68 import org.onap.aai.query.builder.QueryBuilder;
69 import org.onap.aai.query.builder.TraversalQuery;
70 import org.onap.aai.restcore.util.URITools;
71 import org.onap.aai.serialization.db.DBSerializer;
72 import org.onap.aai.serialization.engines.JanusGraphDBEngine;
73 import org.onap.aai.serialization.engines.QueryStyle;
74 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
76 @Category(TinkerpopUpgrade.class)
77 @RunWith(value = Parameterized.class)
78 public class DataLinkTest extends DataLinkSetup {
80 private static JanusGraph graph;
81 private final static ModelType introspectorFactoryType = ModelType.MOXY;
82 private static Loader loader;
83 private static TransactionalGraphEngine dbEngine;
85 private QueryParser parser;
89 private VertexProperty<String> prop;
91 public ExpectedException thrown = ExpectedException.none();
93 @Parameterized.Parameter
94 public QueryStyle queryStyle;
96 @Parameterized.Parameters(name = "QueryStyle.{0}")
97 public static Collection<Object[]> data() {
98 return Arrays.asList(new Object[][] {{QueryStyle.TRAVERSAL}});
102 public static void setup() {
103 graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open();
104 JanusGraphManagement graphMgt = graph.openManagement();
105 graphMgt.makePropertyKey(AAIProperties.CREATED_TS).dataType(Long.class).cardinality(Cardinality.SINGLE).make();
106 graphMgt.makePropertyKey(AAIProperties.LAST_MOD_TS).dataType(Long.class).cardinality(Cardinality.SINGLE).make();
109 graph.traversal().addV().property("aai-node-type", "vpn-binding").property("vpn-id", "addKey")
110 .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/addKey")
111 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
112 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
113 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
114 .as("v1").addV().property("aai-node-type", "vpn-binding").property("vpn-id", "modifyKey")
115 .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/modifyKey")
116 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
117 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
118 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
119 .as("v2").addV().property("aai-node-type", "route-target")
120 .property("global-route-target", "modifyTargetKey").property("route-target-role", "modifyRoleKey")
121 .property("linked", true)
122 .property(AAIProperties.AAI_URI,
123 "/network/vpn-bindings/vpn-binding/modifyKey/route-targets/route-target/modifyTargetKey/modifyRoleKey")
124 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
125 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
126 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
127 .as("v3").addE("org.onap.relationships.inventory.BelongsTo").to("v2").from("v3")
128 .property(EdgeProperty.CONTAINS.toString(), true).addV().property("aai-node-type", "vpn-binding")
129 .property("vpn-id", "deleteKey")
130 .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/deleteKey")
131 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
132 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
133 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
134 .as("v4").addV().property("aai-node-type", "route-target")
135 .property("global-route-target", "deleteTargetKey").property("route-target-role", "deleteRoleKey")
136 .property("linked", true)
137 .property(AAIProperties.AAI_URI,
138 "/network/vpn-bindings/vpn-binding/deleteKey/route-targets/route-target/deleteTargetKey/deleteRoleKey")
139 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
140 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
141 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
142 .as("v5").addE("org.onap.relationships.inventory.BelongsTo").to("v4").from("v5")
143 .property(EdgeProperty.CONTAINS.toString(), true).addV().property("aai-node-type", "vpn-binding")
144 .property("vpn-id", "getKey")
145 .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/getKey")
146 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
147 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
148 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
149 .as("v6").addV().property("aai-node-type", "route-target")
150 .property("global-route-target", "getTargetKey").property("route-target-role", "getRoleKey")
151 .property("linked", true)
152 .property(AAIProperties.AAI_URI,
153 "/network/vpn-bindings/vpn-binding/getKey/route-targets/route-target/getTargetKeyNoLink/getRoleKeyNoLink")
154 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
155 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
156 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
157 .as("v7").addE("org.onap.relationships.inventory.BelongsTo").to("v6").from("v7")
158 .property(EdgeProperty.CONTAINS.toString(), true).addV().property("aai-node-type", "vpn-binding")
159 .property("vpn-id", "getKeyNoLink")
160 .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/getKeyNoLink")
161 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
162 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
163 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
164 .as("v8").addV().property("aai-node-type", "route-target")
165 .property("global-route-target", "getTargetKeyNoLink").property("route-target-role", "getRoleKeyNoLink")
166 .property(AAIProperties.AAI_URI,
167 "/network/vpn-bindings/vpn-binding/getKeyNoLink/route-targets/route-target/getTargetKeyNoLink/getRoleKeyNoLink")
168 .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()).property(AAIProperties.CREATED_TS, 123)
169 .property(AAIProperties.SOURCE_OF_TRUTH, "sot").property(AAIProperties.RESOURCE_VERSION, "123")
170 .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot").property(AAIProperties.LAST_MOD_TS, 333)
171 .as("v9").addE("org.onap.relationships.inventory.BelongsTo").to("v8").from("v9")
172 .property(EdgeProperty.CONTAINS.toString(), true).next();
178 public static void tearDown() {
179 graph.tx().rollback();
184 public void initMock() {
185 loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, schemaVersions.getDefaultVersion());
186 MockitoAnnotations.openMocks(this);
187 dbEngine = new JanusGraphDBEngine(queryStyle, loader);
191 public void verifyCreationOfVertex()
192 throws AAIException, UnsupportedEncodingException, IllegalArgumentException, SecurityException {
194 final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion());
195 final Introspector obj = loader.introspectorFromName("vpn-binding");
196 obj.setValue("vpn-id", "addKey");
197 obj.setValue("global-route-target", "key1");
198 obj.setValue("route-target-role", "key2");
199 TransactionalGraphEngine spy = spy(dbEngine);
200 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
201 Graph g = graph.newTransaction();
202 GraphTraversalSource traversal = g.traversal();
203 when(spy.asAdmin()).thenReturn(adminSpy);
204 when(adminSpy.getTraversalSource()).thenReturn(traversal);
205 when(spy.tx()).thenReturn(g);
206 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
207 when(prop.orElse(null)).thenReturn(obj.getURI());
208 DBSerializer serializer =
209 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
210 SideEffectRunner runner =
211 new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkWriter.class).build();
213 runner.execute(obj, self);
215 assertTrue("route-target vertex found", traversal.V().has(AAIProperties.NODE_TYPE, "route-target")
216 .has("global-route-target", "key1").has("route-target-role", "key2").has("linked", true).hasNext());
222 * This is more directly testing the modification mechanism (see verifyModificationOfVertex test)
225 public void linkQuery() throws UnsupportedEncodingException, AAIException, URISyntaxException {
226 Graph g = graph.newTransaction();
227 GraphTraversalSource source = g.traversal();
228 final Loader loader = LoaderUtil.getLatestVersion();
229 URI uri = new URI("/network/vpn-bindings/vpn-binding/modifyKey/route-targets/route-target/modifyTargetKey2/modifyRoleKey2");
230 MultivaluedMap<String, String> map = URITools.getQueryMap(uri);
231 GraphTraversal<Vertex, Vertex> traversal = __.<Vertex>start();
233 QueryParser uriQuery = dbEngine.getQueryBuilder(this.queryStyle, loader, source, traversal).createQueryFromURI(uri, map);
234 // assertEquals(6, traversal.asAdmin().getSteps().size());
235 // assertEquals("HasStep([vpn-id.eq(modifyKey)])", traversal.asAdmin().getSteps().get(0).toString());
236 // assertEquals("HasStep([aai-node-type.eq(vpn-binding)])", traversal.asAdmin().getSteps().get(1).toString());
237 // assertEquals("VertexStep(IN,[org.onap.relationships.inventory.BelongsTo],vertex)", traversal.asAdmin().getSteps().get(2).toString());
238 // assertEquals("HasStep([aai-node-type.eq(route-target)])", traversal.asAdmin().getSteps().get(3).toString());
239 // assertEquals("HasStep([global-route-target.eq(modifyTargetKey2)])", traversal.asAdmin().getSteps().get(4).toString());
240 // assertEquals("HasStep([route-target-role.eq(modifyRoleKey2)])", traversal.asAdmin().getSteps().get(5).toString());
241 List<Vertex> results = uriQuery.getQueryBuilder().toList();
243 assertEquals(0, results.size());
244 // assertEquals(traversal.asAdmin().getSteps().size(), 6);
245 // assertEquals("HasStep([vpn-id.eq(modifyKey)])", traversal.asAdmin().getSteps().get(0).toString());
246 // assertEquals("HasStep([aai-node-type.eq(vpn-binding)])", traversal.asAdmin().getSteps().get(1).toString());
247 // assertEquals("VertexStep(IN,[org.onap.relationships.inventory.BelongsTo],vertex)", traversal.asAdmin().getSteps().get(2).toString());
248 // assertEquals("HasStep([aai-node-type.eq(route-target)])", traversal.asAdmin().getSteps().get(3).toString());
249 // assertEquals("HasStep([global-route-target.eq(modifyTargetKey2)])", traversal.asAdmin().getSteps().get(4).toString());
250 // assertEquals("HasStep([route-target-role.eq(modifyRoleKey2)])", traversal.asAdmin().getSteps().get(5).toString());
252 QueryBuilder<Vertex> queryBuilder = uriQuery.getQueryBuilder().getContainerQuery()
253 .getVerticesByProperty(AAIProperties.LINKED, true);
254 List<Vertex> linkedVertices = queryBuilder.toList();
255 assertEquals(1, linkedVertices.size());
259 public void verifyModificationOfVertex()
260 throws AAIException, UnsupportedEncodingException, IllegalArgumentException, SecurityException {
262 final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion());
263 final Introspector obj = loader.introspectorFromName("vpn-binding");
264 obj.setValue("vpn-id", "modifyKey");
265 obj.setValue("global-route-target", "modifyTargetKey2");
266 obj.setValue("route-target-role", "modifyRoleKey2");
267 TransactionalGraphEngine spy = spy(dbEngine);
268 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
269 Graph g = graph.newTransaction();
270 GraphTraversalSource traversal = g.traversal();
272 when(spy.asAdmin()).thenReturn(adminSpy);
273 when(adminSpy.getTraversalSource()).thenReturn(traversal);
274 when(spy.tx()).thenReturn(g);
275 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
276 when(prop.orElse(null)).thenReturn(obj.getURI());
277 DBSerializer serializer =
278 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
279 SideEffectRunner runner =
280 new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkWriter.class).build();
281 runner.execute(obj, self);
283 assertThat("new route-target vertex found with/or without link",
284 traversal.V().has(AAIProperties.NODE_TYPE, "route-target")
285 .has("global-route-target", "modifyTargetKey2").has("route-target-role", "modifyRoleKey2")
288 assertThat("new route-target vertex found",
289 traversal.V().has(AAIProperties.NODE_TYPE, "route-target")
290 .has("global-route-target", "modifyTargetKey2").has("route-target-role", "modifyRoleKey2")
291 .has("linked", true).hasNext(),
293 assertThat("previous link removed",
294 traversal.V().has(AAIProperties.NODE_TYPE, "route-target").has("global-route-target", "modifyTargetKey")
295 .has("route-target-role", "modifyRoleKey").has("linked").hasNext(),
297 assertThat("previous vertex still exists", traversal.V().has(AAIProperties.NODE_TYPE, "route-target")
298 .has("global-route-target", "modifyTargetKey").has("route-target-role", "modifyRoleKey").hasNext(),
305 public void verifyDeleteOfVertex() throws Exception {
307 final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion());
308 final Introspector obj = loader.introspectorFromName("vpn-binding");
309 obj.setValue("vpn-id", "deleteKey");
310 TransactionalGraphEngine spy = spy(dbEngine);
311 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
312 Graph g = graph.newTransaction();
313 GraphTraversalSource traversal = g.traversal();
314 when(spy.asAdmin()).thenReturn(adminSpy);
315 when(adminSpy.getTraversalSource()).thenReturn(traversal);
316 when(adminSpy.getReadOnlyTraversalSource()).thenReturn(traversal);
317 when(spy.tx()).thenReturn(g);
318 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
319 when(prop.orElse(null)).thenReturn(obj.getURI());
320 DBSerializer serializer =
321 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
322 SideEffectRunner runner =
323 new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkWriter.class).build();
325 runner.execute(obj, self);
327 assertFalse("route-target vertex not found",
328 traversal.V().has(AAIProperties.NODE_TYPE, "route-target").has("global-route-target", "deleteTargetKey")
329 .has("route-target-role", "deleteRoleKey").has("linked", true).hasNext());
336 public void verifyPropertyPopulation() throws Exception {
338 final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion());
339 final Introspector obj = loader.introspectorFromName("vpn-binding");
340 obj.setValue("vpn-id", "getKey");
341 TransactionalGraphEngine spy = spy(dbEngine);
342 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
343 Graph g = graph.newTransaction();
344 GraphTraversalSource traversal = g.traversal();
345 when(spy.asAdmin()).thenReturn(adminSpy);
346 when(adminSpy.getTraversalSource()).thenReturn(traversal);
347 when(spy.tx()).thenReturn(g);
348 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
349 when(prop.orElse(null)).thenReturn(obj.getURI());
350 DBSerializer serializer =
351 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
352 SideEffectRunner runner =
353 new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkReader.class).build();
355 runner.execute(obj, self);
357 assertTrue("both properties have been populated in target object",
358 obj.getValue("global-route-target").equals("getTargetKey")
359 && obj.getValue("route-target-role").equals("getRoleKey"));
365 public void verifyPropertyPopulationWithV10OnlyPut()
366 throws AAIException, UnsupportedEncodingException, IllegalArgumentException, SecurityException {
367 final Introspector obj = loader.introspectorFromName("vpn-binding");
368 obj.setValue("vpn-id", "getKeyNoLink");
369 final Introspector routeTargets = loader.introspectorFromName("route-targets");
370 obj.setValue("route-targets", routeTargets.getUnderlyingObject());
371 List<Object> targets = routeTargets.getValue("route-target");
372 final Introspector routeTargetOne = loader.introspectorFromName("route-target");
373 routeTargetOne.setValue("global-route-target", "getTargetKeyNoLink");
374 routeTargetOne.setValue("route-target-role", "getRoleKeyNoLink");
375 targets.add(routeTargetOne.getUnderlyingObject());
376 final Introspector routeTargetTwo = loader.introspectorFromName("route-target");
377 routeTargetTwo.setValue("global-route-target", "getTargetKeyNoLink2");
378 routeTargetTwo.setValue("route-target-role", "getRoleKeyNoLink2");
379 targets.add(routeTargetTwo.getUnderlyingObject());
380 TransactionalGraphEngine spy = spy(dbEngine);
381 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
382 Graph g = graph.newTransaction();
383 GraphTraversalSource traversal = g.traversal();
384 when(spy.tx()).thenReturn(g);
385 when(spy.asAdmin()).thenReturn(adminSpy);
386 when(adminSpy.getTraversalSource()).thenReturn(traversal);
387 when(spy.tx()).thenReturn(g);
388 when(parser.isDependent()).thenReturn(false);
389 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
390 when(prop.orElse(null)).thenReturn(obj.getURI());
391 DBSerializer serializer =
392 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
393 Vertex v = serializer.createNewVertex(obj);
394 serializer.serializeToDb(obj, v, parser, obj.getURI(), "testing");
395 Vertex routeTargetOneV = traversal.V().has("global-route-target", "getTargetKeyNoLink").next();
396 Vertex routeTargetTwoV = traversal.V().has("global-route-target", "getTargetKeyNoLink2").next();
398 assertEquals("first route target put has linked", true,
399 routeTargetOneV.property(AAIProperties.LINKED).orElse(false));
400 assertEquals("second route target put does not have linked", false,
401 routeTargetTwoV.property(AAIProperties.LINKED).orElse(false));