本文件包含用於進行診斷和測試的程式碼研究室。這項產品目前的設計對像是開發人員在 fuchsia.git 中編寫測試。
必要條件
設定開發環境。
本程式碼研究室假設您已完成入門指南,並具有:
- 一旁有貨,並建造了富希亞樹。
- 執行 Fuchsia 的裝置或模擬器 (
ffx emu
)。 - 用來為 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
測試執行後,您就可以修改樣板來編寫實用的測試。