From 7c94d42117c53eb1eb5b62c71b0939e030dd1280 Mon Sep 17 00:00:00 2001 From: varunj-msft Date: Tue, 1 Sep 2026 02:26:46 +0000 Subject: [PATCH] MAINT Publish the backend log from the shared test jobs The end-to-end tests launch pyrit_backend through ServerLauncher, which writes the server log to a file in the system temp directory and then discards it when the agent is torn down. A failing job therefore reports only the client side of the failure, so a backend that is alive but unresponsive is indistinguishable from one that never started. Collect that log and publish it as a pipeline artifact, following the pattern already used by adversarial-benchmark.yml. The collection step tolerates a missing file so the jobs that do not launch a backend are unaffected, and the publish step is skipped entirely when no log was found. Search every directory tempfile.gettempdir() honours. It reads TMPDIR, TEMP and TMP before falling back to /tmp, so checking only TMPDIR silently dropped the log whenever the agent set one of the other two, which is exactly the diagnostic this change exists to capture. Name the artifact per job attempt. Build.BuildId does not change when a failed job is retried and pipeline artifacts cannot be overwritten, so the retry of any failed job would fail at the publish step. System.JobAttempt keeps each attempt distinct, and continueOnError keeps a failed upload of a diagnostic log from changing the outcome of the test job itself. Report a failed collection separately from a missing log. The step decided whether a log existed by testing the destination, so a copy that failed printed the same line as a job that never launches a backend, which on the end-to-end pipeline is the opposite of what happened. Track whether a source was found, warn with the reason the copy failed, and report the size of what was collected so a zero byte log is not mistaken for a step that did nothing. --- .azuredevops/test-job-template.yml | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/.azuredevops/test-job-template.yml b/.azuredevops/test-job-template.yml index 4de8435de7..99f9f451bf 100644 --- a/.azuredevops/test-job-template.yml +++ b/.azuredevops/test-job-template.yml @@ -129,6 +129,52 @@ jobs: else make ${{ parameters.makeTarget }} fi + - bash: | + set -uo pipefail + artifact_dir="$(Build.ArtifactStagingDirectory)/backend-logs" + mkdir -p "$artifact_dir" + + # ServerLauncher writes the backend log to tempfile.gettempdir(), which honours + # TMPDIR/TEMP/TMP before falling back to /tmp, so check the agent temp directory too. + log_found=false + for candidate in "${TMPDIR:-}" "${TEMP:-}" "${TMP:-}" "${AGENT_TEMPDIRECTORY:-}" /tmp; do + [ -n "$candidate" ] || continue + if [ -f "$candidate/pyrit_backend.log" ]; then + log_found=true + # Only claim success, and only ask for a publish, if the copy actually landed; + # publishing an empty directory would report a log that isn't there. Report the + # size too, because a zero byte log is a real outcome and an empty artifact + # otherwise looks like this step failed. + if cp_error=$(cp "$candidate/pyrit_backend.log" "$artifact_dir/pyrit_backend.log" 2>&1); then + log_bytes=$(wc -c <"$artifact_dir/pyrit_backend.log") + echo "Collected backend log from $candidate ($log_bytes bytes)" + echo "##vso[task.setvariable variable=backendLogFound]true" + else + echo "##vso[task.logissue type=warning]Found pyrit_backend.log in $candidate but failed to copy it: $cp_error" + fi + break + fi + done + + # Distinguish the two outcomes: a job that never launches a backend is expected to have + # no log, whereas a log that was found but could not be collected is a real problem. + if [ "${log_found:-false}" = false ]; then + echo "No pyrit_backend.log found; this job did not launch a backend." + fi + displayName: "Collect pyrit_backend log" + name: collect_backend_log + condition: always() + - task: PublishPipelineArtifact@1 + displayName: "Publish pyrit_backend log" + condition: and(always(), eq(variables['backendLogFound'], 'true')) + # Publishing a diagnostic log must never change the outcome of the test job. + continueOnError: true + inputs: + targetPath: $(Build.ArtifactStagingDirectory)/backend-logs + # BuildId stays the same when a failed job is retried, and pipeline artifacts cannot be + # overwritten, so JobAttempt is needed to keep each attempt's artifact name unique. + artifactName: backend-logs-${{ parameters.jobName }}-$(Build.BuildId)-attempt-$(System.JobAttempt) + publishLocation: pipeline - bash: | rm -f ~/.pyrit/.env ~/.pyrit/.env.local name: clean_up_env_files