Commander
Test your command line interfaces on windows, linux and osx and nodes viá ssh and docker
Install / Use
/learn @commander-cli/CommanderREADME
Commander
Define language independent tests for your command line scripts and programs in simple yaml files.
- It runs on
windows,osxandlinux - It can validate local machines, ssh hosts and docker containers
- It is a self-contained binary - no need to install a heavy lib or language
- It is easy and fast to write
For more information take a look at the quick start, the examples or the integration tests.
Table of contents
Installation
Any system with Go installed
Probably the easiest way to install commander is by using go get to download and install it in one simple command:
go install github.com/commander-cli/commander/v2/cmd/commander@latest
This works on any OS, as long as go is installed. If go is not installed on your system, follow one of the methods below.
Linux & osx
Visit the release page to get the binary for you system.
curl -L https://github.com/commander-cli/commander/releases/download/v2.5.0/commander-linux-amd64 -o commander
chmod +x commander
Windows
- Download the current release
- Add the path to your path environment variable
- Test it:
commander --version
Quick start
A commander test suite consists of a config and tests root element. To start quickly you can use
the following examples.
# You can even let commander add tests for you!
$ ./commander add --stdout --file=/tmp/commander.yaml echo hello
tests:
echo hello:
exit-code: 0
stdout: hello
written to /tmp/commander.yaml
# ... and execute!
$ ./commander test /tmp/commander.yaml
Starting test file /tmp/commander.yaml...
✓ echo hello
Duration: 0.002s
Count: 1, Failed: 0
Complete YAML file
Here you can see an example with all features for a quick reference
nodes:
ssh-host1:
type: ssh
addr: 192.168.0.1:22
user: root
pass: pass
ssh-host2:
type: ssh
addr: 192.168.0.1:22
user: root
identity-file: /home/user/id_rsa.pub
docker-host1:
type: docker
image: alpine:2.4
docker-host2:
type: docker
instance: alpine_instance_1
config: # Config for all executed tests
dir: /tmp #Set working directory
env: # Environment variables
KEY: global
timeout: 50s # Define a timeout for a command under test
retries: 2 # Define retries for each test
nodes:
- ssh-host1 # define default hosts
tests:
echo hello: # Define command as title
stdout: hello # Default is to check if it contains the given characters
exit-code: 0 # Assert exit-code
it should skip:
command: echo "I should be skipped"
stdout: I should be skipped
skip: true
it should fail:
command: invalid
stderr:
contains:
- invalid # Assert only contain work
not-contains:
- not in there # Validate that a string does not occur in stdout
exactly: "/bin/sh: 1: invalid: not found"
line-count: 1 # Assert amount of lines
lines: # Assert specific lines
1: "/bin/sh: 1: invalid: not found"
json:
object.attr: hello # Make assertions on json objects
xml:
"//book//auhtor": Steven King # Make assertions on xml documents
file: correct-output.txt
exit-code: 127
skip: false
it has configs:
command: echo hello
stdout:
contains:
- hello #See test "it should fail"
exactly: hello
line-count: 1
config:
inherit-env: true # You can inherit the parent shells env variables
dir: /home/user # Overwrite working dir
env:
KEY: local # Overwrite env variable
ANOTHER: yeah # Add another env variable
timeout: 1s # Overwrite timeout
retries: 5
nodes: # overwrite default nodes
- docker-host1
- docker-host2
exit-code: 0
Executing
# Execute file commander.yaml in current directory
$ ./commander test
# Execute a specific suite
$ ./commander test /tmp/test.yaml
# Execute a single test
$ ./commander test /tmp/test.yaml --filter "my test"
# Execute suite from stdin
$ cat /tmp/test.yaml | ./commander test -
# Execute suite from url
$ ./commander test https://your-url/commander_test.yaml
# Execute suites within a test directory
$ ./commander test --dir /tmp
# Execute suites in a different working directory
$ ./commander test --workdir /examples minimal_test.yaml
Adding tests
You can use the add argument if you want to commander to create your tests.
# Add a test to the default commander.yaml
$ ./commander add echo hello
written to /tmp/commander.yaml
# Write to a given file
$ ./commander add --file=test.yaml echo hello
written to test.yaml
# Write to stdout and file
$ ./commander add --stdout echo hello
tests:
echo hello:
exit-code: 0
stdout: hello
written to /tmp/commander.yaml
# Only to stdout
$ ./commander add --stdout --no-file echo hello
tests:
echo hello:
exit-code: 0
stdout: hello
Documentation
Usage
NAME:
Commander - CLI app testing
USAGE:
commander [global options] command [command options] [arguments...]
COMMANDS:
test Execute the test suite
add Automatically add a test to your test suite
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
Tests
Tests are defined in the tests root element. Every test consists of a command and an expected result,
i.e. an exit-code.
tests: # root element
echo test: # test case - can either be the command or a given title
stdout: test
exit-code: 0
A test is a map which configures the test.
The key (echo test in the example above) of the test can either be the command itself or the title of the test which will be displayed in the test execution.
If the same command is tested multiple times it is useful to set the title of the test manually and use the command property.
Further the title can be useful to describe tests better. See the commander test suite as an example.
- name:
title or command under test - type:
map - default:
{}
Examples:
tests:
echo test: # command and title will be the same
stdout: test
exit-code: 0
my title: # custom title
command: exit 1 # set command manually
exit-code: 1
command
command is a string containing the command to be tested. Further the command property is automatically parsed from
the key if no command property was given.
- name:
command - type:
string - default:
can't be empty - notes: Will be parsed from the
keyif nocommandproperty was provided and used as the title too
echo test: # use command as key and title
exit-code: 0
it should print hello world: # use a more descriptive title...
command: echo hello world # ... and set the command in the property manually
stdout: hello world
exit-code: 0
<a name="config-test"></a>config
config sets configuration for the test. config can overwrite global configurations.
- name:
config - type:
map - default:
{} - notes:
- for more information look at config
echo test:
config:
timeout: 5s
exit-code
exit-code is an int type and compares the given code to the exit-code of the given command.
- name:
exit-code - type:
int - default:
0
