本文档介绍了如何使用 Rust 压力测试编写压力测试
库。该库可在以下位置找到://src/sys/lib/stress-test
。它会实现测试循环,
运行这些测试所需的并发和同步基元。
编写压力测试
定义 GN build 目标
定义 rustc_binary
、fuchsia_component
和 fuchsia_test_package
GN build 目标
测试:
rustc_binary("filesystem-stressor-bin") {
deps = [
...
"//src/sys/lib/stress-test",
...
]
sources = [
...
]
}
fuchsia_component("filesystem-stressor") {
deps = [ ":filesystem-stressor-bin" ]
manifest = "meta/filesystem-stressor.cml"
testonly = true
}
fuchsia_test_package("filesystem-stress-tests") {
test_components = [
":filesystem-stressor"
]
}
写一个演员
每个 activity 都必须实现 Actor
trait。执行者特征是一种 perform()
方法,即
由 ActorRunner
调用。在被调用时,执行者必须只执行一项操作并返回
将其结果提供给运行程序。操作者必须存储执行操作所需的所有连接。
pub trait Actor: Sync + Send + 'static {
// ActorRunner invokes this function, instructing the actor
// to perform exactly one operation and return result.
async fn perform(&mut self) -> Result<(), ActorError>;
}
操作者可以在返回结果中指明以下内容:
Ok(())
:操作成功并添加到全局操作计数中。Err(ActorError::DoNotCount)
:操作不得计入全局操作 计数。Err(ActorError::ResetEnvironment)
:必须重置环境,且不得执行此操作 会计入全局操作次数
当操作者遇到意外错误时,它应 panic,从而停止测试。
由于操作者是在同一环境中进行操作,因此他们的操作可能会 碰撞。例如,对于文件系统压力测试,参与者可以对同一组文件执行操作。 如果需要此类冲突,则必须设置 actor 以妥善处理此类冲突。 否则,执行者会恐慌,导致测试停止。
操作者可能会故意破坏被测系统,从而需要重置环境。对于
例如,对于文件系统压力测试,参与者可以随机切断
文件系统和底层块存储设备在此示例中,其他操作者应请求
ActorError::ResetEnvironment
,并且环境将重新建立连接
pub struct FilesystemActor {
/// Store a connection to the root of filesystem here
pub root_directory: Directory
...
}
impl FilesystemActor {
pub fn new(root_directory: Directory) -> Self {
...
}
}
#[async_trait]
impl Actor for FilesystemActor {
async pub fn perform(&mut self) -> Result<(), ActorError> {
// Choose exactly one operation to do on the filesystem
// using the root_directory
self.root_directory.delete_all_files();
}
}
编写环境
该环境为压力测试提供了基本配置,即退出标准、 演员和重置方法。
pub trait Environment: Send + Sync + Debug {
/// Returns the target number of operations to complete before exiting
fn target_operations(&self) -> Option<u64>;
/// Returns the number of seconds to wait before exiting
fn timeout_seconds(&self) -> Option<u64>;
/// Return the runners for all the actors
async fn actor_runners(&mut self) -> Vec<ActorRunner>;
/// Reset the environment, when an actor requests one
async fn reset(&mut self);
}
环境可以存储测试的其他配置。您可以提供此配置
使用 argh
crate 替换命令行。
actor 在运行程序和环境之间共享,因此必须封装为
Arc<Mutex<dyn Actor>>
。当操作者执行操作时,运行者会持有锁。
这意味着环境只能在操作间获取操作者的锁。
当操作者确定 被测系统发生故障。环境应为 并锁定操作者以更新其与新实例的连接。
环境还必须实现 Debug
trait。压力测试会记录环境
在测试开始时以及测试 panic 时发出通知。常见的做法是输出
这对于重现测试很有价值,例如所使用的随机种子。
#[derive(Debug)]
pub struct FilesystemEnvironment {
fs_actor: Arc<Mutex<FilesystemActor>>,
seed: u64,
...
}
impl Environment {
pub fn new() -> Self {
...
}
}
#[async_trait]
impl Environment for FilesystemEnvironment {
fn target_operations(&self) -> Option<u64> {
// By specifying None here, the test will run without an operation limit
None
}
fn timeout_seconds(&self) -> Option<u64> {
// By specifying None here, the test will run without a time limit
None
}
async fn actor_runners(&mut self) -> Vec<ActorRunner> {
vec![
ActorRunner::new(
"filesystem_actor", // debug name
60, // delay (in seconds) between each operation (0 means no delay)
self.fs_actor.clone()), // actor
)
]
}
async fn reset(&mut self) {
// If the actor is performing an operation, this will remain
// locked until the operation is complete.
let actor = self.fs_actor.lock().await;
// Now the environment can update the actor before it is run again.
actor.root_directory = ...;
// Releasing the lock will resume the runner.
}
}
编写主函数
压力测试的主要功能非常简单,因为其大部分逻辑都是 在环境和参与者中实现的效果。使用 main 函数来收集命令行 参数(如果有),初始化日志记录并设置日志严重性。
#[fuchsia::main]
async fn main() {
// Create the environment
let env = FilesystemEnvironment::new();
// Run the test.
// Depending on the exit criteria, this may never return.
stress_test::run_test(env).await;
}
在本地运行压力测试
由于压力测试是 fuchsia_test_package
的一部分,因此最简单的运行方式之一
与 fx test
命令结合使用:
fx test filesystem-stress-tests
如需使用自定义命令行参数运行测试,请使用 fx shell run
:
fx shell run fuchsia-pkg://fuchsia.com/filesystem-stress-tests#meta/filesystem-stressor.cm <args>
在基础架构上运行压力测试
压力测试由基础架构通过附加到 stress-tests
的标记进行标识,
fuchsia_test_package
或 fuchsia_unittest_package
GN Build 目标。
fuchsia_test_package("filesystem-stress-tests") {
test_components = [
":filesystem-stressor"
]
test_specs = {
environments = [
{
dimensions = {
device_type = "QEMU"
}
tags = [ "stress-tests" ]
},
]
}
}
专用的 core.x64-stress
构建器可以标识这些测试并运行
最长的 22 小时
调试压力测试
该框架使用 Rust log
crate 记录消息。该测试会在以下位置记录环境对象:
以及测试是否出现了问题
--------------------- stressor is starting -----------------------
Environment {
seed: 268479717856254664270968796173957499835,
filesystem_actor: { ... }
...
}
------------------------------------------------------------------
如果启用了调试日志记录,还会记录各个执行者操作和操作计数。
DEBUG: [0][filesystem_actor][389] Sleeping for 2 seconds
DEBUG: [0][filesystem_actor][389] Performing...
DEBUG: [0][filesystem_actor][389] Done!
DEBUG: Counters -> [total:403] {"filesystem_actor": 403}