parent
49181b0666
commit
eeab507d15
@ -0,0 +1 @@ |
||||
.vagrant/ |
@ -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 |
@ -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 |
@ -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 |
||||
} |
@ -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} |
@ -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 |
@ -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 |
||||
' |
@ -0,0 +1,8 @@ |
||||
test_description='clean ignores nonexistent directories' |
||||
. '../test-lib.bash' |
||||
|
||||
test_expect_success 'run' ' |
||||
run_dotbot <<EOF |
||||
- clean: ["~", "~/fake"] |
||||
EOF |
||||
' |
@ -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 |
||||
' |
@ -0,0 +1,8 @@ |
||||
test_description='blank config allowed' |
||||
. '../test-lib.bash' |
||||
|
||||
test_expect_success 'run' ' |
||||
run_dotbot <<EOF |
||||
[] |
||||
EOF |
||||
' |
@ -0,0 +1,7 @@ |
||||
test_description='empty config disallowed' |
||||
. '../test-lib.bash' |
||||
|
||||
test_expect_failure 'run' ' |
||||
run_dotbot <<EOF |
||||
EOF |
||||
' |
@ -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 |
||||
' |
@ -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 |
||||
' |
@ -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 |
||||
' |
@ -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 |
||||
' |
@ -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 |
||||
' |
@ -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 new issue