Add pipeline to test Operations API and UI together

Change-Id: I225488eea4ef2e99386628e14ec38bf8fef97831
Related-task: #PROD-25044 (PROD:25044)
diff --git a/test-model-generator.groovy b/test-model-generator.groovy
new file mode 100644
index 0000000..bf32033
--- /dev/null
+++ b/test-model-generator.groovy
@@ -0,0 +1,173 @@
+/**
+ * Tests model manager UI
+ * API_GERRIT_REPO
+ * API_GERRIT_REF
+ * UI_GERRIT_REPO
+ * UI_GERRIT_REF
+ * API_DOCKER_IMG
+ * UI_DOCKER_IMG
+ * CVP_DOCKER_IMG
+ * DOCKER_REGISTRY
+ * DOCKER_REVIEW_REGISTRY
+ * MCP_VERSION
+ * FLAVOR
+ */
+
+def common = new com.mirantis.mk.Common()
+def gerrit = new com.mirantis.mk.Gerrit()
+def dockerLib = new com.mirantis.mk.Docker()
+
+def gerritCredentials = env.CREDENTIALS_ID ?: 'gerrit'
+def slaveNode = env.SLAVE_NODE ?: 'python&&docker'
+def event = env.GERRIT_EVENT_TYPE ?: null
+def defaultRef = 'master'
+def apiGerritRef = env.API_GERRIT_REF ?: defaultRef
+def uiGerritRef = env.UI_GERRIT_REF ?: defaultRef
+def gerritProject = env.GERRIT_PROJECT ?: null
+def version = env.MCP_VERSION ?: 'testing'
+def dockerRegistry = env.DOCKER_REGISTRY ?: 'docker-prod-local.docker.mirantis.net'
+def dockerReviewRegistry = env.DOCKER_REVIEW_REGISTRY ?: 'docker-dev-local.docker.mirantis.net'
+
+def checkouted = false
+def testReportFile = "${env.WORKSPACE}/reports/report.html"
+def manualTrigger = false
+
+def apiProject = 'operations-api'
+def uiProject = 'operations-ui'
+def apiImage
+def uiImage
+
+timeout(time: 1, unit: 'HOURS') {
+    node(slaveNode) {
+        sh "mkdir -p reports ${apiProject} ${uiProject}"
+        def img = dockerLib.getImage("${env.CVP_DOCKER_IMG}:${version}", "${dockerRegistry}/mirantis/cvp/cvp-trymcp-tests:${version}")
+        try {
+            stage("checkout") {
+                if (event) {
+                    dir(gerritProject) {
+                        // job is triggered by Gerrit
+                        def gerritChange = gerrit.getGerritChange(env.GERRIT_NAME, env.GERRIT_HOST, env.GERRIT_CHANGE_NUMBER, gerritCredentials, true)
+                        if (gerritChange.commitMessage.contains("WIP")) {
+                            common.successMsg("Commit message contains WIP, skipping tests") // do nothing
+                        } else {
+                            // test if change aren't already merged
+                            def merged = gerritChange.status == "MERGED"
+                            if (!merged) {
+                                checkouted = gerrit.gerritPatchsetCheckout([
+                                        credentialsId: gerritCredentials
+                                ])
+                            } else {
+                                common.successMsg("Change ${env.GERRIT_CHANGE_NUMBER} is already merged, no need to test them")
+                            }
+                        }
+                    }
+                } else {
+                    common.successMsg('Gerrit variables are not set. Assuming it is manual trigger')
+                    manualTrigger = true
+                }
+
+                if (checkouted) {
+                    if (env.FLAVOR == apiProject) {
+                        // Second project is UI
+                        checkout([
+                                $class           : 'GitSCM',
+                                branches         : [[name: 'FETCH_HEAD'],],
+                                extensions       : [[$class: 'RelativeTargetDirectory', relativeTargetDir: uiProject]],
+                                userRemoteConfigs: [[url: env.UI_GERRIT_REPO, refspec: uiGerritRef, credentialsId: gerritCredentials],],
+                        ])
+                        apiImage = image("${dockerReviewRegistry}/review/${env.FLAVOR}-${env.GERRIT_CHANGE_NUMBER}:${env.GERRIT_PATCHSET_NUMBER}")
+                        uiImage = image("${dockerRegistry}/${env.UI_DOCKER_IMG ?: "mirantis/model-generator/operations-ui"}:${version}")
+                    } else if (env.FLAVOR == uiProject) {
+                        // Second project is API
+                        checkout([
+                                $class           : 'GitSCM',
+                                branches         : [[name: 'FETCH_HEAD'],],
+                                extensions       : [[$class: 'RelativeTargetDirectory', relativeTargetDir: apiProject]],
+                                userRemoteConfigs: [[url: env.API_GERRIT_REPO, refspec: apiGerritRef, credentialsId: gerritCredentials],],
+                        ])
+                        apiImage = image("${dockerRegistry}/${env.API_DOCKER_IMG ?: "mirantis/model-generator/operations-api"}:${version}")
+                        uiImage = image("${dockerReviewRegistry}/review/${env.FLAVOR}-${env.GERRIT_CHANGE_NUMBER}:${env.GERRIT_PATCHSET_NUMBER}")
+                    }
+                } else if (manualTrigger) {
+                    checkout([
+                            $class           : 'GitSCM',
+                            branches         : [[name: 'FETCH_HEAD'],],
+                            extensions       : [[$class: 'RelativeTargetDirectory', relativeTargetDir: apiProject]],
+                            userRemoteConfigs: [[url: env.API_GERRIT_REPO, refspec: apiGerritRef, credentialsId: gerritCredentials],],
+                    ])
+                    checkout([
+                            $class           : 'GitSCM',
+                            branches         : [[name: 'FETCH_HEAD'],],
+                            extensions       : [[$class: 'RelativeTargetDirectory', relativeTargetDir: uiProject]],
+                            userRemoteConfigs: [[url: env.UI_GERRIT_REPO, refspec: uiGerritRef, credentialsId: gerritCredentials],],
+                    ])
+                    apiImage = image("${dockerRegistry}/${env.API_DOCKER_IMG ?: "mirantis/model-generator/operations-api"}:${version}")
+                    uiImage = image("${dockerRegistry}/${env.UI_DOCKER_IMG ?: "mirantis/model-generator/operations-ui"}:${version}")
+                } else {
+                    throw new Exception('Cannot checkout gerrit repositories. Please verify that parameters for repositories are properly set')
+                }
+            }
+
+            stage('Pull docker images') {
+                apiImage.pull()
+                uiImage.pull()
+            }
+
+            stage('Prepare and run docker compose services') {
+                sh """
+                    virtualenv ${env.WORKSPACE}/venv
+                    source ${env.WORKSPACE}/venv/bin/activate
+                    pip install docker-compose==1.22.0
+                """
+
+                dir(apiProject) {
+                    sh """
+                        export IMAGE=${apiImage}
+                        source ${env.WORKSPACE}/venv/bin/activate && ./bootstrap_env.sh up
+                    """
+                }
+                dir(uiProject) {
+                    sh """
+                        export IMAGE=${uiImage}
+                        source ${env.WORKSPACE}/venv/bin/activate && docker-compose up -d
+                    """
+                }
+            }
+
+            stage("test") {
+                img.inside("-u root:root -v ${env.WORKSPACE}/reports:/var/lib/qa_reports") {
+                    sh "pytest -m 'not trymcp'"
+                }
+            }
+        } catch (Throwable e) {
+            // If there was an error or exception thrown, the build failed
+            currentBuild.result = "FAILURE"
+            throw e
+        } finally {
+            if (fileExists(testReportFile)) {
+                archiveArtifacts artifacts: testReportFile
+            }
+            stage("Cleanup") {
+                if (fileExists("${env.WORKSPACE}/venv")) {
+                    dir(apiProject) {
+                        sh "source ${env.WORKSPACE}/venv/bin/activate && ./bootstrap_env.sh down || true"
+                    }
+                    dir(uiProject) {
+                        sh "source ${env.WORKSPACE}/venv/bin/activate && docker-compose down || true"
+                    }
+                    sh "rm -rf ${env.WORKSPACE}/venv/"
+                }
+                if (apiImage && apiImage.id) {
+                    sh "docker rm -f ${apiImage.id}"
+                }
+                if (uiImage && uiImage.id) {
+                    sh "docker rm -f ${uiImage.id}"
+                }
+                // Remove everything what is owned by root
+                img.inside("-u root:root -v ${env.WORKSPACE}:/temp") {
+                    sh('rm -rf /temp/reports/* /temp/cockroach_data')
+                }
+            }
+        }
+    }
+}