本文档介绍了如何使用 Rust 压力测试库编写压力测试。该库可以在以下位置找到://src/sys/lib/stress-test
。它实现了测试循环以及运行这些测试所需的并发和同步基元。
编写压力测试
定义 GN build 目标
为您的测试定义 rustc_binary
、fuchsia_component
和 fuchsia_test_package
GN 构建目标:
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"
]
}
写一个演员
每个 actor 都必须实现 Actor
trait。actor trait 是一种由 ActorRunner
调用的 perform()
方法。被调用时,操作方必须仅执行一项操作并将其结果返回给运行程序。操作者必须存储执行操作所需的所有连接。
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)
:必须重置环境,并且不得将操作计入全局操作计数。
当 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 提供此配置。
操作者在运行程序和环境之间共享,因此必须封装为 Arc<Mutex<dyn Actor>>
。运行程序会在操作者执行操作时持有锁。这意味着环境只能在操作之间获取操作者锁。
当操作者确定被测系统的当前实例已损坏时,系统会指示环境重置。环境应为被测系统创建一个新实例,并锁定操作方以更新其与新实例的连接。
环境还必须实现 Debug
trait。压力测试会在测试开始时以及测试是否紧急时记录环境。通常的做法是输出对重现测试有价值的参数,例如所用的随机种子。
#[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.
}
}
编写主函数
压力测试的主要功能很简单,因为大多数逻辑在环境和操作者中实现。使用主函数收集命令行参数(如果有)、初始化日志记录并设置日志严重性。
#[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>
在基础架构上运行压力测试
基础架构通过附加到 fuchsia_test_package
或 fuchsia_unittest_package
GN Build Target 的 stress-tests
标记标识压力测试。
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}