Skip to content
Snippets Groups Projects
Select Git revision
  • 6c1e09b9c22fc7c40c772691330640f4669e753c
  • main default protected
  • testing-imports
  • storybook-improvements
  • OZG-7287-forward-saml-token
  • OZG-7986-mandat-anfragen
  • release-administration
  • OZG-8422-BenutzerSpeichern
  • OZG-8314-Alfa-Vorgang-Bearbeiter-Zuweisung-entfernen
  • release-info
  • release
  • OZG-7856_schadcode-scanner-e2e
  • OZG-7985-fix-sorting
  • OZG-8305-Create-webpack-sbom
  • tooltip-improvements
  • OZG-7714-UpgradeKeycloakDependencyTo25
  • OZG-8086-Admin-Datenanfrage-erstellen
  • OZG-8086-Datenanfrage-Umbenennung
  • mongodb-7-0-16-e2e
  • OZG-6220-Bescheid-speichern-ohne-Postfach
  • OZG-7922-KeycloakOperatorExceptions
  • 1.12.1-administration
  • 1.12.0-administration
  • 1.12.0-info
  • 2.27.0-alfa
  • 1.11.0-info
  • 1.11.0-administration
  • 2.26.0-alfa
  • 1.10.0-info
  • 1.10.0-administration
  • 2.25.0-alfa
  • 1.9.0-info
  • 1.9.0-administration
  • 2.24.0-alfa
  • 1.8.0-info
  • 1.8.0-administration
  • 2.23.0-alfa
  • 1.7.0-info
  • 1.7.0-administration
  • 2.22.0-alfa
  • 1.6.0-info
41 results

cypress-helper.ts

Blame
  • Jenkinsfile 26.76 KiB
    import groovy.json.JsonOutput
    
    def SKIP_RUN = false
    
    pipeline {
        agent {
            node {
                label 'jenkins-build-agent-nodejs-16'
            }
        }
    
        triggers {
            upstream(upstreamProjects: getUpstreamProjects(), threshold: hudson.model.Result.SUCCESS)
        }
    
        environment {
            BLUE_OCEAN_URL = "https://jenkins.ozg-sh.de/job/E2E%20Tests/job/${env.BRANCH_NAME}/${env.BUILD_NUMBER}/"
            BUNDESLAND = "by"
            SSO_URL = "sso.load.by.ozg-cloud.de"
            CLUSTER_BASE_URL = "load.by.ozg-cloud.de"
            FAILED_STAGE = ""
            FAILED_PARALLEL_STAGE = " "
            EA_BEZEICHNER = generateBezeichner("e2e-ea")
            MAIN_BEZEICHNER = generateBezeichner("e2e-main")
            SH_SUCCESS_STATUS_CODE = 0
        }
    
        options {
            timeout(time: 2, unit: 'HOURS')
            disableConcurrentBuilds()
            buildDiscarder(logRotator(numToKeepStr: '5'))
            skipDefaultCheckout(true)
        }
    
        stages {
            stage('Checkout build trigger') {
                when {
                    not {
                        anyOf {
                            triggeredBy 'UpstreamCause'
                            triggeredBy 'BuildUpstreamCause'
                            triggeredBy cause: 'UserIdCause'
                        }
                    }
                }
                steps {
                    script {
                        SKIP_RUN = true
                        currentBuild.result= "UNSTABLE"
                    }
                }
            }
            stage('Checkout SCM') {
                when {
                    expression { !SKIP_RUN }
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        checkout scm
                    }
                }
            }
            stage("Clone Gitops Repo") {
                when {
                    expression { !SKIP_RUN }
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        cloneGitopsRepo()
                    }
                }
            }
    
            stage("Init Default Versions") {
                when {
                    expression { !SKIP_RUN }
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        initEnvGoofyDefaultVersions()
                        initEnvPlutoDefaultVersions()
                        initEnvUserManagerDefaultVersions()
                    }
                }
            }
    
            stage("Set User Versions") {
                when {
                    expression { !SKIP_RUN }
                    beforeInput true
                    triggeredBy cause: "UserIdCause"
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        catchError {
                            timeout(time: 5, unit: 'MINUTES') {
                                userVersions = input message: "Edit Default Values",
                                    parameters: [
                                        string(name: "GoofyImageTag", defaultValue: env.GOOFY_IMAGE_TAG, trim: true),
                                        string(name: "GoofyHelmChartVersion", defaultValue: env.GOOFY_HELM_CHART_VERSION, trim: true),
                                        string(name: "GoofyHelmRepoUrl", defaultValue: env.GOOFY_HELM_REPO_URL, trim: true),
                                        string(name: "PlutoImageTag", defaultValue: env.PLUTO_IMAGE_TAG, trim: true),
                                        string(name: "PlutoHelmChartVersion", defaultValue: env.PLUTO_HELM_CHART_VERSION, trim: true),
                                        string(name: "PlutoHelmRepoUrl", defaultValue: env.PLUTO_HELM_REPO_URL, trim: true),
                                        string(name: "UserManagerImageTag", defaultValue: env.USER_MANAGER_IMAGE_TAG, trim: true),
                                        string(name: "UserManagerHelmChartVersion", defaultValue: env.USER_MANAGER_HELM_CHART_VERSION, trim: true),
                                        string(name: "UserManagerHelmRepoUrl", defaultValue: env.USER_MANAGER_HELM_REPO_URL, trim: true)
                                    ]
    
                                initEnvUserVersions(userVersions)
                            }
                        }
                    }
                }
            }
    
            stage("Install Cypress") {
                when {
                    expression { !SKIP_RUN }
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        sh 'npm --version'
                        dir('goofy-client') {
                            sh 'echo "registry=https://nexus.ozg-sh.de/repository/npm-proxy" >> ~/.npmrc'
                            sh 'echo "//nexus.ozg-sh.de/:_auth=amVua2luczprTSFnNVUhMVQzNDZxWQ==" >> ~/.npmrc'
    
                            sh 'npm cache verify'
                            sh 'npm install'
                            sh "npm run cypress:install"
                        }
                    }
                }
            }
    
            stage('Init k8s') {
                when {
                    expression { !SKIP_RUN }
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        configFileProvider([configFile(fileId: 'kubeconfig-dev-okd-cluster', variable: 'KUBE_CONFIG')]) {
                            sh 'mkdir ~/.kube'
                            sh 'cp ${KUBE_CONFIG} ~/.kube/config'
                        }
    
                        sh 'helm version'
                    }
                }
            }
    
            stage('Rollout E2E Namespaces') {
                when {
                    expression { !SKIP_RUN }
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        checkoutGitopsE2eBranch()
    
                        deleteKopStack([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER])
    
                        generateEaNamespaceYaml()
                        generateMainNamespaceYaml()
    
                        pushGitopsRepo()
    
                        waitForKopStackRollout([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER])
                    }
                }
                post {
                    failure {
                        script {
                            deleteKopStack([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER])
                        }
                    }
                }
            }
    
            stage('Run E2E-Tests') {
                when {
                    expression { !SKIP_RUN }
                }
                failFast false
    
                parallel {
                    stage('E2E-EA') {
                        steps {
                            catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
                                script {
                                    def bezeichner = env.EA_BEZEICHNER
                                    def dbPort = 27018
    
                                    forwardServices(generateNamespace(bezeichner), dbPort)
    
                                    runTests(bezeichner, 'einheitlicher-ansprechpartner', dbPort, env.STAGE_NAME)
                                }
                            }
                        }
                        post {
                            failure {
                                script {
                                    FAILED_PARALLEL_STAGE += "${env.STAGE_NAME} "
                                }
                            }
                            always {
                                script {
                                    publishE2ETestResult("einheitlicher-ansprechpartner", "Goofy E2E-Tests EA")
                                }
                            }
                        }
                    }
    
                    stage('E2E-Main') {
                        steps {
                            catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
                                script {
                                    def bezeichner = env.MAIN_BEZEICHNER
                                    def dbPort = 27019
    
                                    forwardServices(generateNamespace(bezeichner), dbPort)
    
                                    runTests(bezeichner, 'main-tests', dbPort, env.STAGE_NAME)
                                }
                            }
                        }
                        post {
                            failure {
                                script {
                                    FAILED_PARALLEL_STAGE += "${env.STAGE_NAME} "
                                }
                            }
                            always {
                                script {
                                    publishE2ETestResult("main-tests", "Goofy E2E-Tests main")
                                }
                            }
                        }
                    }
                }
            }
    
            stage('Delete E2E Namespaces') {
                when {
                    expression { !SKIP_RUN }
                }
                steps {
                    script {
                        FAILED_STAGE = env.STAGE_NAME
    
                        deleteKopStack([env.EA_BEZEICHNER, env.MAIN_BEZEICHNER])
                    }
                }
            }
        }
        post {
            failure {
                script {
                    if (isMasterBranch() || isReleaseBranch()) {
                        sendFailureMessage()
                    }
                }
            }
        }
    }
    
    String getUpstreamProjects() {
        if (isMasterBranch() || isReleaseBranch()){
            return "goofy/${env.BRANCH_NAME},pluto/${env.BRANCH_NAME},user-manager/${env.BRANCH_NAME}"
        }
    
        return ""
    }
    
    Boolean isReleaseBranch() {
        return env.BRANCH_NAME == 'release'
    }
    
    Boolean isMasterBranch() {
        return env.BRANCH_NAME == 'master'
    }
    
    def cloneGitopsRepo() {
        final email = "jenkins@ozg-sh.de"
        final name = "jenkins"
    
        withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) {
            sh 'git clone https://${USER}:${TOKEN}@git.ozg-sh.de/mgm/gitops.git'
    
            dir("gitops") {
                sh "git config user.email '${email}'"
                sh "git config user.name '${name}'"
            }
        }
    }
    
    Map getApplicationValues(String application) {
        def applicationValues = readYaml file: "gitops/${getEnvironment()}/application/values/${application}-values.yaml"
    
        return applicationValues.get(application.replaceAll("-", "_"))
    }
    
    String getEnvironment() {
        if (isReleaseBranch()) {
            return "test"
        }
    
        return "dev"
    }
    
    String getImageTag(Map applicationValues) {
        return applicationValues.image.tag
    }
    
    String getHelmChartVersion(Map applicationValues) {
        return applicationValues.helm.version
    }
    
    Void initEnvGoofyDefaultVersions() {
        if (isMasterBranch() || isReleaseBranch()) {
            goofyValues = getApplicationValues("goofy")
    
            env.GOOFY_IMAGE_TAG = getImageTag(goofyValues)
            env.GOOFY_HELM_CHART_VERSION = getHelmChartVersion(goofyValues)
        }
        else {
            env.GOOFY_IMAGE_TAG = getFeatureBranchImageTag()
            env.GOOFY_HELM_CHART_VERSION = getFeatureBranchHelmChartVersion()
        }
    
        env.GOOFY_HELM_REPO_URL = getHelmRepoUrl()
    }
    
    String getHelmRepoUrl() {
        if (isReleaseBranch()) {
            return "https://nexus.ozg-sh.de/repository/ozg-base-apps"
        }
    
        return "https://nexus.ozg-sh.de/repository/ozg-base-apps-snapshot"
    }
    
    String getFeatureBranchImageTag() {
        return "${env.BRANCH_NAME}-${getRootPomVersion()}"
    }
    
    String getFeatureBranchHelmChartVersion() {
        return "${getRootPomVersion()}-${env.BRANCH_NAME}".replaceAll("_", "-")
    }
    
    String getRootPomVersion() {
        def rootPom = readMavenPom file: 'pom.xml'
    
        return rootPom.version
    }
    
    Void initEnvPlutoDefaultVersions() {
        plutoValues = getApplicationValues("pluto")
    
        env.PLUTO_IMAGE_TAG = getImageTag(plutoValues)
        env.PLUTO_HELM_CHART_VERSION = getHelmChartVersion(plutoValues)
        env.PLUTO_HELM_REPO_URL = getHelmRepoUrl()
    }
    
    Void initEnvUserManagerDefaultVersions() {
        userManagerValues = getApplicationValues("user-manager")
    
        env.USER_MANAGER_IMAGE_TAG = getImageTag(userManagerValues)
        env.USER_MANAGER_HELM_CHART_VERSION = getHelmChartVersion(userManagerValues)
        env.USER_MANAGER_HELM_REPO_URL = getHelmRepoUrl()
    }
    
    Void initEnvUserVersions(userVersions) {
        env.GOOFY_IMAGE_TAG = userVersions.GoofyImageTag
        env.GOOFY_HELM_CHART_VERSION = userVersions.GoofyHelmChartVersion
        env.GOOFY_HELM_REPO_URL = userVersions.GoofyHelmRepoUrl
        env.PLUTO_IMAGE_TAG = userVersions.PlutoImageTag
        env.PLUTO_HELM_CHART_VERSION = userVersions.PlutoHelmChartVersion
        env.PLUTO_HELM_REPO_URL = userVersions.PlutoHelmRepoUrl
        env.USER_MANAGER_IMAGE_TAG = userVersions.UserManagerImageTag
        env.USER_MANAGER_HELM_CHART_VERSION = userVersions.UserManagerHelmChartVersion
        env.USER_MANAGER_HELM_REPO_URL = userVersions.UserManagerHelmRepoUrl
    }
    
    
    Void pushGitopsRepo() {
        withCredentials([usernamePassword(credentialsId: 'jenkins-gitea-access-token', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) {
            dir("gitops") {
                if (hasUnpushedCommits()) {
                    sh 'git pull'
                    sh 'git push https://${USER}:${TOKEN}@git.ozg-sh.de/mgm/gitops.git'
                }
            }
        }
    }
    
    Boolean hasUnpushedCommits() {
        return sh (script: "git cherry -v | grep .", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    }
    
    Void checkoutGitopsE2eBranch() {
        dir("gitops") {
            sh 'git checkout lasttest'
        }
    }
    
    Void generateEaNamespaceYaml() {
        generateNamespaceYaml(env.EA_BEZEICHNER, "by-ea-dev.yaml", "user-ea");
    }
    
    Void generateMainNamespaceYaml() {
        generateNamespaceYaml(env.MAIN_BEZEICHNER, "by-main-dev.yaml", "user-main");
    }
    
    Void generateNamespaceYaml(String bezeichner, String valuesPathSuffix, String userFolder) {
        def envValues = readYaml file: "goofy-client/apps/goofy-e2e/src/fixtures/argocd/" + valuesPathSuffix;
    
        envValues.kop.bezeichner = bezeichner
        envValues.goofy.put("image", ['tag': env.GOOFY_IMAGE_TAG])
        envValues.goofy.put("helm", ['version': env.GOOFY_HELM_CHART_VERSION, 'repoUrl': env.GOOFY_HELM_REPO_URL])
    
        envValues.pluto.put("image", ['tag': env.PLUTO_IMAGE_TAG])
        envValues.pluto.put("helm", ['version': env.PLUTO_HELM_CHART_VERSION, 'repoUrl': env.PLUTO_HELM_REPO_URL])
    
        envValues.user_manager.put("image", ['tag': env.USER_MANAGER_IMAGE_TAG])
        envValues.user_manager.put("helm", ['version': env.USER_MANAGER_HELM_CHART_VERSION, 'repoUrl': env.USER_MANAGER_HELM_REPO_URL])
    
        envValues.goofy.sso.put("keycloak_groups", generateKeycloakGroupsForHelmChart())
        envValues.goofy.sso.put("keycloak_users", generateKeycloakUserForHelmChart(userFolder))
    
        writeYaml file: "gitops/dev/namespace/namespaces/by-${bezeichner}-dev.yaml", data: envValues, overwrite: true
    
        sh "cat gitops/dev/namespace/namespaces/by-${bezeichner}-dev.yaml"
    
        dir("gitops") {
            sh "git add dev/namespace/namespaces/by-${bezeichner}-dev.yaml"
            sh "git commit -m 'add e2e by-${bezeichner}-dev'"
        }
    }
    
    List generateKeycloakUserForHelmChart(String userFolder) {
        def userFiles = sh (script: 'ls goofy-client/apps/goofy-e2e/src/fixtures/' + userFolder, returnStdout: true);
    
        def helmUsers = []
    
        userFiles.split("\\n").each { userFile ->
            def userJson = readJSON file: "goofy-client/apps/goofy-e2e/src/fixtures/${userFolder}/${userFile}"
            def user = [
                "name": userJson.name,
                "password": userJson.password,
                "first_name": userJson.get("firstName", ""),
                "last_name": userJson.get("lastName", ""),
                "email": userJson.get("email", "")
                ]
    
            if (userJson.containsKey("clientRoles")) {
                user.put("client_roles", mapUserClientRoles(userJson.clientRoles))
            }
    
            if (userJson.containsKey("groups")) {
                user.put("groups", userJson.groups)
            }
    
            helmUsers.add(user)
        }
    
        return helmUsers
    }
    
    List mapUserClientRoles(userClientRoles) {
        def clientRoles = []
    
        for(clientRole in userClientRoles) {
            clientRoles.add(['name': "alfa", 'role': clientRole])
        }
    
        return clientRoles
    }
    
    List generateKeycloakGroupsForHelmChart() {
        def groupFiles = sh (script: 'ls goofy-client/apps/goofy-e2e/src/fixtures/group', returnStdout: true)
    
        def helmGroups = []
    
        groupFiles.split("\\n").each { groupFile ->
            def groupJson = readJSON file: "goofy-client/apps/goofy-e2e/src/fixtures/group/${groupFile}"
            def group = ["name": groupJson.name]
    
            groupJson.attributes.each { key, values ->
                if (!group.containsKey("attributes")) {
                    group.put("attributes", [["name": key, "value": values]])
                }
                else {
                    group.attributes.add(["name": key, "value": values])
                }
            }
    
            helmGroups.add(group)
    	}
    
        return helmGroups
    }
    
    Void deleteKopStack(kopBezeichner) {
        for(bezeichner in kopBezeichner) {
            if (hasNamespaceFile(bezeichner)) {
                removeNamespaceFile(bezeichner)
            }
        }
    
        pushGitopsRepo()
    
        for(bezeichner in kopBezeichner) {
            waitForDeletion(bezeichner)
        }
    }
    
    Void removeNamespaceFile(String bezeichner) {
        dir("gitops/dev/namespace/namespaces") {
            sh "rm by-${bezeichner}-dev.yaml"
            sh "git add by-${bezeichner}-dev.yaml"
            sh "git commit -m 'delete e2e by-${bezeichner}-dev.yaml'"
        }
    }
    
    Boolean hasNamespaceFile(String bezeichner) {
        return sh (script: "ls gitops/dev/namespace/namespaces | grep 'by-${bezeichner}-dev.yaml'", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    }
    
    Void waitForDeletion(String bezeichner) {
        try {
            sh "kubectl wait --for=delete applications/by-${bezeichner}-dev-application -n argocd --timeout=900s"
        } catch (Exception e) {
            error("Application by-${bezeichner}-dev-application konnte nicht gelöscht werden")
        }
    }
    
    Void waitForKopStackRollout(kopBezeichner) {
        for(bezeichner in kopBezeichner) {
            waitForRollout(bezeichner)
        }
    }
    
    Void waitForRollout(String bezeichner) {
        waitForHealthyApplication(bezeichner, 'application')
        waitForHealthyApplication(bezeichner, 'pluto')
        waitForHealthyApplication(bezeichner, 'user-manager')
        waitForHealthyApplication(bezeichner, 'goofy')
    }
    
    Void waitForHealthyApplication(String bezeichner, String application) {
        try {
            def countRetry = 0
            def maxRetry = 24
    
            while (!isApplicationPresent(bezeichner, application) && countRetry < maxRetry ) {
                countRetry++
                sh "sleep 5"
            }
    
            if (!isApplicationHealthy(bezeichner, application)) {
                waitForHealthyStatus(bezeichner, application)
            }
        } catch (Exception e) {
            echo "waitForHealthyApplication Exception: ${e}"
            error("Application ${application} unhealthy")
        }
    }
    
    Boolean isApplicationPresent(String bezeichner, String application) {
        return sh (script: "kubectl get applications -n argocd | grep 'by-${bezeichner}-dev-${application}'", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    }
    
    Boolean isApplicationHealthy(String bezeichner, String application) {
        return sh (script: "kubectl get application/by-${bezeichner}-dev-${application} -n argocd -o=jsonpath='{.status.health.status}' | grep Healthy", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    }
    
    Void waitForHealthyStatus(String bezeichner, String application) {
        sh "kubectl wait --for=jsonpath='{.status.health.status}'=Healthy applications/by-${bezeichner}-dev-${application} -n argocd --timeout=900s"
    }
    
    Void publishE2ETestResult(String reportFolder, String reportName) {
        publishHTML (
            target: [
                allowMissing: false,
                alwaysLinkToLastBuild: false,
                keepAll: true,
                reportDir: "goofy-client/apps/goofy-e2e/reports/${reportFolder}",
                reportFiles: 'report.html',
                reportName: reportName
            ]
        )
    }
    
    String runTests(String bezeichner, String reportFolder, Integer dbPort, String stageName) {
        def config = generateCypressConfig(bezeichner, reportFolder, dbPort)
    
        try {
            dir('goofy-client'){
    			sh "npm run cypress:version"
    			sh "apps/goofy-e2e/run-tests.sh ${reportFolder} ${config}"
            }
        } catch (Exception e) {
            printNpmDebugLog()
    
            error("Fehler in Stage ${stageName}")
        }
    }
    
    Void printNpmDebugLog() {
        if (hasNpmDebugLog()) {
            sh "cat /root/.npm/_logs/*-debug.log"
        }
        else {
            echo "Npm debug log not found"
        }
    }
    
    String makeUrlConform(String input) {
        return input.replaceAll(/[^a-zA-Z0-9]+/, "").toLowerCase()
    }
    
    String generateBezeichner(String stage) {
        def branchName = makeUrlConform(env.BRANCH_NAME)
        def stageName = makeUrlConform(stage)
    
        return "${cutBranchNameForKeycloakRealm(branchName, stageName)}-${stageName}"
    }
    
    String cutBranchNameForKeycloakRealm(String branchName, String stageName) {
        final maxKeycloakRealmLength = 30
    
        def cutBranchNamePosition = maxKeycloakRealmLength - (stageName.length() + "${env.BUNDESLAND}---dev".length())
    
        return branchName.take(cutBranchNamePosition)
    }
    
    String generateCypressConfig(String bezeichner, String testFolder, Integer dbPort) {
        def namespace = generateNamespace(bezeichner)
    	def configName = "cypress-ci-"+testFolder+".json"
    
    	dir('goofy-client/apps/goofy-e2e/'){
    		def config = readJSON file: 'cypress-ci.json'
    
    		def plutoDatabaseSecret = getPlutoDatabaseSecret(namespace);
    		def decodedPassword = decodeString(plutoDatabaseSecret.password);
    		def parsablePassword = makePasswordUrlConform(decodedPassword);
    
    		config.baseUrl = "https://${bezeichner}.${env.CLUSTER_BASE_URL}" as String
    		config.env.dbUrl = "mongodb://${decodeString(plutoDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true" as String
    		config.env.keycloakUrl = "https://${env.SSO_URL}/" as String
    		config.env.keycloakRealm = namespace as String
    		config.env.sabineUuid = getKeycloakUuid(namespace, "sabine") as String
    		config.videosFolder = "./reports/${testFolder}/videos" as String
    		config.screenshotsFolder = "./reports/${testFolder}/screenshots" as String
    		config.reporterOptions.reportDir = "./reports/${testFolder}/mochawesome-report" as String
    
            config.specPattern = "src/e2e/${testFolder}/**/*.cy.{js,jsx,ts,tsx}" as String
    
    		config.env.put("search", getElasticsearchEnv(namespace))
    		config.env.put("userManager", getUserManagerEnv(namespace, dbPort))
    
    		writeJSON file: configName, json: config
    
    		sh "cat ${configName}"
    	}
    
    	return "cypress-ci-"+testFolder+".config.ts"
    }
    
    String makePasswordUrlConform(String password) {
        return sh (script: "printf %s ${password} | jq -sRr @uri", returnStdout: true);
    }
    
    Map getPlutoDatabaseSecret(String namespace) {
        return readJSON ( text: sh (script: "kubectl get secret ozg-mongodb-admin-pluto-user -n ${namespace} -o jsonpath={.data}", returnStdout: true))
    }
    
    Map getUserManagerEnv(String namespace, dbPort){
    	def userManagerDatabaseSecret = getUserManagerDatabaseSecret(namespace);
        def decodedPassword = decodeString(userManagerDatabaseSecret.password);
    	def parsablePassword = makePasswordUrlConform(decodedPassword);
    
        return [
            "dbUrl": "mongodb://${decodeString(userManagerDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true" as String,
            "database": "user-manager-database"
            ]
    }
    
    Map getUserManagerDatabaseSecret(String namespace) {
        return readJSON ( text: sh (script: "kubectl get secret ozg-mongodb-admin-user-manager-user -n ${namespace} -o jsonpath={.data}", returnStdout: true))
    }
    
    String getKeycloakUuid(realm, userName) {
        def shScript = """curl -H 'Content-Type: application/json' \
                            -H 'Authorization: bearer ${getKeycloakAccessToken()}' \
                            'https://${env.SSO_URL}/admin/realms/${realm}/users'
                        """
    
    	def users = readJSON text: sh(script: shScript, returnStdout: true)
    
        echo "users: ${users}"
    
    	for(user in users) {
    		if (user.username == userName) {
                return user.id
    		}
    	}
    }
    
    String getKeycloakAccessToken() {
    	withCredentials([usernamePassword(credentialsId: 'keycloak-ovh-cluster', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
    		def token = readJSON text: sh (script: 'curl -d "client_id=admin-cli" -d "username=$USER" -d "password=$PASSWORD" -d "grant_type=password" https://$SSO_URL/realms/master/protocol/openid-connect/token', returnStdout: true)
    
    		return token.access_token
    	}
    }
    
    Void sendFailureMessage() {
        def data = [
            "msgtype": "m.text",
            "body": "E2E-Tests: Failed stage: ${getFailedStage()} Build-ID: ${env.BUILD_NUMBER} Link: ${BLUE_OCEAN_URL}" as String,
            "format": "org.matrix.custom.html",
            "formatted_body": "E2E-Tests: Failed stage: ${getFailedStage()} Build-ID: <a href='${BLUE_OCEAN_URL}'>${env.BUILD_NUMBER}</a>" as String
            ]
    
        sh "curl -XPOST -H 'authorization: Bearer ${getElementAccessToken()}' -d '${JsonOutput.toJson(data)}' https://matrix.ozg-sh.de/_matrix/client/v3/rooms/${getElementRoomId()}/send/m.room.message"
    }
    
    String getFailedStage() {
        if (FAILED_PARALLEL_STAGE.trim()) {
            return FAILED_PARALLEL_STAGE.trim()
        }
    
        return FAILED_STAGE
    }
    
    String getElementRoomId() {
        final releaseRoomId = "!oWZpUGTFsxkJIYNfYg:matrix.ozg-sh.de"
        final masterRoomId = "!iQPAvQIiRwRpNOszjw:matrix.ozg-sh.de"
    
        if (isReleaseBranch()) {
            return releaseRoomId
        }
    
        return masterRoomId
    }
    
    String getElementAccessToken() {
        withCredentials([string(credentialsId: 'element-login-json', variable: 'LOGIN_JSON')]) {
            return readJSON ( text: sh (script: '''curl -XPOST -d \"$LOGIN_JSON\" https://matrix.ozg-sh.de/_matrix/client/v3/login''', returnStdout: true)).access_token
        }
    }
    
    Map getElasticsearchEnv(String namespace) {
        def elasticsearchSecret = getElasticsearchSecret(namespace)
    
        return [
            "user": decodeString(elasticsearchSecret.username),
            "password": decodeString(elasticsearchSecret.password),
            "index": decodeString(elasticsearchSecret.index),
            "url": "https://localhost:9200"
            ]
    }
    
    Void forwardServices(String namespace, Integer dbPort) {
        try {
            forwardDatenbank(namespace, dbPort)
            forwardElasticSearch()
        }
        catch (Exception e) {
            echo "forwardServices Exception: ${e}"
            error("Error forwarding service")
        }
    }
    
    Void forwardElasticSearch() {
        if(!isElasticSearchForwarded()) {
            sh "kubectl port-forward ozg-search-cluster-es-ozg-search-0 9200:9200 -n elastic-system &"
        }
    }
    
    Boolean isElasticSearchForwarded() {
        return sh (script: "lsof -i -P -n | grep LISTEN | grep :9200", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    }
    
    Void forwardDatenbank(String namespace, port) {
        sh "kubectl port-forward ozg-mongodb-0 ${port}:27017 -n ${namespace} &"
    }
    
    String generateNamespace(String bezeichner) {
        return "${env.BUNDESLAND}-${bezeichner}-dev"
    }
    
    String decodeString(String encoded) {
        return sh (script: "echo -n ${encoded} | base64 --decode", returnStdout: true)
    }
    
    Map getElasticsearchSecret(String namespace) {
        return readJSON ( text: sh (script: "kubectl get secret elasticsearch-credentials -n ${namespace} -o jsonpath={.data}", returnStdout: true))
    }
    
    Boolean hasNpmDebugLog() {
        return sh (script: "ls -l /root/.npm/_logs/*-debug.log", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
    }