Increase code coverage 29/56129/1
authorSotiropoulos, Ioannis (is948x) <Ioannis.Sotiropoulos@amdocs.com>
Tue, 10 Jul 2018 16:57:43 +0000 (17:57 +0100)
committerSotiropoulos, Ioannis (is948x) <Ioannis.Sotiropoulos@amdocs.com>
Tue, 10 Jul 2018 16:57:43 +0000 (17:57 +0100)
Add tests to increase code coverage above 60 percent.

Issue-ID: AAI-1198

Change-Id: I4c2f964ce41d01521cc1313e32e34fb6460d49bf
Signed-off-by: Sotiropoulos, Ioannis (is948x) <Ioannis.Sotiropoulos@amdocs.com>
37 files changed:
pom.xml
src/main/java/org/onap/crud/dao/DataRouterDAO.java
src/main/java/org/onap/crud/dao/champ/ChampDao.java
src/main/java/org/onap/crud/event/response/GraphEventResponseHandler.java
src/main/java/org/onap/crud/service/AaiResourceService.java
src/main/java/org/onap/crud/service/CrudAsyncGraphEventCache.java
src/test/java/org/onap/crud/event/response/GraphEventResponseHandlerTest.java
src/test/java/org/onap/crud/service/BulkPayloadTest.java
src/test/java/org/onap/crud/service/ChampDaoExceptionsTest.java [new file with mode: 0644]
src/test/java/org/onap/crud/service/ChampDaoMockTest.java [new file with mode: 0644]
src/test/java/org/onap/crud/service/CrudRestServiceTest.java
src/test/java/org/onap/crud/service/TestEventConsumer.java [new file with mode: 0644]
src/test/java/org/onap/crud/service/TestEventPublisher.java [new file with mode: 0644]
src/test/java/org/onap/crud/service/TestResourceServiceEdgeOperations.java [new file with mode: 0644]
src/test/java/org/onap/crud/service/VertexPayloadTest.java [new file with mode: 0644]
src/test/java/org/onap/schema/EdgeRulesLoaderTest.java
src/test/java/org/onap/schema/RelationshipSchemaValidatorTest.java [new file with mode: 0644]
src/test/java/org/onap/schema/validation/MultiplicityValidatorTest.java
src/test/resources/aai-resource-service/model/DbEdgeRules_v10.json [new file with mode: 0644]
src/test/resources/aai-resource-service/model/edge_properties_v10.json [new file with mode: 0644]
src/test/resources/aai-resource-service/model/edge_properties_v11.json [new file with mode: 0644]
src/test/resources/aai-resource-service/post-edge-auto-props.json [new file with mode: 0644]
src/test/resources/aai-resource-service/post-edge-no-props.json [new file with mode: 0644]
src/test/resources/aai-resource-service/post-edge-no-type.json [new file with mode: 0644]
src/test/resources/aai-resource-service/post-edge-null-props.json [new file with mode: 0644]
src/test/resources/aai-resource-service/post-edge-upsert.json [new file with mode: 0644]
src/test/resources/aai-resource-service/post-edge-with-id.json [new file with mode: 0644]
src/test/resources/aai-resource-service/post-edge.json [new file with mode: 0644]
src/test/resources/auth/crud_policy.json [new file with mode: 0644]
src/test/resources/event/champ-edge-event.json [new file with mode: 0644]
src/test/resources/event/champ-vertex-event-error.json [new file with mode: 0644]
src/test/resources/event/champ-vertex-event-violations.json [new file with mode: 0644]
src/test/resources/event/champ-vertex-event.json [new file with mode: 0644]
src/test/resources/event/event-envelope-sentinel-no-violations.json
src/test/resources/event/event-envelope-sentinel.json
src/test/resources/event/graph-edge-event.json [new file with mode: 0644]
src/test/resources/event/graph-vertex-event.json [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index 50c6c88..e79e4ad 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -41,7 +41,6 @@ limitations under the License.
         <onap.nexus.url>https://nexus.onap.org</onap.nexus.url>
         <testRouteOffer>workstation</testRouteOffer>
         <testEnv>DEV</testEnv>
-        <version.org.hamcrest.hamcrest-library>1.3</version.org.hamcrest.hamcrest-library>
     </properties>
 
     <dependencyManagement>
@@ -84,6 +83,17 @@ limitations under the License.
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>
+                    spring-boot-configuration-processor
+                </artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
             <artifactId>cxf-rt-frontend-jaxrs</artifactId>
@@ -288,12 +298,6 @@ limitations under the License.
             <version>1.5.0</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-library</artifactId>
-            <version>${version.org.hamcrest.hamcrest-library}</version>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
@@ -304,13 +308,6 @@ limitations under the License.
             <artifactId>httpcore</artifactId>
             <version>4.4.1</version>
         </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>
-                    spring-boot-configuration-processor
-                </artifactId>
-            <optional>true</optional>
-        </dependency>
     </dependencies>
 
     <build>
index c0cf7c1..e5b6d5a 100644 (file)
 package org.onap.crud.dao;
 
 import org.eclipse.jetty.util.security.Password;
-import org.onap.aai.cl.api.Logger;
-import org.onap.aai.cl.eelf.LoggerFactory;
 import org.onap.aai.restclient.client.RestClient;
 import org.onap.aai.restclient.enums.RestAuthenticationMode;
 import org.onap.crud.dao.champ.ChampDao;
 import org.onap.crud.util.CrudServiceConstants;
 
 public class DataRouterDAO extends ChampDao {
-  private Logger logger = LoggerFactory.getInstance().getLogger(DataRouterDAO.class.getName());
-
   public DataRouterDAO(String url, String certPassword) {
     try {
       client = new RestClient().authenticationMode(RestAuthenticationMode.SSL_CERT).validateServerHostname(false)
index 7bd4754..6817ea6 100644 (file)
@@ -33,8 +33,6 @@ import org.apache.http.NameValuePair;
 import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.message.BasicNameValuePair;
 import org.eclipse.jetty.util.security.Password;
-import org.onap.aai.cl.api.Logger;
-import org.onap.aai.cl.eelf.LoggerFactory;
 import org.onap.aai.cl.mdc.MdcContext;
 import org.onap.aai.logging.LoggingContext;
 import org.onap.aai.restclient.client.OperationResult;
@@ -64,8 +62,6 @@ public class ChampDao implements GraphDao {
   protected static final String RELATIONSHIP_SUB_URL = "relationships";
   protected static final String TRANSACTION_SUB_URL = "transaction";
 
-  private Logger logger = LoggerFactory.getInstance().getLogger(ChampDao.class.getName());
-
   // We use a custom vertex serializer for champ because it expects "key"
   // instead of "id"
   protected static final Gson champGson = new GsonBuilder()
@@ -209,7 +205,7 @@ public class ChampDao implements GraphDao {
       if (!edge.getType().equalsIgnoreCase(type)) {
         // We didn't find an edge with the supplied type, so just throw an
         // exception.
-        throw new CrudException("No edge with id " + id + "and type " + type + " found in graph",
+        throw new CrudException("No edge with id " + id + " and type " + type + " found in graph",
             javax.ws.rs.core.Response.Status.NOT_FOUND);
       }
       return getResult;
@@ -537,7 +533,7 @@ public class ChampDao implements GraphDao {
       if (!edge.getType().equalsIgnoreCase(type)) {
         // We didn't find an edge with the supplied type, so just throw an
         // exception.
-        throw new CrudException("No edge with id " + id + "and type " + type + " found in graph",
+        throw new CrudException("No edge with id " + id + " and type " + type + " found in graph",
             javax.ws.rs.core.Response.Status.NOT_FOUND);
       }
       return edge;
@@ -558,7 +554,7 @@ public class ChampDao implements GraphDao {
       if (!vert.getType().equalsIgnoreCase(type)) {
         // We didn't find a vertex with the supplied type, so just throw an
         // exception.
-        throw new CrudException("No vertex with id " + id + "and type " + type + " found in graph",
+        throw new CrudException("No vertex with id " + id + " and type " + type + " found in graph",
             javax.ws.rs.core.Response.Status.NOT_FOUND);
       }
       return vert;
index d858384..83be4bc 100644 (file)
@@ -42,12 +42,7 @@ public class GraphEventResponseHandler {
 
     public String handleVertexResponse(String version, GraphEvent event, GraphEventEnvelope response)
             throws CrudException {
-        handlePolicyViolations(event, response);
-        logResponse(event, response.getBody());
-
-        if (isErrorResponse(response.getBody())) {
-            throwOperationException(response);
-        }
+        validate(event, response);
 
         return CrudResponseBuilder.buildUpsertVertexResponse(
                 OxmModelValidator.validateOutgoingPayload(version, response.getBody().getVertex().toVertex()), version);
@@ -55,12 +50,7 @@ public class GraphEventResponseHandler {
 
     public String handleEdgeResponse(String version, GraphEvent event, GraphEventEnvelope response)
             throws CrudException {
-        handlePolicyViolations(event, response);
-        logResponse(event, response.getBody());
-
-        if (isErrorResponse(response.getBody())) {
-            throwOperationException(response);
-        }
+        validate(event, response);
 
         return CrudResponseBuilder.buildUpsertEdgeResponse(
                 RelationshipSchemaValidator.validateOutgoingPayload(version, response.getBody().getEdge().toEdge()),
@@ -68,23 +58,12 @@ public class GraphEventResponseHandler {
     }
 
     public String handleDeletionResponse(GraphEvent event, GraphEventEnvelope response) throws CrudException {
-        handlePolicyViolations(event, response);
-        logResponse(event, response.getBody());
-
-        if (isErrorResponse(response.getBody())) {
-            throwOperationException(response);
-        }
-
+        validate(event, response);
         return "";
     }
 
     public void handleBulkEventResponse(GraphEvent event, GraphEventEnvelope response) throws CrudException {
-        handlePolicyViolations(event, response);
-        logResponse(event, response.getBody());
-
-        if (isErrorResponse(response.getBody())) {
-            throwOperationException(response);
-        }
+        validate(event, response);
     }
 
     public boolean hasPolicyViolations(GraphEventEnvelope event) {
@@ -92,6 +71,18 @@ public class GraphEventResponseHandler {
                 && event.getPolicyViolations().getAsJsonArray().size() != 0;
     }
 
+    private void validate(GraphEvent event, GraphEventEnvelope response) throws CrudException {
+        handlePolicyViolations(event, response);
+        logResponse(event, response.getBody());
+
+        if (isErrorResponse(response.getBody())) {
+            throw new CrudException(
+                    GraphEventResponseMessage.OPERATION_ERROR_EXCEPTION_MESSAGE
+                            .getMessage(response.getBody().getTransactionId(), response.getBody().getErrorMessage()),
+                    response.getBody().getHttpErrorStatus());
+        }
+    }
+
     private void handlePolicyViolations(GraphEvent event, GraphEventEnvelope response) throws CrudException {
         if (hasPolicyViolations(response)) {
             logPolicyViolation(event, response);
@@ -126,13 +117,6 @@ public class GraphEventResponseHandler {
         //@formatter:on
     }
 
-    private void throwOperationException(GraphEventEnvelope response) throws CrudException {
-        throw new CrudException(
-                GraphEventResponseMessage.OPERATION_ERROR_EXCEPTION_MESSAGE
-                        .getMessage(response.getBody().getTransactionId(), response.getBody().getErrorMessage()),
-                response.getBody().getHttpErrorStatus());
-    }
-
     private boolean isErrorResponse(GraphEvent response) {
         return GraphEventResult.FAILURE.equals(response.getResult());
     }
index 881f9fd..c2e0338 100644 (file)
@@ -169,8 +169,9 @@ public class AaiResourceService {
         ImmutablePair<EntityTag, String> result = graphDataService.addEdge(EdgeRulesLoader.getLatestSchemaVersion(), type, payload);\r
         response = Response.status(Status.CREATED).entity(result.getValue()).tag(result.getKey()).type(mediaType).build();\r
 \r
-      } catch (CrudException e) {\r
-\r
+      } catch (CrudException ce) {\r
+          response = Response.status(ce.getHttpStatus()).entity(ce.getMessage()).build();\r
+      } catch (Exception e) {\r
         response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();\r
       }\r
     }\r
index 3457cff..ff5170a 100644 (file)
  */
 package org.onap.crud.service;
 
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-
 import java.util.concurrent.TimeUnit;
-
 import org.onap.aai.cl.api.Logger;
 import org.onap.aai.cl.eelf.LoggerFactory;
 import org.onap.crud.logging.CrudServiceMsgs;
 import org.onap.crud.service.CrudAsyncGraphDataService.CollectGraphResponse;
 import org.onap.crud.util.CrudProperties;
 import org.onap.crud.util.CrudServiceConstants;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
 
 /**
  * Self expiring Cache to hold request transactionIds . Events are expired
index 1829496..e5ac52d 100644 (file)
  */
 package org.onap.crud.event.response;
 
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onap.crud.event.GraphEvent;
+import org.onap.crud.event.GraphEvent.GraphEventOperation;
 import org.onap.crud.event.envelope.GraphEventEnvelope;
+import org.onap.crud.exception.CrudException;
 import org.onap.crud.util.TestUtil;
+import org.onap.schema.OxmModelLoader;
 import com.google.gson.Gson;
+import com.google.gson.JsonParser;
 
 public class GraphEventResponseHandlerTest {
 
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        System.setProperty("CONFIG_HOME", "src/test/resources");
+        System.setProperty("AJSC_HOME", ".");
+        System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local");
+
+        OxmModelLoader.loadModels();
+    }
+
     @Test
     public void testPolicyViolationsNotDetected() throws Exception {
         String expectedEnvelope = TestUtil.getFileAsString("event/event-envelope-sentinel-no-violations.json");
@@ -36,7 +55,7 @@ public class GraphEventResponseHandlerTest {
         GraphEventEnvelope envelope = gson.fromJson(expectedEnvelope, GraphEventEnvelope.class);
 
         GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
-        assertThat(graphEventResponseHandler.hasPolicyViolations(envelope), is(false));
+        assertThat(graphEventResponseHandler.hasPolicyViolations(envelope)).isFalse();
     }
 
     @Test
@@ -46,6 +65,79 @@ public class GraphEventResponseHandlerTest {
         GraphEventEnvelope envelope = gson.fromJson(expectedEnvelope, GraphEventEnvelope.class);
 
         GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
-        assertThat(graphEventResponseHandler.hasPolicyViolations(envelope), is(true));
+        assertThat(graphEventResponseHandler.hasPolicyViolations(envelope)).isTrue();
+    }
+
+    @Test
+    public void testHandleVertexResponse() throws Exception {
+        String graphEvent = TestUtil.getFileAsString("event/graph-vertex-event.json");
+        String champResult = TestUtil.getFileAsString("event/champ-vertex-event.json");
+        Gson gson = new Gson();
+        GraphEvent event = gson.fromJson(graphEvent, GraphEvent.class);
+        GraphEventEnvelope result = gson.fromJson(champResult, GraphEventEnvelope.class);
+
+        GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
+        String response = graphEventResponseHandler.handleVertexResponse("v13", event, result);
+
+        assertThat(new JsonParser().parse(response).getAsJsonObject().get("url").getAsString())
+                .isEqualTo("services/inventory/v13/pserver/890c8b3f-892f-48e3-85cd-748ebf0426a5");
+    }
+
+    @Test
+    public void testHandleVertexResponseWithError() throws Exception {
+        expectedException.expect(CrudException.class);
+        expectedException.expectMessage("test error");
+
+        String graphEvent = TestUtil.getFileAsString("event/graph-vertex-event.json");
+        String champResult = TestUtil.getFileAsString("event/champ-vertex-event-error.json");
+        Gson gson = new Gson();
+        GraphEvent event = gson.fromJson(graphEvent, GraphEvent.class);
+        GraphEventEnvelope result = gson.fromJson(champResult, GraphEventEnvelope.class);
+
+        GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
+        graphEventResponseHandler.handleVertexResponse("v13", event, result);
+    }
+
+    @Test(expected = CrudException.class)
+    public void testHandleVertexResponseWithViolations() throws Exception {
+
+        String graphEvent = TestUtil.getFileAsString("event/graph-vertex-event.json");
+        String champResult = TestUtil.getFileAsString("event/champ-vertex-event-violations.json");
+        Gson gson = new Gson();
+        GraphEvent event = gson.fromJson(graphEvent, GraphEvent.class);
+        GraphEventEnvelope result = gson.fromJson(champResult, GraphEventEnvelope.class);
+
+        GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
+        graphEventResponseHandler.handleVertexResponse("v13", event, result);
+    }
+
+    @Test
+    public void testHandleEdgeResponse() throws Exception {
+        String graphEvent = TestUtil.getFileAsString("event/graph-edge-event.json");
+        String champResult = TestUtil.getFileAsString("event/champ-edge-event.json");
+        Gson gson = new Gson();
+        GraphEvent event = gson.fromJson(graphEvent, GraphEvent.class);
+        GraphEventEnvelope result = gson.fromJson(champResult, GraphEventEnvelope.class);
+
+        GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
+        String response = graphEventResponseHandler.handleEdgeResponse("v10", event, result);
+
+        String id = new JsonParser().parse(response).getAsJsonObject().get("id").getAsString();
+        assertThat(id).isEqualTo("test-key");
+    }
+
+    @Test
+    public void testHandleDeletionResponse() throws Exception {
+        GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
+        GraphEvent event = GraphEvent.builder(GraphEventOperation.DELETE).build();
+        String response = graphEventResponseHandler.handleDeletionResponse(event, new GraphEventEnvelope(event));
+        assertThat(response).isEqualTo("");
+    }
+
+    @Test
+    public void testHandleBulkEventResponse() throws Exception {
+        GraphEventResponseHandler graphEventResponseHandler = new GraphEventResponseHandler();
+        GraphEvent event = GraphEvent.builder(GraphEventOperation.CREATE).build();
+        graphEventResponseHandler.handleBulkEventResponse(event, new GraphEventEnvelope(event));
     }
 }
index c768339..7a409ec 100644 (file)
  */
 package org.onap.crud.service;
 
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-
-import org.junit.Test;
-import org.onap.crud.parser.BulkPayload;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.ws.rs.core.Response.Status;
+import org.junit.Test;
+import org.onap.crud.exception.CrudException;
+import org.onap.crud.parser.BulkPayload;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
 
 
 public class BulkPayloadTest {
@@ -70,4 +73,23 @@ public class BulkPayloadTest {
     System.out.println("root: " + root.toString());
     System.out.println("payload ids: " + ids.toString());
   }
-}
\ No newline at end of file
+  
+    @Test
+    public void testExceptionHandling() {
+        String payload = null;
+        try {
+            BulkPayload.fromJson(payload);
+        } catch (CrudException e) {
+            assertThat(e.getHttpStatus(), is(Status.BAD_REQUEST));
+            assertThat(e.getMessage(), is("Invalid Json Payload"));
+        }
+
+        payload = "Invalid Json";
+        try {
+            BulkPayload.fromJson(payload);
+        } catch (CrudException e) {
+            assertThat(e.getHttpStatus(), is(Status.BAD_REQUEST));
+            assertThat(e.getMessage(), is("Invalid Json Payload"));
+        }
+    }
+}
diff --git a/src/test/java/org/onap/crud/service/ChampDaoExceptionsTest.java b/src/test/java/org/onap/crud/service/ChampDaoExceptionsTest.java
new file mode 100644 (file)
index 0000000..1f0a20b
--- /dev/null
@@ -0,0 +1,787 @@
+/**
+ * ï»¿============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 Amdocs
+ * ================================================================================
+ * 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=========================================================
+ */
+package org.onap.crud.service;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.core.MediaType;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aai.cl.mdc.MdcContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.crud.dao.champ.ChampDao;
+import org.onap.crud.entity.Edge;
+import org.onap.crud.entity.Vertex;
+import org.onap.crud.exception.CrudException;
+import org.slf4j.MDC;
+
+public class ChampDaoExceptionsTest {
+    // @formatter:off
+               private final String champVertex = "{" +
+                   "\"key\": \"test-uuid\"," +
+                   "\"type\": \"vertexType\"," +
+                   "\"properties\": {" +
+                   "\"fqdn\": \"myhost.onap.com\"," +
+                   "\"hostname\": \"myhost\" } }";
+               
+               private final String champEdge = "{" +
+                           "\"key\": \"test-uuid\"," +
+                           "\"type\": \"edgeType\"," +
+                           "\"properties\": {" +
+                           "\"prevent-delete\": \"NONE\" }," +
+                           "\"source\": {" +
+                           "\"key\": \"50bdab41-ad1c-4d00-952c-a0aa5d827811\", \"type\": \"vserver\"}," +
+                           "\"target\": {" +
+                           "\"key\": \"1d326bc7-b985-492b-9604-0d5d1f06f908\", \"type\": \"pserver\"}" +
+                           " }";
+               
+               private final String vertexPayload = "{" + 
+                       "\"type\":\"pserver\"," + 
+                       "\"properties\":{" + 
+                       "\"aai-node-type\":\"pserver\"}}";
+               // @formatter:on
+
+    private RestClient restClientMock;
+    private ChampDao champDao;
+
+    static final String CHAMP_URL = "https://host:9522/services/champ-service/v1/";
+    static final String OBJECT_SUB_URL = "objects";
+    static final String RELATIONSHIP_SUB_URL = "relationships";
+    static final String TRANSACTION_SUB_URL = "transaction";
+    static final String BASE_OBJECT_URL = CHAMP_URL + OBJECT_SUB_URL;
+    static final String HEADER_FROM_APP = "X-FromAppId";
+    static final String HEADER_TRANS_ID = "X-TransactionId";
+    static final String FROM_APP_NAME = "Gizmo";
+
+    @Before
+    public void setup() {
+        restClientMock = mock(RestClient.class);
+    }
+
+    @Test
+    public void testGetVertexIdNotExists() {
+        String id = "test-id";
+        String idNotExists = "test-id-not-exists";
+        String type = "pserver";
+        String version = "v11";
+        String failureCauseForGetVertex = "No vertex with id " + id + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetVertex(idNotExists, "", "", type, 404, failureCauseForGetVertex);
+        buildChampDao();
+
+        try {
+            champDao.getVertex(idNotExists, version);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetVertex));
+        }
+    }
+
+    @Test
+    public void testGetVertexIdNotExistsWithQueryParams() {
+        String id = "test-id";
+        String idNotExists = "test-id-not-exists";
+        String queryParamsForMock = "?hostname=myhost";
+        String type = "pserver";
+        String version = "v11";
+        String failureCauseForGetVertex = "No vertex with id " + id + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetVertex(idNotExists, queryParamsForMock, "", type, 404, failureCauseForGetVertex);
+        buildChampDao();
+
+        try {
+            champDao.getVertex(idNotExists, type, version, queryParams);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetVertex));
+        }
+    }
+
+    @Test
+    public void testGetVertexWithQueryParamsTypeNotMatch() {
+        String id = "test-id";
+        String queryParamsForMock = "?hostname=myhost";
+        String type = "pserver";
+        String version = "v11";
+        String failureCauseForGetVertexTypeNotMatches = "No vertex with id " + id + " and type vserver found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetVertex(id, queryParamsForMock, "", type, 200, "");
+        buildChampDao();
+
+        try {
+            champDao.getVertex(id, "vserver", version, queryParams);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetVertexTypeNotMatches));
+        }
+    }
+
+    @Test
+    public void testGetVertexIdNotExistsWithTxId() {
+        String id = "test-id";
+        String idNotExists = "test-id-not-exists";
+        String txId = "1234";
+        String type = "pserver";
+        String version = "v11";
+        String failureCauseForGetVertex = "No vertex with id " + id + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetVertex(idNotExists, "", txId, type, 404, failureCauseForGetVertex);
+        buildChampDao();
+
+        try {
+            champDao.getVertex(idNotExists, type, version, txId);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetVertex));
+        }
+    }
+
+    @Test
+    public void testGetVertexWithTxIdAndTypeNotMatch() {
+        String id = "test-id";
+        String txId = "1234";
+        String type = "pserver";
+        String version = "v11";
+        String failureCauseForGetVertexTypeNotMatches = "No vertex with id " + id + " and type vserver found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetVertex(id, "", txId, type, 200, "");
+        buildChampDao();
+
+        try {
+            champDao.getVertex(id, "vserver", version, txId);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetVertexTypeNotMatches));
+        }
+    }
+
+    @Test
+    public void testGetVertices() {
+        String queryParamsForMockGetVertices = "?aai-node-type=pserver";
+        String type = "pserver";
+        String version = "v11";
+        String failureCauseForGetVertices = "No vertices found in graph for given filters";
+
+        Map<String, Object> filter = new HashMap<>();
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetVertices(queryParamsForMockGetVertices, type, 404, failureCauseForGetVertices);
+        buildChampDao();
+
+        try {
+            champDao.getVertices(type, filter, version);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetVertices));
+        }
+    }
+
+    @Test
+    public void testGetEdgeIdNotExists() {
+        String idNotExists = "test-id-not-exists";
+        String id = "test-id";
+        String txId = "1234";
+        String type = "tosca.relationships.HostedOn";
+        String failureCauseForGetEdge = "No edge with id " + id + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetEdge(idNotExists, "", txId, type, 404, failureCauseForGetEdge);
+        buildChampDao();
+
+        try {
+            champDao.getEdge(idNotExists, type, txId);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetEdge));
+        }
+    }
+
+    @Test
+    public void testGetEdgeTypeNotMatch() {
+        String id = "test-id";
+        String txId = "1234";
+        String type = "tosca.relationships.HostedOn";
+        String failureCauseForGetEdgeTypeNotMatches = "No edge with id " + id + " and type " + "" + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetEdge(id, "", txId, type, 200, "");
+        buildChampDao();
+
+        // Type not matches
+        try {
+            champDao.getEdge(id, "", txId);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetEdgeTypeNotMatches));
+        }
+    }
+
+    @Test
+    public void testGetEdgeIdNotExistsWithQueryParams() {
+        String idNotExists = "test-id-not-exists";
+        String id = "test-id";
+        String queryParamsForMock = "?hostname=myhost";
+        String type = "tosca.relationships.HostedOn";
+        String failureCauseForGetEdge = "No edge with id " + id + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetEdge(idNotExists, queryParamsForMock, "", type, 404, failureCauseForGetEdge);
+        buildChampDao();
+
+        try {
+            champDao.getEdge(idNotExists, type, queryParams);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetEdge));
+        }
+    }
+
+    @Test
+    public void testGetEdgeTypeNotMatchWithQueryParams() {
+        String id = "test-id";
+        String queryParamsForMock = "?hostname=myhost";
+        String type = "tosca.relationships.HostedOn";
+        String failureCauseForGetEdgeTypeNotMatches = "No edge with id " + id + " and type " + "" + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetEdge(id, queryParamsForMock, "", type, 200, "");
+        buildChampDao();
+
+        // Type not matches
+        try {
+            champDao.getEdge(id, "", queryParams);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetEdgeTypeNotMatches));
+        }
+    }
+
+    @Test
+    public void testGetEdges() {
+        String type = "tosca.relationships.HostedOn";
+        String failureCauseForGetEdges = "No edges found in graph for given filters";
+
+        Map<String, Object> filter = new HashMap<>();
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetEdges("?", type, 404, failureCauseForGetEdges);
+        buildChampDao();
+
+        try {
+            champDao.getEdges(type, filter);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetEdges));
+        }
+    }
+
+    @Test
+    public void testGetVertexEdges() {
+        String idNotExists = "test-id-not-exists";
+        String id = "test-id";
+        String queryParamsForMock = "?hostname=myhost";
+        String type = "tosca.relationships.HostedOn";
+        String failureCauseForGetVertexEdges = "No vertex with id " + id + " found in graph";
+
+        Map<String, String> queryParams = new HashMap<>();
+        queryParams.put("hostname", "myhost");
+        mockGetVertexEdges(idNotExists, queryParamsForMock, type, 404, failureCauseForGetVertexEdges);
+        buildChampDao();
+
+        try {
+            champDao.getVertexEdges(idNotExists, queryParams);
+        } catch (CrudException e) {
+            assertEquals(404, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseForGetVertexEdges));
+        }
+    }
+
+    @Test
+    public void addVertexTest() {
+        String type = "pserver";
+        String txId = "1234";
+        String version = "v11";
+
+        Map<String, Object> properties = new HashMap<>();
+
+        mockAddVertex(type, vertexPayload, "", 400);
+        mockAddVertex(type, vertexPayload, txId, 400);
+        buildChampDao();
+
+        try {
+            champDao.addVertex(type, properties, version);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to create vertex"));
+        }
+
+        try {
+            champDao.addVertex(type, properties, version, txId);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to create vertex"));
+        }
+    }
+
+    @Test
+    public void addEdgeTest() throws CrudException {
+        String txId = "1234";
+        String vertexType = "pserver";
+        String edgeType = "tosca.relationships.HostedOn";
+        String version = "v11";
+
+        Map<String, Object> properties = new HashMap<>();
+
+        mockGetVertex("test-uuid", "", "", "pserver", 200, "");
+        mockGetVertex("test-uuid", "", txId, "pserver", 200, "");
+        mockAddEdge(edgeType, "", 400);
+        mockAddEdge(edgeType, txId, 400);
+        buildChampDao();
+
+        String vertex = champVertex.replace("vertexType", vertexType);
+        Vertex source = Vertex.fromJson(vertex, "v11");
+        Vertex target = Vertex.fromJson(vertex, "v11");
+
+        try {
+            champDao.addEdge(edgeType, source, target, properties, version);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to create edge"));
+        }
+
+        try {
+            champDao.addEdge(edgeType, source, target, properties, version, txId);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to create edge"));
+        }
+    }
+
+    @Test
+    public void updateVertexTest() {
+        String id = "test-id";
+        String type = "pserver";
+        String txId = "1234";
+        String version = "v11";
+
+        Map<String, Object> properties = new HashMap<>();
+
+        mockPutVertex(id, type, "", 400);
+        mockPutVertex(id, type, txId, 400);
+        buildChampDao();
+
+        try {
+            champDao.updateVertex(id, type, properties, version);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to update vertex"));
+        }
+
+        try {
+            champDao.updateVertex(id, type, properties, version, txId);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to update vertex"));
+        }
+    }
+
+    @Test
+    public void updateEdgeTest() {
+        String id = "test-uuid";
+        String txId = "1234";
+        String type = "tosca.relationships.HostedOn";
+
+        mockPutEdge(id, type, "", 400);
+        mockPutEdge(id, type, txId, 400);
+        buildChampDao();
+
+        String champJson = champEdge.replace("\"test-uuid\"", "null").replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        try {
+            champDao.updateEdge(edge);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Unable to identify edge"));
+        }
+
+        try {
+            champDao.updateEdge(edge, txId);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Unable to identify edge"));
+        }
+
+        champJson = champEdge.replace("edgeType", type);
+        edge = Edge.fromJson(champJson);
+
+        try {
+            champDao.updateEdge(edge);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to update edge"));
+        }
+
+        try {
+            champDao.updateEdge(edge, txId);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to update edge"));
+        }
+    }
+
+    @Test
+    public void deleteVertexTest() {
+        String id = "test-id";
+        String type = "pserver";
+        String txId = "1234";
+
+        mockDeleteVertex(id, type, "", 400);
+        mockDeleteVertex(id, type, txId, 400);
+        buildChampDao();
+
+        try {
+            champDao.deleteVertex(id, type);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to delete vertex"));
+        }
+        try {
+            champDao.deleteVertex(id, type, txId);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Failed to delete vertex"));
+        }
+    }
+
+    @Test
+    public void deleteEdgeTest() {
+        String id = "test-uuid";
+        String txId = "1234";
+        String type = "tosca.relationships.HostedOn";
+        String failureCauseFordeleteEdge = "No edge with id " + id + " found in graph";
+
+        mockDeleteEdge(id, type, "", 400, failureCauseFordeleteEdge);
+        mockDeleteEdge(id, type, txId, 400, failureCauseFordeleteEdge);
+        buildChampDao();
+
+        try {
+            champDao.deleteEdge(id, type);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseFordeleteEdge));
+        }
+        try {
+            champDao.deleteEdge(id, type, txId);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString(failureCauseFordeleteEdge));
+        }
+    }
+
+    @Test
+    public void transactionsTest() {
+        String id = "test-id";
+        int resultCode = 500;
+
+        mockOpenTransaction(resultCode);
+        mockRollbackTransaction(id, resultCode);
+        mockCommitTransaction(id, resultCode);
+        buildChampDao();
+
+        String response = champDao.openTransaction();
+        assertEquals(null, response);
+
+        try {
+            champDao.rollbackTransaction(id);
+        } catch (CrudException e) {
+            assertEquals(500, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Unable to rollback transaction"));
+        }
+
+        try {
+            champDao.commitTransaction(id);
+        } catch (CrudException e) {
+            assertEquals(500, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), containsString("Unable to commit transaction"));
+        }
+    }
+
+    public void buildChampDao() {
+        String baseRelationshipUrl = CHAMP_URL + RELATIONSHIP_SUB_URL;
+        String baseTransactionUrl = CHAMP_URL + TRANSACTION_SUB_URL;
+        champDao = new ChampDao(restClientMock, BASE_OBJECT_URL, baseRelationshipUrl, baseTransactionUrl);
+    }
+
+    public void mockOpenTransaction(int resultCode) {
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult("");
+        operationResult.setResultCode(resultCode);
+        String url = CHAMP_URL + "transaction";
+
+        when(restClientMock.post(url, "", createHeader(), MediaType.TEXT_PLAIN_TYPE, MediaType.TEXT_PLAIN_TYPE))
+                .thenReturn(operationResult);
+    }
+
+    public void mockRollbackTransaction(String id, int resultCode) {
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult("");
+        operationResult.setResultCode(resultCode);
+        String url = CHAMP_URL + TRANSACTION_SUB_URL + "/" + id;
+
+        when(restClientMock.put(url, "{\"method\": \"rollback\"}", createHeader(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.TEXT_PLAIN_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockCommitTransaction(String id, int resultCode) {
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult("");
+        operationResult.setResultCode(resultCode);
+        String url = CHAMP_URL + TRANSACTION_SUB_URL + "/" + id;
+
+        when(restClientMock.put(url, "{\"method\": \"commit\"}", createHeader(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.TEXT_PLAIN_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetVertex(String id, String queryParams, String txId, String type, int resultCode,
+            String failureCause) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(resultCode);
+        operationResult.setFailureCause(failureCause);
+        String url;
+
+        if (queryParams != null && !queryParams.isEmpty() && (txId.isEmpty() || txId == null)) {
+            url = BASE_OBJECT_URL + "/" + id + queryParams;
+        } else if (txId != null && !txId.isEmpty() && (queryParams.isEmpty() || queryParams == null)) {
+            url = BASE_OBJECT_URL + "/" + id + "?transactionId=" + txId;
+        } else {
+            url = BASE_OBJECT_URL + "/" + id;
+        }
+
+        when(restClientMock.get(url, createHeader(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetVertexEdges(String id, String queryParams, String type, int resultCode, String failureCause) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        List<String> edgeResponselist = new ArrayList<>();
+        edgeResponselist.add(edgeResponse);
+        operationResult.setResult(edgeResponselist.toString());
+        operationResult.setResultCode(resultCode);
+        operationResult.setFailureCause(failureCause);
+
+        String url = BASE_OBJECT_URL + "/" + RELATIONSHIP_SUB_URL + "/" + id + queryParams;
+
+        when(restClientMock.get(url, createHeader(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetVertices(String queryParams, String type, int resultCode, String failureCause) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        List<String> vertexResponselist = new ArrayList<>();
+        vertexResponselist.add(vertexResponse);
+        operationResult.setResult(vertexResponselist.toString());
+        operationResult.setResultCode(resultCode);
+        operationResult.setFailureCause(failureCause);
+
+        String url = BASE_OBJECT_URL + "/" + "filter" + queryParams;
+
+        when(restClientMock.get(url, createHeader(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetEdges(String queryParams, String type, int resultCode, String failureCause) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        List<String> edgeResponselist = new ArrayList<>();
+        edgeResponselist.add(edgeResponse);
+        operationResult.setResult(edgeResponselist.toString());
+        operationResult.setResultCode(resultCode);
+        operationResult.setFailureCause(failureCause);
+
+        String url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + "filter" + queryParams;
+
+        when(restClientMock.get(url, createHeader(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetEdge(String id, String queryParams, String txId, String type, int resultCode,
+            String failureCause) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(resultCode);
+        operationResult.setFailureCause(failureCause);
+
+        String url;
+
+        if (queryParams != null && !queryParams.isEmpty() && (txId.isEmpty() || txId == null)) {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id + queryParams;
+        } else if (txId != null && !txId.isEmpty() && (queryParams.isEmpty() || queryParams == null)) {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id + "?transactionId=" + txId;
+        } else {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id;
+        }
+
+        when(restClientMock.get(url, createHeader(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockAddEdge(String type, String txId, int resultCode) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(resultCode);
+
+        String url;
+        if (txId != null && !txId.isEmpty()) {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "?transactionId=" + txId;
+        } else {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL;
+        }
+
+        when(restClientMock.post(eq(url), anyString(), eq(createHeader()), eq(MediaType.APPLICATION_JSON_TYPE),
+                eq(MediaType.APPLICATION_JSON_TYPE))).thenReturn(operationResult);
+    }
+
+    public void mockAddVertex(String type, String payload, String txId, int resultCode) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(resultCode);
+
+        String url;
+        if (txId != null && !txId.isEmpty()) {
+            url = BASE_OBJECT_URL + "?transactionId=" + txId;
+        } else {
+            url = BASE_OBJECT_URL;
+        }
+
+        when(restClientMock.post(url, payload, createHeader(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockPutVertex(String id, String type, String txId, int resultCode) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(resultCode);
+
+        String url;
+        if (txId != null && !txId.isEmpty()) {
+            url = BASE_OBJECT_URL + "/" + id + "?transactionId=" + txId;
+        } else {
+            url = BASE_OBJECT_URL + "/" + id;
+        }
+
+        when(restClientMock.put(eq(url), anyString(), eq(createHeader()), eq(MediaType.APPLICATION_JSON_TYPE),
+                eq(MediaType.APPLICATION_JSON_TYPE))).thenReturn(operationResult);
+    }
+
+    public void mockPutEdge(String id, String type, String txId, int resultCode) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(resultCode);
+
+        String url;
+        if (txId != null && !txId.isEmpty()) {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id + "?transactionId=" + txId;
+        } else {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id;
+        }
+
+        when(restClientMock.put(eq(url), anyString(), eq(createHeader()), eq(MediaType.APPLICATION_JSON_TYPE),
+                eq(MediaType.APPLICATION_JSON_TYPE))).thenReturn(operationResult);
+    }
+
+    public void mockDeleteVertex(String id, String type, String txId, int resultCode) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(resultCode);
+
+        String url;
+        if (txId != null && !txId.isEmpty()) {
+            url = BASE_OBJECT_URL + "/" + id + "?transactionId=" + txId;
+        } else {
+            url = BASE_OBJECT_URL + "/" + id;
+        }
+
+        when(restClientMock.delete(url, createHeader(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockDeleteEdge(String id, String type, String txId, int resultCode, String failureCause) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(resultCode);
+        operationResult.setFailureCause(failureCause);
+
+        String url;
+        if (txId != null && !txId.isEmpty()) {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id + "?transactionId=" + txId;
+        } else {
+            url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id;
+        }
+
+        when(restClientMock.delete(url, createHeader(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public ChampDao getChampDao() {
+        return champDao;
+    }
+
+    public void setChampDao(ChampDao champDao) {
+        this.champDao = champDao;
+    }
+
+    private Map<String, List<String>> createHeader() {
+        Map<String, List<String>> headers = new HashMap<>();
+        headers.put(HEADER_FROM_APP, Arrays.asList(FROM_APP_NAME));
+        headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(MdcContext.MDC_REQUEST_ID)));
+        return headers;
+    }
+}
diff --git a/src/test/java/org/onap/crud/service/ChampDaoMockTest.java b/src/test/java/org/onap/crud/service/ChampDaoMockTest.java
new file mode 100644 (file)
index 0000000..75d5bfd
--- /dev/null
@@ -0,0 +1,562 @@
+/**
+ * ï»¿============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 Amdocs
+ * ================================================================================
+ * 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=========================================================
+ */
+package org.onap.crud.service;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import org.onap.aai.logging.LoggingContext;
+import org.onap.aai.restclient.client.OperationResult;
+import org.onap.aai.restclient.client.RestClient;
+import org.onap.crud.dao.champ.ChampDao;
+import org.slf4j.MDC;
+
+public class ChampDaoMockTest {
+    // @formatter:off
+       private final String champVertex = "{" +
+           "\"key\": \"test-uuid\"," +
+           "\"type\": \"vertexType\"," +
+           "\"properties\": {" +
+           "\"fqdn\": \"myhost.onap.com\"," +
+           "\"hostname\": \"myhost\" } }";
+       
+       private final String champEdge = "{" +
+           "\"key\": \"test-uuid\"," +
+           "\"type\": \"edgeType\"," +
+           "\"properties\": {" +
+           "\"prevent-delete\": \"NONE\" }," +
+           "\"source\": {" +
+           "\"key\": \"50bdab41-ad1c-4d00-952c-a0aa5d827811\", \"type\": \"vserver\"}," +
+           "\"target\": {" +
+           "\"key\": \"1d326bc7-b985-492b-9604-0d5d1f06f908\", \"type\": \"pserver\"}" +
+           " }";
+       
+       private final String edgePayload = "{" + 
+               "\"type\":\"tosca.relationships.HostedOn\"," + 
+               "\"properties\":{" + 
+               "\"prevent-delete\":\"NONE\"}," + 
+               "\"source\":{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"vserver\"," + 
+               "\"properties\":{}}," + 
+               "\"target\":{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{" + 
+               "\"hostname\":\"myhost\"," + 
+               "\"fqdn\":\"myhost.onap.com\"}}}";
+
+       private final String edgePayloadForPut = "{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"tosca.relationships.HostedOn\"," + 
+               "\"properties\":{" + 
+               "\"prevent-delete\":\"NONE\"}," + 
+               "\"source\":{" + 
+               "\"key\":\"50bdab41-ad1c-4d00-952c-a0aa5d827811\"," + 
+               "\"type\":\"vserver\"," + 
+               "\"properties\":{}}," + 
+               "\"target\":{" + 
+               "\"key\":\"1d326bc7-b985-492b-9604-0d5d1f06f908\"," + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{}}}";
+       
+       private final String edgePayloadForPatch = "{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"tosca.relationships.HostedOn\"," + 
+               "\"properties\":{" + 
+               "\"prevent-delete\":\"NONE\"}," + 
+               "\"source\":{" + 
+               "\"key\":\"50bdab41-ad1c-4d00-952c-a0aa5d827811\"," + 
+               "\"type\":\"vserver\"}," + 
+               "\"target\":{" + 
+               "\"key\":\"1d326bc7-b985-492b-9604-0d5d1f06f908\"," + 
+               "\"type\":\"pserver\"}}";
+       
+       private final String edgePayloadForPost = "{" + 
+               "\"type\":\"tosca.relationships.HostedOn\"," + 
+               "\"properties\":{" + 
+               "\"SVC-INFRA\":\"OUT\"," + 
+               "\"prevent-delete\":\"IN\"," + 
+               "\"delete-other-v\":\"NONE\"," + 
+               "\"contains-other-v\":\"NONE\"" + 
+               "}," + 
+               "\"source\":{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"vserver\"," + 
+               "\"properties\":{" + 
+               "" + 
+               "}" + 
+               "}," + 
+               "\"target\":{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{" + 
+               "\"hostname\":\"myhost\"," + 
+               "\"fqdn\":\"myhost.onap.com\"" + 
+               "}" + 
+               "}" + 
+               "}";
+       
+       private final String edgePayloadForPutNoProperties = "{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"tosca.relationships.HostedOn\"," + 
+               "\"properties\":{" + 
+               "\"SVC-INFRA\":\"OUT\"," + 
+               "\"prevent-delete\":\"IN\"," + 
+               "\"delete-other-v\":\"NONE\"," + 
+               "\"contains-other-v\":\"NONE\"" + 
+               "}," + 
+               "\"source\":{" + 
+               "\"key\":\"50bdab41-ad1c-4d00-952c-a0aa5d827811\"," + 
+               "\"type\":\"vserver\"," + 
+               "\"properties\":{" + 
+               "" + 
+               "}" + 
+               "}," + 
+               "\"target\":{" + 
+               "\"key\":\"1d326bc7-b985-492b-9604-0d5d1f06f908\"," + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{" + 
+               "" + 
+               "}" + 
+               "}" + 
+               "}";
+       
+       private final String vertexPayload = "{" + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{" + 
+               "\"hostname\":\"myhost\"," + 
+               "\"in-maint\":false," + 
+               "\"fqdn\":\"myhost.onap.com\"," + 
+               "\"last-mod-source-of-truth\":\"source-of-truth\"," + 
+               "\"source-of-truth\":\"source-of-truth\"," + 
+               "\"aai-node-type\":\"pserver\"}}";
+       
+       private final String vertexPayloadForVserver = "{" + 
+               "\"type\":\"vserver\"," + 
+               "\"properties\":{" + 
+               "\"in-maint\":false," + 
+               "\"vserver-name\":\"test-vserver\"," + 
+               "\"vserver-id\":\"VSER1\"," + 
+               "\"last-mod-source-of-truth\":\"source-of-truth\"," + 
+               "\"vserver-name2\":\"alt-test-vserver\"," + 
+               "\"source-of-truth\":\"source-of-truth\"," + 
+               "\"vserver-selflink\":\"http://1.2.3.4/moreInfo\"," + 
+               "\"is-closed-loop-disabled\":false," + 
+               "\"aai-node-type\":\"vserver\"}}";
+       
+       private final String vertexPayloadForPserver = "{" + 
+               "\"key\":\"50bdab41-ad1c-4d00-952c-a0aa5d827811\"," + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{" + 
+               "\"ptnii-equip-name\":\"e-name\"," + 
+               "\"hostname\":\"steve-host2\"," + 
+               "\"equip-type\":\"server\"," + 
+               "\"equip-vendor\":\"HP\"," + 
+               "\"equip-model\":\"DL380p-nd\"," + 
+               "\"in-maint\":false," + 
+               "\"fqdn\":\"myhost.onap.net\"," + 
+               "\"purpose\":\"my-purpose\"," + 
+               "\"ipv4-oam-address\":\"1.2.3.4\"," + 
+               "\"last-mod-source-of-truth\":\"source-of-truth\"," + 
+               "\"aai-node-type\":\"pserver\"}}";
+       
+       private final String vertexPayloadForPut = "{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{" + 
+               "\"hostname\":\"myhost\"," + 
+               "\"in-maint\":false," + 
+               "\"fqdn\":\"myhost.onap.com\"," + 
+               "\"last-mod-source-of-truth\":\"source-of-truth\"," + 
+               "\"aai-node-type\":\"pserver\"}}";
+       
+       private final String vertexPayloadForPatch = "{" + 
+               "\"key\":\"test-uuid\"," + 
+               "\"type\":\"pserver\"," + 
+               "\"properties\":{" + 
+               "\"hostname\":\"myhost\"," + 
+               "\"fqdn\":\"myhost.onap.com\"," + 
+               "\"last-mod-source-of-truth\":\"source-of-truth\"," + 
+               "\"aai-node-type\":\"pserver\"}}";
+       // @formatter:on
+
+    private RestClient restClientMock;
+    private ChampDao champDao;
+
+    static final String CHAMP_URL = "https://host:9522/services/champ-service/v1/";
+    static final String OBJECT_SUB_URL = "objects";
+    static final String RELATIONSHIP_SUB_URL = "relationships";
+    static final String TRANSACTION_SUB_URL = "transaction";
+    static final String BASE_OBJECT_URL = CHAMP_URL + OBJECT_SUB_URL;
+    static final String HEADER_FROM_APP = "X-FromAppId";
+    static final String HEADER_TRANS_ID = "X-TransactionId";
+    static final String FROM_APP_NAME = "Gizmo";
+    static final String HEADER_TRANS_ID_VALUE = "1234567890";
+
+    ChampDaoMockTest() {
+        restClientMock = mock(RestClient.class);
+        init();
+        buildChampDao();
+    }
+
+    public void init() {
+
+        Map<String, String> queryParamsVertex = new HashMap<>();
+        queryParamsVertex.put("_reserved_version", "v11");
+        queryParamsVertex.put("hostname", "myhost");
+        queryParamsVertex.put("_reserved_aai-type", "pserver");
+
+        Map<String, String> queryParamsVertexV13 = new HashMap<>();
+        queryParamsVertexV13.put("_reserved_version", "v13");
+        queryParamsVertexV13.put("hostname", "myhost");
+        queryParamsVertexV13.put("_reserved_aai-type", "pserver");
+
+        Map<String, String> queryParamsVertices = new HashMap<>();
+        queryParamsVertices.put("_reserved_version", "v11");
+        queryParamsVertices.put("hostname", "myhost");
+        queryParamsVertices.put("_reserved_aai-type", "pserver");
+        queryParamsVertices.put("aai-node-type", "pserver");
+
+        Map<String, String> queryParamsVerticesV13 = new HashMap<>();
+        queryParamsVerticesV13.put("_reserved_version", "v13");
+        queryParamsVerticesV13.put("hostname", "myhost");
+        queryParamsVerticesV13.put("_reserved_aai-type", "pserver");
+        queryParamsVerticesV13.put("aai-node-type", "pserver");
+
+        Map<String, String> queryParamsEdge = new HashMap<>();
+        queryParamsEdge.put("_reserved_version", "v11");
+        queryParamsEdge.put("hostname", "myhost");
+        queryParamsEdge.put("_reserved_aai-type", "tosca.relationships.HostedOn");
+
+        Map<String, String> emptyQueryParams = null;
+
+        mockOpenTransaction();
+        mockRollbackTransaction("");
+        mockTransactionExists("");
+        mockCommitTransaction("");
+        mockGetVertex("872dd5df-0be9-4167-95e9-2cf4b21165ed", queryParamsVertex, "pserver");
+        mockGetVertex("872dd5df-0be9-4167-95e9-2cf4b21165ed", queryParamsVertexV13, "pserver");
+        mockGetVertex("50bdab41-ad1c-4d00-952c-a0aa5d827811", "", "vserver");
+        mockGetVertex("1d326bc7-b985-492b-9604-0d5d1f06f908", "", "pserver");
+        mockGetVertex("1d326bc7-b985-492b-9604-0d5d1f06f908", "?transactionId=", "pserver");
+        mockGetVertex("test-uuid", "", "pserver");
+        mockGetVertex("50bdab41-ad1c-4d00-952c-a0aa5d827811", "?transactionId=", "vserver");
+        mockGetVertices(queryParamsVertices, "pserver");
+        mockGetVertices(queryParamsVerticesV13, "pserver");
+        mockGetVertexEdges("872dd5df-0be9-4167-95e9-2cf4b21165ed", queryParamsVertex, "tosca.relationships.HostedOn");
+        mockGetVertexEdges("872dd5df-0be9-4167-95e9-2cf4b21165ed", queryParamsVertexV13,
+                "tosca.relationships.HostedOn");
+        mockGetVertexEdges("50bdab41-ad1c-4d00-952c-a0aa5d827811", emptyQueryParams, "tosca.relationships.HostedOn");
+        mockGetVertexEdges("1d326bc7-b985-492b-9604-0d5d1f06f908", emptyQueryParams, "tosca.relationships.HostedOn");
+        mockGetEdges("?", "tosca.relationships.HostedOn");
+        mockGetEdge("50bdab41-ad1c-4d00-952c-a0aa5d827811", "?transactionId=", "tosca.relationships.HostedOn");
+        mockGetEdge("872dd5df-0be9-4167-95e9-2cf4b21165ed", emptyQueryParams, "tosca.relationships.HostedOn");
+        mockGetEdge("872dd5df-0be9-4167-95e9-2cf4b21165ed", queryParamsEdge, "tosca.relationships.HostedOn");
+        mockGetEdge("my-uuid", emptyQueryParams, "tosca.relationships.HostedOn");
+        mockGetEdge("50bdab41-ad1c-4d00-952c-a0aa5d827811", queryParamsEdge, "tosca.relationships.HostedOn");
+        mockPostEdge("tosca.relationships.HostedOn", "", edgePayload);
+        mockPostEdge("tosca.relationships.HostedOn", "?transactionId=", edgePayloadForPost);
+        mockPostVertex("pserver", vertexPayload, "");
+        mockPostVertex("vserver", vertexPayloadForVserver, "?transactionId=");
+        mockPutVertex("test-uuid", "pserver", vertexPayloadForPut, "");
+        mockPutVertex("test-uuid", "pserver", vertexPayloadForPatch, "");
+        mockPutVertex("50bdab41-ad1c-4d00-952c-a0aa5d827811", "pserver", vertexPayloadForPserver, "?transactionId=");
+        mockPutEdge("test-uuid", "tosca.relationships.HostedOn", "", edgePayloadForPut);
+        mockPutEdge("test-uuid", "tosca.relationships.HostedOn", "", edgePayloadForPatch);
+        mockPutEdge("test-uuid", "tosca.relationships.HostedOn", "?transactionId=", edgePayloadForPutNoProperties);
+        mockDeleteVertex("872dd5df-0be9-4167-95e9-2cf4b21165ed", "pserver", "");
+        mockDeleteVertex("50bdab41-ad1c-4d00-952c-a0aa5d827811", "pserver", "?transactionId=");
+        mockDeleteEdge("872dd5df-0be9-4167-95e9-2cf4b21165ed", "tosca.relationships.HostedOn", "");
+        mockDeleteEdge("50bdab41-ad1c-4d00-952c-a0aa5d827811", "tosca.relationships.HostedOn", "?transactionId=");
+    }
+
+    public void buildChampDao() {
+        String baseRelationshipUrl = CHAMP_URL + RELATIONSHIP_SUB_URL;
+        String baseTransactionUrl = CHAMP_URL + TRANSACTION_SUB_URL;
+        champDao = new ChampDao(restClientMock, BASE_OBJECT_URL, baseRelationshipUrl, baseTransactionUrl);
+    }
+
+    public void mockOpenTransaction() {
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult("");
+        operationResult.setResultCode(200);
+        String url = CHAMP_URL + "transaction";
+
+
+        when(restClientMock.post(url, "", createHeaders(), MediaType.TEXT_PLAIN_TYPE, MediaType.TEXT_PLAIN_TYPE))
+                .thenReturn(operationResult);
+    }
+
+    public void mockRollbackTransaction(String id) {
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult("");
+        operationResult.setResultCode(200);
+        String url = CHAMP_URL + TRANSACTION_SUB_URL + "/" + id;
+
+
+        when(restClientMock.put(url, "{\"method\": \"rollback\"}", createHeaders(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.TEXT_PLAIN_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockCommitTransaction(String id) {
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult("");
+        operationResult.setResultCode(200);
+        String url = CHAMP_URL + TRANSACTION_SUB_URL + "/" + id;
+
+
+        when(restClientMock.put(url, "{\"method\": \"commit\"}", createHeaders(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.TEXT_PLAIN_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockTransactionExists(String id) {
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult("");
+        operationResult.setResultCode(200);
+        String url = CHAMP_URL + TRANSACTION_SUB_URL + "/" + id;
+
+        Map<String, List<String>> headers = new HashMap<>();
+        headers.put(HEADER_FROM_APP, Arrays.asList(FROM_APP_NAME));
+        headers.put(HEADER_TRANS_ID, Arrays.asList(MDC.get(LoggingContext.LoggingField.REQUEST_ID.toString())));
+
+        when(restClientMock.get(url, headers, MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetVertex(String id, String txId, String type) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(200);
+
+        String url = BASE_OBJECT_URL + "/" + id + txId;
+
+
+        when(restClientMock.get(url, createHeaders(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetVertex(String id, Map<String, String> queryParams, String type) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(200);
+
+        StringBuilder url = appendQueryParams(BASE_OBJECT_URL + "/" + id, queryParams);
+
+        when(restClientMock.get(url.toString(), createHeaders(), MediaType.APPLICATION_JSON_TYPE))
+                .thenReturn(operationResult);
+    }
+
+    public void mockGetVertexEdges(String id, Map<String, String> queryParams, String type) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        List<String> edgeResponselist = new ArrayList<>();
+        edgeResponselist.add(edgeResponse);
+        operationResult.setResult(edgeResponselist.toString());
+        operationResult.setResultCode(200);
+
+        StringBuilder url = appendQueryParams(BASE_OBJECT_URL + "/" + RELATIONSHIP_SUB_URL + "/" + id, queryParams);
+
+        when(restClientMock.get(url.toString(), createHeaders(), MediaType.APPLICATION_JSON_TYPE))
+                .thenReturn(operationResult);
+    }
+
+    public void mockGetVertices(Map<String, String> queryParams, String type) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        List<String> vertexResponselist = new ArrayList<>();
+        vertexResponselist.add(vertexResponse);
+        operationResult.setResult(vertexResponselist.toString());
+        operationResult.setResultCode(200);
+
+        StringBuilder url = appendQueryParams(BASE_OBJECT_URL + "/" + "filter", queryParams);
+
+        when(restClientMock.get(url.toString(), createHeaders(), MediaType.APPLICATION_JSON_TYPE))
+                .thenReturn(operationResult);
+    }
+
+    public void mockGetEdges(String queryParams, String type) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        List<String> edgeResponselist = new ArrayList<>();
+        edgeResponselist.add(edgeResponse);
+        operationResult.setResult(edgeResponselist.toString());
+        operationResult.setResultCode(200);
+
+        String url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + "filter" + queryParams;
+
+
+        when(restClientMock.get(url, createHeaders(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetEdge(String id, String txId, String type) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(200);
+
+        String url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id + txId;
+
+        when(restClientMock.get(url, createHeaders(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockGetEdge(String id, Map<String, String> queryParams, String type) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(200);
+
+        StringBuilder url = appendQueryParams(CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id, queryParams);
+
+        when(restClientMock.get(url.toString(), createHeaders(), MediaType.APPLICATION_JSON_TYPE))
+                .thenReturn(operationResult);
+    }
+
+    public void mockPostEdge(String type, String txId, String payload) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(201);
+        MultivaluedMap<String, String> headers = new MultivaluedHashMap<String, String>();
+        headers.add("etag", "test123");
+        operationResult.setHeaders(headers);
+
+        String baseRelationshipUrl = CHAMP_URL + RELATIONSHIP_SUB_URL + txId;
+        String url = baseRelationshipUrl;
+
+
+        when(restClientMock.post(url, payload, createHeaders(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockPostVertex(String type, String payload, String txId) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(201);
+        MultivaluedMap<String, String> headers = new MultivaluedHashMap<String, String>();
+        headers.add("etag", "test123");
+        operationResult.setHeaders(headers);
+
+        String url = BASE_OBJECT_URL + txId;
+
+
+        when(restClientMock.post(url, payload, createHeaders(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockPutVertex(String id, String type, String payload, String txId) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(200);
+        MultivaluedMap<String, String> headers = new MultivaluedHashMap<String, String>();
+        headers.add("etag", "test123");
+        operationResult.setHeaders(headers);
+
+        String url = BASE_OBJECT_URL + "/" + id + txId;
+
+
+        when(restClientMock.put(url, payload, createHeaders(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockPutEdge(String id, String type, String txId, String payload) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(200);
+        MultivaluedMap<String, String> headers = new MultivaluedHashMap<String, String>();
+        headers.add("etag", "test123");
+        operationResult.setHeaders(headers);
+
+        String url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id + txId;
+
+
+        when(restClientMock.put(url, payload, createHeaders(), MediaType.APPLICATION_JSON_TYPE,
+                MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockDeleteVertex(String id, String type, String txId) {
+        String vertexResponse = champVertex.replace("vertexType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(vertexResponse);
+        operationResult.setResultCode(200);
+
+        String url = BASE_OBJECT_URL + "/" + id + txId;
+
+
+        when(restClientMock.delete(url, createHeaders(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    public void mockDeleteEdge(String id, String type, String txId) {
+        String edgeResponse = champEdge.replace("edgeType", type);
+        OperationResult operationResult = new OperationResult();
+        operationResult.setResult(edgeResponse);
+        operationResult.setResultCode(200);
+
+        String url = CHAMP_URL + RELATIONSHIP_SUB_URL + "/" + id + txId;
+
+
+        when(restClientMock.delete(url, createHeaders(), MediaType.APPLICATION_JSON_TYPE)).thenReturn(operationResult);
+    }
+
+    private Map<String, List<String>> createHeaders() {
+        Map<String, List<String>> headers = new HashMap<>();
+        List<String> listFromApp = new ArrayList<>();
+        List<String> listTransId = new ArrayList<>();
+        listFromApp.add(FROM_APP_NAME);
+        listTransId.add(HEADER_TRANS_ID_VALUE);
+        headers.put(HEADER_FROM_APP, listFromApp);
+        headers.put(HEADER_TRANS_ID, listTransId);
+
+        return headers;
+    }
+
+    private StringBuilder appendQueryParams(String url, Map<String, String> queryParams) {
+        StringBuilder strBuilder = new StringBuilder(url);
+
+        if (queryParams != null) {
+            String prefix = "?";
+            for (Map.Entry<String, String> entry : queryParams.entrySet()) {
+                strBuilder.append(prefix);
+                prefix = "&";
+                strBuilder.append(entry.getKey() + "=" + entry.getValue());
+            }
+        }
+        return strBuilder;
+    }
+
+    public ChampDao getChampDao() {
+        return champDao;
+    }
+
+    public void setChampDao(ChampDao champDao) {
+        this.champDao = champDao;
+    }
+}
index ddf3847..d8be704 100644 (file)
@@ -77,12 +77,11 @@ public class CrudRestServiceTest {
 
   @Before
   public void init() throws Exception {
-    ClassLoader classLoader = getClass().getClassLoader();
-    File dir = new File(classLoader.getResource("rules").getFile());
-    System.setProperty("CONFIG_HOME", dir.getParent());
+    System.setProperty("CONFIG_HOME", "src/test/resources");
     EdgeRulesLoader.resetSchemaVersionContext();
 
-    CrudGraphDataService service = new CrudGraphDataService(new TestDao());
+    ChampDaoMockTest champDaoTest = new ChampDaoMockTest();
+    CrudGraphDataService service = new CrudGraphDataService(champDaoTest.getChampDao());
     CrudRestService restService = new CrudRestService(service, null);
     mockService = Mockito.spy(restService);
 
diff --git a/src/test/java/org/onap/crud/service/TestEventConsumer.java b/src/test/java/org/onap/crud/service/TestEventConsumer.java
new file mode 100644 (file)
index 0000000..8f864f8
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * ï»¿============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 Amdocs
+ * ================================================================================
+ * 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=========================================================
+ */
+package org.onap.crud.service;
+
+import org.onap.aai.event.api.EventConsumer;
+import org.onap.aai.event.api.MessageWithOffset;
+
+public class TestEventConsumer implements EventConsumer {
+
+    @Override
+    public void commitOffsets() throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void commitOffsets(long arg0) throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public Iterable<String> consume() throws Exception {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Iterable<String> consumeAndCommit() throws Exception {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Iterable<MessageWithOffset> consumeWithOffsets() throws Exception {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/src/test/java/org/onap/crud/service/TestEventPublisher.java b/src/test/java/org/onap/crud/service/TestEventPublisher.java
new file mode 100644 (file)
index 0000000..3931c44
--- /dev/null
@@ -0,0 +1,82 @@
+/**
+ * ï»¿============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 Amdocs
+ * ================================================================================
+ * 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=========================================================
+ */
+package org.onap.crud.service;
+
+import java.util.Collection;
+import org.onap.aai.event.api.EventPublisher;
+
+public class TestEventPublisher implements EventPublisher {
+
+    @Override
+    public void close() throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void sendAsync(String arg0) throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void sendAsync(Collection<String> arg0) throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void sendAsync(String arg0, String arg1) throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void sendAsync(String arg0, Collection<String> arg1) throws Exception {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public int sendSync(String arg0) throws Exception {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public int sendSync(Collection<String> arg0) throws Exception {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public int sendSync(String arg0, String arg1) throws Exception {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public int sendSync(String arg0, Collection<String> arg1) throws Exception {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+}
diff --git a/src/test/java/org/onap/crud/service/TestResourceServiceEdgeOperations.java b/src/test/java/org/onap/crud/service/TestResourceServiceEdgeOperations.java
new file mode 100644 (file)
index 0000000..4998e74
--- /dev/null
@@ -0,0 +1,284 @@
+/**
+ * ï»¿============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 Amdocs
+ * ================================================================================
+ * 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=========================================================
+ */
+package org.onap.crud.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import javax.security.auth.x500.X500Principal;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.onap.crud.exception.CrudException;
+import org.onap.crud.util.TestUtil;
+import org.onap.schema.OxmModelLoader;
+import org.springframework.mock.web.MockHttpServletRequest;
+import com.att.aft.dme2.internal.jersey.api.client.ClientResponse.Status;
+
+public class TestResourceServiceEdgeOperations {
+
+    private MockHttpServletRequest servletRequest;
+    private UriInfo uriInfo;
+    private HttpHeaders headers;
+    private AbstractGraphDataService graphDataService;
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        System.setProperty("CONFIG_HOME", "src/test/resources");
+        System.setProperty("AJSC_HOME", ".");
+        System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local");
+
+        OxmModelLoader.loadModels();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        graphDataService = mock(CrudGraphDataService.class);
+        uriInfo = mock(UriInfo.class);
+
+        mockHeaderRequests(getCreateHeaders());
+
+        servletRequest = new MockHttpServletRequest();
+        servletRequest.setSecure(true);
+        servletRequest.setScheme("https");
+        servletRequest.setServerPort(9520);
+        servletRequest.setServerName("localhost");
+        servletRequest.setRequestURI("/services/inventory/relationships/");
+
+        setUser("CN=ONAP, OU=ONAP, O=ONAP, L=Ottawa, ST=Ontario, C=CA");
+
+        servletRequest.setAttribute("javax.servlet.request.cipher_suite", "");
+    }
+
+    private MultivaluedHashMap<String, String> getCreateHeaders() {
+        MultivaluedHashMap<String, String> headersMap = new MultivaluedHashMap<>();
+        headersMap.put("X-TransactionId", createSingletonList("transaction-id"));
+        headersMap.put("X-FromAppId", createSingletonList("app-id"));
+        headersMap.put("Host", createSingletonList("hostname"));
+        return headersMap;
+    }
+
+    private void mockHeaderRequests(MultivaluedHashMap<String, String> headersMap) {
+        headers = Mockito.mock(HttpHeaders.class);
+        for (Entry<String, List<String>> entry : headersMap.entrySet()) {
+            when(headers.getRequestHeader(entry.getKey())).thenReturn(entry.getValue());
+        }
+        when(headers.getRequestHeaders()).thenReturn(headersMap);
+    }
+
+    @Test
+    public void testCreateRelationship() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-auto-props.json");
+
+        Response response = callCreateRelationship(postEdgeBody);
+
+        assertThat(response.getStatus()).isEqualTo(Status.CREATED.getStatusCode());
+    }
+
+    @Test
+    public void testCreateRelationshipWithMatchingType() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-auto-props.json");
+        String type = "tosca.relationships.HostedOn";
+
+        Response response = createRelationshipWithType(postEdgeBody, type);
+
+        assertThat(response.getStatus()).isEqualTo(Status.CREATED.getStatusCode());
+    }
+
+    @Test
+    public void testCreateRelationshipNoMatchingType() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-auto-props.json");
+        String type = "type.does.not.match";
+
+        Response response = createRelationshipWithType(postEdgeBody, type);
+
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testCreateRelationshipWithTypeNullPropsIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-null-props.json");
+        String type = "tosca.relationships.HostedOn";
+
+        Response response = createRelationshipWithType(postEdgeBody, type);
+
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testCreateRelationshipWithTypeWithIdIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-with-id.json");
+        String type = "tosca.relationships.HostedOn";
+
+        Response response = createRelationshipWithType(postEdgeBody, type);
+
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testInvalidUser() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-auto-props.json");
+
+        setUser("CN=INVALID, OU=INVALID, O=INVALID, L=Ottawa, ST=Ontario, C=CA");
+
+        Response response = callCreateRelationship(postEdgeBody);
+
+        assertThat(response.getStatus()).isEqualTo(Status.FORBIDDEN.getStatusCode());
+    }
+
+    @Test
+    public void testNullPropertiesIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-null-props.json");
+
+        Response response = callCreateRelationship(postEdgeBody);
+
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testNoPropertiesIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-no-props.json");
+
+        Response response = callCreateRelationship(postEdgeBody);
+
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testCreateWithIdIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-with-id.json");
+
+        Response response = callCreateRelationship(postEdgeBody);
+
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testNoTypeIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-no-type.json");
+
+        Response response = callCreateRelationship(postEdgeBody);
+
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testPatchEdge() throws Exception {
+        MultivaluedHashMap<String, String> headersMap = getCreateHeaders();
+        headersMap.put(AaiResourceService.HTTP_PATCH_METHOD_OVERRIDE, createSingletonList("PATCH"));
+        mockHeaderRequests(headersMap);
+
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-upsert.json");
+        String type = "tosca.relationships.HostedOn";
+        String id = "12345";
+        EntityTag entityTag = new EntityTag("1234");
+        
+        when(graphDataService.patchEdge(any(), any(), any(), any())).thenReturn(new ImmutablePair<EntityTag, String>(entityTag, "dummy output"));
+        AaiResourceService aaiResourceService = new AaiResourceService(graphDataService);
+        Response response =
+                aaiResourceService.upsertEdge(postEdgeBody, type, id, "uri", headers, uriInfo, servletRequest);
+        assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
+    }
+
+    @Test
+    public void testUpdateEdge() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-upsert.json");
+        String type = "tosca.relationships.HostedOn";
+        String id = "12345";
+        EntityTag entityTag = new EntityTag("1234");
+
+        when(graphDataService.updateEdge(any(), any(), any(), any())).thenReturn(new ImmutablePair<EntityTag, String>(entityTag, "dummy output"));
+        AaiResourceService aaiResourceService = new AaiResourceService(graphDataService);
+        Response response =
+                aaiResourceService.upsertEdge(postEdgeBody, type, id, "uri", headers, uriInfo, servletRequest);
+        assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
+    }
+
+    @Test
+    public void testUpdateEdgeNullPropsIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-null-props.json");
+        String type = "tosca.relationships.HostedOn";
+        String id = "12345";
+        EntityTag entityTag = new EntityTag("1234");
+
+        when(graphDataService.updateEdge(any(), any(), any(), any())).thenReturn(new ImmutablePair<EntityTag, String>(entityTag, "dummy output"));
+        AaiResourceService aaiResourceService = new AaiResourceService(graphDataService);
+        Response response =
+                aaiResourceService.upsertEdge(postEdgeBody, type, id, "uri", headers, uriInfo, servletRequest);
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    @Test
+    public void testUpdateEdgeWithMismatchIdIsBadRequest() throws Exception {
+        String postEdgeBody = TestUtil.getFileAsString("aai-resource-service/post-edge-upsert.json");
+        String type = "tosca.relationships.HostedOn";
+        String id = "mismatch";
+        EntityTag entityTag = new EntityTag("1234");
+
+        when(graphDataService.updateEdge(any(), any(), any(), any())).thenReturn(new ImmutablePair<EntityTag, String>(entityTag, "dummy output"));
+        AaiResourceService aaiResourceService = new AaiResourceService(graphDataService);
+        Response response =
+                aaiResourceService.upsertEdge(postEdgeBody, type, id, "uri", headers, uriInfo, servletRequest);
+        assertThat(response.getStatus()).isEqualTo(Status.BAD_REQUEST.getStatusCode());
+    }
+
+    private Response createRelationshipWithType(String postEdgeBody, String type) throws CrudException, Exception {
+        EntityTag entityTag = new EntityTag("1234");
+        
+        when(graphDataService.addEdge(any(), any(), any())).thenReturn(new ImmutablePair<EntityTag, String>(entityTag, "dummy output"));
+        AaiResourceService aaiResourceService = new AaiResourceService(graphDataService);
+        Response response =
+                aaiResourceService.createRelationship(postEdgeBody, type, "uri", headers, uriInfo, servletRequest);
+        return response;
+    }
+
+    private Response callCreateRelationship(String postEdgeBody) throws CrudException, Exception {
+        EntityTag entityTag = new EntityTag("1234");
+        
+        when(graphDataService.addEdge(any(), any(), any())).thenReturn(new ImmutablePair<EntityTag, String>(entityTag, "dummy output"));
+        AaiResourceService aaiResourceService = new AaiResourceService(graphDataService);
+        Response response =
+                aaiResourceService.createRelationship(postEdgeBody, "uri", headers, uriInfo, servletRequest);
+        return response;
+    }
+
+    private void setUser(String user) {
+        X509Certificate mockCertificate = Mockito.mock(X509Certificate.class);
+        when(mockCertificate.getSubjectX500Principal()).thenReturn(new X500Principal(user));
+        servletRequest.setAttribute("javax.servlet.request.X509Certificate", new X509Certificate[] {mockCertificate});
+    }
+
+    private List<String> createSingletonList(String listItem) {
+        return Collections.<String>singletonList(listItem);
+    }
+}
diff --git a/src/test/java/org/onap/crud/service/VertexPayloadTest.java b/src/test/java/org/onap/crud/service/VertexPayloadTest.java
new file mode 100644 (file)
index 0000000..df0656f
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * ï»¿============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 Amdocs
+ * ================================================================================
+ * 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=========================================================
+ */
+package org.onap.crud.service;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import javax.ws.rs.core.Response.Status;
+import org.junit.Test;
+import org.onap.crud.exception.CrudException;
+import org.onap.crud.parser.VertexPayload;
+
+public class VertexPayloadTest {
+
+    @Test
+    public void testExceptionHandling() {
+        String payload = null;
+        try {
+            VertexPayload.fromJson(payload);
+        } catch (CrudException e) {
+            assertThat(e.getHttpStatus(), is(Status.BAD_REQUEST));
+            assertThat(e.getMessage(), is("Invalid Json Payload"));
+        }
+
+        payload = "Invalid Json";
+        try {
+            VertexPayload.fromJson(payload);
+        } catch (CrudException e) {
+            assertThat(e.getHttpStatus(), is(Status.BAD_REQUEST));
+            assertThat(e.getMessage(), is("Invalid Json Payload"));
+        }
+    }
+}
index 073e1d3..05f998f 100644 (file)
  */
 package org.onap.schema;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import org.junit.Test;
 import org.onap.crud.exception.CrudException;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.*;
-
 public class EdgeRulesLoaderTest {
 
     @Test
diff --git a/src/test/java/org/onap/schema/RelationshipSchemaValidatorTest.java b/src/test/java/org/onap/schema/RelationshipSchemaValidatorTest.java
new file mode 100644 (file)
index 0000000..711152d
--- /dev/null
@@ -0,0 +1,269 @@
+/**
+ * ï»¿============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright Â© 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright Â© 2017-2018 Amdocs
+ * ================================================================================
+ * 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=========================================================
+ */
+package org.onap.schema;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.crud.entity.Edge;
+import org.onap.crud.exception.CrudException;
+import org.onap.crud.parser.EdgePayload;
+import org.onap.schema.validation.RelationshipSchemaValidator;
+
+public class RelationshipSchemaValidatorTest {
+    // @formatter:off
+         private final String edgePayload = "{" +
+                     "\"type\": \"tosca.relationships.HostedOn\"," +
+                     "\"source\": \"services/inventory/v12/vserver/50bdab41-ad1c-4d00-952c-a0aa5d827811\"," +
+                     "\"target\": \"services/inventory/v12/pserver/1d326bc7-b985-492b-9604-0d5d1f06f908\"," +
+                     "\"properties\": {" +
+                     "\"prevent-delete\": \"NONE\" } }";
+         
+         private final String champEdge = "{" +
+                     "\"key\": \"test-uuid\"," +
+                     "\"type\": \"edgeType\"," +
+                     "\"properties\": {" +
+                     "\"prevent-delete\": \"NONE\" }," +
+                     "\"source\": {" +
+                     "\"key\": \"50bdab41-ad1c-4d00-952c-a0aa5d827811\", \"type\": \"vserver\"}," +
+                     "\"target\": {" +
+                     "\"key\": \"1d326bc7-b985-492b-9604-0d5d1f06f908\", \"type\": \"pserver\"}" +
+                     " }";
+       // @formatter:on
+
+    @Before
+    public void init() throws Exception {
+        System.setProperty("CONFIG_HOME", "src/test/resources");
+    }
+
+    @Test
+    public void testValidateIncomingUpdatePayloadMissingSource() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+        EdgePayload payload;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        jsonString = edgePayload.replace("services/inventory/v12/vserver/50bdab41-ad1c-4d00-952c-a0aa5d827811", "");
+        payload = EdgePayload.fromJson(jsonString);
+
+        try {
+            RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Invalid Source/Target Urls"));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingUpdatePayloadInvalidSource() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+        EdgePayload payload;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        jsonString = edgePayload.replace("1d326bc7-b985-492b-9604-0d5d1f06f908", "invalidId");
+        payload = EdgePayload.fromJson(jsonString);
+
+        try {
+            RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Target can't be updated"));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingUpdatePayloadMissingTarget() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+        EdgePayload payload;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        jsonString = edgePayload.replace("services/inventory/v12/pserver/1d326bc7-b985-492b-9604-0d5d1f06f908", "");
+        payload = EdgePayload.fromJson(jsonString);
+
+        try {
+            RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Invalid Source/Target Urls"));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingUpdatePayloadInvalidTarget() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+        EdgePayload payload;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        jsonString = edgePayload.replace("50bdab41-ad1c-4d00-952c-a0aa5d827811", "invalidId");
+        payload = EdgePayload.fromJson(jsonString);
+
+        try {
+            RelationshipSchemaValidator.validateIncomingUpdatePayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Source can't be updated"));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingAddPayloadExceptionHandling() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+
+        EdgePayload payload;
+        jsonString = edgePayload.replace("services/inventory/v12/vserver/50bdab41-ad1c-4d00-952c-a0aa5d827811", "");
+        payload = EdgePayload.fromJson(jsonString);
+
+        try {
+            RelationshipSchemaValidator.validateIncomingAddPayload(version, type, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Invalid Source/Target Urls"));
+        }
+
+        jsonString = edgePayload;
+        payload = EdgePayload.fromJson(jsonString);
+        type = "tosca.relationships.invalidType";
+        try {
+            RelationshipSchemaValidator.validateIncomingAddPayload(version, type, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Invalid source/target/relationship type: vserver:pserver:" + type));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingPatchPayloadMissingSource() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        EdgePayload payload;
+
+        jsonString = edgePayload.replace("services/inventory/v12/vserver/50bdab41-ad1c-4d00-952c-a0aa5d827811", "");
+        payload = EdgePayload.fromJson(jsonString);
+
+        try {
+            RelationshipSchemaValidator.validateIncomingPatchPayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Invalid Source/Target Urls"));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingPatchPayloadInvalidSource() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        EdgePayload payload;
+
+        jsonString = edgePayload.replace("50bdab41-ad1c-4d00-952c-a0aa5d827811", "invalidId");
+        payload = EdgePayload.fromJson(jsonString);
+        try {
+            RelationshipSchemaValidator.validateIncomingPatchPayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Source can't be updated"));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingPatchPayloadMissingTarget() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        EdgePayload payload;
+
+        jsonString = edgePayload.replace("services/inventory/v12/pserver/1d326bc7-b985-492b-9604-0d5d1f06f908", "");
+        payload = EdgePayload.fromJson(jsonString);
+
+        try {
+            RelationshipSchemaValidator.validateIncomingPatchPayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Invalid Source/Target Urls"));
+        }
+    }
+
+    @Test
+    public void testValidateIncomingPatchPayloadInvalidTarget() throws CrudException {
+        String type = "tosca.relationships.HostedOn";
+        String version = "v11";
+        String jsonString;
+
+        String champJson = champEdge.replace("edgeType", type);
+        Edge edge = Edge.fromJson(champJson);
+
+        EdgePayload payload;
+
+        jsonString = edgePayload.replace("1d326bc7-b985-492b-9604-0d5d1f06f908", "invalidId");
+        payload = EdgePayload.fromJson(jsonString);
+        try {
+            RelationshipSchemaValidator.validateIncomingPatchPayload(edge, version, payload);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Target can't be updated"));
+        }
+    }
+
+    @Test
+    public void testValidateTypeExceptionHandling() {
+        String version = "v11";
+        String type = "tosca.relationships.invalidType";
+
+        try {
+            RelationshipSchemaValidator.validateType(version, type);
+        } catch (CrudException e) {
+            assertEquals(400, e.getHttpStatus().getStatusCode());
+            assertThat(e.getMessage(), is("Invalid " + RelationshipSchema.SCHEMA_RELATIONSHIP_TYPE + ": " + type));
+        }
+    }
+}
index 409ce3c..b4d5a31 100644 (file)
@@ -20,7 +20,6 @@
  */\r
 package org.onap.schema.validation;\r
 \r
-import java.io.File;\r
 import java.util.ArrayList;\r
 import java.util.HashMap;\r
 import java.util.List;\r
@@ -49,9 +48,7 @@ public class MultiplicityValidatorTest {
 \r
     @Before\r
     public void init() {\r
-        ClassLoader classLoader = getClass().getClassLoader();\r
-        File dir = new File(classLoader.getResource("rules").getFile());\r
-        System.setProperty("CONFIG_HOME", dir.getParent());\r
+        System.setProperty("CONFIG_HOME", "src/test/resources");\r
         EdgeRulesLoader.resetSchemaVersionContext();\r
     }\r
 \r
diff --git a/src/test/resources/aai-resource-service/model/DbEdgeRules_v10.json b/src/test/resources/aai-resource-service/model/DbEdgeRules_v10.json
new file mode 100644 (file)
index 0000000..0381090
--- /dev/null
@@ -0,0 +1,1819 @@
+{
+       "rules": [
+               {
+                       "from": "availability-zone",
+                       "to": "complex",
+                       "label": "groupsResourcesIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "license-key-resource",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "availability-zone",
+                       "to": "service-capability",
+                       "label": "supportsServiceCapability",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "complex",
+                       "label": "locatedIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "l3-network",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "tenant",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "image",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "flavor",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "availability-zone",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "oam-network",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "dvs-switch",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "volume-group",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "group-assignment",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "snapshot",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "cloud-region",
+                       "to": "zone",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "complex",
+                       "to": "ctag-pool",
+                       "label": "hasCtagPool",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "complex",
+                       "to": "l3-network",
+                       "label": "usesL3Network",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "ctag-pool",
+                       "to": "availability-zone",
+                       "label": "supportsAvailabilityZone",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "customer",
+                       "to": "service-subscription",
+                       "label": "subscribesTo",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "dvs-switch",
+                       "to": "availability-zone",
+                       "label": "existsIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "l-interface",
+                       "label": "hasLInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "availability-zone",
+                       "label": "hasAvailabilityZone",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "lag-interface",
+                       "label": "hasLAGInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "l3-network",
+                       "label": "usesL3Network",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "pserver",
+                       "label": "runsOnPserver",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "vnf-image",
+                       "label": "usesVnfImage",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "vserver",
+                       "label": "runsOnVserver",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "service-instance",
+                       "label": "hasInstance",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "site-pair-set",
+                       "label": "hasSitePairSet",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "network-profile",
+                       "label": "hasNetworkProfile",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "group-assignment",
+                       "to": "tenant",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "group-assignment",
+                       "to": "pserver",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "image",
+                       "to": "metadatum",
+                       "label": "hasMetaDatum",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l-interface",
+                       "to": "instance-group",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l-interface",
+                       "to": "l3-interface-ipv4-address-list",
+                       "label": "hasIpAddress",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l-interface",
+                       "to": "l3-interface-ipv6-address-list",
+                       "label": "hasIpAddress",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l-interface",
+                       "to": "l-interface",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l-interface",
+                       "to": "logical-link",
+                       "label": "usesLogicalLink",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "lag-interface",
+                       "to": "logical-link",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l-interface",
+                       "to": "vlan",
+                       "label": "hasVlan",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l-interface",
+                       "to": "sriov-vf",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2One",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-interface-ipv4-address-list",
+                       "to": "instance-group",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-interface-ipv6-address-list",
+                       "to": "instance-group",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-interface-ipv4-address-list",
+                       "to": "l3-network",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-interface-ipv6-address-list",
+                       "to": "l3-network",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-interface-ipv4-address-list",
+                       "to": "subnet",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "l3-interface-ipv6-address-list",
+                       "to": "subnet",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "l3-network",
+                       "to": "vpn-binding",
+                       "label": "usesVpnBinding",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "l3-network",
+                       "to": "subnet",
+                       "label": "hasSubnet",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-network",
+                       "to": "service-instance",
+                       "label": "hasInstance",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-network",
+                       "to": "ctag-assignment",
+                       "label": "hasCtagAssignment",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-network",
+                       "to": "network-policy",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-network",
+                       "to": "segmentation-assignment",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "l3-network",
+                       "to": "route-table-reference",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "lag-interface",
+                       "to": "lag-link",
+                       "label": "usesLAGLink",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "lag-interface",
+                       "to": "p-interface",
+                       "label": "usesPInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "lag-interface",
+                       "to": "l-interface",
+                       "label": "hasLInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "logical-link",
+                       "to": "lag-link",
+                       "label": "usesLAGLink",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "logical-link",
+                       "to": "pnf",
+                       "label": "bridgedTo",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "logical-link",
+                       "to": "logical-link",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "model",
+                       "to": "model-ver",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "model-ver",
+                       "to": "model-element",
+                       "label": "startsWith",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "model-element",
+                       "to": "model-ver",
+                       "label": "isA",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "model-ver",
+                       "to": "metadatum",
+                       "label": "hasMetaData",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "model-element",
+                       "to": "model-element",
+                       "label": "connectsTo",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "model-element",
+                       "to": "model-constraint",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "model-element",
+                       "to": "constrained-element-set",
+                       "label": "connectsTo",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "model-constraint",
+                       "to": "constrained-element-set",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "constrained-element-set",
+                       "to": "element-choice-set",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "element-choice-set",
+                       "to": "model-element",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "named-query",
+                       "to": "model",
+                       "label": "relatedTo",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "named-query",
+                       "to": "named-query-element",
+                       "label": "startsWith",
+                       "direction": "OUT",
+                       "multiplicity": "One2One",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "named-query-element",
+                       "to": "named-query-element",
+                       "label": "connectsTo",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "named-query-element",
+                       "to": "model",
+                       "label": "isA",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "named-query-element",
+                       "to": "property-constraint",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "named-query-element",
+                       "to": "related-lookup",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "instance-group",
+                       "to": "model",
+                       "label": "targets",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "newvce",
+                       "to": "l-interface",
+                       "label": "hasLInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "oam-network",
+                       "to": "complex",
+                       "label": "definedFor",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "oam-network",
+                       "to": "service-capability",
+                       "label": "supportsServiceCapability",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "p-interface",
+                       "to": "l-interface",
+                       "label": "hasLInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "p-interface",
+                       "to": "physical-link",
+                       "label": "usesPhysicalLink",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "p-interface",
+                       "to": "logical-link",
+                       "label": "usesLogicalLink",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "port-group",
+                       "to": "cvlan-tag",
+                       "label": "hasCTag",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pserver",
+                       "to": "complex",
+                       "label": "locatedIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "pserver",
+                       "to": "cloud-region",
+                       "label": "locatedIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pserver",
+                       "to": "availability-zone",
+                       "label": "existsIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "pserver",
+                       "to": "lag-interface",
+                       "label": "hasLAGInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pserver",
+                       "to": "p-interface",
+                       "label": "hasPinterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pserver",
+                       "to": "zone",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pnf",
+                       "to": "p-interface",
+                       "label": "hasPinterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pnf",
+                       "to": "lag-interface",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pnf",
+                       "to": "complex",
+                       "label": "locatedIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "pnf",
+                       "to": "instance-group",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "pnf",
+                       "to": "zone",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "cvlan-tag",
+                       "label": "hasIPAGFacingVLAN",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "pnf",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-subscription",
+                       "to": "service-instance",
+                       "label": "hasInstance",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "site-pair-set",
+                       "to": "routing-instance",
+                       "label": "hasRoutingInstance",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "routing-instance",
+                       "to": "site-pair",
+                       "label": "hasSitePair",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "site-pair",
+                       "to": "class-of-service",
+                       "label": "hasClassOfService",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "tenant",
+                       "to": "l3-network",
+                       "label": "usesL3Network",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "tenant",
+                       "to": "service-subscription",
+                       "label": "relatedTo",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "tenant",
+                       "to": "vserver",
+                       "label": "owns",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "vce",
+                       "to": "availability-zone",
+                       "label": "hasAvailabilityZone",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "vce",
+                       "to": "complex",
+                       "label": "locatedIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "vce",
+                       "to": "port-group",
+                       "label": "hasPortGroup",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vce",
+                       "to": "vserver",
+                       "label": "runsOnVserver",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vce",
+                       "to": "service-instance",
+                       "label": "hasServiceInstance",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "virtual-data-center",
+                       "to": "generic-vnf",
+                       "label": "hasVNF",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "!${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vlan",
+                       "to": "l3-interface-ipv4-address-list",
+                       "label": "hasIpAddress",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vlan",
+                       "to": "l3-interface-ipv6-address-list",
+                       "label": "hasIpAddress",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vpls-pe",
+                       "to": "complex",
+                       "label": "locatedIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "vpls-pe",
+                       "to": "ctag-pool",
+                       "label": "usesCtagPool",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vpls-pe",
+                       "to": "p-interface",
+                       "label": "hasPinterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vpls-pe",
+                       "to": "lag-interface",
+                       "label": "hasLAGinterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vserver",
+                       "to": "flavor",
+                       "label": "hasFlavor",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "vserver",
+                       "to": "image",
+                       "label": "hasImage",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "vserver",
+                       "to": "l-interface",
+                       "label": "hasLInterface",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vserver",
+                       "to": "pserver",
+                       "label": "runsOnPserver",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "vserver",
+                       "to": "volume",
+                       "label": "hasVolume",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vserver",
+                       "to": "vnfc",
+                       "label": "hosts",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vserver",
+                       "to": "snapshot",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "connector",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "metadatum",
+                       "label": "hasMetaData",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "logical-link",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "vlan",
+                       "label": "dependsOn",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "service-instance",
+                       "label": "dependsOn",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "connector",
+                       "to": "virtual-data-center",
+                       "label": "contains",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "connector",
+                       "to": "metadatum",
+                       "label": "hasMetaData",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "virtual-data-center",
+                       "to": "logical-link",
+                       "label": "contains",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "logical-link",
+                       "to": "generic-vnf",
+                       "label": "bridgedTo",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "logical-link",
+                       "to": "pserver",
+                       "label": "bridgedTo",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "vlan",
+                       "to": "multicast-configuration",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "volume-group",
+                       "to": "complex",
+                       "label": "existsIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "volume-group",
+                       "to": "tenant",
+                       "label": "belongsTo",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "ipsec-configuration",
+                       "to": "vig-server",
+                       "label": "hasVigServer",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "ipsec-configuration",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vf-module",
+                       "to": "volume-group",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vserver",
+                       "to": "vf-module",
+                       "label": "isPartOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vf-module",
+                       "to": "l3-network",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vf-module",
+                       "to": "vnfc",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "${direction}"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "vf-module",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "volume-group",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "vnfc",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vlan",
+                       "to": "logical-link",
+                       "label": "usesLogicalLink",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "${direction}",
+                       "SVC-INFRA": "${direction}",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vpn-binding",
+                       "to": "route-target",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "ctag-assignment",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "allotted-resource",
+                       "to": "generic-vnf",
+                       "label": "isPartOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "allotted-resource",
+                       "to": "l3-network",
+                       "label": "isPartOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "allotted-resource",
+                       "to": "instance-group",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "allotted-resource",
+                       "to": "network-policy",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "One2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "allotted-resource",
+                       "to": "vlan",
+                       "label": "isPartOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "instance-group",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "instance-group",
+                       "label": "isMemberOf",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "allotted-resource",
+                       "to": "tunnel-xconnect",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2One",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "logical-link",
+                       "to": "cloud-region",
+                       "label": "existsIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "logical-link",
+                       "to": "vpn-binding",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "entitlement",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "generic-vnf",
+                       "to": "license",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vce",
+                       "to": "entitlement",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "vce",
+                       "to": "license",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "One2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "zone",
+                       "to": "complex",
+                       "label": "existsIn",
+                       "direction": "OUT",
+                       "multiplicity": "Many2One",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "!${direction}"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "allotted-resource",
+                       "label": "has",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "${direction}",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               },
+               {
+                       "from": "service-instance",
+                       "to": "allotted-resource",
+                       "label": "uses",
+                       "direction": "OUT",
+                       "multiplicity": "Many2Many",
+                       "contains-other-v": "NONE",
+                       "delete-other-v": "NONE",
+                       "SVC-INFRA": "NONE",
+                       "prevent-delete": "NONE"
+               }
+       ]
+}
diff --git a/src/test/resources/aai-resource-service/model/edge_properties_v10.json b/src/test/resources/aai-resource-service/model/edge_properties_v10.json
new file mode 100644 (file)
index 0000000..8d00636
--- /dev/null
@@ -0,0 +1,6 @@
+{
+        "contains-other-v": "java.lang.String",
+        "delete-other-v": "java.lang.String",
+        "SVC-INFRA": "java.lang.String",
+        "prevent-delete": "java.lang.String"
+}
\ No newline at end of file
diff --git a/src/test/resources/aai-resource-service/model/edge_properties_v11.json b/src/test/resources/aai-resource-service/model/edge_properties_v11.json
new file mode 100644 (file)
index 0000000..8d00636
--- /dev/null
@@ -0,0 +1,6 @@
+{
+        "contains-other-v": "java.lang.String",
+        "delete-other-v": "java.lang.String",
+        "SVC-INFRA": "java.lang.String",
+        "prevent-delete": "java.lang.String"
+}
\ No newline at end of file
diff --git a/src/test/resources/aai-resource-service/post-edge-auto-props.json b/src/test/resources/aai-resource-service/post-edge-auto-props.json
new file mode 100644 (file)
index 0000000..2d71bd6
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "type": "tosca.relationships.HostedOn",
+  "source": "services/inventory/v12/vserver/f5eb0ad4-1845-4945-b208-df11b0155e3b",
+  "target": "services/inventory/v11/pserver/46e61b9b-ea02-46ca-b07e-95c7fed60fdf",
+  "properties": {}
+}
diff --git a/src/test/resources/aai-resource-service/post-edge-no-props.json b/src/test/resources/aai-resource-service/post-edge-no-props.json
new file mode 100644 (file)
index 0000000..b655eda
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "type": "tosca.relationships.HostedOn",
+  "source": "services/inventory/v12/vserver/f5eb0ad4-1845-4945-b208-df11b0155e3b",
+  "target": "services/inventory/v11/pserver/46e61b9b-ea02-46ca-b07e-95c7fed60fdf"
+}
diff --git a/src/test/resources/aai-resource-service/post-edge-no-type.json b/src/test/resources/aai-resource-service/post-edge-no-type.json
new file mode 100644 (file)
index 0000000..0b7ae98
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "source":"services/inventory/v12/vserver/f5eb0ad4-1845-4945-b208-df11b0155e3b",
+  "target":"services/inventory/v11/pserver/46e61b9b-ea02-46ca-b07e-95c7fed60fdf",
+  "properties":{}
+}
diff --git a/src/test/resources/aai-resource-service/post-edge-null-props.json b/src/test/resources/aai-resource-service/post-edge-null-props.json
new file mode 100644 (file)
index 0000000..40fef7d
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "type":"tosca.relationships.HostedOn",
+  "source":"services/inventory/v12/vserver/f5eb0ad4-1845-4945-b208-df11b0155e3b",
+  "target":"services/inventory/v11/pserver/46e61b9b-ea02-46ca-b07e-95c7fed60fdf",
+  "properties":null
+}
diff --git a/src/test/resources/aai-resource-service/post-edge-upsert.json b/src/test/resources/aai-resource-service/post-edge-upsert.json
new file mode 100644 (file)
index 0000000..f66fd04
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "id": "12345",
+  "type":"tosca.relationships.HostedOn",
+  "source":"services/inventory/v12/vserver/f5eb0ad4-1845-4945-b208-df11b0155e3b",
+  "target":"services/inventory/v11/pserver/46e61b9b-ea02-46ca-b07e-95c7fed60fdf",
+  "properties":{}
+}
diff --git a/src/test/resources/aai-resource-service/post-edge-with-id.json b/src/test/resources/aai-resource-service/post-edge-with-id.json
new file mode 100644 (file)
index 0000000..4d987b9
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "id":"12345",
+  "type":"tosca.relationships.HostedOn",
+  "source":"services/inventory/v12/vserver/f5eb0ad4-1845-4945-b208-df11b0155e3b",
+  "target":"services/inventory/v11/pserver/46e61b9b-ea02-46ca-b07e-95c7fed60fdf",
+  "properties":{}
+}
diff --git a/src/test/resources/aai-resource-service/post-edge.json b/src/test/resources/aai-resource-service/post-edge.json
new file mode 100644 (file)
index 0000000..040ccd8
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "type":"tosca.relationships.HostedOn",
+  "source":"services/inventory/v12/vserver/f5eb0ad4-1845-4945-b208-df11b0155e3b",
+  "target":"services/inventory/v11/pserver/46e61b9b-ea02-46ca-b07e-95c7fed60fdf",
+  "properties":{
+    "contains-other-v":"NONE",
+    "delete-other-v":"NONE",
+    "SVC-INFRA":"OUT",
+    "prevent-delete":"IN",
+    "multiplicity": "MANY2ONE"
+  }
+}
diff --git a/src/test/resources/auth/crud_policy.json b/src/test/resources/auth/crud_policy.json
new file mode 100644 (file)
index 0000000..d60312b
--- /dev/null
@@ -0,0 +1,18 @@
+{
+       "roles": [
+               {
+                       "name": "admin",
+                       "functions": [
+                               {
+                                       "name": "crud", "methods": [ { "name": "GET" },{ "name": "DELETE" }, { "name": "PUT" }, { "name": "POST" }, { "name": "PATCH" } ]
+                               }
+                       ],
+
+                       "users": [
+                               {
+                                       "username": "CN=ONAP, OU=ONAP, O=ONAP, L=Ottawa, ST=Ontario, C=CA"
+                               }
+                       ]
+               }
+       ]
+}
diff --git a/src/test/resources/event/champ-edge-event.json b/src/test/resources/event/champ-edge-event.json
new file mode 100644 (file)
index 0000000..375901a
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  "header": {
+    "request-id": "5cf7f973-c406-4507-ad71-72d7b3d26c36",
+    "timestamp": "20180316T092301Z",
+    "source-name": "CHAMP",
+    "event-type": "update-result"
+  },
+  "body": {
+    "operation": "CREATE",
+    "transaction-id": "6544a144-0c56-4f71-81d8-a6170efbb296",
+    "timestamp": 1521192181065,
+    "edge": {
+      "key": "test-key",
+      "type": "tosca.relationships.HostedOn",
+      "properties": {
+        "prevent-delete": "NONE"
+      },
+      "source": {
+        "key": "50bdab41-ad1c-4d00-952c-a0aa5d827811",
+        "type": "vserver"
+      },
+      "target": {
+        "key": "1d326bc7-b985-492b-9604-0d5d1f06f908",
+        "type": "pserver"
+      }
+    },
+    "result": "SUCCESS"
+  },
+  "policyViolations": []
+}
\ No newline at end of file
diff --git a/src/test/resources/event/champ-vertex-event-error.json b/src/test/resources/event/champ-vertex-event-error.json
new file mode 100644 (file)
index 0000000..03f3018
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  "header": {
+    "request-id": "5cf7f973-c406-4507-ad71-72d7b3d26c36",
+    "timestamp": "20180316T092301Z",
+    "source-name": "CHAMP",
+    "event-type": "update-result",
+    "validation-entity-type": "pserver"
+  },
+  "body": {
+    "operation": "CREATE",
+    "transaction-id": "6544a144-0c56-4f71-81d8-a6170efbb296",
+    "timestamp": 1521192181065,
+    "vertex": {
+      "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
+      "schema-version": "v13",
+      "type": "pserver",
+      "properties": {
+        "hostname":"hostname1"
+      }
+    },
+    "result": "FAILURE",
+    "error-message":"test error",
+    "httpErrorStatus":"INTERNAL_SERVER_ERROR"
+  },
+  "policyViolations": []
+}
\ No newline at end of file
diff --git a/src/test/resources/event/champ-vertex-event-violations.json b/src/test/resources/event/champ-vertex-event-violations.json
new file mode 100644 (file)
index 0000000..ad30912
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  "header": {
+    "request-id": "5cf7f973-c406-4507-ad71-72d7b3d26c36",
+    "timestamp": "20180316T092301Z",
+    "source-name": "CHAMP",
+    "event-type": "update-result",
+    "validation-entity-type": "pserver"
+  },
+  "body": {
+    "operation": "CREATE",
+    "transaction-id": "6544a144-0c56-4f71-81d8-a6170efbb296",
+    "timestamp": 1521192181065,
+    "vertex": {
+      "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
+      "schema-version": "v13",
+      "type": "pserver",
+      "properties": {
+        "hostname":"hostname1",
+        "number-of-cpus":8
+      }
+    },
+    "result": "SUCCESS"
+  },
+  "policyViolations": [
+    {
+      "summary": "a summary",
+      "policyName": "a policy name"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/src/test/resources/event/champ-vertex-event.json b/src/test/resources/event/champ-vertex-event.json
new file mode 100644 (file)
index 0000000..815780f
--- /dev/null
@@ -0,0 +1,25 @@
+{
+  "header": {
+    "request-id": "5cf7f973-c406-4507-ad71-72d7b3d26c36",
+    "timestamp": "20180316T092301Z",
+    "source-name": "CHAMP",
+    "event-type": "update-result",
+    "validation-entity-type": "pserver"
+  },
+  "body": {
+    "operation": "CREATE",
+    "transaction-id": "6544a144-0c56-4f71-81d8-a6170efbb296",
+    "timestamp": 1521192181065,
+    "vertex": {
+      "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
+      "schema-version": "v13",
+      "type": "pserver",
+      "properties": {
+        "hostname":"hostname1",
+        "number-of-cpus":8
+      }
+    },
+    "result": "SUCCESS"
+  },
+  "policyViolations": []
+}
\ No newline at end of file
index 88e4123..5b6f906 100644 (file)
@@ -2,7 +2,7 @@
   "header": {
     "request-id": "5cf7f973-c406-4507-ad71-72d7b3d26c36",
     "timestamp": "20180316T092301Z",
-    "source-name": "SENTINE",
+    "source-name": "SENTINEL",
     "event-type": "update-result",
     "validation-entity-type": "pserver"
   },
index 91e6c76..567e7d3 100644 (file)
@@ -2,7 +2,7 @@
   "header": {
     "request-id": "5cf7f973-c406-4507-ad71-72d7b3d26c36",
     "timestamp": "20180316T092301Z",
-    "source-name": "SENTINE",
+    "source-name": "SENTINEL",
     "event-type": "update-result",
     "validation-entity-type": "pserver"
   },
diff --git a/src/test/resources/event/graph-edge-event.json b/src/test/resources/event/graph-edge-event.json
new file mode 100644 (file)
index 0000000..30fe94f
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "operation": "CREATE",
+  "transaction-id": "6544a144-0c56-4f71-81d8-a6170efbb296",
+  "timestamp": 1521192181065,
+  "edge": {
+    "type": "tosca.relationships.HostedOn",
+    "properties": {
+      "prevent-delete": "NONE"
+    },
+    "source": {
+      "key": "50bdab41-ad1c-4d00-952c-a0aa5d827811",
+      "type": "vserver"
+    },
+    "target": {
+      "key": "1d326bc7-b985-492b-9604-0d5d1f06f908",
+      "type": "pserver"
+    }
+  }
+}
diff --git a/src/test/resources/event/graph-vertex-event.json b/src/test/resources/event/graph-vertex-event.json
new file mode 100644 (file)
index 0000000..2dcfaee
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "operation": "CREATE",
+    "transaction-id": "6544a144-0c56-4f71-81d8-a6170efbb296",
+    "timestamp": 1521192181065,
+    "vertex": {
+      "schema-version": "v13",
+      "type": "pserver",
+      "properties": {
+        "hostname":"hostname1"
+      }
+    }
+}
\ No newline at end of file