2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright © 2024 Deutsche Telekom.
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
23 package org.onap.aai.introspection.sideeffect;
25 import static org.hamcrest.MatcherAssert.assertThat;
26 import static org.hamcrest.Matchers.is;
27 import static org.hamcrest.Matchers.not;
28 import static org.junit.Assert.*;
29 import static org.mockito.Mockito.spy;
30 import static org.mockito.Mockito.when;
32 import java.io.UnsupportedEncodingException;
34 import java.net.URISyntaxException;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.List;
38 import java.util.UUID;
40 import javax.ws.rs.core.MultivaluedMap;
42 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
43 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
44 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
45 import org.apache.tinkerpop.gremlin.structure.Graph;
46 import org.apache.tinkerpop.gremlin.structure.Vertex;
47 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
48 import org.janusgraph.core.Cardinality;
49 import org.janusgraph.core.JanusGraph;
50 import org.janusgraph.core.JanusGraphFactory;
51 import org.janusgraph.core.schema.JanusGraphManagement;
53 import org.junit.experimental.categories.Category;
54 import org.junit.rules.ExpectedException;
55 import org.junit.runner.RunWith;
56 import org.junit.runners.Parameterized;
57 import org.mockito.Mock;
58 import org.mockito.MockitoAnnotations;
59 import org.onap.aai.DataLinkSetup;
60 import org.onap.aai.TinkerpopUpgrade;
61 import org.onap.aai.db.props.AAIProperties;
62 import org.onap.aai.edges.enums.EdgeProperty;
63 import org.onap.aai.exceptions.AAIException;
64 import org.onap.aai.introspection.Introspector;
65 import org.onap.aai.introspection.Loader;
66 import org.onap.aai.introspection.LoaderUtil;
67 import org.onap.aai.introspection.ModelType;
68 import org.onap.aai.parsers.query.QueryParser;
69 import org.onap.aai.query.builder.QueryBuilder;
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},{QueryStyle.TRAVERSAL_URI}});
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 List<Vertex> results = uriQuery.getQueryBuilder().toList();
236 assertEquals(0, results.size());
238 QueryBuilder<Vertex> queryBuilder = uriQuery.getQueryBuilder().getContainerQuery()
239 .getVerticesByProperty(AAIProperties.LINKED, true);
240 List<Vertex> linkedVertices = queryBuilder.toList();
241 assertEquals(1, linkedVertices.size());
245 public void verifyModificationOfVertex()
246 throws AAIException, UnsupportedEncodingException, IllegalArgumentException, SecurityException {
248 final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion());
249 final Introspector obj = loader.introspectorFromName("vpn-binding");
250 obj.setValue("vpn-id", "modifyKey");
251 obj.setValue("global-route-target", "modifyTargetKey2");
252 obj.setValue("route-target-role", "modifyRoleKey2");
253 TransactionalGraphEngine spy = spy(dbEngine);
254 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
255 Graph g = graph.newTransaction();
256 GraphTraversalSource traversal = g.traversal();
258 when(spy.asAdmin()).thenReturn(adminSpy);
259 when(adminSpy.getTraversalSource()).thenReturn(traversal);
260 when(spy.tx()).thenReturn(g);
261 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
262 when(prop.orElse(null)).thenReturn(obj.getURI());
263 DBSerializer serializer =
264 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
265 SideEffectRunner runner =
266 new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkWriter.class).build();
267 runner.execute(obj, self);
269 assertThat("new route-target vertex found with/or without link",
270 traversal.V().has(AAIProperties.NODE_TYPE, "route-target")
271 .has("global-route-target", "modifyTargetKey2").has("route-target-role", "modifyRoleKey2")
274 assertThat("new route-target vertex found",
275 traversal.V().has(AAIProperties.NODE_TYPE, "route-target")
276 .has("global-route-target", "modifyTargetKey2").has("route-target-role", "modifyRoleKey2")
277 .has("linked", true).hasNext(),
279 assertThat("previous link removed",
280 traversal.V().has(AAIProperties.NODE_TYPE, "route-target").has("global-route-target", "modifyTargetKey")
281 .has("route-target-role", "modifyRoleKey").has("linked").hasNext(),
283 assertThat("previous vertex still exists", traversal.V().has(AAIProperties.NODE_TYPE, "route-target")
284 .has("global-route-target", "modifyTargetKey").has("route-target-role", "modifyRoleKey").hasNext(),
291 public void verifyDeleteOfVertex() throws Exception {
293 final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion());
294 final Introspector obj = loader.introspectorFromName("vpn-binding");
295 obj.setValue("vpn-id", "deleteKey");
296 TransactionalGraphEngine spy = spy(dbEngine);
297 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
298 Graph g = graph.newTransaction();
299 GraphTraversalSource traversal = g.traversal();
300 when(spy.asAdmin()).thenReturn(adminSpy);
301 when(adminSpy.getTraversalSource()).thenReturn(traversal);
302 when(adminSpy.getReadOnlyTraversalSource()).thenReturn(traversal);
303 when(spy.tx()).thenReturn(g);
304 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
305 when(prop.orElse(null)).thenReturn(obj.getURI());
306 DBSerializer serializer =
307 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
308 SideEffectRunner runner =
309 new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkWriter.class).build();
311 runner.execute(obj, self);
313 assertFalse("route-target vertex not found",
314 traversal.V().has(AAIProperties.NODE_TYPE, "route-target").has("global-route-target", "deleteTargetKey")
315 .has("route-target-role", "deleteRoleKey").has("linked", true).hasNext());
322 public void verifyPropertyPopulation() throws Exception {
324 final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion());
325 final Introspector obj = loader.introspectorFromName("vpn-binding");
326 obj.setValue("vpn-id", "getKey");
327 TransactionalGraphEngine spy = spy(dbEngine);
328 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
329 Graph g = graph.newTransaction();
330 GraphTraversalSource traversal = g.traversal();
331 when(spy.asAdmin()).thenReturn(adminSpy);
332 when(adminSpy.getTraversalSource()).thenReturn(traversal);
333 when(spy.tx()).thenReturn(g);
334 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
335 when(prop.orElse(null)).thenReturn(obj.getURI());
336 DBSerializer serializer =
337 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
338 SideEffectRunner runner =
339 new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkReader.class).build();
341 runner.execute(obj, self);
343 assertTrue("both properties have been populated in target object",
344 obj.getValue("global-route-target").equals("getTargetKey")
345 && obj.getValue("route-target-role").equals("getRoleKey"));
351 public void verifyPropertyPopulationWithV10OnlyPut()
352 throws AAIException, UnsupportedEncodingException, IllegalArgumentException, SecurityException {
353 final Introspector obj = loader.introspectorFromName("vpn-binding");
354 obj.setValue("vpn-id", "getKeyNoLink");
355 final Introspector routeTargets = loader.introspectorFromName("route-targets");
356 obj.setValue("route-targets", routeTargets.getUnderlyingObject());
357 List<Object> targets = routeTargets.getValue("route-target");
358 final Introspector routeTargetOne = loader.introspectorFromName("route-target");
359 routeTargetOne.setValue("global-route-target", "getTargetKeyNoLink");
360 routeTargetOne.setValue("route-target-role", "getRoleKeyNoLink");
361 targets.add(routeTargetOne.getUnderlyingObject());
362 final Introspector routeTargetTwo = loader.introspectorFromName("route-target");
363 routeTargetTwo.setValue("global-route-target", "getTargetKeyNoLink2");
364 routeTargetTwo.setValue("route-target-role", "getRoleKeyNoLink2");
365 targets.add(routeTargetTwo.getUnderlyingObject());
366 TransactionalGraphEngine spy = spy(dbEngine);
367 TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin());
368 Graph g = graph.newTransaction();
369 GraphTraversalSource traversal = g.traversal();
370 when(spy.tx()).thenReturn(g);
371 when(spy.asAdmin()).thenReturn(adminSpy);
372 when(adminSpy.getTraversalSource()).thenReturn(traversal);
373 when(spy.tx()).thenReturn(g);
374 when(parser.isDependent()).thenReturn(false);
375 when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop);
376 when(prop.orElse(null)).thenReturn(obj.getURI());
377 DBSerializer serializer =
378 new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST");
379 Vertex v = serializer.createNewVertex(obj);
380 serializer.serializeToDb(obj, v, parser, obj.getURI(), "testing");
381 Vertex routeTargetOneV = traversal.V().has("global-route-target", "getTargetKeyNoLink").next();
382 Vertex routeTargetTwoV = traversal.V().has("global-route-target", "getTargetKeyNoLink2").next();
384 assertEquals("first route target put has linked", true,
385 routeTargetOneV.property(AAIProperties.LINKED).orElse(false));
386 assertEquals("second route target put does not have linked", false,
387 routeTargetTwoV.property(AAIProperties.LINKED).orElse(false));