#!groovy
@Library('infraLib') _

String items_to_keep = env.BRANCH_NAME == 'master' ? '25' : '1'
def devicesList = apolloGoHelpers.supportedMobileDevices()

def app_url
def api_test_cmd
def ui_test_cmd
def testSummary

pipeline {

  agent {
    label 'linux-agents-xlarge'
  }

  options {
    timeout(time: 420, unit: 'MINUTES')
    buildDiscarder logRotator(
      artifactDaysToKeepStr: '',
      artifactNumToKeepStr: '',
      daysToKeepStr: '',
      numToKeepStr: items_to_keep)
    disableResume()
    ansiColor('xterm')
    copyArtifactPermission '*'
  }

  parameters {
    choice(
      choices: [
        'SKIP',
        'API',
        'UI FULL',
        'UI SMOKE',
        'ALL',
      ],
      description: 'Force build all or some modules',
      name: 'FORCE_BUILD'
    )
    separator(name: 'ago-common-build-params', sectionHeader: 'Common build parameters')
    choice(
      choices: [
        'delphi-api-ext.delphiplatform.io',
        'dev-delphi-api-ext.delphiplatform.io',
        'stage-delphi-api-ext.delphiplatform.io',
        'qa-delphi-api-ext.delphiplatform.io',
      ],
      description: 'Choice a target Delphi API',
      name: 'DELPHI_API_URL'
    )
    choice(
      choices: [
        'https://dev-proxy.apollo.stream',
        'https://stage-proxy.apollo.stream',
        'https://test-proxy.apollo.stream',
        'https://uat-proxy.apollo.stream',
        'https://proxy.apollo.stream',
      ],
      description: 'Choice a target API',
      name: 'TARGET_API_URL'
    )
    booleanParam description: 'Skip docker image build, use pre-build image instead', name: 'USE_CACHE'
    separator(name: 'ago-mobile-build-params', sectionHeader: 'Mobile build parameters')
    string (
      defaultValue: 'can be one of http:// or s3://',
      description: 'URL of the file for browser stack testing',
      name: 'FILE_URL',
      trim: true
    )
    string (
      defaultValue: '',
      description: 'Application version',
      name: 'IOS_BUILD',
      trim: true
    )
    choice(
      choices: devicesList,
      description: 'Choice a device',
      name: 'IOS_DEVICE_VERSION'
    )
    string (
      defaultValue: '1.18.0',
      description: 'Appium version',
      name: 'APPIUM_VERSION',
      trim: true
    )
    choice(
      choices: [
        '5',
        '4',
        '3',
        '2',
        '1',
        '10',
        '9',
        '8',
        '7',
        '6',
      ],
      description: 'Choose a device',
      name: 'NUMBER_OF_PARALLEL_TESTS'
    )
    string (
      defaultValue: '',
      description: 'Limit check to these API tests only',
      name: 'API_TESTS',
      trim: true
    )
    string (
      defaultValue: '',
      description: 'Limit check to these UI tests only',
      name: 'UI_TESTS',
      trim: true
    )
    string (
      defaultValue: '',
      description: 'Copy allure report from this build',
      name: 'PREVIOUS_ALLURE_RESULTS_BUILD_NUMBER',
      trim: true
    )
    booleanParam(
      name: 'SKIP_STATIC',
      defaultValue: false,
      description: 'Skip static checks'
    )
  }

  environment {
    AWS_PROFILE           = 'gdb-infra-dev'
    AWS_PROFILE_ALT       = 'gdb-delphi-dev'
    NOTIFICATIONS_CHANNEL ='#apollo-test-reports'

    USER_EMAIL         = 'svidzya.w+4@gmail.com'
    USER_PASSWORD      = utility.getSecretValueById('infra/jenkins/uitest/USER_PASSWORD', env.AWS_PROFILE)
    USER_PASSWORD_PROD = utility.getSecretValueById('infra/jenkins/uitest/USER_PASSWORD_PROD', env.AWS_PROFILE)

    NOTIFICATIONS_EMAIL    = 'svidzya.w+10@gmail.com'
    NOTIFICATIONS_PASSWORD = utility.getSecretValueById('infra/jenkins/uitest/NOTIFICATIONS_PASSWORD', env.AWS_PROFILE)

    AUTH0_CLIENT_ID     = utility.getSecretValueById('infra/jenkins/uitest/apollo/AUTH0_CLIENT_ID', env.AWS_PROFILE)
    AUTH0_CLIENT_SECRET = utility.getSecretValueById('infra/jenkins/uitest/apollo/AUTH0_CLIENT_SECRET', env.AWS_PROFILE)
    AUTH0_CLIENT_ID_PROD     = utility.getSecretValueById('infra/jenkins/uitest/apollo/AUTH0_CLIENT_ID_PROD', env.AWS_PROFILE)
    AUTH0_CLIENT_SECRET_PROD = utility.getSecretValueById('infra/jenkins/uitest/apollo/AUTH0_CLIENT_SECRET_PROD', env.AWS_PROFILE)

    AUTH0_AUDIENCE   = 'https://apollo-private-api/'
    AUTH0_GRANT_TYPE = 'http://auth0.com/oauth/grant-type/password-realm'
    AUTH0_REALM      = 'LevelDB'
    AUTH0_HOST       = 'https://sme-dna.auth0.com/oauth/token'

    AUTH0_REALM_PROD = 'MergedUsersDB'
    AUTH0_SCOPE_PROD = 'openid profile'
    AUTH0_HOST_PROD  = 'https://prod-dna-apps.auth0.com/oauth/token'

    MYSQL_DB_NAME = 'dbSony_dbo'
    MYSQL_DB_HOST = 'dev-apollo-aurora-cep.cluster-custom-cic9zqsxd2y6.us-east-1.rds.amazonaws.com'
    MYSQL_DB_USER = 'dataart'
    MYSQL_DB_PASS = utility.getSecretValueById('infra/jenkins/uitest/MYSQL_DB_PASS', env.AWS_PROFILE)

    BROWSERSTACK_APP_USER = utility.getSecretValueById('infra/jenkins/browserstack/BROWSERSTACK_USERNAME', env.AWS_PROFILE)
    BROWSERSTACK_APP_KEY  = utility.getSecretValueById('infra/jenkins/browserstack/BROWSERSTACK_ACCESS_KEY', env.AWS_PROFILE)

    TARGET_API_URL      = "${params.TARGET_API_URL}"
    TARGET_API_URL_PROD = 'https://proxy.apollo.stream'

    NUMBER_OF_PARALLEL_TESTS = "${params.NUMBER_OF_PARALLEL_TESTS}"

    AWS_ACCOUNT_ID = '725764004555'
    AWS_REGION     = 'us-east-1'

    ECR_REGISTRY        = "${env.AWS_ACCOUNT_ID}.dkr.ecr.${env.AWS_REGION}.amazonaws.com"
    ECR_REPOSITORY_NAME = 'apollo/ago-pytest'
    ECR_REGISTRY_URI    = "${ECR_REGISTRY}/${ECR_REPOSITORY_NAME}"

    DELPHI_API_URL             = "https://${params.DELPHI_API_URL}/"
    AUTH0_CLIENT_ID_DELPHI     = utility.getSecretValueByIdAndJsonPath('infra/jenkins/uitest/apollo/AUTH0_CLIENT_ID_DELPHI', env.AWS_PROFILE, ".\"${params.DELPHI_API_URL}\"")
    AUTH0_CLIENT_SECRET_DELPHI = utility.getSecretValueByIdAndJsonPath('infra/jenkins/uitest/apollo/AUTH0_CLIENT_SECRET_DELPHI', env.AWS_PROFILE, ".\"${params.DELPHI_API_URL}\"")
    AUTH0_GRANT_TYPE_DELPHI    = "client_credentials"

    AUTH0_CLIENT_ID_DELPHI_PROD     = utility.getSecretValueByIdAndJsonPath('infra/jenkins/uitest/apollo/AUTH0_CLIENT_ID_DELPHI', env.AWS_PROFILE, ".\"delphi-api-ext.delphiplatform.io\"")
    AUTH0_CLIENT_SECRET_DELPHI_PROD = utility.getSecretValueByIdAndJsonPath('infra/jenkins/uitest/apollo/AUTH0_CLIENT_SECRET_DELPHI', env.AWS_PROFILE, ".\"delphi-api-ext.delphiplatform.io\"")
    DELPHI_API_URL_PROD             = "https://delphi-api-ext.delphiplatform.io/"

    REVISION = "${sh script: 'git rev-parse --short=8 HEAD', returnStdout: true}".trim()

    MOCK_USER_EMAIL_1 = 'mock_user1@autotest.com'
    MOCK_USER_EMAIL_2 = 'mock_user2@autotest.com'
    MOCK_USER_EMAIL_3 = 'mock_user3@autotest.com'
    MOCK_USER_EMAIL_4 = 'mock_user4@autotest.com'
    MOCK_USER_EMAIL_5 = 'mock_user5@autotest.com'
  }

  stages {
    stage('Notify start') {
      steps {
        script {
          utility.slackNotify(
            currentBuild.currentResult,
            env.NOTIFICATIONS_CHANNEL,
            "started ${env.JOB_NAME} <${env.BUILD_URL}|Open>"
          )
        } /** end: script */
      } /** end: steps */
    } /** end: stage */

    stage('Build') {
      when {
        not { expression { return params.USE_CACHE } }
      }
      steps {
        sh label: 'build docker image', script: 'make docker/image/build'
        sh label: 'backward-compatibility', script: "docker tag ago-pytest:latest ${env.ECR_REGISTRY_URI}:${env.REVISION} || exit 0"
      } /** end: steps */
    } /** end: stage */

    stage('Static') {
      when {
        allOf {
          not { expression { return params.USE_CACHE } }
          not { expression { return params.SKIP_STATIC } }
        }
      }
      parallel {
        stage('Checkstyle') {
          steps {
            sh label: 'checkstyle', script: '''
                        make docker/checkstyle
                      '''
          } /** end: steps */
          post {
            always {
              sh "sudo chown \$(whoami):\$(whoami) -R ${env.WORKSPACE}"
            }
          }
        } /** end: stage */
        stage('Security') {
          steps {
            sh label: 'check dependencies', script: '''
                        make docker/security
                      '''
          } /** end: steps */
          post {
            always {
              sh "sudo chown \$(whoami):\$(whoami) -R ${env.WORKSPACE}"
            }
          }
        } /** end: stage */
      } /** end: parallel */
    } /** end: stage */

    stage('Push') {
      when {
        allOf {
          not { expression { return params.USE_CACHE } }
          branch 'master'
        }
      }
      steps {
        sh label: 'push docker image', script: 'make docker/image/push'
      } /** end: steps */
    } /** end: stage */

    stage('Pull') {
      when {
        allOf {
          expression { return params.USE_CACHE }
          branch 'master'
        }
      }
      steps {
        sh label: 'pull docker image', script: 'make docker/image/pull'
      } /** end: steps */
    } /** end: stage */

    stage('Copy Allure report') {
      when {
        not { expression { return  params.PREVIOUS_ALLURE_RESULTS_BUILD_NUMBER.equals('') } }
      }
      steps {
        script {
          copyArtifacts filter: 'output/allure_report/*',
                        fingerprintArtifacts: true,
                        projectName: currentBuild.fullProjectName,
                        selector: specific("${params.PREVIOUS_ALLURE_RESULTS_BUILD_NUMBER}")
        }
      }
    }

    stage('API test') {
      when {
        anyOf {
          expression { return params.FORCE_BUILD.equals('API') }
          expression { return params.FORCE_BUILD.equals('ALL') }
          triggeredBy 'TimerTrigger'
        }
      }
      environment {
        BROWSER_NAME        = 'ios'
        ENV_BASE_URL        = 'https://qa.apollo.stream'
        SELENIUM_TIMEOUT    = 20
        SELENIUM_ENV        = 'api'
        PYTEST_XDIST_WORKER = 'master'
        SELENIUM_HEADLESS   = 'True'
        CHROMEDRIVER_PATH   = 'path'
      }
      stages {
        stage('Test') {
          steps {
            withDockerContainer(args: "--entrypoint=''", image: "${ECR_REGISTRY_URI}:${env.REVISION}") {
              script {
                api_test_cmd = []
                api_test_cmd << ('pytest')
                api_test_cmd << ('--html=output/report.html')
                api_test_cmd << ('--self-contained-html')
                api_test_cmd << ('--alluredir=output/allure_report')
                api_test_cmd << ('--reruns 1')
                api_test_cmd << ('-v')
                if (params.API_TESTS != '') {
                  api_test_cmd << ("app/src/tests/tests_api/${params.API_TESTS}")
                } else {
                  api_test_cmd << ('app/src/tests/tests_api/')
                }
                echo api_test_cmd.join(' ')
                sh label: 'run api tests', script: api_test_cmd.join(" ")
              } /** end: script */
            } /** end: withDockerContainer */
          } /** end: steps */
          post {
            always {
              sh 'sudo chown ec2-user:ec2-user -R output/ && ls -l output/'
              script {
                allure([
                  includeProperties: false,
                  jdk              : '',
                  properties       : [],
                  reportBuildPolicy: 'ALWAYS',
                  results          : [[path: 'output/allure_report']]
                ])
                script { testSummary = utility.getAllureTestSummary(env.BUILD_URL) }
              } /** end: script */
            } /** end: always */
          } /** end: post */
        } /** end: stage */
      } /** end: stages */
    } /** end: stage */

    stage('UI test') {
      when {
        allOf {
          anyOf {
            expression { return params.FORCE_BUILD.equals('UI FULL') }
            expression { return params.FORCE_BUILD.equals('UI SMOKE') }
            expression { return params.FORCE_BUILD.equals('ALL') }
          }
          not { expression { return  params.FILE_URL.equals('can be one of http:// or s3://') } }
          not { expression { return  params.IOS_BUILD.equals('') } }
        }
      }
      environment {
        BROWSER_NAME        = 'browserstack_ios'
        ENV_BASE_URL        = "${params.TARGET_API_URL}"
        SELENIUM_TIMEOUT    = 10
        SELENIUM_ENV        = 'mobile_bs'
        PYTEST_XDIST_WORKER = 'false'
        SELENIUM_HEADLESS   = 'false'
        CHROMEDRIVER_PATH   = 'path'
        APPIUM_VERSION      = "${params.APPIUM_VERSION}"
      }
      stages {
        stage('Upload artifact') {
          stages {
            stage('HTTP') {
              when {
                expression { return params.FILE_URL.startsWith('http') }
              }
              steps {
                script {
                  app_url = sh (
                      label: 'Upload artifact',
                      returnStdout: true,
                      script: """
                        set +x # suppress debug output
                        curl -q -u \"${env.BROWSERSTACK_APP_USER}:${env.BROWSERSTACK_APP_KEY}\" \
                          -X POST \"https://api-cloud.browserstack.com/app-automate/upload\" \
                          -F \"url=${params.FILE_URL}\" | jq -r '.app_url'
                      """
                  )
                  echo "${app_url}"
                }
              }
            }
            stage('S3') {
              when {
                expression { return params.FILE_URL.startsWith('s3') }
              }
              environment {
                FILE_NAME   = "${params.FILE_URL.split('/').last()}"
                FILE_PATH   = "${env.WORKSPACE}/${env.FILE_NAME}"
                AWS_PROFILE = "gdb-apollo-dev"
              }
              steps {
                script {
                  sh(label: 'Download file from S3', script: "aws s3 cp ${params.FILE_URL} \"${env.FILE_PATH}\"")
                  app_url = sh(
                      label: 'Upload artifact',
                      returnStdout: true,
                      script: """
                        set +x # suppress debug output
                        curl -q -u \"${env.BROWSERSTACK_APP_USER}:${env.BROWSERSTACK_APP_KEY}\" \
                          -X POST \"https://api-cloud.browserstack.com/app-automate/upload\" \
                          -F \"file=@${env.FILE_PATH}\" | jq -r '.app_url'
                      """
                  )
                  echo "${app_url}"
                }
              }
            }
          }
        }
        stage('Test') {
          environment {
            IOS_BUILD    = "${params.IOS_BUILD}"
            IOS_APP_PATH = "${app_url}"
            IOS_DEVICE   = "${params.IOS_DEVICE_VERSION.split(',').first()}"
            IOS_VERSION  = "${params.IOS_DEVICE_VERSION.split(',').last().replace('iOS ', '')}"
          }
          stages {
            stage('Full') {
              when {
                expression { return params.FORCE_BUILD.equals('UI FULL') }
              }
              steps {
                withDockerContainer(args: "--entrypoint=''", image: "${ECR_REGISTRY_URI}:${env.REVISION}") {
                  script {
                    ui_test_cmd = []
                    ui_test_cmd << ('pytest')
                    ui_test_cmd << ('--html=output/report.html')
                    ui_test_cmd << ('--self-contained-html')
                    ui_test_cmd << ('--alluredir=output/allure_report')
                    ui_test_cmd << ('--reruns 2')
                    ui_test_cmd << ("-n ${env.NUMBER_OF_PARALLEL_TESTS}")
                    if (params.UI_TESTS != '') {
                      ui_test_cmd << ("app/src/tests/tests_ui/${params.UI_TESTS}")
                    } else {
                      ui_test_cmd << ('app/src/tests/tests_ui/')
                    }
                    echo ui_test_cmd.join(' ')
                    sh label: 'run ui tests', script: ui_test_cmd.join(" ")
                  } /** end: script */
                } /** end: withDockerContainer */
              } /** end: steps */
            } /** end: stage */
            stage('Smoke') {
              when {
                expression { return params.FORCE_BUILD.equals('UI SMOKE') }
              }
              steps {
                withDockerContainer(args: "--entrypoint=''", image: "${ECR_REGISTRY_URI}:${env.REVISION}") {
                  script {
                    ui_test_cmd = []
                    ui_test_cmd << ('pytest')
                    ui_test_cmd << ('--html=output/report.html')
                    ui_test_cmd << ('--self-contained-html')
                    ui_test_cmd << ('--alluredir=output/allure_report')
                    ui_test_cmd << ("-n ${env.NUMBER_OF_PARALLEL_TESTS}")
                    ui_test_cmd << ('-m smoke')
                    ui_test_cmd << ('--maxfail=100')
                    ui_test_cmd << ('-v')
                    ui_test_cmd << ('--instafail')
                    if (params.UI_TESTS != '') {
                      ui_test_cmd << ("app/src/tests/tests_ui/${params.UI_TESTS}")
                    } else {
                      ui_test_cmd << ('app/src/tests/tests_ui/')
                    }
                    echo ui_test_cmd.join(' ')
                    sh label: 'run ui smoke tests', script: ui_test_cmd.join(" ")
                  } /** end: script */
                } /** end: withDockerContainer */
              } /** end: steps */
            }
          } /** end: steps */
          post {
            always {
              sh 'sudo chown ec2-user:ec2-user -R output/ && ls -l output/'
              script {
                allure([
                  includeProperties: false,
                  jdk              : '',
                  properties       : [],
                  reportBuildPolicy: 'ALWAYS',
                  results          : [[path: 'output/allure_report']]
                ])
                script { testSummary = utility.getAllureTestSummary(env.BUILD_URL) }
              } /** end: script */
            } /** end: always */
          } /** end: post */
        } /** end: stage */
      } /** end: stages */
    } /** end: stage */
  } /** end: stages */
  post {
    success {
      script { utility.slackNotify('SUCCESS', env.NOTIFICATIONS_CHANNEL, 'ignored', testSummary) }
    } /** end: success */
    failure {
      script { utility.slackNotify('FAILURE', env.NOTIFICATIONS_CHANNEL, 'ignored', testSummary) }
    } /** end: unsuccessful */
    unstable {
      script { utility.slackNotify('UNSTABLE', env.NOTIFICATIONS_CHANNEL, 'ignored', testSummary) }
    } /** end: unsuccessful */
    always {
      script {
        archiveArtifacts artifacts: 'output/allure_report/*', allowEmptyArchive: true
        utility.slackNotify(
          currentBuild.currentResult,
          env.NOTIFICATIONS_CHANNEL,
          "finished ${env.JOB_NAME} <${env.BUILD_URL}|Open>"
        )
      } /** end: script */
    } /** end: always */
  } /** end: post */
} /** end: pipeline */
