Add tests

Tests will be run using `bats`.
This commit is contained in:
Tim Byrne 2016-03-23 19:18:33 -05:00
parent bbec7dd540
commit d2cd3b1b26
16 changed files with 1728 additions and 0 deletions

View File

@ -13,6 +13,10 @@ pdf:
@sleep 1 @sleep 1
@rm yadm.ps @rm yadm.ps
.PHONY: test
test:
@bats test
man: man:
groff -man -Tascii ./yadm.1 | less groff -man -Tascii ./yadm.1 | less

11
test/000_unit_syntax.bats Normal file
View File

@ -0,0 +1,11 @@
load common
load_fixtures
@test "Syntax check" {
echo "
$T_YADM must parse correctly
"
#; check the syntax of yadm
bash -n $T_YADM
}

View File

@ -0,0 +1,66 @@
load common
load_fixtures
@test "configure_paths() (standard YADM_DIR)" {
echo "
Correct paths should be defined
YADM_REPO=$DEFAULT_YADM_DIR/$DEFAULT_REPO
YADM_CONFIG=$DEFAULT_YADM_DIR/$DEFAULT_CONFIG
YADM_ENCRYPT=$DEFAULT_YADM_DIR/$DEFAULT_ENCRYPT
YADM_ARCHIVE=$DEFAULT_YADM_DIR/$DEFAULT_ARCHIVE
GIT_DIR=$DEFAULT_YADM_DIR/$DEFAULT_REPO
"
#; load yadm functions
YADM_TEST=1 source $T_YADM
#; configure the paths
configure_paths
echo "CONFIGURED PATHS:"
echo " YADM_REPO:$YADM_REPO"
echo " YADM_CONFIG:$YADM_CONFIG"
echo "YADM_ENCRYPT:$YADM_ENCRYPT"
echo "YADM_ARCHIVE:$YADM_ARCHIVE"
echo " GIT_DIR:$GIT_DIR"
#; test value of configured paths
[ "$DEFAULT_YADM_DIR/$DEFAULT_REPO" = "$YADM_REPO" ]
[ "$DEFAULT_YADM_DIR/$DEFAULT_CONFIG" = "$YADM_CONFIG" ]
[ "$DEFAULT_YADM_DIR/$DEFAULT_ENCRYPT" = "$YADM_ENCRYPT" ]
[ "$DEFAULT_YADM_DIR/$DEFAULT_ARCHIVE" = "$YADM_ARCHIVE" ]
[ "$DEFAULT_YADM_DIR/$DEFAULT_REPO" = "$GIT_DIR" ]
}
@test "configure_paths() (custom YADM_DIR)" {
echo "
Correct paths should be defined
YADM_REPO=$T_DIR_YADM/$DEFAULT_REPO
YADM_CONFIG=$T_DIR_YADM/$DEFAULT_CONFIG
YADM_ENCRYPT=$T_DIR_YADM/$DEFAULT_ENCRYPT
YADM_ARCHIVE=$T_DIR_YADM/$DEFAULT_ARCHIVE
GIT_DIR=$T_DIR_YADM/$DEFAULT_REPO
"
#; load yadm functions
YADM_TEST=1 source $T_YADM
#; configure the paths
TEST_ARGS=(-Y $T_DIR_YADM)
process_global_args ${TEST_ARGS[*]}
configure_paths
echo "CONFIGURED PATHS:"
echo " YADM_REPO:$YADM_REPO"
echo " YADM_CONFIG:$YADM_CONFIG"
echo "YADM_ENCRYPT:$YADM_ENCRYPT"
echo "YADM_ARCHIVE:$YADM_ARCHIVE"
echo " GIT_DIR:$GIT_DIR"
#; test value of configured paths
[ "$T_DIR_YADM/$DEFAULT_REPO" = "$YADM_REPO" ]
[ "$T_DIR_YADM/$DEFAULT_CONFIG" = "$YADM_CONFIG" ]
[ "$T_DIR_YADM/$DEFAULT_ENCRYPT" = "$YADM_ENCRYPT" ]
[ "$T_DIR_YADM/$DEFAULT_ARCHIVE" = "$YADM_ARCHIVE" ]
[ "$T_DIR_YADM/$DEFAULT_REPO" = "$GIT_DIR" ]
}

View File

@ -0,0 +1,31 @@
load common
load_fixtures
@test "Default YADM_DIR" {
echo "
YADM_DIR should default to \$HOME/.yadm
"
#; load yadm functions
YADM_TEST=1 source $T_YADM
#; test value of YADM_DIR
[ "$HOME/.yadm" = "$YADM_DIR" ]
}
@test "Override default YADM_DIR" {
echo "
Override YADM_DIR using -Y $T_DIR_YADM
YADM_DIR should become $T_DIR_YADM
"
#; load yadm functions
YADM_TEST=1 source $T_YADM
#; call process_global_args() with -Y
TEST_ARGS=(-Y $T_DIR_YADM)
process_global_args ${TEST_ARGS[*]}
#; test value of YADM_DIR
[ "$T_DIR_YADM" = "$YADM_DIR" ]
}

View File

@ -0,0 +1,22 @@
load common
load_fixtures
@test "Command 'version'" {
echo "
When 'version' command is provided,
Print the current version with format 'yadm x.xx'
Exit with 0
"
#; run yadm with 'version' command
run $T_YADM version
#; load yadm variables (including VERSION)
YADM_TEST=1 source $T_YADM
#; validate status and output
[ $status -eq 0 ]
[ "$output" = "yadm $VERSION" ]
version_regex="^yadm [[:digit:]\.]+$"
[[ "$output" =~ $version_regex ]]
}

32
test/101_accept_help.bats Normal file
View File

@ -0,0 +1,32 @@
load common
load_fixtures
@test "Missing command" {
echo "
When no command is provided,
Produce usage instructions
Exit with 1
"
#; run yadm with no command
run $T_YADM
#; validate status and output
[ $status -eq 1 ]
[[ "${lines[0]}" =~ ^Usage: ]]
}
@test "Command 'help'" {
echo "
When 'help' command is provided,
Produce usage instructions
Exit with value 1
"
#; run yadm with 'help' command
run $T_YADM help
#; validate status and output
[ $status -eq 1 ]
[[ "${lines[0]}" =~ ^Usage: ]]
}

View File

@ -0,0 +1,18 @@
load common
load_fixtures
@test "Command 'clean'" {
echo "
When 'clean' command is provided,
Do nothing, this is a dangerous Git command when managing dot files
Report the command as disabled
Exit with 1
"
#; run yadm with 'clean' command
run $T_YADM clean
#; validate status and output
[ $status -eq 1 ]
[[ "${lines[0]}" =~ disabled ]]
}

95
test/103_accept_git.bats Normal file
View File

@ -0,0 +1,95 @@
load common
load_fixtures
IN_REPO=(.bash_profile .vimrc)
function setup_environment() {
destroy_tmp
build_repo "${IN_REPO[@]}"
}
@test "Passthru unknown commands to Git" {
echo "
When the command 'bogus' is provided
Report bogus is not a command
Exit with 0
"
#; start fresh
setup_environment
#; run bogus
run $T_YADM_Y bogus
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ .bogus..is.not.a.git.command ]]
}
@test "Git command 'add'" {
echo "
When the command 'add' is provided
Files are added to the index
Exit with 0
"
#; start fresh
setup_environment
#; create a testfile
local testfile="$T_DIR_WORK/testfile"
echo "$testfile" > $testfile
#; run add
run $T_YADM_Y add -v "$testfile"
#; validate status and output
[ "$status" -eq 0 ]
[ "$output" = "add 'testfile'" ]
}
@test "Git command 'status'" {
echo "
When the command 'status' is provided
Added files are shown
Exit with 0
"
#; run status
run $T_YADM_Y status
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ new\ file:[[:space:]]+testfile ]]
}
@test "Git command 'commit'" {
echo "
When the command 'commit' is provided
Index is commited
Exit with 0
"
#; run commit
run $T_YADM_Y commit -m 'Add testfile'
#; validate status and output
[ "$status" -eq 0 ]
[[ "${lines[1]}" =~ 1\ file\ changed ]]
[[ "${lines[1]}" =~ 1\ insertion ]]
}
@test "Git command 'log'" {
echo "
When the command 'log' is provided
Commits are shown
Exit with 0
"
#; run log
run $T_YADM_Y log --oneline
#; validate status and output
[ "$status" -eq 0 ]
[[ "${lines[0]}" =~ Add\ testfile ]]
}

177
test/104_accept_init.bats Normal file
View File

@ -0,0 +1,177 @@
load common
load_fixtures
setup() {
destroy_tmp
create_worktree "$T_DIR_WORK"
}
@test "Command 'init'" {
echo "
When 'init' command is provided,
Create new repo with attributes:
- 0600 permissions
- not bare
- worktree = \$HOME
- showUntrackedFiles = no
- yadm.managed = true
Report the repo as initialized
Exit with 0
"
#; run init
run $T_YADM_Y init
#; validate status and output
[ $status -eq 0 ]
[[ "$output" =~ Initialized ]]
#; validate repo attributes
test_perms $T_DIR_REPO "drw.--.--."
test_repo_attribute $T_DIR_REPO core.bare false
test_repo_attribute $T_DIR_REPO core.worktree "$HOME"
test_repo_attribute $T_DIR_REPO status.showUntrackedFiles no
test_repo_attribute $T_DIR_REPO yadm.managed true
}
@test "Command 'init' -w (alternate worktree)" {
echo "
When 'init' command is provided,
and '-w' is provided,
Create new repo with attributes:
- 0600 permissions
- not bare
- worktree = \$YADM_WORK
- showUntrackedFiles = no
- yadm.managed = true
Report the repo as initialized
Exit with 0
"
#; run init
run $T_YADM_Y init -w "$T_DIR_WORK"
#; validate status and output
[ $status -eq 0 ]
[[ "$output" =~ Initialized ]]
#; validate repo attributes
test_perms $T_DIR_REPO "drw.--.--."
test_repo_attribute $T_DIR_REPO core.bare false
test_repo_attribute $T_DIR_REPO core.worktree "$T_DIR_WORK"
test_repo_attribute $T_DIR_REPO status.showUntrackedFiles no
test_repo_attribute $T_DIR_REPO yadm.managed true
}
@test "Command 'init' (existing repo)" {
echo "
When 'init' command is provided,
and a repo already exists,
Refuse to create a new repo
Exit with 1
"
#; create existing repo content
mkdir -p $T_DIR_REPO
local testfile="$T_DIR_REPO/testfile"
touch "$testfile"
#; run init
run $T_YADM_Y init
#; validate status and output
[ $status -eq 1 ]
[[ "$output" =~ already.exists ]]
#; verify existing repo is intact
if [ ! -e $testfile ]; then
echo "ERROR: existing repo has been changed"
return 1
fi
}
@test "Command 'init' -f (force overwrite repo)" {
echo "
When 'init' command is provided,
and '-f' is provided
and a repo already exists,
Remove existing repo
Create new repo with attributes:
- 0600 permissions
- not bare
- worktree = \$HOME
- showUntrackedFiles = no
- yadm.managed = true
Report the repo as initialized
Exit with 0
"
#; create existing repo content
mkdir -p $T_DIR_REPO
local testfile="$T_DIR_REPO/testfile"
touch "$testfile"
#; run init
run $T_YADM_Y init -f
#; validate status and output
[ $status -eq 0 ]
[[ "$output" =~ Initialized ]]
#; verify existing repo is gone
if [ -e $testfile ]; then
echo "ERROR: existing repo files remain"
return 1
fi
#; validate repo attributes
test_perms $T_DIR_REPO "drw.--.--."
test_repo_attribute $T_DIR_REPO core.bare false
test_repo_attribute $T_DIR_REPO core.worktree "$HOME"
test_repo_attribute $T_DIR_REPO status.showUntrackedFiles no
test_repo_attribute $T_DIR_REPO yadm.managed true
}
@test "Command 'init' -f -w (force overwrite repo with alternate worktree)" {
echo "
When 'init' command is provided,
and '-f' is provided
and '-w' is provided
and a repo already exists,
Remove existing repo
Create new repo with attributes:
- 0600 permissions
- not bare
- worktree = \$YADM_WORK
- showUntrackedFiles = no
- yadm.managed = true
Report the repo as initialized
Exit with 0
"
#; create existing repo content
mkdir -p $T_DIR_REPO
local testfile="$T_DIR_REPO/testfile"
touch "$testfile"
#; run init
run $T_YADM_Y init -f -w "$T_DIR_WORK"
#; validate status and output
[ $status -eq 0 ]
[[ "$output" =~ Initialized ]]
#; verify existing repo is gone
if [ -e $testfile ]; then
echo "ERROR: existing repo files remain"
return 1
fi
#; validate repo attributes
test_perms $T_DIR_REPO "drw.--.--."
test_repo_attribute $T_DIR_REPO core.bare false
test_repo_attribute $T_DIR_REPO core.worktree "$T_DIR_WORK"
test_repo_attribute $T_DIR_REPO status.showUntrackedFiles no
test_repo_attribute $T_DIR_REPO yadm.managed true
}

175
test/105_accept_clone.bats Normal file
View File

@ -0,0 +1,175 @@
load common
load_fixtures
IN_REPO=(.bash_profile .vimrc)
T_DIR_REMOTE="$T_TMP/remote"
REMOTE_URL="file:///$T_TMP/remote"
setup() {
destroy_tmp
build_repo "${IN_REPO[@]}"
cp -rp "$T_DIR_REPO" "$T_DIR_REMOTE"
}
@test "Command 'clone' (bad remote)" {
echo "
When 'clone' command is provided,
and the remote is bad,
Report error
Remove the YADM_REPO
Exit with 1
"
#; remove existing worktree and repo
rm -rf "$T_DIR_WORK"
mkdir -p "$T_DIR_WORK"
rm -rf "$T_DIR_REPO"
#; run clone
run $T_YADM_Y clone -w "$T_DIR_WORK" "file:///bogus-repo"
#; validate status and output
[ "$status" -eq 1 ]
[[ "$output" =~ Unable\ to\ fetch\ origin ]]
#; confirm repo directory is removed
[ ! -d "$T_DIR_REPO" ]
}
@test "Command 'clone'" {
echo "
When 'clone' command is provided,
Create new repo with attributes:
- 0600 permissions
- not bare
- worktree = \$YADM_WORK
- showUntrackedFiles = no
- yadm.managed = true
Report the repo as cloned
A remote named origin exists
Exit with 0
"
#; remove existing worktree and repo
rm -rf "$T_DIR_WORK"
mkdir -p "$T_DIR_WORK"
rm -rf "$T_DIR_REPO"
#; run clone
run $T_YADM_Y clone -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
#; validate repo attributes
test_perms $T_DIR_REPO "drw.--.--."
test_repo_attribute $T_DIR_REPO core.bare false
test_repo_attribute $T_DIR_REPO core.worktree "$T_DIR_WORK"
test_repo_attribute $T_DIR_REPO status.showUntrackedFiles no
test_repo_attribute $T_DIR_REPO yadm.managed true
#; test the remote
local remote_output=$(GIT_DIR="$T_DIR_REPO" git remote show)
[ "$remote_output" = "origin" ]
}
@test "Command 'clone' (existing repo)" {
echo "
When 'clone' command is provided,
and a repo already exists,
Report error
Exit with 1
"
#; run clone
run $T_YADM_Y clone -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 1 ]
[[ "$output" =~ Git\ repo\ already\ exists ]]
}
@test "Command 'clone' -f (force overwrite)" {
echo "
When 'clone' command is provided,
and '-f' is provided,
and a repo already exists,
Overwrite the repo with attributes:
- 0600 permissions
- not bare
- worktree = \$YADM_WORK
- showUntrackedFiles = no
- yadm.managed = true
Report the repo as cloned
A remote named origin exists
Exit with 0
"
#; remove existing worktree
rm -rf "$T_DIR_WORK"
mkdir -p "$T_DIR_WORK"
#; run clone
run $T_YADM_Y clone -w "$T_DIR_WORK" -f "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
#; validate repo attributes
test_perms $T_DIR_REPO "drw.--.--."
test_repo_attribute $T_DIR_REPO core.bare false
test_repo_attribute $T_DIR_REPO core.worktree "$T_DIR_WORK"
test_repo_attribute $T_DIR_REPO status.showUntrackedFiles no
test_repo_attribute $T_DIR_REPO yadm.managed true
#; test the remote
local remote_output=$(GIT_DIR="$T_DIR_REPO" git remote show)
[ "$remote_output" = "origin" ]
}
@test "Command 'clone' (existing conflicts)" {
echo "
When 'clone' command is provided,
and '-f' is provided,
and a repo already exists,
Overwrite the repo with attributes:
- 0600 permissions
- not bare
- worktree = \$YADM_WORK
- showUntrackedFiles = no
- yadm.managed = true
Report the repo as cloned
A remote named origin exists
Exit with 0
"
#; remove existing repo
rm -rf "$T_DIR_REPO"
#; cause a conflict
echo "conflict" >> "$T_DIR_WORK/.bash_profile"
#; run clone
run $T_YADM_Y clone -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
#; validate merging note
[[ "$output" =~ Merging\ origin\/master\ failed ]]
[[ "$output" =~ NOTE ]]
#; validate repo attributes
test_perms $T_DIR_REPO "drw.--.--."
test_repo_attribute $T_DIR_REPO core.bare false
test_repo_attribute $T_DIR_REPO core.worktree "$T_DIR_WORK"
test_repo_attribute $T_DIR_REPO status.showUntrackedFiles no
test_repo_attribute $T_DIR_REPO yadm.managed true
#; test the remote
local remote_output=$(GIT_DIR="$T_DIR_REPO" git remote show)
[ "$remote_output" = "origin" ]
}

122
test/106_accept_config.bats Normal file
View File

@ -0,0 +1,122 @@
load common
load_fixtures
T_SECTION="test"
T_ATTRIB="attribute"
T_KEY="$T_SECTION.$T_ATTRIB"
T_VALUE="testvalue"
T_EXPECTED="[$T_SECTION]\n\t$T_ATTRIB = $T_VALUE"
setup() {
destroy_tmp
}
@test "Command 'config' (no parameters)" {
skip
echo "
When 'config' command is provided alone,
Produce instructions about supported configuration options
Exit with 1
"
#; TODO: This has not been implemented
}
@test "Command 'config' (read missing)" {
echo "
When 'config' command is provided,
and an attribute is provided
and the attribute isn't configured
Report an empty value
Exit with 0
"
#; run config
run $T_YADM_Y config $T_KEY
#; validate status and output
[ $status -eq 0 ]
[ "$output" = "" ]
}
@test "Command 'config' (write)" {
echo "
When 'config' command is provided,
and an attribute is provided
and a value is provided
Report no output
Update configuration file
Exit with 0
"
#; run config
run $T_YADM_Y config "$T_KEY" "$T_VALUE"
#; validate status and output
[ $status -eq 0 ]
[ "$output" = "" ]
#; validate configuration
local config=$(cat $T_YADM_CONFIG)
local expected=$(echo -e "$T_EXPECTED")
if [ "$config" != "$expected" ]; then
echo "ERROR: Config does not match expected"
echo "$config"
return 1
fi
}
@test "Command 'config' (read)" {
echo "
When 'config' command is provided,
and an attribute is provided
and the attribute is configured
Report the requested value
Exit with 0
"
#; manually load a value into the configuration
mkdir -p $(dirname "$T_YADM_CONFIG")
echo -e "$T_EXPECTED" > $T_YADM_CONFIG
#; run config
run $T_YADM_Y config "$T_KEY"
#; validate status and output
[ $status -eq 0 ]
if [ "$output" != "$T_VALUE" ]; then
echo "ERROR: Incorrect value returned. Expected '$T_VALUE', got '$output'"
return 1
fi
}
@test "Command 'config' (update)" {
echo "
When 'config' command is provided,
and an attribute is provided
and the attribute is already configured
Report no output
Update configuration file
Exit with 0
"
#; manually load a value into the configuration
mkdir -p $(dirname "$T_YADM_CONFIG")
echo -e "${T_EXPECTED}_with_extra_data" > $T_YADM_CONFIG
#; run config
run $T_YADM_Y config "$T_KEY" "$T_VALUE"
#; validate status and output
[ $status -eq 0 ]
[ "$output" = "" ]
#; validate configuration
local config=$(cat $T_YADM_CONFIG)
local expected=$(echo -e "$T_EXPECTED")
if [ "$config" != "$expected" ]; then
echo "ERROR: Config does not match expected"
echo "$config"
return 1
fi
}

92
test/107_accept_list.bats Normal file
View File

@ -0,0 +1,92 @@
load common
load_fixtures
IN_REPO=(.bash_profile .hammerspoon/init.lua .vimrc)
SUBDIR=".hammerspoon"
IN_SUBDIR=(init.lua)
function setup() {
destroy_tmp
build_repo "${IN_REPO[@]}"
}
@test "Command 'list' -a" {
echo "
When 'list' command is provided,
and '-a' is provided,
List tracked files
Exit with 0
"
#; run list -a
run $T_YADM_Y list -a
#; validate status and output
[ "$status" -eq 0 ]
local line=0
for f in "${IN_REPO[@]}"; do
[ "${lines[$line]}" = "$f" ]
((line++)) || true
done
}
@test "Command 'list' (outside of worktree)" {
echo "
When 'list' command is provided,
and while outside of the worktree
List tracked files
Exit with 0
"
#; run list
run $T_YADM_Y list
#; validate status and output
[ "$status" -eq 0 ]
local line=0
for f in "${IN_REPO[@]}"; do
[ "${lines[$line]}" = "$f" ]
((line++)) || true
done
}
@test "Command 'list' (in root of worktree)" {
echo "
When 'list' command is provided,
and while in root of the worktree
List tracked files
Exit with 0
"
#; run list
run bash -c "(cd $T_DIR_WORK; $T_YADM_Y list)"
#; validate status and output
[ "$status" -eq 0 ]
local line=0
for f in "${IN_REPO[@]}"; do
[ "${lines[$line]}" = "$f" ]
((line++)) || true
done
}
@test "Command 'list' (in subdirectory of worktree)" {
echo "
When 'list' command is provided,
and while in subdirectory of the worktree
List tracked files for current directory
Exit with 0
"
#; run list
run bash -c "(cd $T_DIR_WORK/$SUBDIR; $T_YADM_Y list)"
#; validate status and output
[ "$status" -eq 0 ]
local line=0
for f in "${IN_SUBDIR[@]}"; do
echo "'${lines[$line]}' = '$f'"
[ "${lines[$line]}" = "$f" ]
((line++)) || true
done
}

160
test/108_accept_alt.bats Normal file
View File

@ -0,0 +1,160 @@
load common
load_fixtures
IN_REPO=(alt*)
setup() {
destroy_tmp
build_repo "${IN_REPO[@]}"
}
function test_alt() {
local alt_type="$1"
local auto_alt="$2"
#; detemine test parameters
case $alt_type in
base)
link_name="alt-base"
link_match="$link_name##"
;;
system)
link_name="alt-system"
link_match="$link_name##$T_SYS"
;;
host)
link_name="alt-host"
link_match="$link_name##$T_SYS.$T_HOST"
;;
user)
link_name="alt-user"
link_match="$link_name##$T_SYS.$T_HOST.$T_USER"
;;
esac
#; verify link doesn't already exist
if [ -L "$T_DIR_WORK/$link_name" ]; then
echo "ERROR: Link already exists before running yadm"
return 1
fi
#; configure yadm.auto_alt=false
if [ "$auto_alt" = "false" ]; then
git config --file="$T_YADM_CONFIG" yadm.auto-alt false
fi
#; run yadm (alt or status)
if [ -z "$auto_alt" ]; then
run $T_YADM_Y alt
#; validate status and output
if [ "$status" != 0 ] || [[ ! "$output" =~ Linking.+$link_name ]]; then
echo "ERROR: Could not confirm status and output of alt command"
return 1;
fi
else
#; running any passed through Git command should trigger auto-alt
run $T_YADM_Y status
if [ ! -z "$auto_alt" ] && [[ "$output" =~ Linking.+$link_name ]]; then
echo "ERROR: Reporting of link should not happen"
return 1
fi
fi
#; validate link content
if [ "$alt_type" = "none" ] || [ "$auto_alt" = "false" ]; then
#; no link should be present
if [ -L "$T_DIR_WORK/$link_name" ]; then
echo "ERROR: Link should not exist"
return 1
fi
else
#; correct link should be present
local link_content=$(cat "$T_DIR_WORK/$link_name")
if [ "$link_content" != "$link_match" ]; then
echo "ERROR: Link content is not correct"
return 1
fi
fi
}
@test "Command 'alt' (select base)" {
echo "
When the command 'alt' is provided
and file matches only ##
Report the linking
Verify correct file is linked
Exit with 0
"
test_alt 'base' ""
}
@test "Command 'alt' (select system)" {
echo "
When the command 'alt' is provided
and file matches only ##SYSTEM
Report the linking
Verify correct file is linked
Exit with 0
"
test_alt 'system' ""
}
@test "Command 'alt' (select host)" {
echo "
When the command 'alt' is provided
and file matches only ##SYSTEM.HOST
Report the linking
Verify correct file is linked
Exit with 0
"
test_alt 'host' ""
}
@test "Command 'alt' (select user)" {
echo "
When the command 'alt' is provided
and file matches only ##SYSTEM.HOST.USER
Report the linking
Verify correct file is linked
Exit with 0
"
test_alt 'user' ""
}
@test "Command 'alt' (select none)" {
echo "
When the command 'alt' is provided
and no file matches
Verify there is no link
Exit with 0
"
test_alt 'none' ""
}
@test "Command 'auto-alt' (enabled)" {
echo "
When a command possibly changes the repo
and auto-alt is configured true
automatically process alternates
report no linking (not loud)
verify alternate created
"
test_alt 'base' "true"
}
@test "Command 'auto-alt' (disabled)" {
echo "
When a command possibly changes the repo
and auto-alt is configured false
do no linking
verify no links
"
test_alt 'base' "false"
}

View File

@ -0,0 +1,393 @@
load common
load_fixtures
T_PASSWD="ExamplePassword"
setup() {
#; start fresh
destroy_tmp
#; create a worktree & repo
build_repo
#; define a YADM_ENCRYPT
mkdir -p $(dirname "$T_YADM_ENCRYPT")
echo -e ".ssh/*.key\n.gnupg/*.gpg" > $T_YADM_ENCRYPT
#; create a YADM_ARCHIVE
(
cd $T_DIR_WORK
for f in $(sort "$T_YADM_ENCRYPT"); do
tar rf "$T_TMP/build_archive.tar" "$f"
echo "$f" >> "$T_TMP/archived_files"
done
)
#; encrypt YADM_ARCHIVE
expect <<EOF >/dev/null
set timeout 2;
spawn gpg --yes -c --output "$T_YADM_ARCHIVE" "$T_TMP/build_archive.tar"
expect "passphrase:" {send "$T_PASSWD\n"}
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
EOF
}
function validate_archive() {
#; inventory what's in the archive
expect <<EOF >/dev/null
set timeout 2;
spawn bash -c "(gpg -q -d '$T_YADM_ARCHIVE' || echo 1) | tar t | sort > $T_TMP/archive_list"
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
EOF
#; inventory what is expected in the archive
(
cd $T_DIR_WORK
for f in $(cat "$T_YADM_ENCRYPT"); do
echo "$f"
done | sort > "$T_TMP/expected_list"
)
#; compare the archive vs expected
if ! cmp -s "$T_TMP/archive_list" "$T_TMP/expected_list"; then
echo "ERROR: Archive does not contain the correct files"
echo "Contains:"
cat "$T_TMP/archive_list"
return 1
fi
return 0
}
function validate_extraction() {
#; test each file which was archived
for f in $(cat "$T_TMP/archived_files"); do
local contents=$(cat "$T_DIR_WORK/$f")
if [ "$contents" != "$f" ]; then
echo "ERROR: Contents of $T_DIR_WORK/$f is incorrect"
return 1
fi
done
return 0
}
@test "Command 'encrypt' (missing YADM_ENCRYPT)" {
echo "
When 'encrypt' command is provided,
and YADM_ENCRYPT does not exist
Report problem
Exit with 1
"
#; remove YADM_ENCRYPT
rm -f "$T_YADM_ENCRYPT"
#; run encrypt
run $T_YADM_Y encrypt
#; validate status and output
[ "$status" -eq 1 ]
[[ "$output" =~ does\ not\ exist ]]
}
@test "Command 'encrypt' (mismatched password)" {
echo "
When 'encrypt' command is provided,
and YADM_ENCRYPT is present
and the provided passwords do not match
Report problem
Exit with 1
"
#; remove existing T_YADM_ARCHIVE
rm -f "$T_YADM_ARCHIVE"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y encrypt;
expect "passphrase:" {send "ONE\n"}
expect "passphrase:" {send "TWO\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 1 ]
[[ "$output" =~ invalid\ passphrase ]]
[[ "$output" =~ Unable\ to\ write ]]
}
@test "Command 'encrypt'" {
echo "
When 'encrypt' command is provided,
and YADM_ENCRYPT is present
Create YADM_ARCHIVE
Report the archive created
Archive should be valid
Exit with 0
"
#; remove existing T_YADM_ARCHIVE
rm -f "$T_YADM_ARCHIVE"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y encrypt;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Wrote\ new\ file:.+$T_YADM_ARCHIVE ]]
#; validate the archive
validate_archive
}
@test "Command 'encrypt' (comments in YADM_ARCHIVE)" {
echo "
When 'encrypt' command is provided,
and YADM_ENCRYPT is present
Create YADM_ARCHIVE
Report the archive created
Archive should be valid
Exit with 0
"
#; remove existing T_YADM_ARCHIVE
rm -f "$T_YADM_ARCHIVE"
#; add comment to YADM_ARCHIVE
local original_encrypt=$(cat "$T_YADM_ENCRYPT")
echo -e "#.vimrc" >> $T_YADM_ENCRYPT
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y encrypt;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Wrote\ new\ file:.+$T_YADM_ARCHIVE ]]
#; restore comment-free version before valiation
echo "$original_encrypt" > "$T_YADM_ENCRYPT"
#; validate the archive
validate_archive
}
@test "Command 'encrypt' (overwrite)" {
echo "
When 'encrypt' command is provided,
and YADM_ENCRYPT is present
and YADM_ARCHIVE already exists
Overwrite YADM_ARCHIVE
Report the archive created
Archive should be valid
Exit with 0
"
#; Explictly create an invalid archive
echo "EXISTING ARCHIVE" > "$T_YADM_ARCHIVE"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y encrypt;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Wrote\ new\ file:.+$T_YADM_ARCHIVE ]]
#; validate the archive
validate_archive
}
@test "Command 'decrypt' (missing YADM_ARCHIVE)" {
echo "
When 'decrypt' command is provided,
and YADM_ARCHIVE does not exist
Report problem
Exit with 1
"
#; remove YADM_ARCHIVE
rm -f "$T_YADM_ARCHIVE"
#; run encrypt
run $T_YADM_Y decrypt
#; validate status and output
[ "$status" -eq 1 ]
[[ "$output" =~ does\ not\ exist ]]
}
@test "Command 'decrypt' (wrong password)" {
echo "
When 'decrypt' command is provided,
and YADM_ARCHIVE is present
and the provided password is wrong
Report problem
Exit with 1
"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y decrypt;
expect "passphrase:" {send "WRONG\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 1 ]
[[ "$output" =~ decryption\ failed ]]
[[ "$output" =~ Unable\ to\ extract ]]
}
@test "Command 'decrypt' -l (wrong password)" {
echo "
When 'decrypt' command is provided,
and '-l' is provided,
and YADM_ARCHIVE is present
and the provided password is wrong
Report problem
Exit with 1
"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y decrypt -l;
expect "passphrase:" {send "WRONG\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 1 ]
[[ "$output" =~ decryption\ failed ]]
[[ "$output" =~ Unable\ to\ extract ]]
}
@test "Command 'decrypt'" {
echo "
When 'decrypt' command is provided,
and YADM_ARCHIVE is present
Report the data created
Data should be valid
Exit with 0
"
#; empty the worktree
rm -rf "$T_DIR_WORK"
mkdir -p "$T_DIR_WORK"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y decrypt;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ All\ files\ decrypted ]]
#; validate the extracted files
validate_extraction
}
@test "Command 'decrypt' (overwrite)" {
echo "
When 'decrypt' command is provided,
and YADM_ARCHIVE is present
and archived content already exists
Report the data overwritten
Data should be valid
Exit with 0
"
#; alter the values of the archived files
for f in $(cat "$T_TMP/archived_files"); do
echo "changed" >> "$T_DIR_WORK/$f"
done
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y decrypt;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ All\ files\ decrypted ]]
#; validate the extracted files
validate_extraction
}
@test "Command 'decrypt' -l" {
echo "
When 'decrypt' command is provided,
and '-l' is provided,
and YADM_ARCHIVE is present
Report the contents of YADM_ARCHIVE
Exit with 0
"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn $T_YADM_Y decrypt -l;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status
[ "$status" -eq 0 ]
#; validate every file is listed in output
for f in $(cat "$T_TMP/archived_files"); do
if [[ ! "$output" =~ $f ]]; then
echo "ERROR: Did not find '$f' in output"
return 1
fi
done
}

179
test/110_accept_perms.bats Normal file
View File

@ -0,0 +1,179 @@
load common
load_fixtures
setup() {
destroy_tmp
build_repo
}
function is_restricted() {
local p
for p in "${restricted[@]}"; do [ "$p" = "$1" ] && return 0; done
return 1
}
function validate_perms() {
local perms="$@"
#; determine which paths should have restricted permissions
restricted=()
local p
for p in $perms; do
case $p in
ssh)
restricted=("${restricted[@]}" $T_DIR_WORK/.ssh $T_DIR_WORK/.ssh/*)
;;
gpg)
restricted=("${restricted[@]}" $T_DIR_WORK/.gnupg $T_DIR_WORK/.gnupg/*)
;;
encrypt)
local glob
while IFS='' read -r glob || [ -n "$glob" ]; do
if [[ ! $glob =~ ^# ]] ; then
restricted=("${restricted[@]}" $T_DIR_WORK/$glob)
fi
done < "$T_YADM_ENCRYPT"
;;
esac
done
#; validate permissions of each path in the worktere
local testpath
for testpath in $(find "$T_DIR_WORK"); do
local perm_regex="....rwxrwx"
if is_restricted "$testpath"; then
perm_regex="....------"
fi
test_perms "$testpath" "$perm_regex" || return 1
done
}
@test "Command 'perms'" {
echo "
When the command 'perms' is provided
Update permissions for ssh/gpg
Verify correct permissions
Exit with 0
"
#; run perms
run $T_YADM_Y perms
#; validate status and output
[ "$status" -eq 0 ]
[ "$output" = "" ]
#; validate permissions
validate_perms ssh gpg
}
@test "Command 'perms' (with encrypt)" {
echo "
When the command 'perms' is provided
And YADM_ENCRYPT is present
Update permissions for ssh/gpg/encrypt
Support comments in YADM_ENCRYPT
Verify correct permissions
Exit with 0
"
#; this version has a comment in it
echo -e "#.vimrc\n.hammerspoon/*" > "$T_YADM_ENCRYPT"
#; run perms
run $T_YADM_Y perms
#; validate status and output
[ "$status" -eq 0 ]
[ "$output" = "" ]
#; this version has no comments in it
echo -e ".hammerspoon/*" > "$T_YADM_ENCRYPT"
#; validate permissions
validate_perms ssh gpg encrypt
}
@test "Command 'perms' (ssh-perms=false)" {
echo "
When the command 'perms' is provided
And yadm.ssh-perms=false
Update permissions for gpg only
Verify correct permissions
Exit with 0
"
#; configure yadm.ssh-perms
git config --file="$T_YADM_CONFIG" "yadm.ssh-perms" "false"
#; run perms
run $T_YADM_Y perms
#; validate status and output
[ "$status" -eq 0 ]
[ "$output" = "" ]
#; validate permissions
validate_perms gpg
}
@test "Command 'perms' (gpg-perms=false)" {
echo "
When the command 'perms' is provided
And yadm.gpg-perms=false
Update permissions for ssh only
Verify correct permissions
Exit with 0
"
#; configure yadm.gpg-perms
git config --file="$T_YADM_CONFIG" "yadm.gpg-perms" "false"
#; run perms
run $T_YADM_Y perms
#; validate status and output
[ "$status" -eq 0 ]
[ "$output" = "" ]
#; validate permissions
validate_perms ssh
}
@test "Command 'auto-perms' (enabled)" {
echo "
When a command possibly changes the repo
Update permissions for ssh/gpg
Verify correct permissions
"
#; run status
run $T_YADM_Y status
#; validate status
[ "$status" -eq 0 ]
#; validate permissions
validate_perms ssh gpg
}
@test "Command 'auto-perms' (disabled)" {
echo "
When a command possibly changes the repo
And yadm.auto-perms=false
Take no action
Verify permissions are intact
"
#; configure yadm.auto-perms
git config --file="$T_YADM_CONFIG" "yadm.auto-perms" "false"
#; run status
run $T_YADM_Y status
#; validate status
[ "$status" -eq 0 ]
#; validate permissions
validate_perms
}

151
test/common.bash Normal file
View File

@ -0,0 +1,151 @@
#; common fixtures
function load_fixtures() {
DEFAULT_YADM_DIR="$HOME/.yadm"
DEFAULT_REPO="repo.git"
DEFAULT_CONFIG="config"
DEFAULT_ENCRYPT="encrypt"
DEFAULT_ARCHIVE="files.gpg"
T_YADM="$PWD/yadm"
T_TMP="$BATS_TMPDIR/ytmp"
T_DIR_YADM="$T_TMP/.yadm"
T_DIR_WORK="$T_TMP/yadm-work"
T_DIR_REPO="$T_DIR_YADM/repo.git"
T_YADM_CONFIG="$T_DIR_YADM/config"
T_YADM_ENCRYPT="$T_DIR_YADM/encrypt"
T_YADM_ARCHIVE="$T_DIR_YADM/files.gpg"
T_YADM_Y="$T_YADM -Y $T_DIR_YADM"
T_SYS=$(uname -s)
T_HOST=$(hostname -s)
T_USER=$(id -u -n)
}
function configure_git() {
(git config user.name || git config --global user.name 'test') >/dev/null
(git config user.email || git config --global user.email 'test@test.test') > /dev/null
}
function test_perms() {
local test_path="$1"
local regex="$2"
local ls=$(ls -ld "$test_path")
local perms="${ls:0:10}"
if [[ ! $perms =~ $regex ]]; then
echo "ERROR: Found permissions $perms for $test_path"
return 1
fi
return 0
}
function test_repo_attribute() {
local repo_dir="$1"
local attribute="$2"
local expected="$3"
local actual=$(GIT_DIR="$repo_dir" git config --local "$attribute")
if [ "$actual" != "$expected" ]; then
echo "ERROR: repo attribute $attribute set to $actual"
return 1
fi
return 0
}
#; create worktree at path
function create_worktree() {
local DIR_WORKTREE="$1"
if [ -z "$DIR_WORKTREE" ]; then
echo "ERROR: create_worktree() called without a path"
return 1
fi
if [[ ! "$DIR_WORKTREE" =~ ^$T_TMP ]]; then
echo "ERROR: create_worktree() called with a path outside of $T_TMP"
return 1
fi
#; remove any existing data
rm -rf "$DIR_WORKTREE"
#; create some standard files
for f in \
"alt-none##S" \
"alt-none##S.H" \
"alt-none##S.H.U" \
"alt-base##" \
"alt-base##S" \
"alt-base##S.H" \
"alt-base##S.H.U" \
"alt-system##" \
"alt-system##S" \
"alt-system##S.H" \
"alt-system##S.H.U" \
"alt-system##$T_SYS" \
"alt-host##" \
"alt-host##S" \
"alt-host##S.H" \
"alt-host##S.H.U" \
"alt-host##$T_SYS.$T_HOST" \
"alt-user##" \
"alt-user##S" \
"alt-user##S.H" \
"alt-user##S.H.U" \
"alt-user##$T_SYS.$T_HOST.$T_USER" \
.bash_profile \
.gnupg/gpg.conf \
.gnupg/pubring.gpg \
.gnupg/secring.gpg \
.hammerspoon/init.lua \
.ssh/config \
.ssh/secret.key \
.ssh/secret.pub \
.tmux.conf \
.vimrc \
;
do
mkdir -p $(dirname "$DIR_WORKTREE/$f")
echo "$f" > "$DIR_WORKTREE/$f"
done
#; change all perms (so permission updates can be observed)
find "$DIR_WORKTREE" -exec chmod 0777 '{}' ';'
}
#; create a repo in T_DIR_REPO
function build_repo() {
local files_to_add="$@"
#; create a worktree
create_worktree "$T_DIR_WORK"
#; remove the repo if it exists
if [ -e "$T_DIR_REPO" ]; then
rm -rf "$T_DIR_REPO"
fi
#; create the repo
git init --shared=0600 --bare "$T_DIR_REPO" >/dev/null 2>&1
#; standard repo config
GIT_DIR="$T_DIR_REPO" git config core.bare 'false'
GIT_DIR="$T_DIR_REPO" git config core.worktree "$T_DIR_WORK"
GIT_DIR="$T_DIR_REPO" git config status.showUntrackedFiles no
GIT_DIR="$T_DIR_REPO" git config yadm.managed 'true'
if [ -n "$files_to_add" ]; then
for f in $files_to_add; do
GIT_DIR="$T_DIR_REPO" git add "$T_DIR_WORK/$f" >/dev/null
done
GIT_DIR="$T_DIR_REPO" git commit -m 'Create repo template' >/dev/null
fi
}
#; remove all tmp files
function destroy_tmp() {
load_fixtures
rm -rf "$T_TMP"
}
configure_git