diff options
Diffstat (limited to 'aai-core')
13 files changed, 1536 insertions, 24 deletions
diff --git a/aai-core/pom.xml b/aai-core/pom.xml index 37edc5b4..a93e2e6e 100644 --- a/aai-core/pom.xml +++ b/aai-core/pom.xml @@ -24,6 +24,7 @@ <gendoc.version>v12</gendoc.version> <aai.wiki.link>https://wiki.onap.org/</aai.wiki.link> <hbase.version>1.0.2</hbase.version> + <jackson.version>2.2.3</jackson.version> </properties> <profiles> <profile> @@ -231,7 +232,7 @@ <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> - <version>2.1.4</version> + <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.googlecode.json-simple</groupId> @@ -276,7 +277,7 @@ <dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-jaxb-annotations</artifactId> - <version>2.1.4</version> + <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> @@ -311,17 +312,17 @@ <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> - <version>2.1.4</version> + <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> - <version>2.1.4</version> + <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-yaml</artifactId> - <version>2.1.4</version> + <version>${jackson.version}</version> </dependency> <dependency> <groupId>xml-apis</groupId> @@ -447,6 +448,12 @@ <version>1.6.2</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.skyscreamer</groupId> + <artifactId>jsonassert</artifactId> + <version>1.4.0</version> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java index 692fd531..7efe2ea9 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java @@ -69,6 +69,7 @@ public class GraphTraversalQueryEngine extends QueryEngine { @Override public List<Vertex> findParents(Vertex start) { + @SuppressWarnings("unchecked") final GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).emit(v -> true).repeat(__.union(__.inE().has(CONTAINS.toString(), OUT.toString()).outV(), __.outE().has(CONTAINS.toString(), IN.toString()).inV())); return pipe.toList(); } @@ -79,6 +80,7 @@ public class GraphTraversalQueryEngine extends QueryEngine { @Override public List<Vertex> findAllChildren(Vertex start) { + @SuppressWarnings("unchecked") GraphTraversal<Vertex, Vertex> pipe = this.g .V(start).emit(v -> true).repeat(__.union(__.outE().has(CONTAINS.toString(), OUT.toString()).inV(), __.inE().has(CONTAINS.toString(), IN.toString()).outV())); @@ -87,7 +89,12 @@ public class GraphTraversalQueryEngine extends QueryEngine { } + /** + * {@inheritDoc} + */ + @Override public List<Vertex> findChildrenOfType(Vertex start, String type) { + @SuppressWarnings("unchecked") GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).union( __.outE().has(CONTAINS.toString(), OUT.toString()).inV(), __.inE().has(CONTAINS.toString(), IN.toString()).outV() @@ -96,7 +103,12 @@ public class GraphTraversalQueryEngine extends QueryEngine { return pipe.toList(); } + /** + * {@inheritDoc} + */ + @Override public List<Vertex> findChildren(Vertex start) { + @SuppressWarnings("unchecked") GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).union( __.outE().has(CONTAINS.toString(), OUT.toString()), __.inE().has(CONTAINS.toString(), IN.toString()) @@ -110,6 +122,7 @@ public class GraphTraversalQueryEngine extends QueryEngine { */ @Override public List<Vertex> findDeletable(Vertex start) { + @SuppressWarnings("unchecked") GraphTraversal<Vertex, Vertex> pipe = this.g .V(start).emit(v -> true).repeat( __.union( diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java index 01f11b17..5a468b79 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java @@ -34,7 +34,7 @@ import java.util.List; public abstract class QueryEngine { - final protected GraphTraversalSource g; + protected final GraphTraversalSource g; /** * Instantiates a new query engine. @@ -46,49 +46,103 @@ public abstract class QueryEngine { } /** - * Find parents. + * Finds all the parents/grandparents/etc of the given start node. * - * @param start the start - * @return the list + * @param start - the start vertex whose parent chain you want + * @return the list of start and start's parent, grandparent, etc, in + * order (ie {start, parent, grandparent, etc} */ public abstract List<Vertex> findParents(Vertex start); /** - * Find children. + * Finds all children, grandchildren, etc of start * - * @param start the start - * @return the list + * @param start the start vertex + * @return the list of child/grandchild/etc vertices */ public abstract List<Vertex> findAllChildren(Vertex start); + /** + * Finds all immediate children of start (no grandchildren or so forth) of the given type + * @param start - the start vertex + * @param type - the desired aai-node-type + * @return the list of immediate child vertices of given type + */ public abstract List<Vertex> findChildrenOfType(Vertex start, String type); + /** + * Finds all immediate children of start (no grandchildren or so forth) + * @param start - the start vertex + * @return the list of immediate child vertices + */ public abstract List<Vertex> findChildren(Vertex start); + /** - * Find deletable. + * Find all vertices that should be deleted in a cascade from a delete of start * - * @param start the start - * @return the list + * @param start - the start vertex + * @return the list of vertices to be deleted when start is deleted */ public abstract List<Vertex> findDeletable(Vertex start); + /** + * Finds the subgraph under start, including cousins as well as start's children/grandchildren/etc. + * More specifically, this includes start, all its descendants, start's cousins, and start's + * descendants' cousins (but not any of the cousins' cousins or descendants), and the edges + * connecting them. + * + * @param start - the start vertex + * @return - Tree containing nodes and edges of the subgraph + */ public Tree<Element> findSubGraph(Vertex start) { return findSubGraph(start, AAIProperties.MAXIMUM_DEPTH, false); } + + /** + * Finds the subgraph under start, including cousins as well as start's children/grandchildren/etc. + * More specifically, this includes start, all its descendants, start's cousins, and start's + * descendants' cousins (but not any of the cousins' cousins or descendants), and the edges + * connecting them. + * + * @param start - the start vertex + * @param iterations - depth of the subgraph, this limits how many generations of + * descendants are included + * @param nodeOnly - if true the subgraph will NOT include the cousins + * @return Tree containing nodes and edges of the subgraph + */ public abstract Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly); + /** - * Find related vertices. + * Find vertices of type nodeType related to start by edges of the given + * direction and label. * - * @param start the start - * @param direction the direction - * @param label the label - * @param nodeType the node type - * @return the list + * @param start - the start vertex + * @param direction - the direction of edges to traverse from start + * @param label - the label of edges to traverse from start + * @param nodeType - the node type the results should be + * @return the list of related vertices */ public abstract List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType); + /** + * Finds cousin edges connecting start to other vertices only of types defined in an old version. + * The idea is that if a user is using an old version, they won't understand any new node types in + * subsequent versions. Thus, revealing edges to new types will cause problems. This methods + * filters any such edges out. + * + * @param start - the start vertex + * @param loader - loader for retrieving the list of allowed node types for the desired version + * (version is set when the loader was instantiated) + * @return list of cousin edges between start and any node types understood by the version specified in loader + */ public abstract List<Edge> findEdgesForVersion(Vertex start, Loader loader); + /** + * Finds all cousins of start. + * + * @param start - the start vertex + * @return list of start's cousin vertices + */ public abstract List<Vertex> findCousinVertices(Vertex start); } diff --git a/aai-core/src/test/java/org/onap/aai/AAIJunitRunner.java b/aai-core/src/test/java/org/onap/aai/AAIJunitRunner.java new file mode 100644 index 00000000..52c83bf3 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/AAIJunitRunner.java @@ -0,0 +1,60 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai; + +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.InitializationError; +import org.onap.aai.util.AAIConstants; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public class AAIJunitRunner extends BlockJUnit4ClassRunner { + + public AAIJunitRunner(Class<?> klass) throws InitializationError { + super(klass); + setProps(); + modifyOxmHome(); + } + + public void setProps(){ + System.setProperty("AJSC_HOME", "."); + System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local"); + } + + public void modifyOxmHome(){ + try { + Field aaiConstantsField = AAIConstants.class.getField("AAI_HOME_ETC_OXM"); + setFinalStatic(aaiConstantsField, "../aai-schema/src/main/resources/oxm/"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void setFinalStatic(Field field, Object newValue) throws Exception { + field.setAccessible(true); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + field.set(null, newValue); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java b/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java new file mode 100644 index 00000000..1ec1a05b --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java @@ -0,0 +1,369 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.javatuples.Pair; +import org.mockito.Mockito; +import org.onap.aai.dbmap.DBConnectionType; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.introspection.Version; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.parsers.uri.URIToObject; +import org.onap.aai.rest.db.DBRequest; +import org.onap.aai.rest.db.HttpEntry; +import org.onap.aai.restcore.HttpMethod; +import org.onap.aai.restcore.RESTAPI; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + +import javax.ws.rs.core.*; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.*; + +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +public class HttpTestUtil extends RESTAPI { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(HttpTestUtil.class); + + protected static final MediaType APPLICATION_JSON = MediaType.valueOf("application/json"); + + private static final String EMPTY = ""; + + protected HttpHeaders httpHeaders; + protected UriInfo uriInfo; + + protected MultivaluedMap<String, String> headersMultiMap; + protected MultivaluedMap<String, String> queryParameters; + + protected List<String> aaiRequestContextList; + protected List<MediaType> outputMediaTypes; + + public void init(){ + + httpHeaders = Mockito.mock(HttpHeaders.class); + uriInfo = Mockito.mock(UriInfo.class); + + headersMultiMap = new MultivaluedHashMap<>(); + queryParameters = Mockito.spy(new MultivaluedHashMap<>()); + + headersMultiMap.add("X-FromAppId", "JUNIT"); + headersMultiMap.add("X-TransactionId", UUID.randomUUID().toString()); + headersMultiMap.add("Real-Time", "true"); + headersMultiMap.add("Accept", "application/json"); + headersMultiMap.add("aai-request-context", ""); + + outputMediaTypes = new ArrayList<>(); + outputMediaTypes.add(APPLICATION_JSON); + + aaiRequestContextList = new ArrayList<>(); + aaiRequestContextList.add(""); + + when(httpHeaders.getRequestHeaders()).thenReturn(headersMultiMap); + when(httpHeaders.getAcceptableMediaTypes()).thenReturn(outputMediaTypes); + + when(httpHeaders.getRequestHeader("aai-request-context")).thenReturn(aaiRequestContextList); + + when(uriInfo.getQueryParameters()).thenReturn(queryParameters); + when(uriInfo.getQueryParameters(false)).thenReturn(queryParameters); + + doReturn(null).when(queryParameters).remove(anyObject()); + when(httpHeaders.getMediaType()).thenReturn(APPLICATION_JSON); + } + + public Response doPut(String uri, String payload) throws UnsupportedEncodingException, AAIException { + + this.init(); + Response response = null; + boolean success = true; + TransactionalGraphEngine dbEngine = null; + + try { + + uri = uri.replaceAll("/aai/", ""); + logger.info("Starting the put request for the uri {} with payload {}", uri, payload); + + String [] arr = uri.split("/"); + + Version version = null; + + if(arr != null && arr.length > 1){ + if(arr[0].matches("^v\\d+")){ + version = Version.valueOf(arr[0]); + uri = uri.replaceAll("^v\\d+", ""); + } + } + + if(version == null){ + version = Version.getLatest(); + } + Mockito.when(uriInfo.getPath()).thenReturn(uri); + + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(version, ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath(uri).build(); + URIToObject uriToObject = new URIToObject(loader, uriObject); + + String objType = uriToObject.getEntityName(); + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + + logger.info("Unmarshalling the payload to this {}", objType); + + Introspector obj; + HttpMethod httpMethod; + if(uri.contains("/relationship-list/relationship")){ + obj = loader.unmarshal("relationship", payload, org.onap.aai.restcore.MediaType.getEnum("application/json")); + httpMethod = HttpMethod.PUT_EDGE; + } else { + obj = loader.unmarshal(objType, payload, org.onap.aai.restcore.MediaType.getEnum("application/json")); + httpMethod = HttpMethod.PUT; + this.validateIntrospector(obj, loader, uriObject, httpMethod); + } + + + DBRequest dbRequest = + new DBRequest.Builder(httpMethod, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .rawRequestContent(payload).build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + response = responsesTuple.getValue1().get(0).getValue1(); + + } catch (AAIException e) { + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, e); + success = false; + } catch(Exception e){ + AAIException ex = new AAIException("AAI_4000", e); + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, ex); + success = false; + } finally { + if(success){ + if(response != null){ + if((response.getStatus() / 100) == 2){ + logger.info("Successfully completed the PUT request with status {} and committing it to DB", response.getStatus()); + } else { + logFailure(HttpMethod.PUT, response); + } + } + dbEngine.commit(); + } else { + if(response != null) { + logFailure(HttpMethod.PUT, response); + } + dbEngine.rollback(); + } + } + + return response; + } + + public Response doGet(String uri) throws UnsupportedEncodingException, AAIException { + + this.init(); + Response response = null; + boolean success = true; + TransactionalGraphEngine dbEngine = null; + + try { + + uri = uri.replaceAll("/aai/", ""); + logger.info("Starting the GET request for the uri {} with depth {}", uri, "all"); + + String [] arr = uri.split("/"); + + Version version = null; + + if(arr != null && arr.length > 1){ + if(arr[0].matches("^v\\d+")){ + version = Version.valueOf(arr[0]); + uri = uri.replaceAll("^v\\d+", ""); + } + } + + if(version == null){ + version = Version.getLatest(); + } + + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(version, ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath(uri).build(); + URIToObject uriToObject = new URIToObject(loader, uriObject); + + String objType = uriToObject.getEntityName(); + queryParameters.add("depth", "all"); + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, queryParameters); + + Mockito.when(uriInfo.getPath()).thenReturn(uri); + + logger.info("Unmarshalling the payload to this {}", objType); + + Introspector obj = loader.introspectorFromName(objType); + + DBRequest dbRequest = + new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + response = responsesTuple.getValue1().get(0).getValue1(); + + } catch (AAIException e) { + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, e); + success = false; + } catch(Exception e){ + AAIException ex = new AAIException("AAI_4000", e); + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, ex); + success = false; + } finally { + if(success){ + if(response != null){ + if((response.getStatus() / 100) == 2){ + logger.info("Successfully completed the GET request with status {} and committing it to DB", response.getStatus()); + } else { + logFailure(HttpMethod.GET, response); + } + } + dbEngine.commit(); + } else { + logFailure(HttpMethod.GET, response); + dbEngine.rollback(); + } + } + + return response; + } + + public Response doDelete(String uri, String resourceVersion) throws UnsupportedEncodingException, AAIException { + + this.init(); + Response response = null; + boolean success = true; + TransactionalGraphEngine dbEngine = null; + + try { + + uri = uri.replaceAll("/aai/", ""); + logger.info("Starting the delete request for the uri {} with resource version {}", uri, resourceVersion); + + String [] arr = uri.split("/"); + + Version version = null; + + if(arr != null && arr.length > 1){ + if(arr[0].matches("^v\\d+")){ + version = Version.valueOf(arr[0]); + if(!uri.contains("relationship-list/relationship")){ + uri = uri.replaceAll("^v\\d+", ""); + } + } + } + + if(version == null){ + version = Version.getLatest(); + } + + Mockito.when(uriInfo.getPath()).thenReturn(uri); + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(version, ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath(uri).build(); + URIToObject uriToObject = new URIToObject(loader, uriObject); + + String objType = uriToObject.getEntityName(); + queryParameters.add("resource-version", resourceVersion); + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, queryParameters); + + logger.info("Unmarshalling the payload to this {}", objType); + + Introspector obj; + HttpMethod httpMethod; + if(uri.contains("/relationship-list/relationship")){ + obj = loader.introspectorFromName("relationship"); + httpMethod = HttpMethod.DELETE_EDGE; + } else { + obj = loader.introspectorFromName(objType); + httpMethod = HttpMethod.DELETE; + } + + DBRequest dbRequest = + new DBRequest.Builder(httpMethod, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + response = responsesTuple.getValue1().get(0).getValue1(); + + } catch (AAIException e) { + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, e); + success = false; + } catch(Exception e){ + AAIException ex = new AAIException("AAI_4000", e); + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, ex); + success = false; + } finally { + if(success){ + if(response != null){ + if((response.getStatus() / 100) == 2){ + logger.info("Successfully completed the DELETE request with status {} and committing it to DB", response.getStatus()); + } else { + logFailure(HttpMethod.DELETE, response); + } + } + dbEngine.commit(); + } else { + logFailure(HttpMethod.DELETE, response); + dbEngine.rollback(); + } + } + + return response; + } + + public static void logFailure(HttpMethod httpMethod, Response response){ + logger.info("Unable to complete the {} request with status {} and rolling back", httpMethod.toString(), response.getStatus()); + logger.info("Response body of failed request {}", response.getEntity()); + + } +} diff --git a/aai-core/src/test/java/org/onap/aai/PayloadUtil.java b/aai-core/src/test/java/org/onap/aai/PayloadUtil.java new file mode 100644 index 00000000..43fd2903 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/PayloadUtil.java @@ -0,0 +1,100 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai; + +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertNotNull; + +public class PayloadUtil { + + private static final Map<String, String> cache = new HashMap<>(); + private static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\$\\{[^}]+\\}"); + + public static String getExpectedPayload(String fileName) throws IOException { + + InputStream inputStream = PayloadUtil.class.getClassLoader().getResourceAsStream("payloads/expected/" + fileName); + + String message = String.format("Unable to find the %s in src/test/resources", fileName); + assertNotNull(message, inputStream); + + String resource = IOUtils.toString(inputStream); + + inputStream.close(); + return resource; + } + + public static String getResourcePayload(String fileName) throws IOException { + + InputStream inputStream = PayloadUtil.class.getClassLoader().getResourceAsStream("payloads/resource/" + fileName); + + String message = String.format("Unable to find the %s in src/test/resources", fileName); + assertNotNull(message, inputStream); + + String resource = IOUtils.toString(inputStream); + + inputStream.close(); + return resource; + } + + public static String getTemplatePayload(String fileName, Map<String, String> templateValueMap) throws Exception { + + InputStream inputStream = PayloadUtil.class.getClassLoader().getResourceAsStream("payloads/templates/" + fileName); + + String message = String.format("Unable to find the %s in src/test/resources", fileName); + assertNotNull(message, inputStream); + + String resource; + + if(cache.containsKey(fileName)){ + resource = cache.get(fileName); + } else { + resource = IOUtils.toString(inputStream); + cache.put(fileName, resource); + } + + Matcher matcher = TEMPLATE_PATTERN.matcher(resource); + + String resourceWithTemplateValues = resource; + + while(matcher.find()){ + int start = matcher.start() + 2; + int end = matcher.end() - 1; + String key = resource.substring(start, end); + if(templateValueMap.containsKey(key)){ + resourceWithTemplateValues = resourceWithTemplateValues.replaceAll("\\$\\{" + key +"\\}", templateValueMap.get(key)); + } else { + throw new RuntimeException("Unable to find the key value pair in map for the template processing for key " + key); + } + } + + inputStream.close(); + return resourceWithTemplateValues; + } +} diff --git a/aai-core/src/test/java/org/onap/aai/rest/PserverTest.java b/aai-core/src/test/java/org/onap/aai/rest/PserverTest.java new file mode 100644 index 00000000..843d9934 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/PserverTest.java @@ -0,0 +1,136 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.rest; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.jayway.jsonpath.JsonPath; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aai.AAIJunitRunner; +import org.onap.aai.HttpTestUtil; +import org.onap.aai.PayloadUtil; +import org.onap.aai.introspection.*; +import org.skyscreamer.jsonassert.JSONAssert; + +import javax.ws.rs.core.Response; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(AAIJunitRunner.class) +public class PserverTest { + + private static EELFLogger logger = EELFManager.getInstance().getLogger(PserverTest.class); + private HttpTestUtil httpTestUtil; + private Map<String, String> relationshipMap; + + @Before + public void setup(){ + httpTestUtil = new HttpTestUtil(); + relationshipMap = new HashMap<>(); + } + + @Test + public void testPutPServerCreateGetAndDeleteAndCreateRelationshipBetweenPserverAndCloudRegion() throws Exception { + + logger.info("Starting the pserver testPutServerCreateGetAndDelete"); + + String pserverUri = "/aai/v12/cloud-infrastructure/pservers/pserver/test-pserver"; + String cloudRegionUri = "/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/test1/test2"; + String cloudRegionRelationshipUri = cloudRegionUri + "/relationship-list/relationship"; + + Response response = httpTestUtil.doGet(pserverUri); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + logger.info("Verifying that the pserver is already not in the database successfully"); + + Map<String, String> templateValueMap = new HashMap<>(); + templateValueMap.put("hostname", "test-pserver"); + String pserverPayload = PayloadUtil.getTemplatePayload("pserver.json", templateValueMap); + + response = httpTestUtil.doPut(pserverUri, pserverPayload); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + logger.info("Successfully created the pserver into db"); + + response = httpTestUtil.doGet(pserverUri); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONAssert.assertEquals(pserverPayload, response.getEntity().toString(), false); + logger.info("Successfully retrieved the created pserver from db and verified with put data"); + + response = httpTestUtil.doPut(cloudRegionUri, "{}"); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expect the cloud region to be created", 201, response.getStatus()); + logger.info("Successfully able to create the cloud region with payload that has no keys to be retrieved from uri"); + + response = httpTestUtil.doGet(cloudRegionUri); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the cloud region to be found", 200, response.getStatus()); + logger.info("Successfully retrieved the cloud region from db"); + + relationshipMap.put("related-to", "pserver"); + relationshipMap.put("related-link", pserverUri); + + String pserverRelationshipPayload = PayloadUtil.getTemplatePayload("relationship.json", relationshipMap); + // Creates the relationship between cloud region and pserver + response = httpTestUtil.doPut(cloudRegionRelationshipUri, pserverRelationshipPayload); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expect the cloud region relationship to pserver to be created", 200, response.getStatus()); + logger.info("Successfully created the relationship between cloud region and pserver"); + + response = httpTestUtil.doGet(cloudRegionUri); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expect the cloud region to be created", 200, response.getStatus()); + logger.info("Successfully retrieved the cloud region from db"); + + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, Version.getLatest()); + Introspector in = loader.unmarshal("cloud-region", response.getEntity().toString()); + + System.out.println(in.marshal(true)); + String resourceVersion = JsonPath.read(response.getEntity().toString(), "$.resource-version"); + + response = httpTestUtil.doDelete(cloudRegionUri, resourceVersion); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the cloud region to be deleted", 204, response.getStatus()); + logger.info("Successfully deleted the cloud region from db"); + + response = httpTestUtil.doGet(pserverUri); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the pserver to be not found", 200, response.getStatus()); + resourceVersion = JsonPath.read(response.getEntity().toString(), "$.resource-version"); + logger.info("Successfully retrieved the cloud region from db to get the latest resource version"); + + response = httpTestUtil.doDelete(pserverUri, resourceVersion); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the cloud region to be deleted", 204, response.getStatus()); + logger.info("Successfully deleted the pserver from db"); + + logger.info("Ending the pserver testPutServerCreateGetAndDelete"); + } + +} diff --git a/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java b/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java new file mode 100644 index 00000000..f643fc47 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java @@ -0,0 +1,298 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.rest.db; + +import org.javatuples.Pair; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.aai.AAISetup; +import org.onap.aai.dbmap.DBConnectionType; +import org.onap.aai.domain.yang.Pserver; +import org.onap.aai.domain.yang.Pservers; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.*; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.restcore.HttpMethod; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + +import javax.ws.rs.core.*; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.when; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class HttpEntryTest extends AAISetup { + + protected static final MediaType APPLICATION_JSON = MediaType.valueOf("application/json"); + + private static final Set<Integer> VALID_HTTP_STATUS_CODES = new HashSet<>(); + + static { + VALID_HTTP_STATUS_CODES.add(200); + VALID_HTTP_STATUS_CODES.add(201); + VALID_HTTP_STATUS_CODES.add(204); + } + + private HttpHeaders httpHeaders; + + private UriInfo uriInfo; + + private MultivaluedMap<String, String> headersMultiMap; + private MultivaluedMap<String, String> queryParameters; + + private List<String> aaiRequestContextList; + + private List<MediaType> outputMediaTypes; + + @Before + public void setup(){ + + httpHeaders = Mockito.mock(HttpHeaders.class); + uriInfo = Mockito.mock(UriInfo.class); + + headersMultiMap = new MultivaluedHashMap<>(); + queryParameters = Mockito.spy(new MultivaluedHashMap<>()); + + headersMultiMap.add("X-FromAppId", "JUNIT"); + headersMultiMap.add("X-TransactionId", UUID.randomUUID().toString()); + headersMultiMap.add("Real-Time", "true"); + headersMultiMap.add("Accept", "application/json"); + headersMultiMap.add("aai-request-context", ""); + + outputMediaTypes = new ArrayList<>(); + outputMediaTypes.add(APPLICATION_JSON); + + aaiRequestContextList = new ArrayList<>(); + aaiRequestContextList.add(""); + + when(httpHeaders.getAcceptableMediaTypes()).thenReturn(outputMediaTypes); + when(httpHeaders.getRequestHeaders()).thenReturn(headersMultiMap); + + when(httpHeaders.getRequestHeader("aai-request-context")).thenReturn(aaiRequestContextList); + + + when(uriInfo.getQueryParameters()).thenReturn(queryParameters); + when(uriInfo.getQueryParameters(false)).thenReturn(queryParameters); + + // TODO - Check if this is valid since RemoveDME2QueryParameters seems to be very unreasonable + Mockito.doReturn(null).when(queryParameters).remove(anyObject()); + + when(httpHeaders.getMediaType()).thenReturn(APPLICATION_JSON); + } + + + @Test + public void test1PutOnPserver() throws UnsupportedEncodingException, AAIException { + + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + TransactionalGraphEngine dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test1").build(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + String content = "{\"hostname\":\"junit-test1\"}"; + + Introspector obj = loader.unmarshal("pserver", content, org.onap.aai.restcore.MediaType.getEnum("application/json")); + + DBRequest dbRequest = + new DBRequest.Builder(HttpMethod.PUT, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .rawRequestContent(content).build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + Response response = responsesTuple.getValue1().get(0).getValue1(); + dbEngine.commit(); + assertEquals("Expected the pserver to be created", 201, response.getStatus()); + } + + @Test + public void test2GetOnPserver() throws UnsupportedEncodingException, AAIException { + + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + TransactionalGraphEngine dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test1").build(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + String content = ""; + + Introspector obj = loader.introspectorFromName("pserver"); + + DBRequest dbRequest = + new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .rawRequestContent(content).build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + Response response = responsesTuple.getValue1().get(0).getValue1(); + dbEngine.commit(); + assertEquals("Expected the pserver to be returned", 200, response.getStatus()); + } + + @Test + public void test3MergePatchOnPserver() throws UnsupportedEncodingException, AAIException { + + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + TransactionalGraphEngine dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test1").build(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + String content = "{\"hostname\":\"junit-test1\", \"equip-type\":\"junit-equip-type\"}"; + + Introspector obj = loader.unmarshal("pserver", content, org.onap.aai.restcore.MediaType.getEnum("application/json")); + + DBRequest dbRequest = + new DBRequest.Builder(HttpMethod.MERGE_PATCH, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .rawRequestContent(content).build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + Response response = responsesTuple.getValue1().get(0).getValue1(); + dbEngine.commit(); + assertEquals("Expected the pserver to be updated", 200, response.getStatus()); + } + + private int doDelete(String resourceVersion) throws UnsupportedEncodingException, AAIException { + queryParameters.add("resource-version", resourceVersion); + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + TransactionalGraphEngine dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test1").build(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + String content = ""; + + Introspector obj = loader.introspectorFromName("pserver"); + + DBRequest dbRequest = + new DBRequest.Builder(HttpMethod.DELETE, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .rawRequestContent(content).build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + Response response = responsesTuple.getValue1().get(0).getValue1(); + dbEngine.commit(); + return response.getStatus(); + } + + @Test + public void test4DeleteOnPserver() throws UnsupportedEncodingException, AAIException { + + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + TransactionalGraphEngine dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test1").build(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + String content = ""; + + Introspector obj = loader.introspectorFromName("pserver"); + + DBRequest dbRequest = + new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .rawRequestContent(content).build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + Response response = responsesTuple.getValue1().get(0).getValue1(); + dbEngine.commit(); + String msg = response.getEntity().toString(); + JsonObject jsonObj = new JsonParser().parse(msg).getAsJsonObject(); + String resourceVersion = ""; + if ( jsonObj.isJsonObject()) { + resourceVersion = jsonObj.get("resource-version").getAsString(); + } + assertEquals("Expected the pserver to be deleted", 204, doDelete(resourceVersion)); + } + + @Test + public void test5FailedGetOnPserver() throws UnsupportedEncodingException, AAIException { + + DBConnectionType type = DBConnectionType.REALTIME; + HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + Loader loader = httpEntry.getLoader(); + TransactionalGraphEngine dbEngine = httpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test2").build(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + String content = ""; + + Introspector obj = loader.introspectorFromName("pserver"); + + DBRequest dbRequest = + new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .rawRequestContent(content).build(); + + List<DBRequest> dbRequestList = new ArrayList<>(); + dbRequestList.add(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT"); + Response response = responsesTuple.getValue1().get(0).getValue1(); + dbEngine.commit(); + + assertEquals("Expected the pserver to be deleted", 404, response.getStatus()); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java index 4d46c021..5fade2ed 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java @@ -38,6 +38,7 @@ import java.util.List; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; import org.junit.After; @@ -319,11 +320,11 @@ public class DbSerializerTest extends AAISetup { rules.addTreeEdge(engine.tx().traversal(), cr, ten); rules.addTreeEdge(engine.tx().traversal(), ten, vs); - List<Vertex> vertices = new ArrayList<Vertex>(Arrays.asList(cr, ten, vs)); + List<Vertex> vertices = Arrays.asList(cr, ten, vs); Introspector crIn = dbser.getVertexProperties(cr); Introspector tenIn = dbser.getVertexProperties(ten); Introspector vsIn = dbser.getVertexProperties(vs); - List<Introspector> intros = new ArrayList<Introspector>(Arrays.asList(crIn, tenIn, vsIn)); + List<Introspector> intros = Arrays.asList(crIn, tenIn, vsIn); dbser.setCachedURIs(vertices, intros); @@ -1009,4 +1010,135 @@ public class DbSerializerTest extends AAISetup { return localDbser; } + @Test + public void addRelatedToPropertyTest() throws AAIException { + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, Version.v11); + Introspector gv = loader.introspectorFromName("generic-vnf"); + gv.setValue("vnf-name", "myname"); + Introspector rel = loader.introspectorFromName("relationship"); + DBSerializer dbser = new DBSerializer(Version.v11, dbEngine, + ModelType.MOXY, "AAI-TEST"); + + dbser.addRelatedToProperty(rel, gv); + List<Introspector> relToProps = rel.getWrappedListValue("related-to-property"); + assertTrue(relToProps.size() == 1); + Introspector relToProp = relToProps.get(0); + assertTrue("generic-vnf.vnf-name".equals(relToProp.getValue("property-key"))); + assertTrue("myname".equals(relToProp.getValue("property-value"))); + } + + @Test + public void dbToObjectContainerMismatchTest() throws AAIException, UnsupportedEncodingException { + DBSerializer dbser = new DBSerializer(Version.v11, dbEngine, + ModelType.MOXY, "AAI-TEST"); + + Graph vertexMaker = TinkerGraph.open(); + Vertex a = vertexMaker.addVertex(T.id, "0"); + Vertex b = vertexMaker.addVertex(T.id, "1"); + List<Vertex> vertices = Arrays.asList(a,b); + + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, Version.v11); + Introspector intro = loader.introspectorFromName("image"); //just need any non-container object + + thrown.expect(AAIException.class); + thrown.expectMessage("query object mismatch: this object cannot hold multiple items."); + + dbser.dbToObject(vertices, intro, Integer.MAX_VALUE, true, "doesn't matter"); + } + + @Test + public void dbToObjectTest() throws AAIException, UnsupportedEncodingException { + engine.startTransaction(); + + DBSerializer dbser = new DBSerializer(Version.getLatest(), engine, + ModelType.MOXY, "AAI-TEST"); + + Vertex gv1 = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id1"); + Vertex gv2 = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id2"); + List<Vertex> vertices = Arrays.asList(gv1, gv2); + + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, Version.getLatest()); + Introspector gvContainer = loader.introspectorFromName("generic-vnfs"); + + Introspector res = dbser.dbToObject(vertices, gvContainer, 0, true, "true"); + List<Introspector> gvs = res.getWrappedListValue("generic-vnf"); + assertTrue(gvs.size() == 2); + for (Introspector i : gvs) { + String vnfId = i.getValue("vnf-id"); + assertTrue("id1".equals(vnfId) || "id2".equals(vnfId)); + } + + engine.rollback(); + } + + @Test + public void getEdgeBetweenNoLabelTest() throws AAIException { + DBSerializer dbser = new DBSerializer(Version.getLatest(), engine, + ModelType.MOXY, "AAI-TEST"); + + engine.startTransaction(); + Vertex gv = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id1"); + Vertex lint = engine.tx().addVertex("aai-node-type", "l-interface", "interface-name", "name1"); + rules.addTreeEdge(engine.tx().traversal(), gv, lint); + + Edge res = dbser.getEdgeBetween(EdgeType.TREE, gv, lint); + assertTrue("hasLInterface".equals(res.label())); + engine.rollback(); + } + + @Test + public void deleteItemsWithTraversal() throws AAIException { + DBSerializer dbser = new DBSerializer(Version.getLatest(), engine, + ModelType.MOXY, "AAI-TEST"); + + engine.startTransaction(); + Vertex gv = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id1"); + Vertex lint = engine.tx().addVertex("aai-node-type", "l-interface", "interface-name", "name1"); + + assertTrue(engine.tx().traversal().V().has("vnf-id", "id1").hasNext()); + assertTrue(engine.tx().traversal().V().has("interface-name", "name1").hasNext()); + + dbser.deleteItemsWithTraversal(Arrays.asList(gv, lint)); + + assertTrue(!engine.tx().traversal().V().has("vnf-id", "id1").hasNext()); + assertTrue(!engine.tx().traversal().V().has("interface-name", "name1").hasNext()); + + engine.rollback(); + } + + @Test + public void serializeToDbWithParentTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + DBSerializer dbser = new DBSerializer(Version.getLatest(), engine, + ModelType.MOXY, "AAI-TEST"); + + engine.startTransaction(); + Vertex gv = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id1"); + Vertex lint = engine.tx().addVertex("aai-node-type", "l-interface", "interface-name", "name1"); + rules.addTreeEdge(engine.tx().traversal(), gv, lint); + + Introspector lintIntro = loader.introspectorFromName("l-interface"); + lintIntro.setValue("interface-role", "actor"); + URI lintURI = new URI("/network/generic-vnfs/generic-vnf/id1/l-interfaces/l-interface/name1"); + QueryParser uriQuery = dbEngine.getQueryBuilder(gv).createQueryFromURI(lintURI); + dbser.serializeToDb(lintIntro, lint, uriQuery, "test-identifier", "AAI-TEST"); + + assertTrue(engine.tx().traversal().V(lint).has("interface-role", "actor").hasNext()); + + engine.rollback(); + } + + @Test + public void getLatestVersionViewTest() throws AAIException, UnsupportedEncodingException { + DBSerializer dbser = new DBSerializer(Version.getLatest(), engine, + ModelType.MOXY, "AAI-TEST"); + + engine.startTransaction(); + Vertex phys = engine.tx().addVertex("aai-node-type", "physical-link", "link-name", "zaldo", + "speed-value", "very-fast", "service-provider-bandwidth-up-units", "things"); + + Introspector res = dbser.getLatestVersionView(phys); + assertTrue("zaldo".equals(res.getValue("link-name"))); + assertTrue("very-fast".equals(res.getValue("speed-value"))); + assertTrue("things".equals(res.getValue("service-provider-bandwidth-up-units"))); + } }
\ No newline at end of file diff --git a/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java b/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java index 4e3b7d0f..4b4a0e64 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java @@ -26,18 +26,156 @@ import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Set; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerVertex; import org.junit.Test; +import org.onap.aai.AAISetup; import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.LoaderFactory; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.introspection.Version; import org.onap.aai.serialization.db.EdgeRules; -public class GraphTraversalQueryEngineTest { +public class GraphTraversalQueryEngineTest extends AAISetup { + + @Test + public void testFindParents() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + Graph graph = TinkerGraph.open(); + + Vertex cloudreg = graph.addVertex(T.id, "00", "aai-node-type", "cloud-region"); + Vertex tenant = graph.addVertex(T.id, "10", "aai-node-type", "tenant"); + Vertex vserver = graph.addVertex(T.id, "20", "aai-node-type", "vserver"); + + GraphTraversalSource g = graph.traversal(); + + rules.addTreeEdge(g, cloudreg, tenant); + rules.addTreeEdge(g, tenant, vserver); + + //expect start vertex back plus any parents + List<Vertex> crExpected = new ArrayList<>(Arrays.asList(cloudreg)); //no parents + List<Vertex> tenExpected = new ArrayList<>(Arrays.asList(tenant, cloudreg)); //only has the immediate parent + List<Vertex> vsExpected = new ArrayList<>(Arrays.asList(vserver, tenant, cloudreg)); //parent & grandparent + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + List<Vertex> crRes = engine.findParents(cloudreg); + assertTrue(crRes.containsAll(crExpected) && crExpected.containsAll(crRes)); + + List<Vertex> tenRes = engine.findParents(tenant); + assertTrue(tenRes.containsAll(tenExpected) && tenExpected.containsAll(tenRes)); + + List<Vertex> vsRes = engine.findParents(vserver); + assertTrue(vsRes.containsAll(vsExpected) && vsExpected.containsAll(vsRes)); + //verify expected ordering - start, parent, grandparent + assertTrue(vsRes.get(0).equals(vserver)); + assertTrue(vsRes.get(1).equals(tenant)); + assertTrue(vsRes.get(2).equals(cloudreg)); + } + + @Test + public void testFindAllChildren() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + Graph graph = TinkerGraph.open(); + + Vertex cloudreg = graph.addVertex(T.id, "00", "aai-node-type", "cloud-region"); + Vertex tenant = graph.addVertex(T.id, "10", "aai-node-type", "tenant"); + Vertex vserver = graph.addVertex(T.id, "20", "aai-node-type", "vserver"); + Vertex vserver2 = graph.addVertex(T.id, "21", "aai-node-type", "vserver"); + Vertex oam = graph.addVertex(T.id, "30", "aai-node-type", "oam-network"); + + GraphTraversalSource g = graph.traversal(); + + rules.addTreeEdge(g, cloudreg, tenant); + rules.addTreeEdge(g, tenant, vserver); + rules.addTreeEdge(g, tenant, vserver2); + rules.addTreeEdge(g, cloudreg, oam); + + List<Vertex> crExpected = new ArrayList<>(Arrays.asList(cloudreg, tenant, vserver, vserver2, oam)); + List<Vertex> vsExpected = new ArrayList<>(Arrays.asList(vserver)); + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + List<Vertex> crRes = engine.findAllChildren(cloudreg); + assertTrue(crRes.containsAll(crExpected) && crExpected.containsAll(crRes)); + + List<Vertex> vsRes = engine.findAllChildren(vserver); + assertTrue(vsRes.containsAll(vsExpected) && vsExpected.containsAll(vsRes)); + } + + @Test + public void testFindChildrenOfType() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + Graph graph = TinkerGraph.open(); + + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); + Vertex lint1 = graph.addVertex(T.id, "10", "aai-node-type", "l-interface"); + Vertex lint2 = graph.addVertex(T.id, "11", "aai-node-type", "l-interface"); + Vertex lag = graph.addVertex(T.id, "20", "aai-node-type", "lag-interface"); + Vertex lint3 = graph.addVertex(T.id, "12", "aai-node-type", "l-interface"); + + GraphTraversalSource g = graph.traversal(); + + rules.addTreeEdge(g, gv, lint1); + rules.addTreeEdge(g, gv, lint2); + rules.addTreeEdge(g, gv, lag); + rules.addTreeEdge(g, lag, lint3); + + List<Vertex> expected = new ArrayList<>(Arrays.asList(lint1, lint2)); + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + List<Vertex> results = engine.findChildrenOfType(gv, "l-interface"); + assertTrue(results.containsAll(expected) && expected.containsAll(results)); + } + + @Test + public void testFindChildren() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + Graph graph = TinkerGraph.open(); + + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); + Vertex lint1 = graph.addVertex(T.id, "10", "aai-node-type", "l-interface"); + Vertex lint2 = graph.addVertex(T.id, "11", "aai-node-type", "l-interface"); + Vertex lag = graph.addVertex(T.id, "20", "aai-node-type", "lag-interface"); + Vertex lint3 = graph.addVertex(T.id, "12", "aai-node-type", "l-interface"); + + GraphTraversalSource g = graph.traversal(); + + rules.addTreeEdge(g, gv, lint1); + rules.addTreeEdge(g, gv, lint2); + rules.addTreeEdge(g, gv, lag); + rules.addTreeEdge(g, lag, lint3); + + List<Vertex> expected = new ArrayList<>(Arrays.asList(lint1, lint2, lag)); + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + List<Vertex> results = engine.findChildren(gv); + assertTrue(results.containsAll(expected) && expected.containsAll(results)); + } @Test public void testFindDeletable() throws AAIException { @@ -72,4 +210,172 @@ public class GraphTraversalQueryEngineTest { List<Vertex> cousinDeletes = engine.findDeletable(cousin); assertTrue(cousinExpected.containsAll(cousinDeletes) && cousinDeletes.containsAll(cousinExpected)); } + + @Test + public void testFindRelatedVertices() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + + Graph graph = TinkerGraph.open(); + + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); + Vertex lint = graph.addVertex(T.id, "10", "aai-node-type", "l-interface"); + Vertex lint2 = graph.addVertex(T.id, "11", "aai-node-type", "l-interface"); + Vertex log = graph.addVertex(T.id, "20", "aai-node-type", "logical-link"); + + GraphTraversalSource g = graph.traversal(); + + rules.addTreeEdge(g, gv, lint); + rules.addEdge(g, lint, log); + rules.addEdge(g, log, lint2); + + List<Vertex> outExpected = new ArrayList<>(Arrays.asList(lint)); + List<Vertex> inExpected = new ArrayList<>(Arrays.asList(lint, lint2)); + List<Vertex> bothExpected = new ArrayList<>(Arrays.asList(log)); + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + List<Vertex> outRes = engine.findRelatedVertices(gv, Direction.OUT, "hasLInterface", "l-interface"); + assertTrue(outRes.containsAll(outExpected) && outExpected.containsAll(outRes)); + + List<Vertex> inRes = engine.findRelatedVertices(log, Direction.IN, "usesLogicalLink", "l-interface"); + assertTrue(inRes.containsAll(inExpected) && inExpected.containsAll(inRes)); + + List<Vertex> bothRes = engine.findRelatedVertices(lint, Direction.BOTH, "usesLogicalLink", "logical-link"); + assertTrue(bothRes.containsAll(bothExpected) && bothExpected.containsAll(bothRes)); + } + + @Test + public void testFindSubGraph() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + Graph graph = TinkerGraph.open(); + + Vertex cr = graph.addVertex(T.id, "00", "aai-node-type", "cloud-region"); + Vertex ten = graph.addVertex(T.id, "10", "aai-node-type", "tenant"); + Vertex ten2 = graph.addVertex(T.id, "11", "aai-node-type", "tenant"); + Vertex vs = graph.addVertex(T.id, "20", "aai-node-type", "vserver"); + Vertex vs2 = graph.addVertex(T.id, "21", "aai-node-type", "vserver"); + Vertex lint = graph.addVertex(T.id, "30", "aai-node-type", "l-interface"); + Vertex comp = graph.addVertex(T.id, "40", "aai-node-type", "complex"); + Vertex ctag = graph.addVertex(T.id, "50", "aai-node-type", "ctag-pool"); + Vertex gv = graph.addVertex(T.id, "60", "aai-node-type", "generic-vnf"); + Vertex lag = graph.addVertex(T.id, "70", "aai-node-type", "lag-interface"); + Vertex lint2 = graph.addVertex(T.id, "31", "aai-node-type", "l-interface"); + Vertex log = graph.addVertex(T.id, "80", "aai-node-type", "logical-link"); + Vertex vnfc = graph.addVertex(T.id, "90", "aai-node-type", "vnfc"); + + GraphTraversalSource g = graph.traversal(); + + Edge crTen = rules.addTreeEdge(g, cr, ten); + Edge crTen2 = rules.addTreeEdge(g, cr, ten2); + Edge tenVs = rules.addTreeEdge(g, ten, vs); + Edge tenVs2 = rules.addTreeEdge(g, ten, vs2); + Edge vsLInt = rules.addTreeEdge(g, vs, lint); + Edge lintLog = rules.addEdge(g, lint, log); + Edge vsGv = rules.addEdge(g, vs, gv); + rules.addEdge(g, gv, vnfc); + + rules.addTreeEdge(g, gv, lag); + rules.addTreeEdge(g, lag, lint2); + + rules.addTreeEdge(g, comp, ctag); + Edge crComp = rules.addEdge(g, cr, comp); + + //findSubGraph(cr, 0, true) + List<Element> expected1 = new ArrayList<>(Arrays.asList(cr)); + //findSubGraph(cr, 2, true) + List<Element> expected2 = new ArrayList<>(Arrays.asList(cr, ten, ten2, vs, vs2, + crTen, crTen2, tenVs, tenVs2)); + //findSubGraph(cr) + List<Element> expected3 = new ArrayList<>(Arrays.asList(cr, ten, ten2, comp, vs, vs2, lint, gv, log, + crTen, crTen2, crComp, tenVs, tenVs2, vsLInt, + vsGv, lintLog)); + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + Tree<Element> res1 = engine.findSubGraph(cr, 0, true); + Set<Element> resList1 = treeToList(res1); + assertTrue(resList1.containsAll(expected1) && expected1.containsAll(resList1)); + + Tree<Element> res2 = engine.findSubGraph(cr, 2, true); + Set<Element> resList2 = treeToList(res2); + assertTrue(resList2.containsAll(expected2) && expected2.containsAll(resList2)); + + Tree<Element> res3 = engine.findSubGraph(cr); + Set<Element> resList3 = treeToList(res3); + assertTrue(resList3.containsAll(expected3) && expected3.containsAll(resList3)); + } + + /** + * convenience helper method to make it easier to check the contents of the tree against + * a list of expected results + * @param tree - the tree whose contents you want in collection form + * @return set of the contents of the tree + */ + private Set<Element> treeToList(Tree<Element> tree) { + Set<Element> ret = new HashSet<>(); + + for (Element key : tree.keySet()) { + ret.add(key); + ret.addAll(treeToList(tree.get(key))); + } + + return ret; + } + + @Test + public void testFindEdgesForVersion() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + Graph graph = TinkerGraph.open(); + + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); + Vertex vnfc = graph.addVertex(T.id, "10", "aai-node-type", "vnfc"); + Vertex lob = graph.addVertex(T.id, "20", "aai-node-type", "line-of-business"); + Vertex lint = graph.addVertex(T.id, "30", "aai-node-type", "l-interface"); + + GraphTraversalSource g = graph.traversal(); + + rules.addTreeEdge(g, gv, lint); //tree edge so shouldn't appear in results + Edge gvVnfc = rules.addEdge(g, gv, vnfc); + rules.addEdge(g, gv, lob); //v11/12 not v10 + + List<Edge> expected = new ArrayList<>(Arrays.asList(gvVnfc)); + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, Version.v10); + List<Edge> results = engine.findEdgesForVersion(gv, loader); + assertTrue(results.containsAll(expected) && expected.containsAll(results)); + } + + @Test + public void testFindCousinVertices() throws AAIException { + //setup + EdgeRules rules = EdgeRules.getInstance(); + Graph graph = TinkerGraph.open(); + + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); + Vertex vnfc = graph.addVertex(T.id, "10", "aai-node-type", "vnfc"); + Vertex lob = graph.addVertex(T.id, "20", "aai-node-type", "line-of-business"); + Vertex lint = graph.addVertex(T.id, "30", "aai-node-type", "l-interface"); + + GraphTraversalSource g = graph.traversal(); + + rules.addTreeEdge(g, gv, lint); //tree edge so shouldn't appear in results + rules.addEdge(g, gv, vnfc); + rules.addEdge(g, gv, lob); + + List<Vertex> expected = new ArrayList<>(Arrays.asList(vnfc, lob)); + + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); + + //test + List<Vertex> results = engine.findCousinVertices(gv); + assertTrue(results.containsAll(expected) && expected.containsAll(results)); + } } diff --git a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties index 3da02475..c91976f3 100644 --- a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties +++ b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties @@ -25,3 +25,8 @@ aai.resourceversion.enableflag=true aai.logging.maxStackTraceEntries=10 aai.default.api.version=v9 +aai.server.rebind=g +aai.run.migrations=false +ecm.auth.password.x=OBF:1igd1i9a1jnb1yte1vv11vu91yt81jk71i6o1idt + +aai.jms.enable=false diff --git a/aai-core/src/test/resources/payloads/templates/pserver.json b/aai-core/src/test/resources/payloads/templates/pserver.json new file mode 100644 index 00000000..c1c261a4 --- /dev/null +++ b/aai-core/src/test/resources/payloads/templates/pserver.json @@ -0,0 +1,28 @@ +{ + "hostname": "${hostname}", + "ptnii-equip-name": "example-ptnii-equip-name-val-36969", + "number-of-cpus": 62220, + "disk-in-gigabytes": 872, + "ram-in-megabytes": 35331, + "equip-type": "example-equip-type-val-22986", + "equip-vendor": "example-equip-vendor-val-37452", + "equip-model": "example-equip-model-val-14665", + "fqdn": "example-fqdn-val-33429", + "pserver-selflink": "example-pserver-selflink-val-10125", + "ipv4-oam-address": "example-ipv4-oam-address-val-3155", + "serial-number": "example-serial-number-val-12010", + "ipaddress-v4-loopback-0": "example-ipaddress-v4-loopback0-val-77686", + "ipaddress-v6-loopback-0": "example-ipaddress-v6-loopback0-val-17856", + "ipaddress-v4-aim": "example-ipaddress-v4-aim-val-33665", + "ipaddress-v6-aim": "example-ipaddress-v6-aim-val-6210", + "ipaddress-v6-oam": "example-ipaddress-v6-oam-val-40977", + "inv-status": "example-inv-status-val-3682", + "pserver-id": "example-pserver-id-val-82142", + "internet-topology": "example-internet-topology-val-56425", + "in-maint": true, + "pserver-name2": "example-pserver-name2-val-53802", + "purpose": "example-purpose-val-90218", + "prov-status": "example-prov-status-val-11642", + "management-option": "example-management-option-val-91111", + "host-profile": "example-host-profile-val-36247" +}
\ No newline at end of file diff --git a/aai-core/src/test/resources/payloads/templates/relationship.json b/aai-core/src/test/resources/payloads/templates/relationship.json new file mode 100644 index 00000000..ea07d5e7 --- /dev/null +++ b/aai-core/src/test/resources/payloads/templates/relationship.json @@ -0,0 +1,4 @@ +{ + "related-to": "${related-to}", + "related-link": "${related-link}" +}
\ No newline at end of file |