Rust网络模拟库tor-rtmock的使用:Tor运行时模拟与异步网络测试工具
Rust网络模拟库tor-rtmock的使用:Tor运行时模拟与异步网络测试工具
tor-rtmock概述
tor-rtmock
是一个支持对tor-rtcompat
异步运行时进行模拟的库。它提供了可以部分或完全覆盖Runtime
特性的模拟实现,主要用于测试目的。
这个库是Arti项目的一部分,Arti是一个用Rust实现Tor的项目。它被用于为Arti中依赖异步运行时的高级crate编写测试。
主要功能
- 模拟时间流逝(通过
SimpleMockTimeProvider
和MockExecutor
) - 模拟网络连接(通过
MockNetRuntime
) - 仅用于测试目的
综合示例
以下是一个完整的示例,展示了如何使用tor-rtmock
来测试一个依赖网络连接和超时处理的函数:
# #[cfg(miri)] // miri cannot do CLOCK_REALTIME
# return;
use tor_rtcompat::{Runtime, SleepProviderExt as _n};
use std::{io, net::{IpAddr, SocketAddr}, time::Duration};
use futures::{channel::oneshot, io::{AsyncReadExt as _, AsyncWriteExt as _}, poll};
use futures::StreamExt as _;
use std::io::ErrorKind;
use tor_rtmock::{MockRuntime, /*MockNetRuntime,*/ net::MockNetwork};
use tor_rtcompat::{NetStreamProvider as _, NetStreamListener as _};
// 要测试的代码:
// 连接到addr,发送问候信息,并返回服务器的响应
async fn converse(runtime: impl Runtime, addr: &SocketAddr) -> io::Result<Vec<u8>> {
let delay = Duration::new(5,0);
runtime.timeout(delay, async {
let mut conn = runtime.connect(addr).await?;
conn.write_all(b"Hello world!\r\n").await?;
conn.flush().await?;
let mut response = vec![];
conn.read_to_end(&mut response).await?;
io::Result::Ok(response)
}).await?
}
// 在测试模块中:
MockRuntime::test_with_various(|rt| async move {
// 提供的`rt`有一个空的模拟网络
// 我们将其包装在测试中使用的非空网络视图上
let fake_internet = MockNetwork::new();
// 创建一个假装我们在服务器地址的视图
let sip: IpAddr = "198.51.100.99".parse().unwrap();
let srt = fake_internet.builder().add_address(sip).runtime(rt.clone());
// 创建一个假装我们在客户端地址的视图
let cip: IpAddr = "198.51.100.7".parse().unwrap();
let crt = fake_internet.builder().add_address(cip).runtime(rt.clone());
// 辅助函数:生成一个任务来执行`converse`并报告其结果
// 返回一个oneshot::Receiver,当`converse`返回时变为ready
let spawn_test = |saddr| {
let (ret_tx, ret_rx) = oneshot::channel();
let crt = crt.clone();
rt.spawn_identified("function under test", async move {
let ret = converse(crt, &saddr).await;
ret_tx.send(ret).unwrap();
});
ret_rx
};
eprintln!("First test. Nothing is listening.");
let saddr = SocketAddr::new(sip, 1);
let ret = spawn_test(saddr).await.unwrap();
assert_eq!(ret.unwrap_err().kind(), ErrorKind::ConnectionRefused);
eprintln!("Second test. Listening, but no-one picks up the phone: timeout.");
let saddr = SocketAddr::new(sip, 2);
let listener = srt.listen(&saddr).await.unwrap();
let mut ret_fut = spawn_test(saddr);
rt.progress_until_stalled().await; // 让它运行到尽可能远的地方
assert!(ret_fut.t极速赛车开奖结果历史
assert!(poll!(&mut ret_fut).is_pending()); // 替代检查,适用于任何future
rt.advance_by(Duration::from_secs(4)).await; // 运行4秒,<超时
assert!(ret_fut.try_recv().unwrap().is_none()); // 它仍然没有完成
rt.advance_by(Duration::from_secs(1)).await; // 再运行1秒,达到超时
let ret = ret_fut.try_recv().unwrap().unwrap();
assert_eq!(ret.unwrap_err().kind(), ErrorKind::TimedOut);
eprintln!("Third test. Working.");
let saddr = SocketAddr::new(sip, 3);
let listener = srt.listen(&saddr).await.unwrap();
let mut incoming_streams = listener.incoming();
let mut ret_fut = spawn_test(saddr);
let (mut conn, caddr) = incoming_streams.next().await.unwrap().unwrap();
eprintln!("listener accepted from {caddr:?}");
assert_eq!(caddr.ip(), cip);
let expect = b"Hello world!\r\n";
let mut output = vec![b'X'; expect.len()];
conn.read_exact(&mut output).await.unwrap();
eprintln!("listener received {output:?}");
assert_eq!(output, expect);
let reply_data = b"reply data";
conn.write(reply_data).await.unwrap();
conn.close().await.unwrap();
let ret = ret_fut.await.unwrap();
assert_eq!(ret.unwrap(), reply_data);
});
完整示例代码解释
这个示例展示了如何测试一个网络连接函数converse
,该函数会:
- 连接到指定地址
- 发送"Hello world!\r\n"消息
- 读取服务器响应
- 在5秒内超时
测试分为三个场景:
- 测试无服务器监听的情况(应返回连接拒绝错误)
- 测试有服务器监听但不响应的情况(应超时)
- 测试正常工作流程(成功连接并交换数据)
通过MockRuntime
和MockNetwork
,我们能够:
- 完全控制时间流逝(无需实际等待)
- 模拟网络连接(无需实际网络)
- 验证各种边界条件
安装
将以下内容添加到你的Cargo.toml中:
tor-rtmock = "0.32.0"
许可证
MIT OR Apache-2.0
1 回复
Rust网络模拟库tor-rtmock的使用:Tor运行时模拟与异步网络测试工具
介绍
tor-rtmock
是一个用于模拟 Tor 网络运行时的 Rust 库,主要用于异步网络测试场景。它允许开发者在测试环境中模拟 Tor 网络行为,而无需连接到真实的 Tor 网络,特别适合需要隔离网络环境的单元测试和集成测试。
这个库是 Arti 项目(Tor 的 Rust 实现)的一部分,提供了对 Tor 运行时组件的模拟实现,包括模拟网络连接、模拟目录服务等。
主要特性
- 模拟 Tor 网络连接行为
- 支持异步测试环境
- 可配置的模拟网络行为
- 与
async-std
和tokio
兼容 - 提供测试断言工具
完整示例代码
下面是一个完整的测试示例,展示了 tor-rtmock
的主要功能:
use tor_rtmock::{MockSleepRuntime, ConnBehavior, Delay};
use tor_rtcompat::TcpProvider;
use std::time::Duration;
use std::sync::Arc;
#[tokio::test]
async fn test_tor_network_simulation() {
// 1. 创建模拟运行时
let runtime = MockSleepRuntime::new();
// 2. 模拟普通HTTP连接
runtime.network().add_connection(
"http.example.com:80",
b"HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHello Tor!",
);
// 3. 模拟延迟连接
runtime.network().add_connection_with_delay(
"slow.example.com:80",
b"HTTP/1.1 200 OK\r\n\r\nDelayed response",
Delay::new(Duration::from_secs(3)),
);
// 4. 模拟自定义行为连接
let custom_behavior = ConnBehavior::new()
.read_delay(Duration::from_millis(200))
.read_data(b"Custom behavior data")
.close_after(1);
runtime.network().add_connection_with_behavior(
"custom.example.com:80",
Arc::new(custom_behavior),
);
// 测试普通连接
let mut http_conn = runtime.connect("http.example.com:80").await.unwrap();
let mut http_buf = [0u8; 50];
let http_len = http_conn.read(&mut http_buf).await.unwrap();
assert_eq!(&http_buf[..http_len], b"HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHello Tor!");
// 测试超时处理
let timeout_result = tokio::time::timeout(
Duration::from_secs(1),
runtime.connect("slow.example.com:80")
).await;
assert!(timeout_result.is_err());
// 测试自定义行为
let mut custom_conn = runtime.connect("custom.example.com:80").await.unwrap();
let mut custom_buf = [0u8; 50];
let custom_len = custom_conn.read(&mut custom_buf).await.unwrap();
assert_eq!(&custom_buf[..custom_len], b"Custom behavior data");
// 验证网络调用
let calls = runtime.network().check_calls();
assert!(calls.contains(&"http.example.com:80".to_string()));
assert!(calls.contains(&"slow.example.com:80".to_string()));
assert!(calls.contains(&"custom.example.com:80".to_string()));
}
测试技巧
- 隔离测试:每个测试用例应该使用独立的
MockSleepRuntime
实例 - 验证调用:可以使用
runtime.network().check_calls()
验证预期的网络调用是否发生 - 时间控制:模拟时间可以加速测试,避免真实等待
- 错误注入:可以轻松模拟各种网络错误情况
注意事项
- 主要用于测试环境,不适合生产环境
- 模拟行为需要手动配置,可能无法覆盖所有真实网络情况
- 与真实 Tor 网络行为可能存在差异,关键功能仍需真实环境测试
通过 tor-rtmock
,开发者可以高效地编写与 Tor 网络交互的测试代码,而无需依赖外部网络环境或真实的 Tor 连接。