3
votes

I'm using PHPUnit for a set of functional tests. A remote database is accessed during these tests. The database is only accessible through an SSH tunnel. So I manually start a tunnel in a separate terminal each time I run these tests.

Is there an elegant way to start an SSH tunnel during PHPUnit setup and then close the tunnel at teardown?

2

2 Answers

3
votes

Cleanest method I can think of is to "hotwire" the bootstrap code:

// your bootstrap code above

// this gets called before first test
system("script_to_start_ssh_tunnel");

// this gets called after last test
register_shutdown_function(function(){
    system("script_to_stop_ssh_tunnel");
});

// i went with 'system()' so you can also see the output.
// if you don't need it, go with 'exec()'

This is useful if you need your ssh tunnel available to more than one test.

For a single test you can look into setUpBeforeClass and tearDownAfterClass.

More details available here: phpunit docs

1
votes

@alex-tartan sent me in the right direction. This post also helped. Just for completeness here's the solution I'm using. Start the SSH tunnel as a background process with a control socket. At shutdown check for the socket and exit the background process. At each unit test setup check for the control socket and skip starting SSH if it's already running.

protected function setUp()
{
    ...
    if (!file_exists('/tmp/tunnel_ctrl_socket')) {
        // Redirect to /dev/null or exec will never return
        exec("ssh -M -S /tmp/tunnel_ctrl_socket -fnNT -i $key -L 3306:$db:3306 $user@$host &>/dev/null");
        $closeTunnel = function($signo = 0) use ($user, $host) {
            if (file_exists('/tmp/tunnel_ctrl_socket')) {
                exec("ssh -S /tmp/tunnel_ctrl_socket -O exit $user@$host");
            }
        };
        register_shutdown_function($closeTunnel);
        // In case we kill the tests early...
        pcntl_signal(SIGTERM, $closeTunnel);
    }
}

I put this in a class that other tests extend so the tunnel is set up just once and runs until all tests are done or we kill the process.