#fuzz-testing #testing #testing-utilities #fuzz #utility #async

reord

以可重复的方式多线程运行您的测试

10 个版本

0.2.3 2024 年 1 月 30 日
0.2.2 2024 年 1 月 16 日
0.1.5 2024 年 1 月 11 日

#191 in 并发

Download history 13/week @ 2024-03-11 13/week @ 2024-03-18 15/week @ 2024-04-01 13/week @ 2024-04-08 2/week @ 2024-05-06 9/week @ 2024-05-20 137/week @ 2024-05-27 34/week @ 2024-06-03 20/week @ 2024-06-10 1/week @ 2024-06-17 14/week @ 2024-06-24

每月下载 74

MIT/Apache

48KB
1K SLoC

reord

以可重复的方式多线程运行您的测试。

此 crate 提供测试工具,以验证您的代码是否符合某些并发条件。

它将以随机顺序交错运行多个异步任务,以验证大多数执行路径是否验证了测试声明的属性。

此外,如果配置为,它可以在每次理论上的锁冲突后等待一段时间,如果锁被获取了两次则失败。这在尝试使用外部工具加锁或实现自定义锁时很有用。

为什么不选择 loom

loom 是一个完整的模型检查器,可以完全验证您的代码是否正确。如果您的代码可以由 loom 检查,那么请务必这样做,loom 在检查您的 crate 方面将比 reord 做得更好!

但是,loom 要求您将所有互斥访问替换为 loom 的互斥访问。这并不总是可能的,例如,当您有一些被 FFI 捕获的互斥锁时。或者更糟糕的是,这个 crate 被写出来的原因,当您试图验证 postgreSQL 事务是否以适当的锁定行为写入时。

reord 究竟做了什么?

reord 不会对您的代码进行模型检查。它只会运行一次,就像它在多线程中运行一样。然而,它会为您提供一个主要的东西:确定性的交错,这将允许您重现您的错误。

这使得 reord 适合在 fuzzer 中使用,以多次运行您的测试,并使用不同的代码路径。

如何使用 reord

您可以在生产代码中(并且应该)散布调用 reord 函数,因为它只有在设置了 reord/test 功能时才会编译为空操作。 reord 能够在任何 reord::point().await 调用处混合您的线程。请注意,调用任何 reord 函数隐式地意味着调用 reord::point,除了由于缺少 async Drop 而释放锁的情况。

需要注意的是,reord 一次只能运行一个任务。所以如果您获取锁,必须意识到这一点,以避免一个任务在另一个任务持有的锁上阻塞。有两种表示锁的方法。一种是在获取锁之前放置 reord::Lock,它表示获取了锁。它应该放在获取锁之前,并返回一个锁卫兵,应该像真实的锁卫兵一样保持,以便 reord 锁在真实锁解锁时解锁。

reord 还支持“模糊”锁:您不确定是否会锁定的锁。例如,在使用 postgresql 时,事务内部的多数查询将获取难以量化的锁。例如,它可能获取页级锁,这时基本上无法猜测哪些其他查询可能会受到影响。为了做到这一点,您应该在模糊锁之前放置一个 reord::maybe_lock().await 调用,并在之后放置一个 reord::point().await 调用。

reord 还支持检查您的锁实际上是否锁定您期望锁定的内容。这可能非常有用,如果您不信任您的锁实现(或您使用的外部锁),或者您如何使用 reord 仪器化了您的锁。为此,您应该设置适当的配置选项。

在任何情况下,您都应该在每次锁获取活动之后尝试设置一个 reord::point,以便 reord 可以高效地执行检查。然而,您不必为了这个原因使代码变得丑陋,直到您从 reord 获得虚假的测试失败:在没有这样的 reord::point 的情况下,最糟糕的事情是 reord 虚假地认为锁正常工作,而实际上没有,或者任务仍在进行中时任务被阻塞。在任何情况下,这只会使测试稍微难以复制,但它们仍然比没有 reord 时更容易复制。因此,除非您确实需要它,否则您可能不应该在锁获取活动中仪器化 ? 调用。

然而,检查锁以及模糊锁意味着在继续之前等待一些延迟。因此,尽可能少地这样做,因为它会在实际有锁竞争时使测试(或更重要的是,模糊器)运行速度大大减慢。

最后,当您需要调试失败的测试时,您可以

  1. 获取执行失败的测试所使用的种子
  2. 使用相同的种子再次运行测试,但启用 reord/tracing 功能
  3. TRACE 级别读取日志,以识别确切的交织模式。

reord 代码比较冗长,每次任务切换时都会通知您。它还提供了一个 INFO 级别的范围,即使是对您自己的日志,也能让您知道正在执行的任务。

局限性

鉴于便利性是一个目标,reord 使用全局变量来代理正在运行的测试信息。这意味着像 cargo test 这样的多线程测试框架不能与多个 reord 测试一起使用。当有使用 reord 的测试时,您应该使用 cargo nextest

依赖项

~2.8–4MB
~67K SLoC