node('container') {
  // Load and execute common functions Groovy script
  sh 'curl -O https://raw.githubusercontent.com/OpenVidu/openvidu/master/openvidu-test-e2e/jenkins/commonFunctions.groovy'
  def commonFunctions = load 'commonFunctions.groovy'
  commonFunctions.prepareTestingEnvironment()

  // Clone and checkout OpenVidu/openvidu repository
  def commitId = "${OPENVIDU_COMMIT}"
  checkout([$class: 'GitSCM', branches: [[name: commitId]], userRemoteConfigs: [[url: 'https://github.com/OpenVidu/openvidu']], extensions: [[$class: 'RelativeTargetDirectory', relativeTargetDir: 'openvidu']]])

  // Volumes to use in container openvidu/openvidu-test-e2e
  def bindsArray = ['-v /var/run/docker.sock:/var/run/docker.sock:rw',
                    '-v /dev/shm:/dev/shm',
                    '-v /opt/openvidu:/opt/openvidu',
                    '-v /opt/openvidu-cache/test-layouts:/opt/openvidu/test-layouts',
                    '-v /opt/openvidu-cache/.m2:/root/.m2'].join(' ')

  // Run openvidu/openvidu-test-e2e container
  docker.image("openvidu/openvidu-test-e2e:${DISTRO}").inside('--privileged -p 4200:4200 -p 4443:4443 -p 4114:4114 -u root -e MY_UID=0 ' + "${bindsArray}") {
    stage('Build 1') {
      parallel 'OpenVidu Browser build': {
        stage('OpenVidu Browser build') {
          sh(script: '''#!/bin/bash -xe
            cd openvidu/openvidu-browser
            npm install --quiet --unsafe-perm
            npm run build --quiet
            npm pack --quiet
            cp openvidu-browser-*.tgz /opt/openvidu
          '''.stripIndent())
        }
      }, 'OpenVidu Node Client build': {
        stage('OpenVidu Node Client build') {
          sh(script: '''#!/bin/bash -xe
            cd openvidu/openvidu-node-client
            npm install --quiet --unsafe-perm
            npm run build --quiet
            npm pack --quiet
            cp openvidu-node-client-*.tgz /opt/openvidu
          '''.stripIndent())
        }
      }, 'OpenVidu Java Client build': {
        stage('OpenVidu Java Client build') {
          sh(script: '''#!/bin/bash -xe
            cd openvidu/openvidu-java-client
            mvn -B versions:set -DnewVersion=TEST
            mvn -B clean compile package
            mvn -B install:install-file -Dfile=target/openvidu-java-client-TEST.jar -DgroupId=io.openvidu -DartifactId=openvidu-java-client -Dversion=TEST -Dpackaging=jar
          '''.stripIndent())
        }
      }
    }

    stage('Build 2') {
      parallel 'OpenVidu TestApp build': {
        stage('OpenVidu TestApp build') {
          sh(script: '''#!/bin/bash -xe
          cd openvidu/openvidu-testapp
          npm install --force --unsafe-perm --quiet
          npm install /opt/openvidu/openvidu-browser-*.tgz --quiet
          npm install /opt/openvidu/openvidu-node-client-*.tgz --quiet
          export NG_CLI_ANALYTICS="false" && ./node_modules/@angular/cli/bin/ng build --prod --output-path=/opt/openvidu/testapp
        '''.stripIndent())
        }
      }, 'OpenVidu Server dashboard build': {
        stage('OpenVidu Server dashboard build') {
          sh(script: '''#!/bin/bash -xe
            cd openvidu/openvidu-server/src/dashboard
            npm install --unsafe-perm --quiet
            npm install /opt/openvidu/openvidu-browser-*.tgz --quiet
            export NG_CLI_ANALYTICS="false" && npm run build-prod --quiet
          '''.stripIndent())
        }
      }, 'OpenVidu Server pre-build': {
        stage('OpenVidu parent build') {
          sh(script: '''#!/bin/bash -xe
            if [[ ${KURENTO_JAVA_COMMIT} != "default" ]]; then
              git clone https://github.com/Kurento/kurento-java.git
              cd kurento-java
              git checkout -f ${KURENTO_JAVA_COMMIT}
              mvn -B clean install
              MVN_VERSION=$(mvn -B -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
              cd ../openvidu && mvn -B versions:set-property -Dproperty=version.kurento -DnewVersion=${MVN_VERSION}
            fi
          '''.stripIndent())
          sh 'cd openvidu && mvn -B versions:set-property -Dproperty=version.openvidu.java.client -DnewVersion=TEST'
          sh 'cd openvidu && mvn -B -DskipTests=true clean install'
        }
        stage('OpenVidu Server unit tests') {
          sh 'cd openvidu/openvidu-server && mvn -B -Dtest=io.openvidu.server.test.unit.*Test test'
        }
        stage('OpenVidu Server integration tests') {
          sh 'cd openvidu/openvidu-server && mvn -B -Dtest=io.openvidu.server.test.integration.*Test test'
        }
        stage('OpenVidu Test E2E build') {
          sh(script: '''#!/bin/bash -xe
            cd openvidu/openvidu-test-browsers
            mvn -B versions:set -DnewVersion=TEST && mvn -B clean install
            cd ..
            mvn -B versions:set-property -Dproperty=version.openvidu.java.client -DnewVersion=TEST
            mvn -B versions:set-property -Dproperty=version.openvidu.test.browsers -DnewVersion=TEST
            cd openvidu-test-e2e
            mvn -B -DskipTests=true clean install
          '''.stripIndent())
        }
      }
    }

    stage('OpenVidu Server build') {
      sh(script: '''#!/bin/bash -xe
        cd openvidu/openvidu-server
        mvn -B -DskipTests=true package
        cp target/openvidu-server*.jar /opt/openvidu
      '''.stripIndent())
    }

    // Kurento tests
    stage ('Environment Launch Kurento') {
      environmentLaunch('kurento')
    }
    try {
      stage ('OpenVidu Kurento E2E tests') {
        try {
          openViduE2ETest("kurento/kurento-media-server:${KURENTO_MEDIA_SERVER_VERSION}")
        } catch (err) {
          // In case of error, fail the stage
          sh 'exit 1'
        } finally {
          junit 'openvidu/openvidu-test-e2e/**/target/surefire-reports/TEST-*.xml'
          archiveArtifacts artifacts: '**/openvidu-server-*.log'
        }
      }
    } catch (error) {
      echo 'Test failed'
      currentBuild.result = 'FAILURE'
    } finally {
      // Kill all environment for next test
      environmentStop()
    }

    // Mediasoup tests
    stage ('Environment Launch Mediasoup') {
      environmentLaunch('mediasoup')
    }
    try {
      stage ('OpenVidu Mediasoup E2E tests') {
        try {
          openViduE2ETest("openvidu/mediasoup-controller:${MEDIASOUP_CONTROLLER_VERSION}")
        } catch (err) {
          // In case of error, fail the stage
          sh 'exit 1'
        } finally {
          junit 'openvidu/openvidu-test-e2e/**/target/surefire-reports/TEST-*.xml'
          archiveArtifacts artifacts: '**/openvidu-server-*.log'
        }
      }
    } catch (error) {
      echo 'Test failed'
      currentBuild.result = 'FAILURE'
    } finally {
      environmentStop()
      commonFunctions.removeStrandedContainers(false)
    }
  }
}

def environmentLaunch(mediaServer) {
  sh 'openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -subj "/CN=www.mydom.com/O=My Company LTD./C=US" -keyout /opt/openvidu/testapp/key.pem -out /opt/openvidu/testapp/cert.pem'
  sh 'cd /opt/openvidu/testapp && http-server -S -p 4200 &> /opt/openvidu/testapp.log &'
  if (mediaServer == 'kurento') {
    sh(script: '''#!/bin/bash -xe
      docker run -e KMS_UID=$(id -u) --network=host --detach=true --volume=/opt/openvidu/recordings:/opt/openvidu/recordings kurento/kurento-media-server:${KURENTO_MEDIA_SERVER_VERSION}
    '''.stripIndent())
  } else if (mediaServer == 'mediasoup') {
    sh(script: '''#!/bin/bash -xe
      docker run --network=host --restart=always --detach=true \
      --env=KMS_MIN_PORT=40000 \
      --env=KMS_MAX_PORT=65535 \
      --env=OPENVIDU_PRO_LICENSE=${OPENVIDU_PRO_LICENSE} \
      --env=OPENVIDU_PRO_LICENSE_API=${OPENVIDU_PRO_LICENSE_API} \
      --env=WEBRTC_LISTENIPS_0_ANNOUNCEDIP=172.17.0.1 \
      --env=WEBRTC_LISTENIPS_0_IP=172.17.0.1 \
      --volume=/opt/openvidu/recordings:/opt/openvidu/recordings \
      openvidu/mediasoup-controller:${MEDIASOUP_CONTROLLER_VERSION}
    '''.stripIndent())
  }
  script {
    env.mediaServer = mediaServer
    sh(script: '''#!/bin/bash -xe
      KMS_IP=172.17.0.1
      until $(curl --insecure --output /dev/null --silent http://${KMS_IP}:8888/kurento); do echo "Waiting for ${mediaServer}..."; sleep 1; done
      if [ "${DOCKER_RECORDING_VERSION}" != "default" ]; then
        echo "Using custom openvidu-recording tag: ${DOCKER_RECORDING_VERSION}"
        java -jar -DKMS_URIS=[\\"ws://${KMS_IP}:8888/kurento\\"] -DDOMAIN_OR_PUBLIC_IP=172.17.0.1 -DOPENVIDU_SECRET=MY_SECRET -DHTTPS_PORT=4443 -DOPENVIDU_RECORDING=true -DOPENVIDU_RECORDING_CUSTOM_LAYOUT=/opt/openvidu/test-layouts -DOPENVIDU_RECORDING_VERSION=${DOCKER_RECORDING_VERSION} -DOPENVIDU_WEBHOOK=true -DOPENVIDU_WEBHOOK_ENDPOINT=http://127.0.0.1:7777/webhook /opt/openvidu/openvidu-server-*.jar &> openvidu-server-${mediaServer}.log &
      else
        echo "Using default openvidu-recording tag"
        java -jar -DKMS_URIS=[\\"ws://${KMS_IP}:8888/kurento\\"] -DDOMAIN_OR_PUBLIC_IP=172.17.0.1 -DOPENVIDU_SECRET=MY_SECRET -DHTTPS_PORT=4443 -DOPENVIDU_RECORDING=true -DOPENVIDU_RECORDING_CUSTOM_LAYOUT=/opt/openvidu/test-layouts -DOPENVIDU_WEBHOOK=true -DOPENVIDU_WEBHOOK_ENDPOINT=http://127.0.0.1:7777/webhook /opt/openvidu/openvidu-server-*.jar &> openvidu-server-${mediaServer}.log &
      fi
    '''.stripIndent())
  }
  sh 'until $(curl --insecure --output /dev/null --silent --head --fail https://OPENVIDUAPP:MY_SECRET@localhost:4443/); do echo "Waiting for openvidu-server..."; sleep 2; done'
}

def environmentStop() {
  // Kill openvidu-server
  sh 'kill -9 $(pgrep -f /opt/openvidu/openvidu-server) || true'
  // Kill media server
  sh(script: '''#!/bin/bash -xe
    declare -a arr=("openvidu/mediasoup-controller:"
                    "kurento/kurento-media-server:")
    for image in "${arr[@]}"
    do
        docker ps -a | awk '{ print $1,$2 }' | grep "${image}" | awk '{ print $1 }' | xargs -I {} docker rm -f {}
    done
  '''.stripIndent())
}

def openViduE2ETest(mediaServerImage) {
  script {
      env.mediaServerImage = mediaServerImage
      env.openviduProLicense = "${OPENVIDU_PRO_LICENSE}"
      env.openviduProLicenseApi = "${OPENVIDU_PRO_LICENSE_API}"
      env.chromeVersion = "${CHROME_VERSION}"
      env.firefoxVersion = "${FIREFOX_VERSION}"
      env.operaVersion = "${OPERA_VERSION}"
      env.edgeVersion = "${EDGE_VERSION}"
      sh(script: '''#!/bin/bash -xe
        cd openvidu/openvidu-test-e2e
        ENV_VARS="-DMEDIA_SERVER_IMAGE=${mediaServerImage} -DCHROME_VERSION=${chromeVersion} -DFIREFOX_VERSION=${firefoxVersion} -DOPERA_VERSION=${operaVersion} -DEDGE_VERSION=${edgeVersion} -Dtest=OpenViduTestAppE2eTest -DAPP_URL=https://172.17.0.1:4200/ -DOPENVIDU_URL=https://172.17.0.1:4443/ -DREMOTE_URL_CHROME=http://172.17.0.1:6666/wd/hub/ -DREMOTE_URL_FIREFOX=http://172.17.0.1:6667/wd/hub/ -DREMOTE_URL_OPERA=http://172.17.0.1:6668/wd/hub/ -DREMOTE_URL_EDGE=http://172.17.0.1:6669/wd/hub/ -DEXTERNAL_CUSTOM_LAYOUT_URL=http://172.17.0.1:4114 -DEXTERNAL_CUSTOM_LAYOUT_PARAMS=sessionId,CUSTOM_LAYOUT_SESSION,secret,MY_SECRET"
        if [[ $mediaServerImage == *"openvidu/mediasoup-controller"* ]]; then
          ENV_VARS+=" -DOPENVIDU_PRO_LICENSE=${openviduProLicense} -DOPENVIDU_PRO_LICENSE_API=${openviduProLicenseApi}"
        fi
        sudo mvn -B ${ENV_VARS} test
      '''.stripIndent())
  }
}
