診斷與測試程式碼研究室

本文件包含用於進行診斷和測試的程式碼研究室。這項產品目前的設計對像是開發人員在 fuchsia.git 中編寫測試。

必要條件

設定開發環境。

本程式碼研究室假設您已完成入門指南,並具有:

  1. 一旁有貨,並建造了富希亞樹。
  2. 執行 Fuchsia 的裝置或模擬器 (ffx emu)。
  3. 用來為 Fuchsia 裝置或模擬器提供元件 (fx serve) 的工作站。

如要在本程式碼研究室中建構並執行範例,請在 fx set 叫用中加入下列引數:

fx set core.x64 \
--release \
--with //examples/diagnostics/workshop \
--with //examples/diagnostics/workshop:tests

說明

以下元件範例提供名為 ProfileStore 的通訊協定:

@discoverable
closed protocol ProfileStore {
    strict Open(resource struct {
        key string:KEY_LENGTH;
        channel server_end:Profile;
    });

    strict OpenReader(resource struct {
        key string:KEY_LENGTH;
        channel server_end:ProfileReader;
    });

    strict Delete(struct {
        key string:KEY_LENGTH;
    }) -> (struct {
        success bool;
    });

    strict CreateOrOpen(resource struct {
        key string:KEY_LENGTH;
        channel server_end:Profile;
    });
};

此通訊協定可讓您建立、刪除及檢查使用者個人資料,其中包含名稱和餘額。元件發生錯誤,無法刪除設定檔。

本程式碼研究室的程式碼位於 //example/diagnostics/workshop

執行元件

除了提供 ProfileStore 的主要元件之外,還有一些元件可以連線至 ProfileStore 並與之互動。所有元件都位於 fuchsia-pkg://fuchsia.com/profile_store_example 套件中。

  • #meta/profile_store.cm - 提供 ProfileStore
  • #meta/add_olive.cm - 連結至 ProfileStore,並新增名為「Olive」的設定檔
  • #meta/add_balance_olive.cm - 連結至 ProfileStore,為「橄欖綠」設定檔新增餘額
  • #meta/withdraw_balance_olive.cm - 連線至 ProfileStore,並從「橄欖綠」設定檔提款餘額
  • #meta/add_jane.cm - 連結至 ProfileStore,並新增名為「Jane」的設定檔
  • #meta/delete_olive.cm - 連線至 ProfileStore 並刪除「Olive」設定檔

功能會由 #meta/laboratory_server.cm 元件轉送。

您可以使用 ffx component 指令與元件互動,並使用 ffx log 檢查元件的輸出內容。首先,在殼層執行 ffx log --tags workshop。這個殼層會包含來自元件的所有輸出內容。請在其他殼層中執行玩具元件:

# setup server
ffx component create /core/ffx-laboratory:profile_store fuchsia-pkg://fuchsia.com/profile_store_example#meta/laboratory_server.cm

# setup first client
ffx component create /core/ffx-laboratory:profile_store/clients:add_olive fuchsia-pkg://fuchsia.com/profile_store_example#meta/add_olive.cm

# see the results of the previous two steps
ffx component show profile_store

# add a profile key and read it
ffx component start /core/ffx-laboratory:profile_store/clients:add_olive
ffx component create /core/ffx-laboratory:profile_store/clients:reader fuchsia-pkg://fuchsia.com/profile_store_example#meta/profile_reader.cm
ffx component start /core/ffx-laboratory:profile_store/clients:reader

# demonstrate persistence
ffx component stop /core/ffx-laboratory:profile_store/profile_store
ffx component start /core/ffx-laboratory:profile_store/clients:reader

# update balance
ffx component create /core/ffx-laboratory:profile_store/clients:add_balance_olive fuchsia-pkg://fuchsia.com/profile_store_example#meta/add_balance_olive.cm
ffx component start /core/ffx-laboratory:profile_store/clients:add_balance_olive
ffx component start /core/ffx-laboratory:profile_store/clients:reader

# add second profile
ffx component create /core/ffx-laboratory:profile_store/clients:add_jane fuchsia-pkg://fuchsia.com/profile_store_example#meta/add_jane.cm
ffx component start /core/ffx-laboratory:profile_store/clients:add_jane
ffx component start /core/ffx-laboratory:profile_store/clients:reader

# update balance
ffx component create /core/ffx-laboratory:profile_store/clients:withdraw_balance_olive fuchsia-pkg://fuchsia.com/profile_store_example#meta/withdraw_balance_olive.cm
ffx component start /core/ffx-laboratory:profile_store/clients:withdraw_balance_olive
ffx component start /core/ffx-laboratory:profile_store/clients:reader

# delete olive (this will not work as there is a bug in the server code)
ffx component create /core/ffx-laboratory:profile_store/clients:delete_olive fuchsia-pkg://fuchsia.com/profile_store_example#meta/delete_olive.cm
ffx component start /core/ffx-laboratory:profile_store/clients:delete_olive
ffx component start /core/ffx-laboratory:profile_store/clients:reader

透過診斷偵錯

「診斷」提供多種產品,可協助元件作者在開發時與實際工作中偵錯。

本研討會將探討三項核心技術:

結構化記錄

「診斷」提供結構化的記錄程式庫,允許元件寫入記錄檔。為協助找出錯誤,我們會在設定檔商店元件中新增一些記錄。

將記錄新增至元件的第一步,是在二進位檔依附元件中加入記錄程式庫。方法是按照以下步驟更新 BUILD.gn

source_set("lib") {
  ...
  public_deps = [
    ...
    "//sdk/lib/syslog/cpp",
  ]
}

系統會在呼叫其中一個記錄巨集時初始化記錄。不過,程式庫提供了一些應在 main() 中呼叫的公用程式,例如設定標記 (如果只想提供,則可視情況選用)。

標記日後可查詢一組元件的記錄檔。我們可以新增 workshop 標記,以滿足需求:

#include <lib/syslog/cpp/log_settings.h>
...
fuchsia_logging::SetTags({"workshop", "profile_store_server"});

接著要寫入一些記錄了。我們將使用 FX_SLOG 巨集,這允許寫入結構化鍵和值。

舉例來說,如果我們收到 ProfileStore::Open 的要求,但設定檔不存在,可以新增下列記錄:

#include <lib/syslog/cpp/macros.h>
...
FX_SLOG(WARNING, "Profile doesn't exist", KV("key", key.c_str()));

請嘗試新增該記錄、建構 (fx build),重新啟動元件 (ffx component start ...),然後執行:ffx log --tags workshop

我們還能加入哪些記錄,有助於識別記錄?請多多嘗試!

如需解決方案,請參閱這個修補程式

檢查

檢查可讓元件公開關於自身的狀態。與記錄 (串流) 不同,「檢查」代表元件目前狀態的即時檢視畫面。

建議先閱讀檢查快速入門導覽課程,如要進一步瞭解檢查,也可以按照檢查程式碼研究室的說明操作。

如要開始使用,請先新增程式庫依附元件:

source_set("lib") {
  ...
  public_deps = [
    ...
    "//sdk/lib/inspect/component/cpp",
  ]
}

接著,在 main.cc 中初始化檢查:

#include <lib/inspect/component/cpp/component.h>
...
// Immediately following the line defining "startup".
auto inspector = std::make_unique<inspect::ComponentInspector>(async_get_default_dispatcher(), inspect::PublishOptions{});
inspector->Health().Ok();

重新啟動 profile_store 後,您現在可以查看檢查內容:

# Note that double \\ is necessary! ':' must be escaped in a "diagnostic selector."
ffx inspect show core/ffx-laboratory\\:profile_store/profile_store

您應該會看到元件的狀態為「OK」。與類別階層整合時,檢查功能最實用。任意值以 inspect::Node 為基礎,包括更多節點!您可以嘗試修改 ProfileStore,以便執行下列編譯:

  // In main.cc
  std::unique_ptr<ProfileStore> profile_store =
      std::make_unique<ProfileStore>(loop.dispatcher(), inspector->GetRoot().CreateChild("profiles"));

提示:如果變更 ProfileStore 的建構函式,就必須更新 ProfileStoreTests 類別。您只要傳遞 inspect::Node() 做為新參數即可。

現在您已經設定基本檢查功能,接下來可以加入哪項結構,以防止/找出這個元件中的錯誤?- 請考慮為每個 Profile 新增 inspect::Node,並在傳遞至 ProfileStore 的節點上使用 CreateChild 建立這些元件。- 建議使用 inspect::LazyNode (node.CreateLazyNode(...)) 動態建立階層。

如需可能的解決方案,請參閱以下修補程式: https://fuchsia-review.googlesource.com/c/fuchsia/+/682671

分類

分類可讓您編寫規則來自動處理檢查快照並找出潛在問題,或是收集快照可能包含的統計資料。

建議先詳閱「行程程式碼研究室」,並詳閱分類設定指南

如要開始使用,請在 examples/diagnostics/workshop/triage/profile_store.triage 中使用下列內容建立新檔案:

{
  select: {
    profile_status: "INSPECT:core/ffx-laboratory\\:profile_store/profile_store:fuchsia.inspect.Health:status",
  },
  act: {
    profile_status_ok: {
      type: "Warning",
      trigger: "profile_status != 'OK'",
      print: "Profile store is not healthy.",
    }
  }
}

如果您按照上一節的「檢查快速入門」操作,請執行 ffx triage --config examples/diagnostics/workshop/triage/。如果 profile_store 正在執行,且回報狀態正常,您不會看到任何失敗!請嘗試將 main.cc 中的 Health().Ok() 呼叫變更為 Health().StartingUp(),然後再次執行 ffx triage --config examples/diagnostics/workshop/triage/。這次應會顯示這則警告。

嘗試撰寫分類設定,可能有助於找出現場收集的快照中的錯誤。

以下修補程式是以檢查解決方案為基礎建構的可能解決方案: https://fuchsia-review.googlesource.com/c/fuchsia/+/684762

使用測試進行驗證

本節說明如何新增測試,以便驗證修正結果。

這個範例含有單元測試範例整合測試範例,包括部分因錯誤而停用的測試。

嘗試編寫新的測試,避免元件發生錯誤。您可以修改範例測試,或按照下方流程從頭開始建立新測試。

新增單元測試

單元測試的程式碼結構主要取決於使用的執行階段。本節將逐步說明如何設定新的單元測試,以便驗證 ProfileStore C++ 類別的行為。

examples/diagnostics/workshop/profile_store_unittest.cc 中以下列內容建立新檔案:

#include "src/lib/testing/loop_fixture/test_loop_fixture.h"

#include <gtest/gtest.h>

#include "fuchsia/examples/diagnostics/cpp/fidl.h"
#include "lib/fidl/cpp/interface_ptr.h"
#include "profile_store.h"

class ProfileStoreTests : public gtest::TestLoopFixture {};

TEST_F(ProfileStoreTests, SampleTest) {
    ProfileStore store(dispatcher());
    fidl::InterfacePtr<fuchsia::examples::diagnostics::ProfileStore> store_ptr;
    store.AddBinding(store_ptr.NewRequest(dispatcher()));

    store_ptr->Delete("my_key", [&](bool successful) { EXPECT_FALSE(successful); });
    RunLoopUntilIdle();
}

這會設定用來建立 ProfileStore 的最低單元測試,並建立用戶端,以便在非同步測試迴圈下與其互動。接下來,您將建立測試的元件資訊清單,定義如何執行測試。為 examples/diagnostics/workshop/meta/profile_store_unittests.cm 中的測試建立新的元件資訊清單,並在其中加入以下內容:

{
    include: [
        // Needed for gtest runners
        "//src/sys/test_runners/gtest/default.shard.cml",
        // Needed so that logs are created
        "syslog/client.shard.cml",
    ],
    program: {
        binary: "bin/profile_store_unittests",
    },
    use: [
        {
            // ProfileStore uses /data to store profiles. We'll use the tmp
            // storage provided to the test.
            storage: "tmp",
            path: "/data",
        },
    ],
}

最後,將新的建構規則新增至 examples/diagnostics/workshop/BUILD.gn


# Builds the test binary.
executable("test_bin") {
  testonly = true
  output_name = "profile_store_unittests"

  sources = [
    "profile_store_unittest.cc",
  ]

  deps = [
    ":lib",
    "//src/lib/fxl/test:gtest_main",
    "//src/lib/testing/loop_fixture",
  ]
}

# Creates a test component and test package.
fuchsia_unittest_package("profile_store_unittests") {
  deps = [ ":test_bin" ]
  manifest = "meta/profile_store_unittests.cml"
}

# Update the existing group("tests") to include the new package as a dep
group("tests") {
  testonly = true
  deps = [
    # new dependency
    ":profile_store_unittests",

    ":profile_store_example_unittests",
    "example-integration:tests",
  ]
}

接著,驗證測試版本並執行。

# Build is needed the first time so that fx test becomes aware of the new test.
# For subsequent test executions, fx build is automatically invoked.
fx build examples/diagnostics/workshop:tests

fx test profile_store_unittests

您現在可以修改測試程式碼來驗證行為。

新增整合測試

fx testgen 指令會自動產生整合測試樣板設定,以便使用 RealmBuilder。如要使用,您需要在輸出目錄中找出 profile_store 元件的編譯元件資訊清單。

# find the manifest in output directory.
find $(fx get-build-dir) -name profile_store.cm

# generate integration tests.
fx testgen --cm-location find result --out-dir examples/diagnostics/workshop/tests -c

系統隨即會在 examples/diagnostics/workshop/tests 底下產生幾個檔案。在執行測試之前,需要更新以下幾個建構規則:

  • 在新產生的 examples/diagnostics/workshop/tests/BUILD.gn
    • {COMPONENT_FIDL_BUILD_TARGET} 替換為 ProfileStore fidl 的建構目標 - //examples/diagnostics/workshop/fidl:fuchsia.examples.diagnostics
    • {COMPONENT_BUILD_TARGET} 替換為 ProfileStore 元件的建構目標 - //examples/diagnostics/workshop:profile_store/
  • examples/diagnostics/workshop/BUILD.gn
    • group("tests") 定義中新增「tests」至依附元件。確保 GN 能找到新的測試。

接著,驗證測試版本並執行。

# Build is needed the first time so that fx test becomes aware of the new test.
# For subsequent test executions, fx build is automatically invoked.
fx build examples/diagnostics/workshop:tests

fx test profile_store_test

測試執行後,您就可以修改樣板來編寫實用的測試。