diff --git a/src/lib/script.sh b/src/lib/script.sh new file mode 100644 index 0000000..1894c36 --- /dev/null +++ b/src/lib/script.sh @@ -0,0 +1,101 @@ +#! /usr/bin/env bash + +# script.sh - utilitary functions. +# Copyright (c) 2022 ge +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +validate_sources() { + # Check sources array. + # + # Usage: validate_sources ARRAY + + # Allowed URI schemes: file, mysql postgres, sqlite + # No required schemes. + + local array=("$@") + local scheme= + + for uri in "${array[@]}"; do + scheme="${uri%%:*}" + case "$scheme" in + file|mysql|postgres|sqlite) : ;; # do nothing, this is OK + *) echo "Error: Unsupported URI scheme: $scheme" >&2; exit 1;; + esac + done +} + +validate_targets() { + # Check targets array. + # + # Usage: validate_targets ARRAY + + # Allowed URI schemes: file, ftp, sftp, rsync, s3, swift, sj, dav, davs + # Required schemes (one or more times): file + + local array=("$@") + local scheme= + local file_scheme=0 + + for uri in "${array[@]}"; do + scheme="${uri%%:*}" + case "$scheme" in + file|ftp|sftp|rsync|s3|swift|sj|dav|davs) + if [[ "$scheme" == file ]]; then + (( file_scheme++ )) || true + fi + ;; + *) echo "Error: Unsupported URI scheme: $scheme" >&2; exit 1;; + esac + done + + if [ "$file_scheme" -eq 0 ]; then + echo "Error: 'file' scheme is not set in targets." \ + "You must provide one or more targets with 'file' scheme." >&2 + exit 1 + fi +} + +source_script() { + # Safely as possible source backup script. + # + # Usage: source_script SCRIPT + + local script="$1" + + if ! test -f "$script"; then + echo "Error: No such file: $script" >&2; exit 1 + fi + + # Dry run script, check syntax. See set(1p) + if ! bash -n "$script"; then + echo Error: Please check your syntax >&2; exit 1 + fi + + # Source script + . "$@" + + # Check required variables + if [[ "$sources" ]]; then + validate_sources "${sources[@]}" + else + echo Error: sources array is not set >&2; exit 1 + fi + + if [[ "$targets" ]]; then + validate_targets "${targets[@]}" + else + echo Error: targets array is not set >&2; exit 1 + fi +} diff --git a/tests/files/bad_syntax.plan b/tests/files/bad_syntax.plan new file mode 100644 index 0000000..9e765d8 --- /dev/null +++ b/tests/files/bad_syntax.plan @@ -0,0 +1,2 @@ +sources= ('file:/home/user') +targets=('file:/var/backup') diff --git a/tests/files/empty_script.plan b/tests/files/empty_script.plan new file mode 100644 index 0000000..e69de29 diff --git a/tests/files/empty_sources.plan b/tests/files/empty_sources.plan new file mode 100644 index 0000000..05533cd --- /dev/null +++ b/tests/files/empty_sources.plan @@ -0,0 +1,2 @@ +sources=() +targets=('file:/var/backup') diff --git a/tests/files/empty_targets.plan b/tests/files/empty_targets.plan new file mode 100644 index 0000000..3efc79e --- /dev/null +++ b/tests/files/empty_targets.plan @@ -0,0 +1,2 @@ +sources=('file:/home/user') +targets=() diff --git a/tests/files/no_file_target.plan b/tests/files/no_file_target.plan new file mode 100644 index 0000000..cdb9601 --- /dev/null +++ b/tests/files/no_file_target.plan @@ -0,0 +1,2 @@ +sources=(file:///) +targets=(ftp://user:pass@host/path) diff --git a/tests/files/unsupported_source_scheme.plan b/tests/files/unsupported_source_scheme.plan new file mode 100644 index 0000000..7e5b940 --- /dev/null +++ b/tests/files/unsupported_source_scheme.plan @@ -0,0 +1,2 @@ +sources=('mongo:/user:password@localhost/database') +targets=('file:/var/backup') diff --git a/tests/files/unsupported_target_scheme.plan b/tests/files/unsupported_target_scheme.plan new file mode 100644 index 0000000..04fffd3 --- /dev/null +++ b/tests/files/unsupported_target_scheme.plan @@ -0,0 +1,2 @@ +sources=('file:/home/user') +targets=(scp://user:pass@host/path) diff --git a/tests/source_script.bats b/tests/source_script.bats new file mode 100644 index 0000000..2814add --- /dev/null +++ b/tests/source_script.bats @@ -0,0 +1,58 @@ +#! /usr/bin/env bats + +# source_script() from lib/script.sh tests. +# See: https://bats-core.readthedocs.io/en/latest/index.html + +setup() { + # Bats setup + load 'helpers/bats-support/load' + load 'helpers/bats-assert/load' + DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" + PATH="$DIR/../src/lib:$PATH" +} + +# ------------------------------ # +# Do tests! # +# ------------------------------ # + +@test "Bad script syntax" { + . script.sh + run source_script $DIR/files/bad_syntax.plan + assert_output --partial 'Error: Please check your syntax' +} + +@test "Empty script" { + . script.sh + run source_script $DIR/files/empty_script.plan + assert_output --partial 'Error: sources array is not set' +} + +@test "Empty sources array" { + . script.sh + run source_script $DIR/files/empty_sources.plan + assert_output --partial 'Error: sources array is not set' +} + +@test "Empty targets array" { + . script.sh + run source_script $DIR/files/empty_targets.plan + assert_output --partial 'Error: targets array is not set' +} + +@test "No targets with file URI scheme" { + . script.sh + run source_script $DIR/files/no_file_target.plan + assert_output --partial "Error: 'file' scheme is not set in targets. You must provide one or more targets with 'file' scheme." +} + +@test "Unsuported source scheme" { + . script.sh + run source_script $DIR/files/unsupported_source_scheme.plan + assert_output --partial 'Error: Unsupported URI scheme: mongo' +} + +@test "Unsuported target scheme" { + . script.sh + run source_script $DIR/files/unsupported_target_scheme.plan + assert_output --partial 'Error: Unsupported URI scheme: scp' +}