added svcapi ui and camunda code
[it/otf.git] / otf-service-api / src / main / java / org / oran / otf / api / service / impl / TestInstanceServiceImpl.java
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java
new file mode 100644 (file)
index 0000000..d171206
--- /dev/null
@@ -0,0 +1,807 @@
+/*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+##############################################################################*/\r
+\r
+\r
+package org.oran.otf.api.service.impl;\r
+\r
+import org.oran.otf.api.Utilities;\r
+import org.oran.otf.api.Utilities.LogLevel;\r
+import org.oran.otf.api.handler.CamundaProcessExecutionHandler;\r
+import org.oran.otf.api.service.TestInstanceService;\r
+import org.oran.otf.common.model.Group;\r
+import org.oran.otf.common.model.TestDefinition;\r
+import org.oran.otf.common.model.TestInstance;\r
+import org.oran.otf.common.model.User;\r
+import org.oran.otf.common.model.local.BpmnInstance;\r
+import org.oran.otf.common.model.local.TestInstanceCreateRequest;\r
+import org.oran.otf.common.model.local.WorkflowRequest;\r
+import org.oran.otf.common.repository.GroupRepository;\r
+import org.oran.otf.common.repository.TestDefinitionRepository;\r
+import org.oran.otf.common.repository.TestInstanceRepository;\r
+import org.oran.otf.common.repository.UserRepository;\r
+import org.oran.otf.common.utility.Utility;\r
+import org.oran.otf.common.utility.database.Generic;\r
+import org.oran.otf.common.utility.http.ResponseUtility;\r
+import org.oran.otf.common.utility.permissions.PermissionChecker;\r
+import org.oran.otf.common.utility.permissions.UserPermission;\r
+import com.google.common.base.Strings;\r
+import org.bson.types.ObjectId;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
+import org.springframework.stereotype.Service;\r
+\r
+import javax.ws.rs.core.MediaType;\r
+import javax.ws.rs.core.Response;\r
+import java.util.*;\r
+\r
+@Service\r
+public class TestInstanceServiceImpl implements TestInstanceService {\r
+    @Autowired\r
+    CamundaProcessExecutionHandler camundaProcessExecutionHandler;\r
+    @Autowired\r
+    UserRepository userRepository;\r
+    @Autowired\r
+    TestInstanceRepository testInstanceRepository;\r
+    @Autowired\r
+    TestDefinitionRepository testDefinitionRepository;\r
+    @Autowired\r
+    GroupRepository groupRepository;\r
+\r
+    private static final Logger logger = LoggerFactory.getLogger(TestInstanceServiceImpl.class);\r
+    private static final String logPrefix = Utility.getLoggerPrefix();\r
+\r
+    @Override\r
+    public Response execute(String testInstanceId, String authorization, WorkflowRequest request) {\r
+        try {\r
+            if (request == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage("Request body is null.");\r
+            }\r
+\r
+            // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request\r
+            // response.\r
+            if (!Utilities.isObjectIdValid(testInstanceId)) {\r
+                String error =\r
+                        String.format(\r
+                                "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",\r
+                                logPrefix, testInstanceId);\r
+                return ResponseUtility.Build.badRequestWithMessage(error);\r
+            }\r
+\r
+            // Create an ObjectId now that we know the provided String was valid.\r
+            ObjectId oiTestInstanceId = new ObjectId(testInstanceId);\r
+            // Check if the testInstance exists, otherwise return a not found response.\r
+            TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);\r
+            if (testInstance == null) {\r
+                String error =\r
+                        String.format(\r
+                                "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);\r
+                return ResponseUtility.Build.notFoundWithMessage(error);\r
+            }\r
+            // Check if the testDefinition exists.\r
+            TestDefinition testDefinition =\r
+                    Generic.findByIdGeneric(testDefinitionRepository, testInstance.getTestDefinitionId());\r
+            if (testDefinition == null) {\r
+                String error =\r
+                        String.format(\r
+                                "%sThe testDefinition with _id, %s, was not found.",\r
+                                logPrefix, testInstance.getTestDefinitionId().toString());\r
+                return ResponseUtility.Build.notFoundWithMessage(error);\r
+            }\r
+\r
+            // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+            // the database.\r
+            User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+            if (mechanizedIdUser == null) {\r
+                String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+                if (decodedAuth == null) {\r
+                    return ResponseUtility.Build.badRequestWithMessage(\r
+                            String.format("Unable to decode authorization header: %s", authorization));\r
+                }\r
+                String error =\r
+                        String.format(\r
+                                "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+                return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+            }\r
+\r
+            // If the mechanizedId is not an OTF mechanizedId, check if the user is authorized to\r
+            // execute\r
+            // the test instance. This is required because the executorId only needs to be read from the\r
+            // otf-frontend component. The user/group system is not fully integrated with AAF, so this\r
+            // is\r
+            // required. A better way might be to use certificates to check identities.\r
+            Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
+            // if we cant find the test instance group then we cant check the permission\r
+            if (testInstanceGroup == null) {\r
+                return ResponseUtility.Build.\r
+                        badRequestWithMessage(\r
+                                String.format("Can not find test instance group, id:%s", testInstance.getGroupId().toString()));\r
+            }\r
+            // If the mechanizedId is authorized, set the executorId in the WorkflowRequest to the\r
+            // mechanizedId's ObjectId to make sure that the executorId isn't spoofed. Only use the\r
+            // executorId sent with the request if it uses the OTF mechanizedId because we "trust" it.\r
+            if (isOtfMechanizedIdentifier(mechanizedIdUser.getEmail()) && request.getExecutorId() != null) {\r
+                mechanizedIdUser = Utilities.resolveOptional(userRepository.findById(request.getExecutorId().toString()));\r
+            } else {\r
+                request.setExecutorId(mechanizedIdUser.get_id());\r
+            }\r
+            if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup, UserPermission.Permission.EXECUTE,groupRepository)) {\r
+                String error =\r
+                        String.format(\r
+                                "%sUnauthorized the execute test instance with _id, %s.",\r
+                                logPrefix, testInstanceId);\r
+                return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+            }\r
+\r
+            // Set the test instance _id after authorization.\r
+            request.setTestInstanceId(testInstance.get_id());\r
+\r
+            // Check if the test instance is disabled.\r
+            if (testInstance.isDisabled()) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("The test instance with identifier %s is disabled.", testInstanceId));\r
+            }\r
+            // Check if the test definition is disabled.\r
+            if (testDefinition.isDisabled()) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format(\r
+                                "The test definition with identifier %s is disabled.",\r
+                                testInstance.getTestDefinitionId().toString()));\r
+            }\r
+\r
+            // Send the request to Camunda.\r
+            return camundaProcessExecutionHandler.startProcessInstance(request);\r
+        } catch (Exception e) {\r
+            Utilities.printStackTrace(e, LogLevel.ERROR);\r
+            return ResponseUtility.Build.internalServerError();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Response createByTestDefinitionId(\r
+            String testDefinitionId, String authorization, TestInstanceCreateRequest request) {\r
+        try {\r
+            // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+            // the database.\r
+            User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+            if (mechanizedIdUser == null) {\r
+                String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+                if (decodedAuth == null) {\r
+                    return ResponseUtility.Build.badRequestWithMessage(\r
+                            String.format("Unable to decode authorization header: %s", authorization));\r
+                }\r
+                String error =\r
+                        String.format(\r
+                                "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+                return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+            }\r
+\r
+            // Check if the String correctly parses as an ObjectId.\r
+            if (!Utilities.isObjectIdValid(testDefinitionId)) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format(\r
+                                "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));\r
+            }\r
+            ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);\r
+\r
+            // Find the testDefinition\r
+            TestDefinition testDefinition =\r
+                    Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);\r
+            if (testDefinition == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format("Test definition with id, %s, was not found.", testDefinitionId));\r
+            }\r
+            // Check if the mechanizedId has access to the test definition.\r
+            Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
+            if (testDefGroup == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
+            }\r
+//            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
+//                return ResponseUtility.Build.unauthorizedWithMessage(\r
+//                        String.format(\r
+//                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
+//                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+//            }\r
+//            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
+//                return ResponseUtility.Build.unauthorizedWithMessage(\r
+//                        String.format(\r
+//                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
+//                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+//            }\r
+            if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
+                    Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
+            {\r
+                return ResponseUtility.Build.unauthorizedWithMessage(\r
+                        String.format(\r
+                                "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
+                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+            }\r
+            // Get the latest version of the test definition to link it with the test instance\r
+            BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, true);\r
+            if (bpmnInstance == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format(\r
+                                "Test definition with id, %s, does not have any versions associated with it.",\r
+                                testDefinitionId));\r
+            }\r
+\r
+            TestInstance testInstance =\r
+                    new TestInstance(\r
+                            new ObjectId(),\r
+                            request.getTestInstanceName(),\r
+                            request.getTestInstanceDescription(),\r
+                            testDefinition.getGroupId(),\r
+                            testDefinition.get_id(),\r
+                            bpmnInstance.getProcessDefinitionId(),\r
+                            request.isUseLatestTestDefinition(),\r
+                            false,\r
+                            request.isSimulationMode(),\r
+                            request.getMaxExecutionTimeInMillis(),\r
+                            request.getPfloInput(),\r
+                            new HashMap<>(),\r
+                            request.getSimulationVthInput(),\r
+                            request.getTestData(),\r
+                            request.getVthInput(),\r
+                            new Date(System.currentTimeMillis()),\r
+                            new Date(System.currentTimeMillis()),\r
+                            mechanizedIdUser.get_id(),\r
+                            mechanizedIdUser.get_id());\r
+\r
+            return Response.ok()\r
+                    .type(MediaType.APPLICATION_JSON_TYPE)\r
+                    .entity(testInstance.toString())\r
+                    .build();\r
+        } catch (Exception e) {\r
+            Utilities.printStackTrace(e, LogLevel.ERROR);\r
+            return ResponseUtility.Build.internalServerError();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Response createByTestDefinitionId(\r
+            String testDefinitionId,\r
+            int version,\r
+            String authorization,\r
+            TestInstanceCreateRequest request) {\r
+        try {\r
+            // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+            // the database.\r
+            User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+            if (mechanizedIdUser == null) {\r
+                String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+                if (decodedAuth == null) {\r
+                    return ResponseUtility.Build.badRequestWithMessage(\r
+                            String.format("Unable to decode authorization header: %s", authorization));\r
+                }\r
+                String error =\r
+                        String.format(\r
+                                "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+                return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+            }\r
+\r
+            // Check if the String correctly parses as an ObjectId.\r
+            if (!Utilities.isObjectIdValid(testDefinitionId)) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format(\r
+                                "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));\r
+            }\r
+            ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);\r
+\r
+            // Find the testDefinition\r
+            TestDefinition testDefinition =\r
+                    Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);\r
+            if (testDefinition == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format("Test definition with id, %s, was not found.", testDefinitionId));\r
+            }\r
+            // permission checking\r
+            Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
+            if (testDefGroup == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
+            }\r
+            // if not otf email and is not authorized\r
+//            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
+////                return ResponseUtility.Build.unauthorizedWithMessage(\r
+////                        String.format(\r
+////                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
+////                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+////            }\r
+////            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
+////                return ResponseUtility.Build.unauthorizedWithMessage(\r
+////                        String.format(\r
+////                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
+////                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+////            }\r
+            if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
+                    Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
+            {\r
+                return ResponseUtility.Build.unauthorizedWithMessage(\r
+                        String.format(\r
+                                "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
+                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+            }\r
+            // Get the latest version of the test definition to link it with the test instance\r
+            BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);\r
+            if (bpmnInstance == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format(\r
+                                "Test definition with id, %s, does not have any versions associated with it.",\r
+                                testDefinitionId));\r
+            }\r
+\r
+            TestInstance testInstance =\r
+                    new TestInstance(\r
+                            new ObjectId(),\r
+                            request.getTestInstanceName(),\r
+                            request.getTestInstanceDescription(),\r
+                            testDefinition.getGroupId(),\r
+                            testDefinition.get_id(),\r
+                            bpmnInstance.getProcessDefinitionId(),\r
+                            request.isUseLatestTestDefinition(),\r
+                            false,\r
+                            request.isSimulationMode(),\r
+                            request.getMaxExecutionTimeInMillis(),\r
+                            request.getPfloInput(),\r
+                            new HashMap<>(),\r
+                            request.getSimulationVthInput(),\r
+                            request.getTestData(),\r
+                            request.getVthInput(),\r
+                            new Date(System.currentTimeMillis()),\r
+                            new Date(System.currentTimeMillis()),\r
+                            mechanizedIdUser.get_id(),\r
+                            mechanizedIdUser.get_id());\r
+\r
+            return Response.ok()\r
+                    .type(MediaType.APPLICATION_JSON_TYPE)\r
+                    .entity(testInstance.toString())\r
+                    .build();\r
+        } catch (Exception e) {\r
+            Utilities.printStackTrace(e, LogLevel.ERROR);\r
+            return ResponseUtility.Build.internalServerError();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Response createByProcessDefinitionKey(\r
+            String processDefinitionKey, String authorization, TestInstanceCreateRequest request) {\r
+        try {\r
+            // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+            // the database.\r
+            User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+            if (mechanizedIdUser == null) {\r
+                String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+                if (decodedAuth == null) {\r
+                    return ResponseUtility.Build.badRequestWithMessage(\r
+                            String.format("Unable to decode authorization header: %s", authorization));\r
+                }\r
+                String error =\r
+                        String.format(\r
+                                "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+                return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+            }\r
+\r
+            // Check if the String correctly parses as an ObjectId.\r
+            if (Strings.isNullOrEmpty(processDefinitionKey)) {\r
+                return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");\r
+            }\r
+\r
+            // Find the testDefinition\r
+            TestDefinition testDefinition =\r
+                    testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);\r
+            if (testDefinition == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format(\r
+                                "Test definition with processDefinitionKey, %s, was not found.",\r
+                                processDefinitionKey));\r
+            }\r
+\r
+            Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
+            if (testDefGroup == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
+            }\r
+            // if not otf email and is not authorized\r
+//            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
+//                return ResponseUtility.Build.unauthorizedWithMessage(\r
+//                        String.format(\r
+//                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
+//                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+//            }\r
+//            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
+//                return ResponseUtility.Build.unauthorizedWithMessage(\r
+//                        String.format(\r
+//                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
+//                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+//            }\r
+            if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
+                    Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
+            {\r
+                return ResponseUtility.Build.unauthorizedWithMessage(\r
+                        String.format(\r
+                                "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
+                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+            }\r
+            // Get the latest version of the test definition to link it with the test instance\r
+            BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, false);\r
+            if (bpmnInstance == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format(\r
+                                "Test definition with id, %s, does not have any versions associated with it.",\r
+                                testDefinition.get_id().toString()));\r
+            }\r
+\r
+            TestInstance testInstance =\r
+                    new TestInstance(\r
+                            new ObjectId(),\r
+                            request.getTestInstanceName(),\r
+                            request.getTestInstanceDescription(),\r
+                            testDefinition.getGroupId(),\r
+                            testDefinition.get_id(),\r
+                            bpmnInstance.getProcessDefinitionId(),\r
+                            request.isUseLatestTestDefinition(),\r
+                            false,\r
+                            request.isSimulationMode(),\r
+                            request.getMaxExecutionTimeInMillis(),\r
+                            request.getPfloInput(),\r
+                            new HashMap<>(),\r
+                            request.getSimulationVthInput(),\r
+                            request.getTestData(),\r
+                            request.getVthInput(),\r
+                            new Date(System.currentTimeMillis()),\r
+                            new Date(System.currentTimeMillis()),\r
+                            mechanizedIdUser.get_id(),\r
+                            mechanizedIdUser.get_id());\r
+\r
+            return Response.ok()\r
+                    .type(MediaType.APPLICATION_JSON_TYPE)\r
+                    .entity(testInstance.toString())\r
+                    .build();\r
+        } catch (Exception e) {\r
+            Utilities.printStackTrace(e, LogLevel.ERROR);\r
+            return ResponseUtility.Build.internalServerError();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Response createByProcessDefinitionKey(\r
+            String processDefinitionKey,\r
+            int version,\r
+            String authorization,\r
+            TestInstanceCreateRequest request) {\r
+        try {\r
+            // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+            // the database.\r
+            User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+            if (mechanizedIdUser == null) {\r
+                String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+                if (decodedAuth == null) {\r
+                    return ResponseUtility.Build.badRequestWithMessage(\r
+                            String.format("Unable to decode authorization header: %s", authorization));\r
+                }\r
+                String error =\r
+                        String.format(\r
+                                "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+                return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+            }\r
+\r
+            // Check if the String correctly parses as an ObjectId.\r
+            if (Strings.isNullOrEmpty(processDefinitionKey)) {\r
+                return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");\r
+            }\r
+\r
+            // Find the testDefinition\r
+            TestDefinition testDefinition =\r
+                    testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);\r
+            if (testDefinition == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format(\r
+                                "Test definition with processDefinitionKey, %s, was not found.",\r
+                                processDefinitionKey));\r
+            }\r
+\r
+            Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));\r
+            if (testDefGroup == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));\r
+            }\r
+            // if not otf email and is not authorized\r
+//            if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {\r
+//                return ResponseUtility.Build.unauthorizedWithMessage(\r
+//                        String.format(\r
+//                                "MechanizedId, %s, does not have read access to test definition in group with name, %s",\r
+//                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+//            }\r
+//            if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {\r
+//                return ResponseUtility.Build.unauthorizedWithMessage(\r
+//                        String.format(\r
+//                                "MechanizedId, %s, does not have write access to the group with name, %s",\r
+//                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+//            }\r
+            if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,\r
+                    Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))\r
+            {\r
+                return ResponseUtility.Build.unauthorizedWithMessage(\r
+                        String.format(\r
+                                "MechanizedId, %s, does not have access (read/write) to the group with name, %s",\r
+                                mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));\r
+            }\r
+            // Get the latest version of the test definition to link it with the test instance\r
+            BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);\r
+            if (bpmnInstance == null) {\r
+                return ResponseUtility.Build.notFoundWithMessage(\r
+                        String.format(\r
+                                "Test definition with id, %s, does not have any versions associated with it.",\r
+                                testDefinition.get_id().toString()));\r
+            }\r
+\r
+            TestInstance testInstance =\r
+                    new TestInstance(\r
+                            new ObjectId(),\r
+                            request.getTestInstanceName(),\r
+                            request.getTestInstanceDescription(),\r
+                            testDefinition.getGroupId(),\r
+                            testDefinition.get_id(),\r
+                            bpmnInstance.getProcessDefinitionId(),\r
+                            request.isUseLatestTestDefinition(),\r
+                            false,\r
+                            request.isSimulationMode(),\r
+                            request.getMaxExecutionTimeInMillis(),\r
+                            request.getPfloInput(),\r
+                            new HashMap<>(),\r
+                            request.getSimulationVthInput(),\r
+                            request.getTestData(),\r
+                            request.getVthInput(),\r
+                            new Date(System.currentTimeMillis()),\r
+                            new Date(System.currentTimeMillis()),\r
+                            mechanizedIdUser.get_id(),\r
+                            mechanizedIdUser.get_id());\r
+\r
+            return Response.ok()\r
+                    .type(MediaType.APPLICATION_JSON_TYPE)\r
+                    .entity(testInstance.toString())\r
+                    .build();\r
+        } catch (Exception e) {\r
+            Utilities.printStackTrace(e, LogLevel.ERROR);\r
+            return ResponseUtility.Build.internalServerError();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Response findById(String testInstanceId, String authorization) {\r
+        // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+        // the database.\r
+        User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+        if (mechanizedIdUser == null) {\r
+            String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+            if (decodedAuth == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("Unable to decode authorization header: %s", authorization));\r
+            }\r
+            String error =\r
+                    String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+            return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+        }\r
+\r
+        // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request\r
+        // response.\r
+        if (!Utilities.isObjectIdValid(testInstanceId)) {\r
+            String error =\r
+                    String.format(\r
+                            "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",\r
+                            logPrefix, testInstanceId);\r
+            return ResponseUtility.Build.badRequestWithMessage(error);\r
+        }\r
+\r
+        // Create an ObjectId now that we know the provided String was valid.\r
+        ObjectId oiTestInstanceId = new ObjectId(testInstanceId);\r
+        // Check if the testInstance exists, otherwise return a not found response.\r
+        TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);\r
+        if (testInstance == null) {\r
+            String error =\r
+                    String.format(\r
+                            "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);\r
+            return ResponseUtility.Build.notFoundWithMessage(error);\r
+        }\r
+\r
+        Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
+        if (testInstanceGroup == null) {\r
+            return ResponseUtility.Build.badRequestWithMessage(\r
+                    String.format("Can not find test instance's group, group name :%s", testInstance.get_id().toString()));\r
+        }\r
+        if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {\r
+            return ResponseUtility.Build.unauthorizedWithMessage(\r
+                    String.format(\r
+                            "User %s does not have read access to test instance group, group name: %s.",\r
+                            mechanizedIdUser.getEmail(), testInstanceGroup.getGroupName()));\r
+        }\r
+        return Response.ok(testInstance.toString(), MediaType.APPLICATION_JSON_TYPE).build();\r
+    }\r
+\r
+    @Override\r
+    public Response findByProcessDefinitionKey(String processDefinitionKey, String authorization) {\r
+        // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+        // the database.\r
+        User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+        if (mechanizedIdUser == null) {\r
+            String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+            if (decodedAuth == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("Unable to decode authorization header: %s", authorization));\r
+            }\r
+            String error =\r
+                    String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+            return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+        }\r
+\r
+        Optional<TestDefinition> optionalTestDefinition =\r
+                testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);\r
+        TestDefinition testDefinition = optionalTestDefinition.orElse(null);\r
+        if (testDefinition == null) {\r
+            return Utilities.Http.BuildResponse.badRequestWithMessage(\r
+                    String.format(\r
+                            "Cannot find test instance because a test"\r
+                                    + " definition with the process definition key (%s) does not exist.",\r
+                            processDefinitionKey));\r
+        }\r
+\r
+        List<TestInstance> testInstances =\r
+                testInstanceRepository.findAllByTestDefinitionId(testDefinition.get_id());\r
+        if (testInstances.isEmpty()) {\r
+            return Utilities.Http.BuildResponse.badRequestWithMessage(\r
+                    String.format(\r
+                            "No test instances found with process " + "definition key (%s).",\r
+                            processDefinitionKey));\r
+        }\r
+\r
+        List<TestInstance> result = new ArrayList<>();\r
+        for (TestInstance testInstance : testInstances) {\r
+            Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
+            if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {\r
+                result.add(testInstance);\r
+            }\r
+        }\r
+\r
+        return Response.ok(result.toString()).build();\r
+    }\r
+\r
+    @Override\r
+    public Response findByProcessDefinitionKeyAndVersion(\r
+            String processDefinitionKey, String version, String authorization) {\r
+        // Check if a user associated with the mechanizedId used in the authorization header exists in\r
+        // the database.\r
+        User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);\r
+        if (mechanizedIdUser == null) {\r
+            String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);\r
+            if (decodedAuth == null) {\r
+                return ResponseUtility.Build.badRequestWithMessage(\r
+                        String.format("Unable to decode authorization header: %s", authorization));\r
+            }\r
+            String error =\r
+                    String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);\r
+            return ResponseUtility.Build.unauthorizedWithMessage(error);\r
+        }\r
+\r
+        Optional<TestDefinition> optionalTestDefinition =\r
+                testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);\r
+        TestDefinition testDefinition = optionalTestDefinition.orElse(null);\r
+\r
+        if (testDefinition == null) {\r
+            return Utilities.Http.BuildResponse.badRequestWithMessage(\r
+                    String.format(\r
+                            "Cannot find test instance because a test"\r
+                                    + " definition with the process definition key (%s) does not exist.",\r
+                            processDefinitionKey));\r
+        }\r
+\r
+        int iVersion;\r
+        try {\r
+            iVersion = Integer.parseInt(version);\r
+        } catch (NumberFormatException nfe) {\r
+            return Utilities.Http.BuildResponse.badRequestWithMessage("Version must be a valid integer.");\r
+        }\r
+\r
+        BpmnInstance bpmnInstance =\r
+                testDefinition.getBpmnInstances().stream()\r
+                        .filter(_bpmnInstance -> _bpmnInstance.getVersion() == iVersion)\r
+                        .findAny()\r
+                        .orElse(null);\r
+\r
+        if (bpmnInstance == null) {\r
+            return Utilities.Http.BuildResponse.badRequestWithMessage(\r
+                    String.format("Cannot find any test instances using " + "version %s.", version));\r
+        }\r
+\r
+        List<TestInstance> testInstances =\r
+                testInstanceRepository.findAllByTestDefinitionIdAndPDId(\r
+                        testDefinition.get_id(), bpmnInstance.getProcessDefinitionId());\r
+\r
+        if (testInstances.isEmpty()) {\r
+            return Utilities.Http.BuildResponse.badRequestWithMessage(\r
+                    String.format(\r
+                            "No test instances found with process " + "definition key (%s).",\r
+                            processDefinitionKey));\r
+        }\r
+\r
+        List<TestInstance> result = new ArrayList<>();\r
+        for (TestInstance testInstance : testInstances) {\r
+            Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));\r
+            if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {\r
+                result.add(testInstance);\r
+            }\r
+        }\r
+\r
+        return Response.ok(result.toString()).build();\r
+    }\r
+\r
+    private boolean isOtfMechanizedIdentifier(String email) {\r
+        return email.equalsIgnoreCase("email@localhost")\r
+                || email.equalsIgnoreCase("email@localhost")\r
+                || email.equalsIgnoreCase("email@localhost")\r
+                || email.equalsIgnoreCase("email@localhost")\r
+                || email.equalsIgnoreCase("email@localhost");\r
+    }\r
+\r
+    private BpmnInstance findBpmnInstance(TestDefinition testDefinition, int version, boolean latest)\r
+            throws Exception {\r
+        BpmnInstance bpmnInstance = null;\r
+        int maxVersion = Integer.MIN_VALUE;\r
+        // Check if the version exists\r
+        for (BpmnInstance bi : testDefinition.getBpmnInstances()) {\r
+            // If this field is null or empty, it means the bpmn hasn't been deployed, or there was a\r
+            // creation error on the Test Definition page (UI). Skip the field so the user isn't allowed\r
+            // to create a test instance based off this bpmn instance.\r
+            if (Strings.isNullOrEmpty(bi.getProcessDefinitionId())) {\r
+                continue;\r
+            }\r
+\r
+            // Split the processDefinitionId based on it's format:\r
+            // {processDefinitionKey}:{version}:{processDefinitionId}.\r
+            String processDefinitionId = bi.getProcessDefinitionId();\r
+            String[] processDefinitionIdSplit = processDefinitionId.split(":");\r
+            if (processDefinitionIdSplit.length != 3) {\r
+                throw new Exception(\r
+                        String.format(\r
+                                "testDefinition[%s].bpmnInstances.processDefinitionId[%s] is invalid.",\r
+                                testDefinition.get_id().toString(), bi.getProcessDefinitionId()));\r
+            }\r
+\r
+            String sVersion = processDefinitionIdSplit[1];\r
+            int currentVersion = Integer.parseInt(sVersion);\r
+            if (latest && currentVersion > maxVersion) {\r
+                bpmnInstance = bi;\r
+            } else if (currentVersion == version) {\r
+                bpmnInstance = bi;\r
+                break;\r
+            }\r
+        }\r
+\r
+        return bpmnInstance;\r
+    }\r
+\r
+//    private boolean isAuthorized(User user, Group group, String permission, GroupRepository groupRepository) {\r
+//        if (isOtfMechanizedIdentifier(user.getEmail())) {\r
+//            return true;\r
+//        }\r
+//        return PermissionChecker.isAuthorized(user, group, permission.toUpperCase(), groupRepository);\r
+//    }\r
+}\r
+/*\r
+ PermissionChecker.hasReadPermission(mechanizedIdUser,testInstanceGroup,groupRepository)\r
+\r
+  PermissionChecker.hasPermission(mechanizedIdUser,testInstanceGroup,groupRepository, [READ, WRITE])\r
+  PermissionsMAp = PermissionChecker.Build.hasRead\r
+ */
\ No newline at end of file