#!/usr/bin/env bash # Execute the immutable self-contained apphost through the cached Linux VSTest controller. verify_mapped_coreclr() { awk -v identity="$2" ' $6 ~ /\/libcoreclr.so$/ { if (NF != 6 || ($5 " " $6) != identity) bad = 1 else matched = 1 } END { exit (matched && !bad) ? 0 : 1 } ' "$1" } # The offline controls source only the mapping check above. if [[ ${BASH_SOURCE[0]} != "$0" ]]; then return 0; fi set -euo pipefail umask 077 app=ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests test_class="$app.Sdk2LifecycleSoakTests" [[ -d /task/tmp && ! -L /task/tmp && -d /tmp && ! -L /tmp ]] [[ $(stat -c '%a' /task/tmp) == 700 && $(stat -c '%d:%i' /task/tmp) == "$(stat -c '%d:%i' /tmp)" ]] mkdir -p /task/data /task/cli /task/results export TMPDIR=/task/tmp XDG_DATA_HOME=/task/data DOTNET_CLI_HOME=/task/cli export OTOPCUA_SDK2_SOAK=1 OTOPCUA_SDK2_SOAK_MODE=late-slope OTOPCUA_SDK2_SOAK_SECONDS=7200 export OTOPCUA_SDK2_SOAK_OUTPUT=/task/resources.jsonl OPCUA_CERTIFICATE_LEAK_TRACKING=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1 [[ $(uname -s) == Linux && $(uname -m) == aarch64 && -d /proc/self/fd ]] [[ ${OTOPCUA_SOAK_BUILD_SHA:-} =~ ^[0-9a-f]{40}$ ]] dotnet --info > /task/controller-runtime.txt dotnet vstest "/app/$app.dll" \ --TestCaseFilter:"FullyQualifiedName~$test_class.Descriptor_probe_" \ --ResultsDirectory:/task/results '--Logger:trx;LogFileName=descriptor-controls.trx' > /task/descriptor-controls.log 2>&1 # Verify actual execution before starting the long test. The host parses the complete TRX independently. controls=/task/results/descriptor-controls.trx counters=$(grep -E '^[[:space:]]*/dev/null || true; fi } trap cleanup EXIT dotnet vstest "/app/$app.dll" \ --TestCaseFilter:"FullyQualifiedName=$test_class.Repeated_lifecycles_return_resources_to_a_steady_baseline" \ --ResultsDirectory:/task/results '--Logger:trx;LogFileName=late-slope.trx' > /task/test.log 2>&1 & vstest_pid=$! # The canonical startup deadline is 120 seconds. Allow controller startup before observing its first complete row. proof_deadline=$((SECONDS + 150)) observed=0 while ((SECONDS < proof_deadline)) && kill -0 "$vstest_pid" 2>/dev/null; do if [[ -s /task/resources.jsonl ]] && IFS= read -r header < /task/resources.jsonl; then [[ $header == *'"kind":"start"'* && $header == *'"mode":"late-slope"'* ]] pid=$(sed -n 's/.*"processId":\([1-9][0-9]*\),.*/\1/p' <<< "$header") [[ $pid =~ ^[1-9][0-9]*$ ]] executable=$(readlink "/proc/$pid/exe") [[ $executable == "/app/$app" ]] runtime=/app/libcoreclr.so verify_mapped_coreclr "/proc/$pid/maps" "$(stat -c '%i %n' "$runtime")" runtime_hash=$(sha256sum "$runtime") printf 'targetPid=%s\nactualExecutable=%s\nmappedCoreClr=%s\ncoreClrSha256=%s\n' \ "$pid" "$executable" "$runtime" "${runtime_hash%% *}" > /task/target-runtime.txt observed=1 break fi sleep 0.1 done if [[ $observed != 1 ]]; then kill "$vstest_pid" 2>/dev/null || true; fi test_status=0 wait "$vstest_pid" || test_status=$? vstest_pid= printf '%s\n' "$test_status" > /task/test-exit-status.txt if [[ $test_status != 0 ]]; then exit "$test_status"; fi [[ $observed == 1 ]]