From c5d48d1c68bfd525ff5df879ad918a73e19ca2ef Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Fri, 13 Dec 2024 17:27:11 -0800 Subject: [PATCH 01/46] Break out test targets into a separate config b/354062546 --- .github/config/android-arm.json | 23 ++++++++++++--------- .github/config/android-arm64.json | 23 ++++++++++++--------- .github/config/android-x86.json | 22 +++++++++++--------- .github/config/chromium_android-arm.json | 22 +++++++++++--------- .github/config/chromium_android-arm64.json | 22 +++++++++++--------- .github/config/chromium_android-x86.json | 22 +++++++++++--------- .github/config/chromium_linux.json | 24 ++++++++++++---------- .github/config/linux.json | 22 +++++++++++--------- .github/workflows/main.yaml | 13 +++++++++--- docker-compose.yaml | 4 ++-- 10 files changed, 111 insertions(+), 86 deletions(-) diff --git a/.github/config/android-arm.json b/.github/config/android-arm.json index 0ece3896deb1..e8be887ccd2a 100644 --- a/.github/config/android-arm.json +++ b/.github/config/android-arm.json @@ -4,21 +4,24 @@ "android-arm" ], "targets": [ - "base_unittests", - "sql_unittests", - "net_unittests", - "url_unittests", - "ipc_tests", - "mojo_unittests", - "gpu_unittests", - "gin_unittests", - "blink_unittests", - "media_unittests", "content_shell", "system_webview_apk", "system_webview_shell_apk", "cobalt:gn_all" ], + "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", + "url_unittests" + ], + "test_on_device": true, "includes": [ { "name":"arm", diff --git a/.github/config/android-arm64.json b/.github/config/android-arm64.json index 1b34e70b8975..e90a3d101158 100644 --- a/.github/config/android-arm64.json +++ b/.github/config/android-arm64.json @@ -4,21 +4,24 @@ "android-arm64" ], "targets": [ - "base_unittests", - "sql_unittests", - "net_unittests", - "url_unittests", - "ipc_tests", - "mojo_unittests", - "gpu_unittests", - "gin_unittests", - "blink_unittests", - "media_unittests", "content_shell", "system_webview_apk", "system_webview_shell_apk", "cobalt:gn_all" ], + "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", + "url_unittests" + ], + "test_on_device": true, "includes": [ { "name":"arm64", diff --git a/.github/config/android-x86.json b/.github/config/android-x86.json index 262d0cfc8c44..a96814f41ba4 100644 --- a/.github/config/android-x86.json +++ b/.github/config/android-x86.json @@ -4,21 +4,23 @@ "android-x86" ], "targets": [ - "base_unittests", - "sql_unittests", - "net_unittests", - "url_unittests", - "ipc_tests", - "mojo_unittests", - "gpu_unittests", - "gin_unittests", - "blink_unittests", - "media_unittests", "content_shell", "system_webview_apk", "system_webview_shell_apk", "cobalt:gn_all" ], + "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", + "url_unittests" + ], "includes": [ { "name":"x86", diff --git a/.github/config/chromium_android-arm.json b/.github/config/chromium_android-arm.json index 9eac89f0b668..52a8e509c1d1 100644 --- a/.github/config/chromium_android-arm.json +++ b/.github/config/chromium_android-arm.json @@ -4,20 +4,22 @@ "chromium_android-arm" ], "targets": [ - "base_unittests", - "sql_unittests", - "net_unittests", - "url_unittests", - "ipc_tests", - "mojo_unittests", - "gpu_unittests", - "gin_unittests", - "blink_unittests", - "media_unittests", "content_shell", "system_webview_apk", "system_webview_shell_apk" ], + "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", + "url_unittests" + ], "includes": [ { "name":"arm", diff --git a/.github/config/chromium_android-arm64.json b/.github/config/chromium_android-arm64.json index 1aea4037d668..77a3541cadb1 100644 --- a/.github/config/chromium_android-arm64.json +++ b/.github/config/chromium_android-arm64.json @@ -4,20 +4,22 @@ "chromium_android-arm64" ], "targets": [ - "base_unittests", - "sql_unittests", - "net_unittests", - "url_unittests", - "ipc_tests", - "mojo_unittests", - "gpu_unittests", - "gin_unittests", - "blink_unittests", - "media_unittests", "content_shell", "system_webview_apk", "system_webview_shell_apk" ], + "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", + "url_unittests" + ], "includes": [ { "name":"arm64", diff --git a/.github/config/chromium_android-x86.json b/.github/config/chromium_android-x86.json index c97a39f99ec8..68a5ecab872a 100644 --- a/.github/config/chromium_android-x86.json +++ b/.github/config/chromium_android-x86.json @@ -4,20 +4,22 @@ "chromium_android-x86" ], "targets": [ - "base_unittests", - "sql_unittests", - "net_unittests", - "url_unittests", - "ipc_tests", - "mojo_unittests", - "gpu_unittests", - "gin_unittests", - "blink_unittests", - "media_unittests", "content_shell", "system_webview_apk", "system_webview_shell_apk" ], + "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", + "url_unittests" + ], "includes": [ { "name":"x86", diff --git a/.github/config/chromium_linux.json b/.github/config/chromium_linux.json index 01114cd966a6..3357d29ed02c 100644 --- a/.github/config/chromium_linux.json +++ b/.github/config/chromium_linux.json @@ -4,17 +4,19 @@ "chromium_linux-x64x11" ], "targets": [ - "base_unittests", - "sql_unittests", - "net_unittests", - "url_unittests", - "ipc_tests", - "mojo_unittests", - "gpu_unittests", - "gin_unittests", - "blink_unittests", - "media_unittests", - "content_shell" + "content_shell" + ], + "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", + "url_unittests" ], "includes": [ { diff --git a/.github/config/linux.json b/.github/config/linux.json index a6259f06bdde..f1b030aec179 100644 --- a/.github/config/linux.json +++ b/.github/config/linux.json @@ -6,16 +6,18 @@ "linux-x64x11" ], "targets": [ - "base_unittests", - "cobalt:gn_all", - "content_shell", - "gin_unittests", - "gpu_unittests", - "ipc_tests", - "media_unittests", - "mojo_unittests", - "sql_unittests", - "url_unittests" + "content_shell", + "cobalt:gn_all" + ], + "gtest_targets": [ + "base_unittests", + "ipc_tests", + "gin_unittests", + "gpu_unittests", + "media_unittests", + "mojo_unittests", + "sql_unittests", + "url_unittests" ], "includes": [ { diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 9f3cf8e1125f..ec95fd422b10 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -65,6 +65,11 @@ jobs: run: | targets=$(cat ${GITHUB_WORKSPACE}/.github/config/${{ inputs.platform }}.json | jq -c '.targets | join(" ")') echo "targets=${targets}" >> $GITHUB_ENV + - id: set-test-targets + shell: bash + run: | + gtest_targets=$(cat ${GITHUB_WORKSPACE}/.github/config/${{ inputs.platform }}.json | jq -c '.gtest_targets | join(" ")') + echo "gtest_targets=${gtest_targets}" >> $GITHUB_ENV - id: set-includes shell: bash run: | @@ -98,6 +103,7 @@ jobs: outputs: platforms: ${{ env.platforms }} targets: ${{ env.targets }} + gtest_targets: ${{ env.gtest_targets }} includes: ${{ env.includes }} docker_service: ${{ env.docker_service }} num_gtest_shards: ${{ env.num_gtest_shards }} @@ -178,9 +184,10 @@ jobs: # TODO(bug?): android debug builds are broken. if: ${{ ! (contains(matrix.platform, 'android') && matrix.config == 'debug') }} with: - targets: ${{ needs.initialize.outputs.targets }} - - name: Upload Test Artifacts - if: matrix.config == 'devel' + targets: ${{ needs.initialize.outputs.targets }} ${{ needs.initialize.outputs.gtest_targets }} + test_artifacts_key: ${{ env.TEST_ARTIFACTS_KEY }} + - name: Upload On Device Test Artifacts + if: matrix.config == 'devel' && needs.initialize.outputs.test_on_device == 'true' uses: ./src/.github/actions/upload_test_artifacts with: test_artifacts_key: ${{ env.TEST_ARTIFACTS_KEY }} diff --git a/docker-compose.yaml b/docker-compose.yaml index 656d567a5ec3..1bd9a0de3d13 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,8 +4,8 @@ services: build: context: cobalt/docker/linux cache_from: - - ghcr.io/youtube/cobalt/linux:latest - image: ghcr.io/youtube/cobalt/linux:latest + - ghcr.io/youtube/cobalt_sandbox/linux:latest + image: ghcr.io/youtube/cobalt_sandbox/linux:latest platform: linux/amd64 environment: - DEPOT_TOOLS_UPDATE=0 From ac2684b1243012e5c69ff4be4baa2f768c89ab52 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Wed, 18 Dec 2024 21:59:46 -0800 Subject: [PATCH 02/46] Chrobalt on-device test work for Android b/354062546 --- .github/actions/on_device_tests/action.yaml | 156 +++++++++++++++++++- .github/config/android-arm.json | 2 + .github/workflows/main.yaml | 41 ++++- 3 files changed, 190 insertions(+), 9 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index df6b4bf39d62..2d8b8c42a02f 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -1,9 +1,157 @@ -name: On Host Tests -description: Runs on-host tests. +name: On Device Test +description: Runs on-device tests. + runs: using: "composite" steps: - - name: Run On-Device Tests + - name: Install Requirements + run: | + pip3 install grpcio==1.38.0 grpcio-tools==1.38.0 + shell: bash + - name: Generate gRPC files + run: | + python -m grpc_tools.protoc -Itools/ --python_out=tools/ --grpc_python_out=tools/ tools/on_device_tests_gateway.proto + shell: bash + - name: Set Up Cloud SDK + uses: isarkis/setup-gcloud@40dce7857b354839efac498d3632050f568090b6 # v1.1.1 + - name: Set env vars + run: | + echo "PROJECT_NAME=$(gcloud config get-value project)" >> $GITHUB_ENV + + # Test results and logs + echo "GCS_RESULTS_PATH=gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }}" >> $GITHUB_ENV + + # Dimension env + if [ "${{ matrix.dimension }}" != "null" ]; then + echo "DIMENSION=${{ matrix.dimension }}" >> $GITHUB_ENV + fi + + echo "TEST_TYPE=unit_test" >> $GITHUB_ENV shell: bash + - name: Run ${{ env.SHARD_NAME }} Tests on ${{ matrix.platform }} Platform + env: + GCS_PATH: gs://${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} + GITHUB_SHA: ${{ github.sha }} + GITHUB_TOKEN: ${{ github.token }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TRIGGERING_ACTOR: ${{ github.triggering_actor }} + GITHUB_ACTOR_ID: ${{ github.actor_id }} + GITHUB_REPO: ${{ github.repository }} + GITHUB_PR_HEAD_USER_LOGIN: ${{ github.event.pull_request.head.user.login }} + GITHUB_PR_HEAD_USER_ID: ${{ github.event.pull_request.head.user.id }} + GITHUB_COMMIT_AUTHOR_USERNAME: ${{ github.event.commits[0].author.username }} + GITHUB_COMMIT_AUTHOR_EMAIL: ${{ github.event.commits[0].author.email }} + GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_RUN_NUMBER: ${{ github.run_number }} + GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_WORKFLOW: ${{ github.workflow }} run: | - echo "Nothing yet" + set -uxe + python3 -u tools/on_device_tests_gateway_client.py \ + --github_workspace ${GITHUB_WORKSPACE} \ + --token ${GITHUB_TOKEN} \ + --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ + trigger \ + --test_type ${TEST_TYPE} \ + --platform ${{ matrix.target_platform }} \ + --config ${{ matrix.config }} \ + --tag cobalt_github_${GITHUB_EVENT_NAME} \ + --builder_name github_${{ matrix.platform }}_tests \ + --build_number ${GITHUB_RUN_NUMBER} \ + --builder_url ${GITHUB_RUN_URL} \ + ${LOADER_PLATFORM:+"--loader_config" "$LOADER_CONFIG"} \ + ${LOADER_PLATFORM:+"--loader_platform" "$LOADER_PLATFORM"} \ + ${DIMENSION:+"--dimension" "$DIMENSION"} \ + ${USE_SHARDING:+"--unittest_shard_index" "${{ matrix.shard }}"} \ + ${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" "$ON_DEVICE_TEST_ATTEMPTS"} \ + --archive_path "${GCS_PATH}/artifacts.tar" \ + --gcs_result_path "${GCS_RESULTS_PATH}" \ + --label github \ + --label ${GITHUB_EVENT_NAME} \ + --label ${GITHUB_WORKFLOW} \ + --label actor-${GITHUB_ACTOR} \ + --label actor_id-${GITHUB_ACTOR_ID} \ + --label triggering_actor-${GITHUB_TRIGGERING_ACTOR} \ + --label sha-${GITHUB_SHA} \ + --label repository-${GITHUB_REPO} \ + --label author-${GITHUB_PR_HEAD_USER_LOGIN:-$GITHUB_COMMIT_AUTHOR_USERNAME} \ + --label author_id-${GITHUB_PR_HEAD_USER_ID:-$GITHUB_COMMIT_AUTHOR_EMAIL} + shell: bash + - name: Download ${{ matrix.platform }} Test Results + if: always() && env.TEST_TYPE == 'unit_test' + run: | + # Don't break on error (-e), some commands are expected to fail. + set -ux + + COBALT_LOGS_DIR="${GITHUB_WORKSPACE}/cobalt_logs" + UNIT_TEST_RESULT_PATH="${GITHUB_WORKSPACE}/unit-test-results" + COBALT_XMLS_FILENAME="cobalt_xmls.zip" + + # Forward environment variables for uploading artifacts in later steps. + echo "UNIT_TEST_RESULT_PATH=${UNIT_TEST_RESULT_PATH}" >> $GITHUB_ENV + echo "COBALT_LOGS_DIR=${COBALT_LOGS_DIR}" >> $GITHUB_ENV + + mkdir -p "${GITHUB_WORKSPACE}/test_results" + cd "${GITHUB_WORKSPACE}/test_results" + + i=0 + # Try downloading the results for 6x 10 seconds before giving up. + while [ $i -lt 6 ]; do + # The results are uploaded after the test has completed. + sleep 10 + + # The log files are named by the device lab test driver. + COBALT_ERROR_LOG_FILENAME="webDriverTestLog.ERROR" + COBALT_INFO_LOG_FILENAME="webDriverTestLog.INFO" + + # This command will fail until the results have been uploaded. + gsutil cp "${GCS_RESULTS_PATH}/${COBALT_ERROR_LOG_FILENAME}" . + gsutil cp "${GCS_RESULTS_PATH}/${COBALT_INFO_LOG_FILENAME}" . + gsutil cp "${GCS_RESULTS_PATH}/${COBALT_XMLS_FILENAME}" . + + # Break if all files were downloaded. + if [[ -f "${COBALT_XMLS_FILENAME}" && -f "${COBALT_ERROR_LOG_FILENAME}" && -f "${COBALT_INFO_LOG_FILENAME}" ]]; then + break + fi + + i=$(( ${i} + 1 )) + done + + # Rename log files for archiving to not expose legacy weirdness. + mkdir -p "${COBALT_LOGS_DIR}/${{ matrix.platform }}/" + cp "${COBALT_ERROR_LOG_FILENAME}" "${COBALT_LOGS_DIR}/${{ matrix.platform }}/stderr_${{ matrix.shard }}.log" + cp "${COBALT_INFO_LOG_FILENAME}" "${COBALT_LOGS_DIR}/${{ matrix.platform }}/stdout_${{ matrix.shard }}.log" + + # Prepare unit test results for DataDog upload. + RESULT_PATH=${UNIT_TEST_RESULT_PATH}/${{ matrix.platform }}/${{ matrix.shard }}/ + mkdir -p ${RESULT_PATH} + + # Set tags for test differentiation. + tags="os.platform:${{ matrix.platform }}" + echo $tags > ${UNIT_TEST_RESULT_PATH}/${{ matrix.platform }}/TAGS + + unzip ${COBALT_XMLS_FILENAME} -d ${RESULT_PATH} + shell: bash + - name: Archive Unit Test Logs + uses: actions/upload-artifact@v3 + if: always() && env.TEST_TYPE == 'unit_test' + with: + name: Device logs + path: ${{ env.COBALT_LOGS_DIR }}/ + - name: Archive Unit Test Results + uses: actions/upload-artifact@v3 + if: always() && env.TEST_TYPE == 'unit_test' + with: + name: unit-test-results + path: ${{ env.UNIT_TEST_RESULT_PATH }}/ + - name: Print device logs + if: always() + run: | + if ls ${COBALT_LOGS_DIR}/**/*.log 1> /dev/null 2>&1; then + cat ${COBALT_LOGS_DIR}/**/*.log + else + echo "No device logs found" + fi + shell: bash diff --git a/.github/config/android-arm.json b/.github/config/android-arm.json index e8be887ccd2a..684725c6f75e 100644 --- a/.github/config/android-arm.json +++ b/.github/config/android-arm.json @@ -21,6 +21,8 @@ "sql_unittests", "url_unittests" ], + "gtest_device": "sabrina", + "gtest_lab": "maneki", "test_on_device": true, "includes": [ { diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index ec95fd422b10..35c85676f956 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -194,9 +194,9 @@ jobs: on_host: ${{ needs.initialize.outputs.test_on_host }} on_device: ${{ needs.initialize.outputs.test_on_device }} - test: + on-host-test: needs: [initialize, docker-build-image, build] - if: needs.initialize.outputs.test_on_host == 'true' || needs.initialize.outputs.test_on_device == 'true' + if: needs.initialize.outputs.test_on_host == 'true' permissions: {} # TODO(b/372303096): Should have dedicated runner? runs-on: [self-hosted, chrobalt-linux-runner] @@ -260,12 +260,12 @@ jobs: datadog_api_key: ${{ secrets.datadog_api_key }} continue-on-error: true + validate-test-result: - needs: [initialize, docker-build-image, build, test] + needs: [initialize, docker-build-image, build, on-host-test] if: always() && ( - needs.initialize.outputs.test_on_host == 'true' || - needs.initialize.outputs.test_on_device == 'true' + needs.initialize.outputs.test_on_host == 'true' ) permissions: {} runs-on: ubuntu-latest @@ -281,3 +281,34 @@ jobs: run: | echo "Failing because at least one test shard had errors." exit 1 + + # Runs on-device integration and unit tests. + on-device-test: + needs: [initialize, build] + # Run ODT when on_device label is applied on PR. + # Also, run ODT on push and schedule if not explicitly disabled via repo vars. + if: | + needs.initialize.outputs.test_on_device == 'true' && (( + github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( + inputs.nightly == 'true' || github.event_name == 'schedule') && + vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || + ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' ) ) + runs-on: [self-hosted, odt-runner] + name: ${{ matrix.name }}_on_device + permissions: {} + strategy: + fail-fast: false + matrix: + platform: ${{ fromJson(needs.initialize.outputs.platforms) }} + config: [devel] + include: ${{ fromJson(needs.initialize.outputs.includes) }} + steps: + - name: Checkout + uses: kaidokert/checkout@v3.5.999 + timeout-minutes: 30 + with: + fetch-depth: 1 + persist-credentials: false + - name: Run Tests (${{ matrix.shard }}) + uses: ./.github/actions/on_device_tests From 39eb4946ea50cef42bf9dac6fbc10bb0f44f0941 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Thu, 19 Dec 2024 14:30:59 -0800 Subject: [PATCH 03/46] Update params passed to ODT gateway --- .github/actions/on_device_tests/action.yaml | 44 ++------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 2d8b8c42a02f..b03c0772535c 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -25,59 +25,21 @@ runs: if [ "${{ matrix.dimension }}" != "null" ]; then echo "DIMENSION=${{ matrix.dimension }}" >> $GITHUB_ENV fi - - echo "TEST_TYPE=unit_test" >> $GITHUB_ENV shell: bash - name: Run ${{ env.SHARD_NAME }} Tests on ${{ matrix.platform }} Platform env: GCS_PATH: gs://${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} - GITHUB_SHA: ${{ github.sha }} - GITHUB_TOKEN: ${{ github.token }} - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - GITHUB_EVENT_NAME: ${{ github.event_name }} - GITHUB_ACTOR: ${{ github.actor }} - GITHUB_TRIGGERING_ACTOR: ${{ github.triggering_actor }} - GITHUB_ACTOR_ID: ${{ github.actor_id }} - GITHUB_REPO: ${{ github.repository }} - GITHUB_PR_HEAD_USER_LOGIN: ${{ github.event.pull_request.head.user.login }} - GITHUB_PR_HEAD_USER_ID: ${{ github.event.pull_request.head.user.id }} - GITHUB_COMMIT_AUTHOR_USERNAME: ${{ github.event.commits[0].author.username }} - GITHUB_COMMIT_AUTHOR_EMAIL: ${{ github.event.commits[0].author.email }} - GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} - GITHUB_RUN_NUMBER: ${{ github.run_number }} - GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GITHUB_WORKFLOW: ${{ github.workflow }} run: | set -uxe python3 -u tools/on_device_tests_gateway_client.py \ - --github_workspace ${GITHUB_WORKSPACE} \ + --platform_json "${GITHUB_WORKSPACE}/src/.github/config/${{ matrix.platform}}.json" \ + --filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/${{ matrix.platform}}" \ --token ${GITHUB_TOKEN} \ - --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ - trigger \ - --test_type ${TEST_TYPE} \ - --platform ${{ matrix.target_platform }} \ - --config ${{ matrix.config }} \ - --tag cobalt_github_${GITHUB_EVENT_NAME} \ - --builder_name github_${{ matrix.platform }}_tests \ - --build_number ${GITHUB_RUN_NUMBER} \ - --builder_url ${GITHUB_RUN_URL} \ - ${LOADER_PLATFORM:+"--loader_config" "$LOADER_CONFIG"} \ - ${LOADER_PLATFORM:+"--loader_platform" "$LOADER_PLATFORM"} \ ${DIMENSION:+"--dimension" "$DIMENSION"} \ - ${USE_SHARDING:+"--unittest_shard_index" "${{ matrix.shard }}"} \ ${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" "$ON_DEVICE_TEST_ATTEMPTS"} \ --archive_path "${GCS_PATH}/artifacts.tar" \ --gcs_result_path "${GCS_RESULTS_PATH}" \ - --label github \ - --label ${GITHUB_EVENT_NAME} \ - --label ${GITHUB_WORKFLOW} \ - --label actor-${GITHUB_ACTOR} \ - --label actor_id-${GITHUB_ACTOR_ID} \ - --label triggering_actor-${GITHUB_TRIGGERING_ACTOR} \ - --label sha-${GITHUB_SHA} \ - --label repository-${GITHUB_REPO} \ - --label author-${GITHUB_PR_HEAD_USER_LOGIN:-$GITHUB_COMMIT_AUTHOR_USERNAME} \ - --label author_id-${GITHUB_PR_HEAD_USER_ID:-$GITHUB_COMMIT_AUTHOR_EMAIL} + trigger \ shell: bash - name: Download ${{ matrix.platform }} Test Results if: always() && env.TEST_TYPE == 'unit_test' From 8ff567b035c713152f49bd6505d42a7e4c280456 Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Fri, 20 Dec 2024 23:36:40 +0000 Subject: [PATCH 04/46] ODT Client code --- .../android-arm/base_unittests_filter.json | 10 + tools/on_device_tests_gateway.proto | 81 ++++ tools/on_device_tests_gateway_client.py | 305 ++++++++++++ tools/on_device_tests_gateway_pb2.py | 437 ++++++++++++++++++ tools/on_device_tests_gateway_pb2_grpc.py | 64 +++ 5 files changed, 897 insertions(+) create mode 100644 cobalt/testing/android-arm/base_unittests_filter.json create mode 100644 tools/on_device_tests_gateway.proto create mode 100644 tools/on_device_tests_gateway_client.py create mode 100644 tools/on_device_tests_gateway_pb2.py create mode 100644 tools/on_device_tests_gateway_pb2_grpc.py diff --git a/cobalt/testing/android-arm/base_unittests_filter.json b/cobalt/testing/android-arm/base_unittests_filter.json new file mode 100644 index 000000000000..bb161c725dc4 --- /dev/null +++ b/cobalt/testing/android-arm/base_unittests_filter.json @@ -0,0 +1,10 @@ +{ + "failing_tests": [ + "BreakIteratorTest.BreakCharacter", + "ValuesUtilTest.FilePath" + ], + "passing_tests": [ + "test1", + "test2" + ] +} diff --git a/tools/on_device_tests_gateway.proto b/tools/on_device_tests_gateway.proto new file mode 100644 index 000000000000..50cc02d478f7 --- /dev/null +++ b/tools/on_device_tests_gateway.proto @@ -0,0 +1,81 @@ +// Copyright 2022 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package on_device_tests_gateway; + +// Interface exported by the server. +service on_device_tests_gateway { + // A dumb proxy RPC service that passes user defined command line options + // to the on-device tests gateway and streams back output in real time. + rpc exec_command (OnDeviceTestsCommand) returns (stream OnDeviceTestsResponse) { + } + + rpc exec_watch_command (OnDeviceTestsWatchCommand) returns (stream OnDeviceTestsResponse) { + } +} + +// Working directory and command line arguments to be passed to the gateway. +message OnDeviceTestsCommand { + // Next ID: 23 + string workdir = 1; + string token = 2; + string test_type = 3; + string platform = 4; + string archive_path = 5; + string config = 6; + string tag = 7; + repeated string labels = 8; + string builder_name = 9; + string change_id = 10; + string build_number = 11; + string loader_platform = 12; + string loader_config = 13; + string version = 14; + bool dry_run = 15; + repeated string dimension = 16; + string unittest_shard_index = 17; + string test_attempts = 18; + string retry_level = 19; + string start_timeout = 20; + string test_timeout = 21; + string builder_url = 22; + string gcs_result_path = 23; + repeated ApkTest apk_tests = 24; +} + +message ApkTest { + string test_target = 1; + string apk_path = 2; + string device_model = 3; + string device_pool = 4; + string gtest_filters = 5; +} + +// Working directory and command line arguments to be passed to the gateway. +message OnDeviceTestsWatchCommand { + // Next ID: 6 + string workdir = 1; + string token = 2; + string session_id = 3; + string change_id = 4; + bool dry_run = 5; +} + +// Response from the on-device tests. +message OnDeviceTestsResponse { + // Next ID: 2 + string response = 1; +} diff --git a/tools/on_device_tests_gateway_client.py b/tools/on_device_tests_gateway_client.py new file mode 100644 index 000000000000..99cdbb5f7166 --- /dev/null +++ b/tools/on_device_tests_gateway_client.py @@ -0,0 +1,305 @@ +#!/usr/bin/env python3 +# +# Copyright 2022 The Cobalt Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""gRPC On-device Tests Gateway client.""" + +import argparse +import logging +import sys +import os +import json + +import grpc + +import on_device_tests_gateway_pb2 +import on_device_tests_gateway_pb2_grpc + +# All tests On-Device tests support +_TEST_TYPES = [ + 'black_box_test', + 'evergreen_test', + 'unit_test', +] + +# All test configs On-Device tests support +_TEST_CONFIGS = [ + 'devel', + 'staging', + 'production', +] + +_WORK_DIR = '/on_device_tests_gateway' +_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( + #'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') + 'localhost') +#_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' +_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '12345' + + +class OnDeviceTestsGatewayClient(): + """On-device tests Gateway Client class.""" + + def __init__(self): + self.channel = grpc.insecure_channel( + target=f'{_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST}:{_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT}', # pylint:disable=line-too-long + # These options need to match server settings. + options=[('grpc.keepalive_time_ms', 10000), + ('grpc.keepalive_timeout_ms', 5000), + ('grpc.keepalive_permit_without_calls', 1), + ('grpc.http2.max_pings_without_data', 0), + ('grpc.http2.min_time_between_pings_ms', 10000), + ('grpc.http2.min_ping_interval_without_data_ms', 5000)]) + self.stub = on_device_tests_gateway_pb2_grpc.on_device_tests_gatewayStub( + self.channel) + + def run_trigger_command(self, workdir: str, args: argparse.Namespace, apk_tests = None): + """Calls On-Device Tests service and passing given parameters to it. + + Args: + workdir (str): Current script workdir. + args (Namespace): Arguments passed in command line. + """ + for response_line in self.stub.exec_command( + on_device_tests_gateway_pb2.OnDeviceTestsCommand( + workdir=workdir, + token=args.token, + #test_type=args.test_type, + platform=args.platform, + archive_path=args.archive_path, + #config=args.config, + #tag=args.tag, + labels=args.label, + gcs_result_path=args.gcs_result_path, + #builder_name=args.builder_name, + #builder_url=args.builder_url, + change_id=args.change_id, + #build_number=args.build_number, + #loader_platform=args.loader_platform, + #loader_config=args.loader_config, + #version=args.version, + dry_run=args.dry_run, + dimension=args.dimension or [], + #unittest_shard_index=args.unittest_shard_index, + test_attempts=args.test_attempts, + retry_level=args.retry_level, + apk_tests=apk_tests, + )): + + print(response_line.response) + + def run_watch_command(self, workdir: str, args: argparse.Namespace): + """Calls On-Device Tests watch service and passing given parameters to it. + + Args: + workdir (str): Current script workdir. + args (Namespace): Arguments passed in command line. + """ + for response_line in self.stub.exec_watch_command( + on_device_tests_gateway_pb2.OnDeviceTestsWatchCommand( + workdir=workdir, + token=args.token, + change_id=args.change_id, + session_id=args.session_id, + )): + + print(response_line.response) + +def _read_json_config(filename): + """ + Reads and parses data from a JSON configuration file. + + Args: + filename: The name of the JSON configuration file. + + Returns: + A list of dictionaries, where each dictionary represents a test configuration. + """ + try: + with open(filename, 'r') as f: + data = json.load(f) + return data + except FileNotFoundError: + #print(f" Config file '{filename}' not found.") + return None + except json.JSONDecodeError: + #print(f" Invalid JSON format in '{filename}'.") + return None + +def _default_platform_json_file(platform): + current_dir = os.path.dirname(os.path.abspath(__file__)) + relative_path = os.path.join("..", ".github", "config", platform + ".json") + return os.path.join(current_dir, relative_path) + +def _get_tests_filter_json_file(platform, gtest_target): + current_dir = os.path.dirname(os.path.abspath(__file__)) + relative_path = os.path.join("..", "cobalt", "testing", platform, gtest_target + "_filter.json") + return os.path.join(current_dir, relative_path) + +def _process_apk_tests(args): + apk_tests = [] + platform_json_file = args.platform_json if args.platform_json else _default_platform_json_file(args.platform) + #print(' The platform_json_file is ' + platform_json_file) + platform_json_file_data = _read_json_config(platform_json_file) + gtest_device = platform_json_file_data["gtest_device"] + gtest_lab = platform_json_file_data["gtest_lab"] + gtest_blaze_target = "//experimental/cobalt/chrobalt_poc:custom_chrobalt_unit_tests_" + gtest_device + default_gtest_filters = "GURL*" + + #print(' processing gtest_targets in json file') + for gtest_target in platform_json_file_data["gtest_targets"]: + apk_test = { + "test_target": gtest_blaze_target, + "device_model": gtest_device, + "device_pool": gtest_lab + } + print(f" gtest_target: {gtest_target}") + gtest_filter_json_file = _get_tests_filter_json_file(args.platform, gtest_target) + print(f" gtest_filter_json_file = {gtest_filter_json_file}") + gtest_filter_json_file_data = _read_json_config(gtest_filter_json_file) + gtest_filters = default_gtest_filters + if gtest_filter_json_file_data is None: + print(" This gtest_target does not have gtest_filters_specified"); + else: + failing_tests_list = gtest_filter_json_file_data["failing_tests"] + passing_tests_list = gtest_filter_json_file_data["passing_tests"] + #print(f" failing tests in json: {failing_tests_list}") + #print(f" passing tests in json: {passing_tests_list}") + failing_tests_string = ":".join(failing_tests_list) + passing_tests_string = ":".join(passing_tests_list) + #print(f" failing_tests_string = '{failing_tests_string}'") + #print(f" passing_tests_string = '{passing_tests_string}'") + if passing_tests_string: + gtest_filters += ":" + passing_tests_string + if failing_tests_string: + gtest_filters += ":-" + failing_tests_string + #print(f" gtest_filters = {gtest_filters}"); + apk_test["apk_path"] = "/bigstore/yt-temp/" + gtest_target + "-debug.apk" + apk_test["gtest_filters"] = gtest_filters + apk_tests.append(apk_test) + + print(f" apk_tests: {apk_tests}") + return apk_tests + +def main(): + """Main routine.""" + print('Starting main routine') + + logging.basicConfig( + level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s') + + parser = argparse.ArgumentParser( + epilog=('Example: ./on_device_tests_gateway_client.py ' + '--test_type=unit_test ' + '--remote_archive_path=gs://my_bucket/path/to/artifacts.tar ' + '--platform=raspi-2 ' + '--config=devel'), + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + '-t', + '--token', + type=str, + required=True, + help='On Device Tests authentication token') + parser.add_argument( + '--dry_run', + action='store_true', + help='Specifies to show what would be done without actually doing it.') + parser.add_argument( + '-i', + '--change_id', + type=str, + help='ChangeId that triggered this test, if any. ' + 'Saved with performance test results.') + + subparsers = parser.add_subparsers( + dest='action', help='On-Device tests commands', required=True) + trigger_parser = subparsers.add_parser( + 'trigger', help='Trigger On-Device tests') + + trigger_parser.add_argument( + '-p', + '--platform', + type=str, + required=True, + help='Platform this test was built for.') + trigger_parser.add_argument( + '-pf', + '--platform_json', + type=str, + help='Platform-specific json file containing the list of target tests.') + trigger_parser.add_argument( + '-a', + '--archive_path', + type=str, + required=True, + help='Path to Chrobalt archive to be tested. Must be on gcs.') + trigger_parser.add_argument( + '-l', + '--label', + type=str, + default=[], + action='append', + help='Additional labels to assign to the test.') + trigger_parser.add_argument( + '--gcs_result_path', + type=str, + help='GCS url where test result files should be uploaded.') + trigger_parser.add_argument( + '--dimension', + type=str, + action='append', + help='On-Device Tests dimension used to select a device. ' + 'Must have the following form: =.' + ' E.G. "release_version=regex:10.*') + trigger_parser.add_argument( + '--test_attempts', + type=str, + default='1', + required=False, + help='The maximum number of times a test could retry.') + trigger_parser.add_argument( + '--retry_level', + type=str, + default='ERROR', + required=False, + help='The retry level of Mobile harness job. Either ERROR (to retry for ' + 'MH errors) or FAIL (to retry for failing tests). Setting retry_level to ' + 'FAIL will also retry for MH errors.') + + watch_parser = subparsers.add_parser('watch', help='Trigger On-Device tests') + watch_parser.add_argument( + 'session_id', + type=str, + help='Session id of a previously triggered mobile ' + 'harness test. If passed, the test will not be ' + 'triggered, but will be watched until the exit ' + 'status is reached.') + + args = parser.parse_args() + apk_tests = _process_apk_tests(args) + + client = OnDeviceTestsGatewayClient() + try: + if args.action == 'trigger': + client.run_trigger_command(workdir=_WORK_DIR, args=args, apk_tests=apk_tests) + else: + client.run_watch_command(workdir=_WORK_DIR, args=args) + except grpc.RpcError as e: + print(e) + return e.code().value + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/on_device_tests_gateway_pb2.py b/tools/on_device_tests_gateway_pb2.py new file mode 100644 index 000000000000..f6c8947b850f --- /dev/null +++ b/tools/on_device_tests_gateway_pb2.py @@ -0,0 +1,437 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: on_device_tests_gateway.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='on_device_tests_gateway.proto', + package='on_device_tests_gateway', + syntax='proto3', + serialized_pb=_b('\n\x1don_device_tests_gateway.proto\x12\x17on_device_tests_gateway\"\x9c\x04\n\x14OnDeviceTestsCommand\x12\x0f\n\x07workdir\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x11\n\ttest_type\x18\x03 \x01(\t\x12\x10\n\x08platform\x18\x04 \x01(\t\x12\x14\n\x0c\x61rchive_path\x18\x05 \x01(\t\x12\x0e\n\x06\x63onfig\x18\x06 \x01(\t\x12\x0b\n\x03tag\x18\x07 \x01(\t\x12\x0e\n\x06labels\x18\x08 \x03(\t\x12\x14\n\x0c\x62uilder_name\x18\t \x01(\t\x12\x11\n\tchange_id\x18\n \x01(\t\x12\x14\n\x0c\x62uild_number\x18\x0b \x01(\t\x12\x17\n\x0floader_platform\x18\x0c \x01(\t\x12\x15\n\rloader_config\x18\r \x01(\t\x12\x0f\n\x07version\x18\x0e \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x0f \x01(\x08\x12\x11\n\tdimension\x18\x10 \x03(\t\x12\x1c\n\x14unittest_shard_index\x18\x11 \x01(\t\x12\x15\n\rtest_attempts\x18\x12 \x01(\t\x12\x13\n\x0bretry_level\x18\x13 \x01(\t\x12\x15\n\rstart_timeout\x18\x14 \x01(\t\x12\x14\n\x0ctest_timeout\x18\x15 \x01(\t\x12\x13\n\x0b\x62uilder_url\x18\x16 \x01(\t\x12\x17\n\x0fgcs_result_path\x18\x17 \x01(\t\x12\x33\n\tapk_tests\x18\x18 \x03(\x0b\x32 .on_device_tests_gateway.ApkTest\"r\n\x07\x41pkTest\x12\x13\n\x0btest_target\x18\x01 \x01(\t\x12\x10\n\x08\x61pk_path\x18\x02 \x01(\t\x12\x14\n\x0c\x64\x65vice_model\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65vice_pool\x18\x04 \x01(\t\x12\x15\n\rgtest_filters\x18\x05 \x01(\t\"s\n\x19OnDeviceTestsWatchCommand\x12\x0f\n\x07workdir\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x12\n\nsession_id\x18\x03 \x01(\t\x12\x11\n\tchange_id\x18\x04 \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x05 \x01(\x08\")\n\x15OnDeviceTestsResponse\x12\x10\n\x08response\x18\x01 \x01(\t2\x8a\x02\n\x17on_device_tests_gateway\x12q\n\x0c\x65xec_command\x12-.on_device_tests_gateway.OnDeviceTestsCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x12|\n\x12\x65xec_watch_command\x12\x32.on_device_tests_gateway.OnDeviceTestsWatchCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x62\x06proto3') +) + + + + +_ONDEVICETESTSCOMMAND = _descriptor.Descriptor( + name='OnDeviceTestsCommand', + full_name='on_device_tests_gateway.OnDeviceTestsCommand', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='workdir', full_name='on_device_tests_gateway.OnDeviceTestsCommand.workdir', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='token', full_name='on_device_tests_gateway.OnDeviceTestsCommand.token', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='test_type', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_type', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='platform', full_name='on_device_tests_gateway.OnDeviceTestsCommand.platform', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='archive_path', full_name='on_device_tests_gateway.OnDeviceTestsCommand.archive_path', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='config', full_name='on_device_tests_gateway.OnDeviceTestsCommand.config', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='tag', full_name='on_device_tests_gateway.OnDeviceTestsCommand.tag', index=6, + number=7, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='labels', full_name='on_device_tests_gateway.OnDeviceTestsCommand.labels', index=7, + number=8, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='builder_name', full_name='on_device_tests_gateway.OnDeviceTestsCommand.builder_name', index=8, + number=9, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='change_id', full_name='on_device_tests_gateway.OnDeviceTestsCommand.change_id', index=9, + number=10, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='build_number', full_name='on_device_tests_gateway.OnDeviceTestsCommand.build_number', index=10, + number=11, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='loader_platform', full_name='on_device_tests_gateway.OnDeviceTestsCommand.loader_platform', index=11, + number=12, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='loader_config', full_name='on_device_tests_gateway.OnDeviceTestsCommand.loader_config', index=12, + number=13, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='version', full_name='on_device_tests_gateway.OnDeviceTestsCommand.version', index=13, + number=14, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dry_run', full_name='on_device_tests_gateway.OnDeviceTestsCommand.dry_run', index=14, + number=15, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dimension', full_name='on_device_tests_gateway.OnDeviceTestsCommand.dimension', index=15, + number=16, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='unittest_shard_index', full_name='on_device_tests_gateway.OnDeviceTestsCommand.unittest_shard_index', index=16, + number=17, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='test_attempts', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_attempts', index=17, + number=18, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='retry_level', full_name='on_device_tests_gateway.OnDeviceTestsCommand.retry_level', index=18, + number=19, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='start_timeout', full_name='on_device_tests_gateway.OnDeviceTestsCommand.start_timeout', index=19, + number=20, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='test_timeout', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_timeout', index=20, + number=21, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='builder_url', full_name='on_device_tests_gateway.OnDeviceTestsCommand.builder_url', index=21, + number=22, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='gcs_result_path', full_name='on_device_tests_gateway.OnDeviceTestsCommand.gcs_result_path', index=22, + number=23, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='apk_tests', full_name='on_device_tests_gateway.OnDeviceTestsCommand.apk_tests', index=23, + number=24, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=59, + serialized_end=599, +) + + +_APKTEST = _descriptor.Descriptor( + name='ApkTest', + full_name='on_device_tests_gateway.ApkTest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='test_target', full_name='on_device_tests_gateway.ApkTest.test_target', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='apk_path', full_name='on_device_tests_gateway.ApkTest.apk_path', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='device_model', full_name='on_device_tests_gateway.ApkTest.device_model', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='device_pool', full_name='on_device_tests_gateway.ApkTest.device_pool', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='gtest_filters', full_name='on_device_tests_gateway.ApkTest.gtest_filters', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=601, + serialized_end=715, +) + + +_ONDEVICETESTSWATCHCOMMAND = _descriptor.Descriptor( + name='OnDeviceTestsWatchCommand', + full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='workdir', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.workdir', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='token', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.token', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='session_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.session_id', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='change_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.change_id', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dry_run', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.dry_run', index=4, + number=5, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=717, + serialized_end=832, +) + + +_ONDEVICETESTSRESPONSE = _descriptor.Descriptor( + name='OnDeviceTestsResponse', + full_name='on_device_tests_gateway.OnDeviceTestsResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='response', full_name='on_device_tests_gateway.OnDeviceTestsResponse.response', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=834, + serialized_end=875, +) + +_ONDEVICETESTSCOMMAND.fields_by_name['apk_tests'].message_type = _APKTEST +DESCRIPTOR.message_types_by_name['OnDeviceTestsCommand'] = _ONDEVICETESTSCOMMAND +DESCRIPTOR.message_types_by_name['ApkTest'] = _APKTEST +DESCRIPTOR.message_types_by_name['OnDeviceTestsWatchCommand'] = _ONDEVICETESTSWATCHCOMMAND +DESCRIPTOR.message_types_by_name['OnDeviceTestsResponse'] = _ONDEVICETESTSRESPONSE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +OnDeviceTestsCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsCommand', (_message.Message,), dict( + DESCRIPTOR = _ONDEVICETESTSCOMMAND, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsCommand) + )) +_sym_db.RegisterMessage(OnDeviceTestsCommand) + +ApkTest = _reflection.GeneratedProtocolMessageType('ApkTest', (_message.Message,), dict( + DESCRIPTOR = _APKTEST, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.ApkTest) + )) +_sym_db.RegisterMessage(ApkTest) + +OnDeviceTestsWatchCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsWatchCommand', (_message.Message,), dict( + DESCRIPTOR = _ONDEVICETESTSWATCHCOMMAND, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsWatchCommand) + )) +_sym_db.RegisterMessage(OnDeviceTestsWatchCommand) + +OnDeviceTestsResponse = _reflection.GeneratedProtocolMessageType('OnDeviceTestsResponse', (_message.Message,), dict( + DESCRIPTOR = _ONDEVICETESTSRESPONSE, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsResponse) + )) +_sym_db.RegisterMessage(OnDeviceTestsResponse) + + + +_ON_DEVICE_TESTS_GATEWAY = _descriptor.ServiceDescriptor( + name='on_device_tests_gateway', + full_name='on_device_tests_gateway.on_device_tests_gateway', + file=DESCRIPTOR, + index=0, + options=None, + serialized_start=878, + serialized_end=1144, + methods=[ + _descriptor.MethodDescriptor( + name='exec_command', + full_name='on_device_tests_gateway.on_device_tests_gateway.exec_command', + index=0, + containing_service=None, + input_type=_ONDEVICETESTSCOMMAND, + output_type=_ONDEVICETESTSRESPONSE, + options=None, + ), + _descriptor.MethodDescriptor( + name='exec_watch_command', + full_name='on_device_tests_gateway.on_device_tests_gateway.exec_watch_command', + index=1, + containing_service=None, + input_type=_ONDEVICETESTSWATCHCOMMAND, + output_type=_ONDEVICETESTSRESPONSE, + options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_ON_DEVICE_TESTS_GATEWAY) + +DESCRIPTOR.services_by_name['on_device_tests_gateway'] = _ON_DEVICE_TESTS_GATEWAY + +# @@protoc_insertion_point(module_scope) diff --git a/tools/on_device_tests_gateway_pb2_grpc.py b/tools/on_device_tests_gateway_pb2_grpc.py new file mode 100644 index 000000000000..fdbfa59ddf18 --- /dev/null +++ b/tools/on_device_tests_gateway_pb2_grpc.py @@ -0,0 +1,64 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import on_device_tests_gateway_pb2 as on__device__tests__gateway__pb2 + + +class on_device_tests_gatewayStub(object): + """Interface exported by the server. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.exec_command = channel.unary_stream( + '/on_device_tests_gateway.on_device_tests_gateway/exec_command', + request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.SerializeToString, + response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, + ) + self.exec_watch_command = channel.unary_stream( + '/on_device_tests_gateway.on_device_tests_gateway/exec_watch_command', + request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.SerializeToString, + response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, + ) + + +class on_device_tests_gatewayServicer(object): + """Interface exported by the server. + """ + + def exec_command(self, request, context): + """A dumb proxy RPC service that passes user defined command line options + to the on-device tests gateway and streams back output in real time. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def exec_watch_command(self, request, context): + # missing associated documentation comment in .proto file + pass + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_on_device_tests_gatewayServicer_to_server(servicer, server): + rpc_method_handlers = { + 'exec_command': grpc.unary_stream_rpc_method_handler( + servicer.exec_command, + request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.FromString, + response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, + ), + 'exec_watch_command': grpc.unary_stream_rpc_method_handler( + servicer.exec_watch_command, + request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.FromString, + response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'on_device_tests_gateway.on_device_tests_gateway', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) From a7dace2ccc1fea5ba650adb780ec6ad6dbc85610 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Mon, 23 Dec 2024 14:32:50 -0800 Subject: [PATCH 05/46] Incremental commit based on review comments --- .github/actions/on_device_tests/action.yaml | 78 +-------------------- 1 file changed, 1 insertion(+), 77 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index b03c0772535c..9040a36d95ad 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -26,7 +26,7 @@ runs: echo "DIMENSION=${{ matrix.dimension }}" >> $GITHUB_ENV fi shell: bash - - name: Run ${{ env.SHARD_NAME }} Tests on ${{ matrix.platform }} Platform + - name: Run Tests on ${{ matrix.platform }} Platform env: GCS_PATH: gs://${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} run: | @@ -41,79 +41,3 @@ runs: --gcs_result_path "${GCS_RESULTS_PATH}" \ trigger \ shell: bash - - name: Download ${{ matrix.platform }} Test Results - if: always() && env.TEST_TYPE == 'unit_test' - run: | - # Don't break on error (-e), some commands are expected to fail. - set -ux - - COBALT_LOGS_DIR="${GITHUB_WORKSPACE}/cobalt_logs" - UNIT_TEST_RESULT_PATH="${GITHUB_WORKSPACE}/unit-test-results" - COBALT_XMLS_FILENAME="cobalt_xmls.zip" - - # Forward environment variables for uploading artifacts in later steps. - echo "UNIT_TEST_RESULT_PATH=${UNIT_TEST_RESULT_PATH}" >> $GITHUB_ENV - echo "COBALT_LOGS_DIR=${COBALT_LOGS_DIR}" >> $GITHUB_ENV - - mkdir -p "${GITHUB_WORKSPACE}/test_results" - cd "${GITHUB_WORKSPACE}/test_results" - - i=0 - # Try downloading the results for 6x 10 seconds before giving up. - while [ $i -lt 6 ]; do - # The results are uploaded after the test has completed. - sleep 10 - - # The log files are named by the device lab test driver. - COBALT_ERROR_LOG_FILENAME="webDriverTestLog.ERROR" - COBALT_INFO_LOG_FILENAME="webDriverTestLog.INFO" - - # This command will fail until the results have been uploaded. - gsutil cp "${GCS_RESULTS_PATH}/${COBALT_ERROR_LOG_FILENAME}" . - gsutil cp "${GCS_RESULTS_PATH}/${COBALT_INFO_LOG_FILENAME}" . - gsutil cp "${GCS_RESULTS_PATH}/${COBALT_XMLS_FILENAME}" . - - # Break if all files were downloaded. - if [[ -f "${COBALT_XMLS_FILENAME}" && -f "${COBALT_ERROR_LOG_FILENAME}" && -f "${COBALT_INFO_LOG_FILENAME}" ]]; then - break - fi - - i=$(( ${i} + 1 )) - done - - # Rename log files for archiving to not expose legacy weirdness. - mkdir -p "${COBALT_LOGS_DIR}/${{ matrix.platform }}/" - cp "${COBALT_ERROR_LOG_FILENAME}" "${COBALT_LOGS_DIR}/${{ matrix.platform }}/stderr_${{ matrix.shard }}.log" - cp "${COBALT_INFO_LOG_FILENAME}" "${COBALT_LOGS_DIR}/${{ matrix.platform }}/stdout_${{ matrix.shard }}.log" - - # Prepare unit test results for DataDog upload. - RESULT_PATH=${UNIT_TEST_RESULT_PATH}/${{ matrix.platform }}/${{ matrix.shard }}/ - mkdir -p ${RESULT_PATH} - - # Set tags for test differentiation. - tags="os.platform:${{ matrix.platform }}" - echo $tags > ${UNIT_TEST_RESULT_PATH}/${{ matrix.platform }}/TAGS - - unzip ${COBALT_XMLS_FILENAME} -d ${RESULT_PATH} - shell: bash - - name: Archive Unit Test Logs - uses: actions/upload-artifact@v3 - if: always() && env.TEST_TYPE == 'unit_test' - with: - name: Device logs - path: ${{ env.COBALT_LOGS_DIR }}/ - - name: Archive Unit Test Results - uses: actions/upload-artifact@v3 - if: always() && env.TEST_TYPE == 'unit_test' - with: - name: unit-test-results - path: ${{ env.UNIT_TEST_RESULT_PATH }}/ - - name: Print device logs - if: always() - run: | - if ls ${COBALT_LOGS_DIR}/**/*.log 1> /dev/null 2>&1; then - cat ${COBALT_LOGS_DIR}/**/*.log - else - echo "No device logs found" - fi - shell: bash From c9f93a46261b1380a4c20bedb0066c0196fe349e Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Thu, 2 Jan 2025 22:46:03 +0000 Subject: [PATCH 06/46] new changes for odt gateway --- .../android-arm/base_unittests_filter.json | 4 -- tools/on_device_tests_gateway.proto | 36 +++++-------- tools/on_device_tests_gateway_client.py | 54 ++++++------------- 3 files changed, 29 insertions(+), 65 deletions(-) diff --git a/cobalt/testing/android-arm/base_unittests_filter.json b/cobalt/testing/android-arm/base_unittests_filter.json index bb161c725dc4..fb7886542530 100644 --- a/cobalt/testing/android-arm/base_unittests_filter.json +++ b/cobalt/testing/android-arm/base_unittests_filter.json @@ -2,9 +2,5 @@ "failing_tests": [ "BreakIteratorTest.BreakCharacter", "ValuesUtilTest.FilePath" - ], - "passing_tests": [ - "test1", - "test2" ] } diff --git a/tools/on_device_tests_gateway.proto b/tools/on_device_tests_gateway.proto index 50cc02d478f7..933b5818faa4 100644 --- a/tools/on_device_tests_gateway.proto +++ b/tools/on_device_tests_gateway.proto @@ -29,33 +29,23 @@ service on_device_tests_gateway { // Working directory and command line arguments to be passed to the gateway. message OnDeviceTestsCommand { - // Next ID: 23 string workdir = 1; string token = 2; - string test_type = 3; - string platform = 4; - string archive_path = 5; - string config = 6; - string tag = 7; - repeated string labels = 8; - string builder_name = 9; - string change_id = 10; - string build_number = 11; - string loader_platform = 12; - string loader_config = 13; - string version = 14; - bool dry_run = 15; - repeated string dimension = 16; - string unittest_shard_index = 17; - string test_attempts = 18; - string retry_level = 19; - string start_timeout = 20; - string test_timeout = 21; - string builder_url = 22; - string gcs_result_path = 23; - repeated ApkTest apk_tests = 24; + string platform = 3; + string archive_path = 4; + repeated string labels = 5; + string change_id = 6; + bool dry_run = 7; + repeated string dimension = 8; + string test_attempts = 9; + string retry_level = 10; + string start_timeout = 11; + string test_timeout = 12; + string gcs_result_path = 13; + repeated ApkTest apk_tests = 14; } +// apk_test details message ApkTest { string test_target = 1; string apk_path = 2; diff --git a/tools/on_device_tests_gateway_client.py b/tools/on_device_tests_gateway_client.py index 99cdbb5f7166..2ff477bd0087 100644 --- a/tools/on_device_tests_gateway_client.py +++ b/tools/on_device_tests_gateway_client.py @@ -26,25 +26,15 @@ import on_device_tests_gateway_pb2 import on_device_tests_gateway_pb2_grpc -# All tests On-Device tests support -_TEST_TYPES = [ - 'black_box_test', - 'evergreen_test', - 'unit_test', -] - -# All test configs On-Device tests support -_TEST_CONFIGS = [ - 'devel', - 'staging', - 'production', -] - _WORK_DIR = '/on_device_tests_gateway' + +# Comment out thw next three lines for local testing _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( - #'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') - 'localhost') -#_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' + 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') +_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' + +# Uncomment the next two lines for local testing +_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') _ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '12345' @@ -75,23 +65,13 @@ def run_trigger_command(self, workdir: str, args: argparse.Namespace, apk_tests on_device_tests_gateway_pb2.OnDeviceTestsCommand( workdir=workdir, token=args.token, - #test_type=args.test_type, platform=args.platform, archive_path=args.archive_path, - #config=args.config, - #tag=args.tag, labels=args.label, gcs_result_path=args.gcs_result_path, - #builder_name=args.builder_name, - #builder_url=args.builder_url, change_id=args.change_id, - #build_number=args.build_number, - #loader_platform=args.loader_platform, - #loader_config=args.loader_config, - #version=args.version, dry_run=args.dry_run, dimension=args.dimension or [], - #unittest_shard_index=args.unittest_shard_index, test_attempts=args.test_attempts, retry_level=args.retry_level, apk_tests=apk_tests, @@ -131,10 +111,10 @@ def _read_json_config(filename): data = json.load(f) return data except FileNotFoundError: - #print(f" Config file '{filename}' not found.") + print(f" Config file '{filename}' not found.") return None except json.JSONDecodeError: - #print(f" Invalid JSON format in '{filename}'.") + print(f" Invalid JSON format in '{filename}'.") return None def _default_platform_json_file(platform): @@ -150,12 +130,12 @@ def _get_tests_filter_json_file(platform, gtest_target): def _process_apk_tests(args): apk_tests = [] platform_json_file = args.platform_json if args.platform_json else _default_platform_json_file(args.platform) - #print(' The platform_json_file is ' + platform_json_file) + print(f" The platform_json_file is '{platform_json_file}'") platform_json_file_data = _read_json_config(platform_json_file) gtest_device = platform_json_file_data["gtest_device"] gtest_lab = platform_json_file_data["gtest_lab"] gtest_blaze_target = "//experimental/cobalt/chrobalt_poc:custom_chrobalt_unit_tests_" + gtest_device - default_gtest_filters = "GURL*" + default_gtest_filters = "*" #print(' processing gtest_targets in json file') for gtest_target in platform_json_file_data["gtest_targets"]: @@ -170,22 +150,20 @@ def _process_apk_tests(args): gtest_filter_json_file_data = _read_json_config(gtest_filter_json_file) gtest_filters = default_gtest_filters if gtest_filter_json_file_data is None: - print(" This gtest_target does not have gtest_filters_specified"); + print(" This gtest_target does not have gtest_filters specified"); else: failing_tests_list = gtest_filter_json_file_data["failing_tests"] passing_tests_list = gtest_filter_json_file_data["passing_tests"] - #print(f" failing tests in json: {failing_tests_list}") - #print(f" passing tests in json: {passing_tests_list}") failing_tests_string = ":".join(failing_tests_list) passing_tests_string = ":".join(passing_tests_list) - #print(f" failing_tests_string = '{failing_tests_string}'") - #print(f" passing_tests_string = '{passing_tests_string}'") if passing_tests_string: gtest_filters += ":" + passing_tests_string if failing_tests_string: gtest_filters += ":-" + failing_tests_string - #print(f" gtest_filters = {gtest_filters}"); - apk_test["apk_path"] = "/bigstore/yt-temp/" + gtest_target + "-debug.apk" + print(f" gtest_filters = {gtest_filters}"); + + #apk_test["apk_path"] = "/bigstore/yt-temp/" + gtest_target + "-debug.apk" + apk_test["apk_path"] = "/bigstore/yt-temp/base_unittests-debug.apk" apk_test["gtest_filters"] = gtest_filters apk_tests.append(apk_test) From 4a1c7831b1be7f591888022bd8274d517eec45b5 Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Thu, 2 Jan 2025 23:54:04 +0000 Subject: [PATCH 07/46] additional changes to odt gateway code --- .github/actions/on_device_tests/action.yaml | 2 +- tools/on_device_tests_gateway_client.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 9040a36d95ad..1e61b0892b40 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -28,7 +28,7 @@ runs: shell: bash - name: Run Tests on ${{ matrix.platform }} Platform env: - GCS_PATH: gs://${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} + GCS_PATH: /bigstore/${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} run: | set -uxe python3 -u tools/on_device_tests_gateway_client.py \ diff --git a/tools/on_device_tests_gateway_client.py b/tools/on_device_tests_gateway_client.py index 2ff477bd0087..55937fd4b39c 100644 --- a/tools/on_device_tests_gateway_client.py +++ b/tools/on_device_tests_gateway_client.py @@ -28,10 +28,10 @@ _WORK_DIR = '/on_device_tests_gateway' -# Comment out thw next three lines for local testing -_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( - 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') -_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' +# Comment out the next three lines for local testing +#_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( +# 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') +#_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' # Uncomment the next two lines for local testing _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') @@ -153,11 +153,11 @@ def _process_apk_tests(args): print(" This gtest_target does not have gtest_filters specified"); else: failing_tests_list = gtest_filter_json_file_data["failing_tests"] - passing_tests_list = gtest_filter_json_file_data["passing_tests"] + #passing_tests_list = gtest_filter_json_file_data["passing_tests"] failing_tests_string = ":".join(failing_tests_list) - passing_tests_string = ":".join(passing_tests_list) - if passing_tests_string: - gtest_filters += ":" + passing_tests_string + #passing_tests_string = ":".join(passing_tests_list) + #if passing_tests_string: + # gtest_filters += ":" + passing_tests_string if failing_tests_string: gtest_filters += ":-" + failing_tests_string print(f" gtest_filters = {gtest_filters}"); From 9ef1c4cf9924d73c62466560f74209c0a3cd2de8 Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Fri, 3 Jan 2025 00:36:28 +0000 Subject: [PATCH 08/46] changing --archive_path in action.yaml --- .github/actions/on_device_tests/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 1e61b0892b40..a1e7fbe2542e 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -37,7 +37,7 @@ runs: --token ${GITHUB_TOKEN} \ ${DIMENSION:+"--dimension" "$DIMENSION"} \ ${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" "$ON_DEVICE_TEST_ATTEMPTS"} \ - --archive_path "${GCS_PATH}/artifacts.tar" \ + --archive_path "${GCS_PATH}" \ --gcs_result_path "${GCS_RESULTS_PATH}" \ trigger \ shell: bash From f1c937daec9c0305b1c71304aa456cc410165996 Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Tue, 7 Jan 2025 00:50:48 +0000 Subject: [PATCH 09/46] Additional changes for odt gateway --- tools/on_device_tests_gateway_client.py | 30 +++++++++++-------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tools/on_device_tests_gateway_client.py b/tools/on_device_tests_gateway_client.py index 55937fd4b39c..78e91763bf02 100644 --- a/tools/on_device_tests_gateway_client.py +++ b/tools/on_device_tests_gateway_client.py @@ -29,13 +29,13 @@ _WORK_DIR = '/on_device_tests_gateway' # Comment out the next three lines for local testing -#_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( -# 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') -#_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' +_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( + 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') +_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' # Uncomment the next two lines for local testing -_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') -_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '12345' +#_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') +#_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '12345' class OnDeviceTestsGatewayClient(): @@ -137,7 +137,6 @@ def _process_apk_tests(args): gtest_blaze_target = "//experimental/cobalt/chrobalt_poc:custom_chrobalt_unit_tests_" + gtest_device default_gtest_filters = "*" - #print(' processing gtest_targets in json file') for gtest_target in platform_json_file_data["gtest_targets"]: apk_test = { "test_target": gtest_blaze_target, @@ -153,17 +152,13 @@ def _process_apk_tests(args): print(" This gtest_target does not have gtest_filters specified"); else: failing_tests_list = gtest_filter_json_file_data["failing_tests"] - #passing_tests_list = gtest_filter_json_file_data["passing_tests"] failing_tests_string = ":".join(failing_tests_list) - #passing_tests_string = ":".join(passing_tests_list) - #if passing_tests_string: - # gtest_filters += ":" + passing_tests_string if failing_tests_string: gtest_filters += ":-" + failing_tests_string print(f" gtest_filters = {gtest_filters}"); - #apk_test["apk_path"] = "/bigstore/yt-temp/" + gtest_target + "-debug.apk" - apk_test["apk_path"] = "/bigstore/yt-temp/base_unittests-debug.apk" + apk_test["apk_path"] = f"{args.archive_path}/{gtest_target}-debug.apk" + #apk_test["apk_path"] = "/bigstore/yt-temp/base_unittests-debug.apk" apk_test["gtest_filters"] = gtest_filters apk_tests.append(apk_test) @@ -178,11 +173,12 @@ def main(): level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s') parser = argparse.ArgumentParser( - epilog=('Example: ./on_device_tests_gateway_client.py ' - '--test_type=unit_test ' - '--remote_archive_path=gs://my_bucket/path/to/artifacts.tar ' - '--platform=raspi-2 ' - '--config=devel'), + epilog=('Example: ./on_device_tests_gateway_client.py' + 'trigger' + '--token token1' + '--platform android-arm' + '--archive_path /bigstore/yt-temp' + '--dimension host_name=regex:maneki-mhserver-05.*'), formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument( '-t', From 9287f8887e0c166f9fb4be031f21ef81896aa88a Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Tue, 7 Jan 2025 11:21:00 -0800 Subject: [PATCH 10/46] Add additional argument for ODT gateway client --- .github/actions/on_device_tests/action.yaml | 32 ++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index a1e7fbe2542e..d4f26042e261 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -29,15 +29,45 @@ runs: - name: Run Tests on ${{ matrix.platform }} Platform env: GCS_PATH: /bigstore/${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} + GITHUB_SHA: ${{ github.sha }} + GITHUB_TOKEN: ${{ github.token }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TRIGGERING_ACTOR: ${{ github.triggering_actor }} + GITHUB_ACTOR_ID: ${{ github.actor_id }} + GITHUB_REPO: ${{ github.repository }} + GITHUB_PR_HEAD_USER_LOGIN: ${{ github.event.pull_request.head.user.login }} + GITHUB_PR_HEAD_USER_ID: ${{ github.event.pull_request.head.user.id }} + GITHUB_COMMIT_AUTHOR_USERNAME: ${{ github.event.commits[0].author.username }} + GITHUB_COMMIT_AUTHOR_EMAIL: ${{ github.event.commits[0].author.email }} + GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_RUN_NUMBER: ${{ github.run_number }} + GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_WORKFLOW: ${{ github.workflow }} run: | set -uxe python3 -u tools/on_device_tests_gateway_client.py \ --platform_json "${GITHUB_WORKSPACE}/src/.github/config/${{ matrix.platform}}.json" \ --filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/${{ matrix.platform}}" \ --token ${GITHUB_TOKEN} \ + --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ + --tag cobalt_github_${GITHUB_EVENT_NAME} \ + --builder_name github_${{ matrix.platform }}_tests \ + --build_number ${GITHUB_RUN_NUMBER} \ + --builder_url ${GITHUB_RUN_URL} \ + --label github \ + --label ${GITHUB_EVENT_NAME} \ + --label ${GITHUB_WORKFLOW} \ + --label actor-${GITHUB_ACTOR} \ + --label actor_id-${GITHUB_ACTOR_ID} \ + --label triggering_actor-${GITHUB_TRIGGERING_ACTOR} \ + --label sha-${GITHUB_SHA} \ + --label repository-${GITHUB_REPO} \ + --label author-${GITHUB_PR_HEAD_USER_LOGIN:-$GITHUB_COMMIT_AUTHOR_USERNAME} \ + --label author_id-${GITHUB_PR_HEAD_USER_ID:-$GITHUB_COMMIT_AUTHOR_EMAIL} ${DIMENSION:+"--dimension" "$DIMENSION"} \ ${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" "$ON_DEVICE_TEST_ATTEMPTS"} \ --archive_path "${GCS_PATH}" \ --gcs_result_path "${GCS_RESULTS_PATH}" \ - trigger \ + trigger shell: bash From 924b4940f1637e9a5ffd6ea384df99257e5043bc Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Tue, 7 Jan 2025 19:20:46 +0000 Subject: [PATCH 11/46] Additional improvements for odt gateway code --- tools/on_device_tests_gateway_client.py | 392 +++++++++++++++--------- 1 file changed, 244 insertions(+), 148 deletions(-) diff --git a/tools/on_device_tests_gateway_client.py b/tools/on_device_tests_gateway_client.py index 78e91763bf02..2cfad00758fc 100644 --- a/tools/on_device_tests_gateway_client.py +++ b/tools/on_device_tests_gateway_client.py @@ -117,162 +117,258 @@ def _read_json_config(filename): print(f" Invalid JSON format in '{filename}'.") return None -def _default_platform_json_file(platform): - current_dir = os.path.dirname(os.path.abspath(__file__)) - relative_path = os.path.join("..", ".github", "config", platform + ".json") - return os.path.join(current_dir, relative_path) +def _get_platform_json_file(platform): + """Constructs the path to the platform JSON configuration file. + + Args: + platform: The name of the platform. + + Returns: + The absolute path to the platform JSON file. + """ + return os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "..", + ".github", + "config", + f"{platform}.json" + ) def _get_tests_filter_json_file(platform, gtest_target): - current_dir = os.path.dirname(os.path.abspath(__file__)) - relative_path = os.path.join("..", "cobalt", "testing", platform, gtest_target + "_filter.json") - return os.path.join(current_dir, relative_path) + """Constructs the path to the gtest filter JSON file. + + Args: + platform: The name of the platform. + gtest_target: The name of the gtest target. + + Returns: + The absolute path to the gtest filter JSON file. + """ + return os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "..", + "cobalt", + "testing", + platform, + f"{gtest_target}_filter.json" + ) def _process_apk_tests(args): - apk_tests = [] - platform_json_file = args.platform_json if args.platform_json else _default_platform_json_file(args.platform) - print(f" The platform_json_file is '{platform_json_file}'") - platform_json_file_data = _read_json_config(platform_json_file) - gtest_device = platform_json_file_data["gtest_device"] - gtest_lab = platform_json_file_data["gtest_lab"] - gtest_blaze_target = "//experimental/cobalt/chrobalt_poc:custom_chrobalt_unit_tests_" + gtest_device - default_gtest_filters = "*" - - for gtest_target in platform_json_file_data["gtest_targets"]: - apk_test = { - "test_target": gtest_blaze_target, - "device_model": gtest_device, - "device_pool": gtest_lab - } - print(f" gtest_target: {gtest_target}") - gtest_filter_json_file = _get_tests_filter_json_file(args.platform, gtest_target) - print(f" gtest_filter_json_file = {gtest_filter_json_file}") - gtest_filter_json_file_data = _read_json_config(gtest_filter_json_file) - gtest_filters = default_gtest_filters - if gtest_filter_json_file_data is None: - print(" This gtest_target does not have gtest_filters specified"); - else: - failing_tests_list = gtest_filter_json_file_data["failing_tests"] - failing_tests_string = ":".join(failing_tests_list) - if failing_tests_string: - gtest_filters += ":-" + failing_tests_string - print(f" gtest_filters = {gtest_filters}"); + """Processes APK tests based on provided arguments. - apk_test["apk_path"] = f"{args.archive_path}/{gtest_target}-debug.apk" - #apk_test["apk_path"] = "/bigstore/yt-temp/base_unittests-debug.apk" - apk_test["gtest_filters"] = gtest_filters - apk_tests.append(apk_test) + Args: + args: An argparse.Namespace object containing the following attributes: + platform: The platform for the tests. + platform_json: Optional path to a platform JSON file. + blaze_targets: A list of Blaze targets. + archive_path: Path to the archive containing APKs. + + Returns: + A list of dictionaries, where each dictionary represents an APK test + with keys like "test_target", "device_model", "device_pool", + "apk_path", and "gtest_filters". + """ - print(f" apk_tests: {apk_tests}") - return apk_tests + apk_tests = [] + platform_json_file = args.platform_json or _default_platform_json_file(args.platform) + print(f"The platform_json_file is '{platform_json_file}'") + platform_data = _read_json_config(platform_json_file) + print(f"Loaded platform data: {platform_data}") # Added verbosity + + for target in args.blaze_targets: + print(f"Processing Blaze target: {target}") # Added verbosity + for gtest_target in platform_data["gtest_targets"]: + print(f" Processing gtest_target: {gtest_target}") # Added verbosity + apk_test = { + "test_target": target, + "device_model": platform_data["gtest_device"], + "device_pool": platform_data["gtest_lab"], + "apk_path": f"{args.archive_path}/{gtest_target}-debug.apk", + "gtest_filters": _get_gtest_filters(args.platform, gtest_target) + } + apk_tests.append(apk_test) + print(f" Created apk_test: {apk_test}") # Added verbosity + + print(f"apk_tests: {apk_tests}") + return apk_tests + + +def _get_gtest_filters(platform, gtest_target): + """Retrieves gtest filters for a given target. -def main(): - """Main routine.""" - print('Starting main routine') - - logging.basicConfig( - level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s') - - parser = argparse.ArgumentParser( - epilog=('Example: ./on_device_tests_gateway_client.py' - 'trigger' - '--token token1' - '--platform android-arm' - '--archive_path /bigstore/yt-temp' - '--dimension host_name=regex:maneki-mhserver-05.*'), - formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument( - '-t', - '--token', - type=str, - required=True, - help='On Device Tests authentication token') - parser.add_argument( - '--dry_run', - action='store_true', - help='Specifies to show what would be done without actually doing it.') - parser.add_argument( - '-i', - '--change_id', - type=str, - help='ChangeId that triggered this test, if any. ' - 'Saved with performance test results.') - - subparsers = parser.add_subparsers( - dest='action', help='On-Device tests commands', required=True) - trigger_parser = subparsers.add_parser( - 'trigger', help='Trigger On-Device tests') - - trigger_parser.add_argument( - '-p', - '--platform', - type=str, - required=True, - help='Platform this test was built for.') - trigger_parser.add_argument( - '-pf', - '--platform_json', - type=str, - help='Platform-specific json file containing the list of target tests.') - trigger_parser.add_argument( - '-a', - '--archive_path', - type=str, - required=True, - help='Path to Chrobalt archive to be tested. Must be on gcs.') - trigger_parser.add_argument( - '-l', - '--label', - type=str, - default=[], - action='append', - help='Additional labels to assign to the test.') - trigger_parser.add_argument( - '--gcs_result_path', - type=str, - help='GCS url where test result files should be uploaded.') - trigger_parser.add_argument( - '--dimension', - type=str, - action='append', - help='On-Device Tests dimension used to select a device. ' - 'Must have the following form: =.' - ' E.G. "release_version=regex:10.*') - trigger_parser.add_argument( - '--test_attempts', - type=str, - default='1', - required=False, - help='The maximum number of times a test could retry.') - trigger_parser.add_argument( - '--retry_level', - type=str, - default='ERROR', - required=False, - help='The retry level of Mobile harness job. Either ERROR (to retry for ' - 'MH errors) or FAIL (to retry for failing tests). Setting retry_level to ' - 'FAIL will also retry for MH errors.') - - watch_parser = subparsers.add_parser('watch', help='Trigger On-Device tests') - watch_parser.add_argument( - 'session_id', - type=str, - help='Session id of a previously triggered mobile ' - 'harness test. If passed, the test will not be ' - 'triggered, but will be watched until the exit ' - 'status is reached.') - - args = parser.parse_args() - apk_tests = _process_apk_tests(args) - - client = OnDeviceTestsGatewayClient() - try: - if args.action == 'trigger': - client.run_trigger_command(workdir=_WORK_DIR, args=args, apk_tests=apk_tests) + Args: + platform: The platform for the tests. + gtest_target: The name of the gtest target. + + Returns: + A string representing the gtest filters. + """ + + gtest_filters = "*" + filter_json_file = _get_tests_filter_json_file(platform, gtest_target) + print(f" gtest_filter_json_file = {filter_json_file}") + filter_data = _read_json_config(filter_json_file) + if filter_data: + print(f" Loaded filter data: {filter_data}") # Added verbosity + failing_tests = ":".join(filter_data.get("failing_tests", [])) + if failing_tests: + gtest_filters += ":-" + failing_tests + print(f" gtest_filters = {gtest_filters}") else: - client.run_watch_command(workdir=_WORK_DIR, args=args) - except grpc.RpcError as e: - print(e) - return e.code().value + print(f" This gtest_target does not have gtest_filters specified") + return gtest_filters + + +def main(): + """Main routine for the on-device tests gateway client.""" + + logging.basicConfig( + level=logging.INFO, + format='[%(filename)s:%(lineno)s] %(message)s' + ) + print('Starting main routine') + + parser = argparse.ArgumentParser( + description="Client for interacting with the On-Device Tests gateway.", + epilog=( + 'Example: ./on_device_tests_gateway_client.py trigger ' + '--token token1 ' + '--platform android-arm ' + '--archive_path /bigstore/yt-temp ' + '--blaze_targets //experimental/cobalt/chrobalt_poc:chrobalt_unit_tests_maneki_sabrina //experimental/cobalt/chrobalt_poc:chrobalt_unit_tests_shared_boreal ' + '--dimension host_name=regex:maneki-mhserver-05.*' + ), + formatter_class=argparse.RawDescriptionHelpFormatter + ) + + # Authentication + parser.add_argument( + '-t', + '--token', + type=str, + required=True, + help='On Device Tests authentication token' + ) + + # General options + parser.add_argument( + '--dry_run', + action='store_true', + help='Show what would be done without actually doing it.' + ) + parser.add_argument( + '-i', + '--change_id', + type=str, + help='ChangeId that triggered this test, if any. Saved with performance test results.' + ) + + subparsers = parser.add_subparsers( + dest='action', + help='On-Device tests commands', + required=True + ) + + # Trigger command + trigger_parser = subparsers.add_parser( + 'trigger', + help='Trigger On-Device tests', + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + trigger_parser.add_argument( + '-p', + '--platform', + type=str, + required=True, + help='Platform this test was built for.' + ) + trigger_parser.add_argument( + '-pf', + '--platform_json', + type=str, + help='Platform-specific JSON file containing the list of target tests.' + ) + trigger_parser.add_argument( + '-a', + '--archive_path', + type=str, + required=True, + help='Path to Chrobalt archive to be tested. Must be on GCS.' + ) + trigger_parser.add_argument( + '-l', + '--label', + type=str, + action='append', + default=[], + help='Additional labels to assign to the test.' + ) + trigger_parser.add_argument( + '--gcs_result_path', + type=str, + help='GCS URL where test result files should be uploaded.' + ) + trigger_parser.add_argument( + '--dimension', + type=str, + action='append', + help=( + 'On-Device Tests dimension used to select a device. ' + 'Must have the following form: =. ' + 'E.G. "release_version=regex:10.*"' + ) + ) + trigger_parser.add_argument( + '--test_attempts', + type=str, + default='1', + help='The maximum number of times a test could retry.' + ) + trigger_parser.add_argument( + '--blaze_targets', + nargs="+", + type=str, + required=True, + help='A list of Blaze targets to run.' + ) + trigger_parser.add_argument( + '--retry_level', + type=str, + default='ERROR', + choices=['ERROR', 'FAIL'], + help=( + 'The retry level of Mobile Harness job. ' + 'ERROR to retry for MH errors, ' + 'FAIL to retry for failing tests (and MH errors).' + ) + ) + + # Watch command + watch_parser = subparsers.add_parser( + 'watch', + help='Watch a previously triggered On-Device test' + ) + watch_parser.add_argument( + 'session_id', + type=str, + help=( + 'Session ID of a previously triggered Mobile Harness test. ' + 'The test will be watched until it completes.' + ) + ) + + args = parser.parse_args() + apk_tests = _process_apk_tests(args) + + client = OnDeviceTestsGatewayClient() + try: + if args.action == 'trigger': + client.run_trigger_command(workdir=_WORK_DIR, args=args, apk_tests=apk_tests) + else: + client.run_watch_command(workdir=_WORK_DIR, args=args) + except grpc.RpcError as e: + print(e) + return e.code().value if __name__ == '__main__': From 6b6d877b6498ac7753afc123601960a0b3a5cc59 Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Tue, 7 Jan 2025 19:37:40 +0000 Subject: [PATCH 12/46] removing autogenerated files from pr --- tools/on_device_tests_gateway_pb2.py | 437 ---------------------- tools/on_device_tests_gateway_pb2_grpc.py | 64 ---- 2 files changed, 501 deletions(-) delete mode 100644 tools/on_device_tests_gateway_pb2.py delete mode 100644 tools/on_device_tests_gateway_pb2_grpc.py diff --git a/tools/on_device_tests_gateway_pb2.py b/tools/on_device_tests_gateway_pb2.py deleted file mode 100644 index f6c8947b850f..000000000000 --- a/tools/on_device_tests_gateway_pb2.py +++ /dev/null @@ -1,437 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: on_device_tests_gateway.proto - -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor.FileDescriptor( - name='on_device_tests_gateway.proto', - package='on_device_tests_gateway', - syntax='proto3', - serialized_pb=_b('\n\x1don_device_tests_gateway.proto\x12\x17on_device_tests_gateway\"\x9c\x04\n\x14OnDeviceTestsCommand\x12\x0f\n\x07workdir\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x11\n\ttest_type\x18\x03 \x01(\t\x12\x10\n\x08platform\x18\x04 \x01(\t\x12\x14\n\x0c\x61rchive_path\x18\x05 \x01(\t\x12\x0e\n\x06\x63onfig\x18\x06 \x01(\t\x12\x0b\n\x03tag\x18\x07 \x01(\t\x12\x0e\n\x06labels\x18\x08 \x03(\t\x12\x14\n\x0c\x62uilder_name\x18\t \x01(\t\x12\x11\n\tchange_id\x18\n \x01(\t\x12\x14\n\x0c\x62uild_number\x18\x0b \x01(\t\x12\x17\n\x0floader_platform\x18\x0c \x01(\t\x12\x15\n\rloader_config\x18\r \x01(\t\x12\x0f\n\x07version\x18\x0e \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x0f \x01(\x08\x12\x11\n\tdimension\x18\x10 \x03(\t\x12\x1c\n\x14unittest_shard_index\x18\x11 \x01(\t\x12\x15\n\rtest_attempts\x18\x12 \x01(\t\x12\x13\n\x0bretry_level\x18\x13 \x01(\t\x12\x15\n\rstart_timeout\x18\x14 \x01(\t\x12\x14\n\x0ctest_timeout\x18\x15 \x01(\t\x12\x13\n\x0b\x62uilder_url\x18\x16 \x01(\t\x12\x17\n\x0fgcs_result_path\x18\x17 \x01(\t\x12\x33\n\tapk_tests\x18\x18 \x03(\x0b\x32 .on_device_tests_gateway.ApkTest\"r\n\x07\x41pkTest\x12\x13\n\x0btest_target\x18\x01 \x01(\t\x12\x10\n\x08\x61pk_path\x18\x02 \x01(\t\x12\x14\n\x0c\x64\x65vice_model\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65vice_pool\x18\x04 \x01(\t\x12\x15\n\rgtest_filters\x18\x05 \x01(\t\"s\n\x19OnDeviceTestsWatchCommand\x12\x0f\n\x07workdir\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x12\n\nsession_id\x18\x03 \x01(\t\x12\x11\n\tchange_id\x18\x04 \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x05 \x01(\x08\")\n\x15OnDeviceTestsResponse\x12\x10\n\x08response\x18\x01 \x01(\t2\x8a\x02\n\x17on_device_tests_gateway\x12q\n\x0c\x65xec_command\x12-.on_device_tests_gateway.OnDeviceTestsCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x12|\n\x12\x65xec_watch_command\x12\x32.on_device_tests_gateway.OnDeviceTestsWatchCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x62\x06proto3') -) - - - - -_ONDEVICETESTSCOMMAND = _descriptor.Descriptor( - name='OnDeviceTestsCommand', - full_name='on_device_tests_gateway.OnDeviceTestsCommand', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='workdir', full_name='on_device_tests_gateway.OnDeviceTestsCommand.workdir', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='token', full_name='on_device_tests_gateway.OnDeviceTestsCommand.token', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='test_type', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_type', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='platform', full_name='on_device_tests_gateway.OnDeviceTestsCommand.platform', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='archive_path', full_name='on_device_tests_gateway.OnDeviceTestsCommand.archive_path', index=4, - number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='config', full_name='on_device_tests_gateway.OnDeviceTestsCommand.config', index=5, - number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='tag', full_name='on_device_tests_gateway.OnDeviceTestsCommand.tag', index=6, - number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='labels', full_name='on_device_tests_gateway.OnDeviceTestsCommand.labels', index=7, - number=8, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='builder_name', full_name='on_device_tests_gateway.OnDeviceTestsCommand.builder_name', index=8, - number=9, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='change_id', full_name='on_device_tests_gateway.OnDeviceTestsCommand.change_id', index=9, - number=10, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='build_number', full_name='on_device_tests_gateway.OnDeviceTestsCommand.build_number', index=10, - number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='loader_platform', full_name='on_device_tests_gateway.OnDeviceTestsCommand.loader_platform', index=11, - number=12, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='loader_config', full_name='on_device_tests_gateway.OnDeviceTestsCommand.loader_config', index=12, - number=13, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='version', full_name='on_device_tests_gateway.OnDeviceTestsCommand.version', index=13, - number=14, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='dry_run', full_name='on_device_tests_gateway.OnDeviceTestsCommand.dry_run', index=14, - number=15, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='dimension', full_name='on_device_tests_gateway.OnDeviceTestsCommand.dimension', index=15, - number=16, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='unittest_shard_index', full_name='on_device_tests_gateway.OnDeviceTestsCommand.unittest_shard_index', index=16, - number=17, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='test_attempts', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_attempts', index=17, - number=18, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='retry_level', full_name='on_device_tests_gateway.OnDeviceTestsCommand.retry_level', index=18, - number=19, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='start_timeout', full_name='on_device_tests_gateway.OnDeviceTestsCommand.start_timeout', index=19, - number=20, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='test_timeout', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_timeout', index=20, - number=21, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='builder_url', full_name='on_device_tests_gateway.OnDeviceTestsCommand.builder_url', index=21, - number=22, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='gcs_result_path', full_name='on_device_tests_gateway.OnDeviceTestsCommand.gcs_result_path', index=22, - number=23, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='apk_tests', full_name='on_device_tests_gateway.OnDeviceTestsCommand.apk_tests', index=23, - number=24, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=59, - serialized_end=599, -) - - -_APKTEST = _descriptor.Descriptor( - name='ApkTest', - full_name='on_device_tests_gateway.ApkTest', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='test_target', full_name='on_device_tests_gateway.ApkTest.test_target', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='apk_path', full_name='on_device_tests_gateway.ApkTest.apk_path', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='device_model', full_name='on_device_tests_gateway.ApkTest.device_model', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='device_pool', full_name='on_device_tests_gateway.ApkTest.device_pool', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='gtest_filters', full_name='on_device_tests_gateway.ApkTest.gtest_filters', index=4, - number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=601, - serialized_end=715, -) - - -_ONDEVICETESTSWATCHCOMMAND = _descriptor.Descriptor( - name='OnDeviceTestsWatchCommand', - full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='workdir', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.workdir', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='token', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.token', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='session_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.session_id', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='change_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.change_id', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='dry_run', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.dry_run', index=4, - number=5, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=717, - serialized_end=832, -) - - -_ONDEVICETESTSRESPONSE = _descriptor.Descriptor( - name='OnDeviceTestsResponse', - full_name='on_device_tests_gateway.OnDeviceTestsResponse', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='response', full_name='on_device_tests_gateway.OnDeviceTestsResponse.response', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=834, - serialized_end=875, -) - -_ONDEVICETESTSCOMMAND.fields_by_name['apk_tests'].message_type = _APKTEST -DESCRIPTOR.message_types_by_name['OnDeviceTestsCommand'] = _ONDEVICETESTSCOMMAND -DESCRIPTOR.message_types_by_name['ApkTest'] = _APKTEST -DESCRIPTOR.message_types_by_name['OnDeviceTestsWatchCommand'] = _ONDEVICETESTSWATCHCOMMAND -DESCRIPTOR.message_types_by_name['OnDeviceTestsResponse'] = _ONDEVICETESTSRESPONSE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -OnDeviceTestsCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsCommand', (_message.Message,), dict( - DESCRIPTOR = _ONDEVICETESTSCOMMAND, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsCommand) - )) -_sym_db.RegisterMessage(OnDeviceTestsCommand) - -ApkTest = _reflection.GeneratedProtocolMessageType('ApkTest', (_message.Message,), dict( - DESCRIPTOR = _APKTEST, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.ApkTest) - )) -_sym_db.RegisterMessage(ApkTest) - -OnDeviceTestsWatchCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsWatchCommand', (_message.Message,), dict( - DESCRIPTOR = _ONDEVICETESTSWATCHCOMMAND, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsWatchCommand) - )) -_sym_db.RegisterMessage(OnDeviceTestsWatchCommand) - -OnDeviceTestsResponse = _reflection.GeneratedProtocolMessageType('OnDeviceTestsResponse', (_message.Message,), dict( - DESCRIPTOR = _ONDEVICETESTSRESPONSE, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsResponse) - )) -_sym_db.RegisterMessage(OnDeviceTestsResponse) - - - -_ON_DEVICE_TESTS_GATEWAY = _descriptor.ServiceDescriptor( - name='on_device_tests_gateway', - full_name='on_device_tests_gateway.on_device_tests_gateway', - file=DESCRIPTOR, - index=0, - options=None, - serialized_start=878, - serialized_end=1144, - methods=[ - _descriptor.MethodDescriptor( - name='exec_command', - full_name='on_device_tests_gateway.on_device_tests_gateway.exec_command', - index=0, - containing_service=None, - input_type=_ONDEVICETESTSCOMMAND, - output_type=_ONDEVICETESTSRESPONSE, - options=None, - ), - _descriptor.MethodDescriptor( - name='exec_watch_command', - full_name='on_device_tests_gateway.on_device_tests_gateway.exec_watch_command', - index=1, - containing_service=None, - input_type=_ONDEVICETESTSWATCHCOMMAND, - output_type=_ONDEVICETESTSRESPONSE, - options=None, - ), -]) -_sym_db.RegisterServiceDescriptor(_ON_DEVICE_TESTS_GATEWAY) - -DESCRIPTOR.services_by_name['on_device_tests_gateway'] = _ON_DEVICE_TESTS_GATEWAY - -# @@protoc_insertion_point(module_scope) diff --git a/tools/on_device_tests_gateway_pb2_grpc.py b/tools/on_device_tests_gateway_pb2_grpc.py deleted file mode 100644 index fdbfa59ddf18..000000000000 --- a/tools/on_device_tests_gateway_pb2_grpc.py +++ /dev/null @@ -1,64 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -import grpc - -import on_device_tests_gateway_pb2 as on__device__tests__gateway__pb2 - - -class on_device_tests_gatewayStub(object): - """Interface exported by the server. - """ - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.exec_command = channel.unary_stream( - '/on_device_tests_gateway.on_device_tests_gateway/exec_command', - request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.SerializeToString, - response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, - ) - self.exec_watch_command = channel.unary_stream( - '/on_device_tests_gateway.on_device_tests_gateway/exec_watch_command', - request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.SerializeToString, - response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, - ) - - -class on_device_tests_gatewayServicer(object): - """Interface exported by the server. - """ - - def exec_command(self, request, context): - """A dumb proxy RPC service that passes user defined command line options - to the on-device tests gateway and streams back output in real time. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def exec_watch_command(self, request, context): - # missing associated documentation comment in .proto file - pass - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_on_device_tests_gatewayServicer_to_server(servicer, server): - rpc_method_handlers = { - 'exec_command': grpc.unary_stream_rpc_method_handler( - servicer.exec_command, - request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.FromString, - response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, - ), - 'exec_watch_command': grpc.unary_stream_rpc_method_handler( - servicer.exec_watch_command, - request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.FromString, - response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'on_device_tests_gateway.on_device_tests_gateway', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) From feacfaca894548d670774f995616e8aa7d12906a Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Tue, 7 Jan 2025 19:58:14 +0000 Subject: [PATCH 13/46] moving odt gateway code from tools folder to cobalt/tools --- .github/actions/on_device_tests/action.yaml | 4 ++-- {tools => cobalt/tools}/on_device_tests_gateway.proto | 0 {tools => cobalt/tools}/on_device_tests_gateway_client.py | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename {tools => cobalt/tools}/on_device_tests_gateway.proto (100%) rename {tools => cobalt/tools}/on_device_tests_gateway_client.py (100%) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index d4f26042e261..478772a450ea 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -10,7 +10,7 @@ runs: shell: bash - name: Generate gRPC files run: | - python -m grpc_tools.protoc -Itools/ --python_out=tools/ --grpc_python_out=tools/ tools/on_device_tests_gateway.proto + python -m grpc_tools.protoc -Itools/ --python_out=cobalt/tools/ --grpc_python_out=cobalt/tools/ cobalt/tools/on_device_tests_gateway.proto shell: bash - name: Set Up Cloud SDK uses: isarkis/setup-gcloud@40dce7857b354839efac498d3632050f568090b6 # v1.1.1 @@ -46,7 +46,7 @@ runs: GITHUB_WORKFLOW: ${{ github.workflow }} run: | set -uxe - python3 -u tools/on_device_tests_gateway_client.py \ + python3 -u cobalt/tools/on_device_tests_gateway_client.py \ --platform_json "${GITHUB_WORKSPACE}/src/.github/config/${{ matrix.platform}}.json" \ --filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/${{ matrix.platform}}" \ --token ${GITHUB_TOKEN} \ diff --git a/tools/on_device_tests_gateway.proto b/cobalt/tools/on_device_tests_gateway.proto similarity index 100% rename from tools/on_device_tests_gateway.proto rename to cobalt/tools/on_device_tests_gateway.proto diff --git a/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py similarity index 100% rename from tools/on_device_tests_gateway_client.py rename to cobalt/tools/on_device_tests_gateway_client.py From 3c86d6f154022cb718960f0a618211a048fc3d13 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Tue, 7 Jan 2025 14:36:08 -0800 Subject: [PATCH 14/46] Introduce "test_dimension" key --- .github/actions/on_device_tests/action.yaml | 1 + .github/config/android-arm.json | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 478772a450ea..816277766ebc 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -5,6 +5,7 @@ runs: using: "composite" steps: - name: Install Requirements + # TODO (b/388329764) - set up requirements file. run: | pip3 install grpcio==1.38.0 grpcio-tools==1.38.0 shell: bash diff --git a/.github/config/android-arm.json b/.github/config/android-arm.json index 684725c6f75e..6bfc85207a7e 100644 --- a/.github/config/android-arm.json +++ b/.github/config/android-arm.json @@ -21,8 +21,10 @@ "sql_unittests", "url_unittests" ], - "gtest_device": "sabrina", - "gtest_lab": "maneki", + "test_dimensions": { + "gtest_device": "sabrina", + "gtest_lab": "maneki" + }, "test_on_device": true, "includes": [ { From 5e5e5f55aecc757d437ac1d3caeac00db1d96f15 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Wed, 8 Jan 2025 16:20:34 -0800 Subject: [PATCH 15/46] Log and XML file processing --- .github/actions/on_device_tests/action.yaml | 24 +++++++++++++++++++-- .github/workflows/main.yaml | 20 ++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 816277766ebc..7bb7d04a6fb5 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -1,5 +1,9 @@ name: On Device Test description: Runs on-device tests. +inputs: + results_dir: + description: "Path to directory where test results are saved." + required: true runs: using: "composite" @@ -18,10 +22,8 @@ runs: - name: Set env vars run: | echo "PROJECT_NAME=$(gcloud config get-value project)" >> $GITHUB_ENV - # Test results and logs echo "GCS_RESULTS_PATH=gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }}" >> $GITHUB_ENV - # Dimension env if [ "${{ matrix.dimension }}" != "null" ]; then echo "DIMENSION=${{ matrix.dimension }}" >> $GITHUB_ENV @@ -72,3 +74,21 @@ runs: --gcs_result_path "${GCS_RESULTS_PATH}" \ trigger shell: bash + - name: Download ${{ matrix.platform }} Test Results + if: always() + env: + RESULTS_DIR: ${{ inputs.results_dir }} + run: | + set -uxe + mkdir -p "${GITHUB_WORKSPACE}/${RESULTS_DIR}" + cd "${GITHUB_WORKSPACE}/${RESULTS_DIR}" + gsutil cp "${GCS_RESULTS_PATH}/" . + echo "TEST_LOG=${GITHUB_WORKSPACE}/${RESULTS_DIR}/test_results.txt" >> $GITHUB_ENV + shell: bash + - name: Archive Test Logs + uses: actions/upload-artifact@v3 + if: always() + with: + name: Test log + path: ${{ env.TEST_LOG }}/ + diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 35c85676f956..f7a737857975 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -303,6 +303,8 @@ jobs: platform: ${{ fromJson(needs.initialize.outputs.platforms) }} config: [devel] include: ${{ fromJson(needs.initialize.outputs.includes) }} + env: + TEST_RESULTS_DIR: ${{ matrix.name }}_test_results steps: - name: Checkout uses: kaidokert/checkout@v3.5.999 @@ -310,5 +312,21 @@ jobs: with: fetch-depth: 1 persist-credentials: false - - name: Run Tests (${{ matrix.shard }}) + - name: Run On-Device Tests (${{ matrix.shard }}) + id: on-device-tests uses: ./.github/actions/on_device_tests + with: + results_dir: ${{ env.TEST_RESULTS_DIR }} + - name: Process Test Results + if: | + always() && + ( + steps.on-device-tests.outcome == 'success' || + steps.on-device-tests.outcome == 'failure' + ) + uses: ./src/.github/actions/process_test_results + with: + results_dir: ${{ env.TEST_RESULTS_DIR }} + datadog_api_key: ${{ secrets.DD_API_KEY }} + is_postsubmit: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} + continue-on-error: true From c8bf953fb30323c56e32a051a8f370a0b17022c3 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Mon, 13 Jan 2025 21:14:10 -0800 Subject: [PATCH 16/46] Update gateway client parameters --- .github/actions/on_device_tests/action.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 7bb7d04a6fb5..baf057b7bde2 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -55,9 +55,8 @@ runs: --token ${GITHUB_TOKEN} \ --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ --tag cobalt_github_${GITHUB_EVENT_NAME} \ - --builder_name github_${{ matrix.platform }}_tests \ - --build_number ${GITHUB_RUN_NUMBER} \ - --builder_url ${GITHUB_RUN_URL} \ + --label builder-${{ matrix.platform }} \ + --label builder_url-${GITHUB_RUN_URL} \ --label github \ --label ${GITHUB_EVENT_NAME} \ --label ${GITHUB_WORKFLOW} \ @@ -91,4 +90,3 @@ runs: with: name: Test log path: ${{ env.TEST_LOG }}/ - From d7b06969b4b4bc24c87197ed84df2248c55ce856 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Tue, 14 Jan 2025 11:11:24 -0800 Subject: [PATCH 17/46] remove tag --- .github/actions/on_device_tests/action.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index baf057b7bde2..e31e34c17d2a 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -54,7 +54,6 @@ runs: --filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/${{ matrix.platform}}" \ --token ${GITHUB_TOKEN} \ --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ - --tag cobalt_github_${GITHUB_EVENT_NAME} \ --label builder-${{ matrix.platform }} \ --label builder_url-${GITHUB_RUN_URL} \ --label github \ From 0acf2cce6c44ec79ae8b58f616e74fae2a10bfcc Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Tue, 14 Jan 2025 15:30:40 -0800 Subject: [PATCH 18/46] Parameter work --- .github/actions/on_device_tests/action.yaml | 9 +++++++-- .github/workflows/main.yaml | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index e31e34c17d2a..86bf7a2d940a 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -1,6 +1,9 @@ name: On Device Test description: Runs on-device tests. inputs: + gcs_results_path: + description: "GCS path for the test results" + required: true results_dir: description: "Path to directory where test results are saved." required: true @@ -31,7 +34,8 @@ runs: shell: bash - name: Run Tests on ${{ matrix.platform }} Platform env: - GCS_PATH: /bigstore/${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} + GCS_ARTIFACTS_PATH: /bigstore/${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} + GCS_RESULTS_PATH: ${{ inputs.gcs_results_path }} GITHUB_SHA: ${{ github.sha }} GITHUB_TOKEN: ${{ github.token }} GITHUB_EVENT_NAME: ${{ github.event_name }} @@ -68,13 +72,14 @@ runs: --label author_id-${GITHUB_PR_HEAD_USER_ID:-$GITHUB_COMMIT_AUTHOR_EMAIL} ${DIMENSION:+"--dimension" "$DIMENSION"} \ ${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" "$ON_DEVICE_TEST_ATTEMPTS"} \ - --archive_path "${GCS_PATH}" \ + --gcs_archive_path "${GCS_ARTIFACTS_PATH}" \ --gcs_result_path "${GCS_RESULTS_PATH}" \ trigger shell: bash - name: Download ${{ matrix.platform }} Test Results if: always() env: + GCS_RESULTS_PATH: ${{ inputs.gcs_results_path }} RESULTS_DIR: ${{ inputs.results_dir }} run: | set -uxe diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index f7a737857975..23ac114453f9 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -316,6 +316,7 @@ jobs: id: on-device-tests uses: ./.github/actions/on_device_tests with: + gcs_results_path: gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }} results_dir: ${{ env.TEST_RESULTS_DIR }} - name: Process Test Results if: | From 14fcb8cf6e04e72a64f5969be263a9ea8dc96525 Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Thu, 16 Jan 2025 00:04:18 +0000 Subject: [PATCH 19/46] Updated ODT Gateway Client code --- "cobalt/tools/\\" | 413 ++++++++++++++ cobalt/tools/on_device_tests_gateway.proto | 47 +- .../tools/on_device_tests_gateway_client.py | 535 ++++++++++-------- cobalt/tools/on_device_tests_gateway_pb2.py | 297 ++++++++++ .../tools/on_device_tests_gateway_pb2_grpc.py | 65 +++ 5 files changed, 1085 insertions(+), 272 deletions(-) create mode 100644 "cobalt/tools/\\" create mode 100644 cobalt/tools/on_device_tests_gateway_pb2.py create mode 100644 cobalt/tools/on_device_tests_gateway_pb2_grpc.py diff --git "a/cobalt/tools/\\" "b/cobalt/tools/\\" new file mode 100644 index 000000000000..ea587638e087 --- /dev/null +++ "b/cobalt/tools/\\" @@ -0,0 +1,413 @@ +#!/usr/bin/env python3 +# +# Copyright 2022 The Cobalt Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""gRPC On-device Tests Gateway client.""" + +import argparse +import json +import logging +import sys + +import grpc +import on_device_tests_gateway_pb2 +import on_device_tests_gateway_pb2_grpc + + +_WORK_DIR = '/on_device_tests_gateway' + +# Comment out the next three lines for local testing +# _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( +# 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') +_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' + +# Uncomment the next two lines for local testing +_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') +# _ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '12345' + +_ON_DEVICE_OUTPUT_FILES_DIR = '/sdcard/Download' +_CHROMIUM_TEST_ROOT = '/sdcard/chromium_tests_root' + +class OnDeviceTestsGatewayClient(): + """On-device tests Gateway Client class.""" + + def __init__(self): + self.channel = grpc.insecure_channel( + target=f'{_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST}:{_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT}', # pylint:disable=line-too-long + # These options need to match server settings. + options=[('grpc.keepalive_time_ms', 10000), + ('grpc.keepalive_timeout_ms', 5000), + ('grpc.keepalive_permit_without_calls', 1), + ('grpc.http2.max_pings_without_data', 0), + ('grpc.http2.min_time_between_pings_ms', 10000), + ('grpc.http2.min_ping_interval_without_data_ms', 5000)]) + self.stub = on_device_tests_gateway_pb2_grpc.on_device_tests_gatewayStub( + self.channel) + + def run_trigger_command(self, args: argparse.Namespace, test_requests): + """Calls On-Device Tests service and passing given parameters to it. + + Args: + args (Namespace): Arguments passed in command line. + test_requests (list): A list of test requests. + """ + for response_line in self.stub.exec_command( + on_device_tests_gateway_pb2.OnDeviceTestsCommand( + token=args.token, + labels=args.label, + test_requests=test_requests, + )): + + print(response_line.response) + + def run_watch_command(self, workdir: str, args: argparse.Namespace): + """Calls On-Device Tests watch service and passing given parameters to it. + + Args: + workdir (str): Current script workdir. + args (Namespace): Arguments passed in command line. + """ + for response_line in self.stub.exec_watch_command( + on_device_tests_gateway_pb2.OnDeviceTestsWatchCommand( + workdir=workdir, + token=args.token, + change_id=args.change_id, + session_id=args.session_id, + )): + + print(response_line.response) + + +def _read_json_config(filename): + """Reads and parses data from a JSON configuration file. + + Args: + filename: The name of the JSON configuration file. + + Returns: + A list of dictionaries, where each dictionary represents a test + configuration. + """ + try: + with open(filename, 'r') as f: + data = json.load(f) + return data + except FileNotFoundError: + print(f" Config file '{filename}' not found.") + return None + except json.JSONDecodeError: + print(f" Invalid JSON format in '{filename}'.") + return None + + +def _get_gtest_filters(filter_json_dir, gtest_target): + """Retrieves gtest filters for a given target. + + Args: + filter_json_dir: Directory containing filter JSON files. + gtest_target: The name of the gtest target. + + Returns: + A string containing the gtest filters. + """ + gtest_filters = '*' + filter_json_file = f'{filter_json_dir}/{gtest_target}_filter.json' + print(f" gtest_filter_json_file = {filter_json_file}") + filter_data = _read_json_config(filter_json_file) + if filter_data: + print(f" Loaded filter data: {filter_data}") + failing_tests = ':'.join(filter_data.get('failing_tests', [])) + if failing_tests: + gtest_filters += ':-' + failing_tests + print(f" gtest_filters = {gtest_filters}") + else: + print(' This gtest_target does not have gtest_filters specified') + return gtest_filters + + +def _process_test_requests(args): + """Processes test requests from the given arguments. + + Constructs a list of test requests based on the provided arguments, + including test arguments, command arguments, files, parameters, + and device information. + + Args: + args: The parsed command-line arguments. + + Returns: + A list of test request dictionaries. + """ + test_requests = [] + platform_data = _read_json_config(args.platform_json) + + tests_args = [ + f'job_timeout_secs={args.job_timeout_secs}', + f'test_timeout_secs={args.test_timeout_secs}', + f'start_timeout_secs={args.start_timeout_secs}' + ] + + if args.change_id: + tests_args.append(f'change_id={args.change_id}') + if args.test_attempts: + tests_args.append(f'test_attempts={args.test_attempts}') + if args.dimension: + tests_args.extend( + f'dimension_{dimension}' for dimension in args.dimension + ) + + base_params = [f'push_files=test_runtime_deps:{_CHROMIUM_TEST_ROOT}'] + + if args.gcs_result_path: + base_params.append(f'gcs_result_path={args.gcs_result_path}') + + for gtest_target in platform_data['gtest_targets']: + print(f" Processing gtest_target: {gtest_target}") + + apk_file = f"{args.gcs_archive_path}/{gtest_target}-debug.apk" + test_runtime_deps = f"{args.gcs_archive_path}/{gtest_target}_deps.tar.gz" + + files = [ + f'test_apk={apk_file}', + f'build_apk={apk_file}', + f'test_runtime_deps={test_runtime_deps}' + ] + + gtest_params = [ + f'gtest_xml_file_on_device={_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', + f'gcs_result_filename={gtest_target}_result.xml', + f'gcs_log_filename={gtest_target}_log.txt' + ] + + gtest_filter = _get_gtest_filters(args.filter_json_dir, gtest_target) + + test_cmd_args = [ + f'command_line_args=--gtest_output=xml:{_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', + f'--gtest_filter={gtest_filter}' + ] + + test_request = { + 'test_args': tests_args, + 'test_cmd_args': test_cmd_args, + 'files': files, + 'params': base_params + gtest_params, + 'device_type': platform_data.get('test_dimensions', {}).get( + 'gtest_device' + ), + 'device_pool': platform_data.get('test_dimensions', {}).get( + 'gtest_lab' + ), + } + + test_requests.append(test_request) + print(f' Created test_request: {test_request}') + + print(f'test_requests: {test_requests}') + return test_requests + + +def main() -> int: # Add a return type hint + """Main routine for the on-device tests gateway client.""" + + logging.basicConfig( + level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s' + ) + print('Starting main routine') + + parser = argparse.ArgumentParser( + description='Client for interacting with the On-Device Tests gateway.', + epilog=( + 'Example:' + 'python3 -u cobalt/tools/on_device_tests_gateway_client.py' + '--platform_json "${GITHUB_WORKSPACE}/src/.github/config/' + '${{ matrix.platform}}.json"' + '--filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/' + '${{ matrix.platform}}"' + '--token ${GITHUB_TOKEN}' + '--change_id ${GITHUB_PR_NUMBER:-postsubmit}' + '--label builder-${{ matrix.platform }}' + '--label builder_url-${GITHUB_RUN_URL}' + '--label github' + '--label ${GITHUB_EVENT_NAME}' + '--label ${GITHUB_WORKFLOW}' + '--label actor-${GITHUB_ACTOR}' + '--label actor_id-${GITHUB_ACTOR_ID}' + '--label triggering_actor-${GITHUB_TRIGGERING_ACTOR}' + '--label sha-${GITHUB_SHA}' + '--label repository-${GITHUB_REPO}' + '--label author-${GITHUB_PR_HEAD_USER_LOGIN:-' + '$GITHUB_COMMIT_AUTHOR_USERNAME}' + '--label author_id-${GITHUB_PR_HEAD_USER_ID:-' + '$GITHUB_COMMIT_AUTHOR_EMAIL}' + '--dimension host_name=regex:maneki-mhserver-05.*' + '${DIMENSION:+"--dimension" "$DIMENSION"}' + '${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" ' + '"$ON_DEVICE_TEST_ATTEMPTS"}' + '--gcs_archive_path "${GCS_ARTIFACTS_PATH}"' + '--gcs_result_path "${GCS_RESULTS_PATH}"' + 'trigger' + ), + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + + # Authentication + parser.add_argument( + '-t', + '--token', + type=str, + required=True, + help='On Device Tests authentication token', + ) + + # General options + parser.add_argument( + '-i', + '--change_id', + type=str, + help=( + 'ChangeId that triggered this test, if any. Saved with performance' + ' test results.' + ), + ) + + subparsers = parser.add_subparsers( + dest='action', help='On-Device tests commands', required=True + ) + + # Trigger command + trigger_parser = subparsers.add_parser( + 'trigger', + help='Trigger On-Device tests', + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + # Group trigger arguments + trigger_args = trigger_parser.add_argument_group('Trigger Arguments') + trigger_args.add_argument( + '-pf', + '--platform_json', + type=str, + help='Platform-specific JSON file containing the list of target tests.', + ) + trigger_parser.add_argument( + '--filter_json_dir', + type=str, + help='Directory containing filter JSON files for test selection.', + ) + trigger_parser.add_argument( + '-l', + '--label', + type=str, + action='append', + help='Additional labels to assign to the test.', + ) + trigger_parser.add_argument( + '--dimension', + type=str, + action='append', + help=( + 'On-Device Tests dimension used to select a device. ' + 'Must have the following form: =. ' + 'E.G. "release_version=regex:10.*"' + ), + ) + trigger_parser.add_argument( + '--test_attempts', + type=str, + default='1', + help='The maximum number of times a test can retry.', + ) + trigger_args.add_argument( + '-a', + '--archive_path', + type=str, + required=True, + help='Path to Chrobalt archive to be tested. Must be on GCS.', + ) + trigger_parser.add_argument( + '--gcs_result_path', + type=str, + help='GCS URL where test result files should be uploaded.', + ) + trigger_parser.add_argument( + '--job_timeout_sec', + type=str, + default='1800', + help='Timeout in seconds for the job (default: 1800 seconds).', + ) + trigger_parser.add_argument( + '--test_timeout_sec', + type=str, + default='1800', + help='Timeout in seconds for the test (default: 1800 seconds).', + ) + trigger_parser.add_argument( + '--start_timeout_sec', + type=str, + default='180', + help='Timeout in seconds for the test to start (default: 180 seconds).', + ) + + # Watch command + watch_parser = subparsers.add_parser( + 'watch', help='Watch a previously triggered On-Device test' + ) + watch_parser.add_argument( + 'session_id', + type=str, + help=( + 'Session ID of a previously triggered Mobile Harness test. ' + 'The test will be watched until it completes.' + ), + ) + + args = parser.parse_args() + + if not args.platform_json: + print( + "Error: The '--platform_json' argument is required. " + 'Please provide the path to the Platform JSON file.' + ) + exit(1) # Exit with an error code + if not args.filter_json_dir: + print( + "Error: The '--filter_json_dir' argument is required. " + 'Please provide the directory containing filter JSON files.' + ) + exit(1) # Exit with an error code + if not args.gcs_archive_path: + print( + "Error: The '--gcs_archive_path' argument is required. " + 'Please provide the GCS archive path info.' + ) + exit(1) # Exit with an error code + + test_requests = _process_test_requests(args) + client = OnDeviceTestsGatewayClient() + + try: + if args.action == 'trigger': + client.run_trigger_command(args, test_requests) + else: + client.run_watch_command(workdir=_WORK_DIR, args=args) + except grpc.RpcError as e: + logging.exception('gRPC error occurred:') # Log the full traceback + print(f'Error: {e}') + return e.code().value # Return the error code + + return 0 # Indicate successful execution + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/cobalt/tools/on_device_tests_gateway.proto b/cobalt/tools/on_device_tests_gateway.proto index 933b5818faa4..61f3da41f959 100644 --- a/cobalt/tools/on_device_tests_gateway.proto +++ b/cobalt/tools/on_device_tests_gateway.proto @@ -20,38 +20,36 @@ package on_device_tests_gateway; service on_device_tests_gateway { // A dumb proxy RPC service that passes user defined command line options // to the on-device tests gateway and streams back output in real time. - rpc exec_command (OnDeviceTestsCommand) returns (stream OnDeviceTestsResponse) { - } + rpc exec_command(OnDeviceTestsCommand) + returns (stream OnDeviceTestsResponse) {} - rpc exec_watch_command (OnDeviceTestsWatchCommand) returns (stream OnDeviceTestsResponse) { - } + // A dumb proxy RPC service that passes user defined command line options + // to the on-device tests gateway and streams back output in real time. + rpc exec_watch_command(OnDeviceTestsWatchCommand) + returns (stream OnDeviceTestsResponse) {} } // Working directory and command line arguments to be passed to the gateway. message OnDeviceTestsCommand { - string workdir = 1; string token = 2; - string platform = 3; - string archive_path = 4; - repeated string labels = 5; - string change_id = 6; - bool dry_run = 7; - repeated string dimension = 8; - string test_attempts = 9; - string retry_level = 10; - string start_timeout = 11; - string test_timeout = 12; - string gcs_result_path = 13; - repeated ApkTest apk_tests = 14; + repeated string labels = 8; + repeated TestRequest test_requests = 24; } -// apk_test details -message ApkTest { - string test_target = 1; - string apk_path = 2; - string device_model = 3; - string device_pool = 4; - string gtest_filters = 5; +message TestRequest { + // Args picked up by MH, e.g. "name1=value", "name2=value. + repeated string test_args = 1; + // Args sent to test binary/apk, e.g. "--arg1", "--arg2=value". + repeated string test_cmd_args = 2; + // Files to send to device, e.g. "build_apk=/bigstore/bucket/test.apk", + // "test_apk=/bigstore/bucket/test.apk", + repeated string files = 3; + // e.g. "gcs_result_path=gs://some/gcs/path" + repeated string params = 4; + // "sabrina" or "boreal" + string device_type = 5; + // "shared" or "maneki" + string device_pool = 6; } // Working directory and command line arguments to be passed to the gateway. @@ -69,3 +67,4 @@ message OnDeviceTestsResponse { // Next ID: 2 string response = 1; } + diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index 2cfad00758fc..fb258896eab7 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -16,27 +16,25 @@ """gRPC On-device Tests Gateway client.""" import argparse +import json import logging import sys -import os -import json import grpc - import on_device_tests_gateway_pb2 import on_device_tests_gateway_pb2_grpc + _WORK_DIR = '/on_device_tests_gateway' -# Comment out the next three lines for local testing -_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( - 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') +# For local testing, set: _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') +# _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( +# 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') +_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') _ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' -# Uncomment the next two lines for local testing -#_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') -#_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '12345' - +_ON_DEVICE_OUTPUT_FILES_DIR = '/sdcard/Download' +_CHROMIUM_TEST_ROOT = '/sdcard/chromium_tests_root' class OnDeviceTestsGatewayClient(): """On-device tests Gateway Client class.""" @@ -54,27 +52,18 @@ def __init__(self): self.stub = on_device_tests_gateway_pb2_grpc.on_device_tests_gatewayStub( self.channel) - def run_trigger_command(self, workdir: str, args: argparse.Namespace, apk_tests = None): + def run_trigger_command(self, args: argparse.Namespace, test_requests): """Calls On-Device Tests service and passing given parameters to it. Args: - workdir (str): Current script workdir. args (Namespace): Arguments passed in command line. + test_requests (list): A list of test requests. """ for response_line in self.stub.exec_command( on_device_tests_gateway_pb2.OnDeviceTestsCommand( - workdir=workdir, token=args.token, - platform=args.platform, - archive_path=args.archive_path, labels=args.label, - gcs_result_path=args.gcs_result_path, - change_id=args.change_id, - dry_run=args.dry_run, - dimension=args.dimension or [], - test_attempts=args.test_attempts, - retry_level=args.retry_level, - apk_tests=apk_tests, + test_requests=test_requests, )): print(response_line.response) @@ -96,15 +85,16 @@ def run_watch_command(self, workdir: str, args: argparse.Namespace): print(response_line.response) + def _read_json_config(filename): - """ - Reads and parses data from a JSON configuration file. + """Reads and parses data from a JSON configuration file. Args: filename: The name of the JSON configuration file. Returns: - A list of dictionaries, where each dictionary represents a test configuration. + A list of dictionaries, where each dictionary represents a test + configuration. """ try: with open(filename, 'r') as f: @@ -117,258 +107,307 @@ def _read_json_config(filename): print(f" Invalid JSON format in '{filename}'.") return None -def _get_platform_json_file(platform): - """Constructs the path to the platform JSON configuration file. + +def _get_gtest_filters(filter_json_dir, gtest_target): + """Retrieves gtest filters for a given target. Args: - platform: The name of the platform. + filter_json_dir: Directory containing filter JSON files. + gtest_target: The name of the gtest target. Returns: - The absolute path to the platform JSON file. + A string containing the gtest filters. """ - return os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "..", - ".github", - "config", - f"{platform}.json" - ) - -def _get_tests_filter_json_file(platform, gtest_target): - """Constructs the path to the gtest filter JSON file. + gtest_filters = '*' + filter_json_file = f'{filter_json_dir}/{gtest_target}_filter.json' + print(f" gtest_filter_json_file = {filter_json_file}") + filter_data = _read_json_config(filter_json_file) + if filter_data: + print(f" Loaded filter data: {filter_data}") + failing_tests = ':'.join(filter_data.get('failing_tests', [])) + if failing_tests: + gtest_filters += ':-' + failing_tests + print(f" gtest_filters = {gtest_filters}") + else: + print(' This gtest_target does not have gtest_filters specified') + return gtest_filters + + +def _process_test_requests(args): + """Processes test requests from the given arguments. + + Constructs a list of test requests based on the provided arguments, + including test arguments, command arguments, files, parameters, + and device information. Args: - platform: The name of the platform. - gtest_target: The name of the gtest target. + args: The parsed command-line arguments. Returns: - The absolute path to the gtest filter JSON file. + A list of test request dictionaries. """ - return os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "..", - "cobalt", - "testing", - platform, - f"{gtest_target}_filter.json" - ) + test_requests = [] + platform_data = _read_json_config(args.platform_json) + + tests_args = [ + f'job_timeout_secs={args.job_timeout_secs}', + f'test_timeout_secs={args.test_timeout_secs}', + f'start_timeout_secs={args.start_timeout_secs}' + ] + + if args.change_id: + tests_args.append(f'change_id={args.change_id}') + if args.test_attempts: + tests_args.append(f'test_attempts={args.test_attempts}') + if args.dimension: + tests_args.extend( + f'dimension_{dimension}' for dimension in args.dimension + ) -def _process_apk_tests(args): - """Processes APK tests based on provided arguments. + base_params = [f'push_files=test_runtime_deps:{_CHROMIUM_TEST_ROOT}'] - Args: - args: An argparse.Namespace object containing the following attributes: - platform: The platform for the tests. - platform_json: Optional path to a platform JSON file. - blaze_targets: A list of Blaze targets. - archive_path: Path to the archive containing APKs. - - Returns: - A list of dictionaries, where each dictionary represents an APK test - with keys like "test_target", "device_model", "device_pool", - "apk_path", and "gtest_filters". - """ + if args.gcs_result_path: + base_params.append(f'gcs_result_path={args.gcs_result_path}') - apk_tests = [] - platform_json_file = args.platform_json or _default_platform_json_file(args.platform) - print(f"The platform_json_file is '{platform_json_file}'") - platform_data = _read_json_config(platform_json_file) - print(f"Loaded platform data: {platform_data}") # Added verbosity - - for target in args.blaze_targets: - print(f"Processing Blaze target: {target}") # Added verbosity - for gtest_target in platform_data["gtest_targets"]: - print(f" Processing gtest_target: {gtest_target}") # Added verbosity - apk_test = { - "test_target": target, - "device_model": platform_data["gtest_device"], - "device_pool": platform_data["gtest_lab"], - "apk_path": f"{args.archive_path}/{gtest_target}-debug.apk", - "gtest_filters": _get_gtest_filters(args.platform, gtest_target) - } - apk_tests.append(apk_test) - print(f" Created apk_test: {apk_test}") # Added verbosity - - print(f"apk_tests: {apk_tests}") - return apk_tests - - -def _get_gtest_filters(platform, gtest_target): - """Retrieves gtest filters for a given target. + for gtest_target in platform_data['gtest_targets']: + print(f" Processing gtest_target: {gtest_target}") - Args: - platform: The platform for the tests. - gtest_target: The name of the gtest target. + apk_file = f"{args.gcs_archive_path}/{gtest_target}-debug.apk" + test_runtime_deps = f"{args.gcs_archive_path}/{gtest_target}_deps.tar.gz" - Returns: - A string representing the gtest filters. - """ + files = [ + f'test_apk={apk_file}', + f'build_apk={apk_file}', + f'test_runtime_deps={test_runtime_deps}' + ] - gtest_filters = "*" - filter_json_file = _get_tests_filter_json_file(platform, gtest_target) - print(f" gtest_filter_json_file = {filter_json_file}") - filter_data = _read_json_config(filter_json_file) - if filter_data: - print(f" Loaded filter data: {filter_data}") # Added verbosity - failing_tests = ":".join(filter_data.get("failing_tests", [])) - if failing_tests: - gtest_filters += ":-" + failing_tests - print(f" gtest_filters = {gtest_filters}") - else: - print(f" This gtest_target does not have gtest_filters specified") - return gtest_filters + gtest_params = [ + f'gtest_xml_file_on_device={_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', + f'gcs_result_filename={gtest_target}_result.xml', + f'gcs_log_filename={gtest_target}_log.txt' + ] + gtest_filter = _get_gtest_filters(args.filter_json_dir, gtest_target) -def main(): - """Main routine for the on-device tests gateway client.""" + test_cmd_args = [ + f'command_line_args=--gtest_output=xml:{_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', + f'--gtest_filter={gtest_filter}' + ] - logging.basicConfig( - level=logging.INFO, - format='[%(filename)s:%(lineno)s] %(message)s' - ) - print('Starting main routine') - - parser = argparse.ArgumentParser( - description="Client for interacting with the On-Device Tests gateway.", - epilog=( - 'Example: ./on_device_tests_gateway_client.py trigger ' - '--token token1 ' - '--platform android-arm ' - '--archive_path /bigstore/yt-temp ' - '--blaze_targets //experimental/cobalt/chrobalt_poc:chrobalt_unit_tests_maneki_sabrina //experimental/cobalt/chrobalt_poc:chrobalt_unit_tests_shared_boreal ' - '--dimension host_name=regex:maneki-mhserver-05.*' + print(f" test dimensions is: {platform_data.get('test_dimensions', {})}") + + test_request = { + 'test_args': tests_args, + 'test_cmd_args': test_cmd_args, + 'files': files, + 'params': base_params + gtest_params, + 'device_type': platform_data.get('test_dimensions', {}).get( + 'gtest_device' ), - formatter_class=argparse.RawDescriptionHelpFormatter - ) + 'device_pool': platform_data.get('test_dimensions', {}).get( + 'gtest_lab' + ), + } - # Authentication - parser.add_argument( - '-t', - '--token', - type=str, - required=True, - help='On Device Tests authentication token' - ) + test_requests.append(test_request) + print(f' Created test_request: {test_request}') - # General options - parser.add_argument( - '--dry_run', - action='store_true', - help='Show what would be done without actually doing it.' - ) - parser.add_argument( - '-i', - '--change_id', - type=str, - help='ChangeId that triggered this test, if any. Saved with performance test results.' - ) + print(f'test_requests: {test_requests}') + return test_requests - subparsers = parser.add_subparsers( - dest='action', - help='On-Device tests commands', - required=True - ) - # Trigger command - trigger_parser = subparsers.add_parser( - 'trigger', - help='Trigger On-Device tests', - formatter_class=argparse.ArgumentDefaultsHelpFormatter - ) - trigger_parser.add_argument( - '-p', - '--platform', - type=str, - required=True, - help='Platform this test was built for.' - ) - trigger_parser.add_argument( - '-pf', - '--platform_json', - type=str, - help='Platform-specific JSON file containing the list of target tests.' - ) - trigger_parser.add_argument( - '-a', - '--archive_path', - type=str, - required=True, - help='Path to Chrobalt archive to be tested. Must be on GCS.' - ) - trigger_parser.add_argument( - '-l', - '--label', - type=str, - action='append', - default=[], - help='Additional labels to assign to the test.' - ) - trigger_parser.add_argument( - '--gcs_result_path', - type=str, - help='GCS URL where test result files should be uploaded.' - ) - trigger_parser.add_argument( - '--dimension', - type=str, - action='append', - help=( - 'On-Device Tests dimension used to select a device. ' - 'Must have the following form: =. ' - 'E.G. "release_version=regex:10.*"' - ) - ) - trigger_parser.add_argument( - '--test_attempts', - type=str, - default='1', - help='The maximum number of times a test could retry.' +def main() -> int: # Add a return type hint + """Main routine for the on-device tests gateway client.""" + + logging.basicConfig( + level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s' + ) + print('Starting main routine') + + parser = argparse.ArgumentParser( + description='Client for interacting with the On-Device Tests gateway.', + epilog=( + 'Example:' + 'python3 -u cobalt/tools/on_device_tests_gateway_client.py' + '--platform_json "${GITHUB_WORKSPACE}/src/.github/config/' + '${{ matrix.platform}}.json"' + '--filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/' + '${{ matrix.platform}}"' + '--token ${GITHUB_TOKEN}' + '--change_id ${GITHUB_PR_NUMBER:-postsubmit}' + '--label builder-${{ matrix.platform }}' + '--label builder_url-${GITHUB_RUN_URL}' + '--label github' + '--label ${GITHUB_EVENT_NAME}' + '--label ${GITHUB_WORKFLOW}' + '--label actor-${GITHUB_ACTOR}' + '--label actor_id-${GITHUB_ACTOR_ID}' + '--label triggering_actor-${GITHUB_TRIGGERING_ACTOR}' + '--label sha-${GITHUB_SHA}' + '--label repository-${GITHUB_REPO}' + '--label author-${GITHUB_PR_HEAD_USER_LOGIN:-' + '$GITHUB_COMMIT_AUTHOR_USERNAME}' + '--label author_id-${GITHUB_PR_HEAD_USER_ID:-' + '$GITHUB_COMMIT_AUTHOR_EMAIL}' + '--dimension host_name=regex:maneki-mhserver-05.*' + '${DIMENSION:+"--dimension" "$DIMENSION"}' + '${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" ' + '"$ON_DEVICE_TEST_ATTEMPTS"}' + '--gcs_archive_path "${GCS_ARTIFACTS_PATH}"' + '--gcs_result_path "${GCS_RESULTS_PATH}"' + 'trigger' + ), + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + + # Authentication + parser.add_argument( + '-t', + '--token', + type=str, + required=True, + help='On Device Tests authentication token', + ) + + # General options + parser.add_argument( + '-i', + '--change_id', + type=str, + help=( + 'ChangeId that triggered this test, if any. Saved with performance' + ' test results.' + ), + ) + + subparsers = parser.add_subparsers( + dest='action', help='On-Device tests commands', required=True + ) + + # Trigger command + trigger_parser = subparsers.add_parser( + 'trigger', + help='Trigger On-Device tests', + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + # Group trigger arguments + trigger_args = trigger_parser.add_argument_group('Trigger Arguments') + trigger_args.add_argument( + '-pf', + '--platform_json', + type=str, + required=True, + help='Platform-specific JSON file containing the list of target tests.', + ) + trigger_parser.add_argument( + '--filter_json_dir', + type=str, + required=True, + help='Directory containing filter JSON files for test selection.', + ) + trigger_parser.add_argument( + '-l', + '--label', + type=str, + action='append', + help='Additional labels to assign to the test.', + ) + trigger_parser.add_argument( + '--dimension', + type=str, + action='append', + help=( + 'On-Device Tests dimension used to select a device. ' + 'Must have the following form: =. ' + 'E.G. "release_version=regex:10.*"' + ), + ) + trigger_parser.add_argument( + '--test_attempts', + type=str, + default='1', + help='The maximum number of times a test can retry.', + ) + trigger_args.add_argument( + '-a', + '--gcs_archive_path', + type=str, + required=True, + help='Path to Chrobalt archive to be tested. Must be on GCS.', + ) + trigger_parser.add_argument( + '--gcs_result_path', + type=str, + help='GCS URL where test result files should be uploaded.', + ) + trigger_parser.add_argument( + '--job_timeout_secs', + type=str, + default='1800', + help='Timeout in seconds for the job (default: 1800 seconds).', + ) + trigger_parser.add_argument( + '--test_timeout_secs', + type=str, + default='1800', + help='Timeout in seconds for the test (default: 1800 seconds).', + ) + trigger_parser.add_argument( + '--start_timeout_secs', + type=str, + default='180', + help='Timeout in seconds for the test to start (default: 180 seconds).', + ) + + # Watch command + watch_parser = subparsers.add_parser( + 'watch', help='Watch a previously triggered On-Device test' + ) + watch_parser.add_argument( + 'session_id', + type=str, + help=( + 'Session ID of a previously triggered Mobile Harness test. ' + 'The test will be watched until it completes.' + ), + ) + + args = parser.parse_args() + + if not args.platform_json: + print( + "Error: The '--platform_json' argument is required. " + 'Please provide the path to the Platform JSON file.' ) - trigger_parser.add_argument( - '--blaze_targets', - nargs="+", - type=str, - required=True, - help='A list of Blaze targets to run.' + exit(1) # Exit with an error code + if not args.filter_json_dir: + print( + "Error: The '--filter_json_dir' argument is required. " + 'Please provide the directory containing filter JSON files.' ) - trigger_parser.add_argument( - '--retry_level', - type=str, - default='ERROR', - choices=['ERROR', 'FAIL'], - help=( - 'The retry level of Mobile Harness job. ' - 'ERROR to retry for MH errors, ' - 'FAIL to retry for failing tests (and MH errors).' - ) + exit(1) # Exit with an error code + if not args.gcs_archive_path: + print( + "Error: The '--gcs_archive_path' argument is required. " + 'Please provide the GCS archive path info.' ) + exit(1) # Exit with an error code - # Watch command - watch_parser = subparsers.add_parser( - 'watch', - help='Watch a previously triggered On-Device test' - ) - watch_parser.add_argument( - 'session_id', - type=str, - help=( - 'Session ID of a previously triggered Mobile Harness test. ' - 'The test will be watched until it completes.' - ) - ) + test_requests = _process_test_requests(args) + client = OnDeviceTestsGatewayClient() + + try: + if args.action == 'trigger': + client.run_trigger_command(args, test_requests) + else: + client.run_watch_command(workdir=_WORK_DIR, args=args) + except grpc.RpcError as e: + logging.exception('gRPC error occurred:') # Log the full traceback + print(f'Error: {e}') + return e.code().value # Return the error code - args = parser.parse_args() - apk_tests = _process_apk_tests(args) - - client = OnDeviceTestsGatewayClient() - try: - if args.action == 'trigger': - client.run_trigger_command(workdir=_WORK_DIR, args=args, apk_tests=apk_tests) - else: - client.run_watch_command(workdir=_WORK_DIR, args=args) - except grpc.RpcError as e: - print(e) - return e.code().value + return 0 # Indicate successful execution if __name__ == '__main__': diff --git a/cobalt/tools/on_device_tests_gateway_pb2.py b/cobalt/tools/on_device_tests_gateway_pb2.py new file mode 100644 index 000000000000..ca42ce7d76f7 --- /dev/null +++ b/cobalt/tools/on_device_tests_gateway_pb2.py @@ -0,0 +1,297 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: on_device_tests_gateway.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='on_device_tests_gateway.proto', + package='on_device_tests_gateway', + syntax='proto3', + serialized_pb=_b('\n\x1don_device_tests_gateway.proto\x12\x17on_device_tests_gateway\"r\n\x14OnDeviceTestsCommand\x12\r\n\x05token\x18\x02 \x01(\t\x12\x0e\n\x06labels\x18\x08 \x03(\t\x12;\n\rtest_requests\x18\x18 \x03(\x0b\x32$.on_device_tests_gateway.TestRequest\"\x80\x01\n\x0bTestRequest\x12\x11\n\ttest_args\x18\x01 \x03(\t\x12\x15\n\rtest_cmd_args\x18\x02 \x03(\t\x12\r\n\x05\x66iles\x18\x03 \x03(\t\x12\x0e\n\x06params\x18\x04 \x03(\t\x12\x13\n\x0b\x64\x65vice_type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x65vice_pool\x18\x06 \x01(\t\"s\n\x19OnDeviceTestsWatchCommand\x12\x0f\n\x07workdir\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x12\n\nsession_id\x18\x03 \x01(\t\x12\x11\n\tchange_id\x18\x04 \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x05 \x01(\x08\")\n\x15OnDeviceTestsResponse\x12\x10\n\x08response\x18\x01 \x01(\t2\x8a\x02\n\x17on_device_tests_gateway\x12q\n\x0c\x65xec_command\x12-.on_device_tests_gateway.OnDeviceTestsCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x12|\n\x12\x65xec_watch_command\x12\x32.on_device_tests_gateway.OnDeviceTestsWatchCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x62\x06proto3') +) + + + + +_ONDEVICETESTSCOMMAND = _descriptor.Descriptor( + name='OnDeviceTestsCommand', + full_name='on_device_tests_gateway.OnDeviceTestsCommand', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='token', full_name='on_device_tests_gateway.OnDeviceTestsCommand.token', index=0, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='labels', full_name='on_device_tests_gateway.OnDeviceTestsCommand.labels', index=1, + number=8, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='test_requests', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_requests', index=2, + number=24, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=58, + serialized_end=172, +) + + +_TESTREQUEST = _descriptor.Descriptor( + name='TestRequest', + full_name='on_device_tests_gateway.TestRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='test_args', full_name='on_device_tests_gateway.TestRequest.test_args', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='test_cmd_args', full_name='on_device_tests_gateway.TestRequest.test_cmd_args', index=1, + number=2, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='files', full_name='on_device_tests_gateway.TestRequest.files', index=2, + number=3, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='params', full_name='on_device_tests_gateway.TestRequest.params', index=3, + number=4, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='device_type', full_name='on_device_tests_gateway.TestRequest.device_type', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='device_pool', full_name='on_device_tests_gateway.TestRequest.device_pool', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=175, + serialized_end=303, +) + + +_ONDEVICETESTSWATCHCOMMAND = _descriptor.Descriptor( + name='OnDeviceTestsWatchCommand', + full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='workdir', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.workdir', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='token', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.token', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='session_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.session_id', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='change_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.change_id', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='dry_run', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.dry_run', index=4, + number=5, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=305, + serialized_end=420, +) + + +_ONDEVICETESTSRESPONSE = _descriptor.Descriptor( + name='OnDeviceTestsResponse', + full_name='on_device_tests_gateway.OnDeviceTestsResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='response', full_name='on_device_tests_gateway.OnDeviceTestsResponse.response', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=422, + serialized_end=463, +) + +_ONDEVICETESTSCOMMAND.fields_by_name['test_requests'].message_type = _TESTREQUEST +DESCRIPTOR.message_types_by_name['OnDeviceTestsCommand'] = _ONDEVICETESTSCOMMAND +DESCRIPTOR.message_types_by_name['TestRequest'] = _TESTREQUEST +DESCRIPTOR.message_types_by_name['OnDeviceTestsWatchCommand'] = _ONDEVICETESTSWATCHCOMMAND +DESCRIPTOR.message_types_by_name['OnDeviceTestsResponse'] = _ONDEVICETESTSRESPONSE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +OnDeviceTestsCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsCommand', (_message.Message,), dict( + DESCRIPTOR = _ONDEVICETESTSCOMMAND, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsCommand) + )) +_sym_db.RegisterMessage(OnDeviceTestsCommand) + +TestRequest = _reflection.GeneratedProtocolMessageType('TestRequest', (_message.Message,), dict( + DESCRIPTOR = _TESTREQUEST, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.TestRequest) + )) +_sym_db.RegisterMessage(TestRequest) + +OnDeviceTestsWatchCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsWatchCommand', (_message.Message,), dict( + DESCRIPTOR = _ONDEVICETESTSWATCHCOMMAND, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsWatchCommand) + )) +_sym_db.RegisterMessage(OnDeviceTestsWatchCommand) + +OnDeviceTestsResponse = _reflection.GeneratedProtocolMessageType('OnDeviceTestsResponse', (_message.Message,), dict( + DESCRIPTOR = _ONDEVICETESTSRESPONSE, + __module__ = 'on_device_tests_gateway_pb2' + # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsResponse) + )) +_sym_db.RegisterMessage(OnDeviceTestsResponse) + + + +_ON_DEVICE_TESTS_GATEWAY = _descriptor.ServiceDescriptor( + name='on_device_tests_gateway', + full_name='on_device_tests_gateway.on_device_tests_gateway', + file=DESCRIPTOR, + index=0, + options=None, + serialized_start=466, + serialized_end=732, + methods=[ + _descriptor.MethodDescriptor( + name='exec_command', + full_name='on_device_tests_gateway.on_device_tests_gateway.exec_command', + index=0, + containing_service=None, + input_type=_ONDEVICETESTSCOMMAND, + output_type=_ONDEVICETESTSRESPONSE, + options=None, + ), + _descriptor.MethodDescriptor( + name='exec_watch_command', + full_name='on_device_tests_gateway.on_device_tests_gateway.exec_watch_command', + index=1, + containing_service=None, + input_type=_ONDEVICETESTSWATCHCOMMAND, + output_type=_ONDEVICETESTSRESPONSE, + options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_ON_DEVICE_TESTS_GATEWAY) + +DESCRIPTOR.services_by_name['on_device_tests_gateway'] = _ON_DEVICE_TESTS_GATEWAY + +# @@protoc_insertion_point(module_scope) diff --git a/cobalt/tools/on_device_tests_gateway_pb2_grpc.py b/cobalt/tools/on_device_tests_gateway_pb2_grpc.py new file mode 100644 index 000000000000..284d31d4b2ca --- /dev/null +++ b/cobalt/tools/on_device_tests_gateway_pb2_grpc.py @@ -0,0 +1,65 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import on_device_tests_gateway_pb2 as on__device__tests__gateway__pb2 + + +class on_device_tests_gatewayStub(object): + """Interface exported by the server. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.exec_command = channel.unary_stream( + '/on_device_tests_gateway.on_device_tests_gateway/exec_command', + request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.SerializeToString, + response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, + ) + self.exec_watch_command = channel.unary_stream( + '/on_device_tests_gateway.on_device_tests_gateway/exec_watch_command', + request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.SerializeToString, + response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, + ) + + +class on_device_tests_gatewayServicer(object): + """Interface exported by the server. + """ + + def exec_command(self, request, context): + """A dumb proxy RPC service that passes user defined command line options + to the on-device tests gateway and streams back output in real time. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def exec_watch_command(self, request, context): + """A dumb proxy RPC service that passes user defined command line options + to the on-device tests gateway and streams back output in real time. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_on_device_tests_gatewayServicer_to_server(servicer, server): + rpc_method_handlers = { + 'exec_command': grpc.unary_stream_rpc_method_handler( + servicer.exec_command, + request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.FromString, + response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, + ), + 'exec_watch_command': grpc.unary_stream_rpc_method_handler( + servicer.exec_watch_command, + request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.FromString, + response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'on_device_tests_gateway.on_device_tests_gateway', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) From 2f09d392dece1a268ef033dc4e9154307adfacce Mon Sep 17 00:00:00 2001 From: Felipe Mira Date: Thu, 16 Jan 2025 21:50:15 +0000 Subject: [PATCH 20/46] New Modifications to ODT Gateway code --- .../tools/on_device_tests_gateway_client.py | 8 +- cobalt/tools/on_device_tests_gateway_pb2.py | 297 ------------------ .../tools/on_device_tests_gateway_pb2_grpc.py | 65 ---- 3 files changed, 2 insertions(+), 368 deletions(-) delete mode 100644 cobalt/tools/on_device_tests_gateway_pb2.py delete mode 100644 cobalt/tools/on_device_tests_gateway_pb2_grpc.py diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index fb258896eab7..4d0777bd3491 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -28,9 +28,8 @@ _WORK_DIR = '/on_device_tests_gateway' # For local testing, set: _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') -# _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( -# 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') -_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') +_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( + 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') _ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' _ON_DEVICE_OUTPUT_FILES_DIR = '/sdcard/Download' @@ -194,8 +193,6 @@ def _process_test_requests(args): f'--gtest_filter={gtest_filter}' ] - print(f" test dimensions is: {platform_data.get('test_dimensions', {})}") - test_request = { 'test_args': tests_args, 'test_cmd_args': test_cmd_args, @@ -404,7 +401,6 @@ def main() -> int: # Add a return type hint client.run_watch_command(workdir=_WORK_DIR, args=args) except grpc.RpcError as e: logging.exception('gRPC error occurred:') # Log the full traceback - print(f'Error: {e}') return e.code().value # Return the error code return 0 # Indicate successful execution diff --git a/cobalt/tools/on_device_tests_gateway_pb2.py b/cobalt/tools/on_device_tests_gateway_pb2.py deleted file mode 100644 index ca42ce7d76f7..000000000000 --- a/cobalt/tools/on_device_tests_gateway_pb2.py +++ /dev/null @@ -1,297 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: on_device_tests_gateway.proto - -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor.FileDescriptor( - name='on_device_tests_gateway.proto', - package='on_device_tests_gateway', - syntax='proto3', - serialized_pb=_b('\n\x1don_device_tests_gateway.proto\x12\x17on_device_tests_gateway\"r\n\x14OnDeviceTestsCommand\x12\r\n\x05token\x18\x02 \x01(\t\x12\x0e\n\x06labels\x18\x08 \x03(\t\x12;\n\rtest_requests\x18\x18 \x03(\x0b\x32$.on_device_tests_gateway.TestRequest\"\x80\x01\n\x0bTestRequest\x12\x11\n\ttest_args\x18\x01 \x03(\t\x12\x15\n\rtest_cmd_args\x18\x02 \x03(\t\x12\r\n\x05\x66iles\x18\x03 \x03(\t\x12\x0e\n\x06params\x18\x04 \x03(\t\x12\x13\n\x0b\x64\x65vice_type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x65vice_pool\x18\x06 \x01(\t\"s\n\x19OnDeviceTestsWatchCommand\x12\x0f\n\x07workdir\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x12\n\nsession_id\x18\x03 \x01(\t\x12\x11\n\tchange_id\x18\x04 \x01(\t\x12\x0f\n\x07\x64ry_run\x18\x05 \x01(\x08\")\n\x15OnDeviceTestsResponse\x12\x10\n\x08response\x18\x01 \x01(\t2\x8a\x02\n\x17on_device_tests_gateway\x12q\n\x0c\x65xec_command\x12-.on_device_tests_gateway.OnDeviceTestsCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x12|\n\x12\x65xec_watch_command\x12\x32.on_device_tests_gateway.OnDeviceTestsWatchCommand\x1a..on_device_tests_gateway.OnDeviceTestsResponse\"\x00\x30\x01\x62\x06proto3') -) - - - - -_ONDEVICETESTSCOMMAND = _descriptor.Descriptor( - name='OnDeviceTestsCommand', - full_name='on_device_tests_gateway.OnDeviceTestsCommand', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='token', full_name='on_device_tests_gateway.OnDeviceTestsCommand.token', index=0, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='labels', full_name='on_device_tests_gateway.OnDeviceTestsCommand.labels', index=1, - number=8, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='test_requests', full_name='on_device_tests_gateway.OnDeviceTestsCommand.test_requests', index=2, - number=24, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=58, - serialized_end=172, -) - - -_TESTREQUEST = _descriptor.Descriptor( - name='TestRequest', - full_name='on_device_tests_gateway.TestRequest', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='test_args', full_name='on_device_tests_gateway.TestRequest.test_args', index=0, - number=1, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='test_cmd_args', full_name='on_device_tests_gateway.TestRequest.test_cmd_args', index=1, - number=2, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='files', full_name='on_device_tests_gateway.TestRequest.files', index=2, - number=3, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='params', full_name='on_device_tests_gateway.TestRequest.params', index=3, - number=4, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='device_type', full_name='on_device_tests_gateway.TestRequest.device_type', index=4, - number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='device_pool', full_name='on_device_tests_gateway.TestRequest.device_pool', index=5, - number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=175, - serialized_end=303, -) - - -_ONDEVICETESTSWATCHCOMMAND = _descriptor.Descriptor( - name='OnDeviceTestsWatchCommand', - full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='workdir', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.workdir', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='token', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.token', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='session_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.session_id', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='change_id', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.change_id', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='dry_run', full_name='on_device_tests_gateway.OnDeviceTestsWatchCommand.dry_run', index=4, - number=5, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=305, - serialized_end=420, -) - - -_ONDEVICETESTSRESPONSE = _descriptor.Descriptor( - name='OnDeviceTestsResponse', - full_name='on_device_tests_gateway.OnDeviceTestsResponse', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='response', full_name='on_device_tests_gateway.OnDeviceTestsResponse.response', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=422, - serialized_end=463, -) - -_ONDEVICETESTSCOMMAND.fields_by_name['test_requests'].message_type = _TESTREQUEST -DESCRIPTOR.message_types_by_name['OnDeviceTestsCommand'] = _ONDEVICETESTSCOMMAND -DESCRIPTOR.message_types_by_name['TestRequest'] = _TESTREQUEST -DESCRIPTOR.message_types_by_name['OnDeviceTestsWatchCommand'] = _ONDEVICETESTSWATCHCOMMAND -DESCRIPTOR.message_types_by_name['OnDeviceTestsResponse'] = _ONDEVICETESTSRESPONSE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -OnDeviceTestsCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsCommand', (_message.Message,), dict( - DESCRIPTOR = _ONDEVICETESTSCOMMAND, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsCommand) - )) -_sym_db.RegisterMessage(OnDeviceTestsCommand) - -TestRequest = _reflection.GeneratedProtocolMessageType('TestRequest', (_message.Message,), dict( - DESCRIPTOR = _TESTREQUEST, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.TestRequest) - )) -_sym_db.RegisterMessage(TestRequest) - -OnDeviceTestsWatchCommand = _reflection.GeneratedProtocolMessageType('OnDeviceTestsWatchCommand', (_message.Message,), dict( - DESCRIPTOR = _ONDEVICETESTSWATCHCOMMAND, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsWatchCommand) - )) -_sym_db.RegisterMessage(OnDeviceTestsWatchCommand) - -OnDeviceTestsResponse = _reflection.GeneratedProtocolMessageType('OnDeviceTestsResponse', (_message.Message,), dict( - DESCRIPTOR = _ONDEVICETESTSRESPONSE, - __module__ = 'on_device_tests_gateway_pb2' - # @@protoc_insertion_point(class_scope:on_device_tests_gateway.OnDeviceTestsResponse) - )) -_sym_db.RegisterMessage(OnDeviceTestsResponse) - - - -_ON_DEVICE_TESTS_GATEWAY = _descriptor.ServiceDescriptor( - name='on_device_tests_gateway', - full_name='on_device_tests_gateway.on_device_tests_gateway', - file=DESCRIPTOR, - index=0, - options=None, - serialized_start=466, - serialized_end=732, - methods=[ - _descriptor.MethodDescriptor( - name='exec_command', - full_name='on_device_tests_gateway.on_device_tests_gateway.exec_command', - index=0, - containing_service=None, - input_type=_ONDEVICETESTSCOMMAND, - output_type=_ONDEVICETESTSRESPONSE, - options=None, - ), - _descriptor.MethodDescriptor( - name='exec_watch_command', - full_name='on_device_tests_gateway.on_device_tests_gateway.exec_watch_command', - index=1, - containing_service=None, - input_type=_ONDEVICETESTSWATCHCOMMAND, - output_type=_ONDEVICETESTSRESPONSE, - options=None, - ), -]) -_sym_db.RegisterServiceDescriptor(_ON_DEVICE_TESTS_GATEWAY) - -DESCRIPTOR.services_by_name['on_device_tests_gateway'] = _ON_DEVICE_TESTS_GATEWAY - -# @@protoc_insertion_point(module_scope) diff --git a/cobalt/tools/on_device_tests_gateway_pb2_grpc.py b/cobalt/tools/on_device_tests_gateway_pb2_grpc.py deleted file mode 100644 index 284d31d4b2ca..000000000000 --- a/cobalt/tools/on_device_tests_gateway_pb2_grpc.py +++ /dev/null @@ -1,65 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -import grpc - -import on_device_tests_gateway_pb2 as on__device__tests__gateway__pb2 - - -class on_device_tests_gatewayStub(object): - """Interface exported by the server. - """ - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.exec_command = channel.unary_stream( - '/on_device_tests_gateway.on_device_tests_gateway/exec_command', - request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.SerializeToString, - response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, - ) - self.exec_watch_command = channel.unary_stream( - '/on_device_tests_gateway.on_device_tests_gateway/exec_watch_command', - request_serializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.SerializeToString, - response_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.FromString, - ) - - -class on_device_tests_gatewayServicer(object): - """Interface exported by the server. - """ - - def exec_command(self, request, context): - """A dumb proxy RPC service that passes user defined command line options - to the on-device tests gateway and streams back output in real time. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def exec_watch_command(self, request, context): - """A dumb proxy RPC service that passes user defined command line options - to the on-device tests gateway and streams back output in real time. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_on_device_tests_gatewayServicer_to_server(servicer, server): - rpc_method_handlers = { - 'exec_command': grpc.unary_stream_rpc_method_handler( - servicer.exec_command, - request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsCommand.FromString, - response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, - ), - 'exec_watch_command': grpc.unary_stream_rpc_method_handler( - servicer.exec_watch_command, - request_deserializer=on__device__tests__gateway__pb2.OnDeviceTestsWatchCommand.FromString, - response_serializer=on__device__tests__gateway__pb2.OnDeviceTestsResponse.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'on_device_tests_gateway.on_device_tests_gateway', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) From 22ba293658691752cc8ea27b3c63f56706541d67 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Thu, 16 Jan 2025 14:27:28 -0800 Subject: [PATCH 21/46] Deleting erroneous file --- "cobalt/tools/\\" | 413 ---------------------------------------------- 1 file changed, 413 deletions(-) delete mode 100644 "cobalt/tools/\\" diff --git "a/cobalt/tools/\\" "b/cobalt/tools/\\" deleted file mode 100644 index ea587638e087..000000000000 --- "a/cobalt/tools/\\" +++ /dev/null @@ -1,413 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022 The Cobalt Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""gRPC On-device Tests Gateway client.""" - -import argparse -import json -import logging -import sys - -import grpc -import on_device_tests_gateway_pb2 -import on_device_tests_gateway_pb2_grpc - - -_WORK_DIR = '/on_device_tests_gateway' - -# Comment out the next three lines for local testing -# _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ( -# 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') -_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' - -# Uncomment the next two lines for local testing -_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') -# _ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '12345' - -_ON_DEVICE_OUTPUT_FILES_DIR = '/sdcard/Download' -_CHROMIUM_TEST_ROOT = '/sdcard/chromium_tests_root' - -class OnDeviceTestsGatewayClient(): - """On-device tests Gateway Client class.""" - - def __init__(self): - self.channel = grpc.insecure_channel( - target=f'{_ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST}:{_ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT}', # pylint:disable=line-too-long - # These options need to match server settings. - options=[('grpc.keepalive_time_ms', 10000), - ('grpc.keepalive_timeout_ms', 5000), - ('grpc.keepalive_permit_without_calls', 1), - ('grpc.http2.max_pings_without_data', 0), - ('grpc.http2.min_time_between_pings_ms', 10000), - ('grpc.http2.min_ping_interval_without_data_ms', 5000)]) - self.stub = on_device_tests_gateway_pb2_grpc.on_device_tests_gatewayStub( - self.channel) - - def run_trigger_command(self, args: argparse.Namespace, test_requests): - """Calls On-Device Tests service and passing given parameters to it. - - Args: - args (Namespace): Arguments passed in command line. - test_requests (list): A list of test requests. - """ - for response_line in self.stub.exec_command( - on_device_tests_gateway_pb2.OnDeviceTestsCommand( - token=args.token, - labels=args.label, - test_requests=test_requests, - )): - - print(response_line.response) - - def run_watch_command(self, workdir: str, args: argparse.Namespace): - """Calls On-Device Tests watch service and passing given parameters to it. - - Args: - workdir (str): Current script workdir. - args (Namespace): Arguments passed in command line. - """ - for response_line in self.stub.exec_watch_command( - on_device_tests_gateway_pb2.OnDeviceTestsWatchCommand( - workdir=workdir, - token=args.token, - change_id=args.change_id, - session_id=args.session_id, - )): - - print(response_line.response) - - -def _read_json_config(filename): - """Reads and parses data from a JSON configuration file. - - Args: - filename: The name of the JSON configuration file. - - Returns: - A list of dictionaries, where each dictionary represents a test - configuration. - """ - try: - with open(filename, 'r') as f: - data = json.load(f) - return data - except FileNotFoundError: - print(f" Config file '{filename}' not found.") - return None - except json.JSONDecodeError: - print(f" Invalid JSON format in '{filename}'.") - return None - - -def _get_gtest_filters(filter_json_dir, gtest_target): - """Retrieves gtest filters for a given target. - - Args: - filter_json_dir: Directory containing filter JSON files. - gtest_target: The name of the gtest target. - - Returns: - A string containing the gtest filters. - """ - gtest_filters = '*' - filter_json_file = f'{filter_json_dir}/{gtest_target}_filter.json' - print(f" gtest_filter_json_file = {filter_json_file}") - filter_data = _read_json_config(filter_json_file) - if filter_data: - print(f" Loaded filter data: {filter_data}") - failing_tests = ':'.join(filter_data.get('failing_tests', [])) - if failing_tests: - gtest_filters += ':-' + failing_tests - print(f" gtest_filters = {gtest_filters}") - else: - print(' This gtest_target does not have gtest_filters specified') - return gtest_filters - - -def _process_test_requests(args): - """Processes test requests from the given arguments. - - Constructs a list of test requests based on the provided arguments, - including test arguments, command arguments, files, parameters, - and device information. - - Args: - args: The parsed command-line arguments. - - Returns: - A list of test request dictionaries. - """ - test_requests = [] - platform_data = _read_json_config(args.platform_json) - - tests_args = [ - f'job_timeout_secs={args.job_timeout_secs}', - f'test_timeout_secs={args.test_timeout_secs}', - f'start_timeout_secs={args.start_timeout_secs}' - ] - - if args.change_id: - tests_args.append(f'change_id={args.change_id}') - if args.test_attempts: - tests_args.append(f'test_attempts={args.test_attempts}') - if args.dimension: - tests_args.extend( - f'dimension_{dimension}' for dimension in args.dimension - ) - - base_params = [f'push_files=test_runtime_deps:{_CHROMIUM_TEST_ROOT}'] - - if args.gcs_result_path: - base_params.append(f'gcs_result_path={args.gcs_result_path}') - - for gtest_target in platform_data['gtest_targets']: - print(f" Processing gtest_target: {gtest_target}") - - apk_file = f"{args.gcs_archive_path}/{gtest_target}-debug.apk" - test_runtime_deps = f"{args.gcs_archive_path}/{gtest_target}_deps.tar.gz" - - files = [ - f'test_apk={apk_file}', - f'build_apk={apk_file}', - f'test_runtime_deps={test_runtime_deps}' - ] - - gtest_params = [ - f'gtest_xml_file_on_device={_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', - f'gcs_result_filename={gtest_target}_result.xml', - f'gcs_log_filename={gtest_target}_log.txt' - ] - - gtest_filter = _get_gtest_filters(args.filter_json_dir, gtest_target) - - test_cmd_args = [ - f'command_line_args=--gtest_output=xml:{_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', - f'--gtest_filter={gtest_filter}' - ] - - test_request = { - 'test_args': tests_args, - 'test_cmd_args': test_cmd_args, - 'files': files, - 'params': base_params + gtest_params, - 'device_type': platform_data.get('test_dimensions', {}).get( - 'gtest_device' - ), - 'device_pool': platform_data.get('test_dimensions', {}).get( - 'gtest_lab' - ), - } - - test_requests.append(test_request) - print(f' Created test_request: {test_request}') - - print(f'test_requests: {test_requests}') - return test_requests - - -def main() -> int: # Add a return type hint - """Main routine for the on-device tests gateway client.""" - - logging.basicConfig( - level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s' - ) - print('Starting main routine') - - parser = argparse.ArgumentParser( - description='Client for interacting with the On-Device Tests gateway.', - epilog=( - 'Example:' - 'python3 -u cobalt/tools/on_device_tests_gateway_client.py' - '--platform_json "${GITHUB_WORKSPACE}/src/.github/config/' - '${{ matrix.platform}}.json"' - '--filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/' - '${{ matrix.platform}}"' - '--token ${GITHUB_TOKEN}' - '--change_id ${GITHUB_PR_NUMBER:-postsubmit}' - '--label builder-${{ matrix.platform }}' - '--label builder_url-${GITHUB_RUN_URL}' - '--label github' - '--label ${GITHUB_EVENT_NAME}' - '--label ${GITHUB_WORKFLOW}' - '--label actor-${GITHUB_ACTOR}' - '--label actor_id-${GITHUB_ACTOR_ID}' - '--label triggering_actor-${GITHUB_TRIGGERING_ACTOR}' - '--label sha-${GITHUB_SHA}' - '--label repository-${GITHUB_REPO}' - '--label author-${GITHUB_PR_HEAD_USER_LOGIN:-' - '$GITHUB_COMMIT_AUTHOR_USERNAME}' - '--label author_id-${GITHUB_PR_HEAD_USER_ID:-' - '$GITHUB_COMMIT_AUTHOR_EMAIL}' - '--dimension host_name=regex:maneki-mhserver-05.*' - '${DIMENSION:+"--dimension" "$DIMENSION"}' - '${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" ' - '"$ON_DEVICE_TEST_ATTEMPTS"}' - '--gcs_archive_path "${GCS_ARTIFACTS_PATH}"' - '--gcs_result_path "${GCS_RESULTS_PATH}"' - 'trigger' - ), - formatter_class=argparse.RawDescriptionHelpFormatter, - ) - - # Authentication - parser.add_argument( - '-t', - '--token', - type=str, - required=True, - help='On Device Tests authentication token', - ) - - # General options - parser.add_argument( - '-i', - '--change_id', - type=str, - help=( - 'ChangeId that triggered this test, if any. Saved with performance' - ' test results.' - ), - ) - - subparsers = parser.add_subparsers( - dest='action', help='On-Device tests commands', required=True - ) - - # Trigger command - trigger_parser = subparsers.add_parser( - 'trigger', - help='Trigger On-Device tests', - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - - # Group trigger arguments - trigger_args = trigger_parser.add_argument_group('Trigger Arguments') - trigger_args.add_argument( - '-pf', - '--platform_json', - type=str, - help='Platform-specific JSON file containing the list of target tests.', - ) - trigger_parser.add_argument( - '--filter_json_dir', - type=str, - help='Directory containing filter JSON files for test selection.', - ) - trigger_parser.add_argument( - '-l', - '--label', - type=str, - action='append', - help='Additional labels to assign to the test.', - ) - trigger_parser.add_argument( - '--dimension', - type=str, - action='append', - help=( - 'On-Device Tests dimension used to select a device. ' - 'Must have the following form: =. ' - 'E.G. "release_version=regex:10.*"' - ), - ) - trigger_parser.add_argument( - '--test_attempts', - type=str, - default='1', - help='The maximum number of times a test can retry.', - ) - trigger_args.add_argument( - '-a', - '--archive_path', - type=str, - required=True, - help='Path to Chrobalt archive to be tested. Must be on GCS.', - ) - trigger_parser.add_argument( - '--gcs_result_path', - type=str, - help='GCS URL where test result files should be uploaded.', - ) - trigger_parser.add_argument( - '--job_timeout_sec', - type=str, - default='1800', - help='Timeout in seconds for the job (default: 1800 seconds).', - ) - trigger_parser.add_argument( - '--test_timeout_sec', - type=str, - default='1800', - help='Timeout in seconds for the test (default: 1800 seconds).', - ) - trigger_parser.add_argument( - '--start_timeout_sec', - type=str, - default='180', - help='Timeout in seconds for the test to start (default: 180 seconds).', - ) - - # Watch command - watch_parser = subparsers.add_parser( - 'watch', help='Watch a previously triggered On-Device test' - ) - watch_parser.add_argument( - 'session_id', - type=str, - help=( - 'Session ID of a previously triggered Mobile Harness test. ' - 'The test will be watched until it completes.' - ), - ) - - args = parser.parse_args() - - if not args.platform_json: - print( - "Error: The '--platform_json' argument is required. " - 'Please provide the path to the Platform JSON file.' - ) - exit(1) # Exit with an error code - if not args.filter_json_dir: - print( - "Error: The '--filter_json_dir' argument is required. " - 'Please provide the directory containing filter JSON files.' - ) - exit(1) # Exit with an error code - if not args.gcs_archive_path: - print( - "Error: The '--gcs_archive_path' argument is required. " - 'Please provide the GCS archive path info.' - ) - exit(1) # Exit with an error code - - test_requests = _process_test_requests(args) - client = OnDeviceTestsGatewayClient() - - try: - if args.action == 'trigger': - client.run_trigger_command(args, test_requests) - else: - client.run_watch_command(workdir=_WORK_DIR, args=args) - except grpc.RpcError as e: - logging.exception('gRPC error occurred:') # Log the full traceback - print(f'Error: {e}') - return e.code().value # Return the error code - - return 0 # Indicate successful execution - - -if __name__ == '__main__': - sys.exit(main()) From 6f5a260ceca96c8ff601b3637352a5cee883dc89 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Thu, 16 Jan 2025 14:32:15 -0800 Subject: [PATCH 22/46] Fix build dependency problem --- .github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 23ac114453f9..4cd811fb0f67 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -228,7 +228,7 @@ jobs: num_gtest_shards: ${{ needs.initialize.outputs.num_gtest_shards }} test-upload: - needs: [initialize, docker-build-image, build, test] + needs: [initialize, docker-build-image, build, on-host-test] if: always() && ( needs.initialize.outputs.test_on_host == 'true' || From fb0dbc7ebab7ef23d4e7f5c4d11f4a5c7aa74a68 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Fri, 17 Jan 2025 11:06:17 -0800 Subject: [PATCH 23/46] Testing ODT trigger --- .github/config/android-arm.json | 9 --------- .github/config/android-arm64.json | 1 - .github/workflows/main.yaml | 18 ++++++++++++++++++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/config/android-arm.json b/.github/config/android-arm.json index 6bfc85207a7e..51b99d238b9f 100644 --- a/.github/config/android-arm.json +++ b/.github/config/android-arm.json @@ -10,15 +10,6 @@ "cobalt:gn_all" ], "gtest_targets": [ - "base_unittests", - "blink_unittests", - "gin_unittests", - "gpu_unittests", - "ipc_tests", - "media_unittests", - "mojo_unittests", - "net_unittests", - "sql_unittests", "url_unittests" ], "test_dimensions": { diff --git a/.github/config/android-arm64.json b/.github/config/android-arm64.json index e90a3d101158..1856609020d5 100644 --- a/.github/config/android-arm64.json +++ b/.github/config/android-arm64.json @@ -21,7 +21,6 @@ "sql_unittests", "url_unittests" ], - "test_on_device": true, "includes": [ { "name":"arm64", diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 4cd811fb0f67..68bb9de16004 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -111,6 +111,24 @@ jobs: test_on_host: ${{ env.test_on_host }} test_on_device: ${{ env.test_on_device }} + foo: + needs: [initialize] + + if: | + ${{ needs.initialize.outputs.test_on_device == 'true' && (( + github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( + inputs.nightly == 'true' || github.event_name == 'schedule') && + vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || + ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' ) ) }} + runs-on: [self-hosted, odt-runner] + name: foo-bar + permissions: {} + steps: + - name: Run Foo Bar + shell: bash + run: echo "HELLO WORLD" + # Builds, tags, and pushes Cobalt docker build images to ghr. docker-build-image: needs: [initialize] From 26b093200ae427a5f9e8bd5f6d5b0c57eecc6e00 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Fri, 17 Jan 2025 12:55:08 -0800 Subject: [PATCH 24/46] Fix github actions syntax error --- .github/workflows/main.yaml | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 68bb9de16004..2069a63024a3 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -110,24 +110,6 @@ jobs: gtest_shards: ${{ env.gtest_shards }} test_on_host: ${{ env.test_on_host }} test_on_device: ${{ env.test_on_device }} - - foo: - needs: [initialize] - - if: | - ${{ needs.initialize.outputs.test_on_device == 'true' && (( - github.event_name == 'pull_request' && - contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( - inputs.nightly == 'true' || github.event_name == 'schedule') && - vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || - ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' ) ) }} - runs-on: [self-hosted, odt-runner] - name: foo-bar - permissions: {} - steps: - - name: Run Foo Bar - shell: bash - run: echo "HELLO WORLD" # Builds, tags, and pushes Cobalt docker build images to ghr. docker-build-image: @@ -306,12 +288,12 @@ jobs: # Run ODT when on_device label is applied on PR. # Also, run ODT on push and schedule if not explicitly disabled via repo vars. if: | - needs.initialize.outputs.test_on_device == 'true' && (( + ${{ needs.initialize.outputs.test_on_device == 'true' && (( github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( inputs.nightly == 'true' || github.event_name == 'schedule') && vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || - ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' ) ) + ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' ) ) }} runs-on: [self-hosted, odt-runner] name: ${{ matrix.name }}_on_device permissions: {} From 8e8d1160bc7f351a315329a9102d501e3fda0ca3 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Fri, 17 Jan 2025 14:50:39 -0800 Subject: [PATCH 25/46] Fix grpc proto paths --- .github/actions/on_device_tests/action.yaml | 6 +++--- .github/workflows/main.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 86bf7a2d940a..437bd837f70f 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -18,7 +18,7 @@ runs: shell: bash - name: Generate gRPC files run: | - python -m grpc_tools.protoc -Itools/ --python_out=cobalt/tools/ --grpc_python_out=cobalt/tools/ cobalt/tools/on_device_tests_gateway.proto + python -m grpc_tools.protoc -I${GITHUB_WORKSPACE}/cobalt/tools/ --python_out=${GITHUB_WORKSPACE}/cobalt/tools/ --grpc_python_out=${GITHUB_WORKSPACE}/cobalt/tools/ ${GITHUB_WORKSPACE}/cobalt/tools/on_device_tests_gateway.proto shell: bash - name: Set Up Cloud SDK uses: isarkis/setup-gcloud@40dce7857b354839efac498d3632050f568090b6 # v1.1.1 @@ -54,8 +54,8 @@ runs: run: | set -uxe python3 -u cobalt/tools/on_device_tests_gateway_client.py \ - --platform_json "${GITHUB_WORKSPACE}/src/.github/config/${{ matrix.platform}}.json" \ - --filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/${{ matrix.platform}}" \ + --platform_json "${GITHUB_WORKSPACE}/.github/config/${{ matrix.platform}}.json" \ + --filter_json_dir "${GITHUB_WORKSPACE}/cobalt/testing/${{ matrix.platform}}" \ --token ${GITHUB_TOKEN} \ --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ --label builder-${{ matrix.platform }} \ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 2069a63024a3..ec2470ed1781 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -151,7 +151,7 @@ jobs: matrix: platform: ${{ fromJson(needs.initialize.outputs.platforms) }} include: ${{ fromJson(needs.initialize.outputs.includes) }} - config: [devel, qa, gold] + config: [devel] container: ${{ needs.docker-build-image.outputs.docker_tag }} env: TEST_ARTIFACTS_KEY: ${{ matrix.platform }}_${{ matrix.name }}_test_artifacts From d0f748f411231c84b9adbb0589fcdfdfd4809038 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Sat, 18 Jan 2025 08:45:47 -0800 Subject: [PATCH 26/46] Fix command line arguments --- .github/actions/on_device_tests/action.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 437bd837f70f..d74ec80c774e 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -54,10 +54,11 @@ runs: run: | set -uxe python3 -u cobalt/tools/on_device_tests_gateway_client.py \ - --platform_json "${GITHUB_WORKSPACE}/.github/config/${{ matrix.platform}}.json" \ - --filter_json_dir "${GITHUB_WORKSPACE}/cobalt/testing/${{ matrix.platform}}" \ --token ${GITHUB_TOKEN} \ --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ + trigger \ + --platform_json "${GITHUB_WORKSPACE}/.github/config/${{ matrix.platform}}.json" \ + --filter_json_dir "${GITHUB_WORKSPACE}/cobalt/testing/${{ matrix.platform}}" \ --label builder-${{ matrix.platform }} \ --label builder_url-${GITHUB_RUN_URL} \ --label github \ @@ -73,8 +74,7 @@ runs: ${DIMENSION:+"--dimension" "$DIMENSION"} \ ${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" "$ON_DEVICE_TEST_ATTEMPTS"} \ --gcs_archive_path "${GCS_ARTIFACTS_PATH}" \ - --gcs_result_path "${GCS_RESULTS_PATH}" \ - trigger + --gcs_result_path "${GCS_RESULTS_PATH}" shell: bash - name: Download ${{ matrix.platform }} Test Results if: always() From 65772a9d5767b466bb96e7e2d76fbceed0eb06bb Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Sat, 18 Jan 2025 10:17:39 -0800 Subject: [PATCH 27/46] Testing ODT trigger --- .github/actions/on_device_tests/action.yaml | 4 ++-- .github/workflows/main.yaml | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index d74ec80c774e..089464d02ffc 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -34,7 +34,7 @@ runs: shell: bash - name: Run Tests on ${{ matrix.platform }} Platform env: - GCS_ARTIFACTS_PATH: /bigstore/${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }}_${{ matrix.config }} + GCS_ARTIFACTS_PATH: /bigstore/${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }} GCS_RESULTS_PATH: ${{ inputs.gcs_results_path }} GITHUB_SHA: ${{ github.sha }} GITHUB_TOKEN: ${{ github.token }} @@ -70,7 +70,7 @@ runs: --label sha-${GITHUB_SHA} \ --label repository-${GITHUB_REPO} \ --label author-${GITHUB_PR_HEAD_USER_LOGIN:-$GITHUB_COMMIT_AUTHOR_USERNAME} \ - --label author_id-${GITHUB_PR_HEAD_USER_ID:-$GITHUB_COMMIT_AUTHOR_EMAIL} + --label author_id-${GITHUB_PR_HEAD_USER_ID:-$GITHUB_COMMIT_AUTHOR_EMAIL} \ ${DIMENSION:+"--dimension" "$DIMENSION"} \ ${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" "$ON_DEVICE_TEST_ATTEMPTS"} \ --gcs_archive_path "${GCS_ARTIFACTS_PATH}" \ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index ec2470ed1781..7b5fbeaddbac 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -110,7 +110,7 @@ jobs: gtest_shards: ${{ env.gtest_shards }} test_on_host: ${{ env.test_on_host }} test_on_device: ${{ env.test_on_device }} - + # Builds, tags, and pushes Cobalt docker build images to ghr. docker-build-image: needs: [initialize] @@ -287,13 +287,14 @@ jobs: needs: [initialize, build] # Run ODT when on_device label is applied on PR. # Also, run ODT on push and schedule if not explicitly disabled via repo vars. - if: | - ${{ needs.initialize.outputs.test_on_device == 'true' && (( - github.event_name == 'pull_request' && - contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( - inputs.nightly == 'true' || github.event_name == 'schedule') && - vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || - ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' ) ) }} + if: needs.initialize.outputs.test_on_device == 'true' && + (( + github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( + inputs.nightly == 'true' || github.event_name == 'schedule') && + vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || + ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' + )) runs-on: [self-hosted, odt-runner] name: ${{ matrix.name }}_on_device permissions: {} From f6fe084b18911173322f76ec430e7654f82e943a Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Sun, 19 Jan 2025 16:39:20 -0800 Subject: [PATCH 28/46] Hardcode runtime deps file --- cobalt/tools/on_device_tests_gateway_client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index 4d0777bd3491..ec2135da502d 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -172,7 +172,8 @@ def _process_test_requests(args): print(f" Processing gtest_target: {gtest_target}") apk_file = f"{args.gcs_archive_path}/{gtest_target}-debug.apk" - test_runtime_deps = f"{args.gcs_archive_path}/{gtest_target}_deps.tar.gz" + # test_runtime_deps = f"{args.gcs_archive_path}/{gtest_target}_deps.tar.gz" + test_runtime_deps = "/bigstore/yt-temp/odt-test/url_unittests_deps.tar.gz" files = [ f'test_apk={apk_file}', From 06ffb5af874e2a09e0825312994d136e3931f2e1 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Sun, 19 Jan 2025 18:26:59 -0800 Subject: [PATCH 29/46] Update deps archive path on device --- cobalt/tools/on_device_tests_gateway_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index ec2135da502d..cabac2bb627b 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -33,7 +33,7 @@ _ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' _ON_DEVICE_OUTPUT_FILES_DIR = '/sdcard/Download' -_CHROMIUM_TEST_ROOT = '/sdcard/chromium_tests_root' +_DEPS_ARCHIVE = '/sdcard/chromium_tests_root/deps.tar.gz' class OnDeviceTestsGatewayClient(): """On-device tests Gateway Client class.""" @@ -163,7 +163,7 @@ def _process_test_requests(args): f'dimension_{dimension}' for dimension in args.dimension ) - base_params = [f'push_files=test_runtime_deps:{_CHROMIUM_TEST_ROOT}'] + base_params = [f'push_files=test_runtime_deps:{_DEPS_ARCHIVE}'] if args.gcs_result_path: base_params.append(f'gcs_result_path={args.gcs_result_path}') From c343979f2c849ba06a1a9340f4372131580b5447 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Sun, 19 Jan 2025 20:20:05 -0800 Subject: [PATCH 30/46] Fix gsutil copy command --- .github/actions/on_device_tests/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 089464d02ffc..22fb38845b9b 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -85,7 +85,7 @@ runs: set -uxe mkdir -p "${GITHUB_WORKSPACE}/${RESULTS_DIR}" cd "${GITHUB_WORKSPACE}/${RESULTS_DIR}" - gsutil cp "${GCS_RESULTS_PATH}/" . + gsutil cp -r "${GCS_RESULTS_PATH}/" . echo "TEST_LOG=${GITHUB_WORKSPACE}/${RESULTS_DIR}/test_results.txt" >> $GITHUB_ENV shell: bash - name: Archive Test Logs From a2dc411b80ac44ab305245b933bf1fa992572877 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Sun, 19 Jan 2025 21:21:06 -0800 Subject: [PATCH 31/46] Fix test logs archival mechanism --- .github/actions/on_device_tests/action.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 22fb38845b9b..4b69d75472be 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -83,14 +83,14 @@ runs: RESULTS_DIR: ${{ inputs.results_dir }} run: | set -uxe - mkdir -p "${GITHUB_WORKSPACE}/${RESULTS_DIR}" - cd "${GITHUB_WORKSPACE}/${RESULTS_DIR}" - gsutil cp -r "${GCS_RESULTS_PATH}/" . - echo "TEST_LOG=${GITHUB_WORKSPACE}/${RESULTS_DIR}/test_results.txt" >> $GITHUB_ENV + TEST_LOGS="${GITHUB_WORKSPACE}/${RESULTS_DIR}/" + mkdir -p "${TEST_LOGS}" + gsutil cp -r "${GCS_RESULTS_PATH}/" "${TEST_LOGS}" + echo "TEST_LOGS=${TEST_LOGS}" >> $GITHUB_ENV shell: bash - name: Archive Test Logs uses: actions/upload-artifact@v3 if: always() with: name: Test log - path: ${{ env.TEST_LOG }}/ + path: ${{ env.TEST_LOGS }} From 1dcef0874f5601732317a765509a39eb3c1b4b70 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Sun, 19 Jan 2025 22:18:59 -0800 Subject: [PATCH 32/46] Fix test result processing mechanism --- .github/workflows/main.yaml | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 7b5fbeaddbac..be4776fe88b9 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -220,7 +220,7 @@ jobs: path: src - name: Run On-Host Tests id: on-host-tests - if: always() && needs.initialize.outputs.test_on_host == 'true' + if: always() uses: ./src/.github/actions/on_host_tests with: test_artifacts_key: ${{ env.TEST_ARTIFACTS_KEY }} @@ -229,11 +229,7 @@ jobs: test-upload: needs: [initialize, docker-build-image, build, on-host-test] - if: always() && - ( - needs.initialize.outputs.test_on_host == 'true' || - needs.initialize.outputs.test_on_device == 'true' - ) + if: always() && needs.initialize.outputs.test_on_host == 'true' permissions: {} runs-on: [self-hosted, chrobalt-linux-runner] name: ${{ matrix.name }}_tests_upload @@ -320,13 +316,8 @@ jobs: gcs_results_path: gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }} results_dir: ${{ env.TEST_RESULTS_DIR }} - name: Process Test Results - if: | - always() && - ( - steps.on-device-tests.outcome == 'success' || - steps.on-device-tests.outcome == 'failure' - ) - uses: ./src/.github/actions/process_test_results + if: always() + uses: ./.github/actions/process_test_results with: results_dir: ${{ env.TEST_RESULTS_DIR }} datadog_api_key: ${{ secrets.DD_API_KEY }} From 0757659db90c1eddc8894923d40fb12828ae56c4 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Mon, 20 Jan 2025 10:50:16 -0800 Subject: [PATCH 33/46] Add removed unit tests back --- .github/config/android-arm.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/config/android-arm.json b/.github/config/android-arm.json index 51b99d238b9f..6bfc85207a7e 100644 --- a/.github/config/android-arm.json +++ b/.github/config/android-arm.json @@ -10,6 +10,15 @@ "cobalt:gn_all" ], "gtest_targets": [ + "base_unittests", + "blink_unittests", + "gin_unittests", + "gpu_unittests", + "ipc_tests", + "media_unittests", + "mojo_unittests", + "net_unittests", + "sql_unittests", "url_unittests" ], "test_dimensions": { From 488c881eb14f7946b8f3d72223e56fe213467a4e Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Mon, 20 Jan 2025 18:21:36 -0800 Subject: [PATCH 34/46] Artifact upload work for ODT --- .github/actions/on_device_tests/action.yaml | 10 +- .github/workflows/main.yaml | 102 +++++++++++--------- 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 4b69d75472be..a0e53033c4c9 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -7,6 +7,9 @@ inputs: results_dir: description: "Path to directory where test results are saved." required: true + test_results_key: + description: "Artifact key used to store test results." + required: true runs: using: "composite" @@ -88,9 +91,10 @@ runs: gsutil cp -r "${GCS_RESULTS_PATH}/" "${TEST_LOGS}" echo "TEST_LOGS=${TEST_LOGS}" >> $GITHUB_ENV shell: bash - - name: Archive Test Logs + - name: Archive Test Results uses: actions/upload-artifact@v3 if: always() with: - name: Test log - path: ${{ env.TEST_LOGS }} + name: ${{ inputs.test_results_key }} + path: ${{ env.TEST_LOGS }}/ + diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index be4776fe88b9..e4a4b390be43 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -193,6 +193,54 @@ jobs: test_artifacts_key: ${{ env.TEST_ARTIFACTS_KEY }} on_host: ${{ needs.initialize.outputs.test_on_host }} on_device: ${{ needs.initialize.outputs.test_on_device }} + + # Runs on-device integration and unit tests. + on-device-test: + needs: [initialize, build] + # Run ODT when on_device label is applied on PR. + # Also, run ODT on push and schedule if not explicitly disabled via repo vars. + if: needs.initialize.outputs.test_on_device == 'true' && + (( + github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( + inputs.nightly == 'true' || github.event_name == 'schedule') && + vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || + ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' + )) + runs-on: [self-hosted, odt-runner] + name: ${{ matrix.name }}_on_device + permissions: {} + strategy: + fail-fast: false + matrix: + platform: ${{ fromJson(needs.initialize.outputs.platforms) }} + config: [devel] + include: ${{ fromJson(needs.initialize.outputs.includes) }} + env: + TEST_RESULTS_DIR: ${{ matrix.name }}_test_results + TEST_RESULTS_KEY: ${{ matrix.platform }}_${{ matrix.name }}_test_results + steps: + - name: Checkout + uses: kaidokert/checkout@v3.5.999 + timeout-minutes: 30 + with: + fetch-depth: 1 + persist-credentials: false + - name: Run On-Device Tests (${{ matrix.shard }}) + id: on-device-tests + uses: ./.github/actions/on_device_tests + with: + test_artifacts_key: ${{ env.TEST_ARTIFACTS_KEY }} + gcs_results_path: gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }} + results_dir: ${{ env.TEST_RESULTS_DIR }} + - name: Process Test Results + if: always() + uses: ./.github/actions/process_test_results + with: + results_dir: ${{ env.TEST_RESULTS_DIR }} + datadog_api_key: ${{ secrets.DD_API_KEY }} + is_postsubmit: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} + continue-on-error: true on-host-test: needs: [initialize, docker-build-image, build] @@ -228,8 +276,12 @@ jobs: num_gtest_shards: ${{ needs.initialize.outputs.num_gtest_shards }} test-upload: - needs: [initialize, docker-build-image, build, on-host-test] - if: always() && needs.initialize.outputs.test_on_host == 'true' + needs: [initialize, docker-build-image, build, on-host-test, on-device-test] + if: always() && + ( + needs.initialize.outputs.test_on_host == 'true' || + needs.initialize.outputs.test_on_device == 'true' + ) permissions: {} runs-on: [self-hosted, chrobalt-linux-runner] name: ${{ matrix.name }}_tests_upload @@ -277,49 +329,3 @@ jobs: run: | echo "Failing because at least one test shard had errors." exit 1 - - # Runs on-device integration and unit tests. - on-device-test: - needs: [initialize, build] - # Run ODT when on_device label is applied on PR. - # Also, run ODT on push and schedule if not explicitly disabled via repo vars. - if: needs.initialize.outputs.test_on_device == 'true' && - (( - github.event_name == 'pull_request' && - contains(github.event.pull_request.labels.*.name, 'on_device') ) || (( - inputs.nightly == 'true' || github.event_name == 'schedule') && - vars.RUN_ODT_TESTS_ON_NIGHTLY != 'False') || - ( github.event_name == 'push' && vars.RUN_ODT_TESTS_ON_POSTSUBMIT != 'False' - )) - runs-on: [self-hosted, odt-runner] - name: ${{ matrix.name }}_on_device - permissions: {} - strategy: - fail-fast: false - matrix: - platform: ${{ fromJson(needs.initialize.outputs.platforms) }} - config: [devel] - include: ${{ fromJson(needs.initialize.outputs.includes) }} - env: - TEST_RESULTS_DIR: ${{ matrix.name }}_test_results - steps: - - name: Checkout - uses: kaidokert/checkout@v3.5.999 - timeout-minutes: 30 - with: - fetch-depth: 1 - persist-credentials: false - - name: Run On-Device Tests (${{ matrix.shard }}) - id: on-device-tests - uses: ./.github/actions/on_device_tests - with: - gcs_results_path: gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }} - results_dir: ${{ env.TEST_RESULTS_DIR }} - - name: Process Test Results - if: always() - uses: ./.github/actions/process_test_results - with: - results_dir: ${{ env.TEST_RESULTS_DIR }} - datadog_api_key: ${{ secrets.DD_API_KEY }} - is_postsubmit: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} - continue-on-error: true From cddc68b18bd21c68180218a18769e12e6e8f4d82 Mon Sep 17 00:00:00 2001 From: Igor Sarkisov Date: Wed, 22 Jan 2025 09:49:41 -0800 Subject: [PATCH 35/46] Fix artifact upload mechanism --- .github/actions/on_device_tests/action.yaml | 2 +- .github/workflows/main.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index a0e53033c4c9..7f70ec9251ec 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -96,5 +96,5 @@ runs: if: always() with: name: ${{ inputs.test_results_key }} - path: ${{ env.TEST_LOGS }}/ + path: ${{ env.TEST_LOGS }} diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index e4a4b390be43..064974dc9aef 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -230,7 +230,7 @@ jobs: id: on-device-tests uses: ./.github/actions/on_device_tests with: - test_artifacts_key: ${{ env.TEST_ARTIFACTS_KEY }} + test_results_key: ${{ env.TEST_RESULTS_KEY }} gcs_results_path: gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }} results_dir: ${{ env.TEST_RESULTS_DIR }} - name: Process Test Results From 5a5c647495f6f255a39c06b40d48b815c71cfb6c Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 21:33:54 +0000 Subject: [PATCH 36/46] Lint and formatting --- .github/actions/on_device_tests/action.yaml | 5 +- .github/config/chromium_android-arm64.json | 1 - cobalt/tools/on_device_tests_gateway.proto | 1 - .../tools/on_device_tests_gateway_client.py | 166 ++++++++---------- 4 files changed, 75 insertions(+), 98 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 7f70ec9251ec..6740a9bf2af3 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -53,7 +53,7 @@ runs: GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} GITHUB_RUN_NUMBER: ${{ github.run_number }} GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GITHUB_WORKFLOW: ${{ github.workflow }} + GITHUB_WORKFLOW: ${{ github.workflow }} run: | set -uxe python3 -u cobalt/tools/on_device_tests_gateway_client.py \ @@ -96,5 +96,4 @@ runs: if: always() with: name: ${{ inputs.test_results_key }} - path: ${{ env.TEST_LOGS }} - + path: ${{ env.TEST_LOGS }}/ diff --git a/.github/config/chromium_android-arm64.json b/.github/config/chromium_android-arm64.json index 239aa1d6a9c2..5c5239614c65 100644 --- a/.github/config/chromium_android-arm64.json +++ b/.github/config/chromium_android-arm64.json @@ -14,5 +14,4 @@ "platform": "chromium_android-arm64" } ] - } diff --git a/cobalt/tools/on_device_tests_gateway.proto b/cobalt/tools/on_device_tests_gateway.proto index 61f3da41f959..49f6cdb49917 100644 --- a/cobalt/tools/on_device_tests_gateway.proto +++ b/cobalt/tools/on_device_tests_gateway.proto @@ -67,4 +67,3 @@ message OnDeviceTestsResponse { // Next ID: 2 string response = 1; } - diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index cabac2bb627b..6c5b25a795b7 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -24,7 +24,6 @@ import on_device_tests_gateway_pb2 import on_device_tests_gateway_pb2_grpc - _WORK_DIR = '/on_device_tests_gateway' # For local testing, set: _ON_DEVICE_TESTS_GATEWAY_SERVICE_HOST = ('localhost') @@ -35,6 +34,7 @@ _ON_DEVICE_OUTPUT_FILES_DIR = '/sdcard/Download' _DEPS_ARCHIVE = '/sdcard/chromium_tests_root/deps.tar.gz' + class OnDeviceTestsGatewayClient(): """On-device tests Gateway Client class.""" @@ -96,7 +96,7 @@ def _read_json_config(filename): configuration. """ try: - with open(filename, 'r') as f: + with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) return data except FileNotFoundError: @@ -119,14 +119,14 @@ def _get_gtest_filters(filter_json_dir, gtest_target): """ gtest_filters = '*' filter_json_file = f'{filter_json_dir}/{gtest_target}_filter.json' - print(f" gtest_filter_json_file = {filter_json_file}") + print(f' gtest_filter_json_file = {filter_json_file}') filter_data = _read_json_config(filter_json_file) if filter_data: - print(f" Loaded filter data: {filter_data}") + print(f' Loaded filter data: {filter_data}') failing_tests = ':'.join(filter_data.get('failing_tests', [])) if failing_tests: gtest_filters += ':-' + failing_tests - print(f" gtest_filters = {gtest_filters}") + print(f' gtest_filters = {gtest_filters}') else: print(' This gtest_target does not have gtest_filters specified') return gtest_filters @@ -159,9 +159,7 @@ def _process_test_requests(args): if args.test_attempts: tests_args.append(f'test_attempts={args.test_attempts}') if args.dimension: - tests_args.extend( - f'dimension_{dimension}' for dimension in args.dimension - ) + tests_args.extend(f'dimension_{dimension}' for dimension in args.dimension) base_params = [f'push_files=test_runtime_deps:{_DEPS_ARCHIVE}'] @@ -169,20 +167,20 @@ def _process_test_requests(args): base_params.append(f'gcs_result_path={args.gcs_result_path}') for gtest_target in platform_data['gtest_targets']: - print(f" Processing gtest_target: {gtest_target}") + print(f' Processing gtest_target: {gtest_target}') - apk_file = f"{args.gcs_archive_path}/{gtest_target}-debug.apk" - # test_runtime_deps = f"{args.gcs_archive_path}/{gtest_target}_deps.tar.gz" - test_runtime_deps = "/bigstore/yt-temp/odt-test/url_unittests_deps.tar.gz" + apk_file = f'{args.gcs_archive_path}/{gtest_target}-debug.apk' + # test_runtime_deps = f'{args.gcs_archive_path}/{gtest_target}_deps.tar.gz' + test_runtime_deps = '/bigstore/yt-temp/odt-test/url_unittests_deps.tar.gz' files = [ - f'test_apk={apk_file}', - f'build_apk={apk_file}', + f'test_apk={apk_file}', f'build_apk={apk_file}', f'test_runtime_deps={test_runtime_deps}' ] gtest_params = [ - f'gtest_xml_file_on_device={_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', + f'gtest_xml_file_on_device={_ON_DEVICE_OUTPUT_FILES_DIR}/' + '{gtest_target}_result.xml', f'gcs_result_filename={gtest_target}_result.xml', f'gcs_log_filename={gtest_target}_log.txt' ] @@ -190,21 +188,23 @@ def _process_test_requests(args): gtest_filter = _get_gtest_filters(args.filter_json_dir, gtest_target) test_cmd_args = [ - f'command_line_args=--gtest_output=xml:{_ON_DEVICE_OUTPUT_FILES_DIR}/{gtest_target}_result.xml', - f'--gtest_filter={gtest_filter}' + f'command_line_args=--gtest_output=xml:{_ON_DEVICE_OUTPUT_FILES_DIR}/' + '{gtest_target}_result.xml', f'--gtest_filter={gtest_filter}' ] test_request = { - 'test_args': tests_args, - 'test_cmd_args': test_cmd_args, - 'files': files, - 'params': base_params + gtest_params, - 'device_type': platform_data.get('test_dimensions', {}).get( - 'gtest_device' - ), - 'device_pool': platform_data.get('test_dimensions', {}).get( - 'gtest_lab' - ), + 'test_args': + tests_args, + 'test_cmd_args': + test_cmd_args, + 'files': + files, + 'params': + base_params + gtest_params, + 'device_type': + platform_data.get('test_dimensions', {}).get('gtest_device'), + 'device_pool': + platform_data.get('test_dimensions', {}).get('gtest_lab'), } test_requests.append(test_request) @@ -218,43 +218,39 @@ def main() -> int: # Add a return type hint """Main routine for the on-device tests gateway client.""" logging.basicConfig( - level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s' - ) + level=logging.INFO, format='[%(filename)s:%(lineno)s] %(message)s') print('Starting main routine') parser = argparse.ArgumentParser( description='Client for interacting with the On-Device Tests gateway.', - epilog=( - 'Example:' - 'python3 -u cobalt/tools/on_device_tests_gateway_client.py' - '--platform_json "${GITHUB_WORKSPACE}/src/.github/config/' - '${{ matrix.platform}}.json"' - '--filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/' - '${{ matrix.platform}}"' - '--token ${GITHUB_TOKEN}' - '--change_id ${GITHUB_PR_NUMBER:-postsubmit}' - '--label builder-${{ matrix.platform }}' - '--label builder_url-${GITHUB_RUN_URL}' - '--label github' - '--label ${GITHUB_EVENT_NAME}' - '--label ${GITHUB_WORKFLOW}' - '--label actor-${GITHUB_ACTOR}' - '--label actor_id-${GITHUB_ACTOR_ID}' - '--label triggering_actor-${GITHUB_TRIGGERING_ACTOR}' - '--label sha-${GITHUB_SHA}' - '--label repository-${GITHUB_REPO}' - '--label author-${GITHUB_PR_HEAD_USER_LOGIN:-' - '$GITHUB_COMMIT_AUTHOR_USERNAME}' - '--label author_id-${GITHUB_PR_HEAD_USER_ID:-' - '$GITHUB_COMMIT_AUTHOR_EMAIL}' - '--dimension host_name=regex:maneki-mhserver-05.*' - '${DIMENSION:+"--dimension" "$DIMENSION"}' - '${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" ' - '"$ON_DEVICE_TEST_ATTEMPTS"}' - '--gcs_archive_path "${GCS_ARTIFACTS_PATH}"' - '--gcs_result_path "${GCS_RESULTS_PATH}"' - 'trigger' - ), + epilog=('Example:' + 'python3 -u cobalt/tools/on_device_tests_gateway_client.py' + '--platform_json "${GITHUB_WORKSPACE}/src/.github/config/' + '${{ matrix.platform}}.json"' + '--filter_json_dir "${GITHUB_WORKSPACE}/src/cobalt/testing/' + '${{ matrix.platform}}"' + '--token ${GITHUB_TOKEN}' + '--label builder-${{ matrix.platform }}' + '--label builder_url-${GITHUB_RUN_URL}' + '--label github' + '--label ${GITHUB_EVENT_NAME}' + '--label ${GITHUB_WORKFLOW}' + '--label actor-${GITHUB_ACTOR}' + '--label actor_id-${GITHUB_ACTOR_ID}' + '--label triggering_actor-${GITHUB_TRIGGERING_ACTOR}' + '--label sha-${GITHUB_SHA}' + '--label repository-${GITHUB_REPO}' + '--label author-${GITHUB_PR_HEAD_USER_LOGIN:-' + '$GITHUB_COMMIT_AUTHOR_USERNAME}' + '--label author_id-${GITHUB_PR_HEAD_USER_ID:-' + '$GITHUB_COMMIT_AUTHOR_EMAIL}' + '--dimension host_name=regex:maneki-mhserver-05.*' + '${DIMENSION:+"--dimension" "$DIMENSION"}' + '${ON_DEVICE_TEST_ATTEMPTS:+"--test_attempts" ' + '"$ON_DEVICE_TEST_ATTEMPTS"}' + '--gcs_archive_path "${GCS_ARTIFACTS_PATH}"' + '--gcs_result_path "${GCS_RESULTS_PATH}"' + 'trigger'), formatter_class=argparse.RawDescriptionHelpFormatter, ) @@ -272,15 +268,12 @@ def main() -> int: # Add a return type hint '-i', '--change_id', type=str, - help=( - 'ChangeId that triggered this test, if any. Saved with performance' - ' test results.' - ), + help=('ChangeId that triggered this test, if any. Saved with performance' + ' test results.'), ) subparsers = parser.add_subparsers( - dest='action', help='On-Device tests commands', required=True - ) + dest='action', help='On-Device tests commands', required=True) # Trigger command trigger_parser = subparsers.add_parser( @@ -315,12 +308,8 @@ def main() -> int: # Add a return type hint '--dimension', type=str, action='append', - help=( - 'On-Device Tests dimension used to select a device. ' - 'Must have the following form: =. ' - 'E.G. "release_version=regex:10.*"' - ), - ) + help='On-Device Tests dimension used to select a device. Must have the ' + 'following form: =. E.G. "release_version=regex:10.*"') trigger_parser.add_argument( '--test_attempts', type=str, @@ -360,37 +349,28 @@ def main() -> int: # Add a return type hint # Watch command watch_parser = subparsers.add_parser( - 'watch', help='Watch a previously triggered On-Device test' - ) + 'watch', help='Watch a previously triggered On-Device test') watch_parser.add_argument( 'session_id', type=str, - help=( - 'Session ID of a previously triggered Mobile Harness test. ' - 'The test will be watched until it completes.' - ), + help=('Session ID of a previously triggered Mobile Harness test. ' + 'The test will be watched until it completes.'), ) args = parser.parse_args() if not args.platform_json: - print( - "Error: The '--platform_json' argument is required. " - 'Please provide the path to the Platform JSON file.' - ) - exit(1) # Exit with an error code + print('Error: The \'--platform_json\' argument is required. ' + 'Please provide the path to the Platform JSON file.') + return 1 if not args.filter_json_dir: - print( - "Error: The '--filter_json_dir' argument is required. " - 'Please provide the directory containing filter JSON files.' - ) - exit(1) # Exit with an error code + print('Error: The \'--filter_json_dir\' argument is required. ' + 'Please provide the directory containing filter JSON files.') + return 1 if not args.gcs_archive_path: - print( - "Error: The '--gcs_archive_path' argument is required. " - 'Please provide the GCS archive path info.' - ) - exit(1) # Exit with an error code + print('Error: The \'--gcs_archive_path\' argument is required. ' + 'Please provide the GCS archive path info.') + return 1 test_requests = _process_test_requests(args) client = OnDeviceTestsGatewayClient() From 6f20c766991a6b28519cc907ae16527ab204e2d7 Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 21:37:10 +0000 Subject: [PATCH 37/46] Fix params processing, delete some dead code --- .../tools/on_device_tests_gateway_client.py | 104 +++++++----------- 1 file changed, 42 insertions(+), 62 deletions(-) diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index 6c5b25a795b7..4554868915d5 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -31,7 +31,8 @@ 'on-device-tests-gateway-service.on-device-tests.svc.cluster.local') _ON_DEVICE_TESTS_GATEWAY_SERVICE_PORT = '50052' -_ON_DEVICE_OUTPUT_FILES_DIR = '/sdcard/Download' +# These paths are hardcoded in various places. DO NOT CHANGE! +_DIR_ON_DEVICE = '/sdcard/Download' _DEPS_ARCHIVE = '/sdcard/chromium_tests_root/deps.tar.gz' @@ -148,69 +149,57 @@ def _process_test_requests(args): test_requests = [] platform_data = _read_json_config(args.platform_json) - tests_args = [ - f'job_timeout_secs={args.job_timeout_secs}', - f'test_timeout_secs={args.test_timeout_secs}', - f'start_timeout_secs={args.start_timeout_secs}' - ] - - if args.change_id: - tests_args.append(f'change_id={args.change_id}') - if args.test_attempts: - tests_args.append(f'test_attempts={args.test_attempts}') - if args.dimension: - tests_args.extend(f'dimension_{dimension}' for dimension in args.dimension) - - base_params = [f'push_files=test_runtime_deps:{_DEPS_ARCHIVE}'] - - if args.gcs_result_path: - base_params.append(f'gcs_result_path={args.gcs_result_path}') - for gtest_target in platform_data['gtest_targets']: print(f' Processing gtest_target: {gtest_target}') + tests_args = [ + f'job_timeout_secs={args.job_timeout_secs}', + f'test_timeout_secs={args.test_timeout_secs}', + f'start_timeout_secs={args.start_timeout_secs}' + ] - apk_file = f'{args.gcs_archive_path}/{gtest_target}-debug.apk' - # test_runtime_deps = f'{args.gcs_archive_path}/{gtest_target}_deps.tar.gz' - test_runtime_deps = '/bigstore/yt-temp/odt-test/url_unittests_deps.tar.gz' + if args.change_id: + tests_args.append(f'change_id={args.change_id}') + if args.test_attempts: + tests_args.append(f'test_attempts={args.test_attempts}') + if args.dimension: + tests_args.extend( + f'dimension_{dimension}' for dimension in args.dimension) - files = [ - f'test_apk={apk_file}', f'build_apk={apk_file}', - f'test_runtime_deps={test_runtime_deps}' - ] + params = [f'push_files=test_runtime_deps:{_DEPS_ARCHIVE}'] - gtest_params = [ - f'gtest_xml_file_on_device={_ON_DEVICE_OUTPUT_FILES_DIR}/' - '{gtest_target}_result.xml', + if args.gcs_result_path: + params.append(f'gcs_result_path={args.gcs_result_path}') + params += [ + f'gtest_xml_file_on_device={_DIR_ON_DEVICE}/{gtest_target}_result.xml', f'gcs_result_filename={gtest_target}_result.xml', f'gcs_log_filename={gtest_target}_log.txt' ] gtest_filter = _get_gtest_filters(args.filter_json_dir, gtest_target) - test_cmd_args = [ - f'command_line_args=--gtest_output=xml:{_ON_DEVICE_OUTPUT_FILES_DIR}/' - '{gtest_target}_result.xml', f'--gtest_filter={gtest_filter}' + command_line_args = [ + f'--gtest_output=xml:{_DIR_ON_DEVICE}/{gtest_target}_result.xml', + f'--gtest_filter={gtest_filter}', + ] + test_cmd_args = [f'command_line_args={" ".join(command_line_args)}'] + + files = [ + f'test_apk={args.gcs_archive_path}/{gtest_target}-debug.apk', + f'build_apk={args.gcs_archive_path}/{gtest_target}-debug.apk', + f'test_runtime_deps={args.gcs_archive_path}/{gtest_target}_deps.tar.gz', ] - test_request = { - 'test_args': - tests_args, - 'test_cmd_args': - test_cmd_args, - 'files': - files, - 'params': - base_params + gtest_params, - 'device_type': - platform_data.get('test_dimensions', {}).get('gtest_device'), - 'device_pool': - platform_data.get('test_dimensions', {}).get('gtest_lab'), - } - - test_requests.append(test_request) - print(f' Created test_request: {test_request}') - - print(f'test_requests: {test_requests}') + device_type = platform_data.get('test_dimensions', {}).get('gtest_device') + device_pool = platform_data.get('test_dimensions', {}).get('gtest_lab') + + test_requests.append({ + 'test_args': tests_args, + 'test_cmd_args': test_cmd_args, + 'files': files, + 'params': params, + 'device_type': device_type, + 'device_pool': device_pool, + }) return test_requests @@ -262,16 +251,6 @@ def main() -> int: # Add a return type hint required=True, help='On Device Tests authentication token', ) - - # General options - parser.add_argument( - '-i', - '--change_id', - type=str, - help=('ChangeId that triggered this test, if any. Saved with performance' - ' test results.'), - ) - subparsers = parser.add_subparsers( dest='action', help='On-Device tests commands', required=True) @@ -309,7 +288,8 @@ def main() -> int: # Add a return type hint type=str, action='append', help='On-Device Tests dimension used to select a device. Must have the ' - 'following form: =. E.G. "release_version=regex:10.*"') + 'following form: =. E.G. "release_version=regex:10.*"', + ) trigger_parser.add_argument( '--test_attempts', type=str, From 4381381c7df8d9c8a15d37aff876a6e123818a21 Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 00:36:56 +0000 Subject: [PATCH 38/46] Remove dead code, minor refactoring --- .../tools/on_device_tests_gateway_client.py | 73 +++++++------------ 1 file changed, 26 insertions(+), 47 deletions(-) diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index 4554868915d5..12cf4031320b 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -19,6 +19,7 @@ import json import logging import sys +from typing import List import grpc import on_device_tests_gateway_pb2 @@ -52,7 +53,7 @@ def __init__(self): self.stub = on_device_tests_gateway_pb2_grpc.on_device_tests_gatewayStub( self.channel) - def run_trigger_command(self, args: argparse.Namespace, test_requests): + def run_trigger_command(self, token: str, labels: List[str], test_requests): """Calls On-Device Tests service and passing given parameters to it. Args: @@ -61,26 +62,23 @@ def run_trigger_command(self, args: argparse.Namespace, test_requests): """ for response_line in self.stub.exec_command( on_device_tests_gateway_pb2.OnDeviceTestsCommand( - token=args.token, - labels=args.label, + token=token, + labels=labels, test_requests=test_requests, )): print(response_line.response) - def run_watch_command(self, workdir: str, args: argparse.Namespace): + def run_watch_command(self, token: str, session_id: str): """Calls On-Device Tests watch service and passing given parameters to it. Args: - workdir (str): Current script workdir. args (Namespace): Arguments passed in command line. """ for response_line in self.stub.exec_watch_command( on_device_tests_gateway_pb2.OnDeviceTestsWatchCommand( - workdir=workdir, - token=args.token, - change_id=args.change_id, - session_id=args.session_id, + token=token, + session_id=session_id, )): print(response_line.response) @@ -98,14 +96,13 @@ def _read_json_config(filename): """ try: with open(filename, 'r', encoding='utf-8') as f: - data = json.load(f) - return data + return json.load(f) except FileNotFoundError: print(f" Config file '{filename}' not found.") - return None + raise except json.JSONDecodeError: print(f" Invalid JSON format in '{filename}'.") - return None + raise def _get_gtest_filters(filter_json_dir, gtest_target): @@ -151,32 +148,18 @@ def _process_test_requests(args): for gtest_target in platform_data['gtest_targets']: print(f' Processing gtest_target: {gtest_target}') + tests_args = [ f'job_timeout_secs={args.job_timeout_secs}', f'test_timeout_secs={args.test_timeout_secs}', f'start_timeout_secs={args.start_timeout_secs}' ] - - if args.change_id: - tests_args.append(f'change_id={args.change_id}') if args.test_attempts: tests_args.append(f'test_attempts={args.test_attempts}') if args.dimension: - tests_args.extend( - f'dimension_{dimension}' for dimension in args.dimension) - - params = [f'push_files=test_runtime_deps:{_DEPS_ARCHIVE}'] - - if args.gcs_result_path: - params.append(f'gcs_result_path={args.gcs_result_path}') - params += [ - f'gtest_xml_file_on_device={_DIR_ON_DEVICE}/{gtest_target}_result.xml', - f'gcs_result_filename={gtest_target}_result.xml', - f'gcs_log_filename={gtest_target}_log.txt' - ] + tests_args += [f'dimension_{dimension}' for dimension in args.dimension] gtest_filter = _get_gtest_filters(args.filter_json_dir, gtest_target) - command_line_args = [ f'--gtest_output=xml:{_DIR_ON_DEVICE}/{gtest_target}_result.xml', f'--gtest_filter={gtest_filter}', @@ -189,6 +172,16 @@ def _process_test_requests(args): f'test_runtime_deps={args.gcs_archive_path}/{gtest_target}_deps.tar.gz', ] + params = [] + if args.gcs_result_path: + params.append(f'gcs_result_path={args.gcs_result_path}') + params += [ + f'push_files=test_runtime_deps:{_DEPS_ARCHIVE}', + f'gtest_xml_file_on_device={_DIR_ON_DEVICE}/{gtest_target}_result.xml', + f'gcs_result_filename={gtest_target}_result.xml', + f'gcs_log_filename={gtest_target}_log.txt' + ] + device_type = platform_data.get('test_dimensions', {}).get('gtest_device') device_pool = platform_data.get('test_dimensions', {}).get('gtest_lab') @@ -203,7 +196,7 @@ def _process_test_requests(args): return test_requests -def main() -> int: # Add a return type hint +def main() -> int: """Main routine for the on-device tests gateway client.""" logging.basicConfig( @@ -338,28 +331,14 @@ def main() -> int: # Add a return type hint ) args = parser.parse_args() - - if not args.platform_json: - print('Error: The \'--platform_json\' argument is required. ' - 'Please provide the path to the Platform JSON file.') - return 1 - if not args.filter_json_dir: - print('Error: The \'--filter_json_dir\' argument is required. ' - 'Please provide the directory containing filter JSON files.') - return 1 - if not args.gcs_archive_path: - print('Error: The \'--gcs_archive_path\' argument is required. ' - 'Please provide the GCS archive path info.') - return 1 - test_requests = _process_test_requests(args) - client = OnDeviceTestsGatewayClient() + client = OnDeviceTestsGatewayClient() try: if args.action == 'trigger': - client.run_trigger_command(args, test_requests) + client.run_trigger_command(args.token, args.label, test_requests) else: - client.run_watch_command(workdir=_WORK_DIR, args=args) + client.run_watch_command(args.token, args.session_id) except grpc.RpcError as e: logging.exception('gRPC error occurred:') # Log the full traceback return e.code().value # Return the error code From a455108f696d44aff98ed91c01c6f306bcad7a1e Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 20:13:06 +0000 Subject: [PATCH 39/46] Remove last traces of change_id param --- .github/actions/on_device_tests/action.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 6740a9bf2af3..5eb4ae370250 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -30,10 +30,6 @@ runs: echo "PROJECT_NAME=$(gcloud config get-value project)" >> $GITHUB_ENV # Test results and logs echo "GCS_RESULTS_PATH=gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }}" >> $GITHUB_ENV - # Dimension env - if [ "${{ matrix.dimension }}" != "null" ]; then - echo "DIMENSION=${{ matrix.dimension }}" >> $GITHUB_ENV - fi shell: bash - name: Run Tests on ${{ matrix.platform }} Platform env: @@ -58,10 +54,10 @@ runs: set -uxe python3 -u cobalt/tools/on_device_tests_gateway_client.py \ --token ${GITHUB_TOKEN} \ - --change_id ${GITHUB_PR_NUMBER:-postsubmit} \ trigger \ --platform_json "${GITHUB_WORKSPACE}/.github/config/${{ matrix.platform}}.json" \ --filter_json_dir "${GITHUB_WORKSPACE}/cobalt/testing/${{ matrix.platform}}" \ + --label github_${GITHUB_PR_NUMBER:-postsubmit} \ --label builder-${{ matrix.platform }} \ --label builder_url-${GITHUB_RUN_URL} \ --label github \ From ef6b9add2a2d6d38f7e56289b24db99ff436e350 Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 20:14:55 +0000 Subject: [PATCH 40/46] Add apk copying to artifact script --- .../actions/upload_test_artifacts/action.yaml | 31 ++++++++--------- cobalt/build/archive_test_artifacts.py | 34 +++++++++++++++---- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/.github/actions/upload_test_artifacts/action.yaml b/.github/actions/upload_test_artifacts/action.yaml index a2a645aea29d..c5a6d9cb033c 100644 --- a/.github/actions/upload_test_artifacts/action.yaml +++ b/.github/actions/upload_test_artifacts/action.yaml @@ -16,22 +16,7 @@ inputs: runs: using: "composite" steps: - - name: Set up Cloud SDK - if: inputs.upload_on_device_test_artifacts == 'true' - uses: isarkis/setup-gcloud@40dce7857b354839efac498d3632050f568090b6 # v1.1.1 - - name: Upload Android Test Artifacts to GCS - if: inputs.upload_on_device_test_artifacts == 'true' - env: - WORKFLOW: ${{ github.workflow }} - run: | - set -eux - project_name=$(gcloud config get-value project) - gsutil cp "${GITHUB_WORKSPACE}/src/out/${{ matrix.platform }}_${{ matrix.config }}/**/*.apk" \ - "gs://${project_name}-test-artifacts/${WORKFLOW}/${GITHUB_RUN_NUMBER}/${{matrix.platform}}/" - shell: bash - - - name: Create On-Host Test Artifacts Archive - if: inputs.upload_on_host_test_artifacts == 'true' + - name: Archive Test Artifacts run: | set -x mkdir ${GITHUB_WORKSPACE}/artifacts @@ -49,3 +34,17 @@ runs: name: ${{ inputs.test_artifacts_key }} path: artifacts/* retention-days: 3 + - name: Set up Cloud SDK + if: inputs.upload_on_device_test_artifacts == 'true' + uses: isarkis/setup-gcloud@40dce7857b354839efac498d3632050f568090b6 # v1.1.1 + - name: Upload Android Test Artifacts to GCS + if: inputs.upload_on_device_test_artifacts == 'true' + env: + WORKFLOW: ${{ github.workflow }} + run: | + set -eux + project_name=$(gcloud config get-value project) + + gsutil cp "${GITHUB_WORKSPACE}/artifacts/*" \ + "gs://${project_name}-test-artifacts/${WORKFLOW}/${GITHUB_RUN_NUMBER}/${{matrix.platform}}/" + shell: bash diff --git a/cobalt/build/archive_test_artifacts.py b/cobalt/build/archive_test_artifacts.py index 711f7bb2734c..a2e5e75b625a 100755 --- a/cobalt/build/archive_test_artifacts.py +++ b/cobalt/build/archive_test_artifacts.py @@ -17,6 +17,7 @@ import argparse import json import os +import shutil import subprocess import tempfile from typing import List @@ -35,7 +36,7 @@ def _make_tar(archive_path: str, file_list: str): def create_archive(targets: List[str], source_dir: str, destination_dir: str, - platform: str, combine: bool): + platform: str, uber_archive: bool): """Main logic. Collects runtime dependencies from the source directory for each target.""" # TODO(b/382508397): Remove when dynamically generated. @@ -72,16 +73,27 @@ def create_archive(targets: List[str], source_dir: str, destination_dir: str, } deps |= target_deps - if not combine: + if not uber_archive: output_path = os.path.join(destination_dir, f'{target_name}_deps.tar.gz') _make_tar(output_path, deps) - if combine: + if uber_archive: output_path = os.path.join(destination_dir, 'test_artifacts.tar.gz') _make_tar(output_path, deps) -if __name__ == '__main__': +def copy_apks(targets: List[str], source_dir: str, destination_dir: str): + """Copies the target APKs from the source directory to the destination. + The path to the APK in the source directory (assumed here to be the out + directory) is defined in build/config/android/rules.gni + """ + for target in targets: + _, target_name = target.split(':') + apk_path = f'{source_dir}/{target_name}_apk/{target_name}-debug.apk' + shutil.copy2(apk_path, destination_dir) + + +def main(): parser = argparse.ArgumentParser() parser.add_argument( '-s', @@ -103,9 +115,17 @@ def create_archive(targets: List[str], source_dir: str, destination_dir: str, '--targets', required=True, type=lambda arg: arg.split(','), - help='The targets to package, comma-separated. Must be fully qualified ' - 'for android.') + help='The targets to package, comma-separated. Must be fully qualified, ' + 'e.g. path/to:target.') args = parser.parse_args() + uber_archive = args.platform.startswith('linux') create_archive(args.targets, args.source_dir, args.destination_dir, - args.platform, args.platform.startswith('linux')) + args.platform, uber_archive) + + if args.platform.startswith('android'): + copy_apks(args.targets, args.source_dir, args.destination_dir) + + +if __name__ == '__main__': + main() From a3ee0d861d222968a48cdbd7d1c8eb77e5d3fd2c Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 22:06:19 +0000 Subject: [PATCH 41/46] Remove loading of gtest target from platform configs --- .github/workflows/main.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 29f764f8f87d..b1e71357ef0c 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -65,11 +65,6 @@ jobs: run: | targets=$(cat ${GITHUB_WORKSPACE}/.github/config/${{ inputs.platform }}.json | jq -cr '.targets | join(" ")') echo "targets=${targets}" >> $GITHUB_ENV - - id: set-test-targets - shell: bash - run: | - gtest_targets=$(cat ${GITHUB_WORKSPACE}/.github/config/${{ inputs.platform }}.json | jq -c '.gtest_targets | join(" ")') - echo "gtest_targets=${gtest_targets}" >> $GITHUB_ENV - id: set-includes shell: bash run: | @@ -103,7 +98,6 @@ jobs: outputs: platforms: ${{ env.platforms }} targets: ${{ env.targets }} - gtest_targets: ${{ env.gtest_targets }} includes: ${{ env.includes }} docker_service: ${{ env.docker_service }} num_gtest_shards: ${{ env.num_gtest_shards }} From 41375e9fe2c9678250cefe04bd46efe7f64876ba Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 22:10:48 +0000 Subject: [PATCH 42/46] Unify on-host and on-device test steps --- .github/workflows/main.yaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index b1e71357ef0c..d23f8b1a10c7 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -201,8 +201,8 @@ jobs: fail-fast: false matrix: platform: ${{ fromJson(needs.initialize.outputs.platforms) }} - config: [devel] include: ${{ fromJson(needs.initialize.outputs.includes) }} + config: [devel] env: TEST_RESULTS_DIR: ${{ matrix.name }}_test_results TEST_RESULTS_KEY: ${{ matrix.platform }}_${{ matrix.name }}_test_results @@ -220,14 +220,6 @@ jobs: test_results_key: ${{ env.TEST_RESULTS_KEY }} gcs_results_path: gs://cobalt-unittest-storage/results/${{ matrix.name }}/${{ github.run_id }} results_dir: ${{ env.TEST_RESULTS_DIR }} - - name: Process Test Results - if: always() - uses: ./.github/actions/process_test_results - with: - results_dir: ${{ env.TEST_RESULTS_DIR }} - datadog_api_key: ${{ secrets.DD_API_KEY }} - is_postsubmit: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} - continue-on-error: true on-host-test: needs: [initialize, docker-build-image, build] From a47df725a2862de1a50a714c298b4c017fbdc9f5 Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 23:12:27 +0000 Subject: [PATCH 43/46] Get target list from temp hardcoded json file --- .github/actions/on_device_tests/action.yaml | 6 ++++-- .../android-arm/base_unittests_filter.json | 0 cobalt/tools/on_device_tests_gateway_client.py | 16 ++++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) rename cobalt/testing/{ => filters}/android-arm/base_unittests_filter.json (100%) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 5eb4ae370250..663ec19053a9 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -33,6 +33,8 @@ runs: shell: bash - name: Run Tests on ${{ matrix.platform }} Platform env: + # TODO(b/382508397): Replace hardcoded list with dynamically generated one. + TEST_TARGETS_JSON_FILE: cobalt/build/testing/targets/${{ matrix.platform }}/test_targets.json GCS_ARTIFACTS_PATH: /bigstore/${{ env.PROJECT_NAME }}-test-artifacts/${{ github.workflow }}/${{ github.run_number }}/${{ matrix.platform }} GCS_RESULTS_PATH: ${{ inputs.gcs_results_path }} GITHUB_SHA: ${{ github.sha }} @@ -55,8 +57,8 @@ runs: python3 -u cobalt/tools/on_device_tests_gateway_client.py \ --token ${GITHUB_TOKEN} \ trigger \ - --platform_json "${GITHUB_WORKSPACE}/.github/config/${{ matrix.platform}}.json" \ - --filter_json_dir "${GITHUB_WORKSPACE}/cobalt/testing/${{ matrix.platform}}" \ + --targets $(cat "${{ env.TEST_TARGETS_JSON_FILE }}" | jq -cr '.test_targets | join(",")') + --filter_json_dir "${GITHUB_WORKSPACE}/cobalt/testing/filters/${{ matrix.platform}}" \ --label github_${GITHUB_PR_NUMBER:-postsubmit} \ --label builder-${{ matrix.platform }} \ --label builder_url-${GITHUB_RUN_URL} \ diff --git a/cobalt/testing/android-arm/base_unittests_filter.json b/cobalt/testing/filters/android-arm/base_unittests_filter.json similarity index 100% rename from cobalt/testing/android-arm/base_unittests_filter.json rename to cobalt/testing/filters/android-arm/base_unittests_filter.json diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index 12cf4031320b..7a4933c7e69e 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -144,9 +144,8 @@ def _process_test_requests(args): A list of test request dictionaries. """ test_requests = [] - platform_data = _read_json_config(args.platform_json) - for gtest_target in platform_data['gtest_targets']: + for gtest_target in args.targets.split(','): print(f' Processing gtest_target: {gtest_target}') tests_args = [ @@ -182,8 +181,9 @@ def _process_test_requests(args): f'gcs_log_filename={gtest_target}_log.txt' ] - device_type = platform_data.get('test_dimensions', {}).get('gtest_device') - device_pool = platform_data.get('test_dimensions', {}).get('gtest_lab') + # TODO(oxv): Figure out how to get dimensions from config to here. + device_type = 'sabrina' + device_pool = 'maneki' test_requests.append({ 'test_args': tests_args, @@ -256,12 +256,12 @@ def main() -> int: # Group trigger arguments trigger_args = trigger_parser.add_argument_group('Trigger Arguments') - trigger_args.add_argument( - '-pf', - '--platform_json', + trigger_parser.add_argument( + '--targets', type=str, required=True, - help='Platform-specific JSON file containing the list of target tests.', + help='List of targets to test, comma separated. Must be fully qualified ' + 'ninja target.', ) trigger_parser.add_argument( '--filter_json_dir', From 0f07e803d36505b63072d4fa920330f7b6dae6c9 Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Wed, 22 Jan 2025 23:14:42 +0000 Subject: [PATCH 44/46] Revert sandbox docker config --- docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 1bd9a0de3d13..656d567a5ec3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,8 +4,8 @@ services: build: context: cobalt/docker/linux cache_from: - - ghcr.io/youtube/cobalt_sandbox/linux:latest - image: ghcr.io/youtube/cobalt_sandbox/linux:latest + - ghcr.io/youtube/cobalt/linux:latest + image: ghcr.io/youtube/cobalt/linux:latest platform: linux/amd64 environment: - DEPOT_TOOLS_UPDATE=0 From b2bc541da431cf72449a70dc899716a1421ed170 Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Thu, 23 Jan 2025 02:47:32 +0000 Subject: [PATCH 45/46] Fix inconsistent quote lint error --- cobalt/tools/on_device_tests_gateway_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cobalt/tools/on_device_tests_gateway_client.py b/cobalt/tools/on_device_tests_gateway_client.py index 7a4933c7e69e..a3695a1fc689 100644 --- a/cobalt/tools/on_device_tests_gateway_client.py +++ b/cobalt/tools/on_device_tests_gateway_client.py @@ -159,11 +159,11 @@ def _process_test_requests(args): tests_args += [f'dimension_{dimension}' for dimension in args.dimension] gtest_filter = _get_gtest_filters(args.filter_json_dir, gtest_target) - command_line_args = [ + command_line_args = ' '.join([ f'--gtest_output=xml:{_DIR_ON_DEVICE}/{gtest_target}_result.xml', f'--gtest_filter={gtest_filter}', - ] - test_cmd_args = [f'command_line_args={" ".join(command_line_args)}'] + ]) + test_cmd_args = [f'command_line_args={command_line_args}'] files = [ f'test_apk={args.gcs_archive_path}/{gtest_target}-debug.apk', From 5e26ecaa4924211fb5d2d2dc15c903b89689a092 Mon Sep 17 00:00:00 2001 From: Oscar Vestlie Date: Thu, 23 Jan 2025 00:10:51 +0000 Subject: [PATCH 46/46] Add missing backslash in params list --- .github/actions/on_device_tests/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/on_device_tests/action.yaml b/.github/actions/on_device_tests/action.yaml index 663ec19053a9..17cd7e79c8c3 100644 --- a/.github/actions/on_device_tests/action.yaml +++ b/.github/actions/on_device_tests/action.yaml @@ -57,7 +57,7 @@ runs: python3 -u cobalt/tools/on_device_tests_gateway_client.py \ --token ${GITHUB_TOKEN} \ trigger \ - --targets $(cat "${{ env.TEST_TARGETS_JSON_FILE }}" | jq -cr '.test_targets | join(",")') + --targets $(cat "${{ env.TEST_TARGETS_JSON_FILE }}" | jq -cr '.test_targets | join(",")') \ --filter_json_dir "${GITHUB_WORKSPACE}/cobalt/testing/filters/${{ matrix.platform}}" \ --label github_${GITHUB_PR_NUMBER:-postsubmit} \ --label builder-${{ matrix.platform }} \