如何在 BATS 测试中激活 Bash 函数中的 ssh 帐户?

How to activate an ssh-account in Bash function in BATS test?

上下文

作为使用 BATS 测试的 Bash 脚本的一部分,我注意到当我 运行 一个激活 ssh 帐户的函数时,我的测试没有终止。

代码

以下函数假设 /home/<username>/.ssh/ 中存在私有和 public ssh 密钥对。如果我 运行 它手动使用 source src/the_bash_script.sh && activate_ssh_account <my_git_username>,它会工作并显示 Identity added: /home/name/.ssh/<my_git_email>:

#!/bin/bash
# Activates/enables the ssh for 
activate_ssh_account() {
    git_username=
    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/"$git_username"
}

但是,当它是 运行 来自测试时:

#!./test/libs/bats/bin/bats
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
# https://github.com/bats-core/bats-file#Index-of-all-functions
load 'libs/bats-file/load'
# https://github.com/bats-core/bats-assert#usage
load 'assert_utils'

source src/the_bash_script.sh


@test "Check if ssh-account is activated after activating it." {
    activate_ssh_account "some_git_username"
    assert_equal "Something" "Something_else"
}

它无限期挂起。

问题

如何在不导致 BATS 测试无限期挂起的情况下激活 ssh 帐户?

我从未使用过 BATS,但通过阅读文档,我可以说有一个用于共享公共代码的特定命令。不过您可能需要指定完整路径:

load: Share common code

You may want to share common code across multiple test files. Bats includes a convenient load command for sourcing a Bash source file relative to the location of the current test file. For example, if you have a Bats test in test/foo.bats, the command

load test_helper

will source the script test/test_helper.bash in your test file. This can be useful for sharing functions to set up your environment or load fixtures.

选项 1:

尝试替换

source src/the_bash_script.sh

load '/full/path/to/src/the_bash_script.sh'
选项 2:

尝试在 @test

中添加来源
@test "Check if ssh-account is activated after activating it." {
    source /full/path/to/src/the_bash_script.sh
    activate_ssh_account "some_git_username"
    assert_equal "Something" "Something_else"
}

测试无限期挂起,因为 BATS 等待 ssh-agent 终止(一旦执行第 eval "$(ssh-agent -s)" 行,它就会在后台运行)。更具体地说,BATS 等待 文件描述符 3 关闭(它由 ssh-agent 保持打开状态)。

因此,这可以通过实施 workaround mentioned in the documentation 或杀死 ssh-agent.

来解决

文档中的解决方法:

#!/bin/bash
# Activates/enables the ssh for 
activate_ssh_account() {
    git_username=
    eval "$(ssh-agent -s 3>&-)"
    ssh-add ~/.ssh/"$git_username"
}

这将关闭 ssh-agent 的 fd 3,BATS 将不再挂起。请注意,即使在 BATS 退出后,这也会在后台留下 ssh-agent 运行。从您的问题中不清楚是否需要这样做。如果不是,请使用下面的替代方法。


杀死ssh-agent:

activate_ssh_account 添加清理陷阱:

#!/bin/bash
# Activates/enables the ssh for 
activate_ssh_account() {
    trap "trap - RETURN; kill $SSH_AGENT_PID" RETURN
    git_username=
    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/"$git_username"
}

当函数退出并使用 eval "$(ssh-agent -s)" 导出的 pid(即变量 SSH_AGENT_PID)杀死 ssh-agent 时执行陷阱。

如果您出于某种原因不想使用陷阱,这也可以:

#!/bin/bash
# Activates/enables the ssh for
activate_ssh_account() {
    git_username=
    eval "$(ssh-agent -s)"
    result=0
    ssh-add ~/.ssh/"$git_username" || result=$?
    kill $SSH_AGENT_PID
    return $result
}

请注意,|| 结构是必要的,因为一旦命令失败,BATS 将停止执行函数的代码(即没有 ||,如果 [=27] 将不会执行 kill =]失败)。


作为旁注,要实际测试 activate_ssh_account 是成功还是失败,您应该使用 assert_success 而不是 assert_equal (除非您在问题中省略了更多代码).