Browse Source

add unit tests

main
Nicolas Massé 3 weeks ago
parent
commit
d8b16c5ba5
  1. 3
      .gitmodules
  2. 6
      Makefile
  3. 90
      src/lib/core.sh
  4. 6
      src/zvirt
  5. 1
      test/test_helper/bats-mock
  6. 608
      test/unit/core.bats
  7. 69
      test/unit/usage.bats

3
.gitmodules

@ -4,3 +4,6 @@
[submodule "bats-assert"] [submodule "bats-assert"]
path = test/test_helper/bats-assert path = test/test_helper/bats-assert
url = https://github.com/bats-core/bats-assert.git url = https://github.com/bats-core/bats-assert.git
[submodule "bats-mock"]
path = test/test_helper/bats-mock
url = https://github.com/grayhemp/bats-mock.git

6
Makefile

@ -1,6 +1,6 @@
.PHONY: all test unit-test syntax-test integration-test lint clean .PHONY: all test unit-test syntax-test integration-test lint clean
all: all: syntax-test unit-test lint
syntax-test: syntax-test:
@echo "Running syntax tests..." @echo "Running syntax tests..."
@ -9,9 +9,9 @@ syntax-test:
unit-test: unit-test:
@echo "Running unit tests..." @echo "Running unit tests..."
@bats test/unit @LANG=LC_ALL=C BATS_LIB_PATH=$(PWD)/test/test_helper bats test/unit
clean: clean:
lint: lint:
@echo "Linting..." @echo "Linting..."
@shellcheck src/zvirt src/lib/*.sh @shellcheck src/zvirt src/lib/*.sh

90
src/lib/core.sh

@ -51,7 +51,6 @@ Examples:
EOF EOF
} }
# Initialize the global variables # Initialize the global variables
function init_global_variables () { function init_global_variables () {
# Command line parsing variables # Command line parsing variables
@ -61,7 +60,6 @@ function init_global_variables () {
action="" action=""
batch=0 batch=0
live=0 live=0
should_exit=0
# Cache for domain parameters to avoid redundant calls to the zfs command # Cache for domain parameters to avoid redundant calls to the zfs command
declare -A domain_params_cache=( ) declare -A domain_params_cache=( )
@ -69,6 +67,8 @@ function init_global_variables () {
# Parses the command-line arguments. # Parses the command-line arguments.
function parse_args () { function parse_args () {
local should_exit=0
# Try to get the action from the first positional argument # Try to get the action from the first positional argument
if [ -n "${1:-}" ] && [[ ! "${1:-}" =~ ^- ]]; then if [ -n "${1:-}" ] && [[ ! "${1:-}" =~ ^- ]]; then
action="${1:-}" action="${1:-}"
@ -189,12 +189,12 @@ function domain_checks () {
done done
zfs_dataset_snapshots=( $(get_zfs_snapshots_from_dataset "${zfs_dataset}") ) zfs_dataset_snapshots=( $(get_zfs_snapshots_from_dataset "${zfs_dataset}") )
zfs_mountpoint=$(zfs get -H -o value mountpoint "${zfs_dataset}") zfs_mountpoint=$(get_zfs_dataset_mountpoint "${zfs_dataset}")
if [ -z "$zfs_mountpoint" ] || [[ ! "$zfs_mountpoint" =~ ^/ ]]; then if [ -z "$zfs_mountpoint" ] || [[ ! "$zfs_mountpoint" =~ ^/ ]]; then
error "$domain: Wrong ZFS mountpoint for dataset '$zfs_dataset': '$zfs_mountpoint'." ; error=1 error "$domain: Wrong ZFS mountpoint for dataset '$zfs_dataset': '$zfs_mountpoint'." ; error=1
elif [ ! -d "$zfs_mountpoint" ]; then # elif [ ! -d "$zfs_mountpoint" ]; then
error "$domain: ZFS mountpoint '$zfs_mountpoint' does not exist." ; error=1 # error "$domain: ZFS mountpoint '$zfs_mountpoint' does not exist." ; error=1
fi fi
state=$(domain_state "$domain") state=$(domain_state "$domain")
@ -255,11 +255,20 @@ function domain_checks () {
fi fi
# Store those values in cache for later use # Store those values in cache for later use
domain_params_cache["$domain"]=( "${state}" "${zfs_dataset}" "$zfs_mountpoint" "${zfs_zvols[*]}" ) declare -A domain_params_cache
domain_params_cache["$domain/state"]="${state}"
domain_params_cache["$domain/dataset"]="${zfs_dataset}"
domain_params_cache["$domain/mountpoint"]="${zfs_mountpoint}"
domain_params_cache["$domain/zvols"]="${zfs_zvols[*]}"
return 0 return 0
} }
function get_zfs_dataset_mountpoint () {
local zfs_dataset="$1"
zfs get -H -o value mountpoint "${zfs_dataset}"
}
# Gets the current state of the specified domain. # Gets the current state of the specified domain.
function domain_state () { function domain_state () {
local domain="$1" local domain="$1"
@ -275,13 +284,13 @@ function get_zfs_datasets_from_domain () {
# Gets the list of ZFS zvols used by the specified domain # Gets the list of ZFS zvols used by the specified domain
function get_zfs_zvols_from_domain () { function get_zfs_zvols_from_domain () {
local domain="$1" local domain="$1"
virsh domblklist "$domain" --details | awk '$1 == "block" && $2 == "disk" && $4 ~ /^\/dev\/zvol\// { print gsub(/\/dev\/zvol\//, "", $4) }' virsh domblklist "$domain" --details | awk '$1 == "block" && $2 == "disk" && $4 ~ /^\/dev\/zvol\// { gsub(/\/dev\/zvol\//, "", $4); print $4 }'
} }
# Gets the list of ZFS snapshots for the specified dataset. # Gets the list of ZFS snapshots for the specified dataset.
function get_zfs_snapshots_from_dataset () { function get_zfs_snapshots_from_dataset () {
local dataset="$1" local dataset="$1"
zfs list -H -t snapshot -o name "$dataset" | awk -F'@' '{print $2}' zfs list -H -t snapshot -o name "$dataset" | awk -F'@' '{print $2}' | sort | uniq
} }
# Takes a live snapshot of the specified domain. # Takes a live snapshot of the specified domain.
@ -290,8 +299,8 @@ function take_live_snapshot () {
local snapshot="$2" local snapshot="$2"
log_verbose "$domain: Taking live snapshot '$snapshot'..." log_verbose "$domain: Taking live snapshot '$snapshot'..."
zfs_dataset="${domain_params_cache["$domain"][1]}" zfs_dataset="${domain_params_cache["$domain/dataset"]}"
zfs_mountpoint="${domain_params_cache["$domain"][2]}" zfs_mountpoint="${domain_params_cache["$domain/mountpoint"]}"
virsh save "$domain" "${zfs_mountpoint}/domain.save" --running --verbose --image-format raw virsh save "$domain" "${zfs_mountpoint}/domain.save" --running --verbose --image-format raw
zfs snapshot -r "${zfs_dataset}@${snapshot}" zfs snapshot -r "${zfs_dataset}@${snapshot}"
} }
@ -302,8 +311,7 @@ function take_crash_consistent_snapshot () {
local snapshot="$2" local snapshot="$2"
log_verbose "$domain: Taking crash-consistent snapshot '$snapshot'..." log_verbose "$domain: Taking crash-consistent snapshot '$snapshot'..."
zfs_dataset="${domain_params_cache["$domain"][1]}" zfs_dataset="${domain_params_cache["$domain/dataset"]}"
zfs_mountpoint="${domain_params_cache["$domain"][2]}"
zfs snapshot -r "${zfs_dataset}@${snapshot}" zfs snapshot -r "${zfs_dataset}@${snapshot}"
} }
@ -313,8 +321,7 @@ function revert_snapshot () {
local snapshot="$2" local snapshot="$2"
log_verbose "$domain: Reverting snapshot '$snapshot'..." log_verbose "$domain: Reverting snapshot '$snapshot'..."
zfs_dataset="${domain_params_cache["$domain"][1]}" zfs_dataset="${domain_params_cache["$domain/dataset"]}"
zfs_mountpoint="${domain_params_cache["$domain"][2]}"
zfs list -H -r -o name "$zfs_dataset" | while read dataset; do zfs list -H -r -o name "$zfs_dataset" | while read dataset; do
zfs rollback -Rrf "$dataset@$snapshot" zfs rollback -Rrf "$dataset@$snapshot"
done done
@ -325,8 +332,8 @@ function restore_domain () {
local domain="$1" local domain="$1"
log_verbose "$domain: Restoring live snapshot..." log_verbose "$domain: Restoring live snapshot..."
zfs_dataset="${domain_params_cache["$domain"][1]}" zfs_dataset="${domain_params_cache["$domain/dataset"]}"
zfs_mountpoint="${domain_params_cache["$domain"][2]}" zfs_mountpoint="${domain_params_cache["$domain/mountpoint"]}"
virsh_restore_opts=( ) virsh_restore_opts=( )
if [ "$batch" -eq 1 ]; then if [ "$batch" -eq 1 ]; then
virsh_restore_opts+=( "--paused" ) virsh_restore_opts+=( "--paused" )
@ -338,9 +345,11 @@ function restore_domain () {
# Pauses all domains in the list. # Pauses all domains in the list.
function pause_all_domains () { function pause_all_domains () {
local domains=( "$@" )
for domain in "${domains[@]}"; do for domain in "${domains[@]}"; do
log_verbose "$domain: Pausing domain..." log_verbose "$domain: Pausing domain..."
state="${domain_params_cache["$domain"][0]}" state="${domain_params_cache["$domain/state"]}"
if [ "$state" == "running" ]; then if [ "$state" == "running" ]; then
virsh suspend "$domain" virsh suspend "$domain"
fi fi
@ -349,10 +358,12 @@ function pause_all_domains () {
# Resumes all domains in the list. # Resumes all domains in the list.
function resume_all_domains () { function resume_all_domains () {
local domains=( "$@" )
for domain in "${domains[@]}"; do for domain in "${domains[@]}"; do
log_verbose "$domain: Resuming domain..." log_verbose "$domain: Resuming domain..."
state="${domain_params_cache["$domain"][0]}" state="${domain_params_cache["$domain/state"]}"
case "$(domain_state "$domain")" in case "$state" in
paused) paused)
virsh resume "$domain" || true virsh resume "$domain" || true
;; ;;
@ -368,8 +379,10 @@ function resume_all_domains () {
# Performs pre-flight checks for all specified domains according to the action. # Performs pre-flight checks for all specified domains according to the action.
function preflight_checks () { function preflight_checks () {
local action="$1" local action="$1" ; shift
local snapshot_name="$1" ; shift
local error=0 local error=0
local domains=( "$@" )
for domain in "${domains[@]}"; do for domain in "${domains[@]}"; do
log_verbose "$domain: Performing domain pre-flight checks for $action..." log_verbose "$domain: Performing domain pre-flight checks for $action..."
@ -384,12 +397,12 @@ function preflight_checks () {
# Takes snapshots for all specified domains. # Takes snapshots for all specified domains.
function take_snapshots () { function take_snapshots () {
if [ "$batch" -eq 1 ]; then if [ "$batch" -eq 1 ]; then
pause_all_domains pause_all_domains "${domains[@]}"
fi fi
for domain in "${domains[@]}"; do for domain in "${domains[@]}"; do
state="${domain_params_cache["$domain"][0]}" state="${domain_params_cache["$domain/state"]}"
if [ "$live" -eq 1 ]; then if [ "$live" -eq 1 ] && [ "$state" == "running" ]; then
take_live_snapshot "$domain" "$snapshot_name" take_live_snapshot "$domain" "$snapshot_name"
restore_domain "$domain" restore_domain "$domain"
else else
@ -398,10 +411,10 @@ function take_snapshots () {
done done
if [ "$batch" -eq 1 ]; then if [ "$batch" -eq 1 ]; then
resume_all_domains resume_all_domains "${domains[@]}"
fi fi
return $error return 0
} }
# Reverts snapshots for all specified domains. # Reverts snapshots for all specified domains.
@ -412,26 +425,25 @@ function revert_snapshots () {
done done
if [ "$batch" -eq 1 ]; then if [ "$batch" -eq 1 ]; then
resume_all_domains resume_all_domains "${domains[@]}"
fi fi
} }
# Lists snapshots for all specified domains. # Lists snapshots for all specified domains.
function list_snapshots () { function list_snapshots () {
local domains=( "$@" ) local domains=( "$@" )
local zfs_dataset="" local zfs_datasets
local zfs_mountpoint="" local zfs_dataset
local domain
# TODO
#for domain in "${domains[@]}"; do
zfs_datasets=( $(get_zfs_datasets_from_domain "$domain") ) for domain in "${domains[@]}"; do
if [ ${#zfs_datasets[@]} -ne 1 ]; then zfs_datasets=( $(get_zfs_datasets_from_domain "$domain") )
error "$domain: Wrong number of ZFS datasets (${#zfs_datasets[@]}) found." ; return 1 if [ ${#zfs_datasets[@]} -ne 1 ]; then
fi error "$domain: Wrong number of ZFS datasets (${#zfs_datasets[@]}) found." ; return 1
zfs_dataset="${zfs_datasets[0]:-}" fi
zfs_mountpoint=$(zfs get -H -o value mountpoint "${zfs_dataset}") zfs_dataset="${zfs_datasets[0]:-}"
echo "Snapshots for domain '$domain':" echo "Snapshots for domain '$domain':"
zfs list -H -t snapshot -o name "$zfs_dataset" | awk -F'@' '{print $2}' get_zfs_snapshots_from_dataset "$zfs_dataset" | sed 's/^/ - /'
done
} }

6
src/zvirt

@ -35,19 +35,19 @@ source "$script_dir/lib/core.sh"
# Parse command line arguments and act accordingly # Parse command line arguments and act accordingly
init_global_variables init_global_variables
if ! parse_args; then if ! parse_args "$@"; then
echo echo
show_help >&2 show_help >&2
exit 1 exit 1
fi fi
preflight_checks "$action" || fatal "Pre-flight checks failed."
case "$action" in case "$action" in
snapshot) snapshot)
preflight_checks "$action" "$snapshot_name" "${domains[@]}" || fatal "Pre-flight checks failed."
take_snapshots || fatal "Failed to take snapshots." take_snapshots || fatal "Failed to take snapshots."
;; ;;
revert) revert)
preflight_checks "$action" "$snapshot_name" "${domains[@]}" || fatal "Pre-flight checks failed."
revert_snapshots || fatal "Failed to revert snapshots." revert_snapshots || fatal "Failed to revert snapshots."
;; ;;
list) list)

1
test/test_helper/bats-mock

@ -0,0 +1 @@
Subproject commit 48fce74482a4d2bb879b904ccab31b6bc98e3224

608
test/unit/core.bats

@ -1,19 +1,615 @@
#!/usr/bin/env bats #!/usr/bin/env bats
setup() { setup() {
load '../test_helper/bats-support/load' bats_load_library 'bats-support'
load '../test_helper/bats-assert/load' bats_load_library 'bats-assert'
bats_load_library 'bats-mock'
# Load the core library and export its functions
local fn_before="$(declare -F | cut -d ' ' -f 3 | sort)"
set -Eeuo pipefail
source "${BATS_TEST_DIRNAME}/../../src/lib/core.sh" source "${BATS_TEST_DIRNAME}/../../src/lib/core.sh"
local fn_after="$(declare -F | cut -d ' ' -f 3 | sort)"
declare -a zvirt_fn=( $(comm -13 <(echo "$fn_before") <(echo "$fn_after")) )
for fn in "${zvirt_fn[@]}"; do
export -f "${fn}"
done
# Helper to run commands in a separate bash process with the proper flags
# and with access to the domain_params_cache associative array
in_bash() {
local vars=""
for var in domain_params_cache snapshot_name domains verbose action batch live; do
if declare -p "${var}" &>/dev/null; then
vars+="$(declare -p "${var}") ; "
fi
done
bash -Eeuo pipefail -c "init_global_variables ; $vars \"\$@\"" zvirt "$@"
}
}
@test "domain_state: nominal case" {
# Mock the underlying tools
virsh() { virsh() {
[[ "$1" == "domstate" && "$2" == "foo" ]] && echo "running" [[ "$*" == "domstate foo" ]] && echo "running"
} }
export -f virsh export -f virsh
}
@test "domain_state retourne 'running' pour le domaine foo" { # Run the test
run domain_state "foo" run in_bash domain_state "foo"
assert_success assert_success
assert_output "running" assert_output "running"
} }
@test "domain_exists: nominal case" {
# Mock the underlying tools
virsh() {
[[ "$*" == "dominfo foo" ]] && return 0
return 1
}
export -f virsh
# Run the test
run in_bash domain_exists "foo"
assert_success
run in_bash domain_exists "bar"
assert_failure
}
@test "get_zfs_datasets_from_domain: nominal case" {
# Mock the underlying tools
virsh() {
if [[ "$*" == "domblklist foo --details" ]]; then
cat <<-EOF
Type Device Target Source
------------------------------------------------------------------------
file disk vda /var/lib/libvirt/images/foo/root.img
file disk vdb /var/lib/libvirt/images/foo/data.img
block disk vdc /dev/zvol/data/domains/foo/data-vol
block disk vdd /dev/sda1
EOF
return 0
fi
return 1
}
df() {
if [[ "$*" == "--output=source /var/lib/libvirt/images/foo/root.img" ]] || [[ "$*" == "--output=source /var/lib/libvirt/images/foo/data.img" ]]; then
echo Filesystem
echo "/var/lib/libvirt/images/foo"
return 0
fi
return 1
}
export -f virsh df
# Run the test
run in_bash get_zfs_datasets_from_domain "foo"
assert_output "/var/lib/libvirt/images/foo"
assert_success
run in_bash get_zfs_datasets_from_domain "bar"
assert_failure
}
@test "get_zfs_zvols_from_domain: nominal case" {
# Mock the underlying tools
virsh() {
if [[ "$*" == "domblklist foo --details" ]]; then
cat <<-EOF
Type Device Target Source
------------------------------------------------------------------------
file disk vda /var/lib/libvirt/images/foo/root.img
file disk vdb /var/lib/libvirt/images/foo/data.img
block disk vdc /dev/zvol/data/domains/foo/data-vol
block disk vdd /dev/sda1
EOF
return 0
fi
return 1
}
export -f virsh
# Run the test
run in_bash get_zfs_zvols_from_domain "foo"
assert_output "data/domains/foo/data-vol"
assert_success
run in_bash get_zfs_zvols_from_domain "bar"
assert_failure
}
@test "get_zfs_snapshots_from_dataset: nominal case" {
# Mock the underlying tools
zfs() {
if [[ "$*" == "list -H -t snapshot -o name data/domains/foo" ]]; then
cat <<-EOF
data/domains/foo@snapshot1
data/domains/foo/virtiofs@snapshot1
data/domains/foo@snapshot2
data/domains/foo/virtiofs@snapshot2
EOF
return 0
fi
return 1
}
export -f zfs
# Run the test
run in_bash get_zfs_snapshots_from_dataset "data/domains/foo"
assert_output "snapshot1
snapshot2"
assert_success
run in_bash get_zfs_snapshots_from_dataset "data/domains/bar"
assert_failure
}
@test "get_zfs_dataset_mountpoint: nominal case" {
# Mock the underlying tools
zfs() {
if [[ "$*" == "get -H -o value mountpoint data/domains/foo" ]]; then
echo "/var/lib/libvirt/images/foo"
return 0
fi
return 1
}
export -f zfs
# Run the test
run in_bash get_zfs_dataset_mountpoint "data/domains/foo"
assert_output "/var/lib/libvirt/images/foo"
assert_success
run in_bash get_zfs_dataset_mountpoint "data/domains/bar"
assert_failure
}
@test "take_live_snapshot: nominal case" {
# Mock the underlying tools
declare -A domain_params_cache=( ["foo/state"]="running" ["foo/dataset"]="data/domains/foo" ["foo/mountpoint"]="/var/lib/libvirt/images/foo" ["foo/zvols"]="" )
virsh_mock="$(mock_create)"
virsh() {
if [[ "$*" == "save foo /var/lib/libvirt/images/foo/domain.save --running --verbose --image-format raw" ]]; then
$virsh_mock "$@"
return $?
fi
return 1
}
zfs_mock="$(mock_create)"
zfs() {
if [[ "$*" == "snapshot -r data/domains/foo@backup1" ]]; then
$zfs_mock "$@"
return $?
fi
return 1
}
export -f virsh zfs
export virsh_mock zfs_mock
# Run the test
run in_bash take_live_snapshot foo backup1
assert_success
[[ "$(mock_get_call_num ${virsh_mock})" -eq 1 ]]
[[ "$(mock_get_call_num ${zfs_mock})" -eq 1 ]]
}
@test "take_crash_consistent_snapshot: nominal case" {
# Mock the underlying tools
declare -A domain_params_cache=( ["bar/state"]="running" ["bar/dataset"]="data/domains/bar" ["bar/mountpoint"]="/var/lib/libvirt/images/bar" ["bar/zvols"]="" )
zfs_mock="$(mock_create)"
zfs() {
if [[ "$*" == "snapshot -r data/domains/bar@backup2" ]]; then
$zfs_mock "$@"
return $?
fi
return 1
}
export -f zfs
export zfs_mock
# Run the test
run in_bash take_crash_consistent_snapshot bar backup2
assert_success
[[ "$(mock_get_call_num ${zfs_mock})" -eq 1 ]]
}
@test "revert_snapshot: nominal case" {
# Mock the underlying tools
verbose=1
declare -A domain_params_cache=( ["baz/state"]="running" ["baz/dataset"]="data/domains/baz" ["baz/mountpoint"]="/var/lib/libvirt/images/baz" ["baz/zvols"]="" )
zfs_mock="$(mock_create)"
zfs() {
rollback_pattern="^rollback -Rrf data/domains/baz(/virtiofs)?@backup3$"
if [[ "$*" == "list -H -r -o name data/domains/baz" ]]; then
echo "data/domains/baz
data/domains/baz/virtiofs"
return 0
elif [[ "$*" =~ $rollback_pattern ]]; then
$zfs_mock "$@"
return $?
fi
return 1
}
export -f zfs
export zfs_mock
# Run the test
run in_bash revert_snapshot baz backup3
assert_success
[[ "$(mock_get_call_num ${zfs_mock})" -eq 2 ]]
}
@test "restore_domain: batch mode" {
# Mock the underlying tools
batch=1
declare -A domain_params_cache=( ["foo/state"]="running" ["foo/dataset"]="data/domains/foo" ["foo/mountpoint"]="/var/lib/libvirt/images/foo" ["foo/zvols"]="" )
virsh_mock="$(mock_create)"
virsh() {
if [[ "$*" == "restore /var/lib/libvirt/images/foo/domain.save --verbose --paused" ]]; then
$virsh_mock "$@"
return $?
fi
return 1
}
export -f virsh
export virsh_mock
# Run the test
run in_bash restore_domain foo
assert_success
[[ "$(mock_get_call_num ${virsh_mock})" -eq 1 ]]
}
@test "restore_domain: nominal case" {
# Mock the underlying tools
batch=0
declare -A domain_params_cache=( ["foo/state"]="running" ["foo/dataset"]="data/domains/foo" ["foo/mountpoint"]="/var/lib/libvirt/images/foo" ["foo/zvols"]="" )
virsh_mock="$(mock_create)"
virsh() {
if [[ "$*" == "restore /var/lib/libvirt/images/foo/domain.save --verbose --running" ]]; then
$virsh_mock "$@"
return $?
fi
return 1
}
export -f virsh
export virsh_mock
# Run the test
run in_bash restore_domain foo
assert_success
[[ "$(mock_get_call_num ${virsh_mock})" -eq 1 ]]
}
@test "pause_all_domains: nominal case" {
# Mock the underlying tools
local domains=( "foo" "bar" )
declare -A domain_params_cache=( ["foo/state"]="running" ["bar/state"]="shut off" )
virsh_mock="$(mock_create)"
virsh() {
if [[ "$*" == "suspend foo" ]]; then
$virsh_mock "$@"
return $?
fi
return 1
}
export -f virsh
export virsh_mock
# Run the test
run in_bash pause_all_domains "${domains[@]}"
assert_success
[[ "$(mock_get_call_num ${virsh_mock})" -eq 1 ]]
}
@test "resume_all_domains: nominal case" {
# Mock the underlying tools
local domains=( "foo" "bar" )
declare -A domain_params_cache=( ["foo/state"]="paused" ["bar/state"]="shut off" )
virsh_mock="$(mock_create)"
virsh() {
if [[ "$*" == "resume foo" ]] || [[ "$*" == "start bar" ]]; then
$virsh_mock "$@"
return $?
fi
return 1
}
export -f virsh
export virsh_mock
# Run the test
run in_bash resume_all_domains "${domains[@]}"
assert_success
[[ "$(mock_get_call_num ${virsh_mock})" -eq 2 ]]
}
@test "domain_checks: nominal case" {
# Mock the underlying tools
domain_exists() {
if [[ "$*" == "foo" ]] || [[ "$*" == "bar" ]]; then
return 0
fi
return 1
}
domain_state() {
if [[ "$*" == "foo" ]]; then
echo "running"
return 0
elif [[ "$*" == "bar" ]]; then
echo "shut off"
return 0
fi
return 1
}
get_zfs_datasets_from_domain() {
if [[ "$*" == "foo" ]]; then
echo "data/domains/foo"
return 0
elif [[ "$*" == "bar" ]]; then
echo "data/domains/bar"
return 0
fi
return 1
}
get_zfs_zvols_from_domain() {
if [[ "$*" == "foo" ]]; then
return 0
elif [[ "$*" == "bar" ]]; then
return 0
fi
return 1
}
get_zfs_snapshots_from_dataset() {
if [[ "$*" == "data/domains/foo" ]]; then
echo "backup1"
return 0
elif [[ "$*" == "data/domains/bar" ]]; then
echo "backup1"
return 0
fi
return 1
}
get_zfs_dataset_mountpoint() {
if [[ "$*" == "data/domains/foo" ]]; then
echo "/var/lib/libvirt/images/foo"
return 0
elif [[ "$*" == "data/domains/bar" ]]; then
echo "/var/lib/libvirt/images/bar"
return 0
fi
return 1
}
export -f domain_exists domain_state get_zfs_datasets_from_domain get_zfs_zvols_from_domain get_zfs_snapshots_from_dataset get_zfs_dataset_mountpoint
# Run the test
run in_bash domain_checks snapshot foo backup2
assert_success
run in_bash domain_checks revert bar backup1
assert_success
}
@test "list_snapshots: nominal case" {
# Mock the underlying tools
get_zfs_datasets_from_domain() {
if [[ "$*" == "foo" ]]; then
echo "data/domains/foo"
return 0
fi
return 1
}
get_zfs_snapshots_from_dataset() {
if [[ "$*" == "data/domains/foo" ]]; then
echo "snapshot1
snapshot2"
return 0
fi
return 1
}
export -f get_zfs_datasets_from_domain get_zfs_snapshots_from_dataset
# Run the test
run in_bash list_snapshots foo
assert_success
assert_output "Snapshots for domain 'foo':
- snapshot1
- snapshot2"
}
@test "preflight_checks: nominal case" {
# Mock the underlying tools
domain_checks() {
if [[ "$*" == "snapshot foo backup2" ]]; then
return 0
fi
return 1
}
export -f domain_checks
# Run the test
run in_bash preflight_checks snapshot backup2 foo
assert_success
}
@test "take_snapshots: batch=0, live=0" {
# Mock the underlying tools
take_crash_consistent_snapshot() {
regex="^(foo|bar) backup$"
if [[ "$*" =~ $regex ]]; then
return 0
fi
return 1
}
pause_all_domains() { return 1; }
take_live_snapshot() { return 1; }
restore_domain() { return 1; }
resume_all_domains() { return 1; }
export -f take_crash_consistent_snapshot pause_all_domains take_live_snapshot restore_domain resume_all_domains
declare -A domain_params_cache=( ["foo/state"]="running" ["bar/state"]="shut off" )
# Run the test
domains=( "foo" "bar" )
snapshot_name="backup"
batch=0
live=0
run in_bash take_snapshots
assert_success
# Add a non-existing domain to the list
domains+=( "baz" )
run in_bash take_snapshots
assert_failure
}
@test "take_snapshots: batch=1, live=0" {
# Mock the underlying tools
take_crash_consistent_snapshot() {
regex="^(foo|bar) backup$"
if [[ "$*" =~ $regex ]]; then
return 0
fi
return 1
}
pause_all_domains() {
if [[ "$*" == "foo bar" ]]; then
return 0
fi
return 1
}
take_live_snapshot() { return 1; }
restore_domain() { return 1; }
resume_all_domains() {
if [[ "$*" == "foo bar" ]]; then
return 0
fi
return 1
}
export -f take_crash_consistent_snapshot pause_all_domains take_live_snapshot restore_domain resume_all_domains
declare -A domain_params_cache=( ["foo/state"]="running" ["bar/state"]="shut off" )
# Run the test
domains=( "foo" "bar" )
snapshot_name="backup"
batch=1
live=0
run in_bash take_snapshots
assert_success
# Add a non-existing domain to the list
domains+=( "baz" )
run in_bash take_snapshots
assert_failure
}
@test "take_snapshots: batch=0, live=1" {
# Mock the underlying tools
take_crash_consistent_snapshot() {
if [[ "$*" == "bar backup" ]]; then
return 0
fi
return 1
}
pause_all_domains() { return 1; }
take_live_snapshot() {
if [[ "$*" == "foo backup" ]]; then
return 0
fi
return 1
}
restore_domain() {
if [[ "$*" == "foo" ]]; then
return 0
fi
return 1
}
resume_all_domains() { return 1; }
export -f take_crash_consistent_snapshot pause_all_domains take_live_snapshot restore_domain resume_all_domains
declare -A domain_params_cache=( ["foo/state"]="running" ["bar/state"]="shut off" )
# Run the test
domains=( "foo" "bar" )
snapshot_name="backup"
batch=0
live=1
run in_bash take_snapshots
assert_success
# Add a non-existing domain to the list
domains+=( "baz" )
run in_bash take_snapshots
assert_failure
}
@test "revert_snapshots: batch=0" {
# Mock the underlying tools
revert_snapshot() {
regex="^(foo|bar) backup$"
if [[ "$*" =~ $regex ]]; then
return 0
fi
return 1
}
restore_domain() {
regex="^(foo|bar)$"
if [[ "$*" =~ $regex ]]; then
return 0
fi
return 1
}
resume_all_domains() { return 1; }
export -f revert_snapshot restore_domain resume_all_domains
# Run the test
domains=( "foo" "bar" )
snapshot_name="backup"
batch=0
run in_bash revert_snapshots
assert_success
# Add a non-existing domain to the list
domains+=( "baz" )
run in_bash revert_snapshots
assert_failure
}
@test "revert_snapshots: batch=1" {
# Mock the underlying tools
revert_snapshot() {
regex="^(foo|bar) backup$"
if [[ "$*" =~ $regex ]]; then
return 0
fi
return 1
}
restore_domain() {
regex="^(foo|bar)$"
if [[ "$*" =~ $regex ]]; then
return 0
fi
return 1
}
resume_all_domains() {
if [[ "$*" == "foo bar" ]]; then
return 0
fi
return 1
}
export -f revert_snapshot restore_domain resume_all_domains
# Run the test
domains=( "foo" "bar" )
snapshot_name="backup"
batch=1
run in_bash revert_snapshots
assert_success
# Add a non-existing domain to the list
domains+=( "baz" )
run in_bash revert_snapshots
assert_failure
}

69
test/unit/usage.bats

@ -0,0 +1,69 @@
#!/usr/bin/env bats
bats_require_minimum_version 1.5.0
setup() {
bats_load_library 'bats-support'
bats_load_library 'bats-assert'
set -Eeuo pipefail
source "${BATS_TEST_DIRNAME}/../../src/lib/core.sh"
function call_parse_args () {
init_global_variables
parse_args "$@"
ret=$?
declare -p action batch live verbose domains snapshot_name
return $ret
}
}
@test "call_parse_args: show help and exit" {
run call_parse_args -h
assert_success
assert_output --partial "Usage:"
}
@test "call_parse_args: no action provided" {
run call_parse_args
assert_failure
assert_output --partial "Unsupported action"
}
@test "call_parse_args: list snapshots for a single domain" {
run call_parse_args list -d foo
assert_success
assert_output --partial 'action="list"'
assert_output --partial 'domains=([0]="foo")'
}
@test "call_parse_args: take a snapshot for two domains in batch mode" {
run call_parse_args snapshot -b -d foo -d bar -s backup1 -l
assert_success
assert_output --partial 'action="snapshot"'
assert_output --partial 'batch="1"'
assert_output --partial 'domains=([0]="foo" [1]="bar")'
assert_output --partial 'snapshot_name="backup1"'
assert_output --partial 'live="1"'
}
@test "call_parse_args: take a crash-consistent snapshot for two domains" {
run call_parse_args snapshot -d foo -d bar -s backup2
assert_success
assert_output --partial 'action="snapshot"'
assert_output --partial 'batch="0"'
assert_output --partial 'domains=([0]="foo" [1]="bar")'
assert_output --partial 'snapshot_name="backup2"'
assert_output --partial 'live="0"'
}
@test "call_parse_args: revert snapshot for a domain" {
run call_parse_args revert -d foo -s backup2
assert_success
assert_output --partial 'action="revert"'
assert_output --partial 'batch="0"'
assert_output --partial 'domains=([0]="foo")'
assert_output --partial 'snapshot_name="backup2"'
assert_output --partial 'live="0"'
}
Loading…
Cancel
Save