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

Time:11-23

Context

As part of a Bash script that is tested using the BATS, I noticed that my tests are not terminated when I run a function that activates an ssh-account.

Code

The following function assumes a private and public ssh key pair exists in /home/<username>/.ssh/. If I run it manually using source src/the_bash_script.sh && activate_ssh_account <my_git_username>, it works and says Identity added: /home/name/.ssh/<my_git_email>:

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

However, when it is ran from the test with:

#!./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"
}

It hangs indefinitely.

Question

How can I activate an ssh-account without causing the BATS tests to hang indefinitely?

CodePudding user response:

The test hangs indefinitely because BATS waits for ssh-agent to terminate (which runs in the background once line eval "$(ssh-agent -s)" is executed). To be more specific, BATS waits for file descriptor 3 to be closed (which is being held open by ssh-agent).

Thus, this can be solved by either implementing the workaround mentioned in the documentation or by killing ssh-agent.


Use workaround from documentation:

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

This closes fd3 for ssh-agent and BATS will no longer hang. Note that this leaves ssh-agent running in the background, even after BATS exits. It is unclear from your question if that is desired or not. If it's not, use the alternative below.


Kill ssh-agent:

Add a cleanup trap to activate_ssh_account:

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

The trap is executed when the function exits and kills ssh-agent using the pid exported by eval "$(ssh-agent -s)" (i.e. variable SSH_AGENT_PID).

If you don't want to use a trap for some reason, this will also work:

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

Note that the || construct is necessary because BATS will stop executing the function's code once a command fails (i.e. without ||, kill will not be executed if ssh-add fails).


As a side note, to actually test if activate_ssh_account succeeds or fails, you should use assert_success instead of assert_equal (unless there is more code that you omitted in your question).

CodePudding user response:

I never used BATS but by reading the doc I can say that there is a specific command for sharing common code. You may need to specify the full path though:

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.

Option1:

Try replacing

source src/the_bash_script.sh

with

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

Try adding the sourcing in @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"
}
  • Related