def NOTIFICATION_EMAIL = 'core@onapp.com'
def HOST_BUNDLE_PATH = '${HOME}/onapp-interface/gems-2.3.4'
def BUNDLE_PATH = '${WORKSPACE}/../cached_gems'
def WEBDRIVERS_PATH = '${HOME}/onapp-interface/.webdrivers'
def DOCKERFILE_PATH = 'testing-image'
def CREDENTIALS = '7ce580c0-7d01-412f-bff1-485b4ca6196a'
def RSPEC_RESULTS_PATH = 'rspec_results.xml'
def RSPEC_PROFILE_SPECS = '0'

pipeline {
    agent none
    environment {
        NOTIFICATION_EMAIL = "${NOTIFICATION_EMAIL}"
        CREDENTIALS = "${CREDENTIALS}"
        RSPEC_RESULTS_PATH = "${RSPEC_RESULTS_PATH}"
        RSPEC_PROFILE_SPECS = "${RSPEC_PROFILE_SPECS}"
    }
    options {
        buildDiscarder(logRotator(numToKeepStr: '10', daysToKeepStr: '7'))
    }
    post {
        success {
            sendNotification('SUCCESSFUL')
        }

        failure {
            sendNotification('FAILED')
        }
    }
    stages {
        stage('Install gems') {
            agent {
                dockerfile {
                    dir "${DOCKERFILE_PATH}"
                    args """\
                        -u root:root \
                        -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                    """
                }
            }
            environment {
                BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
            }
            post {
                cleanup {
                    cleanupWorkspace()
                }
            }
            steps {
                bundleInstall()
                dir('components/messaging') {
                    bundleInstall()
                }
                dir('components/onapp-backups') {
                    bundleInstall()
                }
                dir('components/onapp-networking/networking-sdn/spec/dummy') {
                    bundleInstall()
                }
            }
        }
        stage('Run parallel tests') {
            parallel {
                stage('interface (acceptance,lib)') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                startRedis()
                                prepareConfiguration()
                                prepareDb()
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    saveResults()
                                }
                            }
                            steps {
                                runSpecs('spec/acceptance spec/lib')
                            }
                        }
                    }
                }
                stage('interface (controllers,models)') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                startRedis()
                                prepareConfiguration()
                                prepareDb()
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    saveResults()
                                }
                            }
                            steps {
                                runSpecs('spec/controllers spec/models')
                            }
                        }
                    }
                }
                stage('interface (integration)') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                                -v ${WEBDRIVERS_PATH}:/root/.webdrivers \
                                -v /dev/shm:/dev/shm \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                startRedis()
                                prepareConfiguration()
                                prepareDb()
                                sh('bundle exec rake assets:precompile')
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    saveResults()
                                }
                            }
                            steps {
                                runSpecs('spec/integration')
                            }
                        }
                    }
                }
                stage('interface (policies,services)') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                startRedis()
                                prepareConfiguration()
                                prepareDb()
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    saveResults()
                                }
                            }
                            steps {
                                runSpecs('spec/policies spec/services')
                            }
                        }
                    }
                }
                stage('interface (other)') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                startRedis()
                                prepareConfiguration()
                                prepareDb()
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    saveResults()
                                }
                            }
                            steps {
                                runSpecs("--exclude-pattern '{acceptance,controllers,integration,lib,models,policies,services}/**/*_spec.rb'")
                            }
                        }
                    }
                }
                stage('components/messaging') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                sh('cp components/dummy_database.test.yml components/dummy_database.yml')
                                dir('components/messaging') {
                                    prepareComponentDb()
                                }
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    dir('components/messaging') {
                                        saveResults()
                                    }
                                }
                            }
                            steps {
                                dir('components/messaging') {
                                    runSpecs()
                                }
                            }
                        }
                    }
                }
                stage('components/onapp-backups') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                sh('cp components/dummy_database.test.yml components/dummy_database.yml')
                                dir('components/onapp-backups') {
                                    prepareComponentDb()
                                }
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    dir('components/onapp-backups') {
                                        saveResults()
                                    }
                                }
                            }
                            steps {
                                dir('components/onapp-backups') {
                                    runSpecs()
                                }
                            }
                        }
                    }
                }
                stage('components/onapp-networking') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                startRedis()
                                prepareConfiguration()
                                sh("echo -e 'path: ${WORKSPACE}' > components/onapp-networking/config/main_app_info.yml")
                                sh('cp -f Gemfile.lock components/onapp-networking')
                                dir('components/onapp-networking') {
                                    prepareComponentDb()
                                }
                            }
                        }
                        stage('Run tests') {
                            post {
                                always {
                                    dir('components/onapp-networking') {
                                        saveResults()
                                    }
                                }
                            }
                            steps {
                                dir('components/onapp-networking') {
                                    runSpecs()
                                }
                            }
                        }
                    }
                }
                stage('components/onapp-networking/networking-sdn') {
                    agent {
                        dockerfile {
                            dir "${DOCKERFILE_PATH}"
                            args """\
                                -u root:root \
                                -v ${HOST_BUNDLE_PATH}:${BUNDLE_PATH} \
                            """
                        }
                    }
                    environment {
                        BUNDLE_PATH = sh(script: "realpath ${BUNDLE_PATH}", returnStdout: true).trim()
                    }
                    post {
                        cleanup {
                            cleanupWorkspace()
                        }
                    }
                    stages {
                        stage('Configure') {
                            steps {
                                startMysql()
                                sh('cp components/dummy_database.test.yml components/onapp-networking/networking-sdn/spec/dummy/config/database.yml')
                                dir('components/onapp-networking/networking-sdn/spec/dummy') {
                                    prepareDb()
                                }
                            }
                        }
                        stage('Run tests') {
                            environment {
                                BUNDLE_GEMFILE = 'spec/dummy/Gemfile'
                            }
                            post {
                                always {
                                    dir('components/onapp-networking/networking-sdn') {
                                        saveResults()
                                    }
                                }
                            }
                            steps {
                                dir('components/onapp-networking/networking-sdn') {
                                    runSpecs()
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

def sendNotification(status) {
    emailext (
        subject: "${status}: Job '${JOB_NAME} [${BUILD_NUMBER}]'",
        mimeType: 'text/html',
        to: "${NOTIFICATION_EMAIL}",
        body: """
            <p>${status}: Job '${JOB_NAME} [${BUILD_NUMBER}]':</p>
            <p>Check console output at <a href='${BUILD_URL}'>${JOB_NAME} [${BUILD_NUMBER}]</a></p>
        """
    )
}

def cleanupWorkspace() {
    // remove any changes to prevent permission issues
    sh('git clean -fdx')
    deleteDir()
    // additional cleanup required due to https://issues.jenkins.io/browse/JENKINS-41805
    dir("${WORKSPACE}@libs") {
        deleteDir()
    }
    dir("${WORKSPACE}@script") {
        deleteDir()
    }
    dir("${WORKSPACE}@tmp") {
        deleteDir()
    }
}

def bundleInstall() {
    populateKnownHosts('bitbucket.org')
    populateKnownHosts('github.com')
    sh('bundle config jobs 8')
    sshagent(credentials: ["${CREDENTIALS}"]) {
        sh('bundle install')
    }
}

def populateKnownHosts(domain) {
    sh("ssh-keyscan ${domain} >> /root/.ssh/known_hosts")
}

def saveResults() {
    junit(testResults: "${RSPEC_RESULTS_PATH}", allowEmptyResults: true)
}

def startMysql() {
    sh('/etc/init.d/mysqld start')
}

def startRedis() {
    sh('/etc/init.d/redis start')
}

def runSpecs(pattern = '') {
    sh("""\
        bundle exec rspec ${pattern} \
            --format progress \
            --format RspecJunitFormatter \
            --out ${RSPEC_RESULTS_PATH} \
            --deprecation-out /dev/null \
            --profile=${RSPEC_PROFILE_SPECS} \
            --backtrace \
            --tag ~flaky \
    """)
}

def prepareConfiguration() {
    sh('cp config/on_app.yml.example config/on_app.yml')
    sh('cp config/database.test.yml config/database.yml')
    sh('cp config/redis.test.yml config/redis.yml')
    sh('touch config/keys/private')
    sh('touch config/keys/public')
}

def prepareDb() {
    sh('''\
        bundle exec rake db:create \
                         db:schema:load \
    ''')
}

def prepareComponentDb() {
    sh('''\
        bundle exec rake app:db:create \
                         app:db:schema:load \
    ''')
}
