def setCommitStatus(String pStatus, String errorHint = '') {
    switch (pStatus) {
        case 'running':
            pState = 'running'
            pMessage = ""
            break
        case 'success':
            pState = 'success'
            pMessage = ":white_check_mark: ${env.JOB_NAME} :green_apple: <b>MacOS</b> SUCCEEDED :muscle:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'aborted':
            pState = 'canceled'
            pMessage = ":interrobang: ${env.JOB_NAME} :green_apple: <b>MacOS</b> ABORTED :confused:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'build_failure':
            pState = 'failed'
            pMessage = ":red_circle: ${env.JOB_NAME} :green_apple: <b>MacOS</b> FAILURE :worried:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'tests_failure':
            pState = 'failed'
            pMessage = "🟠 ${env.JOB_NAME} :green_apple: <b>MacOS</b> FAILURE :worried:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'unstable':
            pState = 'failed'
            pMessage = ":interrobang: ${env.JOB_NAME} :green_apple: <b>MacOS</b> UNSTABLE :confused:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        default:
            pState = 'failed'
            pMessage = ":interrobang: ${env.JOB_NAME} :green_apple: <b>MacOS</b> UNKNOWN :confused:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
    }
    if (pMessage) {
        if (errorHint) {
            pMessage += '<br/> ' + errorHint
        }
        addGitLabMRComment(comment: pMessage)
    }
    updateGitlabCommitStatus(name: "${PIPELINE_NAME}", state: pState)
}

def CUSTOM_TIMEOUT

pipeline {
    agent none
    options {
        buildDiscarder(logRotator(numToKeepStr: '135', daysToKeepStr: '21'))
        gitLabConnection('GitLabConnectionJenkins')
    }


    environment {
        PIPELINE_NAME = 'Build & test macOS'
        BUILD_OPTIONS = ''
        TESTS_PARALLEL = ''
        APIURL_TO_TEST = ''
        // SDK-5360 fu7-17 G6.S2: opt-in gates parsed from $gitlabTriggerPhrase.
        // Default 'false' so bench+tsan stages skip on regular MRs.
        RUN_TSAN_SWEEP = 'false'
        RUN_BENCH_SWEEP = 'false'
    }

    stages {
        stage('Update Gitlab CommitStatus') {
            agent any
            steps {
                updateGitlabCommitStatus(name: 'Build & test macOS', state: 'running')
                script{
                    COMMIT_ID = env.GIT_COMMIT
                    println GIT_COMMIT
                }
            }
        }
        stage('Build'){
            agent { label 'osx && arm64' }
            stages{
                stage('clean previous runs'){
                    steps{
                        deleteDir()
                    }
                }
                stage('Get parameters'){
                    parallel{
                        stage('Get build and run paramters'){
                            steps {
                                script{
                                    BUILD_OPTIONS = sh(script: 'echo "$gitlabTriggerPhrase" | grep BUILD_OPTIONS | awk -F "BUILD_OPTIONS="  \'{print \$2}\' | cut -d"\\"" -f2 || :', returnStdout: true).trim()
                                    TESTS_PARALLEL = sh(script: 'echo "$gitlabTriggerPhrase" | grep "\\-\\-sequence" >/dev/null 2>&1 && echo "" || echo "--INSTANCES:10"', returnStdout: true).trim()
                                    GTEST_REPEAT = sh(script: 'echo "$gitlabTriggerPhrase" | grep --only-matching "\\-\\-gtest_repeat=[^ ]*" | awk -F "gtest_repeat="  \'{print "--gtest_repeat="\$2}\'|| :', returnStdout: true).trim()
                                    GTEST_FILTER = sh(script: 'echo "$gitlabTriggerPhrase" | grep --only-matching "\\-\\-gtest_filter=[^ ]*" | awk -F "gtest_filter="  \'{print "--gtest_filter="\$2}\'|| :', returnStdout: true).trim()
                                    CUSTOM_TIMEOUT = sh(script: 'echo "$gitlabTriggerPhrase" | grep --only-matching "\\-\\-timeout=[^ ]*" | awk -F "timeout="  \'{print \$2}\'|| :', returnStdout: true).trim()
                                    CUSTOM_TIMEOUT = CUSTOM_TIMEOUT? CUSTOM_TIMEOUT : "450"
                                    RUN_TSAN_SWEEP = sh(script: 'echo "$gitlabTriggerPhrase" | grep "\\-\\-tsan" >/dev/null 2>&1 && echo "true" || echo "false"', returnStdout: true).trim()
                                    RUN_BENCH_SWEEP = sh(script: 'echo "$gitlabTriggerPhrase" | grep "\\-\\-bench" >/dev/null 2>&1 && echo "true" || echo "false"', returnStdout: true).trim()
                                    println BUILD_OPTIONS
                                    println TESTS_PARALLEL
                                    println GTEST_REPEAT
                                    println GTEST_FILTER
                                    println CUSTOM_TIMEOUT
                                    println "RUN_TSAN_SWEEP=${RUN_TSAN_SWEEP}"
                                    println "RUN_BENCH_SWEEP=${RUN_BENCH_SWEEP}"
                                }
                            }
                        }

                        stage('Get API URL'){
                            steps {
                                script{
                                    APIURL_TO_TEST = sh(script: 'echo "$gitlabMergeRequestDescription" | grep USE_APIURL_TO_TEST | awk -F "USE_APIURL_TO_TEST="  \'{print \$2}\' | cut -d" " -f1', returnStdout: true).trim()
                                    println APIURL_TO_TEST
                                    if (APIURL_TO_TEST == ""){
                                        APIURL_TO_TEST = "https://g.api.mega.co.nz/"
                                        echo "APIURL_TO_TEST was not found on description so ${APIURL_TO_TEST} will be used by default"
                                    }
                                    echo "APIURL_TO_TEST will be ${APIURL_TO_TEST}"
                                }
                            }
                        }
                    }
                }


                stage('Checkout macOS'){
                    steps {
                        checkout([
                            $class: 'GitSCM',
                            branches: [[name: "origin/${env.gitlabSourceBranch}"]],
                            userRemoteConfigs: [[ url: "${env.GIT_URL_SDK}", credentialsId: "12492eb8-0278-4402-98f0-4412abfb65c1" ]],
                            extensions: [
                                [$class: "UserIdentity",name: "jenkins", email: "jenkins@jenkins"],
                                [$class: 'PreBuildMerge', options: [fastForwardMode: 'FF', mergeRemote: "origin", mergeStrategy: 'DEFAULT', mergeTarget: "${env.gitlabTargetBranch}"]]
                                ]
                        ])
                        script{
                            mac_sources_workspace = WORKSPACE
                            sh "echo ${BUILD_OPTIONS}"
                        }
                    }
                    post {
                        failure {
                            script {
                                setCommitStatus('build_failure', ':warning: Checkout failed')
                            }
                            echo 'Error: Checkout stage failed'
                        }
                    }
                }
                stage('Build macOS'){
                    options{
                        timeout(time: 120, unit: 'MINUTES')
                    }
                    environment{
                        PATH = "/usr/local/bin:${env.PATH}"
                        VCPKGPATH = "${env.HOME}/jenkins/vcpkg"
                        BUILD_DIR = "build_dir"
                        BUILD_DIR_X64 = "build_dir_x64"
                        VCPKG_BINARY_SOURCES  = 'clear;x-aws,s3://vcpkg-cache/archives/,readwrite'
                        AWS_ACCESS_KEY_ID     = credentials('s4_access_key_id_vcpkg_cache')
                        AWS_SECRET_ACCESS_KEY = credentials('s4_secret_access_key_vcpkg_cache')
                        AWS_ENDPOINT_URL      = "https://s3.g.s4.mega.io"
                        MEGAQTPATH = "${env.HOME}/Qt-build/5.15.16/5.15.16"
                        COMMON_CMAKE_OPTIONS = "-DUSE_LIBUV=ON -DENABLE_QT_BINDINGS=ON -DENABLE_JAVA_BINDINGS=ON -DENABLE_MEDIA_FILE_METADATA=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DENABLE_CHAT=ON -DVCPKG_ROOT=${VCPKGPATH} ${BUILD_OPTIONS}"
                    }
                    steps{
                        dir(mac_sources_workspace){
                            //Build SDK for arm64
                            sh "echo Building SDK for arm64"
                            sh "rm -rf ${BUILD_DIR}; mkdir ${BUILD_DIR}"
                            sh "cmake -DCMAKE_PREFIX_PATH=${MEGAQTPATH}/arm64 ${COMMON_CMAKE_OPTIONS} -S ${mac_sources_workspace} -B ${mac_sources_workspace}/${BUILD_DIR}"
                            sh "cmake --build ${mac_sources_workspace}/${BUILD_DIR} -j3"

                            //Build SDK for x64
                            sh "echo \"Building SDK for x64 (crosscompiling)\""
                            sh "rm -rf ${BUILD_DIR_X64}; mkdir ${BUILD_DIR_X64}"
                            sh "cmake -DCMAKE_PREFIX_PATH=${MEGAQTPATH}/x86_64  ${COMMON_CMAKE_OPTIONS} -DCMAKE_OSX_ARCHITECTURES=x86_64 -S ${mac_sources_workspace} -B ${mac_sources_workspace}/${BUILD_DIR_X64}"
                            sh "cmake --build ${mac_sources_workspace}/${BUILD_DIR_X64} -j3"
                        }
                    }
                    post {
                        failure {
                            script {
                                setCommitStatus('build_failure', ':warning: Build failed. Tests won`t run')
                            }
                            echo "Error: Build stage failed. Tests won't run."
                        }
                    }
                }
                stage('Run macOS tests'){
                    environment {
                        MEGA_PWD = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD_AUX = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD_AUX2 = credentials('MEGA_PWD_DEFAULT')
                        MEGA_REAL_PWD=credentials('MEGA_REAL_PWD_TEST')
                        BUILD_DIR = "build_dir"
                    }
                    steps{
                        script {
                            def lockLabel = ''
                            if ("${APIURL_TO_TEST}" == 'https://g.api.mega.co.nz/') {
                                lockLabel = 'SDK_Concurrent_Test_Accounts'
                            } else  {
                                lockLabel = 'SDK_Concurrent_Test_Accounts_Staging'
                            }
                            lock(label: lockLabel, variable: 'ACCOUNTS_COMBINATION', quantity: 1, resourceSelectStrategy: "random", resource: null){
                                dir(mac_sources_workspace){
                                    timeout(time: "${CUSTOM_TIMEOUT}", unit: 'MINUTES') {
                                        script{
                                            env.MEGA_EMAIL = "${env.ACCOUNTS_COMBINATION}"
                                            echo "${env.ACCOUNTS_COMBINATION}"
                                        }
                                        sh "echo Running tests"
                                        sh """#!/bin/zsh
                                        setopt nonomatch
                                        cd ${env.BUILD_DIR}

                                        ./tests/unit/test_unit &
                                        pid=\$!
                                        wait \$pid || FAILED=1

                                        if [ -z \"\$FAILED\" ]; then
                                            ./tools/gfxworker/tests/integration/gfxworker_test_integration &
                                            pid=\$!
                                            wait \$pid || FAILED=2
                                            gzip -c gfxworker_test_integration.log > gfxworker_test_integration_${BUILD_ID}.log.gz || :
                                            rm gfxworker_test_integration.log || :
                                        fi

                                        # SDK-5360 fu8 S12 C(ii): provision the QaMixed real-media dataset on a
                                        # persistent per-agent path so SdkBenchmarkTest.QaMixedUpload RUNS instead
                                        # of skipping (HarvestQaMixedDataset is idempotent).
                                        export MEGA_BENCH_UPLOAD_SOURCE_DIR=\"\${HOME}/mega_bench_dataset/qa_mixed\"
                                        if [ -z \"\$FAILED\" ]; then
                                            ./tests/integration/test_integration --FREEACCOUNTS --CI --USERAGENT:${env.USER_AGENT_TESTS_SDK} --APIURL:${APIURL_TO_TEST} --gtest_filter=SdkTest.HarvestQaMixedDataset || FAILED=2
                                        fi

                                        if [ -z \"\$FAILED\" ]; then
                                            if [ -z \"${TESTS_PARALLEL}\" ]; then
                                                # Sequential run
                                                ./tests/integration/test_integration --FREEACCOUNTS --CI --USERAGENT:${env.USER_AGENT_TESTS_SDK} --APIURL:${APIURL_TO_TEST} ${GTEST_FILTER} ${GTEST_REPEAT} &
                                                pid=\$!
                                                wait \$pid || FAILED=3
                                                if [ \"\$FAILED\" = \"3\" ]; then
                                                    cp ${mac_sources_workspace}/pid_\$pid/test_integration.log .
                                                fi

                                            else
                                                # Parallel run
                                                ./tests/integration/test_integration --FREEACCOUNTS --CI --USERAGENT:${env.USER_AGENT_TESTS_SDK} --APIURL:${APIURL_TO_TEST} ${GTEST_FILTER} ${GTEST_REPEAT} ${TESTS_PARALLEL} 2>&1 | tee tests.stdout
                                                [ \"\${pipestatus[1]}\" != \"0\" ] && FAILED=3
                                            fi
                                        fi

                                        # Collect PIDs of test processes to match against macOS crash reports.
                                        if [ -z \"${TESTS_PARALLEL}\" ]; then
                                            pid_list=\$pid
                                        else
                                            pid_list=`grep \"<< PROCESS\" tests.stdout | sed 's/.*PID:\\([0-9]*\\).*/\\1/' | tr '\\n' ' '`
                                        fi
                                        # macOS 12+ .ips files contain two JSON objects: metadata on line 1 and
                                        # the crash report body on the remaining lines. pid lives in the body.
                                        # jq must not parse the whole file as a single JSON object.
                                        # https://developer.apple.com/documentation/xcode/interpreting-the-json-format-of-a-crash-report
                                        for ips_file in ~/Library/Logs/DiagnosticReports/*.ips; do
                                            # Modern format: crash body starts at line 2.
                                            ips_pid=`tail -n +2 \"\$ips_file\" 2>/dev/null | jq -r '.pid? // .PID? // empty' 2>/dev/null`
                                            if [ -z \"\$ips_pid\" ]; then
                                                # Legacy format: single JSON object on line 1.
                                                ips_pid=`head -1 \"\$ips_file\" 2>/dev/null | jq -r '.pid? // .PID? // empty' 2>/dev/null`
                                            fi
                                            # Archive only reports that belong to this test run.
                                            if [ -n \"\$ips_pid\" ] && echo \$pid_list | grep -q -w \"\$ips_pid\" ; then
                                                cp -v \$ips_file .
                                                cat \$ips_file
                                            fi
                                        done

                                        gzip -c test_integration.log > test_integration_${BUILD_ID}.log.gz || :

                                        if [ -n "\${FAILED}" ]; then
                                             echo "FAILED: \${FAILED}"
                                             exit "\${FAILED}"
                                        fi
                                        """
                                    }
                                }
                            }
                        }
                    }
                    post {
                        failure {
                            script {
                                setCommitStatus('tests_failure', ':warning: Build succeed. Tests failed')
                            }
                            echo 'Error: Test stage failed'
                        }
                    }
                }
                stage('Build TSAN') {
                    when {
                        expression { return RUN_TSAN_SWEEP == 'true' }
                    }
                    options {
                        timeout(time: 120, unit: 'MINUTES')
                    }
                    environment {
                        PATH = "/usr/local/bin:${env.PATH}"
                        VCPKGPATH = "${env.HOME}/jenkins/vcpkg"
                        TSAN_BUILD_DIR = "build_dir_tsan"
                        VCPKG_BINARY_SOURCES  = 'clear;x-aws,s3://vcpkg-cache/archives/,readwrite'
                        AWS_ACCESS_KEY_ID     = credentials('s4_access_key_id_vcpkg_cache')
                        AWS_SECRET_ACCESS_KEY = credentials('s4_secret_access_key_vcpkg_cache')
                        AWS_ENDPOINT_URL      = "https://s3.g.s4.mega.io"
                        MEGAQTPATH = "${env.HOME}/Qt-build/5.15.16/5.15.16"
                        COMMON_CMAKE_OPTIONS = "-DUSE_LIBUV=ON -DENABLE_QT_BINDINGS=ON -DENABLE_JAVA_BINDINGS=ON -DENABLE_MEDIA_FILE_METADATA=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DENABLE_CHAT=ON -DVCPKG_ROOT=${VCPKGPATH} ${BUILD_OPTIONS}"
                    }
                    steps {
                        dir(mac_sources_workspace){
                            // AppleClang supports -fsanitize=thread natively; ENABLE_TSAN=ON
                            // is enough. Only the arm64 slice is built (x86_64 omitted to keep
                            // the TSAN sweep under timeout — the WS-upload surface cells run identical
                            // logic on either arch).
                            sh "echo Building SDK with TSAN (arm64)"
                            sh "rm -rf ${TSAN_BUILD_DIR}; mkdir ${TSAN_BUILD_DIR}"
                            sh "cmake -DCMAKE_PREFIX_PATH=${MEGAQTPATH}/arm64 ${COMMON_CMAKE_OPTIONS} -DENABLE_TSAN=ON -S ${mac_sources_workspace} -B ${mac_sources_workspace}/${TSAN_BUILD_DIR}"
                            sh "cmake --build ${mac_sources_workspace}/${TSAN_BUILD_DIR} -j3 --target test_integration test_unit"
                        }
                    }
                    post {
                        failure {
                            echo "Error: TSAN build stage failed. TSAN sweep skipped."
                        }
                    }
                }
                stage('Run Benchmarks') {
                    when {
                        expression { return RUN_BENCH_SWEEP == 'true' }
                    }
                    environment {
                        PATH = "/usr/local/bin:${env.PATH}"
                        VCPKGPATH = "${env.HOME}/jenkins/vcpkg"
                        MEGA_PWD = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD_AUX = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD_AUX2 = credentials('MEGA_PWD_DEFAULT')
                        BUILD_DIR = "build_dir"
                        MEGAQTPATH = "${env.HOME}/Qt-build/5.15.16/5.15.16"
                        // SDK-5360 fu7-17 G6.S2: BENCH_FILTER is the fallback used when the user
                        // did NOT supply --gtest_filter= alongside --bench in the trigger phrase.
                        BENCH_FILTER = "SdkBenchmarkTest.*"
                    }
                    steps {
                        timeout(time: 120, unit: 'MINUTES') {
                            script {
                                def lockLabel = ''
                                if ("${APIURL_TO_TEST}" == 'https://g.api.mega.co.nz/') {
                                    lockLabel = 'SDK_Concurrent_Test_Accounts'
                                } else  {
                                    lockLabel = 'SDK_Concurrent_Test_Accounts_Staging'
                                }
                                lock(label: lockLabel, variable: 'ACCOUNTS_COMBINATION', quantity: 1, resourceSelectStrategy: "random", resource: null){
                                    dir(mac_sources_workspace) {
                                        script{
                                            env.MEGA_EMAIL = "${env.ACCOUNTS_COMBINATION}"
                                        }
                                        sh """#!/bin/bash
                                        set -x
                                        # Bench cells emit bench_report_<PID>.json when MEGA_BENCH_FRAMEWORK_ENABLED=ON;
                                        # the framework cmake option must be enabled at configure time.
                                        # ${env.BUILD_DIR}_bench keeps the bench artifacts isolated from the main build.
                                        rm -rf ${env.BUILD_DIR}_bench; mkdir ${env.BUILD_DIR}_bench
                                        cmake -DCMAKE_PREFIX_PATH=${MEGAQTPATH}/arm64 -DUSE_LIBUV=ON -DENABLE_QT_BINDINGS=ON -DENABLE_JAVA_BINDINGS=ON -DENABLE_CHAT=ON -DENABLE_MEDIA_FILE_METADATA=ON -DCMAKE_BUILD_TYPE=Debug -DMEGA_BENCH_FRAMEWORK_ENABLED=ON -DVCPKG_ROOT=${VCPKGPATH} \
                                            \${BUILD_OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=ON -S ${mac_sources_workspace} -B ${mac_sources_workspace}/${env.BUILD_DIR}_bench
                                        cmake --build ${mac_sources_workspace}/${env.BUILD_DIR}_bench -j3 --target test_integration
                                        # SDK-5360 fu7-17 G6.S2: prefer user-supplied --gtest_filter= when present.
                                        # GTEST_FILTER already includes the --gtest_filter= prefix when set.
                                        # GTEST_REPEAT is appended unconditionally; empty when not given.
                                        if [ -n \"${GTEST_FILTER}\" ]; then
                                            BENCH_FILTER_ARG=\"${GTEST_FILTER}\"
                                        else
                                            BENCH_FILTER_ARG=\"--gtest_filter=${env.BENCH_FILTER}\"
                                        fi
                                        ${env.BUILD_DIR}_bench/tests/integration/test_integration --FREEACCOUNTS --CI --USERAGENT:${env.USER_AGENT_TESTS_SDK} --APIURL:${APIURL_TO_TEST} \"\$BENCH_FILTER_ARG\" ${GTEST_REPEAT} 2>&1 | tee bench_sweep.log || true
                                        # Copy bench reports (consolidated JSON + per-iter JSONL, fu7-18 G1) from
                                        # the bench-build's pid_<PID>/bench_reports/ dirs to top-level for archival.
                                        for benchReport in ${env.BUILD_DIR}_bench/pid_*/bench_reports/bench_report_*.json ${env.BUILD_DIR}_bench/pid_*/bench_reports/bench_report_*.jsonl pid_*/bench_reports/bench_report_*.json pid_*/bench_reports/bench_report_*.jsonl; do
                                            [ -f \"\$benchReport\" ] && cp \"\$benchReport\" .
                                        done
                                        # SDK-5360 fu7-17 G6.S2: per-cell bench log split (BSD-csplit compatible).
                                        # macOS BSD csplit lacks -z; we filter empty splits manually below.
                                        mkdir -p bench_logs_${BUILD_ID} || :
                                        if [ -s bench_sweep.log ]; then
                                            csplit -k -s -b '%04d' -f bench_logs_${BUILD_ID}/_split_ bench_sweep.log '/\\[ RUN      \\]/' '{*}' || :
                                            for sf in bench_logs_${BUILD_ID}/_split_*; do
                                                [ -s \"\$sf\" ] || { rm -f \"\$sf\"; continue; }
                                                cellName=\$(grep -m1 -oE '\\[ RUN      \\] [A-Za-z0-9_.]+' \"\$sf\" | awk '{print \$4}' | tr '.' '_' || echo 'preamble')
                                                [ -n \"\$cellName\" ] || cellName=\"preamble\"
                                                mv \"\$sf\" \"bench_logs_${BUILD_ID}/\${cellName}.log\" || :
                                            done
                                        fi
                                        tar -czf bench_logs_${BUILD_ID}.tar.gz bench_logs_${BUILD_ID} || :
                                        rm -rf bench_logs_${BUILD_ID} || :
                                        gzip -c bench_sweep.log > bench_sweep_${BUILD_ID}.log.gz || :
                                        rm bench_sweep.log || :
                                        """
                                    }
                                }
                            }
                        }
                    }
                    post {
                        failure {
                            echo 'Error: Bench sweep failed'
                        }
                    }
                }
                stage('Run TSAN sweep') {
                    when {
                        expression { return RUN_TSAN_SWEEP == 'true' }
                    }
                    environment {
                        MEGA_PWD = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD_AUX = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD_AUX2 = credentials('MEGA_PWD_DEFAULT')
                        TSAN_BUILD_DIR = "build_dir_tsan"
                        TSAN_OPTIONS = "halt_on_error=0:second_deadlock_stack=1:history_size=7:report_thread_leaks=0"
                        // SDK-5360 fu7-17 G6.S2: fallback used when the user did NOT supply
                        // --gtest_filter= alongside --tsan. User filter wins below.
                        // SDK-5360 fu8 S12: + the two watchdog cells (CI TSAN previously never covered
                        // the watchdog/pause recovery paths; S11 carry-over ruled in by the user).
                        TSAN_SURFACE_FILTER = "SdkWsUploadTest.ActivePoolUsesParallelConnections:SdkWsUploadTest.InvalidPinnedSessionFallsBackToFreshSession:SdkWsUploadTest.OverquotaDuringTransfer:SdkWsUploadTest.RepeatedPauseResumeMixedPools:SdkWsUploadTest.AckStallForceReconnectsHungConnection:SdkWsUploadTest.TailCompletionWatchdogRecoversDroppedCompletion:SdkWsUploadTest.QuotaCrossPoolHoldDoesNotBlockOtherPool:SdkWsUploadTest.QuotaAccountRedOverquotaCoexistsWithPredictiveHolds:SdkWsUploadTest.LocallogoutCancelsBlackholedHandshake"
                        // SDK-6476: hermetic unit cells written for this sweep (the CurlHttpIO
                        // proxy/DNS/user-agent config race is invisible to the regular test_unit run).
                        // Any race report from them fails the stage.
                        TSAN_UNIT_FILTER = "CurlHttpIoConfig.*"
                    }
                    steps {
                        timeout(time: 90, unit: 'MINUTES') {
                            script {
                                def lockLabel = ''
                                if ("${APIURL_TO_TEST}" == 'https://g.api.mega.co.nz/') {
                                    lockLabel = 'SDK_Concurrent_Test_Accounts'
                                } else  {
                                    lockLabel = 'SDK_Concurrent_Test_Accounts_Staging'
                                }
                                lock(label: lockLabel, variable: 'ACCOUNTS_COMBINATION', quantity: 1, resourceSelectStrategy: "random", resource: null){
                                    dir(mac_sources_workspace) {
                                        script{
                                            env.MEGA_EMAIL = "${env.ACCOUNTS_COMBINATION}"
                                        }
                                        sh """#!/bin/bash
                                        set -x
                                        # SDK-6476: TSAN-oracle unit cells first (hermetic, no accounts): any race fails the
                                        # stage before the account-bound integration sweep starts. One log covers both binaries.
                                        ${env.TSAN_BUILD_DIR}/tests/unit/test_unit \"--gtest_filter=${TSAN_UNIT_FILTER}\" 2>&1 | tee tsan_sweep.log || true
                                        UNIT_RACES=\$(grep -c "WARNING: ThreadSanitizer" tsan_sweep.log || :)
                                        echo "===TSAN UNIT CELLS (${TSAN_UNIT_FILTER})=== races: \${UNIT_RACES:-0}"
                                        if [ \"\${UNIT_RACES:-0}\" != \"0\" ]; then
                                            echo "[ERROR] TSAN race in the unit cells" >&2
                                            exit 1
                                        fi
                                        if [ -n \"${GTEST_FILTER}\" ]; then
                                            TSAN_FILTER_ARG=\"${GTEST_FILTER}\"
                                        else
                                            TSAN_FILTER_ARG=\"--gtest_filter=${TSAN_SURFACE_FILTER}\"
                                        fi
                                        ${env.TSAN_BUILD_DIR}/tests/integration/test_integration --FREEACCOUNTS --CI --USERAGENT:${env.USER_AGENT_TESTS_SDK} --APIURL:${APIURL_TO_TEST} \"\$TSAN_FILTER_ARG\" ${GTEST_REPEAT} 2>&1 | tee -a tsan_sweep.log || true
                                        echo "===TSAN SUMMARY==="
                                        grep -cE "WARNING: ThreadSanitizer: data race" tsan_sweep.log || :
                                        echo "===WS-UPLOAD SURFACE FIELDS==="
                                        for fld in mChunksInFlight mNumChunksInFlight mUploadingFile WsConn::mLastActive WsConn::mPausedByServerUntilDs WsConn::mReadyState WsUploadFile mWorkGeneration; do
                                            cnt=\$(grep -cE "\$fld" tsan_sweep.log || :)
                                            echo "\$fld: \$cnt"
                                            if [ \"\$cnt\" != \"0\" ]; then
                                                echo "[ERROR] new WS-upload surface race on \$fld" >&2
                                                exit 1
                                            fi
                                        done
                                        # SDK-5360 fu7-17 G6.S2: per-cell TSAN log split (BSD-csplit compatible).
                                        mkdir -p tsan_logs_${BUILD_ID} || :
                                        if [ -s tsan_sweep.log ]; then
                                            csplit -k -s -b '%04d' -f tsan_logs_${BUILD_ID}/_split_ tsan_sweep.log '/\\[ RUN      \\]/' '{*}' || :
                                            for sf in tsan_logs_${BUILD_ID}/_split_*; do
                                                [ -s \"\$sf\" ] || { rm -f \"\$sf\"; continue; }
                                                cellName=\$(grep -m1 -oE '\\[ RUN      \\] [A-Za-z0-9_.]+' \"\$sf\" | awk '{print \$4}' | tr '.' '_' || echo 'preamble')
                                                [ -n \"\$cellName\" ] || cellName=\"preamble\"
                                                mv \"\$sf\" \"tsan_logs_${BUILD_ID}/\${cellName}.log\" || :
                                            done
                                        fi
                                        tar -czf tsan_logs_${BUILD_ID}.tar.gz tsan_logs_${BUILD_ID} || :
                                        rm -rf tsan_logs_${BUILD_ID} || :
                                        gzip -c tsan_sweep.log > tsan_sweep_${BUILD_ID}.log.gz || :
                                        rm tsan_sweep.log || :
                                        """
                                    }
                                }
                            }
                        }
                    }
                    post {
                        failure {
                            echo 'Error: TSAN sweep failed — NEW WS-upload surface race detected'
                        }
                    }
                }
            }
            post{
                always {
                    archiveArtifacts artifacts: 'build_dir/*log.gz, build_dir/examples-*.tar.gz', fingerprint: true, onlyIfSuccessful: false
                    archiveArtifacts artifacts: 'build_dir/*.ips', allowEmptyArchive: true, onlyIfSuccessful: false
                    archiveArtifacts artifacts: 'bench_report_*.json, bench_report_*.jsonl, bench_sweep*.log.gz, bench_logs_*.tar.gz, tsan_sweep*.log.gz, tsan_logs_*.tar.gz', allowEmptyArchive: true, onlyIfSuccessful: false
                    deleteDir()
                }
            }
        }
    }
    post {
        success {
            updateGitlabCommitStatus(name: 'Build & test macOS', state: 'success')
            addGitLabMRComment(comment: ":white_check_mark: ${currentBuild.projectName} :green_apple: <b>macOS</b> SUCCEEDED :muscle:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${COMMIT_ID}" )
        }
        unstable {
            updateGitlabCommitStatus(name: 'Build & test macOS', state: 'failed')
            addGitLabMRComment(comment: ":interrobang: ${currentBuild.projectName} :green_apple: <b>macOS</b> UNSTABLE  :confused:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${COMMIT_ID}" )      
        }
        aborted {
            updateGitlabCommitStatus(name: 'Build & test macOS', state: 'canceled')
            addGitLabMRComment(comment: ":interrobang: ${currentBuild.projectName} :green_apple: <b>macOS</b> ABORTED  :confused:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${COMMIT_ID}" )
        }
    }
}
