Merge "Release 1.14.0 maven artifact"
[aai/aai-common.git] / aai-core / src / test / java / org / onap / aai / introspection / sideeffect / DataLinkTest.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
12  *
13  *    http://www.apache.org/licenses/LICENSE-2.0
14  *
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=========================================================
21  */
22
23 package org.onap.aai.introspection.sideeffect;
24
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;
31
32 import java.io.UnsupportedEncodingException;
33 import java.net.URI;
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;
39
40 import javax.ws.rs.core.MultivaluedMap;
41
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;
52 import org.junit.*;
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;
75
76 @Category(TinkerpopUpgrade.class)
77 @RunWith(value = Parameterized.class)
78 public class DataLinkTest extends DataLinkSetup {
79
80     private static JanusGraph graph;
81     private final static ModelType introspectorFactoryType = ModelType.MOXY;
82     private static Loader loader;
83     private static TransactionalGraphEngine dbEngine;
84     @Mock
85     private QueryParser parser;
86     @Mock
87     private Vertex self;
88     @Mock
89     private VertexProperty<String> prop;
90     @Rule
91     public ExpectedException thrown = ExpectedException.none();
92
93     @Parameterized.Parameter
94     public QueryStyle queryStyle;
95
96     @Parameterized.Parameters(name = "QueryStyle.{0}")
97     public static Collection<Object[]> data() {
98         return Arrays.asList(new Object[][] {{QueryStyle.TRAVERSAL},{QueryStyle.TRAVERSAL_URI}});
99     }
100
101     @BeforeClass
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();
107         graphMgt.commit();
108
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();
173         graph.tx().commit();
174
175     }
176
177     @AfterClass
178     public static void tearDown() {
179         graph.tx().rollback();
180         graph.close();
181     }
182
183     @Before
184     public void initMock() {
185         loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, schemaVersions.getDefaultVersion());
186         MockitoAnnotations.openMocks(this);
187         dbEngine = new JanusGraphDBEngine(queryStyle, loader);
188     }
189
190     @Test
191     public void verifyCreationOfVertex()
192             throws AAIException, UnsupportedEncodingException, IllegalArgumentException, SecurityException {
193
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();
212
213         runner.execute(obj, self);
214
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());
217         g.tx().rollback();
218
219     }
220
221     /** 
222      * This is more directly testing the modification mechanism (see verifyModificationOfVertex test)
223      */
224     @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();
232         
233         QueryParser uriQuery = dbEngine.getQueryBuilder(this.queryStyle, loader, source, traversal).createQueryFromURI(uri, map);
234         List<Vertex> results = uriQuery.getQueryBuilder().toList();
235
236         assertEquals(0, results.size());
237
238         QueryBuilder<Vertex> queryBuilder = uriQuery.getQueryBuilder().getContainerQuery()
239         .getVerticesByProperty(AAIProperties.LINKED, true);
240         List<Vertex> linkedVertices = queryBuilder.toList();
241         assertEquals(1, linkedVertices.size());
242     }
243
244     @Test
245     public void verifyModificationOfVertex()
246             throws AAIException, UnsupportedEncodingException, IllegalArgumentException, SecurityException {
247
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();
257
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);
268
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")
272                         .hasNext(),
273                 is(true));
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(),
278                 is(true));
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(),
282                 is(not(true)));
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(),
285                 is(true));
286         g.tx().rollback();
287
288     }
289
290     @Test
291     public void verifyDeleteOfVertex() throws Exception {
292
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();
310
311         runner.execute(obj, self);
312
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());
316
317         g.tx().rollback();
318
319     }
320
321     @Test
322     public void verifyPropertyPopulation() throws Exception {
323
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();
340
341         runner.execute(obj, self);
342
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"));
346         g.tx().rollback();
347
348     }
349
350     @Test
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();
383
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));
388
389         g.tx().rollback();
390
391     }
392  }
393