added svcapi ui and camunda code
Signed-off-by: Rohan Patel <rp5811@att.com>
Change-Id: I197b4b40fe3d047a417479214e471ae26d51fb2b
diff --git a/otf-service-api/.gitignore b/otf-service-api/.gitignore
new file mode 100644
index 0000000..681073c
--- /dev/null
+++ b/otf-service-api/.gitignore
@@ -0,0 +1,34 @@
+/target/
+tokens/
+out/
+src/main/resources/otf_dev.p12
+/otf/
+
+
+*.log
+
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+/null/
+
+### NetBeans ###
+/nbproject/private/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
diff --git a/otf-service-api/Jenkinsfile b/otf-service-api/Jenkinsfile
new file mode 100644
index 0000000..68e8d66
--- /dev/null
+++ b/otf-service-api/Jenkinsfile
@@ -0,0 +1,169 @@
+#!/usr/bin/env groovy
+
+properties([[$class: 'ParametersDefinitionProperty', parameterDefinitions: [
+ [$class: 'hudson.model.StringParameterDefinition', name: 'PHASE', defaultValue: "BUILD"],
+ [$class: 'hudson.model.StringParameterDefinition', name: 'ENV', defaultValue: "dev"],
+ [$class: 'hudson.model.StringParameterDefinition', name: 'MECHID', defaultValue: "username"],
+ [$class: 'hudson.model.StringParameterDefinition', name: 'KUBE_CONFIG', defaultValue: "kubeConfig-dev"],
+ [$class: 'hudson.model.StringParameterDefinition', name: 'OTF_MONGO_DB', defaultValue: "otf_mongo_dev_db"],
+ [$class: 'hudson.model.StringParameterDefinition', name: 'OTF_CAMUNDA_DB', defaultValue: "otf_camunda_dev_db"],
+ [$class: 'hudson.model.StringParameterDefinition', name: 'TILLER_NAMESPACE', defaultValue: "org-oran-otf"]
+
+]]])
+
+echo "Build branch: ${env.BRANCH_NAME}"
+
+node("docker") {
+ stage 'Checkout'
+ checkout scm
+ PHASES = PHASE.tokenize('_')
+ echo "PHASES : " + PHASES
+ pom = readMavenPom file: 'pom.xml'
+ ARTIFACT_ID = pom.artifactId
+ VERSION = pom.version
+ LABEL_VERSION = pom.version.replaceAll("\\.", "-")
+ echo "LabelVerion: " + LABEL_VERSION
+ NAMESPACE = pom.groupId
+ echo "Tiller Namespace: " + TILLER_NAMESPACE
+ DOCKER_REGISTRY = pom.properties['docker.registry']
+
+
+
+ if( ENV.equalsIgnoreCase("dev") ){
+ IMAGE_NAME = pom.properties['docker.registry'] + "/" + NAMESPACE + "/" + ARTIFACT_ID + ":" + VERSION
+
+ }
+ if( ENV.equalsIgnoreCase("prod") || ENV.equalsIgnoreCase("prod-dr")){
+ IMAGE_NAME = pom.properties['docker.registry'] + "/" + NAMESPACE + ".prod" + "/" + ARTIFACT_ID + ":" + VERSION
+
+ }
+ if( ENV.equalsIgnoreCase("st") ){
+ IMAGE_NAME = pom.properties['docker.registry'] + "/" + NAMESPACE + ".st" + "/" + ARTIFACT_ID + ":" + VERSION
+
+ }
+
+ echo "Artifact: " + IMAGE_NAME
+
+ withEnv(["PATH=${env.PATH}:${tool 'mvn352'}/bin:${tool 'jdk180'}/bin:${env.WORKSPACE}/linux-amd64", "JAVA_HOME=${tool 'jdk180'}", "MAVEN_HOME=${tool 'mvn352'}", "HELM_HOME=${env.WORKSPACE}"]) {
+
+ echo "JAVA_HOME=${env.JAVA_HOME}"
+ echo "MAVEN_HOME=${env.MAVEN_HOME}"
+ echo "PATH=${env.PATH}"
+ echo "HELM_HOME=${env.HELM_HOME}"
+
+ wrap([$class: 'ConfigFileBuildWrapper', managedFiles: [
+ [fileId: 'maven-settings.xml', variable: 'MAVEN_SETTINGS']
+ ]]) {
+
+
+ if (PHASES.contains("BUILD")) {
+ stage 'Compile'
+ sh 'mvn -s $MAVEN_SETTINGS clean compile'
+
+ //stage 'Unit Test'
+ sh 'mvn -s $MAVEN_SETTINGS test -DskipTests'
+
+ stage 'Package'
+ sh 'mvn -s $MAVEN_SETTINGS package -DskipTests'
+// sh 'mvn -DskipTests -Dmaven.test.skip=true -s $MAVEN_SETTINGS package'
+
+// stage 'Verify'
+ sh 'mvn -s $MAVEN_SETTINGS verify -DskipTests'
+
+ stage 'Publish Artifact'
+
+ withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
+
+ echo "Artifact: " + IMAGE_NAME
+
+ sh """
+ docker login $DOCKER_REGISTRY --username $USERNAME --password $PASSWORD
+ docker build -t $IMAGE_NAME -f target/Dockerfile target
+ docker push $IMAGE_NAME
+ """
+ }
+
+ }
+ if (PHASES.contains("DEPLOY") || PHASES.contains("UNDEPLOY")) {
+
+ stage 'Init Helm'
+
+ //check if helm exists if not install
+ if (fileExists('linux-amd64/helm')) {
+ sh """
+ echo "helm is already installed"
+ """
+ } else {
+ //download helm
+ sh """
+ echo "installing helm"
+ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.8.2-linux-amd64.tar.gz
+ tar -xf helm-v2.8.2-linux-amd64.tar.gz
+ rm helm-v2.8.2-linux-amd64.tar.gz
+ """
+ }
+
+ withCredentials([file(credentialsId: KUBE_CONFIG, variable: 'KUBECONFIG')]) {
+
+ dir('helm') {
+ //check if charts are valid, and then perform dry run, if successful then upgrade/install charts
+
+ if (PHASES.contains("UNDEPLOY")) {
+ stage 'Undeploy'
+
+ sh """
+ helm delete --tiller-namespace=$TILLER_NAMESPACE --purge $ARTIFACT_ID
+ """
+ }
+
+ //NOTE Double quotes are used below to access groovy variables like artifact_id and tiller_namespace
+ if (PHASES.contains("DEPLOY")) {
+ stage 'Deploy'
+ withCredentials([
+ usernamePassword(credentialsId: OTF_MONGO_DB, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
+ ]) {
+ sh """
+ echo "Validate Yaml"
+ helm lint $ARTIFACT_ID
+
+ echo "View Helm Templates"
+ helm template $ARTIFACT_ID \
+ --set appName=$ARTIFACT_ID \
+ --set version=$VERSION \
+ --set image=$IMAGE_NAME\
+ --set env=$ENV \
+ --set otf.mongo.username=$USERNAME \
+ --set otf.mongo.password=$PASSWORD \
+ --set namespace=$TILLER_NAMESPACE
+
+
+ echo "Perform Dry Run Of Install"
+ helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install --dry-run $ARTIFACT_ID $ARTIFACT_ID \
+ --set appName=$ARTIFACT_ID \
+ --set version=$VERSION \
+ --set image=$IMAGE_NAME\
+ --set env=$ENV \
+ --set otf.mongo.username=$USERNAME \
+ --set otf.mongo.password=$PASSWORD \
+ --set namespace=$TILLER_NAMESPACE
+
+ echo "Helm Install/Upgrade"
+ helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install $ARTIFACT_ID $ARTIFACT_ID \
+ --set appName=$ARTIFACT_ID \
+ --set version=$VERSION \
+ --set image=$IMAGE_NAME\
+ --set env=$ENV \
+ --set otf.mongo.username=$USERNAME \
+ --set otf.mongo.password=$PASSWORD \
+ --set namespace=$TILLER_NAMESPACE
+
+ """
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/LICENSE.txt b/otf-service-api/LICENSE.txt
new file mode 100644
index 0000000..695ac56
--- /dev/null
+++ b/otf-service-api/LICENSE.txt
@@ -0,0 +1,28 @@
+Unless otherwise specified, all software contained herein is licensed
+under the Apache License, Version 2.0 (the "Software License");
+you may not use this software except in compliance with the Software
+License. You may obtain a copy of the Software License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the Software License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the Software License for the specific language governing permissions
+and limitations under the Software License.
+
+
+
+Unless otherwise specified, all documentation contained herein is licensed
+under the Creative Commons License, Attribution 4.0 Intl. (the
+"Documentation License"); you may not use this documentation except in
+compliance with the Documentation License. You may obtain a copy of the
+Documentation License at
+
+https://creativecommons.org/licenses/by/4.0/
+
+Unless required by applicable law or agreed to in writing, documentation
+distributed under the Documentation License is distributed on an "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied. See the Documentation License for the specific language governing
+permissions and limitations under the Documentation License.
diff --git a/otf-service-api/README.txt b/otf-service-api/README.txt
new file mode 100644
index 0000000..b6e4e99
--- /dev/null
+++ b/otf-service-api/README.txt
@@ -0,0 +1,13 @@
+You must setup environment variables to run and test locally
+These environment variables will be secretes when deployed on kubernetes.
+ AAF_ID (mechid for cadi aaf)
+ AAF_PASSWORD (password for mechid)
+ CADI_KEYFILE (cadi keyfile location for aaf)
+
+ Generate AAF_PASSWORD and CADI_KEYFILE:
+ java -jar cadi-core-1.4.2.jar keygen keyfile
+ java -jar cadi-core-1.4.2.jar digest AAF_MECHID_PASSWORD keyfile > digest.txt 2>&1
+
+ AAF_PERM_TYPE (permission type to check for when authorization a user)
+
+
\ No newline at end of file
diff --git a/otf-service-api/docker/Dockerfile b/otf-service-api/docker/Dockerfile
new file mode 100644
index 0000000..e0e9e53
--- /dev/null
+++ b/otf-service-api/docker/Dockerfile
@@ -0,0 +1,43 @@
+FROM openjdk:8
+
+ENV NAMESPACE=namespace
+ENV APP_NAME=otf-service-api
+ENV AAF_PERM_TYPE=type
+ENV AAF_ID=username
+ENV AAF_MECH_PASSWORD=password
+ENV AAF_PASSWORD=password
+ENV CADI_KEYFILE=/opt/secret/keyfile
+ENV CADI_HOSTNAME=localhost
+ENV APP_VERSION=1.0
+ENV OTF_MONGO_HOSTS=localhost:27017
+ENV OTF_MONGO_USERNAME=username
+ENV OTF_MONGO_PASSWORD=password
+ENV OTF_MONGO_REPLICASET=mongoOTF
+ENV OTF_MONGO_DATABASE=otf
+ENV otf.camunda.host=https://localhost
+ENV otf.camunda.port=31313
+ENV otf.camunda.executionUri=otf/tcu/execute-test/v1
+ENV otf.camunda.pollingUri=otf/tcu/process-instance-completion-check/v1
+ENV otf.camunda.deploymentUri=otf/tcu/deploy-test-strategy-zip/v1
+ENV otf.camunda.processDefinitionKeyUri=rest/process-definition/key
+ENV otf.camunda.deploymentDeletionUri=otf/tcu/delete-test-strategy/v1/deployment-id
+ENV otf.camunda.testDefinitionDeletionUri=otf/tcu/delete-test-strategy/v1/test-definition-id
+ENV otf.camunda.uri.execute-test=otf/tcu/execute/workflowRequest
+ENV otf.camunda.uri.process-instance-completion-check=otf/tcu/process-instance-completion-check/v1
+ENV otf.camunda.uri.deploy-test-strategy-zip=otf/tcu/deploy-test-strategy-zip/v1
+ENV otf.camunda.uri.process-definition=rest/process-definition/key
+ENV otf.camunda.uri.delete-test-strategy=otf/tcu/delete-test-strategy/v1/deployment-id
+ENV otf.camunda.uri.delete-test-strategy-test-definition-id=otf/tcu/delete-test-strategy/v1/test-definition-id
+ENV otf.camunda.uri.health=/otf/health/v1
+ENV otf.api.poll-interval=6000
+ENV otf.api.poll-attempts=50
+ENV OTF_CERT_PATH=opt/cert/cert.p12
+ENV OTF_CERT_PASS=password
+
+COPY otf-service-api.jar app.jar
+
+RUN mkdir -p /otf/logs
+
+ADD src src
+
+ENTRYPOINT ["java", "-jar", "app.jar"]
diff --git a/otf-service-api/helm/otf-service-api/Chart.yaml b/otf-service-api/helm/otf-service-api/Chart.yaml
new file mode 100644
index 0000000..7c05894
--- /dev/null
+++ b/otf-service-api/helm/otf-service-api/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v1
+appVersion: "1.0"
+description: A Helm chart the OTF TCU Service API
+name: otf-service-api
+version: 0.0.1-SNAPSHOT
\ No newline at end of file
diff --git a/otf-service-api/helm/otf-service-api/templates/deployment.yaml b/otf-service-api/helm/otf-service-api/templates/deployment.yaml
new file mode 100644
index 0000000..3a406d3
--- /dev/null
+++ b/otf-service-api/helm/otf-service-api/templates/deployment.yaml
@@ -0,0 +1,280 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: {{ .Values.appName}}
+ namespace: {{.Values.namespace}}
+ labels:
+ app: {{ .Values.appName}}
+ version: {{.Values.version}}
+spec:
+ {{if or (eq .Values.env "prod") (eq .Values.env "prod-dr")}}
+ replicas: {{ .Values.replicas.prod}}
+ {{ else if eq .Values.env "st"}}
+ replicas: {{ .Values.replicas.st}}
+ {{ else }}
+ replicas: {{ .Values.replicas.dev}}
+ {{ end }}
+ selector:
+ matchLabels:
+ app: {{ .Values.appName}}
+ version: {{.Values.version}}
+ template:
+ metadata:
+ labels:
+ app: {{ .Values.appName}}
+ version: {{.Values.version}}
+ spec:
+ revisionHistoryLimit: 1 # keep one replica set to allow rollback
+ minReadySeconds: 10
+ strategy:
+ # indicate which strategy we want for rolling update
+ type: RollingUpdate
+ rollingUpdate:
+ maxSurge: 1
+ maxUnavailable: 1
+ serviceAccount: default
+ volumes:
+ - name: {{ .Values.appName}}-aaf-volume
+ secret:
+ secretName: {{.Values.sharedSecret}}
+ - name: {{ .Values.appName}}-keyfile-volume
+ secret:
+ secretName: {{.Values.sharedSecret}}
+ optional: true
+ items:
+ - key: cadi_keyfile
+ path: keyfile
+ - name: {{ .Values.appName}}-cert-volume
+ secret:
+ secretName: {{.Values.sharedCert}}
+ optional: true
+ items:
+ - key: PKCS12_CERT
+ {{if or (eq .Values.env "prod") (eq .Values.env "prod-dr")}}
+ path: {{ .Values.cert.prod.name | quote }}
+ {{ else if eq .Values.env "st" }}
+ path: {{ .Values.cert.st.name | quote }}
+ {{ else }}
+ path: {{ .Values.cert.dev.name | quote }}
+ {{ end }}
+ {{ if or (eq .Values.env "st") (eq .Values.env "prod-dr")}}
+ {{else}}
+ - name: logging-pvc
+ persistentVolumeClaim:
+ {{if eq .Values.env "prod"}}
+ claimName: {{ .Values.pvc.prod | quote }}
+ {{ else }}
+ claimName: {{ .Values.pvc.dev | quote }}
+ {{ end }}
+ {{end}}
+ containers:
+ - name: {{ .Values.appName}}
+ image: {{ .Values.image}}
+ imagePullPolicy: Always
+ ports:
+ - name: https
+ containerPort: 8443
+ nodePort: {{.Values.nodePort}}
+ protocol: TCP
+ {{ if eq .Values.env "st"}}
+ resources:
+ limits:
+ memory: "3Gi"
+ cpu: "1.8"
+ requests:
+ memory: "2Gi"
+ cpu: "1"
+ {{else}}
+ resources:
+ limits:
+ memory: "6Gi"
+ cpu: "4"
+ requests:
+ memory: "2Gi"
+ cpu: "1.5"
+ {{ end }}
+ env:
+ - name: NAMESPACE
+ value: {{.Values.namespace}}
+ - name: APP_NAME
+ value: {{ .Values.appName}}
+ - name: AAF_PERM_TYPE
+ {{if or (eq .Values.env "prod") (eq .Values.env "prod-dr")}}
+ value: {{ .Values.aafPermType.prod | quote }}
+ {{ else if eq .Values.env "st"}}
+ value: {{ .Values.aafPermType.st | quote }}
+ {{ else }}
+ value: {{ .Values.aafPermType.dev | quote }}
+ {{ end }}
+ - name: AAF_ID
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.sharedSecret}}
+ key: aaf_id
+ optional: true
+ - name: AAF_MECH_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.sharedSecret}}
+ key: aaf_mech_password
+ optional: true
+ - name: AAF_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.sharedSecret}}
+ key: aaf_password
+ optional: true
+ - name: CADI_KEYFILE
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.sharedSecret}}
+ key: keyfile_secret_path
+ optional: true
+ - name: CADI_HOSTNAME
+ {{if eq .Values.env "prod"}}
+ value: {{ .Values.cadiHostname.prod | quote }}
+ {{else if eq .Values.env "prod-dr"}}
+ value: {{ .Values.cadiHostname.prod_dr | quote }}
+ {{else if eq .Values.env "st"}}
+ value: {{ .Values.cadiHostname.st | quote }}
+ {{ else }}
+ value: {{ .Values.cadiHostname.dev | quote }}
+ {{ end }}
+ - name: APP_VERSION
+ value: {{.Values.version}}
+ - name: OTF_MONGO_HOSTS
+ {{if or (eq .Values.env "prod") (eq .Values.env "prod-dr")}}
+ value: {{ .Values.otf.mongo.prod.host | quote }}
+ {{ else if eq .Values.env "st" }}
+ value: {{ .Values.otf.mongo.st.host | quote }}
+ {{ else }}
+ value: {{ .Values.otf.mongo.dev.host | quote }}
+ {{ end }}
+ - name: OTF_MONGO_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.appName}}
+ key: mongo_username
+ optional: true
+ - name: OTF_MONGO_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.appName}}
+ key: mongo_password
+ optional: true
+ - name: OTF_MONGO_REPLICASET
+ {{if or (eq .Values.env "prod") (eq .Values.env "prod-dr")}}
+ value: {{ .Values.otf.mongo.prod.replicaSet | quote }}
+ {{else if eq .Values.env "st"}}
+ value: {{ .Values.otf.mongo.st.replicaSet | quote }}
+ {{ else }}
+ value: {{ .Values.otf.mongo.dev.replicaSet | quote }}
+ {{ end }}
+ - name: OTF_MONGO_DATABASE
+ {{if or (eq .Values.env "prod") (eq .Values.env "prod-dr")}}
+ value: {{ .Values.otf.mongo.prod.database | quote }}
+ {{else if eq .Values.env "st"}}
+ value: {{ .Values.otf.mongo.st.database | quote }}
+ {{ else }}
+ value: {{ .Values.otf.mongo.dev.database | quote }}
+ {{ end }}
+ - name: otf.camunda.host
+ {{if eq .Values.env "prod"}}
+ value: {{ .Values.otf.camunda.prod.host | quote }}
+ {{ else if eq .Values.env "prod-dr" }}
+ value: {{ .Values.otf.camunda.prod_dr.host | quote }}
+ {{ else if eq .Values.env "st" }}
+ value: {{ .Values.otf.camunda.st.host | quote }}
+ {{ else }}
+ value: {{ .Values.otf.camunda.dev.host | quote }}
+ {{ end }}
+ - name: otf.camunda.port
+ {{if eq .Values.env "prod"}}
+ value: {{ .Values.otf.camunda.prod.port | quote }}
+ {{ else if eq .Values.env "prod-dr" }}
+ value: {{ .Values.otf.camunda.prod_dr.port | quote }}
+ {{ else if eq .Values.env "st"}}
+ value: {{ .Values.otf.camunda.st.port | quote }}
+ {{ else }}
+ value: {{ .Values.otf.camunda.dev.port | quote }}
+ {{ end }}
+ - name: otf.camunda.executionUri
+ value: {{.Values.otf.camunda.executionUri | quote }}
+ - name: otf.camunda.pollingUri
+ value: {{.Values.otf.camunda.pollingUri | quote }}
+ - name: otf.camunda.deploymentUri
+ value: {{.Values.otf.camunda.deploymentUri | quote }}
+ - name: otf.camunda.processDefinitionKeyUri
+ value: {{.Values.otf.camunda.processDefinitionKeyUri | quote }}
+ - name: otf.camunda.deploymentDeletionUri
+ value: {{.Values.otf.camunda.deploymentDeletionUri | quote }}
+ - name: otf.camunda.testDefinitionDeletionUri
+ value: {{.Values.otf.camunda.testDefinitionDeletionUri | quote }}
+
+ - name: otf.camunda.uri.execute-test
+ value: {{.Values.otf.camunda.uri.execute_test | quote }}
+ - name: otf.camunda.uri.process-instance-completion-check
+ value: {{.Values.otf.camunda.uri.process_instance_completion_check | quote }}
+ - name: otf.camunda.uri.deploy-test-strategy-zip
+ value: {{.Values.otf.camunda.uri.deploy_test_strategy_zip | quote }}
+ - name: otf.camunda.uri.process-definition
+ value: {{.Values.otf.camunda.uri.process_definition | quote }}
+ - name: otf.camunda.uri.delete-test-strategy
+ value: {{.Values.otf.camunda.uri.delete_test_strategy | quote }}
+ - name: otf.camunda.uri.delete-test-strategy-test-definition-id
+ value: {{.Values.otf.camunda.uri.delete_test_strategy_test_definition_id | quote }}
+ - name: otf.camunda.uri.health
+ value: {{.Values.otf.camunda.uri.health | quote }}
+
+ - name: otf.api.poll-interval
+ value: {{.Values.otf.api.poll_interval | quote}}
+ - name: otf.api.poll-attempts
+ value: {{.Values.otf.api.poll_attempts | quote}}
+
+ - name: OTF_CERT_PATH
+ {{if or (eq .Values.env "prod") (eq .Values.env "prod-dr")}}
+ value: {{ .Values.cert.prod.path | quote }}
+ {{ else if eq .Values.env "st"}}
+ value: {{ .Values.cert.st.path | quote }}
+ {{ else }}
+ value: {{ .Values.cert.dev.path | quote }}
+ {{ end }}
+ - name: OTF_CERT_PASS
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.sharedCert}}
+ key: PKCS12_KEY
+ optional: true
+ volumeMounts:
+ - name: {{.Values.appName}}-keyfile-volume
+ mountPath: /opt/secret
+ - name: {{.Values.appName}}-cert-volume
+ mountPath: /opt/cert
+ {{ if or (eq .Values.env "st") (eq .Values.env "prod-dr")}}
+ {{else}}
+ - name: logging-pvc
+ mountPath: "/otf/logs"
+ {{end}}
+ livenessProbe:
+ httpGet:
+ path: /otf/api/health/v1
+ port: https
+ scheme: HTTPS
+ httpHeaders:
+ - name: X-Custom-Header
+ value: Alive
+ initialDelaySeconds: 30
+ timeoutSeconds: 30
+ periodSeconds: 30
+ readinessProbe:
+ httpGet:
+ path: /otf/api/health/v1
+ port: https
+ scheme: HTTPS
+ httpHeaders:
+ - name: X-Custom-Header
+ value: Ready
+ initialDelaySeconds: 30
+ timeoutSeconds: 30
+ periodSeconds: 30
+ restartPolicy: Always
diff --git a/otf-service-api/helm/otf-service-api/templates/secret.yaml b/otf-service-api/helm/otf-service-api/templates/secret.yaml
new file mode 100644
index 0000000..bc77345
--- /dev/null
+++ b/otf-service-api/helm/otf-service-api/templates/secret.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ .Values.appName}}
+type: Opaque
+data:
+ mongo_username: {{ .Values.otf.mongo.username | b64enc}}
+ mongo_password: {{ .Values.otf.mongo.password | b64enc}}
\ No newline at end of file
diff --git a/otf-service-api/helm/otf-service-api/templates/service.yaml b/otf-service-api/helm/otf-service-api/templates/service.yaml
new file mode 100644
index 0000000..38acf3d
--- /dev/null
+++ b/otf-service-api/helm/otf-service-api/templates/service.yaml
@@ -0,0 +1,18 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ .Values.appName }}
+ namespace: {{ .Values.namespace}}
+ labels:
+ app: {{ .Values.appName }}
+ version: {{ .Values.version}}
+spec:
+ type: NodePort
+ ports:
+ - name: https
+ port: 8443
+ protocol: TCP
+ nodePort: {{ .Values.nodePort}}
+ selector:
+ app: {{ .Values.appName }}
+ version: {{ .Values.version}}
diff --git a/otf-service-api/helm/otf-service-api/values.yaml b/otf-service-api/helm/otf-service-api/values.yaml
new file mode 100644
index 0000000..49ee641
--- /dev/null
+++ b/otf-service-api/helm/otf-service-api/values.yaml
@@ -0,0 +1,89 @@
+appName: otf-service-api
+version: 0.0.1-SNAPSHOT
+image: otf-service-api:0.0.1-SNAPSHOT
+namespace: org-oran-otf
+nodePort: 32303
+replicas:
+ dev: 2
+ st: 1
+ prod: 2
+env: dev
+# Environment variables for the service api.
+otf:
+ mongo:
+ dev:
+ host: localhost:27017,localhost:27017,localhost:27017
+ replicaSet: mongoOTF
+ database: otf
+ st:
+ host: localhost:27017,localhost:27017,localhost:27017
+ replicaSet: mongoOTF
+ database: otf_st
+ prod:
+ host: localhost:18720,localhost:18720,localhost:18720
+ replicaSet: otf-rs-prod2
+ database: otf
+ username: "!"
+ password: "!"
+ camunda:
+ dev:
+ host: https://localhost
+ port: 31313
+ st:
+ host: https://localhost
+ port: 31313
+ prod:
+ host: https://localhost
+ port: 31313
+ prod_dr:
+ host: https://localhost
+ port: 31313
+ uri:
+ process_definition: rest/process-definition/key
+ delete_test_strategy: otf/tcu/delete-test-strategy/v1/deployment-id
+ delete_test_strategy_test_definition_id: otf/tcu/delete-test-strategy/v1/test-definition-id
+ execute_test: otf/tcu/execute/workflowRequest
+ deploy_test_strategy_zip: otf/tcu/deploy-test-strategy-zip/v1
+ process_instance_completion_check: otf/tcu/process-instance-completion-check/v1
+ health: /otf/health/v1
+ executionUri: otf/tcu/execute-test/v1
+ pollingUri: otf/tcu/process-instance-completion-check/v1
+ deploymentUri: otf/tcu/deploy-test-strategy-zip/v1
+ processDefinitionKeyUri: rest/process-definition/key
+ deploymentDeletionUri: otf/tcu/delete-test-strategy/v1/deployment-id
+ testDefinitionDeletionUri: otf/tcu/delete-test-strategy/v1/test-definition-id
+ api:
+ poll_interval: 6000
+ poll_attempts: 50
+
+# permission type for aaf
+aafPermType:
+ dev: org.oran.otf.svcapi
+ st: org.oran.otf.st.svcapi
+ prod: org.oran.otf.prod.svcapi
+
+cadiHostname:
+ dev: localhost
+ st: localhost
+ prod: localhost
+ prod_dr: localhost
+
+# Secret related information.
+sharedSecret: otf-aaf-credential-generator
+sharedCert: otf-cert-secret-builder
+cert:
+ dev:
+ name: otf_dev.p12
+ path: opt/cert/otf_dev.p12
+ st:
+ name: otf_st.p12
+ path: opt/cert/otf_st.p12
+ prod:
+ name: otf_prod.p12
+ path: opt/cert/otf_prod.p12
+
+pvc:
+ dev: org-oran-otf-dev-logs-pv
+ prod: org-oran-otf-prod-logs-pv
+
+
diff --git a/otf-service-api/pom.xml b/otf-service-api/pom.xml
new file mode 100644
index 0000000..fda9ed3
--- /dev/null
+++ b/otf-service-api/pom.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <artifactId>otf-service-api</artifactId>
+ <build>
+ <finalName>otf-service-api</finalName>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ <groupId>org.apache.maven.plugins</groupId>
+ </plugin>
+ <plugin>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ </plugin>
+ <plugin>
+ <artifactId>swagger-maven-plugin</artifactId>
+ <configuration>
+ <outputFileName>openapi</outputFileName>
+ <!--<outputPath>${project.build.directory}/generatedtest</outputPath>-->
+ <outputFormat>JSONANDYAML</outputFormat>
+ <prettyPrint>true</prettyPrint>
+ <resourcePackages>
+ <package>org.oran.otf.api</package>
+ </resourcePackages>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>resolve</goal>
+ </goals>
+ <phase>compile</phase>
+ </execution>
+ </executions>
+ <groupId>io.swagger.core.v3</groupId>
+ <version>2.0.7</version>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.1</version>
+ <configuration>
+ <skipTests>${skipUTs}</skipTests>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.22.1</version>
+ <executions>
+ <execution>
+ <id>run-integration-tests</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <skipTests>${skipTests}</skipTests>
+ <skipITs>${skipITs}</skipITs>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <excludes>
+ <exclude>otf_dev.p12</exclude>
+ </excludes>
+ <filtering>true</filtering>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ <targetPath>${basedir}/target/src/main/resources</targetPath>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ <excludes>
+ <exclude>otf_dev.p12</exclude>
+ </excludes>
+ <filtering>true</filtering>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ <includes>
+ <include>otf_dev.p12</include>
+ </includes>
+ <targetPath>${basedir}/target/src/main/resources</targetPath>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ <includes>
+ <include>otf_dev.p12</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>docker</directory>
+ <includes>
+ <include>Dockerfile</include>
+ </includes>
+ <targetPath>${basedir}/target</targetPath>
+ </resource>
+ </resources>
+ </build>
+ <dependencies>
+ <dependency>
+ <artifactId>spring-boot-starter</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ </dependency>
+
+ <dependency>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ </dependency>
+
+ <dependency>
+ <artifactId>spring-boot-starter-jersey</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>de.flapdoodle.embed</groupId>
+ <artifactId>de.flapdoodle.embed.mongo</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.github.tomakehurst</groupId>
+ <artifactId>wiremock-jre8</artifactId>
+ <version>2.24.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>2.15.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-inline</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <version>4.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured-all</artifactId>
+ <version>4.0.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+
+ <dependency>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>com.vaadin.external.google</groupId>
+ <artifactId>android-json</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <artifactId>spring-boot-starter-data-mongodb</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ </dependency>
+
+ <dependency>
+ <artifactId>swagger-jaxrs2</artifactId>
+ <groupId>io.swagger.core.v3</groupId>
+ <version>2.0.7</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
+ <groupId>io.swagger.core.v3</groupId>
+ <version>2.0.7</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>swagger-annotations</artifactId>
+ <groupId>io.swagger.core.v3</groupId>
+ <version>2.0.7</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>springfox-swagger2</artifactId>
+ <groupId>io.springfox</groupId>
+ <version>2.9.2</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>springfox-swagger-ui</artifactId>
+ <groupId>io.springfox</groupId>
+ <version>2.9.2</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>springfox-bean-validators</artifactId>
+ <groupId>io.springfox</groupId>
+ <version>2.9.2</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>httpclient</artifactId>
+ <groupId>org.apache.httpcomponents</groupId>
+ </dependency>
+
+ <dependency>
+ <artifactId>h2</artifactId>
+ <groupId>com.h2database</groupId>
+ </dependency>
+
+<!-- <dependency>-->
+<!-- <artifactId>wiremock</artifactId>-->
+<!-- <groupId>com.github.tomakehurst</groupId>-->
+<!-- <version>1.58</version>-->
+<!-- </dependency>-->
+
+ <dependency>
+ <artifactId>gson</artifactId>
+ <groupId>com.google.code.gson</groupId>
+ <version>2.8.5</version>
+ </dependency>
+
+ <!-- CADI AAF Dependencies !! -->
+ <dependency>
+ <artifactId>aaf-auth-client</artifactId>
+ <groupId>org.onap.aaf.authz</groupId>
+ <version>${cadi.version}</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>aaf-cadi-core</artifactId>
+ <groupId>org.onap.aaf.authz</groupId>
+ <version>${cadi.version}</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>aaf-cadi-aaf</artifactId>
+ <groupId>org.onap.aaf.authz</groupId>
+ <version>${cadi.version}</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>json</artifactId>
+ <groupId>org.json</groupId>
+ <version>20180813</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>jackson-annotations</artifactId>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ </dependency>
+
+ <dependency>
+ <artifactId>jackson-core</artifactId>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ </dependency>
+
+ <dependency>
+ <artifactId>jackson-databind</artifactId>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ </dependency>
+
+ <dependency>
+ <artifactId>jersey-media-multipart</artifactId>
+ <groupId>org.glassfish.jersey.media</groupId>
+ <version>2.27</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>httpmime</artifactId>
+ <groupId>org.apache.httpcomponents</groupId>
+ <version>4.5.7-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <artifactId>httpasyncclient</artifactId>
+ <groupId>org.apache.httpcomponents</groupId>
+ <version>4.1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna-platform</artifactId>
+ </dependency>
+ </dependencies>
+
+ <description>Service API - OTF</description>
+ <groupId>org.oran.otf</groupId>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <name>otf-service-api</name>
+
+ <packaging>jar</packaging>
+
+ <parent>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ <version>2.1.3.RELEASE</version>
+ </parent>
+
+ <properties>
+ <skipTests>false</skipTests>
+ <skipITs>${skipTests}</skipITs>
+ <skipUTs>${skipTests}</skipUTs>
+ <cadi.version>2.1.10</cadi.version>
+ <docker.registry>registry.hub.docker.io</docker.registry>
+ <java.version>1.8</java.version>
+ <namespace>org.oran.otf</namespace>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ </properties>
+ <version>Camille.1.0</version>
+
+
+</project>
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/Application.java b/otf-service-api/src/main/java/org/oran/otf/api/Application.java
new file mode 100644
index 0000000..8836555
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/Application.java
@@ -0,0 +1,74 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api;
+
+import static com.google.common.collect.Sets.newHashSet;
+
+import io.swagger.v3.oas.annotations.OpenAPIDefinition;
+import io.swagger.v3.oas.annotations.info.Contact;
+import io.swagger.v3.oas.annotations.info.Info;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@SpringBootApplication
+@Configuration
+@EnableAutoConfiguration(
+ exclude = {
+ ErrorMvcAutoConfiguration.class,
+ DataSourceAutoConfiguration.class,
+ HibernateJpaAutoConfiguration.class,
+ })
+@ComponentScan(basePackages = "org.oran.otf")
+@EnableSwagger2
+@OpenAPIDefinition(
+ info =
+ @Info(
+ title = "Open Test Framework API",
+ version = "1.0",
+ description = "A RESTful API used to communicate with the OTF test control unit.",
+ contact = @Contact(url = "https://localhost:32524", name = "OTF")))
+public class Application {
+ private static final Log log = LogFactory.getLog(Application.class);
+
+ public static void main(String[] args) {
+ ApplicationContext ctx = SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ public Docket testInstanceApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .select()
+ // .apis(testInstancePath())
+ .paths(PathSelectors.any())
+ .build()
+ .protocols(newHashSet("https"));
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/Utilities.java b/otf-service-api/src/main/java/org/oran/otf/api/Utilities.java
new file mode 100644
index 0000000..1279688
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/Utilities.java
@@ -0,0 +1,394 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api;
+
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.repository.UserRepository;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.bson.types.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public class Utilities {
+
+ public static JsonObject parseJson(String str) {
+ try {
+ return new JsonParser().parse(str).getAsJsonObject();
+ } catch (JsonParseException jpe) {
+ logger.error("Cannot parse string as Json.");
+ return null;
+ }
+ }
+
+ public static class Http {
+ public static class BuildResponse {
+ public static Response badRequest() {
+ return Response.status(400).build();
+ }
+
+ public static Response badRequestWithMessage(String msg) {
+ return Response.status(400)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(400, msg))
+ .build();
+ }
+
+ public static Response internalServerError() {
+ return Response.status(500).build();
+ }
+
+ public static Response internalServerErrorWithMessage(String msg) {
+ return Response.status(500)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(500, msg))
+ .build();
+ }
+
+ public static Response unauthorized() {
+ return Response.status(401).build();
+ }
+
+ public static Response unauthorizedWithMessage(String msg) {
+ return Response.status(401)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(401, msg))
+ .build();
+ }
+ }
+
+ public static HttpResponse httpPostJsonUsingAAF(String url, String body) throws Exception {
+ HttpResponse response = null;
+
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpPost post = new HttpPost(url);
+ post.setHeader("Content-Type", MediaType.APPLICATION_JSON);
+ post.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+ post.setEntity(new StringEntity(body));
+
+ HttpClient client =
+ HttpClientBuilder.create()
+ .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
+ .build();
+ response = client.execute(post);
+
+ // logger.info(String.format("[POST:%s]\n %s", url, body));
+
+ return response;
+ }
+
+ public static HttpResponse httpDeleteAAF(String url) {
+ HttpResponse response = null;
+
+ try {
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpDelete delete = new HttpDelete(url);
+ delete.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+ HttpClient client =
+ HttpClientBuilder.create()
+ .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
+ .build();
+ response = client.execute(delete);
+
+ // logger.info(String.format("[DELETE:%s]\n", url));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return response;
+ }
+
+ public static HttpResponse httpPostXmlUsingAAF(String url, String body) {
+ HttpResponse response = null;
+
+ try {
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpPost post = new HttpPost(url);
+ post.setHeader("Content-Type", MediaType.APPLICATION_JSON);
+ post.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+ post.setEntity(new StringEntity(body));
+
+ List<NameValuePair> urlParameters = Arrays.asList(new BasicNameValuePair("xml", body));
+ post.setEntity(new UrlEncodedFormEntity(urlParameters));
+
+ HttpClient client = HttpClientBuilder.create().build();
+ response = client.execute(post);
+
+ logger.info(String.format("[POST:%s]\n %s", url, body));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return response;
+ }
+
+ public static HttpResponse httpGetUsingAAF(String url) {
+ HttpResponse response = null;
+
+ try {
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpGet get = new HttpGet(url);
+ get.setHeader("Content-Type", "application/json");
+ get.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+
+ HttpClient client =
+ HttpClientBuilder.create()
+ .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
+ .build();
+ response = client.execute(get);
+
+ logger.info(String.format("[GET:%s]", url));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return response;
+ }
+ }
+
+ public static class Camunda {
+
+ public static boolean isCamundaOnline() {
+ final String healthUrl =
+ String.format(
+ "%s:%s/%s",
+ System.getenv("otf.camunda.host"),
+ System.getenv("otf.camunda.port"),
+ System.getenv("otf.camunda.uri.health"));
+
+ HttpResponse res = Utilities.Http.httpGetUsingAAF(healthUrl);
+ return res != null && res.getStatusLine().getStatusCode() == 200;
+ }
+
+ public static JsonObject processInstanceStatus(String executionId) {
+ // Read necessary environment variables - Avoiding using Spring dependencies (@Value)
+ String host = System.getenv("otf.camunda.host");
+ String path = System.getenv("otf.camunda.uri.process-instance-completion-check");
+ int port = Utilities.TryGetEnvironmentVariable("otf.camunda.port");
+
+ if (!Utilities.isHostValid(host)) {
+ logger.error("Host (%s) must use either the http or https protocol.", host);
+ return null;
+ }
+
+ if (!Utilities.isPortValid(port)) {
+ logger.error(
+ "Invalid port (%s) specified as environment variable 'otf.camunda.port'.",
+ System.getenv("otf.camunda.port"));
+ return null;
+ }
+ try {
+ String getUrl = String.format("%s:%s/%s/%s", host, port, path, executionId);
+ HttpResponse response = Utilities.Http.httpGetUsingAAF(getUrl);
+ HttpEntity entity = response.getEntity();
+ String result = EntityUtils.toString(entity);
+
+ return parseJson(result);
+ } catch (IOException ioe) {
+ Utilities.printStackTrace(ioe, Utilities.LogLevel.ERROR);
+ logger.error("Cannot convert http entity to String.");
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, Utilities.LogLevel.ERROR);
+ }
+ // conversion was unsuccessful
+ return null;
+ }
+ }
+
+ private static final Logger logger = LoggerFactory.getLogger(Utilities.class);
+
+ public static void printStackTrace(Exception exception, LogLevel logLevel) {
+ String stackTrace = getStackTrace(exception);
+
+ switch (logLevel) {
+ case INFO:
+ logger.info(stackTrace);
+ break;
+ case WARN:
+ logger.warn(stackTrace);
+ break;
+ case DEBUG:
+ logger.debug(stackTrace);
+ break;
+ case ERROR:
+ logger.error(stackTrace);
+ break;
+ }
+ }
+
+ public static int TryGetEnvironmentVariable(String variable) {
+ String value = System.getenv(variable);
+ int result = 0x80000000;
+
+ try {
+ result = Integer.parseInt(value);
+ } catch (NumberFormatException error) {
+ error.printStackTrace();
+ logger.error(error.getMessage());
+ }
+
+ return result;
+ }
+
+ public static String getStackTrace(Exception exception) {
+ StringWriter stringWriter = new StringWriter();
+ exception.printStackTrace(new PrintWriter(stringWriter));
+ return stringWriter.toString();
+ }
+
+ public static boolean isObjectIdValid(String input) {
+ ObjectId id = null;
+ try {
+ id = new ObjectId(input); // check if an ObjectId can be created from the string
+ if (id.toString().equalsIgnoreCase(input)) return true;
+ logger.warn("The input string does not have the same value as it's string representation.");
+ } catch (IllegalArgumentException e) {
+ logger.error(String.format("An ObjectId cannot be instantiated from the string: %s", input));
+ }
+
+ return false;
+ }
+
+ public static boolean isPortValid(int port) {
+ return (port >= 0 && port <= 65535);
+ }
+
+ public static boolean isHostValid(String host) {
+ return host.startsWith("http");
+ }
+
+ public static <T> boolean identifierExistsInCollection(
+ MongoRepository<T, String> repository, ObjectId identifier) {
+ return repository.findById(identifier.toString()).isPresent();
+ }
+
+ public static <T> T findByIdGeneric(MongoRepository<T, String> repository, ObjectId identifier) {
+ Optional<T> optionalObj = repository.findById(identifier.toString());
+ return optionalObj.orElse(null);
+ }
+
+ public static String[] decodeBase64AuthorizationHeader(String encodedHeader) {
+ try {
+ byte[] decodedAuthorization = Base64.getDecoder().decode(encodedHeader.replace("Basic ", ""));
+ String credentials = new String(decodedAuthorization);
+ return credentials.split(":");
+ } catch (Exception e) {
+ logger.error("Unable to decode authorization header: " + encodedHeader);
+ return null;
+ }
+ }
+
+ public static User findUserByMechanizedId(String mechanizedId, UserRepository userRepository) {
+ Optional<User> optionalUser = userRepository.findFirstByEmail(mechanizedId);
+ return optionalUser.orElse(null);
+ }
+
+ public static User findUserByAuthHeader(String authorization, UserRepository userRepository) {
+ try {
+ if (Strings.isNullOrEmpty(authorization)) {
+ return null;
+ }
+ String[] credentials = Utilities.decodeBase64AuthorizationHeader(authorization);
+ return findUserByMechanizedId(credentials[0], userRepository);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static <T> T resolveOptional(Optional<T> optional) {
+ return optional.orElse(null);
+ }
+
+ public static <T> T mapRequest(Class<T> targetType, String input) {
+ logger.info(targetType.getName());
+
+ ObjectMapper mapper =
+ new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ try {
+ return mapper.readValue(input, targetType);
+ } catch (IOException e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return null;
+ }
+ }
+
+ public enum LogLevel {
+ WARN,
+ DEBUG,
+ INFO,
+ ERROR
+ }
+
+ public static Date getCurrentDate() {
+ return new Date(System.currentTimeMillis());
+ }
+
+ public static Map<String, Object> replaceObjectId(Map<String, Object> map, String objectIdKey) {
+ if (map.containsKey(objectIdKey)) {
+ ObjectId id = (ObjectId) map.get(objectIdKey);
+ map.replace(objectIdKey, id.toString());
+ }
+
+ return map;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/CadiFilterConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/CadiFilterConfiguration.java
new file mode 100644
index 0000000..d98b9ed
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/CadiFilterConfiguration.java
@@ -0,0 +1,119 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import javax.servlet.Filter;
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.filter.CadiFilter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+@PropertySource("classpath:application.properties")
+@Component
+@ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true",matchIfMissing = true)
+public class CadiFilterConfiguration {
+
+ @Value("${aaf.call-timeout}")
+ private String AAF_CALL_TIMEOUT;
+
+ @Value("${aaf.conn-timeout}")
+ private String AAF_CONN_TIMEOUT;
+
+ @Value("${aaf.default-realm}")
+ private String AAF_DEFAULT_REALM;
+
+ @Value("${aaf.env}")
+ private String AAF_ENV;
+
+ @Value("${aaf.locate-url}")
+ private String AAF_LOCATE_URL;
+
+ @Value("${aaf.lur-class}")
+ private String AAF_LUR_CLASS;
+
+ @Value("${aaf.url}")
+ private String AAF_URL;
+
+ @Value("${basic-realm}")
+ private String BASIC_REALM;
+
+ @Value("${basic-warn}")
+ private String BASIC_WARN;
+
+ @Value("${cadi-latitude}")
+ private String CADI_LATITUDE;
+
+ @Value("${cadi-longitude}")
+ private String CADI_LONGITUDE;
+
+ @Value("${cadi-protocols}")
+ private String CADI_PROTOCOLS;
+
+ @Value("${cadi-noauthn}")
+ private String CADI_NOAUTHN;
+
+ @Bean(name = "cadiFilterRegistrationBean")
+ @ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true",matchIfMissing = true)
+ public FilterRegistrationBean<Filter> cadiFilterRegistration() {
+ FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
+ // set cadi configuration properties
+ initCadiProperties(registration);
+
+ registration.addUrlPatterns("/otf/api/testInstance/*", "/otf/api/testExecution/*", "/otf/api/testStrategy/*", "/otf/api/virtualTestHead/*");
+ registration.setFilter(cadiFilter());
+ registration.setName("otfCadiFilter");
+ registration.setOrder(0);
+ return registration;
+ }
+
+ public Filter cadiFilter() {
+ return new CadiFilter();
+ }
+
+ private void initCadiProperties(FilterRegistrationBean<Filter> registration) {
+ registration.addInitParameter(Config.AAF_APPID, System.getenv("AAF_ID"));
+ registration.addInitParameter(Config.AAF_APPPASS, System.getenv("AAF_PASSWORD"));
+ registration.addInitParameter(Config.AAF_CALL_TIMEOUT, AAF_CALL_TIMEOUT);
+ registration.addInitParameter(Config.AAF_CONN_TIMEOUT, AAF_CONN_TIMEOUT);
+ registration.addInitParameter(Config.AAF_DEFAULT_REALM, AAF_DEFAULT_REALM);
+ registration.addInitParameter(Config.AAF_ENV, AAF_ENV);
+ registration.addInitParameter(Config.AAF_LOCATE_URL, AAF_LOCATE_URL);
+ registration.addInitParameter(Config.AAF_LUR_CLASS, AAF_LUR_CLASS);
+ registration.addInitParameter(
+ Config.AAF_URL, AAF_URL);
+
+ registration.addInitParameter(Config.BASIC_REALM, BASIC_REALM);
+ registration.addInitParameter(Config.BASIC_WARN, BASIC_WARN);
+
+ registration.addInitParameter(Config.CADI_KEYFILE, System.getenv("CADI_KEYFILE"));
+ registration.addInitParameter(Config.CADI_LATITUDE, CADI_LATITUDE);
+ //registration.addInitParameter(Config.CADI_LOGLEVEL, Access.Level.DEBUG.name());
+ registration.addInitParameter(Config.CADI_LONGITUDE, CADI_LONGITUDE);
+ registration.addInitParameter(Config.CADI_NOAUTHN, CADI_NOAUTHN);
+ registration.addInitParameter(Config.CADI_PROTOCOLS, CADI_PROTOCOLS);
+ registration.addInitParameter(Config.CADI_KEYSTORE, System.getenv("OTF_CERT_PATH"));
+ registration.addInitParameter(Config.CADI_KEYSTORE_PASSWORD, System.getenv("OTF_CERT_PASS"));
+
+ registration.addInitParameter(Config.HOSTNAME, System.getenv("CADI_HOSTNAME"));
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/CombinedResourceProvider.java b/otf-service-api/src/main/java/org/oran/otf/api/config/CombinedResourceProvider.java
new file mode 100644
index 0000000..ef7fae5
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/CombinedResourceProvider.java
@@ -0,0 +1,46 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider;
+import springfox.documentation.swagger.web.SwaggerResource;
+import springfox.documentation.swagger.web.SwaggerResourcesProvider;
+
+@Component
+@Primary
+public class CombinedResourceProvider implements SwaggerResourcesProvider {
+
+ @Resource private InMemorySwaggerResourcesProvider inMemorySwaggerResourcesProvider;
+
+ public List<SwaggerResource> get() {
+
+ SwaggerResource jerseySwaggerResource = new SwaggerResource();
+ jerseySwaggerResource.setLocation("/otf/api/openapi.json");
+ jerseySwaggerResource.setSwaggerVersion("2.0");
+ jerseySwaggerResource.setName("Service API");
+
+ return Stream.concat(
+ Stream.of(jerseySwaggerResource), inMemorySwaggerResourcesProvider.get().stream())
+ .collect(Collectors.toList());
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/DataConfig.java b/otf-service-api/src/main/java/org/oran/otf/api/config/DataConfig.java
new file mode 100644
index 0000000..0546a7d
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/DataConfig.java
@@ -0,0 +1,83 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import java.util.ArrayList;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+@Configuration
+@EnableMongoRepositories(basePackages = "org.oran.otf.common.repository")
+@Profile("!test")
+public class DataConfig extends AbstractMongoConfiguration {
+
+ @Value("${otf.mongo.hosts}")
+ private String hosts;
+
+ @Value("${otf.mongo.username}")
+ private String username;
+
+ @Value("${otf.mongo.password}")
+ private String password;
+
+ @Value("${otf.mongo.replicaSet}")
+ private String replicaSet;
+
+ @Value("${otf.mongo.database}")
+ private String database;
+
+ public DataConfig() {}
+
+ @Override
+ protected String getDatabaseName() {
+ return database;
+ }
+
+ @Override
+ public MongoClient mongoClient() {
+ MongoCredential credential =
+ MongoCredential.createScramSha1Credential(username, database, password.toCharArray());
+
+ MongoClientOptions options =
+ MongoClientOptions.builder().sslEnabled(false).requiredReplicaSetName(replicaSet).build();
+
+ String[] hostArray = hosts.split(",");
+ ArrayList<ServerAddress> hosts = new ArrayList<>();
+
+ for (String host : hostArray) {
+ String[] hostSplit = host.split(":");
+ hosts.add(new ServerAddress(hostSplit[0], Integer.parseInt(hostSplit[1])));
+ }
+
+ return new MongoClient(hosts, credential, options);
+ }
+
+ @Override
+ @Bean
+ public MongoTemplate mongoTemplate() {
+ return new MongoTemplate(mongoClient(), database);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/HttpSecurityConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/HttpSecurityConfiguration.java
new file mode 100644
index 0000000..2646431
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/HttpSecurityConfiguration.java
@@ -0,0 +1,68 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.connector.Connector;
+import org.apache.tomcat.util.descriptor.web.SecurityCollection;
+import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties
+public class HttpSecurityConfiguration {
+ @Value("${server.port.http}")
+ private int httpPort;
+
+ @Value("${server.port}")
+ private int httpsPort;
+
+ @Value("${ssl.flag}")
+ private boolean httpsOnly;
+
+ @Bean
+ public ServletWebServerFactory servletContainer() {
+ TomcatServletWebServerFactory tomcat =
+ new TomcatServletWebServerFactory(){
+ @Override
+ protected void postProcessContext(Context context) {
+ SecurityConstraint securityConstraint = new SecurityConstraint();
+ if(httpsOnly){ securityConstraint.setUserConstraint("CONFIDENTIAL");}
+ SecurityCollection collection = new SecurityCollection();
+ collection.addPattern("/*");
+ securityConstraint.addCollection(collection);
+ context.addConstraint(securityConstraint);
+ }
+ };
+ tomcat.addAdditionalTomcatConnectors(redirectConnector());
+ return tomcat;
+ }
+
+ private Connector redirectConnector() {
+ Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
+ connector.setScheme("http");
+ connector.setPort(httpPort);
+ connector.setSecure(false);
+ if(httpsOnly) { connector.setRedirectPort(httpsPort); }
+ return connector;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/JerseyConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/JerseyConfiguration.java
new file mode 100644
index 0000000..6d06ac7
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/JerseyConfiguration.java
@@ -0,0 +1,99 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import org.oran.otf.api.service.impl.*;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.ws.rs.ApplicationPath;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.servlet.ServletProperties;
+import org.oran.otf.api.service.impl.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+
+@Component
+@ApplicationPath("/otf/api")
+public class JerseyConfiguration extends ResourceConfig {
+ private static final Logger log = Logger.getLogger(JerseyConfiguration.class.getName());
+
+ // @Value("${spring.jersey.application-path}")
+ // private String apiPath;
+
+ // @Value("${springfox.documentation.swagger.v2.path}")
+ // private String swagger2Endpoint;
+
+ @Autowired
+ public JerseyConfiguration() {
+ registerFeatures();
+ registerEndpoints();
+ setProperties();
+
+ configureSwagger();
+ }
+
+
+ private void registerFeatures() {
+ register(MultiPartFeature.class);
+ register(new OTFLoggingFeature(Logger.getLogger(getClass().getName()), Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 8192));
+
+ }
+
+ private void registerEndpoints() {
+ register(TestInstanceServiceImpl.class);
+ register(HealthServiceImpl.class);
+ register(TestStrategyServiceImpl.class);
+ register(TestExecutionServiceImpl.class);
+ register(VirtualTestHeadServiceImpl.class);
+
+ register(OtfOpenServiceImpl.class);
+ }
+
+ private void setProperties() {
+ property(ServletProperties.FILTER_FORWARD_ON_404, true);
+ property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
+ }
+
+ private void configureSwagger() {
+ OpenApiResource openApiResource = new OpenApiResource();
+
+ register(openApiResource);
+ }
+
+ @Bean
+ @Primary
+ public ObjectMapper objectMapper() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
+ objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+ return objectMapper;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilter.java b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilter.java
new file mode 100644
index 0000000..aba17f0
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilter.java
@@ -0,0 +1,134 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.Access.Level;
+import org.onap.aaf.cadi.ServletContextAccess;
+import org.onap.aaf.cadi.util.Split;
+
+public class OTFApiEnforcementFilter implements Filter {
+ private static final Log log = LogFactory.getLog(OTFApiEnforcementFilter.class);
+ private String type;
+ private Map<String, List<String>> publicPaths;
+ private Access access = null;
+
+ public OTFApiEnforcementFilter(Access access, String enforce) throws ServletException {
+ this.access = access;
+ init(enforce);
+ }
+
+ @Override
+ public void init(FilterConfig fc) throws ServletException {
+ init(fc.getInitParameter("aaf_perm_type"));
+ // need the Context for Logging, instantiating ClassLoader, etc
+ ServletContextAccess sca = new ServletContextAccess(fc);
+ if (access == null) {
+ access = sca;
+ }
+ }
+
+ private void init(final String ptypes) throws ServletException {
+ if (Strings.isNullOrEmpty(ptypes)) {
+ throw new ServletException("OTFApiEnforcement requires aaf_perm_type property");
+ }
+ String[] full = Split.splitTrim(';', ptypes);
+ if (full.length <= 0) {
+ throw new ServletException("aaf_perm_type property is empty");
+ }
+
+ type = full[0];
+ publicPaths = new TreeMap<>();
+ if (full.length > 1) {
+ for (int i = 1; i < full.length; ++i) {
+ String[] pubArray = Split.split(':', full[i]);
+ if (pubArray.length == 2) {
+ List<String> ls = publicPaths.get(pubArray[0]);
+ if (ls == null) {
+ ls = new ArrayList<>();
+ publicPaths.put(pubArray[0], ls);
+ }
+ ls.add(pubArray[1]);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc)
+ throws IOException, ServletException {
+ HttpServletRequest hreq = (HttpServletRequest) req;
+ final String meth = hreq.getMethod();
+ String path = hreq.getContextPath(); // + hreq.getPathInfo();
+
+ if (Strings.isNullOrEmpty(path) || "null".equals(path)) {
+ path = hreq.getRequestURI().substring(hreq.getContextPath().length());
+ }
+
+ List<String> list = publicPaths.get(meth);
+ if (list != null) {
+ for (String p : publicPaths.get(meth)) {
+ if (path.startsWith(p)) {
+ access.printf(
+ Level.INFO,
+ "%s accessed public API %s %s\n",
+ hreq.getUserPrincipal().getName(),
+ meth,
+ path);
+ fc.doFilter(req, resp);
+ return;
+ }
+ }
+ }
+ if (hreq.isUserInRole(type + '|' + path + '|' + meth)) {
+ access.printf(
+ Level.INFO,
+ "%s is allowed access to %s %s\n",
+ hreq.getUserPrincipal().getName(),
+ meth,
+ path);
+ fc.doFilter(req, resp);
+ } else {
+ access.printf(
+ Level.AUDIT,
+ "%s is denied access to %s %s\n",
+ hreq.getUserPrincipal().getName(),
+ meth,
+ path);
+ ((HttpServletResponse) resp).sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ }
+
+ @Override
+ public void destroy() {}
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilterConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilterConfiguration.java
new file mode 100644
index 0000000..cd37067
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilterConfiguration.java
@@ -0,0 +1,60 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import org.onap.aaf.cadi.Access;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+@PropertySource("classpath:application.properties")
+@Configuration
+@ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true")
+public class OTFApiEnforcementFilterConfiguration {
+
+ private Access access;
+ private FilterConfig fc;
+
+ @Bean(name = "otfApiEnforcementFilterRegistrationBean")
+ @ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true")
+ public FilterRegistrationBean<Filter> otfApiEnforcementFilterRegistration()
+ throws ServletException {
+ FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
+ initFilterParameters(registration);
+ registration.addUrlPatterns("/otf/api/testInstance/*", "/otf/api/testExecution/*", "/otf/api/testStrategy/*", "/otf/api/virtualTestHead/*");
+ registration.setFilter(otfApiEnforcementFilter());
+ registration.setName("otfApiEnforcementFilter");
+ registration.setOrder(1);
+ return registration;
+ }
+
+ @Bean(name = "otfApiEnforcementFilter")
+ @ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true")
+ public Filter otfApiEnforcementFilter() throws ServletException {
+ return new OTFApiEnforcementFilter(access, System.getenv("AAF_PERM_TYPE"));
+ }
+
+ private void initFilterParameters(FilterRegistrationBean<Filter> registration) {
+ registration.addInitParameter("aaf_perm_type", System.getenv("AAF_PERM_TYPE"));
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/OTFLoggingFeature.java b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFLoggingFeature.java
new file mode 100644
index 0000000..c13caab
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFLoggingFeature.java
@@ -0,0 +1,238 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.message.MessageUtils;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.WriterInterceptor;
+import javax.ws.rs.ext.WriterInterceptorContext;
+import java.io.*;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class OTFLoggingFeature extends LoggingFeature implements ContainerRequestFilter, ContainerResponseFilter,
+ ClientRequestFilter, ClientResponseFilter, WriterInterceptor {
+
+ private static final boolean printEntity = true;
+ private static final int maxEntitySize = 8 * 1024;
+ private final Logger logger = Logger.getLogger("OTFLoggingFeature");
+ private static final String ENTITY_LOGGER_PROPERTY = OTFLoggingFeature.class.getName();
+ private static final String NOTIFICATION_PREFIX = "* ";
+ private static final String REQUEST_PREFIX = "> ";
+ private static final String RESPONSE_PREFIX = "< ";
+ private static final String AUTHORIZATION = "Authorization";
+ private static final String EQUAL = " = ";
+ private static final String HEADERS_SEPARATOR = ", ";
+ private static List<String> requestHeaders;
+
+ static {
+ requestHeaders = new ArrayList<>();
+ requestHeaders.add(AUTHORIZATION);
+ }
+
+ public OTFLoggingFeature(Logger logger, Level level, Verbosity verbosity, Integer maxEntitySize) {
+ super(logger, level, verbosity, maxEntitySize);
+ }
+
+ @Override
+ public boolean configure(FeatureContext context) {
+ context.register(this);
+ return true;
+ }
+
+ private Object getEmail(Object authorization){
+ try{
+ String encoded = ((String) authorization).split(" ")[1];
+ String decoded = new String(Base64.getDecoder().decode(encoded));
+ return decoded.split(":")[0];
+ }
+ catch (Exception e){
+ return authorization;
+ }
+ }
+
+ @Override
+ public void filter(final ClientRequestContext context) {
+ final StringBuilder b = new StringBuilder();
+ printHeaders(b, context.getStringHeaders());
+ printRequestLine(b, "Sending client request", context.getMethod(), context.getUri());
+
+ if (printEntity && context.hasEntity()) {
+ final OutputStream stream = new LoggingStream(b, context.getEntityStream());
+ context.setEntityStream(stream);
+ context.setProperty(ENTITY_LOGGER_PROPERTY, stream);
+ // not calling log(b) here - it will be called by the interceptor
+ } else {
+ log(b);
+ }
+ }
+
+ @Override
+ public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext) throws IOException {
+ final StringBuilder b = new StringBuilder();
+ printResponseLine(b, "Client response received", responseContext.getStatus());
+
+ if (printEntity && responseContext.hasEntity()) {
+ responseContext.setEntityStream(logInboundEntity(b, responseContext.getEntityStream(),
+ MessageUtils.getCharset(responseContext.getMediaType())));
+ }
+ log(b);
+ }
+
+ @Override
+ public void filter(final ContainerRequestContext context) throws IOException {
+ final StringBuilder b = new StringBuilder();
+ printHeaders(b, context.getHeaders());
+ printRequestLine(b, "Server has received a request", context.getMethod(), context.getUriInfo().getRequestUri());
+
+ if (printEntity && context.hasEntity()) {
+ context.setEntityStream(logInboundEntity(b, context.getEntityStream(), MessageUtils.getCharset(context.getMediaType())));
+ }
+ log(b);
+ }
+
+ @Override
+ public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) {
+ final StringBuilder b = new StringBuilder();
+ printResponseLine(b, "Server responded with a response", responseContext.getStatus());
+
+ if (printEntity && responseContext.hasEntity()) {
+ final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream());
+ responseContext.setEntityStream(stream);
+ requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream);
+ // not calling log(b) here - it will be called by the interceptor
+ } else {
+ log(b);
+ }
+ }
+
+ @Override
+ public void aroundWriteTo(final WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException {
+ final LoggingStream stream = (LoggingStream) writerInterceptorContext.getProperty(ENTITY_LOGGER_PROPERTY);
+ writerInterceptorContext.proceed();
+ if (stream != null) {
+ log(stream.getStringBuilder(MessageUtils.getCharset(writerInterceptorContext.getMediaType())));
+ }
+ }
+
+ private static class LoggingStream extends FilterOutputStream {
+ private final StringBuilder b;
+ private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+
+ LoggingStream(final StringBuilder b, final OutputStream inner) {
+ super(inner);
+
+ this.b = b;
+ }
+
+ StringBuilder getStringBuilder(Charset charset) {
+ // write entity to the builder
+ final byte[] entity = byteArrayOutputStream.toByteArray();
+
+ b.append(new String(entity, 0, Math.min(entity.length, maxEntitySize), charset));
+ if (entity.length > maxEntitySize) {
+ b.append("...more...");
+ }
+ b.append('\n');
+
+ return b;
+ }
+
+ public void write(final int i) throws IOException {
+ if (byteArrayOutputStream.size() <= maxEntitySize) {
+ byteArrayOutputStream.write(i);
+ }
+ out.write(i);
+ }
+ }
+
+ private void printHeaders(StringBuilder b, MultivaluedMap<String, String> headers) {
+ for (String header : requestHeaders) {
+ if (Objects.nonNull(headers.get(header))) {
+ if(header.equalsIgnoreCase("Authorization")){
+ b.append(header).append(EQUAL).append(getEmail(headers.get(header).get(0))).append(HEADERS_SEPARATOR);
+ }
+ else{
+ b.append(header).append(EQUAL).append(headers.get(header)).append(HEADERS_SEPARATOR);
+ }
+ }
+ }
+ int lastIndex = b.lastIndexOf(HEADERS_SEPARATOR);
+ if (lastIndex != -1) {
+ b.delete(lastIndex, lastIndex + HEADERS_SEPARATOR.length());
+ b.append("\n");
+ }
+ }
+
+ private void log(final StringBuilder b) {
+ String message = b.toString();
+ if (logger != null) {
+ logger.info(message);
+ }
+ }
+
+ private void printRequestLine(final StringBuilder b, final String note, final String method, final URI uri) {
+ b.append(NOTIFICATION_PREFIX)
+ .append(note)
+ .append(" on thread ").append(Thread.currentThread().getId())
+ .append(REQUEST_PREFIX).append(method).append(" ")
+ .append(uri.toASCIIString()).append("\n");
+ }
+
+ private void printResponseLine(final StringBuilder b, final String note, final int status) {
+ b.append(NOTIFICATION_PREFIX)
+ .append(note)
+ .append(" on thread ").append(Thread.currentThread().getId())
+ .append(RESPONSE_PREFIX)
+ .append(Integer.toString(status))
+ .append("\n");
+ }
+
+ private InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) throws IOException {
+ if (!stream.markSupported()) {
+ stream = new BufferedInputStream(stream);
+ }
+ stream.mark(maxEntitySize + 1);
+ final byte[] entity = new byte[maxEntitySize + 1];
+ final int entitySize = stream.read(entity);
+ b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset));
+ if (entitySize > maxEntitySize) {
+ b.append("...more...");
+ }
+ b.append('\n');
+ stream.reset();
+ return stream;
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/exception/TestHeadNotFoundException.java b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestHeadNotFoundException.java
new file mode 100644
index 0000000..7132a88
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestHeadNotFoundException.java
@@ -0,0 +1,33 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.exception;
+
+public class TestHeadNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public TestHeadNotFoundException(String message) {
+ super(message);
+ }
+
+ public TestHeadNotFoundException(Throwable cause) {
+ super(cause);
+ }
+
+ public TestHeadNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/exception/TestParametersException.java b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestParametersException.java
new file mode 100644
index 0000000..2029f5c
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestParametersException.java
@@ -0,0 +1,33 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.exception;
+
+public class TestParametersException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public TestParametersException(String message) {
+ super(message);
+ }
+
+ public TestParametersException(Throwable cause) {
+ super(cause);
+ }
+
+ public TestParametersException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/exception/UserNotFoundException.java b/otf-service-api/src/main/java/org/oran/otf/api/exception/UserNotFoundException.java
new file mode 100644
index 0000000..d319bcb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/exception/UserNotFoundException.java
@@ -0,0 +1,33 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.exception;
+
+public class UserNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public UserNotFoundException(String message) {
+ super(message);
+ }
+
+ public UserNotFoundException(Throwable cause) {
+ super(cause);
+ }
+
+ public UserNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessDeploymentHandler.java b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessDeploymentHandler.java
new file mode 100644
index 0000000..25c06b3
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessDeploymentHandler.java
@@ -0,0 +1,131 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.handler;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import java.io.InputStream;
+import java.util.Base64;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CamundaProcessDeploymentHandler {
+ private static final Logger logger =
+ LoggerFactory.getLogger(CamundaProcessDeploymentHandler.class);
+
+ private CamundaProcessDeploymentHandler() {
+ // prevent instantiation
+ }
+
+ public Response start(InputStream bpmn, InputStream compressedResources) {
+ // Read necessary environment variables - Avoiding using Spring dependencies (@Value)
+ String host = System.getenv("otf.camunda.host");
+ String path = System.getenv("otf.camunda.uri.deploy-test-strategy-zip");
+ int port = Utilities.TryGetEnvironmentVariable("otf.camunda.port");
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ if (!Utilities.isHostValid(host)) {
+ logger.error("Host (%s) must use either the http or https protocol.", host);
+ return null;
+ }
+
+ if (!Utilities.isPortValid(port)) {
+ logger.error(
+ "Invalid port (%s) specified as environment variable 'otf.camunda.port'.",
+ System.getenv("otf.camunda.port"));
+ return null;
+ }
+
+ // Form the full url
+ String postUrl = String.format("%s:%s/%s", host, port, path);
+
+ try (CloseableHttpClient httpclient =
+ HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build()) {
+
+ // build multipart upload request
+ MultipartEntityBuilder builder =
+ MultipartEntityBuilder.create()
+ .addBinaryBody("bpmn", bpmn, ContentType.DEFAULT_BINARY, "bpmn");
+
+ // add resources to the request if they were supplied
+ if (compressedResources != null) {
+ builder.addBinaryBody(
+ "resources", compressedResources, ContentType.DEFAULT_BINARY, "resources");
+ }
+
+ HttpEntity data = builder.build();
+
+ // build http request and assign multipart upload data
+ HttpUriRequest request =
+ RequestBuilder.post(postUrl)
+ .addHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()))
+ .setEntity(data)
+ .build();
+
+ System.out.println("Executing request " + request.getRequestLine());
+
+ // Create a custom response handler
+ ResponseHandler<Response> responseHandler =
+ response -> {
+ int status = response.getStatusLine().getStatusCode();
+ if (status >= 200 && status < 300) {
+ HttpEntity entity = response.getEntity();
+ String message = entity != null ? EntityUtils.toString(entity) : null;
+ return Response.ok(message).build();
+ } else if (status == 400) {
+ HttpEntity entity = response.getEntity();
+ String message =
+ entity != null
+ ? EntityUtils.toString(entity)
+ : "Supplied bpmn file is not deployable.";
+ return Utilities.Http.BuildResponse.badRequestWithMessage(message);
+ } else {
+ throw new ClientProtocolException("Unexpected response status: " + status);
+ }
+ };
+
+ Response responseBody = httpclient.execute(request, responseHandler);
+ System.out.println("----------------------------------------");
+ System.out.println(responseBody.getEntity().toString());
+
+ return responseBody;
+ } catch (HttpHostConnectException e) {
+ return ResponseUtility.Build.serviceUnavailableWithMessage(e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return ResponseUtility.Build.internalServerErrorWithMessage("Unable to deploy definition.");
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessExecutionHandler.java b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessExecutionHandler.java
new file mode 100644
index 0000000..00e26d7
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessExecutionHandler.java
@@ -0,0 +1,105 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.handler;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.Utilities.LogLevel;
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.model.local.WorkflowRequest;
+import org.oran.otf.common.utility.gson.Convert;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CamundaProcessExecutionHandler {
+ private static final Logger logger =
+ LoggerFactory.getLogger(CamundaProcessExecutionHandler.class);
+
+ private CamundaProcessExecutionHandler() {
+ // prevent instantiation
+ }
+
+ public Response startProcessInstance(WorkflowRequest request) throws Exception {
+ try {
+ // if (!Utilities.Camunda.isCamundaOnline()) {
+ // Utilities.Http.BuildResponse.internalServerErrorWithMessage(
+ // "Unable to start process instance because the test control unit is
+ // unavailable.");
+ // }
+
+ // Read necessary environment variables - Avoiding using Spring dependencies (@Value)
+ String host = System.getenv("otf.camunda.host");
+ String path = System.getenv("otf.camunda.uri.execute-test");
+ int port = Utilities.TryGetEnvironmentVariable("otf.camunda.port");
+
+ if (!Utilities.isHostValid(host)) {
+ logger.error(String.format("Host (%s) must use either the http or https protocol.", host));
+ return null;
+ }
+
+ if (!Utilities.isPortValid(port)) {
+ logger.error(
+ String.format(
+ "Invalid port (%s) specified as environment variable 'otf.camunda.port'.",
+ System.getenv("otf.camunda.port")));
+ return null;
+ }
+
+ // Form the URL
+ String postUrl = String.format("%s:%s/%s", host, port, path);
+
+ // Send and store the response
+ HttpResponse response = Utilities.Http.httpPostJsonUsingAAF(postUrl, request.toString());
+ // Get the entity and attempt to convert it to a TestExecution object.
+ HttpEntity entity = response.getEntity();
+ String rawEntity = EntityUtils.toString(entity);
+ ObjectMapper mapper = new ObjectMapper();
+ OTFApiResponse otfApiResponse = mapper.readValue(rawEntity, OTFApiResponse.class);
+
+ if (otfApiResponse.getStatusCode() == 400) {
+ return Response.status(400)
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(otfApiResponse.toString())
+ .build();
+ }
+
+ String jsonMessage = otfApiResponse.getMessage();
+ TestExecution testExecution =
+ Convert.jsonToObject(jsonMessage, new TypeReference<TestExecution>() {});
+ return Response.status(otfApiResponse.getStatusCode())
+ .entity(testExecution.toString())
+ .build();
+
+ } catch (HttpHostConnectException e) {
+ return ResponseUtility.Build.serviceUnavailableWithMessage(e.getMessage());
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/HealthService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/HealthService.java
new file mode 100644
index 0000000..4bd2378
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/HealthService.java
@@ -0,0 +1,54 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.local.OTFApiResponse;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Api
+@Path("/health")
+@Tag(name = "Health Service", description = "Query the availability of the API")
+@Produces({MediaType.APPLICATION_JSON})
+public interface HealthService {
+
+ @GET
+ @Path("/v1")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ summary = "Checks if the test control unit is available",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The test control unit is available",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class)))
+ })
+ Response getHealth();
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/OtfOpenService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/OtfOpenService.java
new file mode 100644
index 0000000..ec32e47
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/OtfOpenService.java
@@ -0,0 +1,35 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.springframework.stereotype.Service;
+
+@Hidden
+@Path("/")
+public interface OtfOpenService {
+ @GET
+ @Hidden
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/demo/openapi.json")
+ Response convertSwaggerFile();
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/TestExecutionService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/TestExecutionService.java
new file mode 100644
index 0000000..b1d5d5e
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/TestExecutionService.java
@@ -0,0 +1,92 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.springframework.stereotype.Component;
+
+@Component
+@Api
+@Path("/testExecution")
+@Tag(name = "Test Services", description = "")
+@Produces(MediaType.APPLICATION_JSON)
+public interface TestExecutionService {
+ @GET
+ @Path("v1/status/executionId/{executionId}")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ description = "Respond with a test execution object if it exists",
+ summary = "Find test execution log by processInstanceId",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))
+ })
+ })
+ Response getExecutionStatus(
+ @HeaderParam("Authorization") String authorization,
+ @PathParam("executionId") String executionId);
+
+ @GET
+ @Path("v1/executionId/{executionId}")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ description =
+ "Respond with a test execution object, and state of the process instance if it exists.",
+ summary = "Find test execution log by executionId",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))
+ }),
+ @ApiResponse(
+ responseCode = "404",
+ description =
+ "No process instance was found with the executionId used to query the service",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class))
+ })
+ })
+ Response getExecution(
+ @HeaderParam("Authorization") String authorization,
+ @PathParam("executionId") String executionId);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/TestInstanceService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/TestInstanceService.java
new file mode 100644
index 0000000..6b60801
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/TestInstanceService.java
@@ -0,0 +1,374 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.TestInstance;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.model.local.TestInstanceCreateRequest;
+import org.oran.otf.common.model.local.WorkflowRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.springframework.stereotype.Component;
+
+@Component
+@Path("/testInstance")
+@Tag(name = "Test Services", description = "")
+@Produces(MediaType.APPLICATION_JSON)
+public interface TestInstanceService {
+ @POST
+ @Path("/execute/v1/id/{testInstanceId}")
+ @Operation(
+ description =
+ "Execute a test instance by it's unique identifier. Test instances can be executed"
+ + " either both synchronously and asynchronously.",
+ summary = "Execute test instance by id",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description =
+ "A successful synchronously executed test returns a test execution object",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))),
+ @ApiResponse(
+ responseCode = "201",
+ description =
+ "A successful asynchronously executed test instance returns a base test execution.",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))),
+ @ApiResponse(
+ responseCode = "401",
+ description =
+ "The mechanized identifier used with the request is prohibited from accessing the resource.",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ Response execute(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "objectid",
+ description = "The UUID of the test instance"))
+ @PathParam("testInstanceId")
+ String testInstanceId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ WorkflowRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the latest version of the test definition.",
+ summary = "Create test instance by test definition id",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/testDefinitionId/{testDefinitionId}")
+ Response createByTestDefinitionId(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "uuid",
+ description = "The UUID of the test definition"))
+ @PathParam("testDefinitionId")
+ String testDefinitionId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the specified version of the test definition",
+ summary = "Create test instance by test definition id and version",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/testDefinitionId/{testDefinitionId}/version/{version}")
+ Response createByTestDefinitionId(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "uuid",
+ description = "The UUID of the test definition."))
+ @PathParam("testDefinitionId")
+ String testDefinitionId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The version of the test definition used to create the instance",
+ example = "2",
+ required = true)
+ @PathParam("version")
+ int version,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the latest version of the test definition",
+ summary = "Create test instance by process definition key",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/processDefinitionKey/{processDefinitionKey}")
+ Response createByProcessDefinitionKey(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the unique process definition key and version",
+ summary = "Create test instance by process definition key and version",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/processDefinitionKey/{processDefinitionKey}/version/{version}")
+ Response createByProcessDefinitionKey(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The version of the test definition used to create the instance",
+ example = "2",
+ required = true)
+ @PathParam("version")
+ int version,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @GET
+ @Operation(
+ description = "Finds a test instance by it's unique identifier",
+ summary = "Find test instance by id",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "A Test Instance object is returned if it exists",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/v1/id/{id}")
+ Response findById(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "uuid",
+ description = "The UUID of the test instance"))
+ @PathParam("id")
+ String testInstanceId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization);
+
+ @GET
+ @Operation(
+ description = "Finds all test instance belonging to the unique process definition key",
+ summary = "Find test instance(s) by process definition key",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "An array of found Test Instance objects are returned",
+ content = {
+ @Content(
+ array = @ArraySchema(schema = @Schema(implementation = TestInstance.class)),
+ mediaType = "application/json")
+ })
+ })
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/v1/processDefinitionKey/{processDefinitionKey}")
+ Response findByProcessDefinitionKey(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization);
+
+ @GET
+ @Operation(
+ description =
+ "Finds all test instance belonging to the unique process definition key and version",
+ summary = "Find test instance(s) by process definition key and version",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "An array of found Test Instance objects are returned",
+ content = {
+ @Content(
+ array = @ArraySchema(schema = @Schema(implementation = TestInstance.class)),
+ mediaType = "application/json")
+ })
+ })
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/v1/processDefinitionKey/{processDefinitionKey}/version/{version}")
+ Response findByProcessDefinitionKeyAndVersion(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The version of the test definition used to create the instance",
+ example = "2",
+ required = true)
+ @PathParam("version")
+ String version,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/TestStrategyService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/TestStrategyService.java
new file mode 100644
index 0000000..84b2535
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/TestStrategyService.java
@@ -0,0 +1,66 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import java.io.InputStream;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+@Api
+@Hidden
+@Path("/testStrategy")
+@Tag(name = "Test Service", description = "Deploy and delete test strategies to and from the test control unit. (This documentation will only be available to the development team)")
+@Produces({MediaType.APPLICATION_JSON})
+public interface TestStrategyService {
+ @POST
+ @Hidden
+ @Path("/deploy/v1")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.APPLICATION_JSON)
+ Response deployTestStrategy(
+ @FormDataParam("bpmn") InputStream bpmn,
+ @FormDataParam("resources") InputStream compressedResources,
+ @FormDataParam("testDefinitionId") String testDefinitionId,
+ @FormDataParam("testDefinitionDeployerId") String testDefinitionDeployerId,
+ @FormDataParam("definitionId") String definitionId,
+ @HeaderParam("Authorization") String authorization);
+
+ @DELETE
+ @Hidden
+ @Path("/delete/v1/testDefinitionId/{testDefinitionId}")
+ Response deleteByTestDefinitionId(
+ @PathParam("testDefinitionId") String testDefinitionId,
+ @HeaderParam("authorization") String authorization);
+
+ @DELETE
+ @Hidden
+ @Path("/delete/v1/deploymentId/{deploymentId}")
+ Response deleteByDeploymentId(
+ @PathParam("deploymentId") String deploymentId,
+ @HeaderParam("authorization") String authorization);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/VirtualTestHeadService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/VirtualTestHeadService.java
new file mode 100644
index 0000000..9c6ed6f
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/VirtualTestHeadService.java
@@ -0,0 +1,55 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.TestHead;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+
+@Api
+@Path("/virtualTestHead")
+@Tag(name = "Health Service", description = "Query the availability of the API")
+@Produces({MediaType.APPLICATION_JSON})
+public interface VirtualTestHeadService {
+
+ @PATCH
+ @Path("/v1/{testHeadName}")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ summary = "Used to update fields in the virtual test head",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The response will include the new vth object",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class)))
+ })
+ Response updateVirtualTestHead(@HeaderParam(HttpHeaders.AUTHORIZATION) String authorization, @PathParam("testHeadName") String testHeadName, TestHead newTestHead);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/HealthServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/HealthServiceImpl.java
new file mode 100644
index 0000000..ed4755a
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/HealthServiceImpl.java
@@ -0,0 +1,34 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.service.HealthService;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import javax.ws.rs.core.Response;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class HealthServiceImpl implements HealthService {
+
+ public HealthServiceImpl() {}
+
+ @Override
+ public Response getHealth() {
+ return Response.ok(new OTFApiResponse(200, "UP")).build();
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/OtfOpenServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/OtfOpenServiceImpl.java
new file mode 100644
index 0000000..bfff6bb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/OtfOpenServiceImpl.java
@@ -0,0 +1,49 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.Utilities.LogLevel;
+import org.oran.otf.api.service.OtfOpenService;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpResponse;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Service;
+
+@Service
+public class OtfOpenServiceImpl implements OtfOpenService {
+
+ @Override
+ public Response convertSwaggerFile() {
+ try {
+ HttpResponse res =
+ Utilities.Http.httpGetUsingAAF("https://localhost:8443/otf/api/openapi.json");
+ String resStr = EntityUtils.toString(res.getEntity());
+ JsonObject resJson = new JsonParser().parse(resStr).getAsJsonObject();
+ if (resJson.has("openapi")) {
+ resJson.addProperty("openapi", "3.0.0");
+ return Response.ok(resJson.toString()).build();
+ }
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ }
+
+ return Utilities.Http.BuildResponse.internalServerError();
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestExecutionServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestExecutionServiceImpl.java
new file mode 100644
index 0000000..e758c6b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestExecutionServiceImpl.java
@@ -0,0 +1,160 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.service.TestExecutionService;
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestExecutionRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.permissions.PermissionChecker;
+import org.oran.otf.common.utility.permissions.UserPermission;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.util.Optional;
+import java.util.UUID;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TestExecutionServiceImpl implements TestExecutionService {
+ private static final Logger logger = LoggerFactory.getLogger(TestExecutionServiceImpl.class);
+ @Autowired
+ private UserRepository userRepository;
+ @Autowired private TestExecutionRepository testExecutionRepository;
+ @Autowired private GroupRepository groupRepository;
+
+ @Override
+ public Response getExecutionStatus(String authorization, String executionId) {
+ if (authorization == null) {
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage("Missing authorization header.");
+ }
+ // check if the executionId is a valid UUID
+ try {
+ UUID.fromString(executionId);
+ } catch (IllegalArgumentException e) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Invalid execution identifier. Expected type is UUID (v4).");
+ }
+
+ // try to find the test execution
+ Optional<TestExecution> optionalTestExecution =
+ testExecutionRepository.findFirstByProcessInstanceId(executionId);
+ TestExecution testExecution = Utilities.resolveOptional(optionalTestExecution);
+ if (testExecution == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("An execution with identifier %s was not found.", executionId));
+ }
+
+ // try to find the group of the test execution
+ String testExecutionGroupId = testExecution.getGroupId().toString();
+ Optional<Group> optionalGroup = groupRepository.findById(testExecutionGroupId);
+ Group group = Utilities.resolveOptional(optionalGroup);
+ if (group == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "The group (id: %s) associated with the test execution does not exist.",
+ testExecutionGroupId));
+ }
+
+ // try to find the user for the mechanizedId used to make this request
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (user == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "No user associated with mechanized identifier used for this request.");
+ }
+ // if it doesnt have read permission then return bad request
+ if (!PermissionChecker.hasPermissionTo(user,group, UserPermission.Permission.READ,groupRepository)){
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage(
+ "Unauthorized to view this test execution.");
+ }
+ // Used the build the final response to be returned
+ JsonObject res = new JsonObject();
+ try {
+ // Parsing is required to prevent Gson from escaping all the characters of the json
+ JsonElement testExecutionParsed = new JsonParser().parse(testExecution.toString());
+ res.add("testExecution", testExecutionParsed);
+ // Get the state of the process instance using the Camunda REST API
+ JsonObject procInstStatus = Utilities.Camunda.processInstanceStatus(executionId);
+ // Extract the state of the process instance from the JSON response
+ String processInstanceState =
+ procInstStatus.getAsJsonObject("historicProcessInstance").get("state").getAsString();
+ // Add the result to the final response
+ res.addProperty("state", processInstanceState);
+ } catch (NullPointerException npe) {
+ // In the case of a null pointer exception, make it clear that the state was not able
+ // to be determined using the Camunda API.
+ logger.error("Unable to determine the live status of the test execution.");
+ res.addProperty("state", "Unable to determine");
+ }
+ // Send the response
+ return Response.ok(res.toString()).build();
+ }
+
+ @Override
+ public Response getExecution(String authorization, String processInstanceId) {
+ try {
+ UUID.fromString(processInstanceId);
+ } catch (IllegalArgumentException e) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Invalid execution identifier. Expected type is UUID (v4).");
+ }
+
+ // try to find the test execution
+ Optional<TestExecution> optionalTestExecution =
+ testExecutionRepository.findFirstByProcessInstanceId(processInstanceId);
+ TestExecution testExecution = Utilities.resolveOptional(optionalTestExecution);
+ if (testExecution == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("An execution with identifier %s was not found.", processInstanceId));
+ }
+
+ // try to find the group of the test execution
+ String testExecutionGroupId = testExecution.getGroupId().toString();
+ Optional<Group> optionalGroup = groupRepository.findById(testExecutionGroupId);
+ Group group = Utilities.resolveOptional(optionalGroup);
+ if (group == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "The group (id: %s) associated with the test execution does not exist.",
+ testExecutionGroupId));
+ }
+
+ // try to find the user for the mechanizedId used to make this request
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (user == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "No user associated with mechanized identifier used" + " for this request.");
+ }
+
+ // if it doesnt have read permission then return bad request
+ if (!PermissionChecker.hasPermissionTo(user,group,UserPermission.Permission.READ,groupRepository)){
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage(
+ "Unauthorized to view this test execution.");
+ }
+
+ return Response.ok(testExecution.toString()).build();
+ }
+}
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
index 0000000..d171206
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java
@@ -0,0 +1,807 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.Utilities.LogLevel;
+import org.oran.otf.api.handler.CamundaProcessExecutionHandler;
+import org.oran.otf.api.service.TestInstanceService;
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.TestDefinition;
+import org.oran.otf.common.model.TestInstance;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.model.local.TestInstanceCreateRequest;
+import org.oran.otf.common.model.local.WorkflowRequest;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestDefinitionRepository;
+import org.oran.otf.common.repository.TestInstanceRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.Utility;
+import org.oran.otf.common.utility.database.Generic;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import org.oran.otf.common.utility.permissions.PermissionChecker;
+import org.oran.otf.common.utility.permissions.UserPermission;
+import com.google.common.base.Strings;
+import org.bson.types.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.*;
+
+@Service
+public class TestInstanceServiceImpl implements TestInstanceService {
+ @Autowired
+ CamundaProcessExecutionHandler camundaProcessExecutionHandler;
+ @Autowired
+ UserRepository userRepository;
+ @Autowired
+ TestInstanceRepository testInstanceRepository;
+ @Autowired
+ TestDefinitionRepository testDefinitionRepository;
+ @Autowired
+ GroupRepository groupRepository;
+
+ private static final Logger logger = LoggerFactory.getLogger(TestInstanceServiceImpl.class);
+ private static final String logPrefix = Utility.getLoggerPrefix();
+
+ @Override
+ public Response execute(String testInstanceId, String authorization, WorkflowRequest request) {
+ try {
+ if (request == null) {
+ return ResponseUtility.Build.badRequestWithMessage("Request body is null.");
+ }
+
+ // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request
+ // response.
+ if (!Utilities.isObjectIdValid(testInstanceId)) {
+ String error =
+ String.format(
+ "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",
+ logPrefix, testInstanceId);
+ return ResponseUtility.Build.badRequestWithMessage(error);
+ }
+
+ // Create an ObjectId now that we know the provided String was valid.
+ ObjectId oiTestInstanceId = new ObjectId(testInstanceId);
+ // Check if the testInstance exists, otherwise return a not found response.
+ TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);
+ if (testInstance == null) {
+ String error =
+ String.format(
+ "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);
+ return ResponseUtility.Build.notFoundWithMessage(error);
+ }
+ // Check if the testDefinition exists.
+ TestDefinition testDefinition =
+ Generic.findByIdGeneric(testDefinitionRepository, testInstance.getTestDefinitionId());
+ if (testDefinition == null) {
+ String error =
+ String.format(
+ "%sThe testDefinition with _id, %s, was not found.",
+ logPrefix, testInstance.getTestDefinitionId().toString());
+ return ResponseUtility.Build.notFoundWithMessage(error);
+ }
+
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // If the mechanizedId is not an OTF mechanizedId, check if the user is authorized to
+ // execute
+ // the test instance. This is required because the executorId only needs to be read from the
+ // otf-frontend component. The user/group system is not fully integrated with AAF, so this
+ // is
+ // required. A better way might be to use certificates to check identities.
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ // if we cant find the test instance group then we cant check the permission
+ if (testInstanceGroup == null) {
+ return ResponseUtility.Build.
+ badRequestWithMessage(
+ String.format("Can not find test instance group, id:%s", testInstance.getGroupId().toString()));
+ }
+ // If the mechanizedId is authorized, set the executorId in the WorkflowRequest to the
+ // mechanizedId's ObjectId to make sure that the executorId isn't spoofed. Only use the
+ // executorId sent with the request if it uses the OTF mechanizedId because we "trust" it.
+ if (isOtfMechanizedIdentifier(mechanizedIdUser.getEmail()) && request.getExecutorId() != null) {
+ mechanizedIdUser = Utilities.resolveOptional(userRepository.findById(request.getExecutorId().toString()));
+ } else {
+ request.setExecutorId(mechanizedIdUser.get_id());
+ }
+ if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup, UserPermission.Permission.EXECUTE,groupRepository)) {
+ String error =
+ String.format(
+ "%sUnauthorized the execute test instance with _id, %s.",
+ logPrefix, testInstanceId);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Set the test instance _id after authorization.
+ request.setTestInstanceId(testInstance.get_id());
+
+ // Check if the test instance is disabled.
+ if (testInstance.isDisabled()) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("The test instance with identifier %s is disabled.", testInstanceId));
+ }
+ // Check if the test definition is disabled.
+ if (testDefinition.isDisabled()) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format(
+ "The test definition with identifier %s is disabled.",
+ testInstance.getTestDefinitionId().toString()));
+ }
+
+ // Send the request to Camunda.
+ return camundaProcessExecutionHandler.startProcessInstance(request);
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByTestDefinitionId(
+ String testDefinitionId, String authorization, TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (!Utilities.isObjectIdValid(testDefinitionId)) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format(
+ "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));
+ }
+ ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format("Test definition with id, %s, was not found.", testDefinitionId));
+ }
+ // Check if the mechanizedId has access to the test definition.
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have write access to the group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, true);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinitionId));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByTestDefinitionId(
+ String testDefinitionId,
+ int version,
+ String authorization,
+ TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (!Utilities.isObjectIdValid(testDefinitionId)) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format(
+ "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));
+ }
+ ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format("Test definition with id, %s, was not found.", testDefinitionId));
+ }
+ // permission checking
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+ // if not otf email and is not authorized
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+//// return ResponseUtility.Build.unauthorizedWithMessage(
+//// String.format(
+//// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+//// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+//// }
+//// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+//// return ResponseUtility.Build.unauthorizedWithMessage(
+//// String.format(
+//// "MechanizedId, %s, does not have write access to the group with name, %s",
+//// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+//// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinitionId));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByProcessDefinitionKey(
+ String processDefinitionKey, String authorization, TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (Strings.isNullOrEmpty(processDefinitionKey)) {
+ return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");
+ }
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with processDefinitionKey, %s, was not found.",
+ processDefinitionKey));
+ }
+
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+ // if not otf email and is not authorized
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have write access to the group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, false);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinition.get_id().toString()));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByProcessDefinitionKey(
+ String processDefinitionKey,
+ int version,
+ String authorization,
+ TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (Strings.isNullOrEmpty(processDefinitionKey)) {
+ return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");
+ }
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with processDefinitionKey, %s, was not found.",
+ processDefinitionKey));
+ }
+
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+ // if not otf email and is not authorized
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have write access to the group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinition.get_id().toString()));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response findById(String testInstanceId, String authorization) {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request
+ // response.
+ if (!Utilities.isObjectIdValid(testInstanceId)) {
+ String error =
+ String.format(
+ "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",
+ logPrefix, testInstanceId);
+ return ResponseUtility.Build.badRequestWithMessage(error);
+ }
+
+ // Create an ObjectId now that we know the provided String was valid.
+ ObjectId oiTestInstanceId = new ObjectId(testInstanceId);
+ // Check if the testInstance exists, otherwise return a not found response.
+ TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);
+ if (testInstance == null) {
+ String error =
+ String.format(
+ "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);
+ return ResponseUtility.Build.notFoundWithMessage(error);
+ }
+
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ if (testInstanceGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test instance's group, group name :%s", testInstance.get_id().toString()));
+ }
+ if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "User %s does not have read access to test instance group, group name: %s.",
+ mechanizedIdUser.getEmail(), testInstanceGroup.getGroupName()));
+ }
+ return Response.ok(testInstance.toString(), MediaType.APPLICATION_JSON_TYPE).build();
+ }
+
+ @Override
+ public Response findByProcessDefinitionKey(String processDefinitionKey, String authorization) {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ Optional<TestDefinition> optionalTestDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);
+ TestDefinition testDefinition = optionalTestDefinition.orElse(null);
+ if (testDefinition == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "Cannot find test instance because a test"
+ + " definition with the process definition key (%s) does not exist.",
+ processDefinitionKey));
+ }
+
+ List<TestInstance> testInstances =
+ testInstanceRepository.findAllByTestDefinitionId(testDefinition.get_id());
+ if (testInstances.isEmpty()) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "No test instances found with process " + "definition key (%s).",
+ processDefinitionKey));
+ }
+
+ List<TestInstance> result = new ArrayList<>();
+ for (TestInstance testInstance : testInstances) {
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {
+ result.add(testInstance);
+ }
+ }
+
+ return Response.ok(result.toString()).build();
+ }
+
+ @Override
+ public Response findByProcessDefinitionKeyAndVersion(
+ String processDefinitionKey, String version, String authorization) {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ Optional<TestDefinition> optionalTestDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);
+ TestDefinition testDefinition = optionalTestDefinition.orElse(null);
+
+ if (testDefinition == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "Cannot find test instance because a test"
+ + " definition with the process definition key (%s) does not exist.",
+ processDefinitionKey));
+ }
+
+ int iVersion;
+ try {
+ iVersion = Integer.parseInt(version);
+ } catch (NumberFormatException nfe) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage("Version must be a valid integer.");
+ }
+
+ BpmnInstance bpmnInstance =
+ testDefinition.getBpmnInstances().stream()
+ .filter(_bpmnInstance -> _bpmnInstance.getVersion() == iVersion)
+ .findAny()
+ .orElse(null);
+
+ if (bpmnInstance == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("Cannot find any test instances using " + "version %s.", version));
+ }
+
+ List<TestInstance> testInstances =
+ testInstanceRepository.findAllByTestDefinitionIdAndPDId(
+ testDefinition.get_id(), bpmnInstance.getProcessDefinitionId());
+
+ if (testInstances.isEmpty()) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "No test instances found with process " + "definition key (%s).",
+ processDefinitionKey));
+ }
+
+ List<TestInstance> result = new ArrayList<>();
+ for (TestInstance testInstance : testInstances) {
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {
+ result.add(testInstance);
+ }
+ }
+
+ return Response.ok(result.toString()).build();
+ }
+
+ private boolean isOtfMechanizedIdentifier(String email) {
+ return email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost");
+ }
+
+ private BpmnInstance findBpmnInstance(TestDefinition testDefinition, int version, boolean latest)
+ throws Exception {
+ BpmnInstance bpmnInstance = null;
+ int maxVersion = Integer.MIN_VALUE;
+ // Check if the version exists
+ for (BpmnInstance bi : testDefinition.getBpmnInstances()) {
+ // If this field is null or empty, it means the bpmn hasn't been deployed, or there was a
+ // creation error on the Test Definition page (UI). Skip the field so the user isn't allowed
+ // to create a test instance based off this bpmn instance.
+ if (Strings.isNullOrEmpty(bi.getProcessDefinitionId())) {
+ continue;
+ }
+
+ // Split the processDefinitionId based on it's format:
+ // {processDefinitionKey}:{version}:{processDefinitionId}.
+ String processDefinitionId = bi.getProcessDefinitionId();
+ String[] processDefinitionIdSplit = processDefinitionId.split(":");
+ if (processDefinitionIdSplit.length != 3) {
+ throw new Exception(
+ String.format(
+ "testDefinition[%s].bpmnInstances.processDefinitionId[%s] is invalid.",
+ testDefinition.get_id().toString(), bi.getProcessDefinitionId()));
+ }
+
+ String sVersion = processDefinitionIdSplit[1];
+ int currentVersion = Integer.parseInt(sVersion);
+ if (latest && currentVersion > maxVersion) {
+ bpmnInstance = bi;
+ } else if (currentVersion == version) {
+ bpmnInstance = bi;
+ break;
+ }
+ }
+
+ return bpmnInstance;
+ }
+
+// private boolean isAuthorized(User user, Group group, String permission, GroupRepository groupRepository) {
+// if (isOtfMechanizedIdentifier(user.getEmail())) {
+// return true;
+// }
+// return PermissionChecker.isAuthorized(user, group, permission.toUpperCase(), groupRepository);
+// }
+}
+/*
+ PermissionChecker.hasReadPermission(mechanizedIdUser,testInstanceGroup,groupRepository)
+
+ PermissionChecker.hasPermission(mechanizedIdUser,testInstanceGroup,groupRepository, [READ, WRITE])
+ PermissionsMAp = PermissionChecker.Build.hasRead
+ */
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestStrategyServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestStrategyServiceImpl.java
new file mode 100644
index 0000000..13d125a
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestStrategyServiceImpl.java
@@ -0,0 +1,228 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.handler.CamundaProcessDeploymentHandler;
+import org.oran.otf.api.service.TestStrategyService;
+import org.oran.otf.common.model.TestDefinition;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.model.local.DeployTestStrategyRequest;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestDefinitionRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.v3.oas.annotations.Hidden;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Base64;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpResponse;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.util.EntityUtils;
+import org.bson.types.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+@Hidden
+public class TestStrategyServiceImpl implements TestStrategyService {
+
+ private static final Logger logger = LoggerFactory.getLogger(TestStrategyServiceImpl.class);
+
+ @Autowired private TestDefinitionRepository testDefinitionRepository;
+
+ @Autowired private UserRepository userRepository;
+
+ @Autowired private CamundaProcessDeploymentHandler camundaProcessDeploymentHandler;
+
+ @Autowired private GroupRepository groupRepository;
+
+ public Response deployTestStrategy(
+ InputStream bpmn,
+ InputStream compressedResources,
+ String testDefinitionId,
+ String testDefinitionDeployerId,
+ String definitionId,
+ String authorization) {
+ if (bpmn == null)
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "BPMN input stream cannot be null.");
+
+ // Decode the authorization header.
+ byte[] decodedAuthorization = Base64.getDecoder().decode(authorization.replace("Basic ", ""));
+ String credentials = new String(decodedAuthorization);
+ String[] credentialsArray = credentials.split(":");
+
+ /* Check if the request came from the system specified mechanized identifier. The request goes through AAF
+ * authorization before reaching this code, therefore, assume the headers aren't spoofed. */
+ if (!credentialsArray[0].equals(System.getenv("AAF_ID")))
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Unauthorized to use this service.");
+
+ // Map to a POJO model2.
+ ObjectId _testDefinitionDeployerId = null;
+ ObjectId _testDefinitionId = null;
+
+ if (testDefinitionDeployerId != null && ObjectId.isValid(testDefinitionDeployerId))
+ _testDefinitionDeployerId = new ObjectId(testDefinitionDeployerId);
+ if (testDefinitionId != null && ObjectId.isValid(testDefinitionId))
+ _testDefinitionId = new ObjectId(testDefinitionId);
+
+ DeployTestStrategyRequest request =
+ new DeployTestStrategyRequest(_testDefinitionDeployerId, _testDefinitionId, definitionId);
+
+ // String bpmnContents = null;
+ // try (final Reader reader = new InputStreamReader(bpmn)) {
+ // bpmnContents = CharStreams.toString(reader);
+ // } catch (Exception e) {
+ // e.printStackTrace();
+ // }
+
+ // Check if the request actually contains a bpmn string.
+ // try {
+ // if (bpmnContents == null || bpmnContents.trim().length() == 0)
+ // return Utilities.Http.BuildResponse.badRequestWithMessage("BPMN contents are null.");
+ // } catch (Exception e) {
+ // logger.error(Utilities.getStackTrace(e));
+ // }
+
+ // If a test definition id is supplied, the request intends to update an existing test
+ // definition.
+ if (request.getTestDefinitionId() != null) {
+ // Check if the test definition exists in the database.
+ Optional<TestDefinition> testDefinitionOptional =
+ testDefinitionRepository.findById(request.getTestDefinitionId().toString());
+
+ if (!testDefinitionOptional.isPresent())
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("Test definition (%s) was not found.", request.getTestDefinitionId()));
+
+ // Check if a user to update the definition was supplied.
+ if (request.getTestDefinitionDeployerId() == null)
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Must specify testDefinitionDeployerId.");
+
+ // Check if the user requesting to update the definition is the user who originally created
+ // the definition.
+ TestDefinition testDefinition = testDefinitionOptional.get();
+
+ if (!testDefinition
+ .getCreatedBy()
+ .toString()
+ .equals(request.getTestDefinitionDeployerId().toString()))
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "User (%s) is not authorized to update this test definition.",
+ request.getTestDefinitionDeployerId()));
+
+ // Check if the version to deploy already exists
+ for (BpmnInstance bpmnInstance : testDefinition.getBpmnInstances()) {
+ if (bpmnInstance.getProcessDefinitionId().equalsIgnoreCase(request.getDefinitionId()))
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "A deployment with the definitionId %s already exists.",
+ request.getDefinitionId()));
+ }
+ }
+
+ // Make the deployment request to Camunda. Relay the response received by Camunda.
+ return camundaProcessDeploymentHandler.start(bpmn, compressedResources);
+ }
+
+ public Response deleteByDeploymentId(String deploymentId, String authorization) {
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (!isAuthorized(authorization)) {
+ return Utilities.Http.BuildResponse.unauthorized();
+ }
+
+ String url =
+ String.format(
+ "%s:%s/%s/%s",
+ System.getenv("otf.camunda.host"),
+ System.getenv("otf.camunda.port"),
+ System.getenv("otf.camunda.deploymentDeletionUri"),
+ deploymentId);
+
+ try {
+ HttpResponse res = Utilities.Http.httpDeleteAAF(url);
+ String resStr = EntityUtils.toString(res.getEntity());
+ int status = res.getStatusLine().getStatusCode();
+ return Response.status(status)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(status, resStr))
+ .build();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return Utilities.Http.BuildResponse.internalServerError();
+ }
+ }
+
+ public Response deleteByTestDefinitionId(String testDefinitionId, String authorization) {
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (!isAuthorized(authorization)) {
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage("Authorization headers not set.");
+ }
+
+ String url =
+ String.format(
+ "%s:%s/%s/%s",
+ System.getenv("otf.camunda.host"),
+ System.getenv("otf.camunda.port"),
+ System.getenv("otf.camunda.testDefinitionDeletionUri"),
+ testDefinitionId);
+
+ try {
+ HttpResponse res = Utilities.Http.httpDeleteAAF(url);
+ String resStr = EntityUtils.toString(res.getEntity());
+ int status = res.getStatusLine().getStatusCode();
+ return Response.status(status)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(status, resStr))
+ .build();
+ } catch (HttpHostConnectException e) {
+ return ResponseUtility.Build.serviceUnavailableWithMessage(e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return Utilities.Http.BuildResponse.internalServerError();
+ }
+ }
+
+ private boolean isAuthorized(String authorization) {
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ return (user.getEmail().equalsIgnoreCase("email@localhost")
+ || user.getEmail().equalsIgnoreCase("email@localhost"));
+ }
+
+ private DeployTestStrategyRequest mapToDeployTestStrategyRequest(String body) {
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ return mapper.readValue(body, DeployTestStrategyRequest.class); // Perform the mapping
+ } catch (IOException e) { // Indicates an unknown request body
+ logger.error(e.getMessage());
+ return null;
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/VirtualTestHeadServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/VirtualTestHeadServiceImpl.java
new file mode 100644
index 0000000..d2a662b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/VirtualTestHeadServiceImpl.java
@@ -0,0 +1,164 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.service.VirtualTestHeadService;
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.TestHead;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestHeadRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.Utility;
+import org.oran.otf.common.utility.database.Generic;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import org.oran.otf.common.utility.permissions.PermissionChecker;
+import org.oran.otf.common.utility.permissions.UserPermission;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Service;
+
+import javax.ws.rs.core.Response;
+import java.util.Date;
+import java.util.Optional;
+
+@Service
+public class VirtualTestHeadServiceImpl implements VirtualTestHeadService {
+
+ @Autowired
+ private UserRepository userRepository;
+ @Autowired
+ private GroupRepository groupRepository;
+
+ @Autowired
+ TestHeadRepository testHeadRepository;
+
+ @Autowired
+ MongoTemplate mongoTemplate;
+
+ private static final String logPrefix = Utility.getLoggerPrefix();
+
+ @Override
+ public Response updateVirtualTestHead(String authorization, String testHeadName, TestHead newTestHead) {
+ if (authorization == null) {
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage("Missing authorization header.");
+ }
+
+ // try to find the test head
+ Optional<TestHead> optionalTestHead =
+ testHeadRepository.findByTestHeadName(testHeadName);
+ TestHead testHead = Utilities.resolveOptional(optionalTestHead);
+ if (testHead == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("A test head with identifier %s was not found.", testHeadName));
+ }
+
+ // try to find the group of the test head
+ String testHeadGroupId = testHead.getGroupId().toString();
+ Group testHeadGroup = Generic.findByIdGeneric(groupRepository, testHead.getGroupId());
+ if (testHeadGroup == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "The group (id: %s) associated with the test head does not exist.",
+ testHeadGroupId));
+ }
+
+ // try to find the user for the mechanizedId used to make this request
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (user == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "No user associated with mechanized identifier used for this request.");
+ }
+
+ if (!PermissionChecker.hasPermissionTo(user, testHeadGroup, UserPermission.Permission.WRITE, groupRepository)) {
+ String error =
+ String.format(
+ "Unauthorized the write to test head with name, %s.",
+ testHeadGroupId);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ return updateTestHeadFields(testHead, newTestHead, user);
+ }
+
+ private Response updateTestHeadFields(TestHead testHead, TestHead newTestHead, User user) {
+ Query select = Query.query(Criteria.where("_id").is(testHead.get_id()));
+ Update update = new Update();
+
+ if (newTestHead.getTestHeadName() != null) {
+ if (doesTestHeadWithNameExist(newTestHead.getTestHeadName())) {
+ String error =
+ String.format(
+ "Cant change testHeadName to %s since it already exists.",
+ newTestHead.getTestHeadName());
+ return ResponseUtility.Build.badRequestWithMessage(error);
+ }
+ testHead.setTestHeadName(newTestHead.getTestHeadName());
+ update.set("testHeadName", newTestHead.getTestHeadName());
+ }
+ if (newTestHead.getTestHeadDescription() != null) {
+ testHead.setTestHeadDescription(newTestHead.getTestHeadDescription());
+ update.set("testHeadDescription", newTestHead.getTestHeadDescription());
+ }
+ if (newTestHead.getHostname() != null) {
+ testHead.setHostname(newTestHead.getHostname());
+ update.set("hostname", newTestHead.getHostname());
+ }
+ if (newTestHead.getPort() != null) {
+ testHead.setPort(newTestHead.getPort());
+ update.set("port", newTestHead.getPort());
+ }
+ if (newTestHead.getResourcePath() != null) {
+ testHead.setResourcePath(newTestHead.getResourcePath());
+ update.set("resourcePath", newTestHead.getResourcePath());
+ }
+ if (newTestHead.getAuthorizationType() != null) {
+ testHead.setAuthorizationType(newTestHead.getAuthorizationType());
+ update.set("authorizationType", newTestHead.getAuthorizationType());
+ }
+ if (newTestHead.getAuthorizationCredential() != null) {
+ testHead.setAuthorizationCredential(newTestHead.getAuthorizationCredential());
+ update.set("authorizationCredential", newTestHead.getAuthorizationCredential());
+ }
+ if (newTestHead.getAuthorizationEnabled() != null) {
+ testHead.setAuthorizationEnabled(newTestHead.getAuthorizationEnabled());
+ update.set("authorizationEnabled", newTestHead.getAuthorizationEnabled());
+ }
+ if (newTestHead.getVthInputTemplate() != null) {
+ testHead.setVthInputTemplate(newTestHead.getVthInputTemplate());
+ update.set("vthInputTemplate", newTestHead.getVthInputTemplate());
+ }
+ testHead.setUpdatedAt(new Date());
+ update.set("updatedAt", testHead.getUpdatedAt());
+ testHead.setUpdatedBy(user.get_id());
+ update.set("updatedBy", user.get_id());
+
+ mongoTemplate.updateFirst(select, update, "testHeads");
+ return ResponseUtility.Build.okRequestWithObject(testHead);
+ }
+
+ // check if test head exists in database by name
+ private boolean doesTestHeadWithNameExist(String name) {
+ Optional<TestHead> optionalTestHead =
+ testHeadRepository.findByTestHeadName(name);
+ return optionalTestHead.isPresent();
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/Group.java b/otf-service-api/src/main/java/org/oran/otf/common/model/Group.java
new file mode 100644
index 0000000..9214407
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/Group.java
@@ -0,0 +1,110 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.List;
+
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "groups")
+public class Group implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private ObjectId _id;
+ private String groupName;
+ private String groupDescription;
+ private List<ObjectId> mechanizedIds;
+ private ObjectId ownerId;
+ private List<Role> roles;
+ private List<GroupMember> members;
+ private ObjectId parentGroupId;
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getGroupName() {
+ return groupName;
+ }
+
+ public void setGroupName(String groupName) {
+ this.groupName = groupName;
+ }
+
+ public String getGroupDescription() {
+ return groupDescription;
+ }
+
+ public void setGroupDescription(String groupDescription) {
+ this.groupDescription = groupDescription;
+ }
+
+ public List<ObjectId> getMechanizedIds() {
+ return mechanizedIds;
+ }
+
+ public void setMechanizedIds(List<ObjectId> mechanizedIds) {
+ this.mechanizedIds = mechanizedIds;
+ }
+
+ public ObjectId getOwnerId() {
+ return ownerId;
+ }
+
+ public void setOwnerId(ObjectId ownerId) {
+ this.ownerId = ownerId;
+ }
+
+ public List<Role> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List<Role> roles) {
+ this.roles = roles;
+ }
+
+ public List<GroupMember> getMembers() {
+ return members;
+ }
+
+ public void setMembers(List<GroupMember> members) {
+ this.members = members;
+ }
+
+ public ObjectId getParentGroupId() {
+ return parentGroupId;
+ }
+
+ public void setParentGroupId(ObjectId parentGroupId) {
+ this.parentGroupId = parentGroupId;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/GroupMember.java b/otf-service-api/src/main/java/org/oran/otf/common/model/GroupMember.java
new file mode 100644
index 0000000..583c213
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/GroupMember.java
@@ -0,0 +1,43 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.bson.types.ObjectId;
+
+import java.util.List;
+import java.util.Map;
+
+public class GroupMember {
+ private ObjectId userId;
+ private List<String> roles;//this is name of roles assigned to user that are created within the group i.e admin,dev,.. etc
+
+ public ObjectId getUserId() {
+ return userId;
+ }
+
+ public void setUserId(ObjectId userId) {
+ this.userId = userId;
+ }
+
+ public List<String> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List<String> roles) {
+ this.roles = roles;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/Role.java b/otf-service-api/src/main/java/org/oran/otf/common/model/Role.java
new file mode 100644
index 0000000..aca09f1
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/Role.java
@@ -0,0 +1,41 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import java.util.List;
+
+public class Role {
+
+ private String roleName;
+ private List<String> permissions;
+
+ public String getRoleName() {
+ return roleName;
+ }
+
+ public void setRoleName(String roleName) {
+ this.roleName = roleName;
+ }
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(List<String> permissions) {
+ this.permissions = permissions;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestDefinition.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestDefinition.java
new file mode 100644
index 0000000..2a66fa2
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestDefinition.java
@@ -0,0 +1,137 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testDefinitions")
+public class TestDefinition implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id private ObjectId _id;
+ private String testName;
+ private String testDescription;
+ private String processDefinitionKey;
+ private List<BpmnInstance> bpmnInstances;
+ private ObjectId groupId;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+ private boolean disabled;
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestName() {
+ return testName;
+ }
+
+ public void setTestName(String testName) {
+ this.testName = testName;
+ }
+
+ public String getTestDescription() {
+ return testDescription;
+ }
+
+ public void setTestDescription(String testDescription) {
+ this.testDescription = testDescription;
+ }
+
+ public String getProcessDefinitionKey() {
+ return processDefinitionKey;
+ }
+
+ public void setProcessDefinitionKey(String processDefinitionKey) {
+ this.processDefinitionKey = processDefinitionKey;
+ }
+
+ public List<BpmnInstance> getBpmnInstances() {
+ return bpmnInstances;
+ }
+
+ public void setBpmnInstances(List<BpmnInstance> bpmnInstances) {
+ this.bpmnInstances = bpmnInstances;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestExecution.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestExecution.java
new file mode 100644
index 0000000..8f02e0b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestExecution.java
@@ -0,0 +1,245 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.historic.TestDefinitionHistoric;
+import org.oran.otf.common.model.historic.TestInstanceHistoric;
+import org.oran.otf.common.model.local.TestHeadResult;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testExecutions")
+public class TestExecution implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private ObjectId _id;
+ private ObjectId groupId;
+ private ObjectId executorId;
+
+ private boolean async;
+ private Date startTime;
+ private Date endTime;
+ private String asyncTopic;
+ private String businessKey;
+ private String processInstanceId;
+ private String testResult;
+ private String testResultMessage;
+ private Map<String, Object> testDetails;
+ private List<TestHeadResult> testHeadResults;
+ private List<TestExecution> testInstanceResults;
+ // Stores historic information of associated
+ private String historicEmail;
+ private TestInstanceHistoric historicTestInstance;
+ private TestDefinitionHistoric historicTestDefinition;
+
+ public TestExecution() {
+ }
+
+ public TestExecution(
+ ObjectId _id,
+ ObjectId groupId,
+ ObjectId executorId,
+ boolean async,
+ Date startTime,
+ Date endTime,
+ String asyncTopic,
+ String businessKey,
+ String processInstanceId,
+ String testResult,
+ String testResultMessage,
+ Map<String, Object> testDetails,
+ List<TestHeadResult> testHeadResults,
+ List<TestExecution> testInstanceResults,
+ String historicEmail,
+ TestInstanceHistoric historicTestInstance,
+ TestDefinitionHistoric historicTestDefinition) {
+ this._id = _id;
+ this.groupId = groupId;
+ this.executorId = executorId;
+ this.async = async;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ this.asyncTopic = asyncTopic;
+ this.businessKey = businessKey;
+ this.processInstanceId = processInstanceId;
+ this.testResult = testResult;
+ this.testDetails = testDetails;
+ this.testHeadResults = testHeadResults;
+ this.testInstanceResults = testInstanceResults;
+ this.historicEmail = historicEmail;
+ this.historicTestInstance = historicTestInstance;
+ this.historicTestDefinition = historicTestDefinition;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public ObjectId getExecutorId() {
+ return executorId;
+ }
+
+ public void setExecutorId(ObjectId executorId) {
+ this.executorId = executorId;
+ }
+
+ public boolean isAsync() {
+ return async;
+ }
+
+ public void setAsync(boolean async) {
+ this.async = async;
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+
+ public String getAsyncTopic() {
+ return asyncTopic;
+ }
+
+ public void setAsyncTopic(String asyncTopic) {
+ this.asyncTopic = asyncTopic;
+ }
+
+ public String getBusinessKey() {
+ return businessKey;
+ }
+
+ public void setBusinessKey(String businessKey) {
+ this.businessKey = businessKey;
+ }
+
+ public String getProcessInstanceId() {
+ return processInstanceId;
+ }
+
+ public void setProcessInstanceId(String processInstanceId) {
+ this.processInstanceId = processInstanceId;
+ }
+
+ public String getTestResult() {
+ return testResult;
+ }
+
+ public void setTestResult(String testResult) {
+ this.testResult = testResult;
+ }
+
+ public String getTestResultMessage() {
+ return testResultMessage;
+ }
+
+ public void setTestResultMessage(String testResultMessage) {
+ this.testResultMessage = testResultMessage;
+ }
+
+ public Map<String, Object> getTestDetails() {
+ return testDetails;
+ }
+
+ public void setTestDetails(Map<String, Object> testDetails) {
+ this.testDetails = testDetails;
+ }
+
+ public List<TestHeadResult> getTestHeadResults() {
+ synchronized (testHeadResults) {
+ return testHeadResults;
+ }
+ }
+
+ public void setTestHeadResults(List<TestHeadResult> testHeadResults) {
+ synchronized (testHeadResults) {
+ this.testHeadResults = testHeadResults;
+ }
+ }
+
+ public List<TestExecution> getTestInstanceResults() {
+ synchronized (testInstanceResults) {
+ return testInstanceResults;
+ }
+ }
+
+ public void setTestInstanceResults(List<TestExecution> testInstanceResults) {
+ synchronized (testInstanceResults) {
+ this.testInstanceResults = testInstanceResults;
+ }
+ }
+
+ public String getHistoricEmail() {
+ return historicEmail;
+ }
+
+ public void setHistoricEmail(String historicEmail) {
+ this.historicEmail = historicEmail;
+ }
+
+ public TestInstanceHistoric getHistoricTestInstance() {
+ return historicTestInstance;
+ }
+
+ public void setHistoricTestInstance(TestInstanceHistoric historicTestInstance) {
+ this.historicTestInstance = historicTestInstance;
+ }
+
+ public TestDefinitionHistoric getHistoricTestDefinition() {
+ return historicTestDefinition;
+ }
+
+ public void setHistoricTestDefinition(
+ TestDefinitionHistoric historicTestDefinition) {
+ this.historicTestDefinition = historicTestDefinition;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestHead.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestHead.java
new file mode 100644
index 0000000..7f4bcbc
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestHead.java
@@ -0,0 +1,224 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testHeads")
+public class TestHead implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private ObjectId _id;
+
+ @Indexed(unique = true)
+ private String testHeadName;
+
+ private String testHeadDescription;
+ private String hostname;
+ private String port;
+ private String resourcePath;
+ private ObjectId creatorId;
+ private ObjectId groupId;
+ private String authorizationType;
+ private String authorizationCredential;
+ private Boolean authorizationEnabled;
+ private Map<String, Object> vthInputTemplate;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId updatedBy;
+ private Boolean isPublic;
+ public TestHead() {
+ }
+
+ public TestHead(
+ ObjectId _id,
+ String testHeadName,
+ String testHeadDescription,
+ String hostname,
+ String port,
+ String resourcePath,
+ ObjectId creatorId,
+ ObjectId groupId,
+ String authorizationType,
+ String authorizationCredential,
+ boolean authorizationEnabled,
+ Map<String, Object> vthInputTemplate,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId updatedBy,
+ Boolean isPublic) {
+ this._id = _id;
+ this.testHeadName = testHeadName;
+ this.testHeadDescription = testHeadDescription;
+ this.hostname = hostname;
+ this.port = port;
+ this.resourcePath = resourcePath;
+ this.creatorId = creatorId;
+ this.groupId = groupId;
+ this.authorizationType = authorizationType;
+ this.authorizationCredential = authorizationCredential;
+ this.authorizationEnabled = authorizationEnabled;
+ this.vthInputTemplate = vthInputTemplate;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.updatedBy = updatedBy;
+ this.isPublic = isPublic;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestHeadName() {
+ return testHeadName;
+ }
+
+ public void setTestHeadName(String testHeadName) {
+ this.testHeadName = testHeadName;
+ }
+
+ public String getTestHeadDescription() {
+ return testHeadDescription;
+ }
+
+ public void setTestHeadDescription(String testHeadDescription) {
+ this.testHeadDescription = testHeadDescription;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getPort() {
+ return port;
+ }
+
+ public void setPort(String port) {
+ this.port = port;
+ }
+
+ public String getResourcePath() {
+ return resourcePath;
+ }
+
+ public void setResourcePath(String resourcePath) {
+ this.resourcePath = resourcePath;
+ }
+
+ public ObjectId getCreatorId() {
+ return creatorId;
+ }
+
+ public void setCreatorId(ObjectId creatorId) {
+ this.creatorId = creatorId;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public String getAuthorizationCredential() {
+ return authorizationCredential;
+ }
+
+ public String getAuthorizationType() {
+ return authorizationType;
+ }
+
+ public void setAuthorizationType(String authorizationType) {
+ this.authorizationType = authorizationType;
+ }
+
+ public void setAuthorizationCredential(String authorizationCredential) {
+ this.authorizationCredential = authorizationCredential;
+ }
+
+ public Boolean getAuthorizationEnabled() {
+ return authorizationEnabled;
+ }
+
+ public void setAuthorizationEnabled(Boolean authorizationEnabled) {
+ this.authorizationEnabled = authorizationEnabled;
+ }
+
+ public Map<String, Object> getVthInputTemplate() {
+ return vthInputTemplate;
+ }
+
+ public void setVthInputTemplate(Map<String, Object> vthInputTemplate) {
+ this.vthInputTemplate = vthInputTemplate;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public Boolean isPublic() {
+ return isPublic;
+ }
+
+ public void setPublic(Boolean aPublic) {
+ isPublic = aPublic;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestInstance.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestInstance.java
new file mode 100644
index 0000000..9b11fa4
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestInstance.java
@@ -0,0 +1,256 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.local.ParallelFlowInput;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testInstances")
+public class TestInstance implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private @Id ObjectId _id;
+ private String testInstanceName;
+ private String testInstanceDescription;
+ private ObjectId groupId;
+ private ObjectId testDefinitionId;
+ private String processDefinitionId;
+ private boolean useLatestTestDefinition;
+ private boolean disabled;
+ private boolean simulationMode;
+ private long maxExecutionTimeInMillis;
+ private HashMap<String, ParallelFlowInput> pfloInput;
+ private HashMap<String, Object> internalTestData;
+ private HashMap<String, Object> simulationVthInput;
+ private HashMap<String, Object> testData;
+ private HashMap<String, Object> vthInput;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+
+ public TestInstance() {}
+
+ public TestInstance(
+ ObjectId _id,
+ String testInstanceName,
+ String testInstanceDescription,
+ ObjectId groupId,
+ ObjectId testDefinitionId,
+ String processDefinitionId,
+ boolean useLatestTestDefinition,
+ boolean disabled,
+ boolean simulationMode,
+ long maxExecutionTimeInMillis,
+ HashMap<String, ParallelFlowInput> pfloInput,
+ HashMap<String, Object> internalTestData,
+ HashMap<String, Object> simulationVthInput,
+ HashMap<String, Object> testData,
+ HashMap<String, Object> vthInput,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId createdBy,
+ ObjectId updatedBy) {
+ this._id = _id;
+ this.testInstanceName = testInstanceName;
+ this.testInstanceDescription = testInstanceDescription;
+ this.groupId = groupId;
+ this.testDefinitionId = testDefinitionId;
+ this.processDefinitionId = processDefinitionId;
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ this.disabled = disabled;
+ this.simulationMode = simulationMode;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ this.pfloInput = pfloInput;
+ this.internalTestData = internalTestData;
+ this.simulationVthInput = simulationVthInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestInstanceName() {
+ return testInstanceName;
+ }
+
+ public void setTestInstanceName(String testInstanceName) {
+ this.testInstanceName = testInstanceName;
+ }
+
+ public String getTestInstanceDescription() {
+ return testInstanceDescription;
+ }
+
+ public void setTestInstanceDescription(String testInstanceDescription) {
+ this.testInstanceDescription = testInstanceDescription;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public String getProcessDefinitionId() {
+ return processDefinitionId;
+ }
+
+ public void setProcessDefinitionId(String processDefinitionId) {
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public boolean isUseLatestTestDefinition() {
+ return useLatestTestDefinition;
+ }
+
+ public void setUseLatestTestDefinition(boolean useLatestTestDefinition) {
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public boolean isSimulationMode() {
+ return simulationMode;
+ }
+
+ public void setSimulationMode(boolean simulationMode) {
+ this.simulationMode = simulationMode;
+ }
+
+ public long getMaxExecutionTimeInMillis() {
+ return maxExecutionTimeInMillis;
+ }
+
+ public void setMaxExecutionTimeInMillis(long maxExecutionTimeInMillis) {
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ }
+
+ public HashMap<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(HashMap<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public HashMap<String, Object> getInternalTestData() {
+ return internalTestData;
+ }
+
+ public void setInternalTestData(HashMap<String, Object> internalTestData) {
+ this.internalTestData = internalTestData;
+ }
+
+ public HashMap<String, Object> getSimulationVthInput() {
+ return simulationVthInput;
+ }
+
+ public void setSimulationVthInput(HashMap<String, Object> simulationVthInput) {
+ this.simulationVthInput = simulationVthInput;
+ }
+
+ public HashMap<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(HashMap<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public HashMap<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(HashMap<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/User.java b/otf-service-api/src/main/java/org/oran/otf/common/model/User.java
new file mode 100644
index 0000000..2c56b85
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/User.java
@@ -0,0 +1,142 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.local.UserGroup;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "users")
+public class User implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId _id;
+ private List<String> permissions;
+ private String firstName;
+ private String lastName;
+ private String email;
+ private String password;
+ private List<UserGroup> groups;
+ private Date createdAt;
+ private Date updatedAt;
+
+ //Added User for testing
+ public User(){};
+
+ public User(
+ ObjectId _id,
+ List<String> permissions,
+ String firstName,
+ String lastName,
+ String email,
+ String password,
+ List<UserGroup> groups,
+ Date createdAt,
+ Date updatedAt) {
+ this._id = _id;
+ this.permissions = permissions;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.email = email;
+ this.password = password;
+ this.groups = groups;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(List<String> permissions) {
+ this.permissions = permissions;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public List<UserGroup> getGroups() {
+ return groups;
+ }
+
+ public void setGroups(List<UserGroup> groups) {
+ this.groups = groups;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestDefinitionHistoric.java b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestDefinitionHistoric.java
new file mode 100644
index 0000000..fe2be4b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestDefinitionHistoric.java
@@ -0,0 +1,185 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.historic;
+
+import org.oran.otf.common.model.TestDefinition;
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import org.bson.types.ObjectId;
+
+public class TestDefinitionHistoric implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId _id;
+ private String testName;
+ private String testDescription;
+ private String processDefinitionKey;
+ private List<BpmnInstance> bpmnInstances;
+ private ObjectId groupId;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+
+ public TestDefinitionHistoric() {
+ }
+
+ public TestDefinitionHistoric(TestDefinition testDefinition, String processDefinitionId) {
+ this._id = testDefinition.get_id();
+ this.testName = testDefinition.getTestName();
+ this.testDescription = testDefinition.getTestDescription();
+ this.processDefinitionKey = testDefinition.getProcessDefinitionKey();
+ this.bpmnInstances =
+ getHistoricBpmnInstanceAsList(testDefinition.getBpmnInstances(), processDefinitionId);
+ this.groupId = testDefinition.getGroupId();
+ this.createdAt = testDefinition.getCreatedAt();
+ this.updatedAt = testDefinition.getUpdatedAt();
+ this.createdBy = testDefinition.getCreatedBy();
+ this.updatedBy = testDefinition.getUpdatedBy();
+ }
+
+ public TestDefinitionHistoric(
+ ObjectId _id,
+ String testName,
+ String testDescription,
+ String processDefinitionKey,
+ List<BpmnInstance> bpmnInstances,
+ ObjectId groupId,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId createdBy,
+ ObjectId updatedBy) {
+ this._id = _id;
+ this.testName = testName;
+ this.testDescription = testDescription;
+ this.processDefinitionKey = processDefinitionKey;
+ this.bpmnInstances = bpmnInstances;
+ this.groupId = groupId;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ }
+
+ private List<BpmnInstance> getHistoricBpmnInstanceAsList(
+ List<BpmnInstance> bpmnInstances, String processDefinitionId) {
+ BpmnInstance bpmnInstance =
+ bpmnInstances.stream()
+ .filter(
+ _bpmnInstance ->
+ _bpmnInstance.getProcessDefinitionId().equalsIgnoreCase(processDefinitionId))
+ .findFirst()
+ .orElse(null);
+
+ List<BpmnInstance> historicBpmnInstance = new ArrayList<>();
+ if (bpmnInstance != null) {
+ historicBpmnInstance.add(bpmnInstance);
+ }
+
+ return historicBpmnInstance;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestName() {
+ return testName;
+ }
+
+ public void setTestName(String testName) {
+ this.testName = testName;
+ }
+
+ public String getTestDescription() {
+ return testDescription;
+ }
+
+ public void setTestDescription(String testDescription) {
+ this.testDescription = testDescription;
+ }
+
+ public String getProcessDefinitionKey() {
+ return processDefinitionKey;
+ }
+
+ public void setProcessDefinitionKey(String processDefinitionKey) {
+ this.processDefinitionKey = processDefinitionKey;
+ }
+
+ public List<BpmnInstance> getBpmnInstances() {
+ return bpmnInstances;
+ }
+
+ public void setBpmnInstances(List<BpmnInstance> bpmnInstances) {
+ this.bpmnInstances = bpmnInstances;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestInstanceHistoric.java b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestInstanceHistoric.java
new file mode 100644
index 0000000..1263893
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestInstanceHistoric.java
@@ -0,0 +1,234 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.historic;
+
+import org.oran.otf.common.model.TestInstance;
+import org.oran.otf.common.model.local.ParallelFlowInput;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+
+public class TestInstanceHistoric implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private @Id
+ ObjectId _id;
+ private String testInstanceName;
+ private String testInstanceDescription;
+ private ObjectId groupId;
+ private ObjectId testDefinitionId;
+ private String processDefinitionId;
+ private Map<String, ParallelFlowInput> pfloInput;
+ private Map<String, Object> simulationVthInput;
+ private Map<String, Object> testData;
+ private Map<String, Object> vthInput;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+ private boolean simulationMode;
+
+ public TestInstanceHistoric() {
+ }
+
+ public TestInstanceHistoric(TestInstance testInstance) {
+ this._id = testInstance.get_id();
+ this.testInstanceName = testInstance.getTestInstanceName();
+ this.testInstanceDescription = testInstance.getTestInstanceDescription();
+ this.groupId = testInstance.getGroupId();
+ this.testDefinitionId = testInstance.getTestDefinitionId();
+ this.pfloInput = testInstance.getPfloInput();
+ this.processDefinitionId = testInstance.getProcessDefinitionId();
+ this.simulationVthInput = testInstance.getSimulationVthInput();
+ this.testData = testInstance.getTestData();
+ this.vthInput = testInstance.getVthInput();
+ this.createdAt = testInstance.getCreatedAt();
+ this.updatedAt = testInstance.getUpdatedAt();
+ this.createdBy = testInstance.getCreatedBy();
+ this.updatedBy = testInstance.getUpdatedBy();
+ this.simulationMode = testInstance.isSimulationMode();
+ }
+
+ public TestInstanceHistoric(
+ ObjectId _id,
+ String testInstanceName,
+ String testInstanceDescription,
+ ObjectId groupId,
+ ObjectId testDefinitionId,
+ String processDefinitionId,
+ HashMap<String, ParallelFlowInput> pfloInput,
+ HashMap<String, Object> simulationVthInput,
+ HashMap<String, Object> testData,
+ HashMap<String, Object> vthInput,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId createdBy,
+ ObjectId updatedBy,
+ boolean simulationMode) {
+ this._id = _id;
+ this.testInstanceName = testInstanceName;
+ this.testInstanceDescription = testInstanceDescription;
+ this.groupId = groupId;
+ this.testDefinitionId = testDefinitionId;
+ this.processDefinitionId = processDefinitionId;
+ this.pfloInput = pfloInput;
+ this.simulationVthInput = simulationVthInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ this.simulationMode = simulationMode;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestInstanceName() {
+ return testInstanceName;
+ }
+
+ public void setTestInstanceName(String testInstanceName) {
+ this.testInstanceName = testInstanceName;
+ }
+
+ public String getTestInstanceDescription() {
+ return testInstanceDescription;
+ }
+
+ public void setTestInstanceDescription(String testInstanceDescription) {
+ this.testInstanceDescription = testInstanceDescription;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public String getProcessDefinitionId() {
+ return processDefinitionId;
+ }
+
+ public void setProcessDefinitionId(String processDefinitionId) {
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public Map<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(
+ HashMap<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public Map<String, Object> getSimulationVthInput() {
+ return simulationVthInput;
+ }
+
+ public void setSimulationVthInput(
+ HashMap<String, Object> simulationVthInput) {
+ this.simulationVthInput = simulationVthInput;
+ }
+
+ public Map<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(HashMap<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public Map<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(HashMap<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public boolean isSimulationMode() {
+ return simulationMode;
+ }
+
+ public void setSimulationMode(boolean simulationMode) {
+ this.simulationMode = simulationMode;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/ApiRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ApiRequest.java
new file mode 100644
index 0000000..05ec6a9
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ApiRequest.java
@@ -0,0 +1,19 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+public class ApiRequest {}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/BpmnInstance.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/BpmnInstance.java
new file mode 100644
index 0000000..c4440b0
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/BpmnInstance.java
@@ -0,0 +1,191 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+public class BpmnInstance implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private String processDefinitionId;
+ private String deploymentId;
+ private int version;
+ private ObjectId bpmnFileId;
+ private ObjectId resourceFileId;
+ private boolean isDeployed;
+ private List<TestHeadNode> testHeads;
+ private List<PfloNode> pflos;
+ private Map<String, Object> testDataTemplate;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+
+ public BpmnInstance() {
+ }
+
+ @JsonCreator
+ public BpmnInstance(
+ @JsonProperty("processDefinitionId") String processDefinitionId,
+ @JsonProperty("deploymentId") String deploymentId,
+ @JsonProperty("version") int version,
+ @JsonProperty("bpmnFileId") ObjectId bpmnFileId,
+ @JsonProperty("resourceFileId") ObjectId resourceFileId,
+ @JsonProperty("isDeployed") boolean isDeployed,
+ @JsonProperty("testHeads") List<TestHeadNode> testHeads,
+ @JsonProperty("plfos") List<PfloNode> pflos,
+ @JsonProperty("testDataTemplate") Map<String, Object> testDataTemplate,
+ @JsonProperty("createdAt") Date createdAt,
+ @JsonProperty("updateAt") Date updatedAt,
+ @JsonProperty("createdBy") ObjectId createdBy,
+ @JsonProperty("updatedBy") ObjectId updatedBy) {
+ this.processDefinitionId = processDefinitionId;
+ this.deploymentId = deploymentId;
+ this.version = version;
+ this.bpmnFileId = bpmnFileId;
+ this.resourceFileId = resourceFileId;
+ this.isDeployed = isDeployed;
+ this.testHeads = testHeads;
+ this.testDataTemplate = testDataTemplate;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ }
+
+ public String getProcessDefinitionId() {
+ return processDefinitionId;
+ }
+
+ public void setProcessDefinitionId(String processDefinitionId) {
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public String getDeploymentId() {
+ return deploymentId;
+ }
+
+ public void setDeploymentId(String deploymentId) {
+ this.deploymentId = deploymentId;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public ObjectId getBpmnFileId() {
+ return bpmnFileId;
+ }
+
+ public void setBpmnFileId(ObjectId bpmnFileId) {
+ this.bpmnFileId = bpmnFileId;
+ }
+
+ public ObjectId getResourceFileId() {
+ return resourceFileId;
+ }
+
+ public void setResourceFileId(ObjectId resourceFileId) {
+ this.resourceFileId = resourceFileId;
+ }
+
+ @JsonProperty(value="isDeployed")
+ public boolean isDeployed() {
+ return isDeployed;
+ }
+
+ public void setDeployed(boolean deployed) {
+ isDeployed = deployed;
+ }
+
+ public List<TestHeadNode> getTestHeads() {
+ return testHeads;
+ }
+
+ public void setTestHeads(List<TestHeadNode> testHeads) {
+ this.testHeads = testHeads;
+ }
+
+ public List<PfloNode> getPflos() {
+ return pflos;
+ }
+
+ public void setPflos(List<PfloNode> pflos) {
+ this.pflos = pflos;
+ }
+
+ public Map<String, Object> getTestDataTemplate() {
+ return testDataTemplate;
+ }
+
+ public void setTestDataTemplate(Map<String, Object> testDataTemplate) {
+ this.testDataTemplate = testDataTemplate;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ private String getObjectIdString(ObjectId value) {
+ return value == null ? "\"\"" : "\"" + value.toString() + "\"";
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/DeployTestStrategyRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/DeployTestStrategyRequest.java
new file mode 100644
index 0000000..16040e7
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/DeployTestStrategyRequest.java
@@ -0,0 +1,73 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.bson.types.ObjectId;
+
+public class DeployTestStrategyRequest {
+ private ObjectId testDefinitionDeployerId;
+ private ObjectId testDefinitionId;
+ private String definitionId;
+
+ public DeployTestStrategyRequest() {}
+
+ public DeployTestStrategyRequest(
+ ObjectId testDefinitionDeployerId, ObjectId testDefinitionId, String definitionId) {
+ this.testDefinitionDeployerId = testDefinitionDeployerId;
+ this.testDefinitionId = testDefinitionId;
+ this.definitionId = definitionId;
+ }
+
+ public ObjectId getTestDefinitionDeployerId() {
+ return testDefinitionDeployerId;
+ }
+
+ public void setTestDefinitionDeployerId(ObjectId testDefinitionDeployerId) {
+ this.testDefinitionDeployerId = testDefinitionDeployerId;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public String getDefinitionId() {
+ return definitionId;
+ }
+
+ public void setDefinitionId(String definitionId) {
+ this.definitionId = definitionId;
+ }
+
+ @Override
+ public String toString() {
+ return "{\"DeployTestStrategyRequest\":{"
+ + "\"testDefinitionDeployerId\":\""
+ + testDefinitionDeployerId
+ + "\""
+ + ", \"testDefinitionId\":\""
+ + testDefinitionId
+ + "\""
+ + ", \"definitionId\":\""
+ + definitionId
+ + "\""
+ + "}}";
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/OTFApiResponse.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/OTFApiResponse.java
new file mode 100644
index 0000000..e4f959e
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/OTFApiResponse.java
@@ -0,0 +1,66 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+
+import java.util.Date;
+
+public class OTFApiResponse {
+
+ private int statusCode;
+ private String message;
+ private Date time;
+
+ public OTFApiResponse() {
+ }
+
+ public OTFApiResponse(int statusCode, String message) {
+ this.statusCode = statusCode;
+ this.message = message;
+ this.time = new Date(System.currentTimeMillis());
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Date getTime() {
+ return time;
+ }
+
+ public void setTime(Date time) {
+ this.time = time;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/ParallelFlowInput.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ParallelFlowInput.java
new file mode 100644
index 0000000..2ac94e1
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ParallelFlowInput.java
@@ -0,0 +1,83 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class ParallelFlowInput implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private List<WorkflowRequest> args;
+ private boolean interruptOnFailure;
+ private int maxFailures;
+ private int threadPoolSize;
+
+ public ParallelFlowInput() {}
+
+ public ParallelFlowInput(
+ List<WorkflowRequest> args, boolean interruptOnFailure, int maxFailures, int threadPoolSize) {
+ this.args = args;
+ this.interruptOnFailure = interruptOnFailure;
+ this.maxFailures = maxFailures;
+ this.threadPoolSize = threadPoolSize;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public List<WorkflowRequest> getArgs() {
+ return args;
+ }
+
+ public void setArgs(List<WorkflowRequest> args) {
+ this.args = args;
+ }
+
+ public boolean isInterruptOnFailure() {
+ return interruptOnFailure;
+ }
+
+ public void setInterruptOnFailure(boolean interruptOnFailure) {
+ this.interruptOnFailure = interruptOnFailure;
+ }
+
+ public int getMaxFailures() {
+ return maxFailures;
+ }
+
+ public void setMaxFailures(int maxFailures) {
+ this.maxFailures = maxFailures;
+ }
+
+ public int getThreadPoolSize() {
+ return threadPoolSize;
+ }
+
+ public void setThreadPoolSize(int threadPoolSize) {
+ this.threadPoolSize = threadPoolSize;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/PfloNode.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/PfloNode.java
new file mode 100644
index 0000000..d8a8bd5
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/PfloNode.java
@@ -0,0 +1,61 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+
+import java.io.Serializable;
+
+public class PfloNode implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private String bpmnPlfoTaskId;
+ private String label;
+
+ public PfloNode() {}
+
+ public PfloNode(String bpmnPlfoTaskId, String label) {
+ this.bpmnPlfoTaskId = bpmnPlfoTaskId;
+ this.label = label;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public String getBpmnPlfoTaskId() {
+ return bpmnPlfoTaskId;
+ }
+
+ public void setBpmnPlfoTaskId(String bpmnPlfoTaskId) {
+ this.bpmnPlfoTaskId = bpmnPlfoTaskId;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadNode.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadNode.java
new file mode 100644
index 0000000..99ed995
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadNode.java
@@ -0,0 +1,58 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import org.bson.types.ObjectId;
+
+public class TestHeadNode implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId testHeadId;
+ private String bpmnVthTaskId;
+
+ public TestHeadNode() {
+ }
+
+ public TestHeadNode(ObjectId testHeadId, String taskId) {
+ this.testHeadId = testHeadId;
+ this.bpmnVthTaskId = taskId;
+ }
+
+ public ObjectId getTestHeadId() {
+ return testHeadId;
+ }
+
+ public void setTestHeadId(ObjectId testHeadId) {
+ this.testHeadId = testHeadId;
+ }
+
+ public String getBpmnVthTaskId() {
+ return bpmnVthTaskId;
+ }
+
+ public void setBpmnVthTaskId(String bpmnVthTaskId) {
+ this.bpmnVthTaskId = bpmnVthTaskId;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadRequest.java
new file mode 100644
index 0000000..89c7457
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadRequest.java
@@ -0,0 +1,53 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import java.io.Serializable;
+import java.util.Map;
+
+public class TestHeadRequest implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private Map<String, String> headers;
+ private Map<String, Object> body;
+
+ public TestHeadRequest(){}
+
+ public TestHeadRequest(Map<String, String> headers,
+ Map<String, Object> body) {
+ this.headers = headers;
+ this.body = body;
+ }
+
+ public Map<String, String> getHeaders() {
+ return headers;
+ }
+
+ public void setHeaders(Map<String, String> headers) {
+ this.headers = headers;
+ }
+
+ public Map<String, Object> getBody() {
+ return body;
+ }
+
+ public void setBody(Map<String, Object> body) {
+ this.body = body;
+ }
+
+
+
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadResult.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadResult.java
new file mode 100644
index 0000000..55f82e9
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadResult.java
@@ -0,0 +1,146 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import org.bson.types.ObjectId;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+public class TestHeadResult implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId testHeadId;
+ private String testHeadName;
+ private ObjectId testHeadGroupId;
+ private String bpmnVthTaskId;
+
+ //TODO: RG Remove maps below, setters and getters to return to normal
+ //private Map<String, String> testHeadHeaders;
+ //private int testHeadCode;
+ private int statusCode;
+
+ private TestHeadRequest testHeadRequest;
+ private Map<String, Object> testHeadResponse;
+ private Date startTime;
+ private Date endTime;
+
+ public TestHeadResult() {
+ }
+
+ public TestHeadResult(
+ ObjectId testHeadId,
+ String testHeadName,
+ ObjectId testHeadGroupId,
+ String bpmnVthTaskId,
+
+ //TODO: RG changed code to int and changed testHeadRequest from Map<String, String> to RequestContent
+ int statusCode,
+
+ TestHeadRequest testHeadRequest,
+ Map<String, Object> testHeadResponse,
+ Date startTime,
+ Date endTime) {
+ this.testHeadId = testHeadId;
+ this.testHeadName = testHeadName;
+ this.testHeadGroupId = testHeadGroupId;
+ this.bpmnVthTaskId = bpmnVthTaskId;
+
+ //this.testHeadHeaders = testHeadHeaders;
+ this.statusCode = statusCode;
+
+ this.testHeadRequest = testHeadRequest;
+ this.testHeadResponse = testHeadResponse;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ }
+
+ public int getStatusCode(){return statusCode;}
+ public void setStatusCode(int testHeadCode){this.statusCode = statusCode;}
+
+ public ObjectId getTestHeadId() {
+ return testHeadId;
+ }
+
+ public void setTestHeadId(ObjectId testHeadId) {
+ this.testHeadId = testHeadId;
+ }
+
+ public String getTestHeadName() {
+ return testHeadName;
+ }
+
+ public void setTestHeadName(String testHeadName) {
+ this.testHeadName = testHeadName;
+ }
+
+ public ObjectId getTestHeadGroupId() {
+ return testHeadGroupId;
+ }
+
+ public void setTestHeadGroupId(ObjectId testHeadGroupId) {
+ this.testHeadGroupId = testHeadGroupId;
+ }
+
+ public String getBpmnVthTaskId() {
+ return bpmnVthTaskId;
+ }
+
+ public void setBpmnVthTaskId(String bpmnVthTaskId) {
+ this.bpmnVthTaskId = bpmnVthTaskId;
+ }
+
+ public TestHeadRequest getTestHeadRequest() {
+ return testHeadRequest;
+ }
+
+ public void setTestHeadRequest(TestHeadRequest testHeadRequest) {
+ this.testHeadRequest = testHeadRequest;
+ }
+
+ public Map<String, Object> getTestHeadResponse() {
+ return testHeadResponse;
+ }
+
+ public void setTestHeadResponse(Map<String, Object> testHeadResponse) {
+ this.testHeadResponse = testHeadResponse;
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestInstanceCreateRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestInstanceCreateRequest.java
new file mode 100644
index 0000000..b497477
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestInstanceCreateRequest.java
@@ -0,0 +1,215 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import com.google.common.base.Strings;
+import java.io.Serializable;
+import java.util.HashMap;
+import org.bson.types.ObjectId;
+
+public class TestInstanceCreateRequest implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId testDefinitionId = null;
+ private int version = Integer.MIN_VALUE;
+ private String processDefinitionKey = null;
+
+ private String testInstanceName;
+ private String testInstanceDescription;
+ private HashMap<String, ParallelFlowInput> pfloInput;
+ private HashMap<String, Object> simulationVthInput;
+ private HashMap<String, Object> testData;
+ private HashMap<String, Object> vthInput;
+ private ObjectId createdBy;
+ private boolean useLatestTestDefinition = true;
+ private boolean simulationMode = false;
+ private long maxExecutionTimeInMillis = 0L;
+
+ public TestInstanceCreateRequest() throws Exception {
+ this.validate();
+ }
+
+ public TestInstanceCreateRequest(
+ String testInstanceName,
+ String testInstanceDescription,
+ HashMap<String, ParallelFlowInput> pfloInput,
+ HashMap<String, Object> simulationVthInput,
+ HashMap<String, Object> testData,
+ HashMap<String, Object> vthInput,
+ ObjectId createdBy,
+ boolean useLatestTestDefinition,
+ boolean simulationMode,
+ long maxExecutionTimeInMillis) throws Exception {
+ this.testInstanceName = testInstanceName;
+ this.testInstanceDescription = testInstanceDescription;
+ this.pfloInput = pfloInput;
+ this.simulationVthInput = simulationVthInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.createdBy = createdBy;
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ this.simulationMode = simulationMode;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+
+ this.validate();
+ }
+
+ private void validate() throws Exception {
+ String missingFieldFormat = "The field %s is required.";
+ if (Strings.isNullOrEmpty(testInstanceName)) {
+ throw new Exception(String.format(missingFieldFormat, "testInstanceName"));
+ }
+
+ if (Strings.isNullOrEmpty(testInstanceDescription)) {
+ throw new Exception(String.format(missingFieldFormat, "testInstanceDescription"));
+ }
+
+ if (pfloInput == null) {
+ pfloInput = new HashMap<>();
+ }
+
+ if (simulationVthInput == null) {
+ simulationVthInput = new HashMap<>();
+ }
+
+ if (testData == null) {
+ testData = new HashMap<>();
+ }
+
+ if (vthInput == null) {
+ vthInput = new HashMap<>();
+ }
+
+ if (this.maxExecutionTimeInMillis < 0L) {
+ this.maxExecutionTimeInMillis = 0L;
+ }
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public String getProcessDefinitionKey() {
+ return processDefinitionKey;
+ }
+
+ public void setProcessDefinitionKey(String processDefinitionKey) {
+ this.processDefinitionKey = processDefinitionKey;
+ }
+
+ public String getTestInstanceName() {
+ return testInstanceName;
+ }
+
+ public void setTestInstanceName(String testInstanceName) {
+ this.testInstanceName = testInstanceName;
+ }
+
+ public String getTestInstanceDescription() {
+ return testInstanceDescription;
+ }
+
+ public void setTestInstanceDescription(String testInstanceDescription) {
+ this.testInstanceDescription = testInstanceDescription;
+ }
+
+ public HashMap<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(HashMap<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public HashMap<String, Object> getSimulationVthInput() {
+ return simulationVthInput;
+ }
+
+ public void setSimulationVthInput(HashMap<String, Object> simulationVthInput) {
+ this.simulationVthInput = simulationVthInput;
+ }
+
+ public HashMap<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(HashMap<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public HashMap<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(HashMap<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public boolean isUseLatestTestDefinition() {
+ return useLatestTestDefinition;
+ }
+
+ public void setUseLatestTestDefinition(boolean useLatestTestDefinition) {
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ }
+
+ public boolean isSimulationMode() {
+ return simulationMode;
+ }
+
+ public void setSimulationMode(boolean simulationMode) {
+ this.simulationMode = simulationMode;
+ }
+
+ public long getMaxExecutionTimeInMillis() {
+ return maxExecutionTimeInMillis;
+ }
+
+ public void setMaxExecutionTimeInMillis(long maxExecutionTimeInMillis) {
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/UserGroup.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/UserGroup.java
new file mode 100644
index 0000000..536bc67
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/UserGroup.java
@@ -0,0 +1,57 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.List;
+import org.bson.types.ObjectId;
+
+public class UserGroup implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId groupId;
+ private List<String> permissions;
+
+ public UserGroup(){}
+ public UserGroup(ObjectId groupId, List<String> permissions) {
+ this.groupId = groupId;
+ this.permissions = permissions;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(List<String> permissions) {
+ this.permissions = permissions;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/WorkflowRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/WorkflowRequest.java
new file mode 100644
index 0000000..f7089a0
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/WorkflowRequest.java
@@ -0,0 +1,163 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import java.io.Serializable;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class WorkflowRequest implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean async = false;
+ private ObjectId executorId = null;
+ private ObjectId testInstanceId = null;
+ private Map<String, ParallelFlowInput> pfloInput = null;
+ private Map<String, Object> testData = null;
+ private Map<String, Object> vthInput = null;
+ private long maxExecutionTimeInMillis = 0L;
+
+ public WorkflowRequest() throws Exception {
+ this.validate();
+ }
+
+ public WorkflowRequest(
+ boolean async,
+ ObjectId executorId,
+ ObjectId testInstanceId,
+ Map<String, ParallelFlowInput> pfloInput,
+ Map<String, Object> testData,
+ Map<String, Object> vthInput,
+ int maxExecutionTimeInMillis)
+ throws Exception {
+ this.async = async;
+ this.executorId = executorId;
+ this.testInstanceId = testInstanceId;
+ this.pfloInput = pfloInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+
+ this.validate();
+ }
+
+ public WorkflowRequest(
+ boolean async,
+ String executorId,
+ String testInstanceId,
+ Map<String, ParallelFlowInput> pfloInput,
+ Map<String, Object> testData,
+ Map<String, Object> vthInput,
+ int maxExecutionTimeInMillis)
+ throws Exception {
+ this.async = async;
+ this.executorId = new ObjectId(executorId);
+ this.testInstanceId = new ObjectId(testInstanceId);
+ this.pfloInput = pfloInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+
+ this.validate();
+ }
+
+ private void validate() throws Exception {
+ String missingFieldFormat = "Missing required field %s.";
+ // if (this.async && this.asyncTopic == null) {
+ // throw new Exception(String.format(missingFieldFormat, "asyncTopic"));
+ // }
+
+ // Only required on the Camunda engine
+ // if (this.executorId == null) {
+ // throw new Exception(String.format(missingFieldFormat, "executorId"));
+ // }
+
+ // Only required on the Camunda engine
+ // if (this.testInstanceId == null) {
+ // throw new Exception(String.format(missingFieldFormat, "testInstanceId"));
+ // }
+
+ if (this.maxExecutionTimeInMillis < 0L) {
+ this.maxExecutionTimeInMillis = 0L;
+ }
+ }
+
+ public boolean isAsync() {
+ return async;
+ }
+
+ public void setAsync(boolean async) {
+ this.async = async;
+ }
+
+ public ObjectId getExecutorId() {
+ return executorId;
+ }
+
+ public void setExecutorId(ObjectId executorId) {
+ this.executorId = executorId;
+ }
+
+ public ObjectId getTestInstanceId() {
+ return testInstanceId;
+ }
+
+ public void setTestInstanceId(ObjectId testInstanceId) {
+ this.testInstanceId = testInstanceId;
+ }
+
+ public Map<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(Map<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public Map<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(Map<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public Map<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(Map<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public long getMaxExecutionTimeInMillis() {
+ return maxExecutionTimeInMillis;
+ }
+
+ public void setMaxExecutionTimeInMillis(long maxExecutionTimeInMillis) {
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/GroupRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/GroupRepository.java
new file mode 100644
index 0000000..69d000c
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/GroupRepository.java
@@ -0,0 +1,31 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.Group;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+
+import java.util.List;
+
+public interface GroupRepository extends MongoRepository<Group, String> {
+ @Query("{ 'members.userId': ?0 }")
+ public List<Group> findAllByMembersId(ObjectId membersUserId);
+ public Group findFirstByGroupName(String groupName);
+}
+
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestDefinitionRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestDefinitionRepository.java
new file mode 100644
index 0000000..ecd2bab
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestDefinitionRepository.java
@@ -0,0 +1,26 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestDefinition;
+import java.util.Optional;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface TestDefinitionRepository extends MongoRepository<TestDefinition, String> {
+
+ Optional<TestDefinition> findByProcessDefinitionKey(String processDefinitionKey);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestExecutionRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestExecutionRepository.java
new file mode 100644
index 0000000..ee86a82
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestExecutionRepository.java
@@ -0,0 +1,26 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestExecution;
+import java.util.Optional;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface TestExecutionRepository extends MongoRepository<TestExecution, String> {
+
+ Optional<TestExecution> findFirstByProcessInstanceId(String processInstanceId);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestHeadRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestHeadRepository.java
new file mode 100644
index 0000000..09ab4ac
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestHeadRepository.java
@@ -0,0 +1,28 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestHead;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.Optional;
+
+public interface TestHeadRepository extends MongoRepository<TestHead, String> {
+ Optional<TestHead> findByTestHeadName(String testHeadName);
+
+
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestInstanceRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestInstanceRepository.java
new file mode 100644
index 0000000..16d1dcb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestInstanceRepository.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestInstance;
+import java.util.List;
+import java.util.Optional;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+
+public interface TestInstanceRepository extends MongoRepository<TestInstance, String> {
+
+ Optional<TestInstance> findByTestInstanceName(String testInstanceName);
+
+ @Query("{ 'testDefinitionId': ?0 }")
+ List<TestInstance> findAllByTestDefinitionId(ObjectId testDefinitionId);
+
+ @Query("{ 'testDefinitionId': ?0, 'processDefinitionId': ?1 }")
+ List<TestInstance> findAllByTestDefinitionIdAndPDId(
+ ObjectId testDefinitionId, String processDefinitionId);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/UserRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/UserRepository.java
new file mode 100644
index 0000000..5dd669f
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/UserRepository.java
@@ -0,0 +1,25 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.User;
+import java.util.Optional;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface UserRepository extends MongoRepository<User, String> {
+ Optional<User> findFirstByEmail(String email);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/util/HttpUtils.java b/otf-service-api/src/main/java/org/oran/otf/common/util/HttpUtils.java
new file mode 100644
index 0000000..b5e3a39
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/util/HttpUtils.java
@@ -0,0 +1,19 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.util;
+
+public class HttpUtils {}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/RSAEncryptDecrypt.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/RSAEncryptDecrypt.java
new file mode 100644
index 0000000..1309d6d
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/RSAEncryptDecrypt.java
@@ -0,0 +1,54 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import org.springframework.stereotype.Service;
+
+@Service
+public class RSAEncryptDecrypt {
+
+ private KeyPair keyPair;
+
+ public RSAEncryptDecrypt() throws NoSuchAlgorithmException {
+ this.keyPair = buildKeyPair();
+ }
+
+ private KeyPair buildKeyPair() throws NoSuchAlgorithmException {
+ final int keySize = 2048;
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(keySize);
+ return keyPairGenerator.genKeyPair();
+ }
+
+ public byte[] encrypt(String message) throws Exception {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, this.keyPair.getPrivate());
+
+ return cipher.doFinal(message.getBytes());
+ }
+
+ public byte[] decrypt(byte[] encrypted) throws Exception {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.DECRYPT_MODE, this.keyPair.getPublic());
+
+ return cipher.doFinal(encrypted);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/Utility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/Utility.java
new file mode 100644
index 0000000..c781ffb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/Utility.java
@@ -0,0 +1,84 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class Utility {
+
+ public static String getLoggerPrefix() {
+ return "[" + Thread.currentThread().getStackTrace()[2].getMethodName() + "]: ";
+ }
+
+ public static Map<?, ?> toMap(Object obj) throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ return mapper.convertValue(obj, HashMap.class);
+ }
+
+ public static boolean isCollection(Object obj) {
+ return obj.getClass().isArray() || obj instanceof Collection;
+ }
+
+ public static List<?> toList(Object obj) {
+ if (obj == null) {
+ throw new NullPointerException("Argument cannot be null.");
+ }
+
+ List<?> list = new ArrayList<>();
+ if (obj.getClass().isArray()) {
+ list = Arrays.asList((Object[]) obj);
+ } else if (obj instanceof Collection) {
+ list = new ArrayList<>((Collection<?>) obj);
+ }
+
+ return list;
+ }
+
+ public static boolean isValidUuid(String str) {
+ if (Strings.isNullOrEmpty(str)) {
+ return false;
+ }
+ try {
+ UUID uuid = UUID.fromString(str);
+ return uuid.toString().equalsIgnoreCase(str);
+ } catch (IllegalArgumentException iae) {
+ return false;
+ }
+ }
+
+ // check a name type pair to see if it matches field in class
+ public static boolean isTypeVariablePairInClass(String variableName, Object variableValue, Class javaClass){
+ List<Field> testHeadFields = Arrays.asList(javaClass.getFields());
+ for(int i = 0; i < testHeadFields.size(); i++){
+ Field field = testHeadFields.get(i);
+ if(field.getName().equals(variableName) && field.getType().isInstance(variableValue)){
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/database/Generic.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/Generic.java
new file mode 100644
index 0000000..5de5043
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/Generic.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.database;
+
+import java.util.Optional;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public class Generic {
+
+ public static <T> boolean identifierExistsInCollection(
+ MongoRepository<T, String> repository, ObjectId identifier) {
+ return repository.findById(identifier.toString()).isPresent();
+ }
+
+ public static <T> T findByIdGeneric(MongoRepository<T, String> repository, ObjectId identifier) {
+ Optional<T> optionalObj = repository.findById(identifier.toString());
+ return optionalObj.orElse(null);
+ }
+
+
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/database/TestExecutionUtility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/TestExecutionUtility.java
new file mode 100644
index 0000000..c54359f
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/TestExecutionUtility.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.database;
+
+import org.oran.otf.common.model.TestExecution;
+import com.mongodb.client.result.UpdateResult;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+public class TestExecutionUtility {
+
+ public static void saveTestResult(
+ MongoTemplate mongoOperation, TestExecution execution, String testResult) {
+ Query query = new Query();
+ query.addCriteria(Criteria.where("businessKey").is(execution.getBusinessKey()));
+ Update update = new Update();
+ update.set("testResult", testResult);
+ UpdateResult result = mongoOperation.updateFirst(query, update, TestExecution.class);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/Convert.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/Convert.java
new file mode 100644
index 0000000..bc1d0af
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/Convert.java
@@ -0,0 +1,95 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.gson;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+public class Convert {
+
+ private static final GsonBuilder gsonBuilder =
+ new GsonBuilder()
+ .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
+ .registerTypeAdapter(
+ ObjectId.class,
+ new JsonSerializer<ObjectId>() {
+ @Override
+ public JsonElement serialize(
+ ObjectId src, Type typeOfSrc, JsonSerializationContext context) {
+ return new JsonPrimitive(src.toHexString());
+ }
+ })
+ .registerTypeAdapter(
+ ObjectId.class,
+ new JsonDeserializer<ObjectId>() {
+ @Override
+ public ObjectId deserialize(
+ JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ return new ObjectId(json.getAsString());
+ }
+ });
+
+ public static Gson getGson() {
+ return gsonBuilder.create();
+ }
+
+ public static String mapToJson(Map map) {
+ if (map.isEmpty()) {
+ return "{}";
+ }
+ return getGson().toJson(map);
+ }
+
+ public static Map<String, Object> jsonToMap(String json) {
+ Type type = new TypeToken<HashMap<String, Object>>() {
+ }.getType();
+ return getGson().fromJson(json, type);
+ }
+
+ public static String objectToJson(Object obj) {
+ return getGson().toJson(obj);
+ }
+
+ public static<T> T mapToObject(Map map, TypeReference<T> typeReference) throws IOException {
+ return jsonToObject(mapToJson(map), typeReference);
+ }
+
+ public static <T> T jsonToObject(String json, TypeReference<T> typeReference) throws IOException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
+ return objectMapper.readValue(json, typeReference);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/GsonUtils.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/GsonUtils.java
new file mode 100644
index 0000000..1b224fc
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/GsonUtils.java
@@ -0,0 +1,69 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.gson;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+public class GsonUtils {
+ private static final GsonBuilder gsonBuilder =
+ new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
+ .registerTypeAdapter(ObjectId.class, new JsonSerializer<ObjectId>() {
+ @Override
+ public JsonElement serialize(ObjectId src, Type typeOfSrc,
+ JsonSerializationContext context) {
+ return new JsonPrimitive(src.toHexString());
+ }
+ }).registerTypeAdapter(ObjectId.class, new JsonDeserializer<ObjectId>() {
+ @Override
+ public ObjectId deserialize(JsonElement json, Type typeOfT,
+ JsonDeserializationContext context) throws JsonParseException {
+ return new ObjectId(json.getAsString());
+ }
+ });
+
+ public static Gson getGson() {
+ return gsonBuilder.create();
+ }
+
+ private static final Gson gson = getGson();
+ private static final Type TT_mapStringString = new TypeToken<Map<String,String>>(){}.getType();
+
+ public static Map<String, String> jsonToMapStringString(String json) {
+ Map<String, String> ret = new HashMap<String, String>();
+ if (json == null || json.isEmpty())
+ return ret;
+ return gson.fromJson(json, TT_mapStringString);
+ }
+ public static String mapStringObjectToJson(Map<String, Object> map) {
+ if (map == null)
+ map = new HashMap<String, Object>();
+ return gson.toJson(map);
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/http/RequestUtility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/RequestUtility.java
new file mode 100644
index 0000000..2af3f90
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/RequestUtility.java
@@ -0,0 +1,160 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.http;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RequestUtility {
+
+ private static Logger logger = LoggerFactory.getLogger(RequestUtility.class);
+
+ public static void postAsync(String url, String body, Map<String, String> headers)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpPost post = buildPost(url, body, headers);
+ executeAsync(post);
+ }
+
+ public static HttpResponse postSync(String url, String body, Map<String, String> headers)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpPost post = buildPost(url, body, headers);
+ return executeSync(post);
+ }
+
+ public static HttpResponse postSync(
+ String url, String body, Map<String, String> headers, int timeoutInMillis)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpPost post = buildPost(url, body, headers);
+ return executeSync(post, timeoutInMillis);
+ }
+
+ public static HttpResponse getSync(String url, Map<String, String> headers)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpGet get = buildGet(url, headers);
+ return executeSync(get);
+ }
+
+ public static HttpResponse getSync(String url, Map<String, String> headers, int timeoutInMillis)
+ throws IOException, InterruptedException, ExecutionException {
+ if (timeoutInMillis < 0) {
+ throw new IllegalArgumentException("The timeoutInMillis must be a value greater than 0.");
+ }
+
+ HttpGet get = buildGet(url, headers);
+ return executeSync(get, timeoutInMillis);
+ }
+
+ public static void getAsync(String url, Map<String, String> headers) throws IOException {
+ HttpGet get = buildGet(url, headers);
+ executeAsync(get);
+ }
+
+ private static HttpPost buildPost(String url, String body, Map<String, String> headers)
+ throws UnsupportedEncodingException {
+ if (Strings.isNullOrEmpty(url) || Strings.isNullOrEmpty(body)) {
+ return null;
+ } else if (headers == null) {
+ headers = new HashMap<>();
+ }
+
+ HttpPost post = new HttpPost(url);
+ headers.forEach(post::setHeader);
+ post.setEntity(new StringEntity(body));
+ return post;
+ }
+
+ private static HttpGet buildGet(String url, Map<String, String> headers) {
+ if (Strings.isNullOrEmpty(url)) {
+ return null;
+ } else if (headers == null) {
+ headers = new HashMap<>();
+ }
+
+ HttpGet get = new HttpGet(url);
+ headers.forEach(get::setHeader);
+ return get;
+ }
+
+ private static HttpResponse executeSync(HttpRequestBase request)
+ throws IOException, InterruptedException, ExecutionException {
+ CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
+ try {
+ httpClient.start();
+ Future<HttpResponse> future = httpClient.execute(request, null);
+ return future.get();
+ } finally {
+ httpClient.close();
+ }
+ }
+
+ private static HttpResponse executeSync(HttpRequestBase request, int timeoutInMillis)
+ throws IOException, InterruptedException, ExecutionException {
+ if (timeoutInMillis < 0) {
+ throw new IllegalArgumentException("The timeoutInMillis must be a value greater than 0.");
+ }
+
+ // Create a timer task that will abort the task (the request) after the specified time. This
+ // task will run *timeoutInMillis* ms
+ TimerTask task =
+ new TimerTask() {
+ @Override
+ public void run() {
+ if (request != null) {
+ request.abort();
+ }
+ }
+ };
+
+ CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
+ try {
+ httpClient.start();
+ // Start the timer before making the request.
+ new Timer(true).schedule(task, timeoutInMillis);
+ Future<HttpResponse> future = httpClient.execute(request, null);
+ return future.get();
+ } finally {
+ httpClient.close();
+ }
+ }
+
+ private static void executeAsync(HttpRequestBase request) throws IOException {
+ CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
+ try {
+ httpClient.start();
+ httpClient.execute(request, null);
+ logger.debug("Sent asynchronous request.");
+ } finally {
+ httpClient.close();
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/http/ResponseUtility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/ResponseUtility.java
new file mode 100644
index 0000000..919897c
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/ResponseUtility.java
@@ -0,0 +1,107 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.http;
+
+import org.oran.otf.common.model.local.OTFApiResponse;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+public class ResponseUtility {
+
+ public static class Build {
+
+ public static Response okRequest() {
+ return Response.ok().build();
+ }
+
+ public static Response badRequest() {
+ return Response.status(400).build();
+ }
+
+ public static Response okRequestWithMessage(String msg) {
+ return Response.status(200)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(200, msg))
+ .build();
+ }
+
+ public static Response okRequestWithObject(Object obj) {
+ return Response.status(200).type(MediaType.APPLICATION_JSON).entity(obj).build();
+ }
+
+ public static Response badRequestWithMessage(String msg) {
+ return Response.status(400)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(400, msg))
+ .build();
+ }
+
+ public static Response internalServerError() {
+ return Response.status(500).build();
+ }
+
+ public static Response internalServerErrorWithMessage(String msg) {
+ return Response.status(500)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(500, msg))
+ .build();
+ }
+
+ public static Response unauthorized() {
+ return Response.status(401).build();
+ }
+ public static Response unauthorizedWithMessage(String msg) {
+ return Response.status(401)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(401, msg))
+ .build();
+ }
+
+ public static Response notFoundWithMessage(String msg) {
+ return Response.status(404)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(404, msg))
+ .build();
+ }
+
+ public static Response serviceUnavailableWithMessage(String msg) {
+ return Response.status(503)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(503, msg))
+ .build();
+ }
+
+ public static Response serviceUnavailable() {
+ return Response.status(503).build();
+ }
+
+ public static Response genericWithCode(int code) {
+ return Response.status(code).build();
+ }
+
+ public static Response genericWithMessage(int code, String msg) {
+ return Response.status(code)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(code, msg))
+ .build();
+ }
+
+ public static Response genericWithObject(int code, Object obj) {
+ return Response.status(code).type(MediaType.APPLICATION_JSON).entity(obj).build();
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/ErrorCode.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/ErrorCode.java
new file mode 100644
index 0000000..8327a81
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/ErrorCode.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.logger;
+
+public enum ErrorCode {
+ PermissionError(100),
+ AvailabilityError(200),
+ DataError(300),
+ SchemaError(400),
+ BusinessProcesssError(500),
+ UnknownError(900);
+
+ private int value;
+
+ ErrorCode(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return this.value;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/LoggerStartupListener.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/LoggerStartupListener.java
new file mode 100644
index 0000000..10c45d8
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/LoggerStartupListener.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * 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.oran.otf.common.utility.logger;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.LoggerContextListener;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.spi.ContextAwareBase;
+import ch.qos.logback.core.spi.LifeCycle;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class LoggerStartupListener extends ContextAwareBase
+ implements LoggerContextListener, LifeCycle {
+
+ private static final Logger logger = LoggerFactory.getLogger(LoggerStartupListener.class);
+ private boolean started = false;
+
+ @Override
+ public void start() {
+ if (started) {
+ return;
+ }
+ InetAddress addr = null;
+ try {
+ addr = InetAddress.getLocalHost();
+ } catch (UnknownHostException e) {
+ logger.error("UnknownHostException", e);
+ }
+ Context context = getContext();
+ if (addr != null) {
+ context.putProperty("server.name", addr.getHostName());
+ }
+ started = true;
+ }
+
+ @Override
+ public void stop() {
+ }
+
+ @Override
+ public boolean isStarted() {
+ return started;
+ }
+
+ @Override
+ public boolean isResetResistant() {
+ return true;
+ }
+
+ @Override
+ public void onReset(LoggerContext arg0) {
+ }
+
+ @Override
+ public void onStart(LoggerContext arg0) {
+ }
+
+ @Override
+ public void onStop(LoggerContext arg0) {
+ }
+
+ @Override
+ public void onLevelChange(ch.qos.logback.classic.Logger logger, Level level) {
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/MessageEnum.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/MessageEnum.java
new file mode 100644
index 0000000..1103c53
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/MessageEnum.java
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oran.otf.common.utility.logger;
+
+
+public enum MessageEnum {
+ // Api Handler Messages
+ APIH_REQUEST_NULL, APIH_QUERY_FOUND, APIH_QUERY_NOT_FOUND, APIH_QUERY_PARAM_WRONG, APIH_DB_ACCESS_EXC, APIH_DB_ACCESS_EXC_REASON, APIH_VALIDATION_ERROR, APIH_REQUEST_VALIDATION_ERROR, APIH_SERVICE_VALIDATION_ERROR, APIH_GENERAL_EXCEPTION_ARG, APIH_GENERAL_EXCEPTION, APIH_GENERAL_WARNING, APIH_AUDIT_EXEC, APIH_GENERAL_METRICS, APIH_DUPLICATE_CHECK_EXC, APIH_DUPLICATE_FOUND, APIH_BAD_ORDER, APIH_DB_ATTRIBUTE_NOT_FOUND, APIH_BPEL_COMMUNICATE_ERROR, APIH_BPEL_RESPONSE_ERROR, APIH_WARP_REQUEST, APIH_ERROR_FROM_BPEL_SERVER, APIH_DB_INSERT_EXC, APIH_DB_UPDATE_EXC, APIH_NO_PROPERTIES, APIH_PROPERTY_LOAD_SUC, APIH_LOAD_PROPERTIES_FAIL, APIH_SDNC_COMMUNICATE_ERROR, APIH_SDNC_RESPONSE_ERROR, APIH_CANNOT_READ_SCHEMA, APIH_HEALTH_CHECK_EXCEPTION, APIH_REQUEST_VALIDATION_ERROR_REASON, APIH_JAXB_MARSH_ERROR, APIH_JAXB_UNMARSH_ERROR, APIH_VNFREQUEST_VALIDATION_ERROR, APIH_DOM2STR_ERROR, APIH_READ_VNFOUTPUT_CLOB_EXCEPTION, APIH_DUPLICATE_CHECK_EXC_ATT, APIH_GENERATED_REQUEST_ID, APIH_GENERATED_SERVICE_INSTANCE_ID, APIH_REPLACE_REQUEST_ID,
+ // Resource Adapter Messages
+ RA_GENERAL_EXCEPTION_ARG, RA_GENERAL_EXCEPTION, RA_GENERAL_WARNING, RA_MISSING_PARAM, RA_AUDIT_EXEC, RA_GENERAL_METRICS, RA_CREATE_STACK_TIMEOUT, RA_DELETE_STACK_TIMEOUT, RA_UPDATE_STACK_TIMEOUT, RA_CONNECTION_EXCEPTION, RA_PARSING_ERROR, RA_PROPERTIES_NOT_FOUND, RA_LOAD_PROPERTIES_SUC, RA_NETWORK_ALREADY_EXIST, RA_UPDATE_NETWORK_ERR, RA_CREATE_STACK_ERR, RA_UPDATE_STACK_ERR, RA_CREATE_TENANT_ERR, RA_NETWORK_NOT_FOUND, RA_NETWORK_ORCHE_MODE_NOT_SUPPORT, RA_CREATE_NETWORK_EXC, RA_NS_EXC, RA_PARAM_NOT_FOUND, RA_CONFIG_EXC, RA_UNKOWN_PARAM, RA_VLAN_PARSE, RA_DELETE_NETWORK_EXC, RA_ROLLBACK_NULL, RA_TENANT_NOT_FOUND, RA_QUERY_NETWORK_EXC, RA_CREATE_NETWORK_NOTIF_EXC, RA_ASYNC_ROLLBACK, RA_WSDL_NOT_FOUND, RA_WSDL_URL_CONVENTION_EXC, RA_INIT_NOTIF_EXC, RA_SET_CALLBACK_AUTH_EXC, RA_FAULT_INFO_EXC, RA_MARSHING_ERROR, RA_PARSING_REQUEST_ERROR, RA_SEND_REQUEST_SDNC, RA_RESPONSE_FROM_SDNC, RA_EXCEPTION_COMMUNICATE_SDNC, RA_EVALUATE_XPATH_ERROR, RA_ANALYZE_ERROR_EXC, RA_ERROR_GET_RESPONSE_SDNC, RA_CALLBACK_BPEL, RA_INIT_CALLBACK_WSDL_ERR, RA_CALLBACK_BPEL_EXC, RA_CALLBACK_BPEL_COMPLETE, RA_SDNC_MISS_CONFIG_PARAM, RA_SDNC_INVALID_CONFIG, RA_PRINT_URL, RA_ERROR_CREATE_SDNC_REQUEST, RA_ERROR_CREATE_SDNC_RESPONSE, RA_ERROR_CONVERT_XML2STR, RA_RECEIVE_SDNC_NOTIF, RA_INIT_SDNC_ADAPTER, RA_SEND_REQUEST_APPC_ERR, RA_SEND_REQUEST_SDNC_ERR, RA_RECEIVE_BPEL_REQUEST, RA_TENANT_ALREADY_EXIST, RA_UPDATE_TENANT_ERR, RA_DELETE_TEMAMT_ERR, RA_ROLLBACK_TENANT_ERR, RA_QUERY_VNF_ERR, RA_VNF_ALREADY_EXIST, RA_VNF_UNKNOWN_PARAM, RA_VNF_EXTRA_PARAM, RA_CREATE_VNF_ERR, RA_VNF_NOT_EXIST, RA_UPDATE_VNF_ERR, RA_DELETE_VNF_ERR, RA_ASYNC_CREATE_VNF, RA_SEND_VNF_NOTIF_ERR, RA_ASYNC_CREATE_VNF_COMPLETE, RA_ASYNC_UPDATE_VNF, RA_ASYNC_UPDATE_VNF_COMPLETE, RA_ASYNC_QUERY_VNF, RA_ASYNC_QUERY_VNF_COMPLETE, RA_ASYNC_DELETE_VNF, RA_ASYNC_DELETE_VNF_COMPLETE, RA_ASYNC_ROLLBACK_VNF, RA_ASYNC_ROLLBACK_VNF_COMPLETE, RA_ROLLBACK_VNF_ERR, RA_DB_INVALID_STATUS, RA_CANT_UPDATE_REQUEST, RA_DB_REQUEST_NOT_EXIST, RA_CONFIG_NOT_FOUND, RA_CONFIG_LOAD, RA_RECEIVE_WORKFLOW_MESSAGE,
+ // BPEL engine Messages
+ BPMN_GENERAL_INFO, BPMN_GENERAL_EXCEPTION_ARG, BPMN_GENERAL_EXCEPTION, BPMN_GENERAL_WARNING, BPMN_AUDIT_EXEC, BPMN_GENERAL_METRICS, BPMN_URN_MAPPING_FAIL, BPMN_VARIABLE_NULL, BPMN_CALLBACK_EXCEPTION,
+ // ASDC Messages
+ ASDC_GENERAL_EXCEPTION_ARG, ASDC_GENERAL_EXCEPTION, ASDC_GENERAL_WARNING, ASDC_GENERAL_INFO, ASDC_AUDIT_EXEC, ASDC_GENERAL_METRICS, ASDC_CREATE_SERVICE, ASDC_ARTIFACT_ALREADY_DEPLOYED, ASDC_CREATE_ARTIFACT, ASDC_ARTIFACT_INSTALL_EXC, ASDC_ARTIFACT_ALREADY_DEPLOYED_DETAIL, ASDC_ARTIFACT_NOT_DEPLOYED_DETAIL, ASDC_ARTIFACT_CHECK_EXC, ASDC_INIT_ASDC_CLIENT_EXC, ASDC_INIT_ASDC_CLIENT_SUC, ASDC_LOAD_ASDC_CLIENT_EXC, ASDC_SINGLETON_CHECKT_EXC, ASDC_SHUTDOWN_ASDC_CLIENT_EXC, ASDC_CHECK_HEAT_TEMPLATE, ASDC_START_INSTALL_ARTIFACT, ASDC_ARTIFACT_TYPE_NOT_SUPPORT, ASDC_ARTIFACT_ALREADY_EXIST, ASDC_ARTIFACT_DOWNLOAD_SUC, ASDC_ARTIFACT_DOWNLOAD_FAIL, ASDC_START_DEPLOY_ARTIFACT, ASDC_SEND_NOTIF_ASDC, ASDC_SEND_NOTIF_ASDC_EXEC, ASDC_RECEIVE_CALLBACK_NOTIF, ASDC_RECEIVE_SERVICE_NOTIF, ASDC_ARTIFACT_NULL, ASDC_SERVICE_NOT_SUPPORT, ASDC_ARTIFACT_DEPLOY_SUC, ASDC_PROPERTIES_NOT_FOUND, ASDC_PROPERTIES_LOAD_SUCCESS,
+ // Default Messages, in case Log catalog is not defined
+ GENERAL_EXCEPTION_ARG, GENERAL_EXCEPTION, GENERAL_WARNING, AUDIT_EXEC, GENERAL_METRICS, LOGGER_SETUP, LOGGER_NOT_FOUND, LOGGER_UPDATE_SUC, LOGGER_UPDATE_DEBUG, LOGGER_UPDATE_DEBUG_SUC, LOAD_PROPERTIES_SUC, NO_PROPERTIES, MADATORY_PARAM_MISSING, LOAD_PROPERTIES_FAIL, INIT_LOGGER, INIT_LOGGER_FAIL, JAXB_EXCEPTION, IDENTITY_SERVICE_NOT_FOUND
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionChecker.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionChecker.java
new file mode 100644
index 0000000..e1749bb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionChecker.java
@@ -0,0 +1,57 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.permissions;
+
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+
+import java.util.Collection;
+
+public class PermissionChecker {
+ //check is a user have a certain permission in a group
+ public static boolean hasPermissionTo(User user,Group group,String permission, GroupRepository groupRepository){
+ UserPermission userPermission = new PermissionUtil().buildUserPermission(user,groupRepository);
+ return hasPermissionTo(userPermission,group,permission);
+ }
+ public static boolean hasPermissionTo(User user, Group group, Collection<String> permissions, GroupRepository groupRepository){
+ UserPermission userPermission = new PermissionUtil().buildUserPermission(user,groupRepository);
+ for(String permission : permissions){
+ if(!hasPermissionTo(userPermission,group,permission)){
+ return false;
+ }
+ }
+ return true;
+ }
+ // check a users list of permission in a group
+ private static boolean hasPermissionTo(UserPermission userPermission, Group group,String permission){
+ switch (permission.toUpperCase()) {
+ case (UserPermission.Permission.READ):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.READ);
+ case (UserPermission.Permission.WRITE):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.WRITE);
+ case (UserPermission.Permission.EXECUTE):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.EXECUTE);
+ case (UserPermission.Permission.DELETE):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.DELETE);
+ case (UserPermission.Permission.MANAGEMENT):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.MANAGEMENT);
+ default:
+ return false;// reaches here when permission provided is not an option
+ }
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionUtil.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionUtil.java
new file mode 100644
index 0000000..e8cdfea
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionUtil.java
@@ -0,0 +1,237 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.permissions;
+
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.GroupMember;
+import org.oran.otf.common.model.Role;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+
+import java.util.*;
+
+public class PermissionUtil {
+ //build userPermission object which contains all access control information of the user
+ public UserPermission buildUserPermission(User user, GroupRepository groupRepository) {
+ UserPermission userPermission = new UserPermission();
+ userPermission.setUser(user);
+ Map<String,Set<String>> userAccessMap; // map from group to permission that user have in that group
+
+ userAccessMap = mapGroupsToPermission(user,groupRepository);
+ userPermission.setUserAccessMap(userAccessMap);
+ return userPermission;
+ }
+ // return if user have specified permission in a certain group
+ // ***********only use this groups that the user is in directly (non-child and non parents)****************
+ public static boolean hasPermissionTo (String permission,User user, Group group) {
+ Set<String> possiblePermissions= getUserGroupPermissions(user,group);
+ return possiblePermissions.stream().anyMatch(p-> p.equalsIgnoreCase(permission)); //
+ }
+ // Get all the permissions the user have in a certain group
+ public static Set<String> getUserGroupPermissions(User user, Group group){
+ Set<String> permissionsAllowed = new HashSet<>();
+ Set<String> usersAssignedRoles = findUserRoles(user,group);
+ if(usersAssignedRoles.isEmpty()) // empty set permissions because the user have no roles in the group aka not a member
+ return permissionsAllowed;
+ //get every single permissions for each role that the user have.
+ for(String role : usersAssignedRoles){
+ permissionsAllowed.addAll(getRolePermissions(role,group));
+ }
+ return permissionsAllowed;
+ }
+ //get the permissions associated with the userRoleName in group
+ public static Set<String> getRolePermissions(String userRoleName,Group group)
+ {
+ for(Role role : group.getRoles())
+ {
+ if(role.getRoleName().equalsIgnoreCase(userRoleName))
+ {
+ return new HashSet<String>(role.getPermissions());
+ }
+ }
+ return new HashSet<String>(); // empty string set if the role name cant be found in the group
+ }
+ // find the user's role in the specified group
+ public static Set<String> findUserRoles(User user,Group group){
+ for(GroupMember member : group.getMembers())
+ {
+ // if userId matches then get all the user's role in the group
+ if(member.getUserId().toString().equals(user.get_id().toString()))
+ return new HashSet<String>(member.getRoles());
+ }
+ return new HashSet<String>(); //if user have no roles
+ }
+ // create map that where key is the group id and value = users permission (string) that that group
+ private Map<String,Set<String>> mapGroupsToPermission(User user, GroupRepository groupRepository){
+ Map<String,Set<String>> groupAccessMap = new HashMap<>();
+ List<Group> enrolledGroups = groupRepository.findAllByMembersId(user.get_id());// enrolledGroups = groups that user is a member of
+ Map<String,Group> allGroupMap = groupListToMap(groupRepository.findAll());
+ // get all permission in the groups the user is ia member of
+ for(Group group: enrolledGroups) {
+ Set<String> permissions = getUserGroupPermissions(user,group);
+ groupAccessMap.put(group.get_id().toString(),convertPermissions(permissions));
+ }
+ //assign add read to all parent groups
+ Set<String> parentGroupsId = getParentGroups(enrolledGroups,allGroupMap);
+ for(String parentId : parentGroupsId)
+ {
+ // if parent access role already exist in
+ // group access map cause they are a member
+ if(groupAccessMap.get(parentId)!= null)
+ groupAccessMap.get(parentId).add(UserPermission.Permission.READ);
+ else
+ groupAccessMap.put(parentId,new HashSet<String>(Arrays.asList(UserPermission.Permission.READ)));
+ }
+ // if there is management role
+ // then assign read access to children
+ if(hasManagementRole(user,enrolledGroups)){
+// Set<String>childIds = getChildrenGroupsId(enrolledGroups,allGroupMap,user);
+ for(Group enrolledGroup : enrolledGroups) {
+ // if enrolled groups is a management group
+ if(hasPermissionTo(UserPermission.Permission.MANAGEMENT,user,enrolledGroup)){
+ // if there is management role then get all the child of that group, do this for all management groups
+ Set<String> childIds= getChildrenGroupsId(Arrays.asList(enrolledGroup),allGroupMap,user);
+ Set<String> userGroupPermissions = convertPermissions(getUserGroupPermissions(user,enrolledGroup));
+ for(String childId : childIds){
+ if (groupAccessMap.get(childId) != null)
+ groupAccessMap.get(childId).addAll(userGroupPermissions);
+ else{
+ groupAccessMap.put(childId,userGroupPermissions);
+ }
+ }
+ }
+ }
+ }
+ return groupAccessMap;
+ }
+ // check is user have managementRole
+ private boolean hasManagementRole(User user, List<Group> enrolledGroups)
+ {
+ for(Group group: enrolledGroups){
+ if(hasPermissionTo(UserPermission.Permission.MANAGEMENT,user,group))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ // get the parent groups starting from the enrolled group of the user
+ private Set<String> getParentGroups(List<Group> enrolledGroup,Map<String,Group> groupMap )
+ {
+ Set<String> parentGroups = new HashSet<>();
+ return lookUp(enrolledGroup,groupMap,parentGroups);
+ }
+ //recursive lookup starting at the enrolled groups that the user is a member of
+ private Set<String> lookUp(List<Group> groupsToCheck, Map<String,Group> groupMap,Set<String> resultSet)
+ {
+ //base case: nothing to check anymore
+ if(groupsToCheck.isEmpty())
+ return resultSet;
+ //This is the parents directly above the current groups that are being checked
+ List<Group> currentParentGroups = new ArrayList<>();
+
+ for(Group group : groupsToCheck)
+ {
+ if(group.getParentGroupId() != null) // if there is a parent
+ {
+ String parentId = group.getParentGroupId().toString();
+ Group parentGroup = groupMap.get(parentId);
+ resultSet.add(parentId);
+ currentParentGroups.add(parentGroup); // add to currentParentGroup so it can be used recursively check for more parents
+ }
+ }
+ return lookUp(currentParentGroups,groupMap,resultSet);
+ }
+ // convert a list of groups to a map of group ids to group
+ private Map<String,Group> groupListToMap(List<Group> allGroups)
+ {
+ Map<String,Group> groupMap = new HashMap<>();
+ allGroups.forEach(group -> groupMap.put(group.get_id().toString(),group));
+ return groupMap;
+ }
+ //get all the child group
+ private Set<String> getChildrenGroupsId(List<Group> enrolledGroup, Map<String,Group> allGroupsMap, User user)
+ {
+ Set<String> childrenGroups = new HashSet<>();
+ Set<String> managementGroupIds = getManagementGroupIds(enrolledGroup,user);
+ return lookForChildren(managementGroupIds,allGroupsMap,childrenGroups);
+ }
+
+ private Set<String> getManagementGroupIds(List<Group> enrolledGroups,User user)
+ {
+ Set<String> parentIds = new HashSet<>();
+ for(Group group: enrolledGroups)
+ {
+ if(hasPermissionTo(UserPermission.Permission.MANAGEMENT,user,group)) // has Management permission
+ {
+ parentIds.add(group.get_id().toString());
+ }
+ }
+ return parentIds;
+ }
+ //recursive look down for childrens via breath first search
+ private Set<String> lookForChildren (Set<String> parentIds, Map<String,Group> allGroupsMap, Set<String> resultSet)
+ {
+ //base case = no groups to check anymore;
+ if (parentIds.isEmpty())
+ return resultSet;
+
+ Set<String> currentChildrenIds = new HashSet<>();
+ for(String groupId : allGroupsMap.keySet())
+ {
+ Group possibleChildGroup = allGroupsMap.get(groupId);
+ if(isChildOf(parentIds,possibleChildGroup)) // if parent id is the same
+ {
+ currentChildrenIds.add(groupId);
+ resultSet.add(groupId);
+ }
+ }
+ return lookForChildren(currentChildrenIds,allGroupsMap,resultSet);
+ }
+ //check if a group is a child of a list of parent group ids
+ private boolean isChildOf(Set<String>parentGroupIds, Group childGroup){
+ for(String parentId: parentGroupIds)
+ {
+ if(isChildOf(parentId,childGroup))
+ return true;
+ }
+ return false;
+ }
+ //check is group has parent that is specified by parentId
+ private boolean isChildOf(String parentId,Group childGroup) {
+ if(childGroup.getParentGroupId() == null)
+ return false;
+ return childGroup.getParentGroupId().toString().equals(parentId);
+ }
+
+ private Set<String> convertPermissions (Set<String> permissions){
+ Set<String> result = new HashSet<>();
+ for (String permission: permissions){
+ if(permission.equalsIgnoreCase(UserPermission.Permission.READ))
+ result.add(UserPermission.Permission.READ);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.WRITE))
+ result.add(UserPermission.Permission.WRITE);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.DELETE))
+ result.add(UserPermission.Permission.DELETE);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.EXECUTE))
+ result.add(UserPermission.Permission.EXECUTE);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.MANAGEMENT))
+ result.add(UserPermission.Permission.MANAGEMENT);
+ }
+ return result;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/UserPermission.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/UserPermission.java
new file mode 100644
index 0000000..1883721
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/UserPermission.java
@@ -0,0 +1,58 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.permissions;
+
+import org.oran.otf.common.model.User;
+
+import java.util.Map;
+import java.util.Set;
+
+public class UserPermission {
+ private User user;
+ private Map<String,Set<String>> userAccessMap;
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+
+ public Map<String, Set<String>> getUserAccessMap() {
+ return userAccessMap;
+ }
+
+ public void setUserAccessMap(Map<String,Set<String>> userAccessMap) {
+ this.userAccessMap = userAccessMap;
+ }
+
+ public boolean hasAccessTo(String groupId,String permission) {
+ if (userAccessMap.get(groupId) == null) {
+ return false;
+ }
+ Set<String> group = userAccessMap.get(groupId);
+ return group.stream().anyMatch(groupPermission->groupPermission.equalsIgnoreCase(permission));
+ }
+ public class Permission{
+ public static final String READ = "READ";
+ public static final String WRITE = "WRITE";
+ public static final String EXECUTE = "EXECUTE";
+ public static final String DELETE = "DELETE";
+ public static final String MANAGEMENT ="MANAGEMENT";
+ }
+}
diff --git a/otf-service-api/src/main/resources/application.properties b/otf-service-api/src/main/resources/application.properties
new file mode 100644
index 0000000..0a68a60
--- /dev/null
+++ b/otf-service-api/src/main/resources/application.properties
@@ -0,0 +1,50 @@
+# Tomcat
+server.port=8443
+server.port.http=8080
+security.require-ssl=false
+
+server.ssl.key-store-type=PKCS12
+server.ssl.key-store=${OTF_CERT_PATH}
+server.ssl.key-store-password=${OTF_CERT_PASS}
+#server.servlet.context-path=/otf/api
+#spring.jersey.application-path=/otf
+#springfox.documentation.swagger.v2.path=/otf/api/swagger.json
+
+# MongoDB
+otf.mongo.hosts=${OTF_MONGO_HOSTS}
+otf.mongo.username=${OTF_MONGO_USERNAME}
+otf.mongo.password=${OTF_MONGO_PASSWORD}
+otf.mongo.replicaSet=${OTF_MONGO_REPLICASET}
+otf.mongo.database=${OTF_MONGO_DATABASE}
+
+# Jackson
+spring.jackson.default-property-inclusion=always
+
+# Logging
+logging.level.org.springframework.web=DEBUG
+logging.level.org.hibernate=ERROR
+logging.file.max-history=5
+logging.file=otf/logs/serviceapi.log
+logging.path=otf/logs
+
+spring.resources.add-mappings=true
+
+ssl.flag =${https-only.flag:true}
+#springfox.documentation.auto-startup=false
+#springfox.documentation.swagger.v2.path=/otf/swagger.json
+
+#config
+aaf.enabled=true
+aaf.call-timeout=10000
+aaf.conn-timeout=6000
+aaf.default-realm=localhost
+aaf.env=PROD
+aaf.locate-url=https://localhost
+aaf.lur-class=org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm
+aaf.url=https://localhost
+basic-realm=localhost
+basic-warn=true
+cadi-latitude=38.62782
+cadi-longitude=-90.19458
+cadi-protocols=TLSv1.1,TLSv1.2
+cadi-noauthn=/health/v1:/demo/openapi.json
\ No newline at end of file
diff --git a/otf-service-api/src/main/resources/banner.txt b/otf-service-api/src/main/resources/banner.txt
new file mode 100644
index 0000000..544bdea
--- /dev/null
+++ b/otf-service-api/src/main/resources/banner.txt
@@ -0,0 +1,8 @@
+ U ___ u _____ _____
+ \/"_ \/ |_ " _| |" ___|
+ | | | | | | U| |_ u
+ .-,_| |_| | /| |\ \| _|/
+ \_)-\___/ u |_|U |_|
+ \\ _// \\_ )(\\,-
+ (__) (__) (__) (__)(_/
+
diff --git a/otf-service-api/src/main/resources/truststore2018.jks b/otf-service-api/src/main/resources/truststore2018.jks
new file mode 100644
index 0000000..5d52914
--- /dev/null
+++ b/otf-service-api/src/main/resources/truststore2018.jks
Binary files differ
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/config/DataConfig2.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/config/DataConfig2.java
new file mode 100644
index 0000000..f6d9f66
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/config/DataConfig2.java
@@ -0,0 +1,109 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.config;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import de.flapdoodle.embed.mongo.Command;
+import de.flapdoodle.embed.mongo.MongodExecutable;
+import de.flapdoodle.embed.mongo.MongodStarter;
+import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder;
+import de.flapdoodle.embed.mongo.config.ExtractedArtifactStoreBuilder;
+import de.flapdoodle.embed.mongo.config.IMongodConfig;
+import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
+import de.flapdoodle.embed.mongo.config.Net;
+import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder;
+import de.flapdoodle.embed.mongo.distribution.Version;
+import de.flapdoodle.embed.process.config.IRuntimeConfig;
+import de.flapdoodle.embed.process.config.store.HttpProxyFactory;
+import de.flapdoodle.embed.process.runtime.Network;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+
+@Configuration
+@EnableMongoRepositories(basePackages = "org.oran.otf.common.repository")
+@Profile("test")
+public class DataConfig2 extends AbstractMongoConfiguration {
+
+ @Value("${otf.embedded.host}")
+ private String host;
+
+ @Value("${otf.embedded.port}")
+ private int port;
+
+
+ @Value("${otf.embedded.database}")
+ private String database;
+
+ public DataConfig2(){
+ }
+
+ @Override
+ protected String getDatabaseName() {
+ return database;
+ }
+
+ /*
+ @Override
+ public MongoClient mongoClient() {
+ MongoCredential credential = MongoCredential.createScramSha1Credential(username, database, password.toCharArray());
+
+ MongoClientOptions options = MongoClientOptions
+ .builder()
+ .sslEnabled(false)
+ .requiredReplicaSetName(replicaSet)
+ .build();
+
+ String[] hostArray = hosts.split(",");
+ ArrayList<ServerAddress> hosts = new ArrayList<>();
+
+ for (String host : hostArray) {
+ String[] hostSplit = host.split(":");
+ hosts.add(new ServerAddress(hostSplit[0], Integer.parseInt(hostSplit[1])));
+ }
+
+ return new MongoClient(hosts, credential, options);
+ }
+
+ @Override
+ public @Bean
+ MongoTemplate mongoTemplate() {
+ return new MongoTemplate(mongoClient(), database);
+ }
+*/
+
+ @Override
+ public MongoClient mongoClient(){
+ return new MongoClient();
+ }
+
+ @Override
+ public @Bean MongoTemplate mongoTemplate(){
+ return new MongoTemplate(new MongoClient(host, port), "test");
+ }
+
+}
+
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/config/InMemory.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/config/InMemory.java
new file mode 100644
index 0000000..a5243a5
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/config/InMemory.java
@@ -0,0 +1,69 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.config;
+
+import de.flapdoodle.embed.mongo.Command;
+import de.flapdoodle.embed.mongo.MongodExecutable;
+import de.flapdoodle.embed.mongo.MongodStarter;
+import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder;
+import de.flapdoodle.embed.mongo.config.ExtractedArtifactStoreBuilder;
+import de.flapdoodle.embed.mongo.config.IMongodConfig;
+import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
+import de.flapdoodle.embed.mongo.config.Net;
+import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder;
+import de.flapdoodle.embed.mongo.distribution.Version.Main;
+import de.flapdoodle.embed.process.config.IRuntimeConfig;
+import de.flapdoodle.embed.process.config.store.HttpProxyFactory;
+import de.flapdoodle.embed.process.runtime.Network;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Configuration
+@Profile("test")
+public class InMemory {
+ @Autowired MongodStarter mongodStarter;
+
+ @Bean
+ public MongodStarter mongodStarter(){
+ Command command = Command.MongoD;
+ IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
+ .defaults(command)
+ .artifactStore(new ExtractedArtifactStoreBuilder()
+ .defaults(command)
+ .download(new DownloadConfigBuilder()
+ .defaultsForCommand(command)
+ //.downloadPath("http://fastdl.mongodb.org/win32/")
+ .proxyFactory(new HttpProxyFactory("localhost",8080))))
+ .build();
+
+ MongodStarter starter = MongodStarter.getInstance(runtimeConfig);
+
+ return MongodStarter.getInstance(runtimeConfig);
+ }
+ @Bean
+ public MongodExecutable mongodExecutable()throws Exception{
+ IMongodConfig mongodConfig = new MongodConfigBuilder().version(Main.PRODUCTION)
+ .net(new Net("localhost", 5555, Network.localhostIsIPv6()))
+ .build();
+ //MongodStarter starter = MongodStarter.getDefaultInstance();
+ return mongodStarter.prepare(mongodConfig);
+
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/ExecutionServiceRouteIT.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/ExecutionServiceRouteIT.java
new file mode 100644
index 0000000..85d7016
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/ExecutionServiceRouteIT.java
@@ -0,0 +1,79 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.integration.services;
+
+import org.oran.otf.api.Application;
+import org.oran.otf.api.tests.shared.MemoryDatabase;
+import io.restassured.RestAssured;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ webEnvironment = WebEnvironment.RANDOM_PORT,
+ classes = {Application.class}
+)
+@TestPropertySource("classpath:application-test.properties")
+@ActiveProfiles("test")
+public class ExecutionServiceRouteIT {
+ @LocalServerPort
+ private int port;
+
+ @BeforeClass
+ public static void setup() throws Exception{
+ MemoryDatabase.setup();
+ }
+ @AfterClass
+ public static void cleanup(){
+ MemoryDatabase.cleanup();
+ }
+
+ @Before
+ public void setupRestAssured() throws Exception{
+ RestAssured.port = port;
+ RestAssured.urlEncodingEnabled = false;
+ RestAssured.baseURI = "https://localhost";
+ RestAssured.basePath="/otf/api/testExecution/v1";
+ RestAssured.useRelaxedHTTPSValidation();
+ }
+
+ @Ignore
+ @Test
+ public void testExecutionServiceRouteRespondsWith200(){}
+ @Test
+ public void testExecutionServiceRouteStatusRespondsWithOnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/status/executionId/abced").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testExecutionServiceRouteExecutionIdRespondsWithOnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/executionId/abced").then().assertThat().statusCode(401);
+ }
+
+
+}
+
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/HealthRouteIT.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/HealthRouteIT.java
new file mode 100644
index 0000000..a04169e
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/HealthRouteIT.java
@@ -0,0 +1,80 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.integration.services;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+
+import org.oran.otf.api.Application;
+import org.oran.otf.api.tests.shared.MemoryDatabase;
+import io.restassured.RestAssured;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ webEnvironment = WebEnvironment.RANDOM_PORT,
+ classes = {
+ Application.class
+ })
+@TestPropertySource("classpath:application-test.properties")
+@ActiveProfiles("test")
+public class HealthRouteIT {
+ @LocalServerPort
+ private int port;
+
+
+ @BeforeClass
+ public static void setup()throws Exception{
+ MemoryDatabase.setup();
+ }
+ @AfterClass
+ public static void cleanup(){
+ MemoryDatabase.cleanup();
+ }
+ @Before
+ public void setupRestAssured(){
+ RestAssured.port = port;
+ RestAssured.baseURI="https://localhost";
+ RestAssured.basePath="/otf/api";
+ RestAssured.urlEncodingEnabled =false;
+ RestAssured.useRelaxedHTTPSValidation();
+
+ }
+ @Test
+ public void testHealthRouteRespondsWith200(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/health/v1").then().assertThat().statusCode(200);
+ }
+ @Test
+ public void testHealthRouteRespondsWithUp(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/health/v1").then().assertThat().body("message", equalTo("UP"));
+ }
+ @Test
+ public void testHealthRouteRespondsWithJson(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/health/v1").then().contentType("application/json");
+ }
+
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/InstanceServiceRouteIT.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/InstanceServiceRouteIT.java
new file mode 100644
index 0000000..a16a23c
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/InstanceServiceRouteIT.java
@@ -0,0 +1,170 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.integration.services;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+
+import org.oran.otf.api.Application;
+import org.oran.otf.api.tests.shared.MemoryDatabase;
+import org.oran.otf.common.model.TestDefinition;
+import org.oran.otf.common.model.TestInstance;
+import org.oran.otf.common.model.User;
+import io.restassured.RestAssured;
+import org.eclipse.jetty.http.QuotedQualityCSV;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ webEnvironment = WebEnvironment.RANDOM_PORT,
+ classes = {Application.class}
+)
+@TestPropertySource("classpath:application-test.properties")
+@ActiveProfiles("test")
+public class InstanceServiceRouteIT {
+ @LocalServerPort
+ private int port;
+ @Value("${otf.mechid}")
+ private String username;
+ @Value("${otf.mechpass}")
+ private String password;
+ private static User mechUser;
+
+ @Autowired
+ private MongoTemplate mongoTemplate;
+
+ @BeforeClass
+ public static void setup() throws Exception{
+ MemoryDatabase.createAllTables();
+ MemoryDatabase.createAllAdmin();
+ //mechUser = MemoryDatabase.createMechUser();
+ }
+ @AfterClass
+ public static void cleanup(){
+ MemoryDatabase.cleanup();
+ }
+ @Before
+ public void setupRestAssured() {
+ RestAssured.port = port;
+ RestAssured.urlEncodingEnabled = false;
+ RestAssured.baseURI = "https://localhost";
+ RestAssured.basePath="/otf/api/testInstance";
+ RestAssured.useRelaxedHTTPSValidation();
+ }
+ //NoAuth Tests
+
+ @Test
+ public void testFindByIdRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/v1/id/abced").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testFindByProcessKeyRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/v1/processDefinitionKey/abced").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testFindByProcessKeyAndVersionRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/v1/processDefinitionKey/abced/version/1").then().assertThat().statusCode(401);
+ }
+
+
+ @Test
+ public void testExecuteRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/execute/v1/id/abced/").then().assertThat().statusCode(401);
+ }
+
+
+ @Test
+ public void testCreateByTestDefinitionIdRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/create/v1/testDefinitionId/abced/").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testCreateByTestDefinitionIdAndVersionRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/create/v1/testDefinitionId/abced/version/2").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testCreateByProcessDefinitionKeyRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/create/v1/processDefinitionKey/abced").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testCreateByProcessDefinitionKeyAndVersionRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/create/v1/processDefinitionKey/abced/version/2").then().assertThat().statusCode(401);
+ }
+
+ //With Auth and Wrong id
+ @Test
+ public void testFindByIdRespondsWith400OnWrongId(){
+ RestAssured.given().auth().basic(username,password).log().all().header("Accept", "application/json").get("/v1/id/abced").then().assertThat().statusCode(400);
+ }
+ @Test
+ public void testFindByIdRespondsWithMessageOnWrongId(){
+ RestAssured.given().auth().basic(username,password).log().all().header("Accept", "application/json").get("/v1/id/abcde").then().assertThat().body("message", containsString("is not a valid ObjectId (BSON)"));
+ }
+ @Test
+ public void testFindByProcessDefinitionRespondsWith400OnWrongProcessDefinition(){
+ TestDefinition testDefinition = mongoTemplate.findOne(new Query(Criteria.where("testName").is("testDef1")), TestDefinition.class);
+ RestAssured.given().auth().basic(username,password).log().all().header("Accept", "*/*").get("/v1/processDefinitionKey/"+testDefinition.getProcessDefinitionKey()).then().assertThat().statusCode(400);
+ }
+ @Test
+ public void testFindByProcessDefinitionRespondsWithMessageOnWrongProcessDefinition(){
+ TestDefinition testDefinition = mongoTemplate.findOne(new Query(Criteria.where("testName").is("testDef1")), TestDefinition.class);
+ RestAssured.given().auth().basic(username,password).log().all().header("Accept", "application/json").get("/v1/processDefinitionKey/"+testDefinition.getProcessDefinitionKey()).then().assertThat().body("message", containsString("No test instances found"));
+ }
+
+ //Successful Get Methods
+
+ @Test
+ public void testFindByIdRespondsWith200OnSuccess(){
+ TestInstance testInstance = mongoTemplate.findOne(new Query(Criteria.where("testInstanceName").is("MechTestInstance")), TestInstance.class);
+ RestAssured.given().auth().basic(username,password).log().all().header("Accept", "*/*").get("/v1/id/"+testInstance.get_id()).then().assertThat().statusCode(200);
+ }
+
+ @Test
+ public void testFindByProcessDefinitionKeyRespondsWith200OnSuccess(){
+ TestDefinition testDefinition = mongoTemplate.findOne(new Query(Criteria.where("testName").is("MechTestDefinition")), TestDefinition.class);
+ RestAssured.given().auth().basic(username, password).log().all().header("Accept", "*/*").get("/v1/processDefinitionKey/"+testDefinition.getProcessDefinitionKey()).then().assertThat().statusCode(200);
+ }
+
+ @Test
+ public void testFindByProcessDefinitionKeyAndVersionRespondsWith200OnSuccess(){
+ TestDefinition testDefinition = mongoTemplate.findOne(new Query(Criteria.where("testName").is("MechTestDefinition")), TestDefinition.class);
+ RestAssured.given().auth().basic(username, password).log().all().header("Accept", "*/*").get("/v1/processDefinitionKey/"+testDefinition.getProcessDefinitionKey()+"/version/"+1).then().assertThat().statusCode(200);
+ }
+
+ @Test
+ public void testCreateByTestDefinitionIdRespondsWith201OnSuccess(){
+ TestDefinition testDefinition = mongoTemplate.findOne(new Query(Criteria.where("testName").is("MechTestDefinition")), TestDefinition.class);
+ System.out.println(testDefinition.getBpmnInstances());
+ RestAssured.given().contentType("application/json\r\n").auth().basic(username, password).log().all().header("Accept", "*/*").post("/create/v1/testDefinitionId/"+testDefinition.get_id()+"/version/"+1).then().assertThat().statusCode(404);
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/OtfOpenRouteIT.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/OtfOpenRouteIT.java
new file mode 100644
index 0000000..132464a
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/OtfOpenRouteIT.java
@@ -0,0 +1,67 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.integration.services;
+
+import org.oran.otf.api.Application;
+import org.oran.otf.api.tests.shared.MemoryDatabase;
+import io.restassured.RestAssured;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ webEnvironment = WebEnvironment.RANDOM_PORT,
+ classes = {Application.class}
+)
+@TestPropertySource("classpath:application-test.properties")
+@ActiveProfiles("test")
+public class OtfOpenRouteIT {
+ @LocalServerPort
+ private int port;
+
+ @BeforeClass
+ public static void setup() throws Exception{
+ MemoryDatabase.setup();
+ }
+ @AfterClass
+ public static void cleanup(){
+ MemoryDatabase.cleanup();
+ }
+ @Before
+ public void setupRestAssured(){
+ RestAssured.port =port;
+ RestAssured.urlEncodingEnabled = false;
+ RestAssured.baseURI="https://localhost";
+ RestAssured.basePath="/otf/api";
+ RestAssured.useRelaxedHTTPSValidation();
+ }
+ @Ignore("Ignoring test because it fails since it tries to request to specific port, uncomment to view error")
+ @Test
+ public void testOtfOpenRouteRespondsWith200(){
+ RestAssured.given().log().all().header("Accept", "application/json").get("/demo/openapi.json").then().statusCode(200);
+ }
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/Permissions/PermissionServiceIT.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/Permissions/PermissionServiceIT.java
new file mode 100644
index 0000000..6186d3a
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/Permissions/PermissionServiceIT.java
@@ -0,0 +1,331 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.integration.services.Permissions;
+
+import org.oran.otf.api.Application;
+import org.oran.otf.api.tests.shared.MemoryDatabase;
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.GroupMember;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.utility.permissions.PermissionChecker;
+import org.oran.otf.common.utility.permissions.PermissionUtil;
+import org.oran.otf.common.utility.permissions.UserPermission;
+import org.bson.types.ObjectId;
+import org.junit.*;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ classes = {
+ Application.class,
+ })
+@TestPropertySource("classpath:application-test.properties")
+@ActiveProfiles("test")
+public class PermissionServiceIT {
+ @Autowired
+ private GroupRepository groupRepository;
+ private List<Group> groups;
+ private Group parentGroup;
+ private Group firstChildGroup;
+ private Group childOfChildGroup;
+
+ @BeforeClass
+ public static void setUp() throws Exception{
+ MemoryDatabase.setup();
+ MemoryDatabase.createGroupsForPermission();
+ }
+ @Before
+ public void setUpGroups()
+ {
+ groups = groupRepository.findAll();
+ parentGroup = groupRepository.findFirstByGroupName("parent group");
+ firstChildGroup = groupRepository.findFirstByGroupName("first child group");
+ childOfChildGroup = groupRepository.findFirstByGroupName("child of child group");
+ }
+ @AfterClass
+ public static void cleanup(){
+ MemoryDatabase.cleanup();
+ }
+ /*
+ if this test failed there was a error during set up so ignore the failures produced by other tests til this pass
+ */
+ @Test
+ public void setUpTest(){
+ List<Group> groups = groupRepository.findAll();
+ parentGroup = groupRepository.findFirstByGroupName("parent group");
+ firstChildGroup = groupRepository.findFirstByGroupName("first child group");
+ childOfChildGroup = groupRepository.findFirstByGroupName("child of child group");
+ Assert.assertNotNull(groups);
+ Assert.assertFalse(groups.isEmpty());
+
+ Assert.assertNotNull(parentGroup.getMembers());
+ Assert.assertFalse(parentGroup.getMembers().isEmpty());
+ Assert.assertNotNull(parentGroup.getRoles());
+ Assert.assertFalse(parentGroup.getRoles().isEmpty());
+
+ Assert.assertNotNull(firstChildGroup.getMembers());
+ Assert.assertFalse(firstChildGroup.getMembers().isEmpty());
+ Assert.assertNotNull(firstChildGroup.getRoles());
+ Assert.assertFalse(firstChildGroup.getRoles().isEmpty());
+
+ Assert.assertNotNull(childOfChildGroup.getMembers());
+ Assert.assertFalse(childOfChildGroup.getMembers().isEmpty());
+ Assert.assertNotNull(childOfChildGroup.getRoles());
+ Assert.assertFalse(childOfChildGroup.getRoles().isEmpty());
+ // all groups are set up with 1 member in memory db
+ Assert.assertEquals(1,parentGroup.getMembers().size());
+ Assert.assertEquals(1,firstChildGroup.getMembers().size());
+ Assert.assertEquals(1,childOfChildGroup.getMembers().size());
+ }
+ @Test
+ public void findUserRoles(){
+ GroupMember parentMember = parentGroup.getMembers().get(0);
+ GroupMember firstChildMember = firstChildGroup.getMembers().get(0);
+ GroupMember childOfChildMember = childOfChildGroup.getMembers().get(0);
+
+ User parentUserMock = Mockito.mock(User.class);
+ User firstChildUserMock = Mockito.mock(User.class);
+ User childOfChildUserMock = Mockito.mock(User.class);
+
+ Mockito.when(parentUserMock.get_id()).thenReturn(parentMember.getUserId());
+ Mockito.when(firstChildUserMock.get_id()).thenReturn(firstChildMember.getUserId());
+ Mockito.when(childOfChildUserMock.get_id()).thenReturn(childOfChildMember.getUserId());
+
+ Set<String> parentMemberRoles = PermissionUtil.findUserRoles(parentUserMock, parentGroup);
+ Set<String> firstChildRoles = PermissionUtil.findUserRoles(firstChildUserMock, firstChildGroup);
+ Set<String> childOfChildRoles = PermissionUtil.findUserRoles(childOfChildUserMock, childOfChildGroup);
+
+ // all group members should only have 1 role (admin) set up except first child
+ Assert.assertEquals(1,parentMemberRoles.size());
+ Assert.assertTrue(parentMemberRoles.contains("admin"));
+ Assert.assertEquals(2,firstChildRoles.size());
+ Assert.assertTrue(firstChildRoles.contains("admin"));
+ Assert.assertTrue(firstChildRoles.contains("dev"));
+ Assert.assertEquals(1,childOfChildRoles.size());
+ Assert.assertTrue(childOfChildRoles.contains("executor"));
+
+ Assert.assertFalse(parentMemberRoles.contains("executor"));
+ Assert.assertFalse(firstChildRoles.contains("executor"));
+ Assert.assertFalse("should not have admin roles in child of child", childOfChildRoles.contains("admin"));
+ }
+ @Test
+ public void getRolePermissionsTest()
+ {
+ ObjectId firstChildId =firstChildGroup.getMembers().get(0).getUserId();
+ User firstChildUserMock = Mockito.mock(User.class);
+ Mockito.when(firstChildUserMock.get_id()).thenReturn(firstChildId);
+ Set<String> roles = PermissionUtil.findUserRoles(firstChildUserMock,firstChildGroup); //dev and admin roles only
+
+ Assert.assertEquals(2,roles.size());
+ for(String role : roles){
+ Set<String> permissions = PermissionUtil.getRolePermissions(role,parentGroup);
+ Assert.assertTrue("all permissions allowed except execute and delete",permissions.contains("READ"));
+ Assert.assertTrue("all permissions allowed except execute and delete",permissions.contains("WRITE"));
+ Assert.assertFalse("all permissions allowed except execute and delete",permissions.contains("DELETE"));
+ Assert.assertFalse("all permissions allowed except execute and delete",permissions.contains("EXECUTE"));
+ }
+ }
+ @Test
+ public void getUserGroupPermissionTest(){
+ GroupMember firstChildMember = firstChildGroup.getMembers().get(0);
+ User firstChildUser = Mockito.mock(User.class);
+ Mockito.when(firstChildUser.get_id()).thenReturn(firstChildMember.getUserId());
+ Set<String> permissions = PermissionUtil.getUserGroupPermissions(firstChildUser,firstChildGroup); // should include everything except execute and delete
+
+ Assert.assertEquals(3,permissions.size());
+ Assert.assertTrue("all permissions allowed except execute and delete",permissions.contains("READ"));
+ Assert.assertTrue("all permissions allowed except execute and delete",permissions.contains("WRITE"));
+ Assert.assertFalse("all permissions allowed except execute and delete",permissions.contains("DELETE"));
+ Assert.assertFalse("all permissions allowed except execute and delete",permissions.contains("EXECUTE"));
+ Assert.assertTrue("all permissions allowed except execute and delete",permissions.contains("MANAGEMENT"));
+ }
+
+ @Test
+ public void hasPermissionToTest(){
+ GroupMember parentMember = parentGroup.getMembers().get(0);
+ GroupMember firstChildMember = firstChildGroup.getMembers().get(0);
+ GroupMember childOfChildMember = childOfChildGroup.getMembers().get(0);
+
+ User parentGroupUser = Mockito.mock(User.class);
+ User firstChildUser = Mockito.mock(User.class);
+ User childOfChildUser =Mockito.mock(User.class);
+ Mockito.when(parentGroupUser.get_id()).thenReturn(parentMember.getUserId());
+ Mockito.when(firstChildUser.get_id()).thenReturn(firstChildMember.getUserId());
+ Mockito.when(childOfChildUser.get_id()).thenReturn(childOfChildMember.getUserId());
+
+ String read = "read";
+ String write= "write";
+ String manage = "management";
+ String delete = "delete";
+ String execute= "execute";
+
+ Assert.assertTrue(PermissionUtil.hasPermissionTo(read,parentGroupUser,parentGroup));
+ Assert.assertTrue(PermissionUtil.hasPermissionTo(write,parentGroupUser,parentGroup));
+ Assert.assertTrue(PermissionUtil.hasPermissionTo(manage,parentGroupUser,parentGroup));
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(delete,parentGroupUser,parentGroup));
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(execute,parentGroupUser,parentGroup));
+
+ Assert.assertTrue(PermissionUtil.hasPermissionTo(read,firstChildUser,firstChildGroup));
+ Assert.assertTrue(PermissionUtil.hasPermissionTo(write,firstChildUser,firstChildGroup));
+ Assert.assertTrue(PermissionUtil.hasPermissionTo(manage,firstChildUser,firstChildGroup));
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(delete,firstChildUser,firstChildGroup));
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(execute,firstChildUser,firstChildGroup));
+
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(read,childOfChildUser,childOfChildGroup));
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(write,childOfChildUser,childOfChildGroup));
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(manage,childOfChildUser,childOfChildGroup));
+ Assert.assertFalse(PermissionUtil.hasPermissionTo(delete,childOfChildUser,childOfChildGroup));
+ Assert.assertTrue(PermissionUtil.hasPermissionTo(execute,childOfChildUser,childOfChildGroup));
+ }
+ @Test
+ public void buildUserPermissionTest()
+ {
+ /*
+ should be the following format
+ parent members:
+ parentGroup = {read,write,management}
+ first Child group = {read}
+ child of child group = {read}
+
+ first child group:
+ parentGroup = {read}
+ first Child group = {read,write,management}
+ child of child group = {read}
+
+ child of child:
+ parentGroup = {read}
+ first Child group = {read}
+ child of child group = {execute}
+ */
+
+ GroupMember parentMember = parentGroup.getMembers().get(0);
+ GroupMember firstChildMember = firstChildGroup.getMembers().get(0);
+ GroupMember childOfChildMember = childOfChildGroup.getMembers().get(0);
+
+ User parentGroupUser = Mockito.mock(User.class);
+ User firstChildUser = Mockito.mock(User.class);
+ User childOfChildUser =Mockito.mock(User.class);
+ Mockito.when(parentGroupUser.get_id()).thenReturn(parentMember.getUserId());
+ Mockito.when(firstChildUser.get_id()).thenReturn(firstChildMember.getUserId());
+ Mockito.when(childOfChildUser.get_id()).thenReturn(childOfChildMember.getUserId());
+
+ String read = "READ";
+ String write= "WRITE";
+ String manage = "MANAGEMENT";
+ String delete = "DELETE";
+ String execute= "EXECUTE";
+
+ UserPermission parentUserPermissions = new PermissionUtil().buildUserPermission(parentGroupUser,groupRepository);
+ UserPermission firstChildUserPermissions = new PermissionUtil().buildUserPermission(firstChildUser,groupRepository);
+ UserPermission childOfChildUserPermissions = new PermissionUtil().buildUserPermission(childOfChildUser,groupRepository);
+ Map<String,Set<String>> parentAccessControl = parentUserPermissions.getUserAccessMap();
+ Map<String,Set<String>> firstChildAccessControl = firstChildUserPermissions.getUserAccessMap();
+ Map<String,Set<String>> childOfChildAccessControl = childOfChildUserPermissions.getUserAccessMap();
+
+ //test for parent access control
+ Assert.assertTrue(parentAccessControl.get(parentGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(parentAccessControl.get(parentGroup.get_id().toString()).contains(write));
+ Assert.assertTrue(parentAccessControl.get(parentGroup.get_id().toString()).contains(manage));
+ //test all access is passed to firstChildGroup
+ Assert.assertTrue(parentAccessControl.get(firstChildGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(parentAccessControl.get(firstChildGroup.get_id().toString()).contains(write));
+ Assert.assertTrue(parentAccessControl.get(firstChildGroup.get_id().toString()).contains(manage));
+ //test all access is passed to child of child group
+ Assert.assertTrue(parentAccessControl.get(childOfChildGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(parentAccessControl.get(childOfChildGroup.get_id().toString()).contains(write));
+ Assert.assertTrue(parentAccessControl.get(childOfChildGroup.get_id().toString()).contains(manage));
+ // make sure parent user dont have other permissions in first child group
+ Assert.assertFalse(parentAccessControl.get(firstChildGroup.get_id().toString()).contains(delete));
+ Assert.assertFalse(parentAccessControl.get(firstChildGroup.get_id().toString()).contains(execute));
+ //test that parent dont have other permissions in child of child group
+ Assert.assertFalse(parentAccessControl.get(childOfChildGroup.get_id().toString()).contains(delete));
+ Assert.assertFalse(parentAccessControl.get(childOfChildGroup.get_id().toString()).contains(execute));
+
+ //test for first child access control
+ Assert.assertTrue(firstChildAccessControl.get(parentGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(firstChildAccessControl.get(firstChildGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(firstChildAccessControl.get(firstChildGroup.get_id().toString()).contains(write));
+ Assert.assertTrue(firstChildAccessControl.get(firstChildGroup.get_id().toString()).contains(manage));
+ // test that first child group get passed to child of child
+ Assert.assertTrue(firstChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(firstChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(write));
+ Assert.assertTrue(firstChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(manage));
+ // make sure firstchild user dont have other permissions
+ Assert.assertFalse(firstChildAccessControl.get(parentGroup.get_id().toString()).contains(write));
+ Assert.assertFalse(firstChildAccessControl.get(parentGroup.get_id().toString()).contains(manage));
+ Assert.assertFalse(firstChildAccessControl.get(parentGroup.get_id().toString()).contains(delete));
+ Assert.assertFalse(firstChildAccessControl.get(parentGroup.get_id().toString()).contains(execute));
+ // test to confirm no extra permission is passed to child of child
+ Assert.assertFalse(firstChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(delete));
+ Assert.assertFalse(firstChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(execute));
+
+ //test for child of child access control
+ Assert.assertTrue(childOfChildAccessControl.get(parentGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(childOfChildAccessControl.get(firstChildGroup.get_id().toString()).contains(read));
+ Assert.assertTrue(childOfChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(execute));
+ // make sure child of child user dont have other permissions
+ Assert.assertFalse(childOfChildAccessControl.get(parentGroup.get_id().toString()).contains(write));
+ Assert.assertFalse(childOfChildAccessControl.get(parentGroup.get_id().toString()).contains(manage));
+ Assert.assertFalse(childOfChildAccessControl.get(parentGroup.get_id().toString()).contains(delete));
+ Assert.assertFalse(childOfChildAccessControl.get(parentGroup.get_id().toString()).contains(execute));
+
+ Assert.assertFalse(childOfChildAccessControl.get(firstChildGroup.get_id().toString()).contains(write));
+ Assert.assertFalse(childOfChildAccessControl.get(firstChildGroup.get_id().toString()).contains(manage));
+ Assert.assertFalse(childOfChildAccessControl.get(firstChildGroup.get_id().toString()).contains(delete));
+ Assert.assertFalse(childOfChildAccessControl.get(firstChildGroup.get_id().toString()).contains(execute));
+
+ Assert.assertFalse(childOfChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(write));
+ Assert.assertFalse(childOfChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(manage));
+ Assert.assertFalse(childOfChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(delete));
+ Assert.assertFalse(childOfChildAccessControl.get(childOfChildGroup.get_id().toString()).contains(read));
+ }
+ @Test
+ public void basicTest(){
+ GroupMember parentMember = parentGroup.getMembers().get(0);
+ GroupMember firstChildMember = firstChildGroup.getMembers().get(0);
+ GroupMember childOfChildMember = childOfChildGroup.getMembers().get(0);
+
+ User parentGroupUser = Mockito.mock(User.class);
+ User firstChildUser = Mockito.mock(User.class);
+ User childOfChildUser =Mockito.mock(User.class);
+ Mockito.when(parentGroupUser.get_id()).thenReturn(parentMember.getUserId());
+ Mockito.when(firstChildUser.get_id()).thenReturn(firstChildMember.getUserId());
+ Mockito.when(childOfChildUser.get_id()).thenReturn(childOfChildMember.getUserId());
+
+ Assert.assertTrue(PermissionChecker.hasPermissionTo(childOfChildUser,firstChildGroup,UserPermission.Permission.READ,groupRepository));
+ Assert.assertTrue(PermissionChecker.hasPermissionTo(childOfChildUser,parentGroup,UserPermission.Permission.READ,groupRepository));
+ Assert.assertFalse(PermissionChecker.hasPermissionTo(childOfChildUser,childOfChildGroup,UserPermission.Permission.READ,groupRepository));
+
+ Assert.assertFalse(PermissionChecker.hasPermissionTo(childOfChildUser,firstChildGroup,UserPermission.Permission.EXECUTE,groupRepository));
+ Assert.assertTrue(PermissionChecker.hasPermissionTo(firstChildUser,firstChildGroup,UserPermission.Permission.WRITE,groupRepository));
+ Assert.assertFalse(PermissionChecker.hasPermissionTo(firstChildUser,firstChildGroup,UserPermission.Permission.EXECUTE,groupRepository));
+
+ Assert.assertFalse(PermissionChecker.hasPermissionTo(parentGroupUser,parentGroup,UserPermission.Permission.DELETE,groupRepository));
+ Assert.assertFalse(PermissionChecker.hasPermissionTo(parentGroupUser,parentGroup,UserPermission.Permission.EXECUTE,groupRepository));
+ Assert.assertFalse(PermissionChecker.hasPermissionTo(parentGroupUser,firstChildGroup,UserPermission.Permission.EXECUTE,groupRepository));
+ }
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/StrategyServiceRouteIT.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/StrategyServiceRouteIT.java
new file mode 100644
index 0000000..7cd2b43
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/integration/services/StrategyServiceRouteIT.java
@@ -0,0 +1,74 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.integration.services;
+
+import org.oran.otf.api.Application;
+import org.oran.otf.api.tests.shared.MemoryDatabase;
+import io.restassured.RestAssured;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+ webEnvironment = WebEnvironment.RANDOM_PORT,
+ classes = {Application.class}
+)
+@TestPropertySource("classpath:application-test.properties")
+@ActiveProfiles("test")
+public class StrategyServiceRouteIT {
+ @LocalServerPort
+ private int port;
+ @BeforeClass
+ public static void setup() throws Exception{
+ MemoryDatabase.setup();
+ }
+ @AfterClass
+ public static void cleanup(){
+ MemoryDatabase.cleanup();
+ }
+ @Before
+ public void setupRestAssured(){
+ RestAssured.port = port;
+ RestAssured.baseURI="https://localhost";
+ RestAssured.basePath="/otf/api/testStrategy";
+ RestAssured.urlEncodingEnabled=false;
+ RestAssured.useRelaxedHTTPSValidation();
+ }
+
+ @Test
+ public void testStrategyServiceRouteDeployRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").post("/deploy/v1").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testStrategyServiceRouteDeleteByTestDefinitionIdRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").delete("/delete/v1/testDefinitionId/56565656").then().assertThat().statusCode(401);
+ }
+ @Test
+ public void testStrategyServiceRouteDeleteByDeploymentIdRespondsWith401OnNoAuth(){
+ RestAssured.given().log().all().header("Accept", "application/json").delete("/delete/v1/deploymentId/54545454").then().assertThat().statusCode(401);
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/shared/MemoryDatabase.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/shared/MemoryDatabase.java
new file mode 100644
index 0000000..2c17abb
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/shared/MemoryDatabase.java
@@ -0,0 +1,386 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.shared;
+
+import org.oran.otf.common.model.*;
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.model.local.UserGroup;
+import com.mongodb.BasicDBObjectBuilder;
+import com.mongodb.DBObject;
+import com.mongodb.MongoClient;
+import de.flapdoodle.embed.mongo.Command;
+import de.flapdoodle.embed.mongo.MongodExecutable;
+import de.flapdoodle.embed.mongo.MongodProcess;
+import de.flapdoodle.embed.mongo.MongodStarter;
+import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder;
+import de.flapdoodle.embed.mongo.config.ExtractedArtifactStoreBuilder;
+import de.flapdoodle.embed.mongo.config.IMongodConfig;
+import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
+import de.flapdoodle.embed.mongo.config.Net;
+import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder;
+import de.flapdoodle.embed.mongo.distribution.Version;
+import de.flapdoodle.embed.mongo.distribution.Version.Main;
+import de.flapdoodle.embed.process.config.IRuntimeConfig;
+import de.flapdoodle.embed.process.config.store.HttpProxyFactory;
+import de.flapdoodle.embed.process.runtime.Network;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
+import javassist.util.proxy.ProxyFactory;
+import org.apache.commons.lang3.time.DateUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.oran.otf.common.model.*;
+import org.springframework.context.annotation.Configuration;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.test.context.ActiveProfiles;
+
+
+@ActiveProfiles("test")
+public abstract class MemoryDatabase {
+ protected static MongodExecutable mongodExecutable;
+ protected static MongoTemplate mongoTemplate;
+
+ //TODO use mongod process to be response from mongodExecutable.start(), on pulbic calls check if null if so call setup else dont
+ protected static MongodProcess mongod = null;
+
+ protected static Query userQuery = new Query(Criteria.where("firstName").is("Mech"));
+ //protected static Query mechUserQuery = new Query(Criteria.where("firstName").is("Mech"));
+ protected static Query testInstanceQuery = new Query(Criteria.where("testInstanceName").is("MechTestInstance"));
+ protected static Query groupQuery = new Query(Criteria.where("groupName").is("MechGroup"));
+ protected static Query testDefQuery = new Query(Criteria.where("testName").is("MechTestDefinition"));
+
+ //values should match with DataConfig2
+ protected static int port=5555;
+ protected static String host="localhost";
+
+
+ public static void setup()throws Exception{
+ Command command = Command.MongoD;
+ IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
+ .defaults(command)
+ .artifactStore(new ExtractedArtifactStoreBuilder()
+ .defaults(command)
+ .download(new DownloadConfigBuilder()
+ .defaultsForCommand(command)
+ .proxyFactory(new HttpProxyFactory("localhost",8080))))
+ .build();
+
+ //String host = "localhost";
+ //int port = 5555;
+
+ IMongodConfig mongodConfig = new MongodConfigBuilder().version(Main.PRODUCTION)
+ .net(new Net(host, port, Network.localhostIsIPv6()))
+ .build();
+ //MongodStarter starter = MongodStarter.getDefaultInstance();
+ MongodStarter starter = MongodStarter.getInstance(runtimeConfig);
+ mongodExecutable = starter.prepare(mongodConfig);
+ mongodExecutable.start();
+ mongoTemplate = new MongoTemplate(new MongoClient(host, port), "test");
+
+ DBObject objectToSave = BasicDBObjectBuilder.start()
+ .add("name", "john")
+ .get();
+ mongoTemplate.save(objectToSave, "collection");
+
+
+ }
+ /*
+ public static User createMechUser(){
+
+ User user = mongoTemplate.findOne(mechUserQuery, User.class);
+ if(user == null) {
+ user = new User();
+ user.setFirstName("Mech");
+ user.setLastName("Id");
+ user.setEmail("email@localhost");
+ mongoTemplate.save(user, "users");
+ user = mongoTemplate.findOne(mechUserQuery, User.class);
+ }
+ return user;
+ }
+
+ */
+ //TODO: make admin user be the mechid, this is because of AAF test will fail if random user is used
+ private static User createMechUserIfNotExists(){
+ User user = mongoTemplate.findOne(userQuery, User.class);
+ if(user == null) {
+ user = new User();
+ user.setFirstName("Mech");
+ user.setLastName("Id");
+ user.setEmail("email@localhost");
+ mongoTemplate.save(user, "users");
+ user = mongoTemplate.findOne(userQuery, User.class);
+ }
+ return user;
+
+ }
+ private static Group createMechGroupIfNotExists(){
+ User user = MemoryDatabase.createMechUserIfNotExists();
+ Group group = mongoTemplate.findOne(groupQuery, Group.class);
+ if(group == null) {
+ String groupName = "MechGroup";
+ group = new Group();
+ group.setOwnerId(user.get_id());
+ group.setGroupName(groupName);
+ group.setGroupDescription(groupName + " description");
+ mongoTemplate.save(group, "groups");
+ group = mongoTemplate.findOne(groupQuery, Group.class);
+ }
+ return group;
+ }
+ private static TestDefinition createMechTestDefinitionIfNotExists(){
+ TestDefinition testDefinition = mongoTemplate.findOne(testDefQuery, TestDefinition.class);
+ if(testDefinition == null){
+
+ BpmnInstance bpmnInstance = new BpmnInstance();
+ bpmnInstance.setDeployed(true);
+ bpmnInstance.setVersion(1);
+ List list = new ArrayList(Arrays.asList(bpmnInstance));
+
+ testDefinition = new TestDefinition();
+ testDefinition.setDisabled(false);
+ testDefinition.setBpmnInstances(list);
+ testDefinition.setTestName("MechTestDefinition");
+ testDefinition.setTestDescription("MechTestDefinition description");
+ testDefinition.setProcessDefinitionKey("MechTestDefinitionKey");
+ testDefinition.setCreatedBy(createMechUserIfNotExists().get_id());
+ testDefinition.setGroupId(createMechGroupIfNotExists().get_id());
+ testDefinition.setCreatedAt(new Timestamp(new Date().getTime()));
+ testDefinition.setUpdatedAt(new Timestamp(new Date().getTime()));
+ mongoTemplate.save(testDefinition, "testDefinitions");
+ testDefinition = mongoTemplate.findOne(testDefQuery, TestDefinition.class);
+ }
+ return testDefinition;
+
+ }
+
+
+ private static TestInstance createMechTestInstanceIfNotExists(){
+ TestInstance testInstance = mongoTemplate.findOne(testInstanceQuery, TestInstance.class);
+ User user = createMechUserIfNotExists();
+ UserGroup userGroup = new UserGroup();
+ if(testInstance == null){
+ testInstance = new TestInstance();
+ testInstance.setTestInstanceName("MechTestInstance");
+ testInstance.setTestInstanceDescription("MechTestInstance description");
+ testInstance.setCreatedBy(user.get_id());
+ testInstance.setGroupId(createMechGroupIfNotExists().get_id());
+ testInstance.setTestDefinitionId(createMechTestDefinitionIfNotExists().get_id());
+ testInstance.setMaxExecutionTimeInMillis(new Random().nextInt(5000));
+ testInstance.setUseLatestTestDefinition(true);
+ mongoTemplate.save(testInstance, "testInstances");
+ testInstance = mongoTemplate.findOne(testInstanceQuery, TestInstance.class);
+ }
+ userGroup.setGroupId(testInstance.getGroupId());
+ userGroup.setPermissions(Arrays.asList("Admin"));
+ user.setGroups(Arrays.asList(userGroup));
+ mongoTemplate.save(user, "users");
+ return testInstance;
+ }
+
+ public static void createGroups(){
+
+ MemoryDatabase.createMechUserIfNotExists();
+ List<String> groupNames = new ArrayList<>(Arrays.asList("Group1", "Group2", "Group3", "Group4", "Group5"));
+ groupNames.forEach(name->{
+ Group group = new Group();
+ User usr = mongoTemplate.findOne(userQuery, User.class);
+ group.setOwnerId(usr.get_id());
+ group.setGroupName(name);
+ group.setGroupDescription(name + " description");
+ mongoTemplate.save(group, "groups");
+ });
+
+ }
+
+ public static void createGroupsForPermission()
+ {
+ Group parentGroup = new Group();
+ Group firstChildGroup = new Group();
+ Group childOfChildGroup = new Group();
+ parentGroup.setGroupName("parent group");
+ firstChildGroup.setGroupName("first child group");
+ childOfChildGroup.setGroupName("child of child group");
+ Role adminRole = new Role();
+ Role devRole = new Role();
+ Role executorRole = new Role();
+ GroupMember parentMember = new GroupMember();
+ GroupMember firstChildMember = new GroupMember();
+ GroupMember childOfChildMember = new GroupMember();
+ //set up members
+ createUsers();
+ List<User> users = mongoTemplate.findAll(User.class,"users"); // this should be atleast 3 users
+ /*
+ set up
+ parent group -> members only with admin roles. Permission = "READ","WRITE","MANAGEMENT"
+ child group -> members only with admin and dev roles. Permission = "READ","WRITE", "MANAGEMENT
+ child of child group -> members with only executor roles. Permission = "EXECUTE
+ */
+ parentMember.setUserId(users.get(0).get_id());
+ parentMember.setRoles(Arrays.asList("admin"));
+ firstChildMember.setUserId(users.get(1).get_id());
+ firstChildMember.setRoles(Arrays.asList("dev","admin"));
+ childOfChildMember.setUserId(users.get(2).get_id());
+ childOfChildMember.setRoles(Arrays.asList("executor"));
+ //set up roles
+ adminRole.setRoleName("admin");
+ adminRole.setPermissions(Arrays.asList("READ","WRITE","MANAGEMENT"));
+ devRole.setRoleName("dev");
+ devRole.setPermissions(Arrays.asList("READ","WRITE"));
+ executorRole.setRoleName("executor");
+ executorRole.setPermissions(Arrays.asList("EXECUTE"));
+ List<Role> defaultRoles = new ArrayList<>();
+ defaultRoles.add(devRole);
+ defaultRoles.add(adminRole);
+ defaultRoles.add(executorRole);
+ //set up groups
+ parentGroup.setRoles(defaultRoles);
+ parentGroup.setMembers(Arrays.asList(parentMember));
+ firstChildGroup.setRoles(defaultRoles);
+ firstChildGroup.setMembers(Arrays.asList(firstChildMember));
+ childOfChildGroup.setRoles(defaultRoles);
+ childOfChildGroup.setMembers(Arrays.asList(childOfChildMember));
+ /*
+ set up parent tree
+ structure:
+ parentGroup
+ |
+ Child group
+ |
+ Child of child group
+ */
+ mongoTemplate.save(parentGroup,"groups");
+ mongoTemplate.save(firstChildGroup,"groups");
+ mongoTemplate.save(childOfChildGroup,"groups");
+ // query object so we can get the object id and set up parent ids
+ Query parentQ = new Query(Criteria.where("groupName").is("parent group"));
+ Query firstChildQ = new Query(Criteria.where("groupName").is("first child group"));
+ Query childOfChildQ = new Query(Criteria.where("groupName").is("child of child group"));
+ Group parentGroupDbObj = mongoTemplate.findOne(parentQ,Group.class);
+ Group firstChildDbObj = mongoTemplate.findOne(firstChildQ,Group.class);
+ Group childOfChildDbObj = mongoTemplate.findOne(childOfChildQ,Group.class);
+
+ firstChildDbObj.setParentGroupId(parentGroupDbObj.get_id());
+ childOfChildDbObj.setParentGroupId(firstChildDbObj.get_id());
+ mongoTemplate.save(firstChildDbObj);
+ mongoTemplate.save(childOfChildDbObj);
+ }
+
+ public static void createUsers(){
+ List<String> usersFirstNames = new ArrayList<>(Arrays.asList("Joe", "Jim", "Rick", "David", "Tony"));
+ List<String> usersLastNames = new ArrayList<>(Arrays.asList("Terry", "Roll", "Luis", "Perry"));
+ usersFirstNames.forEach(name->{
+ User user = new User();
+ int index = new Random().nextInt(usersFirstNames.size()-1);
+ user.setEmail(name+usersLastNames.get(index)+"@email.com");
+ user.setLastName(name);
+ user.setFirstName(usersLastNames.get(index));
+ mongoTemplate.save(user, "users");
+ });
+
+ }
+ public static void createTeatHeads(){
+ List<String> testheadNames = new ArrayList<>(Arrays.asList("SSH", "FTP", "PING", "PROCESS", "daRudeSandstorm"));
+ testheadNames.forEach(name->{
+ String random = Integer.toString(new Random().nextInt(4000)+4000);
+ TestHead testHead = new TestHead();
+ testHead.setTestHeadName(name);
+ testHead.setTestHeadDescription(name+" virtual test head ");
+ testHead.setPort(random);
+ testHead.setResourcePath("resources.vths.com/"+name);
+ testHead.setHostname("resources.vths.com");
+ testHead.setGroupId(createMechUserIfNotExists().get_id());
+ testHead.setGroupId(createMechGroupIfNotExists().get_id());
+ testHead.setCreatedAt(new Timestamp(new Date().getTime()));
+ testHead.setUpdatedAt(new Timestamp(new Date().getTime()));
+ mongoTemplate.save(testHead, "testHeads");
+
+ });
+ }
+ public static void createTestDefinitions(){
+ List<String> testDefinitionNames = new ArrayList<>(Arrays.asList("testDef1", "testDef2", "testDef3", "testDef4"));
+ testDefinitionNames.forEach(name->{
+ TestDefinition testDefinition = new TestDefinition();
+ testDefinition.setDisabled(false);
+ testDefinition.setTestName(name);
+ testDefinition.setTestDescription(name+" description");
+ testDefinition.setProcessDefinitionKey(name+"key");
+ testDefinition.setCreatedBy(createMechUserIfNotExists().get_id());
+ testDefinition.setGroupId(createMechGroupIfNotExists().get_id());
+ testDefinition.setCreatedAt(new Timestamp(new Date().getTime()));
+ testDefinition.setUpdatedAt(new Timestamp(new Date().getTime()));
+ mongoTemplate.save(testDefinition, "testDefinitions");
+ });
+ }
+ public static void createTestInstances(){
+ List<String> testInstanceName = new ArrayList<>(Arrays.asList("TestInstance1", "TestInstance2", "TestInstance3", "TestInstance4"));
+ testInstanceName.forEach(name->{
+ TestInstance testInstance = new TestInstance();
+ testInstance.setTestInstanceName(name);
+ testInstance.setTestInstanceDescription(name+" description");
+ testInstance.setCreatedBy(createMechUserIfNotExists().get_id());
+ testInstance.setGroupId(createMechGroupIfNotExists().get_id());
+ testInstance.setTestDefinitionId(createMechTestDefinitionIfNotExists().get_id());
+ testInstance.setMaxExecutionTimeInMillis(new Random().nextInt(5000));
+ testInstance.setUseLatestTestDefinition(true);
+ mongoTemplate.save(testInstance, "testInstances");
+ });
+ }
+
+ public static void createTestExecutions(){
+ List<String> results = new ArrayList<>(Arrays.asList("COMPLETED", "FAILED", "PASSED", "INCOMPLETE"));
+ results.forEach(result->{
+ TestExecution testExecution = new TestExecution();
+ testExecution.setAsync(false);
+ testExecution.setExecutorId(createMechUserIfNotExists().get_id());
+ testExecution.setGroupId(createMechGroupIfNotExists().get_id());
+ testExecution.setStartTime(new Timestamp(new Date().getTime()));
+ testExecution.setEndTime(new Timestamp(DateUtils.addHours(new Date(),3).getTime()));
+ testExecution.setTestResult(result);
+ testExecution.setTestResultMessage("Process result is: "+ result);
+ mongoTemplate.save(testExecution, "testExecutions");
+ });
+ }
+
+ public static void createAllAdmin(){
+ createMechTestDefinitionIfNotExists();
+ createMechTestInstanceIfNotExists();
+ }
+
+ public static void createAllTables()throws Exception{
+ setup();
+ createUsers();
+ createGroups();
+ createTeatHeads();
+ createTestDefinitions();
+ createTestInstances();
+ createTestExecutions();
+ }
+
+ public static void cleanup(){
+ mongodExecutable.stop();
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/DefinitionTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/DefinitionTest.java
new file mode 100644
index 0000000..be607d1
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/DefinitionTest.java
@@ -0,0 +1,82 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models;
+
+import org.oran.otf.common.model.TestDefinition;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class DefinitionTest {
+ private static TestDefinition testDefinition;
+
+ @BeforeClass
+ public static void setup(){
+ testDefinition = new TestDefinition();
+ }
+
+ @Test
+ public void testDefinitionHasTestNameField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("testName");
+ }
+
+ @Test
+ public void testDefinitionHasTestDescriptionField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("testDescription");
+ }
+ @Test
+ public void testDefinitionHasProcessDefinitionKeyField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("processDefinitionKey");
+ }
+ @Test
+ public void testDefinitionHasBpmnInstancesField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("bpmnInstances");
+ }
+ @Test
+ public void testDefinitionHasGroupIdField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("groupId");
+ }
+ @Test
+ public void testDefinitionHasCreatedAtField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("createdAt");
+ }
+ @Test
+ public void testDefinitionHasUpdateAtField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("updatedAt");
+ }
+ @Test
+ public void testDefinitionHasCreatedByField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("createdBy");
+ }
+ @Test
+ public void testDefinitionHasUpdatedByField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("updatedBy");
+ }
+ @Test
+ public void testDefinitionHasDisabledField(){
+ Assertions.assertThat(testDefinition).hasFieldOrProperty("disabled");
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/ExecutionTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/ExecutionTest.java
new file mode 100644
index 0000000..966ee76
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/ExecutionTest.java
@@ -0,0 +1,107 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models;
+
+import org.oran.otf.common.model.TestExecution;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ExecutionTest {
+ private static TestExecution testExecution;
+
+ @BeforeClass
+ public static void setup(){
+ testExecution = new TestExecution();
+ }
+
+ @Test
+ public void testExecutionHasGroupIdField(){
+ Assertions.assertThat(testExecution).hasFieldOrProperty("groupId");
+ }
+ @Test
+ public void testExecutionHasExecutorIdField(){
+ Assertions.assertThat(testExecution).hasFieldOrProperty("executorId");
+ }
+ @Test
+ public void testExecutionHasAsyncField(){
+ Assertions.assertThat(testExecution).hasFieldOrProperty("async");
+ }
+ @Test
+ public void testExecutionHasStartTimeField(){
+ Assertions.assertThat(testExecution).hasFieldOrProperty("startTime");
+ }
+ @Test
+ public void testExecutionHasEndTimeField(){
+ Assertions.assertThat(testExecution).hasFieldOrProperty("endTime");
+ }
+ @Test
+ public void testExecutionHasAsyncTopicField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("asyncTopic");
+ }
+ @Test
+ public void testExecutionHasBussinessKeyField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("businessKey");
+ }
+ @Test
+ public void testExecutionHasProcessInstanceIdField(){
+ Assertions.assertThat(testExecution).hasFieldOrProperty("processInstanceId");
+ }
+ @Test
+ public void testExecutionHasTestResultField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("testResult");
+ }
+ @Test
+ public void testExecutionHasTestResultMessageField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("testResultMessage");
+ }
+ @Test
+ public void testExecutionHasTestDetailsField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("testDetails");
+ }
+ @Test
+ public void testExecutionHasTestHeadResultsField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("testHeadResults");
+ }
+ @Test
+ public void testExecutionHasTestInstanceResultsField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("testInstanceResults");
+ }
+ @Test
+ public void testExecutionHasHistoricEmailField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("historicEmail");
+ }
+ @Test
+ public void testExecutionHasHistoricTestInstanceField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("historicTestInstance");
+ }
+ @Test
+ public void testExecutionHasHistoricTestDefinitionField(){
+
+ Assertions.assertThat(testExecution).hasFieldOrProperty("historicTestDefinition");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/GroupTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/GroupTest.java
new file mode 100644
index 0000000..c28a406
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/GroupTest.java
@@ -0,0 +1,50 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.oran.otf.common.model.Group;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+public class GroupTest {
+ private static Group group;
+ @BeforeClass
+ public static void setup(){
+ group = new Group();
+ }
+ @Test
+ public void testGroupHasNameField(){
+ assertThat(group).hasFieldOrProperty("groupName");
+ }
+ @Test
+ public void testGroupHasGroupDescriptionField(){
+ assertThat(group).hasFieldOrProperty("groupDescription");
+ }
+
+ @Test
+ public void testGroupHasMechanizedIdsField(){
+ assertThat(group).hasFieldOrProperty("mechanizedIds");
+ }
+
+ @Test
+ public void testGroupHasOwnerIdField(){
+ assertThat(group).hasFieldOrProperty("ownerId");
+ }
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/HeadTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/HeadTest.java
new file mode 100644
index 0000000..00ba7ca
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/HeadTest.java
@@ -0,0 +1,72 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models;
+
+import org.oran.otf.common.model.TestHead;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class HeadTest {
+ private static TestHead testHead;
+
+ @BeforeClass
+ public static void setup(){
+ testHead = new TestHead();
+ }
+ @Test
+ public void testHeadHasTestHeadNameField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("testHeadName");
+ }
+ @Test
+ public void testHeadHasTestHeadDescriptionField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("testHeadDescription");
+ }
+ @Test
+ public void testHeadHasHostNameField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("hostname");
+ }
+ @Test
+ public void testHeadHasPortField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("port");
+ }
+ @Test
+ public void testHeadHasResourcePathField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("resourcePath");
+ }
+ @Test
+ public void testHeadHasCreatorIdField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("creatorId");
+ }
+ @Test
+ public void testHeadHasGroupIdField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("groupId");
+ }
+ @Test
+ public void testHeadHasCreatedAtField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("createdAt");
+ }
+ @Test
+ public void testHeadHasUpdatedAtField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("updatedAt");
+ }
+ @Test
+ public void testHeadHasUpdatedByField(){
+ Assertions.assertThat(testHead).hasFieldOrProperty("updatedBy");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/InstanceTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/InstanceTest.java
new file mode 100644
index 0000000..3f1a4be
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/InstanceTest.java
@@ -0,0 +1,104 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models;
+
+import org.oran.otf.common.model.TestInstance;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class InstanceTest {
+
+ private static TestInstance testInstance;
+
+ @BeforeClass
+ public static void setup(){
+ testInstance = new TestInstance();
+ }
+ @Test
+ public void testInstanceHasTestInstanceNameField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("testInstanceName");
+ }
+ @Test
+ public void testInstanceHasInstanceDescriptionField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("testInstanceDescription");
+ }
+ @Test
+ public void testInstanceHasGroupIdField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("groupId");
+ }
+ @Test
+ public void testInstanceHasTestDefinitionIdField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("testDefinitionId");
+ }
+ @Test
+ public void testInstanceHasProcessDefinitionIdField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("processDefinitionId");
+ }
+ @Test
+ public void testInstanceHasUseLatestTestDefinitionField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("useLatestTestDefinition");
+ }
+ @Test
+ public void testInstanceHasDisabledField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("disabled");
+ }
+ @Test
+ public void testInstanceHasSimulationModeField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("simulationMode");
+ }
+ @Test
+ public void testInstanceHasMaxExecutionTimeInMillisField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("maxExecutionTimeInMillis");
+ }
+ @Test
+ public void testInstanceHasPfloInputField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("pfloInput");
+ }
+ @Test
+ public void testInstanceHasInternalTestDataField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("internalTestData");
+ }
+ @Test
+ public void testInstanceHasSimulationVthInputField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("simulationVthInput");
+ }
+ @Test
+ public void testInstanceHasTestDataField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("testData");
+ }
+ @Test
+ public void testInstanceHasVthInputField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("vthInput");
+ }
+ @Test
+ public void testInstanceHasCreatedAtField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("createdAt");
+ }
+ @Test
+ public void testInstanceHasUpdatedAtField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("updatedAt");
+ }
+ @Test
+ public void testInstanceHasCreatedByField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("createdBy");
+ }
+ @Test
+ public void testInstanceHasUpdatedByField(){
+ Assertions.assertThat(testInstance).hasFieldOrProperty("updatedBy");
+ }
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/UserTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/UserTest.java
new file mode 100644
index 0000000..49fb31c
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/UserTest.java
@@ -0,0 +1,63 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models;
+
+import org.oran.otf.common.model.User;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class UserTest {
+
+ private static User user;
+ @BeforeClass
+ public static void setup(){
+ user = new User();
+ }
+ @Test
+ public void testUserHasPermissionsField(){
+ Assertions.assertThat(user).hasFieldOrProperty("permissions");
+ }
+ @Test
+ public void testUserHasFirstNameField(){
+ Assertions.assertThat(user).hasFieldOrProperty("firstName");
+ }
+ @Test
+ public void testUserHasLastNameField(){
+ Assertions.assertThat(user).hasFieldOrProperty("lastName");
+ }
+ @Test
+ public void testUserHasEmailField(){
+ Assertions.assertThat(user).hasFieldOrProperty("email");
+ }
+ @Test
+ public void testUserHasPasswordField(){
+ Assertions.assertThat(user).hasFieldOrProperty("password");
+ }
+ @Test
+ public void testUserHasGroupsField(){
+ Assertions.assertThat(user).hasFieldOrProperty("groups");
+ }
+ @Test
+ public void testUserHasCreatedAtField(){
+ Assertions.assertThat(user).hasFieldOrProperty("createdAt");
+ }
+ @Test
+ public void testUserHasUpdatedAtField(){
+ Assertions.assertThat(user).hasFieldOrProperty("updatedAt");
+ }
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/BpmnTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/BpmnTest.java
new file mode 100644
index 0000000..2f7f166
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/BpmnTest.java
@@ -0,0 +1,83 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class BpmnTest {
+ private static BpmnInstance bpmnInstance;
+ @BeforeClass
+ public static void setup(){
+ bpmnInstance = new BpmnInstance();
+ }
+ @Test
+ public void testBpmnInstanceHasProcessDefinitionIdField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("processDefinitionId");
+ }
+ @Test
+ public void testBpmnInstanceHasDeploymentIdField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("deploymentId");
+ }
+ @Test
+ public void testBpmnInstanceHasVersionField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("version");
+ }
+ @Test
+ public void testBpmnInstanceHasBpmnFileIdField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("bpmnFileId");
+ }
+ @Test
+ public void testBpmnInstanceHasResourceFileIdField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("resourceFileId");
+ }
+ @Test
+ public void testBpmnInstanceHasIsDeployedField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("isDeployed");
+ }
+ @Test
+ public void testBpmnInstanceHasTestHeadsField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("testHeads");
+ }
+ @Test
+ public void testBpmnInstanceHasPflowsField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("pflos");
+ }
+ @Test
+ public void testBpmnInstanceHasTestDataTemplateField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("testDataTemplate");
+ }
+ @Test
+ public void testBpmnInstanceHasCreatedAtField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("createdAt");
+ }
+ @Test
+ public void testBpmnInstanceUpdatedAtField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("updatedAt");
+ }
+ @Test
+ public void testBpmnInstanceHasCreatedByField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("createdBy");
+ }
+ @Test
+ public void testBpmnInstanceHasUpdatedByField(){
+ Assertions.assertThat(bpmnInstance).hasFieldOrProperty("updatedBy");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/DeployTestStrategyRequestTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/DeployTestStrategyRequestTest.java
new file mode 100644
index 0000000..b41c4ee
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/DeployTestStrategyRequestTest.java
@@ -0,0 +1,44 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.DeployTestStrategyRequest;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class DeployTestStrategyRequestTest {
+ private static DeployTestStrategyRequest deployTestStrategyRequest;
+
+ @BeforeClass
+ public static void setup(){
+ deployTestStrategyRequest = new DeployTestStrategyRequest();
+ }
+ @Test
+ public void testDeployTestStrategyRequestHasTestDefinitionDeployerIdField(){
+ Assertions.assertThat(deployTestStrategyRequest).hasFieldOrProperty("testDefinitionDeployerId");
+ }
+ @Test
+ public void testDeployTestStrategyRequestHasTestDefinitionIdField(){
+ Assertions.assertThat(deployTestStrategyRequest).hasFieldOrProperty("TestDefinitionId");
+ }
+ @Test
+ public void testDeployTestStrategyRequestHasDefinitionIdField(){
+ Assertions.assertThat(deployTestStrategyRequest).hasFieldOrProperty("DefinitionId");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/HeadNodeTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/HeadNodeTest.java
new file mode 100644
index 0000000..fe0ce0f
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/HeadNodeTest.java
@@ -0,0 +1,40 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.TestHeadNode;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class HeadNodeTest {
+ private static TestHeadNode testHeadNode;
+
+ @BeforeClass
+ public static void setup(){
+ testHeadNode = new TestHeadNode();
+ }
+ @Test
+ public void testHeadNodeHasTestHeadIdField(){
+ Assertions.assertThat(testHeadNode).hasFieldOrProperty("testHeadId");
+ }
+ @Test
+ public void testHeadNodeHasBpmnVthTaskIdField(){
+ Assertions.assertThat(testHeadNode).hasFieldOrProperty("bpmnVthTaskId");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/HeadResultTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/HeadResultTest.java
new file mode 100644
index 0000000..1fde494
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/HeadResultTest.java
@@ -0,0 +1,60 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.TestHeadResult;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class HeadResultTest {
+ private static TestHeadResult testHeadResult;
+
+ @BeforeClass
+ public static void setup(){
+ testHeadResult = new TestHeadResult();
+ }
+ @Test
+ public void testHeadResultHasTestHeadIdField(){
+ Assertions.assertThat(testHeadResult).hasFieldOrProperty("testHeadId");
+ }
+ @Test
+ public void testHeadResultHasTestHeadNameField(){
+ Assertions.assertThat(testHeadResult).hasFieldOrProperty("testHeadName");
+ }
+ @Test
+ public void testHeadResultHasBpmnVthTaskIdField(){
+ Assertions.assertThat(testHeadResult).hasFieldOrProperty("bpmnVthTaskId");
+ }
+ @Test
+ public void testHeadResultHasTestHeadRequestField(){
+ Assertions.assertThat(testHeadResult).hasFieldOrProperty("testHeadRequest");
+ }
+ @Test
+ public void testHeadResultHasTestHeadResponseField(){
+ Assertions.assertThat(testHeadResult).hasFieldOrProperty("testHeadResponse");
+ }
+ @Test
+ public void testHeadResultHasStartTimeField(){
+ Assertions.assertThat(testHeadResult).hasFieldOrProperty("startTime");
+ }
+ @Test
+ public void testHeadResultHasEndTimeField(){
+ Assertions.assertThat(testHeadResult).hasFieldOrProperty("endTime");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/InstanceCreateRequestTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/InstanceCreateRequestTest.java
new file mode 100644
index 0000000..83fdf09
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/InstanceCreateRequestTest.java
@@ -0,0 +1,93 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.TestInstanceCreateRequest;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class InstanceCreateRequestTest {
+ private static TestInstanceCreateRequest testInstanceCreateRequest;
+
+ @BeforeClass
+ public static void setup() throws Exception{
+ //No Argument Constructor does not work because of the requiered name when creating
+ testInstanceCreateRequest = new TestInstanceCreateRequest(
+ "Name",
+ "Description",
+ null,
+ null,
+ null,
+ null,
+ null,
+ true,
+ false,
+ 0L
+ );
+ }
+
+ @Test
+ public void testInstanceCreateRequestHasTestDefinitionIdField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("testDefinitionId");
+ }
+ @Test
+ public void testInstanceCreateRequestHasVersionField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("version");
+ }
+ @Test
+ public void testInstanceCreateRequestHasProcessDefinitionKeyField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("processDefinitionKey");
+ }
+ @Test
+ public void testInstanceCreateRequestHastestInstanceNameField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("testInstanceName");
+ }
+ @Test
+ public void testInstanceCreateRequestHasPfloInputField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("pfloInput");
+ }
+ @Test
+ public void testInstanceCreateRequestHasSimulationVthInputField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("simulationVthInput");
+ }
+ @Test
+ public void testInstanceCreateRequestHasTestDataField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("testData");
+ }
+ @Test
+ public void testInstanceCreateRequestHasVthInputField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("vthInput");
+ }
+ @Test
+ public void testInstanceCreateRequestHasCreatedByField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("createdBy");
+ }
+ @Test
+ public void testInstanceCreateRequestHasUseLatestTestDefinitionField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("useLatestTestDefinition");
+ }
+ @Test
+ public void testInstanceCreateRequestHasSimulationModeField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("simulationMode");
+ }
+ @Test
+ public void testInstanceCreateRequestHasMaxExecutionTimeInMillisField(){
+ Assertions.assertThat(testInstanceCreateRequest).hasFieldOrProperty("maxExecutionTimeInMillis");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/OtfApiResponseTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/OtfApiResponseTest.java
new file mode 100644
index 0000000..45c10a4
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/OtfApiResponseTest.java
@@ -0,0 +1,43 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class OtfApiResponseTest {
+ private static OTFApiResponse otfApiResponse;
+ @BeforeClass
+ public static void setup(){
+ otfApiResponse = new OTFApiResponse();
+ }
+ @Test
+ public void testOtfApiResponseHasStatusCodeField(){
+ Assertions.assertThat(otfApiResponse).hasFieldOrProperty("statusCode");
+ }
+ @Test
+ public void testOtfApiResponseHasMessageField(){
+ Assertions.assertThat(otfApiResponse).hasFieldOrProperty("message");
+ }
+ @Test
+ public void testOtfApiResponseHasTimeField(){
+ Assertions.assertThat(otfApiResponse).hasFieldOrProperty("time");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/ParallelFlowInputTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/ParallelFlowInputTest.java
new file mode 100644
index 0000000..320df54
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/ParallelFlowInputTest.java
@@ -0,0 +1,47 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.ParallelFlowInput;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ParallelFlowInputTest {
+ private static ParallelFlowInput parallelFlowInput;
+ @BeforeClass
+ public static void setup(){
+ parallelFlowInput = new ParallelFlowInput();
+ }
+ @Test
+ public void testParallelFlowInputHasArgsField(){
+ Assertions.assertThat(parallelFlowInput).hasFieldOrProperty("args");
+ }
+ @Test
+ public void testParallelFlowInputHasInterruptOnFailureField(){
+ Assertions.assertThat(parallelFlowInput).hasFieldOrProperty("interruptOnFailure");
+ }
+ @Test
+ public void testParallelFlowInputHasMaxFailuresField(){
+ Assertions.assertThat(parallelFlowInput).hasFieldOrProperty("maxFailures");
+ }
+ @Test
+ public void testParallelFlowInputHasThreadPoolSizeField(){
+ Assertions.assertThat(parallelFlowInput).hasFieldOrProperty("threadPoolSize");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/PfloNodeTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/PfloNodeTest.java
new file mode 100644
index 0000000..7a0a20b
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/PfloNodeTest.java
@@ -0,0 +1,40 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.PfloNode;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class PfloNodeTest {
+ private static PfloNode pfloNode;
+
+ @BeforeClass
+ public static void setup(){
+ pfloNode = new PfloNode();
+ }
+ @Test
+ public void testPfloNodeHasBpmnPfloTaskIdField(){
+ Assertions.assertThat(pfloNode).hasFieldOrProperty("bpmnPlfoTaskId");
+ }
+ @Test
+ public void testPfloNodeHasLabelField(){
+ Assertions.assertThat(pfloNode).hasFieldOrProperty("label");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/UserGroupTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/UserGroupTest.java
new file mode 100644
index 0000000..92e7497
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/UserGroupTest.java
@@ -0,0 +1,42 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.UserGroup;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class UserGroupTest {
+ private static UserGroup userGroup;
+
+ //TODO (DONE): Added NoArg Constructor to UserGroup model for testing
+ @BeforeClass
+ public static void setup(){
+ userGroup = new UserGroup();
+ }
+
+ @Test
+ public void testUserGroupHasGroupIdField(){
+ Assertions.assertThat(userGroup).hasFieldOrProperty("groupId");
+ }
+ @Test
+ public void testUserGroupHasPermissionsField(){
+ Assertions.assertThat(userGroup).hasFieldOrProperty("permissions");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/WorkFlowRequestTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/WorkFlowRequestTest.java
new file mode 100644
index 0000000..6debf07
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/models/local/WorkFlowRequestTest.java
@@ -0,0 +1,61 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.models.local;
+
+import org.oran.otf.common.model.local.WorkflowRequest;
+import org.assertj.core.api.Assertions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class WorkFlowRequestTest {
+ private static WorkflowRequest workflowRequest;
+
+ @BeforeClass
+ public static void setup()throws Exception{
+ workflowRequest = new WorkflowRequest();
+ }
+
+ @Test
+ public void testWorkFlowRequestHasAsyncField(){
+ Assertions.assertThat(workflowRequest).hasFieldOrProperty("async");
+ }
+ @Test
+ public void testWorkFlowRequestHasExecutorIdField(){
+ Assertions.assertThat(workflowRequest).hasFieldOrProperty("executorId");
+ }
+ @Test
+ public void testWorkFlowRequestHasTestInstanceIdField(){
+ Assertions.assertThat(workflowRequest).hasFieldOrProperty("testInstanceId");
+ }
+ @Test
+ public void testWorkFlowRequestHasPfloInputField(){
+ Assertions.assertThat(workflowRequest).hasFieldOrProperty("pfloInput");
+ }
+ @Test
+ public void testWorkFlowRequestHasTestDataField(){
+ Assertions.assertThat(workflowRequest).hasFieldOrProperty("testData");
+ }
+ @Test
+ public void testWorkFlowRequestHasVthInputField(){
+ Assertions.assertThat(workflowRequest).hasFieldOrProperty("vthInput");
+ }
+ @Test
+ public void testWorkFlowRequestHasMaxExecutionTimeInMillisField(){
+ Assertions.assertThat(workflowRequest).hasFieldOrProperty("maxExecutionTimeInMillis");
+ }
+
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/utility/BuildResponseTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/utility/BuildResponseTest.java
new file mode 100644
index 0000000..15afaa3
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/utility/BuildResponseTest.java
@@ -0,0 +1,74 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.utility;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+
+public class BuildResponseTest {
+ @Test
+ public void badResponseTest(){
+ Response badResponse = Utilities.Http.BuildResponse.badRequest();
+ Assert.assertNotNull(badResponse);
+ Assert.assertEquals(badResponse.getStatus(),400);
+ }
+
+ @Test
+ public void badRequestWithMessageTest() {
+ Response badResponse = Utilities.Http.BuildResponse.badRequestWithMessage("this is bad");
+ OTFApiResponse response = (OTFApiResponse) badResponse.getEntity();
+
+ Assert.assertNotNull(badResponse);
+ Assert.assertEquals(badResponse.getStatus(),400);
+ Assert.assertEquals(response.getStatusCode(), 400);
+ Assert.assertEquals(response.getMessage(), "this is bad");
+ }
+ @Test
+ public void internalServerErrorTest(){
+ Response badResponse = Utilities.Http.BuildResponse.internalServerError();
+ Assert.assertNotNull(badResponse);
+ Assert.assertEquals(badResponse.getStatus(),500);
+ }
+ @Test
+ public void internalServerErrorWithMessageTest(){
+ Response badResponse = Utilities.Http.BuildResponse.internalServerErrorWithMessage("internal error");
+ OTFApiResponse response = (OTFApiResponse) badResponse.getEntity();
+
+ Assert.assertNotNull(badResponse);
+ Assert.assertEquals(badResponse.getStatus(),500);
+ Assert.assertEquals(response.getStatusCode(), 500);
+ Assert.assertEquals(response.getMessage(), "internal error");
+ }
+
+ @Test
+ public void unauthorizedTest(){
+ Response basicUnauthorizedResponse= Utilities.Http.BuildResponse.unauthorized();
+ Response unauthorizedMsgResponse = Utilities.Http.BuildResponse.unauthorizedWithMessage("unauthorized");
+ OTFApiResponse response = (OTFApiResponse) unauthorizedMsgResponse.getEntity();
+
+ Assert.assertNotNull(basicUnauthorizedResponse);
+ Assert.assertNotNull(unauthorizedMsgResponse);
+ Assert.assertEquals(basicUnauthorizedResponse.getStatus(),401);
+ Assert.assertEquals(unauthorizedMsgResponse.getStatus(),401);
+ Assert.assertEquals(response.getStatusCode(),401);
+ Assert.assertEquals(response.getMessage(),"unauthorized");
+ }
+}
diff --git a/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/utility/UserPermissionTest.java b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/utility/UserPermissionTest.java
new file mode 100644
index 0000000..e2d7954
--- /dev/null
+++ b/otf-service-api/src/test/java/org/oran/otf/api/tests/unit/utility/UserPermissionTest.java
@@ -0,0 +1,67 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# 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. #
+##############################################################################*/
+
+
+package org.oran.otf.api.tests.unit.utility;
+
+import org.oran.otf.common.utility.permissions.UserPermission;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UserPermissionTest {
+
+ @Mock
+ Map<String, Set<String>> userAccessMap ;
+
+ @InjectMocks
+ private UserPermission userPermission;
+
+ @Before
+ public void setUp()
+ {
+ String fakeGroupId1 = "abc123";
+ Set<String> user1Permissions = new HashSet<>(Arrays.asList("READ","WRITE"));
+ Mockito.when(userAccessMap.get(fakeGroupId1)).thenReturn(user1Permissions);
+ }
+
+ @Test
+ public void testHasAccessToMethod(){
+
+ Assert.assertNotNull(userPermission.getUserAccessMap());
+ //test when user have access to group with certain permissions and a fake permission(mix of upper and lower case
+ Assert.assertTrue(userPermission.hasAccessTo("abc123","READ"));
+ Assert.assertTrue(userPermission.hasAccessTo("abc123","WrIte"));
+ Assert.assertFalse(userPermission.hasAccessTo("abc123","DEleTE"));
+ Assert.assertFalse(userPermission.hasAccessTo("abc123","ExECUTe"));
+ Assert.assertFalse(userPermission.hasAccessTo("abc123","mANAgEMENT"));
+ Assert.assertFalse(userPermission.hasAccessTo("abc123","READ+WRITE"));
+
+ //test when user have no access to the group
+ Assert.assertFalse(userPermission.hasAccessTo("edf567","READ"));
+ Assert.assertFalse(userPermission.hasAccessTo("edf567","WRITE"));
+ Assert.assertFalse(userPermission.hasAccessTo("edf567","DELETE"));
+ Assert.assertFalse(userPermission.hasAccessTo("edf567","EXECUTE"));
+ Assert.assertFalse(userPermission.hasAccessTo("edf567","MANAGEMENT"));
+ }
+}
diff --git a/otf-service-api/src/test/resources/application-test.properties b/otf-service-api/src/test/resources/application-test.properties
new file mode 100644
index 0000000..a0a7d2a
--- /dev/null
+++ b/otf-service-api/src/test/resources/application-test.properties
@@ -0,0 +1,19 @@
+server.port=8443
+server.port.http=8181
+
+otf.mongo.hosts=${OTF_MONGO_HOSTS}
+otf.mongo.username=${OTF_MONGO_USERNAME}
+otf.mongo.password=${OTF_MONGO_PASSWORD}
+otf.mongo.replicaSet=${OTF_MONGO_REPLICASET}
+otf.mongo.database=${OTF_MONGO_DATABASE}
+
+cadi.prop.files=src/main/resources/cadi.properties
+
+otf.proxy=localhost
+otf.proxy-port=8080
+otf.embedded.host=localhost
+otf.embedded.port=5555
+otf.embedded.database=otf
+
+otf.mechid=${AAF_ID}
+otf.mechpass=${AAF_MECH_PASSWORD}
diff --git a/otf-service-api/swagger.json b/otf-service-api/swagger.json
new file mode 100644
index 0000000..2f5f6c8
--- /dev/null
+++ b/otf-service-api/swagger.json
@@ -0,0 +1 @@
+{"openapi":"3.0.1","info":{"title":"Open Test Framework API","description":"A RESTful API used to communicate with the OTF test control unit.","contact":{"name":"OTF","url":"https://localhost:32524"},"version":"1.0"},"tags":[{"name":"Health Service","description":"Query the availability of the API"},{"name":"Test Execution Service","description":"Query the status and history of your test executions"},{"name":"Test Instance Service","description":"Create, execute, and query test instances"},{"name":"Test Strategy Service","description":"Deploy and delete test strategies to and from the test control unit. (This documentation will only be available to the development team)"}],"paths":{"/otf/api/health/v1":{"get":{"tags":["Health Service"],"summary":"Checks if the test control unit is available","operationId":"getHealth_1","responses":{"200":{"description":"The test control unit is available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}}}}},"/otf/api/testExecution/v1/executionId/{executionId}":{"get":{"tags":["Test Execution Service"],"operationId":"getExecutionStatus_1","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","schema":{"type":"string"}}],"responses":{"default":{"description":"default response","content":{"application/json":{}}}}}},"/otf/api/testInstance/execute/v1/id/{testInstanceId}":{"post":{"tags":["Test Instance Service"],"summary":"Executes a test instance by it's unique identifier","operationId":"execute_1","parameters":[{"name":"testInstanceId","in":"path","description":"A string representation of a BSON ObjectId","required":true,"schema":{"type":"string","description":"The UUID of the test instance","format":"uuid"},"example":"12345678912345678912345f"},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteTestInstanceRequest"}}}},"responses":{"200":{"description":"A successful synchronously executed test returns a test execution object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestExecutionResult"}}}},"201":{"description":"A successful asynchronously executed test with asyncMode set to 'poll' returns an execution identifier\nThe identifier can be used as a parameter to the Test Execution Service to check the status of the executed test","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestExecutionResult"}}}},"401":{"description":"The mechanized identifier used with the request is prohibited from accessing the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}}}}},"/otf/api/testInstance/v1/id/{id}":{"get":{"tags":["Test Instance Service"],"operationId":"findById_1","parameters":[{"name":"id","in":"path","description":"A string representation of a BSON ObjectId","required":true,"schema":{"type":"string","description":"The UUID of the test instance","format":"uuid"},"example":"12345678912345678912345f"},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="}],"responses":{"default":{"description":"default response","content":{"application/json":{}}}}}},"/otf/api/testInstance/create/v1/testDefinitionId/{testDefinitionId}/version/{version}":{"post":{"tags":["Test Instance Service"],"summary":"Create a test instance using the specified version of the test definition","operationId":"createByTestDefinitionIdAndVersion_1","parameters":[{"name":"testDefinitionId","in":"path","description":"A string representation of a BSON ObjectId","required":true,"schema":{"type":"string","description":"The UUID of the test definition.","format":"uuid"},"example":"12345678912345678912345f"},{"name":"version","in":"path","description":"The version of the test definition used to create the instance","required":true,"schema":{"type":"string"},"example":2},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="},{"name":"execute","in":"query","description":"Execute the test instance after it is created","allowEmptyValue":true,"schema":{"type":"boolean"},"example":true}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTestInstanceRequest"}}}},"responses":{"201":{"description":"The created Test Instance object is returned when it is created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInstance"}}}}}}},"/otf/api/testInstance/v1/testInstanceName/{testInstanceName}":{"get":{"tags":["Test Instance Service"],"summary":"Finds a test instance by it's name","operationId":"findByTestInstanceName_1","parameters":[{"name":"testInstanceName","in":"path","description":"The name of the test instance to retrieve","required":true,"schema":{"type":"string"},"example":"myTestInstance"},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="}],"responses":{"200":{"description":"A test instance object is returned when if it is found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInstance"}}}}}}},"/otf/api/testInstance/v1/processDefinitionKey/{processDefinitionKey}":{"get":{"tags":["Test Instance Service"],"operationId":"findByProcessDefKey_1","parameters":[{"name":"processDefinitionKey","in":"path","description":"The process definition key associated with the test definition","required":true,"schema":{"type":"string"},"example":"someUniqueProcessDefinitionKey"},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="}],"responses":{"default":{"description":"default response","content":{"application/json":{}}}}}},"/otf/api/testInstance/create/v1/testDefinitionId/{testDefinitionId}":{"post":{"tags":["Test Instance Service"],"summary":"Create a test instance using the latest version of the test definition","operationId":"createByTestDefinitionId_1","parameters":[{"name":"testDefinitionId","in":"path","description":"A string representation of a BSON ObjectId","required":true,"schema":{"type":"string","description":"The UUID of the test definition","format":"uuid"},"example":"12345678912345678912345f"},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="},{"name":"execute","in":"query","description":"Execute the test instance after it is created","allowEmptyValue":true,"schema":{"type":"boolean"},"example":true}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTestInstanceRequest"}}}},"responses":{"201":{"description":"The created Test Instance object is returned when it is created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInstance"}}}}}}},"/otf/api/testInstance/v1/processDefinitionKey/{processDefinitionKey}/version/{version}":{"get":{"tags":["Test Instance Service"],"operationId":"findByProcessDefKeyAndVersion_1","parameters":[{"name":"processDefinitionKey","in":"path","description":"The process definition key associated with the test definition","required":true,"schema":{"type":"string"},"example":"someUniqueProcessDefinitionKey"},{"name":"version","in":"path","description":"The version of the test definition used to create the instance","required":true,"schema":{"type":"string"},"example":2},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="}],"responses":{"default":{"description":"default response","content":{"application/json":{}}}}}},"/otf/api/testInstance/create/v1/processDefinitionKey/{processDefinitionKey}/version/{version}":{"post":{"tags":["Test Instance Service"],"summary":"Create a test instance using the specified version of the test definition","operationId":"createByProcessDefKeyAndVersion_1","parameters":[{"name":"processDefinitionKey","in":"path","description":"The process definition key associated with the test definition","required":true,"schema":{"type":"string"},"example":"someUniqueProcessDefinitionKey"},{"name":"version","in":"path","description":"The version of the test definition used to create the instance","required":true,"schema":{"type":"string"},"example":2},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="},{"name":"execute","in":"query","description":"Execute the test instance after it is created","allowEmptyValue":true,"schema":{"type":"boolean"},"example":true}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTestInstanceRequest"}}}},"responses":{"201":{"description":"The created Test Instance object is returned when it is created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInstance"}}}}}}},"/otf/api/testInstance/create/v1/processDefinitionKey/{processDefinitionKey}":{"post":{"tags":["Test Instance Service"],"summary":"Create a test instance using the latest version of the test definition","operationId":"createByProcessDefKey_1","parameters":[{"name":"processDefinitionKey","in":"path","description":"The process definition key associated with the test definition","required":true,"schema":{"type":"string"},"example":"someUniqueProcessDefinitionKey"},{"name":"Authorization","in":"header","description":"Base64 encoded Application Authorization Framework credentials","required":true,"schema":{"type":"string"},"example":"Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM="},{"name":"execute","in":"query","description":"Execute the test instance after it is created","allowEmptyValue":true,"schema":{"type":"boolean"},"example":true}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTestInstanceRequest"}}}},"responses":{"201":{"description":"The created Test Instance object is returned when it is created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInstance"}}}}}}},"/otf/api/testStrategy/delete/v1/deploymentId/{deploymentId}":{"delete":{"tags":["Test Strategy Service"],"operationId":"deleteByDeploymentId_1","parameters":[{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string"}},{"name":"authorization","in":"header","schema":{"type":"string"}}],"responses":{"default":{"description":"default response","content":{"application/json":{}}}}}},"/otf/api/testStrategy/delete/v1/testDefinitionId/{testDefinitionId}":{"delete":{"tags":["Test Strategy Service"],"operationId":"deleteByTestDefinitionId_1","parameters":[{"name":"testDefinitionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"authorization","in":"header","schema":{"type":"string"}}],"responses":{"default":{"description":"default response","content":{"application/json":{}}}}}},"/otf/api/testStrategy/deploy/v1":{"post":{"tags":["Test Strategy Service"],"operationId":"deployTestStrategy_1","parameters":[{"name":"Authorization","in":"header","schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"bpmn":{"type":"object"},"resources":{"type":"object"},"testDefinitionId":{"type":"string"},"testDefinitionDeployerId":{"type":"string"},"definitionId":{"type":"string"}}}}}},"responses":{"default":{"description":"default response","content":{"application/json":{}}}}}},"/otf/api/application.wadl/{path}":{"get":{"operationId":"getExternalGrammar","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"default":{"description":"default response","content":{"application/xml":{}}}}}},"/otf/api/application.wadl":{"get":{"operationId":"getWadl","responses":{"default":{"description":"default response","content":{"application/vnd.sun.wadl+xml":{},"application/xml":{}}}}}}},"components":{"schemas":{"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"date":{"type":"string","format":"date-time"},"message":{"type":"string"}}},"JSONObject":{"type":"object"},"ObjectId":{"type":"object","properties":{"timestamp":{"type":"integer","format":"int32"},"machineIdentifier":{"type":"integer","format":"int32"},"processIdentifier":{"type":"integer","format":"int32"},"counter":{"type":"integer","format":"int32"},"time":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"},"timeSecond":{"type":"integer","format":"int32"}}},"TestExecution":{"type":"object","properties":{"get_id":{"$ref":"#/components/schemas/ObjectId"},"executionId":{"type":"string"},"testResult":{"type":"string"},"testDetails":{"type":"object","additionalProperties":{"type":"object"}},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"async":{"type":"boolean"},"asyncTopic":{"type":"string"},"asyncMode":{"type":"string"},"executor":{"type":"string"},"groupId":{"$ref":"#/components/schemas/ObjectId"},"testInstanceId":{"$ref":"#/components/schemas/ObjectId"},"testInstance":{"type":"object","additionalProperties":{"type":"object"}},"testHeadResults":{"type":"array","items":{"$ref":"#/components/schemas/TestHeadResult"}},"testDetailsJSON":{"type":"string"},"testInstanceJSON":{"type":"string"}}},"TestExecutionResult":{"type":"object","properties":{"testExecution":{"$ref":"#/components/schemas/TestExecution"},"executionId":{"type":"string"},"testCompleted":{"type":"boolean"},"testExists":{"type":"boolean"}}},"TestHeadResult":{"type":"object","properties":{"testHeadId":{"$ref":"#/components/schemas/ObjectId"},"testHeadName":{"type":"string"},"bpmnVthTaskId":{"type":"string"},"testHeadResponse":{"type":"object","additionalProperties":{"type":"object"}},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"testHeadResponseJSON":{"$ref":"#/components/schemas/JSONObject"}}},"ExecuteTestInstanceRequest":{"type":"object","properties":{"async":{"type":"boolean","writeOnly":true},"asyncTopic":{"title":"Execute the test synchronously or asynchronously..","type":"string","description":"Ignored unless async is true, and asyncMode is DMaaP.","example":"MyDMaaPTopic."},"asyncMode":{"title":"Set the asynchronous execution mode.","type":"string","description":"Ignored unless async is true. The poll mode will return an executionId that can be used to query the result of the executed test. DMaaP is currently unsupported.","example":"POLL","enum":["POLL","DMAAP"]},"testData":{"title":"Use an existing test instance with different global test data.","type":"object","description":"Overrides (not overwrites) the testData field for the requested execution. The overridden data will be preserved in the test execution result.","example":{"globalVar1":"I'm available to your workflow!","globalVar2":{"me":"too"}}},"vthInput":{"title":"Use an existing test instance with different inputs to your VTHs.","type":"object","description":"Overrides (not overwrites) the vthInput field for the requested execution. The overridden data will be preserved in the test execution result.","example":{"ServiceTask_123":{"vthArg1":"An argument your VTH expects.","vthArg2":{}},"ServiceTask_456":{"vthArg1":"An argument your VTH expects."}}}},"description":"The model for a test instance execution request."},"TestInstance":{"type":"object","properties":{"get_id":{"$ref":"#/components/schemas/ObjectId"},"testInstanceName":{"type":"string"},"testInstanceDescription":{"type":"string"},"groupId":{"$ref":"#/components/schemas/ObjectId"},"testDefinitionId":{"$ref":"#/components/schemas/ObjectId"},"processDefinitionId":{"type":"string"},"useLatestTestDefinition":{"type":"boolean"},"testData":{"type":"object","additionalProperties":{"type":"object"}},"vthInput":{"type":"object","additionalProperties":{"type":"object"}},"internalTestData":{"type":"object","additionalProperties":{"type":"object"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdBy":{"$ref":"#/components/schemas/ObjectId"},"updatedBy":{"$ref":"#/components/schemas/ObjectId"},"vthInputJSON":{"$ref":"#/components/schemas/JSONObject"},"testDataJSON":{"$ref":"#/components/schemas/JSONObject"},"internalTestDataJSON":{"$ref":"#/components/schemas/JSONObject"}}},"CreateTestInstanceRequest":{"required":["testData","testInstanceDescription","testInstanceName"],"type":"object","properties":{"testInstanceName":{"title":"Name the test instance","type":"string","description":"The name must be unique among all test instances belonging to the same test definition.","example":"MyTestInstance"},"testInstanceDescription":{"title":"Describe the test instance being created","type":"string","description":"Use this field to describe the functionality of the test instance","example":"This test instance does absolutely nothing!"},"testData":{"title":"Set global variables","type":"object","description":"This field has read and write access by any task within the workflow.\nSee the example for more information","example":{"globalVar1":"I'm available to your workflow!","globalVar2":{"me":"too"}}},"vthInput":{"title":"Set virtual test head data","type":"object","description":"This field determines the data each VTH at the designated ServiceTask will receive.\nSee the example for more information","example":{"ServiceTask_123":{"vthArg1":"An argument your VTH expects.","vthArg2":{}},"ServiceTask_456":{"vthArg1":"An argument your VTH expects."}}},"async":{"type":"boolean"},"asyncTopic":{"type":"string"},"asyncMode":{"type":"string"}},"description":"The model for a test instance creation request."}}}}
\ No newline at end of file
diff --git a/otf-service-api/swagger.yml b/otf-service-api/swagger.yml
new file mode 100644
index 0000000..7bae19f
--- /dev/null
+++ b/otf-service-api/swagger.yml
@@ -0,0 +1,714 @@
+openapi: 3.0.1
+info:
+ title: Open Test Framework API
+ description: A RESTful API used to communicate with the OTF test control unit.
+ contact:
+ name: OTF
+ url: https://localhost:32524
+ version: "1.0"
+tags:
+- name: Health Service
+ description: Query the availability of the API
+- name: Test Execution Service
+ description: Query the status and history of your test executions
+- name: Test Instance Service
+ description: Create, execute,and query test instances
+- name: Test Strategy Service
+ description: Deploy and delete test strategies to and from the test control unit.
+ (This documentation will only be available to the development team)
+paths:
+ /otf/api/health/v1:
+ get:
+ tags:
+ - Health Service
+ summary: Checks if the test control unit is available
+ operationId: getHealth_1
+ responses:
+ 200:
+ description: The test control unit is available
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OtfApiResponse'
+ /otf/api/testExecution/v1/executionId/{executionId}:
+ get:
+ tags:
+ - Test Execution Service
+ operationId: getExecutionStatus_1
+ parameters:
+ - name: executionId
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ in: header
+ schema:
+ type: string
+ responses:
+ default:
+ description: default response
+ content:
+ application/json: {}
+ /otf/api/testInstance/execute/v1/id/{testInstanceId}:
+ post:
+ tags:
+ - Test Instance Service
+ summary: Executes a test instance by it's unique identifier
+ operationId: execute_1
+ parameters:
+ - name: testInstanceId
+ in: path
+ description: A string representation of a BSON ObjectId
+ required: true
+ schema:
+ type: string
+ description: The UUID of the test instance
+ format: uuid
+ example: 12345678912345678912345f
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExecuteTestInstanceRequest'
+ responses:
+ 200:
+ description: A successful synchronously executed test returns a test execution
+ object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestExecutionResult'
+ 201:
+ description: |-
+ A successful asynchronously executed test with asyncMode set to 'poll' returns an execution identifier
+ The identifier can be used as a parameter to the Test Execution Service to check the status of the executed test
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestExecutionResult'
+ 401:
+ description: The mechanized identifier used with the request is prohibited
+ from accessing the resource.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OtfApiResponse'
+ /otf/api/testInstance/v1/id/{id}:
+ get:
+ tags:
+ - Test Instance Service
+ operationId: findById_1
+ parameters:
+ - name: id
+ in: path
+ description: A string representation of a BSON ObjectId
+ required: true
+ schema:
+ type: string
+ description: The UUID of the test instance
+ format: uuid
+ example: 12345678912345678912345f
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ responses:
+ default:
+ description: default response
+ content:
+ application/json: {}
+ /otf/api/testInstance/create/v1/testDefinitionId/{testDefinitionId}/version/{version}:
+ post:
+ tags:
+ - Test Instance Service
+ summary: Create a test instance using the specified version of the test definition
+ operationId: createByTestDefinitionIdAndVersion_1
+ parameters:
+ - name: testDefinitionId
+ in: path
+ description: A string representation of a BSON ObjectId
+ required: true
+ schema:
+ type: string
+ description: The UUID of the test definition.
+ format: uuid
+ example: 12345678912345678912345f
+ - name: version
+ in: path
+ description: The version of the test definition used to create the instance
+ required: true
+ schema:
+ type: string
+ example: 2
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ - name: execute
+ in: query
+ description: Execute the test instance after it is created
+ allowEmptyValue: true
+ schema:
+ type: boolean
+ example: true
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateTestInstanceRequest'
+ responses:
+ 201:
+ description: The created Test Instance object is returned when it is created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestInstance'
+ /otf/api/testInstance/v1/testInstanceName/{testInstanceName}:
+ get:
+ tags:
+ - Test Instance Service
+ summary: Finds a test instance by it's name
+ operationId: findByTestInstanceName_1
+ parameters:
+ - name: testInstanceName
+ in: path
+ description: The name of the test instance to retrieve
+ required: true
+ schema:
+ type: string
+ example: myTestInstance
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ responses:
+ 200:
+ description: A test instance object is returned when if it is found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestInstance'
+ /otf/api/testInstance/v1/processDefinitionKey/{processDefinitionKey}:
+ get:
+ tags:
+ - Test Instance Service
+ operationId: findByProcessDefKey_1
+ parameters:
+ - name: processDefinitionKey
+ in: path
+ description: The process definition key associated with the test definition
+ required: true
+ schema:
+ type: string
+ example: someUniqueProcessDefinitionKey
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ responses:
+ default:
+ description: default response
+ content:
+ application/json: {}
+ /otf/api/testInstance/create/v1/testDefinitionId/{testDefinitionId}:
+ post:
+ tags:
+ - Test Instance Service
+ summary: Create a test instance using the latest version of the test definition
+ operationId: createByTestDefinitionId_1
+ parameters:
+ - name: testDefinitionId
+ in: path
+ description: A string representation of a BSON ObjectId
+ required: true
+ schema:
+ type: string
+ description: The UUID of the test definition
+ format: uuid
+ example: 12345678912345678912345f
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ - name: execute
+ in: query
+ description: Execute the test instance after it is created
+ allowEmptyValue: true
+ schema:
+ type: boolean
+ example: true
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateTestInstanceRequest'
+ responses:
+ 201:
+ description: The created Test Instance object is returned when it is created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestInstance'
+ /otf/api/testInstance/v1/processDefinitionKey/{processDefinitionKey}/version/{version}:
+ get:
+ tags:
+ - Test Instance Service
+ operationId: findByProcessDefKeyAndVersion_1
+ parameters:
+ - name: processDefinitionKey
+ in: path
+ description: The process definition key associated with the test definition
+ required: true
+ schema:
+ type: string
+ example: someUniqueProcessDefinitionKey
+ - name: version
+ in: path
+ description: The version of the test definition used to create the instance
+ required: true
+ schema:
+ type: string
+ example: 2
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ responses:
+ default:
+ description: default response
+ content:
+ application/json: {}
+ /otf/api/testInstance/create/v1/processDefinitionKey/{processDefinitionKey}/version/{version}:
+ post:
+ tags:
+ - Test Instance Service
+ summary: Create a test instance using the specified version of the test definition
+ operationId: createByProcessDefKeyAndVersion_1
+ parameters:
+ - name: processDefinitionKey
+ in: path
+ description: The process definition key associated with the test definition
+ required: true
+ schema:
+ type: string
+ example: someUniqueProcessDefinitionKey
+ - name: version
+ in: path
+ description: The version of the test definition used to create the instance
+ required: true
+ schema:
+ type: string
+ example: 2
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ - name: execute
+ in: query
+ description: Execute the test instance after it is created
+ allowEmptyValue: true
+ schema:
+ type: boolean
+ example: true
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateTestInstanceRequest'
+ responses:
+ 201:
+ description: The created Test Instance object is returned when it is created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestInstance'
+ /otf/api/testInstance/create/v1/processDefinitionKey/{processDefinitionKey}:
+ post:
+ tags:
+ - Test Instance Service
+ summary: Create a test instance using the latest version of the test definition
+ operationId: createByProcessDefKey_1
+ parameters:
+ - name: processDefinitionKey
+ in: path
+ description: The process definition key associated with the test definition
+ required: true
+ schema:
+ type: string
+ example: someUniqueProcessDefinitionKey
+ - name: Authorization
+ in: header
+ description: Base64 encoded Application Authorization Framework credentials
+ required: true
+ schema:
+ type: string
+ example: Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=
+ - name: execute
+ in: query
+ description: Execute the test instance after it is created
+ allowEmptyValue: true
+ schema:
+ type: boolean
+ example: true
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateTestInstanceRequest'
+ responses:
+ 201:
+ description: The created Test Instance object is returned when it is created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TestInstance'
+ /otf/api/testStrategy/delete/v1/deploymentId/{deploymentId}:
+ delete:
+ tags:
+ - Test Strategy Service
+ operationId: deleteByDeploymentId_1
+ parameters:
+ - name: deploymentId
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: authorization
+ in: header
+ schema:
+ type: string
+ responses:
+ default:
+ description: default response
+ content:
+ application/json: {}
+ /otf/api/testStrategy/delete/v1/testDefinitionId/{testDefinitionId}:
+ delete:
+ tags:
+ - Test Strategy Service
+ operationId: deleteByTestDefinitionId_1
+ parameters:
+ - name: testDefinitionId
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: authorization
+ in: header
+ schema:
+ type: string
+ responses:
+ default:
+ description: default response
+ content:
+ application/json: {}
+ /otf/api/testStrategy/deploy/v1:
+ post:
+ tags:
+ - Test Strategy Service
+ operationId: deployTestStrategy_1
+ parameters:
+ - name: Authorization
+ in: header
+ schema:
+ type: string
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ bpmn:
+ type: object
+ resources:
+ type: object
+ testDefinitionId:
+ type: string
+ testDefinitionDeployerId:
+ type: string
+ definitionId:
+ type: string
+ responses:
+ default:
+ description: default response
+ content:
+ application/json: {}
+components:
+ schemas:
+ ApiResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ date:
+ type: string
+ format: date-time
+ message:
+ type: string
+ JSONObject:
+ type: object
+ ObjectId:
+ type: object
+ properties:
+ timestamp:
+ type: integer
+ format: int32
+ machineIdentifier:
+ type: integer
+ format: int32
+ processIdentifier:
+ type: integer
+ format: int32
+ counter:
+ type: integer
+ format: int32
+ time:
+ type: integer
+ format: int64
+ date:
+ type: string
+ format: date-time
+ timeSecond:
+ type: integer
+ format: int32
+ TestExecution:
+ type: object
+ properties:
+ get_id:
+ $ref: '#/components/schemas/ObjectId'
+ executionId:
+ type: string
+ testResult:
+ type: string
+ testDetails:
+ type: object
+ additionalProperties:
+ type: object
+ startTime:
+ type: string
+ format: date-time
+ endTime:
+ type: string
+ format: date-time
+ async:
+ type: boolean
+ asyncTopic:
+ type: string
+ asyncMode:
+ type: string
+ executor:
+ type: string
+ groupId:
+ $ref: '#/components/schemas/ObjectId'
+ testInstanceId:
+ $ref: '#/components/schemas/ObjectId'
+ testInstance:
+ type: object
+ additionalProperties:
+ type: object
+ testHeadResults:
+ type: array
+ items:
+ $ref: '#/components/schemas/TestHeadResult'
+ testDetailsJSON:
+ type: string
+ testInstanceJSON:
+ type: string
+ TestExecutionResult:
+ type: object
+ properties:
+ testExecution:
+ $ref: '#/components/schemas/TestExecution'
+ executionId:
+ type: string
+ testCompleted:
+ type: boolean
+ testExists:
+ type: boolean
+ TestHeadResult:
+ type: object
+ properties:
+ testHeadId:
+ $ref: '#/components/schemas/ObjectId'
+ testHeadName:
+ type: string
+ bpmnVthTaskId:
+ type: string
+ testHeadResponse:
+ type: object
+ additionalProperties:
+ type: object
+ startTime:
+ type: string
+ format: date-time
+ endTime:
+ type: string
+ format: date-time
+ testHeadResponseJSON:
+ $ref: '#/components/schemas/JSONObject'
+ ExecuteTestInstanceRequest:
+ type: object
+ properties:
+ async:
+ type: boolean
+ writeOnly: true
+ asyncTopic:
+ title: Execute the test synchronously or asynchronously..
+ type: string
+ description: Ignored unless async is true, and asyncMode is DMaaP.
+ example: MyDMaaPTopic.
+ asyncMode:
+ title: Set the asynchronous execution mode.
+ type: string
+ description: Ignored unless async is true. The poll mode will return an
+ executionId that can be used to query the result of the executed test.
+ DMaaP is currently unsupported.
+ example: POLL
+ enum:
+ - POLL
+ - DMAAP
+ testData:
+ title: Use an existing test instance with different global test data.
+ type: object
+ description: Overrides (not overwrites) the testData field for the requested
+ execution. The overridden data will be preserved in the test execution
+ result.
+ example:
+ globalVar1: I'm available to your workflow!
+ globalVar2:
+ me: too
+ vthInput:
+ title: Use an existing test instance with different inputs to your VTHs.
+ type: object
+ description: Overrides (not overwrites) the vthInput field for the requested
+ execution. The overridden data will be preserved in the test execution
+ result.
+ example:
+ ServiceTask_123:
+ vthArg1: An argument your VTH expects.
+ vthArg2: {}
+ ServiceTask_456:
+ vthArg1: An argument your VTH expects.
+ description: The model2 for a test instance execution request.
+ TestInstance:
+ type: object
+ properties:
+ get_id:
+ $ref: '#/components/schemas/ObjectId'
+ testInstanceName:
+ type: string
+ testInstanceDescription:
+ type: string
+ groupId:
+ $ref: '#/components/schemas/ObjectId'
+ testDefinitionId:
+ $ref: '#/components/schemas/ObjectId'
+ processDefinitionId:
+ type: string
+ useLatestTestDefinition:
+ type: boolean
+ testData:
+ type: object
+ additionalProperties:
+ type: object
+ vthInput:
+ type: object
+ additionalProperties:
+ type: object
+ internalTestData:
+ type: object
+ additionalProperties:
+ type: object
+ createdAt:
+ type: string
+ format: date-time
+ updatedAt:
+ type: string
+ format: date-time
+ createdBy:
+ $ref: '#/components/schemas/ObjectId'
+ updatedBy:
+ $ref: '#/components/schemas/ObjectId'
+ vthInputJSON:
+ $ref: '#/components/schemas/JSONObject'
+ testDataJSON:
+ $ref: '#/components/schemas/JSONObject'
+ internalTestDataJSON:
+ $ref: '#/components/schemas/JSONObject'
+ CreateTestInstanceRequest:
+ required:
+ - testData
+ - testInstanceDescription
+ - testInstanceName
+ type: object
+ properties:
+ testInstanceName:
+ title: Name the test instance
+ type: string
+ description: The name must be unique among all test instances belonging
+ to the same test definition.
+ example: MyTestInstance
+ testInstanceDescription:
+ title: Describe the test instance being created
+ type: string
+ description: Use this field to describe the functionality of the test instance
+ example: This test instance does absolutely nothing!
+ testData:
+ title: Set global variables
+ type: object
+ description: |-
+ This field has read and write access by any task within the workflow.
+ See the example for more information
+ example:
+ globalVar1: I'm available to your workflow!
+ globalVar2:
+ me: too
+ vthInput:
+ title: Set virtual test head data
+ type: object
+ description: |-
+ This field determines the data each VTH at the designated ServiceTask will receive.
+ See the example for more information
+ example:
+ ServiceTask_123:
+ vthArg1: An argument your VTH expects.
+ vthArg2: {}
+ ServiceTask_456:
+ vthArg1: An argument your VTH expects.
+ async:
+ type: boolean
+ asyncTopic:
+ type: string
+ asyncMode:
+ type: string
+ description: The model2 for a test instance creation request.