FIDL 測試與分析;GN

本文件將標準化我們在 GN 建構系統中定義與組織 FIDL 測試的方式,並遵循下列目標:

  • 名稱一致:如果 Rust 使用 fx test fidl_rust_conformance_tests,則 Go 應使用 fx test fidl_go_conformance_tests。一致且可預測的命名方式可以提供更優質的開發人員體驗。
  • 執行所需操作。測試工作流程應可讓您輕鬆執行單一測試元件,而不必建構或執行任何其他項目。
  • 在主機上執行。請盡可能讓測試支援在主機 (非 Fuchsia) 上執行,因為編輯建構執行的週期通常更快。
  • 遵循最佳做法。您應遵循 Fuchsia 最佳做法,瞭解使用 fx test建構元件等。

術語

本文件使用下列術語:

  • target:BUILD.gn 檔案中定義的 GN 目標
  • toolchain:請參閱 fx gn help toolchain
  • host:開發人員的平台,尤其是 linux 或 mac
  • device:Fuchsia 平台,可以是實體或模擬 (例如 qemu)
  • 套件Fuchsia 套件;Fuchsia 的發行單位
  • 元件Fuchsia 元件;Fuchsia 中的可執行軟體單位

命名

一般原則:

  • 請使用底線,不要使用連字號。
  • 結尾為複數 _tests,而非單數 _test
  • 針對套件、元件和二進位檔,請使用具描述性的完整名稱。

最後一步代表偏好使用全名 (例如 fidl_rust_conformance_tests),而非 conformance_tests 等情境相關名稱。在目錄、套件、元件和二進位檔層級重複「fidl」和「rust」,看起來好像很複雜,而且看起來很冗長。但實際上,這些名稱不得重複,而且最好保持名稱不重複,而不要記住像 fidl-bindings-test 這樣的奇怪規則,fidl-test 代表 Dart,fidl-test 則代表 C。

名稱應採用以下配置,以底線連接部分:

tool [ bindings ] [ category [ subcategory ] ] tests

其中 tool 為下列任一值:

  • fidl:FIDL 執行階段支援
  • fidlc:FIDL 編譯器前端
  • fidlgen:FIDL 編譯器後端
  • gidlmeasure_tape 等工具:其他工具

其他部分包括:

  • 繫結
    • 可以是 ccppcpp_wirehlcpprustgodart
  • categorysubcategory
    • 範例類別:conformancetypesparserlib
    • 「請勿」使用「前端」、「後端」、「繫結」 (工具) 來區分這些項目

階層圖

每個定義測試的 BUILD.gn 檔案都應包含一個 "tests" 群組:

group("tests") {
  testonly = true
  deps = [ ... ]  # not public_deps
}

如果目錄以「tests」結尾,且 BUILD.gn 檔案只定義測試目標,則該群組應改為與目錄名稱相符。例如,foo_tests/BUILD.gn 可以使用 group("foo_tests")。這可讓 GN 標籤簡寫 //path/to/foo_tests (相當於 //path/to/foo_tests:foo_tests)。

這些群組會匯總至父項目錄中的 BUILD.gn 檔案的「tests」群組。根「tests」群組 (針對部分程式碼集,例如 src/lib/fidl/BUILD.gn) 應包含在 bundle/fidl/BUILD.gn。這樣做可讓 fx set ... --with //bundles/fidl:tests 在建構作業中納入所有 FIDL 測試。(由於 //bundles/buildbot/core 包含 //bundles/fidl:tests,因此也會在 CQ 中執行測試)。

二進位檔名稱

通常測試二進位檔名稱是以目標名稱為基礎。舉例來說,test("some_tests") { ... } 目標會產生 some_tests 二進位檔。然而,如果是單一測試,您通常需要多個名稱不重複的多個目標 (來源集、元件、套件等)。因此,本文件中的範例使用目標名稱 (例如 some_tests_bin),並使用 output_name 參數覆寫二進位檔名稱:

test("some_tests_bin") {
  output_name = "some_tests"
  ...
}

這也適用於 rustc_testgo_test 等。

裝置測試

假設我們有可產生 fidl_foo_tests 二進位檔的 :fidl_foo_tests_bin 目標,如要將此套件納入套件,請使用 fuchsia_unittest_package

import("//build/components.gni")

fuchsia_unittest_package("fidl_foo_tests") {
  deps = [ ":fidl_foo_tests_bin" ]
}

我們現在可以使用 fx test fidl_foo_tests,依套件名稱或元件名稱 (兩者相同) 執行測試。

為每項測試使用不同的套件。如果不相關的測試元件組合放在同一個套件中,執行其中一項測試會導致重新建構整個套件。只有打算同時測試 (例如用戶端和伺服器整合測試) 的測試元件時,才應該在套件中組合多個測試元件。如需範例,請參閱複雜拓撲和整合測試

如果測試需要 fuchsia_unittest_component 預設值以外的任何元件功能、服務等項目,則必須編寫元件資訊清單檔案:

# BUILD.gn
import("//build/components.gni")

fuchsia_unittest_package("fidl_foo_tests") {
  manifest = "meta/fidl_foo_tests.cml"
  deps = [ ":fidl_foo_tests_bin" ]
}

# meta/fidl_foo_tests.cml
{
    program: {
        "binary": "bin/fidl_foo_tests"
    },
    use: [
      {
        protocol: [
          "fuchsia.logger.LogSink",   # some example services
          "fuchsia.process.Launcher"
        ]
      }
    ]
}

如要進一步瞭解套件和元件範本,請參閱建構元件

主機測試

假設我們有可產生 fidl_bar_tests 二進位檔的 :fidl_bar_tests_bin 目標,我們必須確保 GN 在達到該目標時位於 $host_toolchain,否則就會嘗試為 Fuchsia 建構 GN:

groups("tests") {
  testonly = true
  deps = [ ":fidl_bar_tests_bin($host_toolchain)" ]
}

(($host_toolchain) 一律應放在 BUILD.gn 檔案的 tests 群組內,而不是 //bundles/fidl:tests)。

這項操作會建立名為 host_x64/fidl_bar_tests 的 test_spec 項目,最終位於 out/default/tests.json 中:

{
  "command": [ "host_x64/fidl_bar_tests", "--test.timeout", "5m" ],
  "cpu": "x64",
  "label": "//PATH/TO/BAR:fidl_bar_tests_bin(//build/toolchain:host_x64)",
  "name": "host_x64/fidl_bar_tests",
  "os": "linux",
  "path": "host_x64/fidl_bar_tests",
  "runtime_deps": "host_x64/gen/PATH/TO/BAR/fidl_bar_tests_bin.deps.json"
}

由於 tests.json 中的「name」欄位,執行 fx test fidl_bar_tests 能夠正常運作。

主機/裝置測試

在主機和裝置上執行的測試分為兩類。在第一個類別中,測試目標只會在其中一個工具鍊下建構。例如:

import("//build/components.gni")

rustc_test("fidl_rust_conformance_tests_bin") {
  output_name = "fidl_rust_conformance_tests"              # host test name
  ...
}

fuchsia_unittest_package("fidl_rust_conformance_tests") {  # device test name
  deps = [ ":fidl_rust_conformance_tests_bin" ]
}

group("tests") {
  testonly = true
  deps = [
    ":fidl_rust_conformance_tests_bin($host_toolchain)",
    ":fidl_rust_conformance_tests",
  ]
}

我們現在可以以下列兩種方式執行測試:

  • 所需裝置:fx test fidl_rust_conformance_tests --device
  • 代管於主機:fx test fidl_rust_conformance_tests --host

在第二個類別中,裝置和主機測試共用原始碼,但兩者差異很大,因此必須由不同目標定義。這會需要將主機測試定義納入 if (is_host) { ... },以免 GN 抱怨多個目標產生相同的輸出。例如:

import("//build/components.gni")

source_set("conformance_test_sources") {
  ...
}

test("fidl_hlcpp_conformance_tests_bin") {
  output_name = "fidl_hlcpp_conformance_tests"
  ...
  deps = [
    ":conformance_test_sources",
    ...
  ]
}

if (is_host) {
  test("fidl_hlcpp_conformance_tests_bin_host") {
    output_name = "fidl_hlcpp_conformance_tests"            # host test name
    ...
    deps = [
      ":conformance_test_sources",
      ...
    ]
  }
}

fuchsia_unittest_package("fidl_hlcpp_conformance_tests") {  # device test name
  deps = [ ":fidl_hlcpp_conformance_tests_bin" ]
}

group("tests") {
  testonly = true
  deps = [
    ":fidl_hlcpp_conformance_tests_bin_host($host_toolchain)",
    ":fidl_hlcpp_conformance_tests",
  ]
}

現在,我們可以透過兩種方式執行測試:

  • 所需裝置:fx test fidl_hlcpp_conformance_tests --device
  • 代管於主機:fx test fidl_hlcpp_conformance_tests --host

Rust 單元測試

Rust 程式庫的定義如下:

rustc_library("baz") {
  with_unit_tests = true
  ...
}

系統會自動建立可建構 baz_lib_test 二進位檔的 baz_test 目標。請勿使用此情況,原因有二:

  1. 命名規範要求加上 _tests 後置字串,而非 _test
  2. 可能會令人感到困惑,日後可能會淘汰

與其使用 with_unit_tests,您需使用適當的名稱分別撰寫 rustc_test 目標:

rustc_library("baz") {
  ...
}

rustc_test("fidl_baz_tests") {
  ...
}

分組

假設我們的測試結構如下:

  • FIDL Rust
    • 裝置
      • 合規
      • 整合
    • 主機
      • 合規

葉子應有測試目標:

  • fx test fidl_rust_conformance_tests
  • fx test fidl_rust_integration_tests

我們不應針對執行不同的測試子集做出其他套件。使用 fx test

  • 執行所有測試:fx test //path/to/fidl/rust
  • 執行所有裝置測試:fx test //path/to/fidl/rust --device
  • 執行所有主機測試:fx test //path/to/fidl/rust --host

參考資料