Interface operation feature enhancements

1. API restructuring to enhance model and provide more capabilities.
2. Allowed multiple interface creation under same resource/service.
3. Enhanced validations to align with updated model.
4. API restructuring to align UI model with Tosca model.
5. Enhanced Junit and code coverage.
6. Added BDD and CI-API tests.

Change-Id: I2d8ac8a6154fd9be8254836ba0da1540210031c0
Issue-ID: SDC-1999
Signed-off-by: priyanshu <pagarwal@amdocs.com>
diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java
index 26b6b6d..d3b717e 100644
--- a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java
+++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java
@@ -395,4 +395,10 @@
 
 	// Interface Lifecycle Types
 	final String GET_All_INTERFACE_LIFECYCLE_TYPES = SDC_HTTP_METHOD + "://%s:%s/sdc2/rest/v1/catalog/interfaceLifecycleTypes";
+
+	// Interface Operation
+	final String ADD_INTERFACE_OPERATIONS = SDC_HTTP_METHOD + "://%s:%s/sdc2/rest/v1/catalog/%s/%s/interfaceOperations";
+	final String UPDATE_INTERFACE_OPERATIONS = SDC_HTTP_METHOD + "://%s:%s/sdc2/rest/v1/catalog/%s/%s/interfaceOperations";
+	final String GET_INTERFACE_OPERATIONS = SDC_HTTP_METHOD + "://%s:%s/sdc2/rest/v1/catalog/%s/%s/interfaces/%s/operations/%s";
+	final String DELETE_INTERFACE_OPERATIONS = SDC_HTTP_METHOD + "://%s:%s/sdc2/rest/v1/catalog/%s/%s/interfaces/%s/operations/%s";
 }
diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/interfaceoperation/InterfaceOperationsTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/interfaceoperation/InterfaceOperationsTest.java
new file mode 100644
index 0000000..8b2343c
--- /dev/null
+++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/interfaceoperation/InterfaceOperationsTest.java
@@ -0,0 +1,264 @@
+package org.openecomp.sdc.ci.tests.execute.interfaceoperation;
+
+import static org.testng.AssertJUnit.fail;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import fj.data.Either;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
+import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition;
+import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
+import org.openecomp.sdc.be.model.InputDefinition;
+import org.openecomp.sdc.be.model.InterfaceDefinition;
+import org.openecomp.sdc.be.model.Operation;
+import org.openecomp.sdc.be.model.PropertyDefinition;
+import org.openecomp.sdc.be.model.Resource;
+import org.openecomp.sdc.be.model.Service;
+import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.ci.tests.api.ComponentBaseTest;
+import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum;
+import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse;
+import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils;
+import org.openecomp.sdc.ci.tests.utils.general.ElementFactory;
+import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils;
+import org.openecomp.sdc.ci.tests.utils.rest.InterfaceOperationsRestUtils;
+import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class InterfaceOperationsTest extends ComponentBaseTest {
+
+    @Rule
+    private static final TestName name = new TestName();
+    private static final String INTERFACES = "interfaces";
+    private static final String TOSCA_PRESENTATION = "toscaPresentation";
+    private static final User user = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER);
+
+    private static Service service;
+    private static Resource resource;
+    private String resourceInterfaceUniqueId;
+    private String resourceOperationUniqueId;
+    private String serviceInterfaceUniqueId;
+    private String serviceOperationUniqueId;
+
+    public InterfaceOperationsTest() {
+        super(name, InterfaceOperationsTest.class.getName());
+    }
+
+    @BeforeClass
+    public static void init() throws Exception {
+        // Create default service
+        Either<Service, RestResponse> createDefaultServiceEither =
+                AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true);
+        if (createDefaultServiceEither.isRight()) {
+            fail("Error creating default service");
+        }
+        service = createDefaultServiceEither.left().value();
+
+        // Create default resource
+        Either<Resource, RestResponse> createDefaultResourceEither =
+                AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true);
+        if (createDefaultResourceEither.isRight()) {
+            fail("Error creating default resource");
+        }
+        resource = createDefaultResourceEither.left().value();
+    }
+
+    private Map<String, Object> buildInterfaceDefinitionForResource() {
+        Operation operation = new Operation();
+        operation.setName("TestOperationOnResource");
+        operation.setWorkflowId("WorkflowId");
+        operation.setWorkflowVersionId("workflowVersionId");
+        operation.setWorkflowAssociationType("NONE");
+        PropertyDefinition property =
+                resource.getInputs().stream().filter(a -> a.getName().equalsIgnoreCase("nf_naming")).findFirst()
+                        .orElse(new InputDefinition());
+        ListDataDefinition<OperationInputDefinition> operationInputDefinitionList = new ListDataDefinition<>();
+        operationInputDefinitionList.add(createOperationInputDefinition("TestInput1", property.getUniqueId()));
+        operation.setInputs(operationInputDefinitionList);
+        ListDataDefinition<OperationOutputDefinition> operationOutputDefinitionList = new ListDataDefinition<>();
+        operationOutputDefinitionList.add(createOperationOutputDefinition("TestOutput1"));
+        operation.setOutputs(operationOutputDefinitionList);
+        return buildInterfaceDefinitionMap(operation, "TestInterface", resourceInterfaceUniqueId, resourceOperationUniqueId);
+    }
+
+    private Map<String, Object> buildInterfaceDefinitionOfGlobalTypeForResource() {
+        Operation operation = new Operation();
+        operation.setName("create");
+        operation.setWorkflowId("WorkflowId");
+        operation.setWorkflowVersionId("workflowVersionId");
+        operation.setWorkflowAssociationType("NONE");
+        PropertyDefinition property =
+                resource.getInputs().stream().filter(a -> a.getName().equalsIgnoreCase("nf_naming")).findFirst()
+                        .orElse(new InputDefinition());
+        ListDataDefinition<OperationInputDefinition> operationInputDefinitionList = new ListDataDefinition<>();
+        operationInputDefinitionList.add(createOperationInputDefinition("TestInput1", property.getUniqueId()));
+        operation.setInputs(operationInputDefinitionList);
+        ListDataDefinition<OperationOutputDefinition> operationOutputDefinitionList = new ListDataDefinition<>();
+        operationOutputDefinitionList.add(createOperationOutputDefinition("TestOutput1"));
+        operation.setOutputs(operationOutputDefinitionList);
+        return buildInterfaceDefinitionMap(operation,"tosca.interfaces.node.lifecycle.Standard", resourceInterfaceUniqueId, resourceOperationUniqueId);
+    }
+
+    private OperationInputDefinition createOperationInputDefinition(String name, String inputId) {
+        OperationInputDefinition operationInputDefinition = new OperationInputDefinition();
+        operationInputDefinition.setName(name);
+        operationInputDefinition.setInputId(inputId);
+        operationInputDefinition.setRequired(true);
+        operationInputDefinition.setType("string");
+        return operationInputDefinition;
+    }
+
+    private OperationOutputDefinition createOperationOutputDefinition(String name) {
+        OperationOutputDefinition operationOutputDefinition = new OperationOutputDefinition();
+        operationOutputDefinition.setName(name);
+        operationOutputDefinition.setRequired(true);
+        operationOutputDefinition.setType("string");
+        return operationOutputDefinition;
+    }
+
+    private Map<String, Object> buildInterfaceDefinitionMap(Operation operation, String interfaceType, String interfaceId,
+            String operationId) {
+        if (operationId != null) {
+            operation.setUniqueId(operationId);
+        }
+        Map<String, Operation> operationMap = new HashMap<>();
+        operationMap.put(operation.getName(), operation);
+
+        InterfaceDefinition interfaceDefinition = new InterfaceDefinition();
+        interfaceDefinition.setType(interfaceType);
+        interfaceDefinition.setOperationsMap(operationMap);
+        if (interfaceId != null) {
+            interfaceDefinition.setUniqueId(interfaceId);
+        }
+        interfaceDefinition.setOperationsMap(operationMap);
+
+        Map<String, Object> interfaceDefAsMap = getObjectAsMap(interfaceDefinition);
+        Map<String, Object> interfaceMap = new HashMap<>();
+        interfaceMap.put(interfaceDefinition.getType(), interfaceDefAsMap);
+        Map<String, Object> outerMap = new HashMap<>();
+        outerMap.put(INTERFACES, interfaceMap);
+        return outerMap;
+    }
+
+    private static Map<String, Object> getObjectAsMap(Object obj) {
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (obj instanceof InterfaceDefinition) {
+            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        }
+        Map<String, Object> objectAsMap =
+                obj instanceof Map ? (Map<String, Object>) obj : objectMapper.convertValue(obj, Map.class);
+        objectAsMap.remove(TOSCA_PRESENTATION);
+        return objectAsMap;
+    }
+
+    private Map<String, Object> buildInterfaceDefinitionForService() {
+        Operation operation = new Operation();
+        operation.setName("TestOperationOnService");
+        operation.setWorkflowId("WorkflowId");
+        operation.setWorkflowVersionId("workflowVersionId");
+        operation.setWorkflowAssociationType("NONE");
+        return buildInterfaceDefinitionMap(operation,"TestInterface", serviceInterfaceUniqueId, serviceOperationUniqueId);
+    }
+
+    @Test
+    public void addInterfaceOperationsOnResource() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .addInterfaceOperations(resource, buildInterfaceDefinitionForResource(),
+                                                    user);
+        logger.info("addInterfaceOperationsOnResource Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+        String interfaceDefinitionStr = ResponseParser.getListFromJson(restResponse, INTERFACES).get(0).toString();
+        InterfaceDefinition interfaceDefinition =
+                ResponseParser.convertInterfaceDefinitionResponseToJavaObject(interfaceDefinitionStr);
+        resourceInterfaceUniqueId = interfaceDefinition.getUniqueId();
+        resourceOperationUniqueId = interfaceDefinition.getOperationsMap().keySet().stream().findFirst().orElse(null);
+    }
+
+    @Test(dependsOnMethods = "addInterfaceOperationsOnResource")
+    public void getInterfaceOperationsFromResource() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .getInterfaceOperations(resource, resourceInterfaceUniqueId,
+                                                    resourceOperationUniqueId, user);
+        logger.info("getInterfaceOperationsFromResource Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+    }
+
+    @Test(dependsOnMethods = "getInterfaceOperationsFromResource")
+    public void updateInterfaceOperationsOnResource() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .updateInterfaceOperations(resource, buildInterfaceDefinitionForResource(),
+                                                    user);
+        logger.info("updateInterfaceOperationsOnResource Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+    }
+
+    /*@Test(dependsOnMethods = "updateInterfaceOperationsOnResource")
+    public void deleteInterfaceOperationsFromResource() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .deleteInterfaceOperations(resource, resourceInterfaceUniqueId,
+                                                    resourceOperationUniqueId, user);
+        logger.info("deleteInterfaceOperationsFromResource Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+    }*/
+
+    @Test
+    public void addInterfaceOperationsOnService() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .addInterfaceOperations(service, buildInterfaceDefinitionForService(),
+                                                    user);
+        logger.info("addInterfaceOperationsOnService Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+        String interfaceDefinitionStr = ResponseParser.getListFromJson(restResponse, INTERFACES).get(0).toString();
+        InterfaceDefinition interfaceDefinition =
+                ResponseParser.convertInterfaceDefinitionResponseToJavaObject(interfaceDefinitionStr);
+        serviceInterfaceUniqueId = interfaceDefinition.getUniqueId();
+        serviceOperationUniqueId = interfaceDefinition.getOperationsMap().keySet().stream().findFirst().orElse(null);
+    }
+
+    @Test(dependsOnMethods = "addInterfaceOperationsOnService")
+    public void getInterfaceOperationsFromService() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .getInterfaceOperations(service, serviceInterfaceUniqueId,
+                                                    serviceOperationUniqueId, user);
+        logger.info("getInterfaceOperationsFromService Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+    }
+
+    @Test(dependsOnMethods = "getInterfaceOperationsFromService")
+    public void updateInterfaceOperationsOnService() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .updateInterfaceOperations(service, buildInterfaceDefinitionForService(),
+                                                    user);
+        logger.info("updateInterfaceOperations Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+    }
+
+    @Test(dependsOnMethods = "updateInterfaceOperationsOnService")
+    public void deleteInterfaceOperationsFromService() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .deleteInterfaceOperations(service, serviceInterfaceUniqueId,
+                                                    serviceOperationUniqueId, user);
+        logger.info("deleteInterfaceOperations Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+    }
+
+    @Test
+    public void addInterfaceOperationsOfGlobalTypeOnResource() throws Exception {
+        RestResponse restResponse = InterfaceOperationsRestUtils
+                                            .addInterfaceOperations(resource, buildInterfaceDefinitionOfGlobalTypeForResource(),
+                                                    user);
+        logger.info("addInterfaceOperationsOnResource Response Code:" + restResponse.getErrorCode());
+        Assert.assertEquals((int) restResponse.getErrorCode(), BaseRestUtils.STATUS_CODE_SUCCESS);
+        String interfaceDefinitionStr = ResponseParser.getListFromJson(restResponse, INTERFACES).get(0).toString();
+        InterfaceDefinition interfaceDefinition =
+                ResponseParser.convertInterfaceDefinitionResponseToJavaObject(interfaceDefinitionStr);
+    }
+
+}
diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/InterfaceOperationsRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/InterfaceOperationsRestUtils.java
new file mode 100644
index 0000000..c3486cd
--- /dev/null
+++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/InterfaceOperationsRestUtils.java
@@ -0,0 +1,59 @@
+package org.openecomp.sdc.ci.tests.utils.rest;
+
+import com.google.gson.Gson;
+import java.io.IOException;
+import java.util.Map;
+import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.User;
+import org.openecomp.sdc.ci.tests.api.Urls;
+import org.openecomp.sdc.ci.tests.config.Config;
+import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse;
+import org.openecomp.sdc.ci.tests.utils.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InterfaceOperationsRestUtils extends BaseRestUtils {
+
+    @SuppressWarnings("unused")
+    private static Logger logger = LoggerFactory.getLogger(InterfaceOperationsRestUtils.class.getName());
+
+    public static RestResponse addInterfaceOperations(Component component, Map<String, Object> interfaceDefinitionMap,
+            User user) throws IOException {
+        Config config = Utils.getConfig();
+        String url = String.format(Urls.ADD_INTERFACE_OPERATIONS, config.getCatalogBeHost(), config.getCatalogBePort(),
+                ComponentTypeEnum.findParamByType(component.getComponentType()), component.getUniqueId());
+        String jsonBody = new Gson().toJson(interfaceDefinitionMap);
+        return sendPost(url, jsonBody, user.getUserId(), acceptHeaderData);
+    }
+
+    public static RestResponse updateInterfaceOperations(Component component,
+            Map<String, Object> interfaceDefinitionMap, User user) throws IOException {
+        Config config = Utils.getConfig();
+        String url =
+                String.format(Urls.UPDATE_INTERFACE_OPERATIONS, config.getCatalogBeHost(), config.getCatalogBePort(),
+                        ComponentTypeEnum.findParamByType(component.getComponentType()), component.getUniqueId());
+        String jsonBody = new Gson().toJson(interfaceDefinitionMap);
+        return sendPut(url, jsonBody, user.getUserId(), acceptHeaderData);
+    }
+
+    public static RestResponse getInterfaceOperations(Component component, String interfaceId, String operationIds,
+            User user) throws IOException {
+        Config config = Utils.getConfig();
+        String url = String.format(Urls.GET_INTERFACE_OPERATIONS, config.getCatalogBeHost(), config.getCatalogBePort(),
+                ComponentTypeEnum.findParamByType(component.getComponentType()), component.getUniqueId(), interfaceId,
+                operationIds);
+        return sendGet(url, user.getUserId());
+    }
+
+    public static RestResponse deleteInterfaceOperations(Component component, String interfaceId, String operationIds,
+            User user) throws IOException {
+        Config config = Utils.getConfig();
+        String url =
+                String.format(Urls.DELETE_INTERFACE_OPERATIONS, config.getCatalogBeHost(), config.getCatalogBePort(),
+                        ComponentTypeEnum.findParamByType(component.getComponentType()), component.getUniqueId(),
+                        interfaceId, operationIds);
+        return sendDelete(url, user.getUserId());
+    }
+
+}
diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java
index ec21214..30e54d3 100644
--- a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java
+++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java
@@ -680,4 +680,18 @@
 		return  vfModulesMap;
 	}
 
+	public static InterfaceDefinition convertInterfaceDefinitionResponseToJavaObject(String response) {
+		ObjectMapper mapper = new ObjectMapper();
+		InterfaceDefinition interfaceDefinition = null;
+		try {
+			mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+			interfaceDefinition = mapper.readValue(response, InterfaceDefinition.class);
+			logger.debug(interfaceDefinition.toString());
+		}
+		catch (IOException e) {
+			logger.debug(e);
+		}
+		return interfaceDefinition;
+	}
+
 }
diff --git a/test-apis-ci/src/main/resources/ci/testSuites/resource.xml b/test-apis-ci/src/main/resources/ci/testSuites/resource.xml
index 803fb01..05080b2 100644
--- a/test-apis-ci/src/main/resources/ci/testSuites/resource.xml
+++ b/test-apis-ci/src/main/resources/ci/testSuites/resource.xml
@@ -354,6 +354,15 @@
 				<include name="undoCheckOutProductByPm"/>	
 			  </methods>
 		</class>
+			<class name="org.openecomp.sdc.ci.tests.execute.interfaceoperation.InterfaceOperationsTest">
+				<methods>
+					<include name="addInterfaceOperationsOfGlobalTypeOnResource"/>
+					<include name="addInterfaceOperationsOnResource"/>
+					<include name="getInterfaceOperationsFromResource"/>
+					<include name="updateInterfaceOperationsOnResource"/>
+					<include name="deleteInterfaceOperationsFromResource"/>
+				</methods>
+			</class>
 		<!-- Product tests end-->
 	 </classes>
   </test> <!-- Test -->
diff --git a/test-apis-ci/src/main/resources/ci/testSuites/service.xml b/test-apis-ci/src/main/resources/ci/testSuites/service.xml
index 18d5630..5c64fb4 100644
--- a/test-apis-ci/src/main/resources/ci/testSuites/service.xml
+++ b/test-apis-ci/src/main/resources/ci/testSuites/service.xml
@@ -10,6 +10,14 @@
       <class name="org.openecomp.sdc.ci.tests.execute.service.ServiceComponentInstanceCRUDTest"/>
       <class name="org.openecomp.sdc.ci.tests.execute.service.UpdateServiceMetadataTest"/>
       <class name="org.openecomp.sdc.ci.tests.execute.service.GetAllServiceVersions"/>
+      <class name="org.openecomp.sdc.ci.tests.execute.interfaceoperation.InterfaceOperationsTest">
+        <methods>
+          <include name="addInterfaceOperationsOnService"/>
+          <include name="getInterfaceOperationsFromService"/>
+          <include name="updateInterfaceOperationsOnService"/>
+          <include name="deleteInterfaceOperationsFromService"/>
+        </methods>
+      </class>
         </classes> 
     </test>
 </suite> <!-- Service -->