Add unit tests
This commit is contained in:
parent
8f69f332af
commit
e1aa25db96
9 changed files with 256 additions and 29 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
coverage
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "test/shunit2"]
|
||||
path = test/shunit2
|
||||
url = https://github.com/kward/shunit2.git
|
27
backup.sh
27
backup.sh
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Minecraft server automatic backup management script
|
||||
# by Nicolas Chan
|
||||
# https://github.com/nicolaschan/minecraft-backup
|
||||
# MIT License
|
||||
#
|
||||
# For Minecraft servers running in a GNU screen.
|
||||
|
@ -33,7 +33,8 @@ while getopts 'a:cd:e:f:hi:l:m:o:p:qs:vw:' FLAG; do
|
|||
d) DELETE_METHOD=$OPTARG ;;
|
||||
e) COMPRESSION_FILE_EXTENSION=".$OPTARG" ;;
|
||||
f) TIMESTAMP=$OPTARG ;;
|
||||
h) echo "Minecraft Backup (by Nicolas Chan)"
|
||||
h) echo "Minecraft Backup"
|
||||
echo "Repository: https://github.com/nicolaschan/minecraft-backup"
|
||||
echo "-a Compression algorithm (default: gzip)"
|
||||
echo "-c Enable chat messages"
|
||||
echo "-d Delete method: thin (default), sequential, none"
|
||||
|
@ -70,6 +71,10 @@ log-warning () {
|
|||
echo -e "\033[0;33mWARNING:\033[0m $*"
|
||||
}
|
||||
|
||||
if [[ $COMPRESSION_FILE_EXTENSION == "." ]]; then
|
||||
COMPRESSION_FILE_EXTENSION=""
|
||||
fi
|
||||
|
||||
# Check for missing encouraged arguments
|
||||
if ! $SUPPRESS_WARNINGS; then
|
||||
if [[ $SCREEN_NAME == "" ]]; then
|
||||
|
@ -88,7 +93,7 @@ if [[ $BACKUP_DIRECTORY == "" ]]; then
|
|||
fi
|
||||
|
||||
if $MISSING_CONFIGURATION; then
|
||||
exit 0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCHIVE_FILE_NAME=$TIMESTAMP.tar$COMPRESSION_FILE_EXTENSION
|
||||
|
@ -239,11 +244,11 @@ execute-command "save-off"
|
|||
# Backup world
|
||||
START_TIME=$(date +"%s")
|
||||
case $COMPRESSION_ALGORITHM in
|
||||
"") # No compression
|
||||
tar -cf $ARCHIVE_PATH -C $SERVER_WORLD .
|
||||
# No compression
|
||||
"") tar -cf $ARCHIVE_PATH -C $SERVER_WORLD .
|
||||
;;
|
||||
*) # With compression
|
||||
tar -cf - -C $SERVER_WORLD . | $COMPRESSION_ALGORITHM -cv -$COMPRESSION_LEVEL - > $ARCHIVE_PATH 2>> /dev/null
|
||||
# With compression
|
||||
*) tar -cf - -C $SERVER_WORLD . | $COMPRESSION_ALGORITHM -cv -$COMPRESSION_LEVEL - > $ARCHIVE_PATH 2>> /dev/null
|
||||
;;
|
||||
esac
|
||||
sync
|
||||
|
@ -268,13 +273,13 @@ delete-old-backups () {
|
|||
# Notify players of completion
|
||||
WORLD_SIZE_BYTES=$(du -b --max-depth=0 $SERVER_WORLD | awk '{print $1}')
|
||||
ARCHIVE_SIZE_BYTES=$(du -b $ARCHIVE_PATH | awk '{print $1}')
|
||||
COMPRESSION_PERCENT=$(($ARCHIVE_SIZE_BYTES * 100 / $WORLD_SIZE_BYTES))
|
||||
ARCHIVE_SIZE=$(du -h $ARCHIVE_PATH | awk '{print $1}')
|
||||
BACKUP_DIRECTORY_SIZE=$(du -h --max-depth=0 $BACKUP_DIRECTORY | awk '{print $1}')
|
||||
TIME_DELTA=$((END_TIME - START_TIME))
|
||||
|
||||
# Check that archive size is not null and at least 1024 KB
|
||||
if [[ "$ARCHIVE_SIZE" != "" && "$ARCHIVE_SIZE_BYTES" -gt 8 ]]; then
|
||||
# Check that archive size is not null and at least 200 Bytes
|
||||
if [[ "$WORLD_SIZE_BYTES" -gt 0 && "$ARCHIVE_SIZE" != "" && "$ARCHIVE_SIZE_BYTES" -gt 200 ]]; then
|
||||
COMPRESSION_PERCENT=$(($ARCHIVE_SIZE_BYTES * 100 / $WORLD_SIZE_BYTES))
|
||||
message-players-success "Backup complete!" "$TIME_DELTA s, $ARCHIVE_SIZE/$BACKUP_DIRECTORY_SIZE, $COMPRESSION_PERCENT%"
|
||||
delete-old-backups
|
||||
else
|
||||
|
|
18
test.sh
18
test.sh
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
START_TIMESTAMP=1501484400
|
||||
|
||||
ITERATIONS=1000
|
||||
MINUTE_INTERVAL=30
|
||||
MINUTES_SINCE_START=0
|
||||
|
||||
if [[ $1 != "" ]]; then
|
||||
ITERATIONS=$1
|
||||
fi
|
||||
|
||||
for (( c=1; c<=$ITERATIONS; c++ )); do
|
||||
TIMESTAMP=$(( START_TIMESTAMP + MINUTES_SINCE_START * 60 ))
|
||||
FILE_NAME=$(date -d "@$TIMESTAMP" +%F_%H-%M-%S)
|
||||
./backup.sh -q -i /home/nicolas/privatesurvival/world -o /home/nicolas/backups -f $FILE_NAME
|
||||
(( MINUTES_SINCE_START += MINUTE_INTERVAL ))
|
||||
done
|
1
test/.gitignore
vendored
Normal file
1
test/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
tmp
|
5
test/data/test-chat-messages.txt
Normal file
5
test/data/test-chat-messages.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
tellraw @a ["",{"text":"[Backup] ","color":"gray","italic":true},{"text":"Starting backup...","color":"gray","italic":true,"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"2021-01-01_00-00-00.tar.gz"}]}}}]
|
||||
save-off
|
||||
save-on
|
||||
save-all
|
||||
tellraw @a ["",{"text":"[Backup] ","color":"gray","italic":true},{"text":"Backup complete!","color":"green","italic":true,"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"0 s, 4.0K/4.0K, 316%"}]}}}]
|
5
test/data/test-chat-prefix.txt
Normal file
5
test/data/test-chat-prefix.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
tellraw @a ["",{"text":"[Hello] ","color":"gray","italic":true},{"text":"Starting backup...","color":"gray","italic":true,"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"2021-01-01_00-00-00.tar.gz"}]}}}]
|
||||
save-off
|
||||
save-on
|
||||
save-all
|
||||
tellraw @a ["",{"text":"[Hello] ","color":"gray","italic":true},{"text":"Hello complete!","color":"green","italic":true,"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"0 s, 4.0K/4.0K, 316%"}]}}}]
|
1
test/shunit2
Submodule
1
test/shunit2
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit ebc4baa08f045b7ef0f45c4b7d6f34f08d732f3d
|
224
test/test.sh
Executable file
224
test/test.sh
Executable file
|
@ -0,0 +1,224 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Helper functions
|
||||
|
||||
TEST_DIR="test"
|
||||
TEST_TMP="$TEST_DIR/tmp"
|
||||
SCREEN_TMP="tmp-screen"
|
||||
setUp () {
|
||||
rm -rf "$TEST_TMP"
|
||||
mkdir -p "$TEST_TMP/server/world"
|
||||
mkdir -p "$TEST_TMP/backups"
|
||||
echo "file1" > "$TEST_TMP/server/world/file1.txt"
|
||||
echo "file2" > "$TEST_TMP/server/world/file2.txt"
|
||||
echo "file3" > "$TEST_TMP/server/world/file3.txt"
|
||||
|
||||
screen -dmS "$SCREEN_TMP" bash
|
||||
screen -S "$SCREEN_TMP" -X stuff "cat > $TEST_TMP/screen-output\n"
|
||||
tmux new-session -d -s "$SCREEN_TMP"
|
||||
tmux send-keys -t "$SCREEN_TMP" "cat > $TEST_TMP/tmux-output" ENTER
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
tearDown () {
|
||||
screen -S "$SCREEN_TMP" -X quit >/dev/null 2>&1 || true
|
||||
tmux kill-session -t "$SCREEN_TMP" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
assert-equals-directory () {
|
||||
if [ -d "$1" ]; then
|
||||
for FILE in "$1"/*; do
|
||||
assert-equals-directory "$FILE" "$2/${FILE##$1}"
|
||||
done
|
||||
else
|
||||
assertEquals "$(cat "$1")" "$(cat "$2")"
|
||||
fi
|
||||
}
|
||||
|
||||
check-backup () {
|
||||
BACKUP_ARCHIVE="$1"
|
||||
mkdir -p "$TEST_TMP/restored"
|
||||
tar --extract --file "$TEST_TMP/backups/$BACKUP_ARCHIVE" --directory "$TEST_TMP/restored"
|
||||
assert-equals-directory "$TEST_TMP/server/world" "$TEST_TMP/restored"
|
||||
rm -rf "$TEST_TMP/restored"
|
||||
}
|
||||
|
||||
# Tests
|
||||
|
||||
test-backup-defaults () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
./backup.sh -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
check-backup "$TIMESTAMP.tar.gz"
|
||||
}
|
||||
|
||||
test-backup-no-compression () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
./backup.sh -a "" -e "" -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
check-backup "$TIMESTAMP.tar"
|
||||
}
|
||||
|
||||
test-backup-max-compression () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
./backup.sh -a "xz" -e "xz" -l 9e -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
check-backup "$TIMESTAMP.tar.xz"
|
||||
}
|
||||
|
||||
test-chat-messages () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
./backup.sh -c -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
EXPECTED_OUTPUT="$(head -n-1 "$TEST_DIR/data/test-chat-messages.txt")"
|
||||
ACTUAL_OUTPUT="$(head -n-1 "$TEST_TMP/screen-output")"
|
||||
assertEquals "$EXPECTED_OUTPUT" "$ACTUAL_OUTPUT"
|
||||
}
|
||||
|
||||
test-chat-prefix () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
./backup.sh -p "Hello" -c -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
EXPECTED_OUTPUT="$(head -n-1 "$TEST_DIR/data/test-chat-prefix.txt")"
|
||||
ACTUAL_OUTPUT="$(head -n-1 "$TEST_TMP/screen-output")"
|
||||
assertEquals "$EXPECTED_OUTPUT" "$ACTUAL_OUTPUT"
|
||||
}
|
||||
|
||||
test-check-help () {
|
||||
HELP_HEADER="$(./backup.sh -h)"
|
||||
assertEquals "Minecraft Backup" "$(head -n1 <<< "$HELP_HEADER")"
|
||||
}
|
||||
|
||||
test-missing-options () {
|
||||
OUTPUT="$(./backup.sh 2>&1)"
|
||||
EXIT_CODE="$?"
|
||||
assertEquals 1 "$EXIT_CODE"
|
||||
assertContains "$OUTPUT" "Minecraft screen name not specified"
|
||||
assertContains "$OUTPUT" "Server world not specified"
|
||||
assertContains "$OUTPUT" "Backup directory not specified"
|
||||
}
|
||||
|
||||
test-missing-options-suppress-warnings () {
|
||||
OUTPUT="$(./backup.sh -q 2>&1)"
|
||||
EXIT_CODE="$?"
|
||||
assertEquals 1 "$EXIT_CODE"
|
||||
assertNotContains "$OUTPUT" "Minecraft screen name not specified"
|
||||
}
|
||||
|
||||
test-empty-world-warning () {
|
||||
mkdir -p "$TEST_TMP/server/empty-world"
|
||||
OUTPUT="$(./backup.sh -v -i "$TEST_TMP/server/empty-world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP" 2>&1)"
|
||||
assertContains "$OUTPUT" "Backup was not saved!"
|
||||
}
|
||||
|
||||
test-block-size-warning () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
OUTPUT="$(./backup.sh -m 10 -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP" 2>&1)"
|
||||
EXIT_CODE="$?"
|
||||
assertContains "$OUTPUT" "is smaller than TOTAL_BLOCK_SIZE"
|
||||
}
|
||||
|
||||
test-screen-interface () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
./backup.sh -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
EXPECTED_CONTENTS=$(echo -e "save-off\nsave-on\nsave-all")
|
||||
SCREEN_CONTENTS="$(cat "$TEST_TMP/screen-output")"
|
||||
assertEquals "$SCREEN_CONTENTS" "$EXPECTED_CONTENTS"
|
||||
}
|
||||
|
||||
test-tmux-interface () {
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01")"
|
||||
./backup.sh -w tmux -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
EXPECTED_CONTENTS=$(echo -e "save-off\nsave-on\nsave-all")
|
||||
SCREEN_CONTENTS="$(cat "$TEST_TMP/tmux-output")"
|
||||
assertEquals "$SCREEN_CONTENTS" "$EXPECTED_CONTENTS"
|
||||
}
|
||||
|
||||
test-sequential-delete () {
|
||||
for i in $(seq 0 99); do
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01 +$i hour")"
|
||||
./backup.sh -d "sequential" -m 10 -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
done
|
||||
for i in $(seq 90 99); do
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01 +$i hour")"
|
||||
check-backup "$TIMESTAMP.tar.gz"
|
||||
done
|
||||
}
|
||||
|
||||
test-thinning-delete () {
|
||||
for i in $(seq 0 99); do
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01 +$i hour")"
|
||||
./backup.sh -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP"
|
||||
done
|
||||
EXPECTED_TIMESTAMPS=(
|
||||
# Weekly
|
||||
|
||||
# Daily (30)
|
||||
"2021-01-01_00-00-00"
|
||||
"2021-01-02_00-00-00"
|
||||
"2021-01-03_00-00-00"
|
||||
|
||||
# Hourly (24)
|
||||
"2021-01-03_12-00-00"
|
||||
"2021-01-03_13-00-00"
|
||||
"2021-01-03_14-00-00"
|
||||
"2021-01-03_15-00-00"
|
||||
"2021-01-03_16-00-00"
|
||||
"2021-01-03_17-00-00"
|
||||
"2021-01-03_18-00-00"
|
||||
"2021-01-03_19-00-00"
|
||||
"2021-01-03_20-00-00"
|
||||
"2021-01-04_09-00-00"
|
||||
"2021-01-04_10-00-00"
|
||||
"2021-01-04_11-00-00"
|
||||
|
||||
# Sub-hourly (16)
|
||||
"2021-01-04_12-00-00"
|
||||
"2021-01-04_13-00-00"
|
||||
"2021-01-04_14-00-00"
|
||||
"2021-01-04_15-00-00"
|
||||
"2021-01-04_16-00-00"
|
||||
"2021-01-04_17-00-00"
|
||||
"2021-01-04_18-00-00"
|
||||
"2021-01-04_19-00-00"
|
||||
"2021-01-04_20-00-00"
|
||||
"2021-01-04_21-00-00"
|
||||
"2021-01-04_22-00-00"
|
||||
"2021-01-04_23-00-00"
|
||||
"2021-01-05_00-00-00"
|
||||
"2021-01-05_01-00-00"
|
||||
"2021-01-05_02-00-00"
|
||||
"2021-01-05_03-00-00"
|
||||
)
|
||||
for TIMESTAMP in "${EXPECTED_TIMESTAMPS[@]}"; do
|
||||
check-backup "$TIMESTAMP.tar.gz"
|
||||
done
|
||||
}
|
||||
|
||||
test-thinning-delete-long () {
|
||||
for i in $(seq 0 99); do
|
||||
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01 +$i day")"
|
||||
OUTPUT="$(./backup.sh -v -i "$TEST_TMP/server/world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP")"
|
||||
done
|
||||
EXPECTED_TIMESTAMPS=(
|
||||
# Weekly
|
||||
"2021-01-04_00-00-00"
|
||||
"2021-01-11_00-00-00"
|
||||
"2021-01-25_00-00-00"
|
||||
"2021-01-25_00-00-00"
|
||||
|
||||
# Daily (30)
|
||||
"2021-01-31_00-00-00"
|
||||
"2021-03-01_00-00-00"
|
||||
|
||||
# Hourly (24)
|
||||
"2021-03-02_00-00-00"
|
||||
"2021-03-25_00-00-00"
|
||||
|
||||
# Sub-hourly (16)
|
||||
"2021-03-26_00-00-00"
|
||||
"2021-04-10_00-00-00"
|
||||
)
|
||||
assertContains "$OUTPUT" "promoted to next block"
|
||||
for TIMESTAMP in "${EXPECTED_TIMESTAMPS[@]}"; do
|
||||
check-backup "$TIMESTAMP.tar.gz"
|
||||
done
|
||||
}
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
. test/shunit2/shunit2
|
Loading…
Add table
Reference in a new issue