1
0
Fork 0
mirror of synced 2024-12-21 05:31:08 -05:00

Add testing framework and tests

This commit is contained in:
Anish Athalye 2015-05-05 19:58:25 -04:00
parent 49181b0666
commit eeab507d15
17 changed files with 398 additions and 0 deletions

1
test/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.vagrant/

24
test/README.md Normal file
View 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
View 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
View 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
View 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
View 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

View 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
'

View file

@ -0,0 +1,8 @@
test_description='clean ignores nonexistent directories'
. '../test-lib.bash'
test_expect_success 'run' '
run_dotbot <<EOF
- clean: ["~", "~/fake"]
EOF
'

View 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
'

View file

@ -0,0 +1,8 @@
test_description='blank config allowed'
. '../test-lib.bash'
test_expect_success 'run' '
run_dotbot <<EOF
[]
EOF
'

View file

@ -0,0 +1,7 @@
test_description='empty config disallowed'
. '../test-lib.bash'
test_expect_failure 'run' '
run_dotbot <<EOF
EOF
'

View 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
'

View 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
'

View 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
'

View 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
'

View 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
'

View 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
'