Search code examples
bashshellterminalfunctional-testingend-to-end

Simulate the interaction with a CLI


I have a CLI that can launch processes, especially interactive shells and waits for them, they can be closed using the same CLI. I need to create some end to end tests for it using bash but I cannot see how to simulate the execution in the terminal; the output should be sent to the process in the "foreground".

Suppose that executing my-cli start launches a python script that start a subprocess (running an interactive shell) and waits to it. in the testing script, exec(my-cli start) will replace the current process with the process running python script and not the interactive shell, so I cannot interact with the interactive shell after.

I thought about using pipes, but I think something that can simulate using a terminal will be better, any ideas ?

Example:

Suppose the code of my CLI (cli.py) is:

import subprocess


process = subprocess.Popen(['/bin/bash', '-i'], shell=False)
process.communicate()

Using expect I don't know if it's possible to communicate with the interactive shell (/bin/bash -i)

#!/usr/bin/expect -f


spawn python3 cli.py

#expect eof

send -- "echo $$\r"

Solution

  • As mentioned in a comment by Benjamin. I and many others have used expect in this scenario. As long as you can tell the text that will be presented in the terminal then you can use the following web pages as a guide to creating an expect script.

    Update based on the example provided. For this, I have a file foo.py:

    import subprocess
    
    
    process = subprocess.Popen(['/bin/bash', '-i'], shell=False)
    process.communicate()
    

    An expect file (expect-example.exp):

    #!/usr/bin/expect
    spawn  python3 foo.py
    
    expect "*bash*"
    send "date\r"
    send "exit\r"
    
    interact
    

    When I run this expect expect-example.exp I get the following:

    $ expect expect-example.exp 
    spawn python3 foo.py
    bash-3.2$ date
    Mon  3 Jun 2019 14:03:37 BST
    bash-3.2$ exit
    exit
    $ 
    

    It is worth mentioning, given that I am running a single command date and I want to see the output from it I must include the interact command at the end of the script. Otherwise, my expect script will exit as soon as it has sent the date command and won't wait for the response.