【问题标题】:How to handle abort in test unit如何处理测试单元中的中止
【发布时间】:2021-06-19 09:20:42
【问题描述】:

我想测试我的一个应该恐慌的函数,但我的 GitHub 操作 abort() 导致即使我的代码要求“仅”2**31 字节(在我的真实代码中,限制是 libc::c_int::MAX)我的电脑有,GitHub action 没有这样的内存:p.

#[test]
#[should_panic]
fn reserve_with_max() {
    Vec::with_capacity(usize::MAX);
}

但这失败了:

test tests::bad_fd ... ok
test tests::create_true ... ok
test tests::create_false ... ok
test tests::create_with_one ... ok
memory allocation of 25769803764 bytes failed

这会停止测试并报告错误,即使这是我所期望的(恐慌或中止)。

我没有找到太多关于这个问题的信息:

我希望应该有一个#[should_abort],我该如何处理?

目前我的明显解决方案是ignore 测试:

#[test]
#[should_panic]
#[ignore = "Ask too much memory"]

【问题讨论】:

  • 不应该被认为是 GitHub Actions 实现中的一个 bug 吗?
  • @DenysSéguret 很难说,从技术上讲,我实际上并没有使用这个内存,我只是在我的真实代码中做一个with_capacity(),这样内存可以保持完全虚拟并且永远不会被操作系统分配.但是没有什么不允许 github 操作报告 oom(当您询问这么多内存时,这是意料之中的)。我想我会在最后删除这个测试,我不喜欢它但我认为这个问题仍然很有趣,我们可以清楚地看到,使用 cargo 测试中止是不容易的。

标签: unit-testing rust abort


【解决方案1】:

你可以分叉测试,但有很多缺点:

  • 需要 nix(也许某处有一个与操作系统无关的 fork crate...)
  • 测试代码变得复杂
  • 代码覆盖工具问题
  • 询问更多资源
  • 哈克
#[test]
#[ignore = "Still ignored taupaulin doesn't like it too"]
fn create_with_max() {
    use nix::{
        sys::{
            signal::Signal,
            wait::{waitpid, WaitStatus},
        },
        unistd::{fork, ForkResult},
    };
    use std::panic;
    use std::process::abort;

    match unsafe { fork() } {
        Ok(ForkResult::Parent { child }) => match waitpid(child, None) {
            Ok(WaitStatus::Signaled(_, s, _)) => {
                if s != Signal::SIGABRT {
                    panic!("Didn't abort")
                }
            }
            o => panic!("Didn't expect: {:?}", o),
        },
        Ok(ForkResult::Child) => {
            let result = panic::catch_unwind(|| {
                Vec::with_capacity(usize::MAX);
            });

            if let Err(_) = result {
                abort();
            }
        }
        Err(_) => panic!("Fork failed"),
    }
}

我不认为我会建议这样做。

【讨论】:

    【解决方案2】:

    有一个 RFC 2116 允许配置 rust 以消除内存恐慌,而不是 abort()

    [profile.dev]
    oom = "panic"
    
    [profile.release]
    oom = "panic"
    

    缺点:

    • 即使在夜间 #43596 上也没有实现
    • 它适用于您的用例,因为它是 oom 中止,但它不是处理 abort() 在测试中的通用解决方案。

    【讨论】:

    • 从技术上讲,您始终可以运行kill -ABRT $pid_of_test,这可能永远不会被视为成功的测试。所以我不知道 通用 abort() "handler" 会有多大用处。
    • @trentcl 是的,这个解决方案在我的情况下是完美的,我不认为中止是要处理的,我只是碰巧没有选择当前标准状态的原因。
    猜你喜欢
    • 2010-11-30
    • 2014-12-29
    • 2018-02-25
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    • 2014-02-28
    相关资源
    最近更新 更多