測試驅動程式並進行偵錯

Fuchsia 支援使用 Fuchsia 偵錯工具 (zxdb) 逐步偵錯元件。偵錯工具會附加至元件執行的主機程序,讓開發人員設定中斷點,並逐步完成程式碼執行工作。開發人員可透過測試執行工具架構編寫測試,以執行驅動程式庫元件。

在本節中,您將使用 Fuchsia 偵錯工具 (zxdb) 檢查正在執行的驅動程式庫,並建構測試元件來運用驅動程式庫的功能。

連結偵錯工具

如要將 Fuchsia 偵錯工具連線至驅動程式庫元件,請先判斷主機程序的 PID。使用 ffx driver list-hosts 指令,找出載入驅動程式庫的主機程序 PID:

ffx driver list-hosts

這個指令會輸出類似以下的清單。找出列出 qemu_edu 驅動程式庫的驅動程式代管程序:

Driver Host: 5053
    fuchsia-boot:///#meta/block.core.cm
    fuchsia-boot:///#meta/bus-pci.cm
    fuchsia-boot:///#meta/cpu-trace.cm
    fuchsia-boot:///#meta/fvm.cm
    fuchsia-boot:///#meta/hid.cm
    fuchsia-boot:///#meta/netdevice-migration.cm
    fuchsia-boot:///#meta/network-device.cm
    fuchsia-boot:///#meta/platform-bus-x86.cm
    fuchsia-boot:///#meta/platform-bus.cm
    fuchsia-boot:///#meta/ramdisk.cm
    fuchsia-boot:///#meta/sysmem.cm
    fuchsia-boot:///#meta/virtio_block.cm
    fuchsia-boot:///#meta/virtio_ethernet.cm
    fuchsia-pkg://fuchsia.com/virtual_audio#meta/virtual_audio_driver.cm

Driver Host: 7774
    fuchsia-boot:///#meta/intel-rtc.cm

Driver Host: 7855
    fuchsia-boot:///#meta/pc-ps2.cm

Driver Host: 44887 
    fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm 

請記下 qemu_edu 驅動程式代管程序的 PID。 在上述範例中,PID 為 44887。

使用 ffx debug connect 啟動 Fuchsia 偵錯工具:

ffx debug connect

偵錯工具連上目標裝置後,請從 zxdb 提示附加至 qemu_edu 驅動程式庫主機:

[zxdb] attach HOST_PID

HOST_PID 換成上一個步驟中識別的驅動程式代管程序 PID。例如:

[zxdb] attach 44887

在驅動程式庫的 ComputeFactorial 函式中設定中斷點:

[zxdb] break QemuEduServer::ComputeFactorial

指令會列印類似以下的輸出內容,指出中斷點的設定位置:

[zxdb] break QemuEduServer::ComputeFactorial
Created Breakpoint 1 @ QemuEduServer::ComputeFactorial
   47 void QemuEduServer::ComputeFactorial(ComputeFactorialRequestView request,
 ◉ 48                                      ComputeFactorialCompleter::Sync& completer) {
   49   auto edu_device = device_.lock();

逐步執行驅動程式庫函式

在另一個終端機中,再次執行 eductl 工具:

bazel run //fuchsia-codelab/qemu_edu/tools:pkg.eductl_tool -- fact 12

zxdb 終端機中,確認偵錯工具已在驅動程式庫的 ComputeFactorial 函式中觸發中斷點。例如:

🛑 thread 2 on bp 1 qemu_edu::QemuEduServer::ComputeFactorial(qemu_edu::QemuEduServer*, fidl::WireServer<fuchsia_examples_qemuedu::Device>::ComputeFactorialRequestView, fidl::Completer<fidl::internal::WireCompleterBase<fuchsia_examples_qemuedu::Device::ComputeFactorial> >::Sync&) • qemu_edu.cc:144
   46 // Driver Service: Compute factorial on the edu device
   47 void QemuEduServer::ComputeFactorial(ComputeFactorialRequestView request,
 ▶ 48                                      ComputeFactorialCompleter::Sync& completer) {
   49   auto edu_device = device_.lock();
   50   if (!edu_device) {

zxdb 提示中,使用 list 指令顯示目前暫停執行的位置:

[zxdb] list

這個指令會輸出類似以下的內容:

   46 // Driver Service: Compute factorial on the edu device
   47 void QemuEduServer::ComputeFactorial(ComputeFactorialRequestView request,
 ▶ 48                                      ComputeFactorialCompleter::Sync& completer) {
   49   auto edu_device = device_.lock();
   50   if (!edu_device) {
   51     FDF_LOG(ERROR, "Unable to access device resources.");
   52     completer.ReplyError(ZX_ERR_BAD_STATE);
   53     return;
   54   }
   55
   56   uint32_t input = request->input;
   57
   58   edu_device->ComputeFactorial(input);

使用 next 指令逐步執行 ComputeFactorial 函式:

[zxdb] next

列印傳遞至函式的要求內容:

[zxdb] print request

指令會列印輸出內容,其中包含階乘輸入值:

(*)0x747c1f2e98 ➔ {input = 12}

結束偵錯工具工作階段並中斷連線:

[zxdb] exit

建立新的系統測試元件

在本節中,您將建立新的測試元件,以練習 qemu_edu 驅動程式庫公開的函式。

在 Bazel 工作區中,為新的測試元件建立新的專案目錄:

mkdir -p fuchsia-codelab/qemu_edu/tests

完成本節後,專案應具有下列目錄結構:

//fuchsia-codelab/qemu_edu/tests
                  |- BUILD.bazel
                  |- meta
                  |   |- qemu_edu_system_test.cml
                  |- qemu_edu_system_test.cc

建立 qemu_edu/tests/BUILD.bazel 檔案,並加入下列陳述式,從 Fuchsia SDK 納入必要的建構規則:

qemu_edu/tests/BUILD.bazel

load(
    "@rules_fuchsia//fuchsia:defs.bzl",
    "fuchsia_cc_test",
    "fuchsia_component_manifest",
    "fuchsia_select",
    "fuchsia_test_component",
    "fuchsia_test_package",
)

在專案中建立新的 qemu_edu/tests/meta/qemu_edu_system_test.cml 元件資訊清單檔案,並加入下列內容:

qemu_edu/tests/meta/qemu_edu_system_test.cml

{
    include: [
        "//sdk/lib/gtest/gtest.shard.cml",
        "syslog/client.shard.cml",
    ],
    program: {
        runner: "gtest_runner",
        test: "bin/qemu_edu_system_test",
    },
    use: [
        {
            service: "fuchsia.examples.qemuedu.DeviceService",
            from: "parent",
        },
    ],
}

測試元件會使用 fuchsia.examples.qemuedu.DeviceService 服務能力探索及存取驅動程式庫。這個元件也包含 elf_test_runner.shard.cml,因此可使用 Test Runner Framework 執行。

建立新的 qemu_edu/tests/qemu_edu_system_test.cc 檔案,並在當中加入下列內容來實作測試:

qemu_edu/tests/qemu_edu_system_test.cc

#include <lib/component/incoming/cpp/service_member_watcher.h>
#include <gtest/gtest.h>

#include "fidl/examples.qemuedu/cpp/wire.h"

namespace {

class QemuEduSystemTest : public testing::Test {
 public:
  void SetUp() override {
    component::SyncServiceMemberWatcher<examples_qemuedu::Service::Device> watcher;
    zx::result<fidl::ClientEnd<examples_qemuedu::Device>> client_end = watcher.GetNextInstance(true);
    ASSERT_EQ(client_end.status_value(), ZX_OK);
    device_ = fidl::WireSyncClient(std::move(*client_end));
  }

  fidl::WireSyncClient<examples_qemuedu::Device>& device() { return device_; }

 private:
  fidl::WireSyncClient<examples_qemuedu::Device> device_;
};

TEST_F(QemuEduSystemTest, LivenessCheck) {
  fidl::WireResult result = device()->LivenessCheck();
  ASSERT_EQ(result.status(), ZX_OK);
  ASSERT_TRUE(result->value()->result);
}

TEST_F(QemuEduSystemTest, ComputeFactorial) {
  std::array<uint32_t, 11> kExpected = {
      1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800,
  };
  for (uint32_t i = 0; i < kExpected.size(); i++) {
    fidl::WireResult result = device()->ComputeFactorial(i);
    ASSERT_EQ(result.status(), ZX_OK);
    EXPECT_EQ(result->value()->output, kExpected[i]);
  }
}

}  // namespace

每個測試案例都會連線至驅動程式庫服務,並執行其中一個公開函式。

在專案的建構設定中新增下列規則,將測試元件建構為 Fuchsia 測試套件:

qemu_edu/tests/BUILD.bazel

fuchsia_cc_test(
    name = "qemu_edu_system_test",
    size = "small",
    srcs = [
        "qemu_edu_system_test.cc",
    ],
    deps = ["@com_google_googletest//:gtest_main"] + fuchsia_select({
        "@platforms//os:fuchsia": [
            "//fuchsia-codelab/qemu_edu/fidl:examples.qemuedu_cc",
            "@fuchsia_sdk//pkg/driver_incoming_cpp",
        ],
    }),
)

fuchsia_component_manifest(
    name = "manifest",
    src = "meta/qemu_edu_system_test.cml",
    includes = [
        "@fuchsia_sdk//pkg/sys/testing:elf_test_runner",
        "@fuchsia_sdk//pkg/syslog:client",
    ],
)

fuchsia_test_component(
    name = "component",
    manifest = "manifest",
    deps = [
        ":qemu_edu_system_test",
    ],
)

fuchsia_test_package(
    name = "pkg",
    package_name = "qemu_edu_system_test",
    test_components = [
        ":component",
    ],
    visibility = ["//visibility:public"],
)

執行系統測試

使用 bazel run 指令建構及執行測試元件目標:

bazel run //fuchsia-codelab/qemu_edu/tests:pkg.component

bazel run 指令會執行下列步驟:

  1. 建構元件並套件。
  2. 將套件發布至本機套件存放區。
  3. 向目標裝置註冊套件存放區。
  4. 使用 ffx test run 執行元件的測試套件。

確認所有測試都順利通過:

Running test 'fuchsia-pkg://bazel.test.pkg.system.test.component/qemu_edu_system_test#meta/qemu_edu_system_test.cm'
[RUNNING]   main
[stdout - main]
Running main() from gmock_main.cc
[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from QemuEduSystemTest
[ RUN      ] QemuEduSystemTest.LivenessCheck
[       OK ] QemuEduSystemTest.LivenessCheck (4 ms)
[ RUN      ] QemuEduSystemTest.ComputeFactorial
[       OK ] QemuEduSystemTest.ComputeFactorial (4 ms)
[----------] 2 tests from QemuEduSystemTest (9 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (9 ms total)
[  PASSED  ] 2 tests.
[PASSED]    main

後續步驟

恭喜!您已成功偵錯並將測試新增至 Fuchsia 驅動程式庫。

您已體驗在 Fuchsia 上開發驅動程式的基本概念,現在可以進一步深入瞭解:

驅動程式概念