Add testing framework and tests
This commit is contained in:
parent
49181b0666
commit
eeab507d15
17 changed files with 398 additions and 0 deletions
1
test/.gitignore
vendored
Normal file
1
test/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.vagrant/
|
24
test/README.md
Normal file
24
test/README.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
Testing
|
||||
=======
|
||||
|
||||
Dotbot testing code uses [Vagrant][vagrant] to run all tests inside a virtual
|
||||
machine to have tests be completely isolated from the host machine. The test
|
||||
driver relies on the [Sahara][sahara] plugin to snapshot and roll back virtual
|
||||
machine state. The tests are deterministic, and each test is run in a virtual
|
||||
machine with fresh state, ensuring that tests that modify system state are
|
||||
easily repeatable.
|
||||
|
||||
Running the Tests
|
||||
-----------------
|
||||
|
||||
Before running the tests, the virtual machine must be running. It can be
|
||||
started by running `vagrant up`.
|
||||
|
||||
The test suite can be run by running `./test`. Selected tests can be run by
|
||||
passing paths to the tests as arguments to `./test`.
|
||||
|
||||
When finished with testing, it is good to shut down the virtual machine by
|
||||
running `vagrant halt`.
|
||||
|
||||
[vagrant]: https://www.vagrantup.com/
|
||||
[sahara]: https://github.com/jedi4ever/sahara
|
10
test/Vagrantfile
vendored
Normal file
10
test/Vagrantfile
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
Vagrant.configure(2) do |config|
|
||||
config.vm.box = 'ubuntu/trusty64'
|
||||
|
||||
# sync by copying for isolation
|
||||
config.vm.synced_folder "..", "/dotbot", type: "rsync",
|
||||
rsync__exclude: ".git/"
|
||||
|
||||
# disable default synced folder
|
||||
config.vm.synced_folder ".", "/vagrant", disabled: true
|
||||
end
|
117
test/driver-lib.bash
Normal file
117
test/driver-lib.bash
Normal file
|
@ -0,0 +1,117 @@
|
|||
MAXRETRY=5
|
||||
TIMEOUT=1
|
||||
|
||||
red() {
|
||||
if [ -t 1 ]; then
|
||||
printf "\033[31m%s\033[0m\n" "$*"
|
||||
else
|
||||
printf "%s\n" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
green() {
|
||||
if [ -t 1 ]; then
|
||||
printf "\033[32m%s\033[0m\n" "$*"
|
||||
else
|
||||
printf "%s\n" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
yellow() {
|
||||
if [ -t 1 ]; then
|
||||
printf "\033[33m%s\033[0m\n" "$*"
|
||||
else
|
||||
printf "%s\n" "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
check_prereqs() {
|
||||
if ! (vagrant ssh -c 'exit') >/dev/null 2>&1; then
|
||||
>&2 echo "vagrant vm must be running."
|
||||
return 1
|
||||
fi
|
||||
if ! (vagrant plugin list | grep '^sahara\s\+') >/dev/null 2>&1; then
|
||||
>&2 echo "vagrant plugin 'sahara' is not installed."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
until_success() {
|
||||
local timeout=${TIMEOUT}
|
||||
local attempt=0
|
||||
local success=0
|
||||
while [ $attempt -lt $MAXRETRY ]; do
|
||||
if ($@) >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep $timeout
|
||||
timeout=$((timeout * 2))
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_vagrant() {
|
||||
until_success vagrant ssh -c 'exit'
|
||||
}
|
||||
|
||||
rollback() {
|
||||
vagrant sandbox rollback >/dev/null 2>&1 &&
|
||||
wait_for_vagrant &&
|
||||
vagrant rsync >/dev/null 2>&1
|
||||
}
|
||||
|
||||
initialize() {
|
||||
echo "initializing."
|
||||
vagrant sandbox on >/dev/null 2>&1
|
||||
tests_run=0
|
||||
tests_passed=0
|
||||
tests_failed=0
|
||||
tests_total="${1}"
|
||||
local plural="" && [ ${tests_total} -gt 1 ] && plural="s"
|
||||
printf -- "running %d test%s...\n\n" ${tests_total} $plural
|
||||
}
|
||||
|
||||
pass() {
|
||||
tests_passed=$((tests_passed + 1))
|
||||
green "-> ok."
|
||||
echo
|
||||
}
|
||||
|
||||
fail() {
|
||||
tests_failed=$((tests_failed + 1))
|
||||
yellow "-> fail!"
|
||||
echo
|
||||
}
|
||||
|
||||
run_test() {
|
||||
tests_run=$((tests_run + 1))
|
||||
printf '[%d/%d]\n' ${tests_run} ${tests_total}
|
||||
rollback || die "unable to rollback vm." # start with a clean slate
|
||||
vagrant ssh -c "cd /dotbot/test/tests && bash ${1}" 2>/dev/null && pass || fail
|
||||
}
|
||||
|
||||
report() {
|
||||
printf -- "test report\n"
|
||||
printf -- "-----------\n"
|
||||
printf -- "- %3d run\n" ${tests_run}
|
||||
printf -- "- %3d passed\n" ${tests_passed}
|
||||
if [ ${tests_failed} -gt 0 ]; then
|
||||
printf -- "- %3d failed\n" ${tests_failed}
|
||||
echo
|
||||
red "==> not ok!"
|
||||
return 1
|
||||
else
|
||||
echo
|
||||
green "==> all ok."
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
die() {
|
||||
>&2 echo $@
|
||||
>&2 echo "terminating..."
|
||||
exit 1
|
||||
}
|
35
test/test
Executable file
35
test/test
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "${BASEDIR}"
|
||||
. "./driver-lib.bash"
|
||||
|
||||
start="$(date +%s)"
|
||||
|
||||
check_prereqs || die "prerequisites unsatsfied."
|
||||
|
||||
declare -a tests=()
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
while read file; do
|
||||
tests+=("${file}")
|
||||
done < <(find tests -type f -name '*.bash')
|
||||
else
|
||||
tests=("$@")
|
||||
fi
|
||||
|
||||
initialize "${#tests[@]}"
|
||||
|
||||
for file in "${tests[@]}"; do
|
||||
run_test "$(basename ${file})"
|
||||
done
|
||||
|
||||
if report; then
|
||||
ret=0
|
||||
else
|
||||
ret=1
|
||||
fi
|
||||
|
||||
echo "(tests run in $(($(date +%s) - start)) seconds)"
|
||||
exit ${ret}
|
51
test/test-lib.bash
Normal file
51
test/test-lib.bash
Normal file
|
@ -0,0 +1,51 @@
|
|||
DEBUG=false
|
||||
DOTFILES='/home/vagrant/dotfiles'
|
||||
INSTALL_CONF='install.conf.yaml'
|
||||
|
||||
test_run_() {
|
||||
if ! ${DEBUG}; then
|
||||
(eval "$*") >/dev/null 2>&1
|
||||
else
|
||||
(eval "$*")
|
||||
fi
|
||||
}
|
||||
|
||||
test_expect_success() {
|
||||
local tag=${1} && shift
|
||||
if ! test_run_ "$@"; then
|
||||
>&2 echo "- ${tag} failed."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
test_expect_failure() {
|
||||
local tag=${1} && shift
|
||||
if test_run_ "$@"; then
|
||||
>&2 echo "- ${tag} failed."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_vm() {
|
||||
if [ "$(whoami)" != "vagrant" ]; then
|
||||
>&2 echo "test can't run outside vm!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
initialize() {
|
||||
check_vm
|
||||
echo "${test_description}"
|
||||
mkdir -p "${DOTFILES}"
|
||||
cd
|
||||
}
|
||||
|
||||
run_dotbot() {
|
||||
(
|
||||
cd "${DOTFILES}"
|
||||
cat > "${INSTALL_CONF}"
|
||||
/dotbot/bin/dotbot -d . -c "${INSTALL_CONF}" "${@}"
|
||||
)
|
||||
}
|
||||
|
||||
initialize
|
19
test/tests/clean-missing.bash
Normal file
19
test/tests/clean-missing.bash
Normal file
|
@ -0,0 +1,19 @@
|
|||
test_description='clean deletes links to missing files'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'setup' '
|
||||
touch ${DOTFILES}/f &&
|
||||
ln -s ${DOTFILES}/f ~/.f &&
|
||||
ln -s ${DOTFILES}/g ~/.g
|
||||
'
|
||||
|
||||
test_expect_success 'run' '
|
||||
run_dotbot <<EOF
|
||||
- clean: ["~"]
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'test' '
|
||||
test -f ~/.f &&
|
||||
! test -h ~/.g
|
||||
'
|
8
test/tests/clean-nonexistent.bash
Normal file
8
test/tests/clean-nonexistent.bash
Normal file
|
@ -0,0 +1,8 @@
|
|||
test_description='clean ignores nonexistent directories'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'run' '
|
||||
run_dotbot <<EOF
|
||||
- clean: ["~", "~/fake"]
|
||||
EOF
|
||||
'
|
18
test/tests/clean-outside.bash
Normal file
18
test/tests/clean-outside.bash
Normal file
|
@ -0,0 +1,18 @@
|
|||
test_description='clean ignores files linking outside dotfiles directory'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'setup' '
|
||||
ln -s ${DOTFILES}/f ~/.f &&
|
||||
ln -s ~/g ~/.g
|
||||
'
|
||||
|
||||
test_expect_success 'run' '
|
||||
run_dotbot <<EOF
|
||||
- clean: ["~"]
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'test' '
|
||||
! test -h ~/.f &&
|
||||
test -h ~/.g
|
||||
'
|
8
test/tests/config-blank.bash
Normal file
8
test/tests/config-blank.bash
Normal file
|
@ -0,0 +1,8 @@
|
|||
test_description='blank config allowed'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'run' '
|
||||
run_dotbot <<EOF
|
||||
[]
|
||||
EOF
|
||||
'
|
7
test/tests/config-empty.bash
Normal file
7
test/tests/config-empty.bash
Normal file
|
@ -0,0 +1,7 @@
|
|||
test_description='empty config disallowed'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_failure 'run' '
|
||||
run_dotbot <<EOF
|
||||
EOF
|
||||
'
|
21
test/tests/link-force-overwrite-symlink.bash
Normal file
21
test/tests/link-force-overwrite-symlink.bash
Normal file
|
@ -0,0 +1,21 @@
|
|||
test_description='force overwrites symlinked directory'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'setup' '
|
||||
mkdir ${DOTFILES}/dir ~/dir &&
|
||||
touch ${DOTFILES}/dir/f &&
|
||||
ln -s ~/ ~/.dir
|
||||
'
|
||||
|
||||
test_expect_success 'run' '
|
||||
run_dotbot <<EOF
|
||||
- link:
|
||||
~/.dir:
|
||||
path: dir
|
||||
force: true
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'test' '
|
||||
test -f ~/.dir/f
|
||||
'
|
18
test/tests/link-leaves-file.bash
Normal file
18
test/tests/link-leaves-file.bash
Normal file
|
@ -0,0 +1,18 @@
|
|||
test_description='relink does not overwrite file'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo "apple" > ${DOTFILES}/f &&
|
||||
echo "grape" > ~/.f
|
||||
'
|
||||
|
||||
test_expect_failure 'run' '
|
||||
run_dotbot <<EOF
|
||||
- link:
|
||||
~/.f: f
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'test' '
|
||||
grep "grape" ~/.f
|
||||
'
|
20
test/tests/link-relink-leaves-file.bash
Normal file
20
test/tests/link-relink-leaves-file.bash
Normal file
|
@ -0,0 +1,20 @@
|
|||
test_description='relink does not overwrite file'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo "apple" > ${DOTFILES}/f &&
|
||||
echo "grape" > ~/.f
|
||||
'
|
||||
|
||||
test_expect_failure 'run' '
|
||||
run_dotbot <<EOF
|
||||
- link:
|
||||
~/.f:
|
||||
path: f
|
||||
relink: true
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'test' '
|
||||
grep "grape" ~/.f
|
||||
'
|
21
test/tests/link-relink-overwrite-symlink.bash
Normal file
21
test/tests/link-relink-overwrite-symlink.bash
Normal file
|
@ -0,0 +1,21 @@
|
|||
test_description='relink overwrites symlink'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'setup' '
|
||||
echo "apple" > ${DOTFILES}/f &&
|
||||
echo "grape" > ~/f &&
|
||||
ln -s ~/f ~/.f
|
||||
'
|
||||
|
||||
test_expect_success 'run' '
|
||||
run_dotbot <<EOF
|
||||
- link:
|
||||
~/.f:
|
||||
path: f
|
||||
relink: true
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'test' '
|
||||
grep "apple" ~/.f
|
||||
'
|
11
test/tests/shell-allow-stdout.bash
Normal file
11
test/tests/shell-allow-stdout.bash
Normal file
|
@ -0,0 +1,11 @@
|
|||
test_description='shell command stdout works'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'run' '
|
||||
(run_dotbot | grep "^apple") <<EOF
|
||||
- shell:
|
||||
-
|
||||
command: echo apple
|
||||
stdout: true
|
||||
EOF
|
||||
'
|
9
test/tests/shell-disables-stdout.bash
Normal file
9
test/tests/shell-disables-stdout.bash
Normal file
|
@ -0,0 +1,9 @@
|
|||
test_description='shell command stdout disabled by default'
|
||||
. '../test-lib.bash'
|
||||
|
||||
test_expect_success 'run' '
|
||||
(run_dotbot | (! grep "^banana")) <<EOF
|
||||
- shell:
|
||||
- echo banana
|
||||
EOF
|
||||
'
|
Loading…
Reference in a new issue