In python, how can I run a command-line program that does not return until I send Ctrl+D to it

883 views Asked by At

I'm writing python unit tests that test against a REST API that needs to be running as another process.

The REST server is a tomcat application that I call from the shell to run in development mode, so what I am looking to do in the python test is:

  1. Start the server, return when the server is up.
  2. Run unit tests
  3. Send the server Ctrl+D so it shuts down gracefully.

Is there a way to use a single point of entry for python so that the server starts and unit tests run all from one python script call?

I've look around at python subprocess and multithreading in python, but I still don't quite see how to get there from here.

For those that are familiar, this is an Atlassian JIRA plugin we are developing, so the actual shell command is "atlas-run".

1

There are 1 answers

1
wflynny On BEST ANSWER

Since no one has offered any code to help with this problem, I would do something like the following. Turns out pexpect is very powerful and you don't need the signal module.

import os
import sys
import pexpect

def run_server():
    server_dir = '/path/to/server/root'
    current_dir = os.path.abspath(os.curdir)

    os.chdir(server_dir)
    server_call = pexpect.spawn('atlas-run')
    server_response = server_call.expect(['Server Error!', 'Sever is running!'])
    os.chdir(current_dir)
    if server_response:
        return server_call #return server spawn object so we can shutdown later
    else:
        print 'Error starting the server: %s'%server_response.after
        sys.exit(1)

def run_unittests():
    # several ways to do this. either make a unittest.TestSuite or run command line
    # here is the second option
    unittest_dir = '/path/to/tests'
    pexpect.spawn('python -m unittest discover -s %s -p "*test.py"'%unittest_dir)
    test_response = pexpect.expect('Ran [0-9]+ tests in [0-9\.]+s') #catch end
    print test_response.before #print output of unittests before ending.
    return

def main():
    server = run_sever()
    run_unittests()
    server.sendcontrol('d') #shutdown server

if __name__ == "__main__":
    main()