Bazel 測試

範圍

本文說明如何定義、建構及執行 Bazel 圖表中專屬的測試。

Fuchsia 僅支援符合下列條件的 Bazel 主機測試

  • 這些測試必須完全使用 Bazel 建構,也就是說,測試不得依附於先前 Ninja 叫用產生的構件。

  • 這些測試只包含可在相容主機系統上執行的二進位檔和執行階段檔案,且「未」連線至任何 Fuchsia 裝置或模擬器。

fxbug.dev/546173288 會追蹤 Bazel 中支援的目標測試。

在 Bazel 中定義 Fuchsia 主機測試

一般 Bazel 測試規則 (例如 rustc_testgo_test) 與 Fuchsia 測試執行器不相容。fx test無法查看這些檔案,基礎架構建構工具也不會執行這些檔案。

因此,如要在 Bazel 中定義與 Fuchsia 相容的主機測試,請執行下列操作:

  • 使用 //build/bazel/rules/host_tests:host_<xxx>_test.bzl 中的語言專屬主機測試包裝函式,例如 host_rustc_test()host_go_test() 等。

    這些規則的設計目的是取代一般的 Bazel 測試規則,並提供 test_datatest_args 等額外引數,因此 Fuchsia 測試執行器可以透過正確的執行階段環境和引數叫用這些規則。

  • 只有在測試沒有適用的語言專屬包裝函式時,才使用 host_test() 的一般包裝函式 (來自 //build/bazel/rules/host_tests:host_test.bzl)。例如:

    load("//build/bazel/rules/host_tests:host_test.bzl", "host_test")
    load("@rules_sh//sh:sh_binary.bzl", "sh_binary")
    
    sh_binary(
        name = "test_bin",
        ...
    )
    
    host_test(
        name = "shell_test",
        binary = ":test_bin",
    )
    
  • 假設測試二進位檔的執行位置 (例如從 out/default),因為系統會從確切路徑無法預測的目錄啟動測試。

    Bazel 主機測試必須是密封的,並明確列出所有執行階段依附元件,就像 GN 主機測試一樣。您可以透過下列其中一種機制提供執行階段依附元件:

    • 做為 test_data 依附元件,指向 host_test_data_files()host_test_data_map() 目標 (請參閱 //build/bazel/rules/host_tests:host_test_data.bzl)。 這些依附元件會讓檔案在執行階段可供使用,且檔案位置相對於測試的執行目錄,與 GN host_test_data() 範本類似。

    • 做為 host_xxx_test() 目標的 data 屬性。 在這種情況下,檔案會新增至測試的執行檔,並可使用執行檔程式庫存取。

  • 使用 test_suite() 定義測試群組,而不是 filegroup()。 測試套件可以依附於測試和其他測試套件。

將 Bazel 主機測試匯出至 fx test 和基礎架構建構工具

單獨定義 host_xxx_test() 目標不會fx test 和基礎架構建構人員看到該目標。

如要讓 fx test 和基礎架構建構工具可見 Bazel 主機測試,請在 GN 中編寫 bazel_test_suite 目標,列出一個或多個 Bazel 主機測試或套件的 Bazel 標籤,然後將該目標新增至 GN 中的「tests」群組。例如:

//src/foo/bar/BUILD.bazel

load("//build/bazel/platforms:constraints.bzl", "HOST_OS_CONSTRAINTS")

test_suite(
  name = "host_tests",
  host_tests = [
    "//src/foo/bar/lib:lib_tests",
    "//src/foo/bar/util:util_tests",
  ]
  target_compatible_with = HOST_OS_CONSTRAINTS,
)

//src/foo/bar/BUILD.gn

import("//build/bazel/bazel_test_suite.gni")

bazel_test_suite("bazel_tests") {
  host_tests = [
    # This references the target in BUILD.bazel.
    "//src/foo/bar:host_tests",
  ]
}

group("tests") {
  deps = [
    ":bazel_tests",
    ...
  ]
}

這樣一來,Bazel 測試的項目就會顯示在 out/default/tests.json 中。如有疑問,請在 fx setfx gen 後檢查這個檔案的內容。Bazel 測試的 label 欄位開頭為 @

開發期間,定義測試目標後,即可建構及執行測試目標,然後再如上所述匯出。請參閱下方的「直接使用 Bazel 執行測試」一節。

最佳做法

建議避免 Bazel test_suite 目標的深層巢狀結構。請改為每個原始碼子區域 (例如主機工具或 Fuchsia 元件) 只使用一個 test_suite Bazel 目標和一個對應的 bazel_test_suite GN 目標。

執行 Fuchsia Bazel 主機測試

本機測試

使用 fx test 執行測試

如要使用 fx test 執行 Bazel 主機測試,必須按照上方「將 Bazel 主機測試匯出至 fx test 和基礎架構建構工具」一節的說明匯出測試。

匯出測試後,請使用 fx test --host <name_or_label> 在本機建構及執行 Bazel 主機測試,與 GN 定義的主機測試相同。

唯一不同的是,系統會直接叫用 Bazel 隨選建構測試,完全略過 Ninja。

請注意,使用 fx test 時:

  • <name_or_label> 會進行模糊比對,如果情況不明確,fx test 會回報多個候選項目。

  • <name_or_label> 無法參照 Bazel test_suite() 標籤,就像無法參照 GN group() 標籤一樣。

如要進一步瞭解如何使用 fx test,請參閱「fx 測試使用者指南」。

直接使用 fx bazel test 執行測試

您可以使用 fx bazel test --config=host <target_pattern>,直接透過 Bazel 在本機建構及執行測試。這樣就不需要額外的管道,讓 fx test 看到測試,如上一節所述,且具有下列優點:

  • <target_pattern> 是一組 Bazel 目標模式,可比對「指定套件中的所有測試目標」,在這種情況下,Bazel 會自動略過非測試目標。

  • <target_pattern> 可以比對 test_suite() 標籤,方便您在開發期間重複執行一組主機測試。

  • bazel test 會快取測試結果,且只會重新執行上次叫用後,受最新變更影響的測試。

    (使用 --nocache_test_results 旗標即可停用)。

  • <target_pattern> 可以參照 tests.json 中未顯示的標籤。 新增測試時,這項功能非常實用。

基礎架構測試

只有列在 tests.json 中的主機測試,才能在基礎架構測試機器人上啟動。這同樣適用於 GN 和 Bazel 主機測試。因此,您必須按照上方的「將 Bazel 主機測試匯出至 fx test 和基礎架構建構工具」一節,確保測試在 tests.json 中顯示,否則基礎架構不會持續測試。

基礎架構會使用 fint 建構 Bazel 測試,在執行 ninja 後直接呼叫 bazel build,建構 bazel_test_suite GN 目標中列出的所有 Bazel 測試。

在基礎架構測試執行器上執行 GN 和 Bazel 定義的主機測試,或收集結果時,兩者之間沒有明確區別。特別是基礎架構不會使用 bazel test 執行測試。而是會採用 bazel build 產生的二進位檔,並直接執行這些檔案,就像處理 Ninja 的主機測試一樣。

偵錯符號傳播

使用除錯符號編譯的主機測試二進位檔必須註冊未經剝除的 ELF 二進位檔,工具才能將回溯追蹤符號化,並將 LLVM 程式碼涵蓋率設定檔 (-profile-correlate=binary) 相互關聯。

如要瞭解 Fuchsia 管理 Bazel 偵錯符號的一般背景資訊,請參閱「偵錯符號產生技術附註」。

使用偵錯符號編寫主機測試規則

一般 host_test() 規則會在 FuchsiaHostTestInfo 供應器中公開 unstripped_binary 欄位:

  • 如果未明確設定 unstripped_binaryhost_test() 會檢查基礎 binary 屬性:

    • 如果 binary 提供 DebugPackageInfo (C++ 目標),則會使用 DebugPackageInfo.unstripped_file
    • 如果 binary 提供 CrateInfo (Rust 目標),則會使用 CrateInfo.output
  • 如果測試使用包裝函式指令碼啟動器 (例如 host_rustc_test() 中的 rust_test_parser),巨集必須透過 unstripped_binary 明確轉送原始未經剝除的二進位目標:

    host_test(
        name = name,
        binary = wrapper_script,
        unstripped_binary = ":" + binary_name,
        ...
    )
    

傳播至基礎架構和 debuginfod

將 Bazel 主機測試匯出至 GN 建構時:

  1. 測試查詢bazel_tests_utils.py 會使用 //build/bazel/starlark/FuchsiaHostTestInfo.cquery 執行 bazel cquery,並為所有已註冊的主機測試擷取 unstripped_binary 的 execroot 路徑。

  2. 主機測試資訊清單:路徑會相對於 Ninja 建構目錄進行正規化,並寫入 ${root_build_dir}/bazel_host_tests.debug_symbols.json

  3. GN Build API 整合//:bazel_test_suites 會在 BUILD.gn 中附加指向 bazel_host_tests.debug_symbols.jsondebug_symbol_manifests 中繼資料,供 build_api_module("debug_symbols") 目標使用。

  4. Artifactory 上傳:在 CI/CQ 建構作業中,Artifactory 會處理 debug_symbols.json 並將未經剝除的 ELF 二進位檔上傳至雲端儲存空間 / debuginfod 伺服器,讓 covargs 等工具解析建構 ID。

本機開發和 fx coverage

在辦公室本機執行涵蓋範圍時,未提交的二進位檔會產生新的建構 ID,這些 ID 不會出現在 debuginfod 伺服器上。

如要支援本機符號關聯,fx coverage 會執行:

python3 ${FUCHSIA_DIR}/build/bazel/scripts/copy_bazel_debug_symbols.py ${FUCHSIA_BUILD_DIR}

這個指令碼會讀取 bazel_host_tests.debug_symbols.json,計算每個 ELF 二進位檔的 GNU 建構 ID,然後將未剝除的二進位檔複製或符號連結至 ${root_build_dir}/.build-id/xx/yyyyyyyy.debugffx coveragellvm-profdata 等工具會透過 .symbol-index.json 解析這些二進位檔。

常見問題

Bazel 測試相容性

如果 test_suite() 中的任何測試 (或任何依附元件) 與目前的設定不相容 (例如使用 target_compatible_with),系統會在評估套件時略過該測試,而非導致建構失敗。

在指令列上使用 //...:all 等模式時,情況亦同。

詳情請參閱處理不相容目標

執行 test_suite() 或使用目標模式時,開發人員必須確認感興趣的測試回報為 PASSED (而非 SKIPPED)。