5个版本
0.0.5 | 2022年3月3日 |
---|---|
0.0.4 | 2022年1月25日 |
0.0.3 | 2020年4月24日 |
0.0.2 | 2019年9月12日 |
0.0.1 | 2019年8月24日 |
#396 in 测试
每月165次下载
2MB
9K SLoC
x86test定制测试运行器
x86test是一个定制测试运行器,允许您编写使用特权(x86)指令的单元测试。
它是这样实现的:为每个单元测试创建一个微小的虚拟机(使用kvm),该虚拟机反映了当前测试进程在客户机虚拟机中的地址空间。然后初始化虚拟机,并跳转到单元测试函数,现在在客户机环0中执行(在这里您可以使用所有您喜欢的指令)。最后,一旦测试返回(或恐慌),控制权从虚拟机返回到我们的测试运行器。
很酷?是的。
使用起来困难吗?不!它通过rust定制测试框架和过程宏与rust紧密集成。请看下面的示例。
它有效吗?它有一些限制(这是预期的,您正在运行裸机x86),所以不要期望有太多基础设施。对于panic和assert,您必须使用特殊版本,而且您不能使用任何进行系统调用的东西(如println!,但提供了一个自定义的sprintln!宏)。
示例
这特别有助于测试x86 crate。例如,假设我们有一个这样的函数
/// Read 16 bits from port
#[inline]
pub unsafe fn inw(port: u16) -> u16 {
let ret: u16;
asm!("inw %dx, %ax", in("dx") port, out("ax") ret, options(att_syntax));
ret
}
inw
的问题在于它需要在E/RFlags中的IO特权级别下运行,以避免引发异常(从而造成进程崩溃)。普通的Linux进程不会以这个特权级别运行,但是我们现在可以编写一个x86test
#[x86test(ioport(0x1, 0xfe))]
fn check_inw_port_read() {
unsafe {
kassert!(
x86::io::inw(0x1) == 0xfe,
"`inw` instruction didn't read the correct value"
);
}
}
这里发生了一些事情,值得解释
首先,我们不是使用 #[test]
,而是使用 #[x86test]
来告诉系统我们不希望使用常规单元测试。 x86test
支持一些参数(更多内容将在后面介绍),这里我们只是告诉测试运行器的“虚拟机管理程序”安装一个端口号为1的ioport,在读取时总是返回0xfe。接下来,是我们的函数声明——这里没有特别之处——然后是unsafe,因为 inw
是不安全的。最后,我们使用 kassert!
,这是一个在虚拟机管理程序的guest ring 0中工作的自定义断言宏,来检查 inw
是否做了正确的事情。
你可以在 x86 测试 中找到更多示例测试。请注意,目前运行 x86test 仅适用于 Linux,并需要一些链接魔术。设置 RUSTFLAGS="-C relocation-model=dynamic-no-pic -C code-model=kernel"
应该可以。我预计将来不再需要自定义的 RUSTFLAGS
。
x86test 参考文档
目前 x86test 属性支持以下参数
ioport(port, val)
:读取到port
将返回val
,对port
的写入操作如果不是val
将使测试失败。ram(from, to)
:在地址范围from
--to
中添加物理内存。should_halt
:告诉虚拟机管理程序测试将停止(注意:使用方法如#[x86test(should_halt)]
)。#[should_panic]
:如果测试预期会崩溃,则可以添加。
代码组织
- x86test_macro:包含
x86test
的过程宏实现。 - x86test_types:包含 kassert、kpanic 和 X86TestFn 结构体的实现。
- src:包含自定义测试运行器的实现。
更新
应按照以下顺序进行
- 发布
x86test-types
的新版本 - 发布
x86test-macro
的新版本(调整 x86test-types 的版本依赖关系) - 发布
x86test
的新版本(调整 x86test-types 和 x86test-macro 的版本依赖关系) - 使用
git tag x86test-0.0.x
标记