diff --git a/.github/workflows/qa-android-critical-flow-tests.yml b/.github/workflows/qa-android-critical-flow-tests.yml index 674889f073..91e469bd7f 100644 --- a/.github/workflows/qa-android-critical-flow-tests.yml +++ b/.github/workflows/qa-android-critical-flow-tests.yml @@ -48,9 +48,6 @@ on: - alpha beta - staging compat - experimental - - column-1 - - column-2 - - column-3 - debug - fdroid - production @@ -243,8 +240,6 @@ jobs: contents: write env: - AWS_REGION: eu-west-1 - OP_VAULT: "Test Automation" FLAVORS_CONFIG_PATH: "/etc/android-qa/flavors.json" DEVICE_GROUPS_JSON: ${{ vars.ANDROID_DEVICE_GROUPS_JSON }} @@ -253,6 +248,10 @@ jobs: shell: bash steps: + - name: Register log masks + run: | + echo "::add-mask::eu-west-1" + - name: Checkout (with submodules) uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: @@ -276,7 +275,7 @@ jobs: run: make qa-ui-setup cmd=ensure-required-tools # Flavor resolution is runner-driven (from /etc/android-qa/flavors.json), not hardcoded in repo. - # This bash subcommand exports S3_FOLDER, APP_ID, and PACKAGES_TO_UNINSTALL for downstream steps. + # Keep app install data job-wide, but pass the S3 folder only to the download step. - name: Resolve flavor (runner config) id: resolve_flavor env: @@ -298,6 +297,7 @@ jobs: IS_UPGRADE: ${{ needs.validate-and-resolve-inputs.outputs.resolvedIsUpgrade }} OLD_BUILD_NUMBER: ${{ needs.validate-and-resolve-inputs.outputs.resolvedOldBuildNumber }} S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + S3_FOLDER: ${{ steps.resolve_flavor.outputs.s3Folder }} run: make qa-ui-setup cmd=download-apks # Select device(s): use input device when provided, otherwise auto-pick. diff --git a/.github/workflows/qa-android-ui-test-manual-deflake.yml b/.github/workflows/qa-android-ui-test-manual-deflake.yml index 08ebdbcba3..7f2e2b7b0e 100644 --- a/.github/workflows/qa-android-ui-test-manual-deflake.yml +++ b/.github/workflows/qa-android-ui-test-manual-deflake.yml @@ -85,8 +85,6 @@ jobs: actions: read env: - AWS_REGION: eu-west-1 - OP_VAULT: "Test Automation" FLAVORS_CONFIG_PATH: "/etc/android-qa/flavors.json" DEVICE_GROUPS_JSON: ${{ vars.ANDROID_DEVICE_GROUPS_JSON }} @@ -95,6 +93,10 @@ jobs: shell: bash steps: + - name: Register log masks + run: | + echo "::add-mask::eu-west-1" + # Mirror qa-android-critical-flow-tests.yml runner setup so manual # deflake executes in the same QA office runner environment. - name: Checkout (with submodules) @@ -181,9 +183,10 @@ jobs: RERUN_FAILED_COUNT: ${{ steps.validate_deflake_input.outputs.rerunFailedCount }} run: make qa-ui-validate cmd=validate-rerun-inputs - # Reuse the same flavor resolver and APK download path so the deflake run - # stays aligned with qa-android-critical-flow-tests.yml app setup. + # Reuse the same flavor resolver and pass its S3 folder output into the APK + # download step so deflake stays aligned with qa-android-critical-flow-tests.yml. - name: Resolve flavor (runner config) + id: resolve_flavor env: FLAVOR_INPUT: ${{ steps.validate_deflake_input.outputs.flavor }} run: make qa-ui-setup cmd=resolve-flavor @@ -202,6 +205,7 @@ jobs: IS_UPGRADE: ${{ steps.validate_deflake_input.outputs.isUpgrade }} OLD_BUILD_NUMBER: ${{ steps.validate_deflake_input.outputs.oldBuildNumber }} S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + S3_FOLDER: ${{ steps.resolve_flavor.outputs.s3Folder }} run: make qa-ui-setup cmd=download-apks # Keep device selection and app installation identical to the selected run diff --git a/scripts/qa/android-ui/resolve_flavor.py b/scripts/qa/android-ui/resolve_flavor.py index 6ca5c037fb..9b62064968 100755 --- a/scripts/qa/android-ui/resolve_flavor.py +++ b/scripts/qa/android-ui/resolve_flavor.py @@ -51,8 +51,16 @@ print("ERROR: GITHUB_ENV not set", file=sys.stderr) sys.exit(1) +output_path = os.environ.get("GITHUB_OUTPUT") +if not output_path: + print("ERROR: GITHUB_OUTPUT not set", file=sys.stderr) + sys.exit(1) + with open(env_path, "a", encoding="utf-8") as handle: - # Export variables used by downstream setup/install workflow steps. - handle.write(f"S3_FOLDER={s3}\n") + # Only keep install-related values job-wide. handle.write(f"APP_ID={app}\n") handle.write("PACKAGES_TO_UNINSTALL=" + " ".join(pkgs) + "\n") + +with open(output_path, "a", encoding="utf-8") as handle: + # Only the download step needs the resolved S3 folder. + handle.write(f"s3Folder={s3}\n") diff --git a/scripts/qa/android-ui/run_ui_tests.sh b/scripts/qa/android-ui/run_ui_tests.sh index 41e1cc01f1..a31e3c2a2c 100755 --- a/scripts/qa/android-ui/run_ui_tests.sh +++ b/scripts/qa/android-ui/run_ui_tests.sh @@ -330,10 +330,26 @@ device_reported_zero_tests() { local log_file="${LOG_DIR}/attempt-${attempt}-instrument-${serial}.log" [[ -f "${log_file}" ]] || return 1 - # Zero-test shards are valid for filtered/sharded runs and should not fail the pull step. + # A device shard can legitimately run zero tests after filtering or sharding. + # In that case it will not produce Allure results, so the pull step should not fail. grep -qE 'INSTRUMENTATION_STATUS: numtests=0|OK \(0 tests\)|No tests found' "${log_file}" } +# Treat a zero-test attempt as valid only when every device log for that +# attempt explicitly reported zero tests. +attempt_reported_zero_tests() { + local attempt="$1" + shift + local devices=("$@") + [[ ${#devices[@]} -gt 0 ]] || return 1 + + for serial in "${devices[@]}"; do + if ! device_reported_zero_tests "${attempt}" "${serial}"; then + return 1 + fi + done +} + pull_allure_results_for_attempt() { local attempt="$1" shift @@ -641,6 +657,21 @@ while true; do extract_failed_ids "${attempt}" "${attempt_failed_file}" "${attempt_executed_file}" executed_count="$(wc -l < "${attempt_executed_file}" | tr -d ' ')" if (( executed_count == 0 )); then + # During reruns, a shard can legitimately end up with no tests assigned. + # Only treat that as valid when every device log explicitly reported + # zero tests and the instrumentation command itself did not fail. + if ! attempt_uses_selector_mode "${attempt}" && attempt_reported_zero_tests "${attempt}" "${attempt_devices[@]}"; then + if (( attempt_worker_failed != 0 )); then + echo "ERROR: Attempt ${attempt} reported zero tests but instrumentation failed." + exit 1 + fi + echo "Attempt ${attempt} executed zero tests across all shards." + if [[ ! -f "${first_failed_file}" ]]; then + cp "${attempt_failed_file}" "${first_failed_file}" + fi + current_failed_file="${attempt_failed_file}" + break + fi echo "ERROR: Attempt ${attempt} produced no identifiable executed tests." exit 1 fi