mirror of
https://github.com/clearlinux/swupd-client.git
synced 2026-09-08 06:31:50 +00:00
The test library includes many assertions intended to validate a command's output. These assertions take the command output and compare it against an expected output. Some of these assertions take a literal string and others take a string with regular expression values. However, regardless of what king of string is being used for the expected output, there are some common lines in the output that are usually not important and are safe to ignore. An example would be empty lines or lines with only dots. This commit adds the capability for those assertions to use an ignore file to include patterns that could be ignored/removed from the command's output before comparing it against the expected output. Also with this commit empty lines and lines with only dots will be ignored by default. If the assertion needs to validate an exact output without ignoring anything in the ignore-list nor ignoring dots and blank lines, then the --identical option can be used with the assertion.
1327 lines
40 KiB
Bash
1327 lines
40 KiB
Bash
#!bin/bash
|
|
|
|
FUNC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
TEST_FILENAME=$(basename "$BATS_TEST_FILENAME")
|
|
TEST_NAME=${TEST_FILENAME%.bats}
|
|
THEME_DIRNAME="$BATS_TEST_DIRNAME"
|
|
|
|
export TEST_NAME
|
|
export THEME_DIRNAME
|
|
export FUNC_DIR
|
|
export SWUPD_DIR="$FUNC_DIR/../.."
|
|
export SWUPD="$SWUPD_DIR/swupd"
|
|
|
|
# Error codes
|
|
export EBUNDLE_MISMATCH=2 # at least one local bundle mismatches from MoM
|
|
export EBUNDLE_REMOVE=3 # cannot delete local bundle filename
|
|
export EMOM_NOTFOUND=4 # MoM cannot be loaded into memory (this could imply network issue)
|
|
export ETYPE_CHANGED_FILE_RM=5 # do_staging() couldn't delete a file which must be deleted
|
|
export EDIR_OVERWRITE=6 # do_staging() couldn't overwrite a directory
|
|
export EDOTFILE_WRITE=7 # do_staging() couldn't create a dotfile
|
|
export ERECURSE_MANIFEST=8 # error while recursing a manifest
|
|
export ELOCK_FILE=9 # cannot get the lock
|
|
export ECURL_INIT=11 # cannot initialize curl agent
|
|
export EINIT_GLOBALS=12 # cannot initialize globals
|
|
export EBUNDLE_NOT_TRACKED=13 # bundle is not tracked on the system
|
|
export EMANIFEST_LOAD=14 # cannot load manifest into memory
|
|
export EINVALID_OPTION=15 # invalid command option
|
|
export ENOSWUPDSERVER=16 # no net connection to swupd server
|
|
export EFULLDOWNLOAD=17 # full_download problem
|
|
export ENET404=404 # download 404'd
|
|
export EBUNDLE_INSTALL=18 # Cannot install bundles
|
|
export EREQUIRED_DIRS=19 # Cannot create required dirs
|
|
export ECURRENT_VERSION=20 # Cannot determine current OS version
|
|
export ESIGNATURE=21 # Cannot initialize signature verification
|
|
export EBADTIME=22 # System time is bad
|
|
export EDOWNLOADPACKS=23 # Pack download failed
|
|
export EBADCERT=24 # unable to verify server SSL certificate
|
|
|
|
|
|
generate_random_content() {
|
|
|
|
local bottom_range=${1:-5}
|
|
local top_range=${2:-100}
|
|
local range=$((top_range - bottom_range + 1))
|
|
local number_of_lines=$((RANDOM%range+$bottom_range))
|
|
< /dev/urandom tr -dc 'a-zA-Z0-9-_!@#$%^&*()_+{}|:<>?=' | fold -w 100 | head -n $number_of_lines
|
|
|
|
}
|
|
|
|
generate_random_name() {
|
|
|
|
local prefix=${1:-test-}
|
|
local uuid
|
|
|
|
# generate random 8 character alphanumeric string (lowercase only)
|
|
uuid=$(< /dev/urandom tr -dc 'a-f0-9' | fold -w 8 | head -n 1)
|
|
echo "$prefix$uuid"
|
|
|
|
}
|
|
|
|
terminate() {
|
|
|
|
# since the library could be sourced and run from an interactive shell
|
|
# not only from a script, we cannot use exit in interactive shells since it
|
|
# would terminate the shell, so we are using parameter expansion with a fake
|
|
# parameter "param" to force an error when running interactive shells
|
|
local msg=$1
|
|
local param
|
|
case "$-" in
|
|
*i*) : ${param:?"$msg, exiting..."} ;;
|
|
*) echo "$msg, exiting..."
|
|
exit 1;;
|
|
esac
|
|
|
|
}
|
|
|
|
validate_path() {
|
|
|
|
local path=$1
|
|
if [ -z "$path" ] || [ ! -d "$path" ]; then
|
|
terminate "Please provide a valid path"
|
|
fi
|
|
|
|
}
|
|
|
|
validate_item() {
|
|
|
|
local vfile=$1
|
|
if [ -z "$vfile" ] || [ ! -e "$vfile" ]; then
|
|
terminate "Please provide a valid file"
|
|
fi
|
|
|
|
}
|
|
|
|
validate_param() {
|
|
|
|
local param=$1
|
|
if [ -z "$param" ]; then
|
|
terminate "Mandatory parameter missing"
|
|
fi
|
|
|
|
}
|
|
|
|
# Writes to a file that is owned by root
|
|
# Parameters:
|
|
# - "-a": if set, the text will be appeneded to the file,
|
|
# otherwise will be overwritten
|
|
# - FILE: the path to the file to write to
|
|
# - STREAM: the content to be written
|
|
write_to_protected_file() {
|
|
|
|
local arg
|
|
[ "$1" = "-a" ] && { arg=-a ; shift ; }
|
|
local file=${1?Missing output file in write_to_protected_file}
|
|
shift
|
|
printf "$@" | sudo tee $arg "$file" >/dev/null
|
|
|
|
}
|
|
|
|
# Exports environment variables that are dependent on the test environment
|
|
# Parameters:
|
|
# - ENV_NAME: the name of the test environment
|
|
set_env_variables() {
|
|
|
|
local env_name=$1
|
|
local path
|
|
validate_path "$env_name"
|
|
path=$(dirname "$(realpath "$env_name")")
|
|
|
|
export SWUPD_OPTS="-S $path/$env_name/state -p $path/$env_name/target-dir -F staging -u file://$path/$env_name/web-dir -C $FUNC_DIR/Swupd_Root.pem -I"
|
|
export SWUPD_OPTS_NO_CERT="-S $path/$env_name/state -p $path/$env_name/target-dir -F staging -u file://$path/$env_name/web-dir"
|
|
export SWUPD_OPTS_MIRROR="-p $path/$env_name/target-dir"
|
|
export TEST_DIRNAME="$path"/"$env_name"
|
|
|
|
}
|
|
|
|
# Creates a directory with a hashed name in the specified path, if a directory
|
|
# already exists it returns the name
|
|
# Parameters:
|
|
# - PATH: the path where the directory will be created
|
|
create_dir() {
|
|
|
|
local path=$1
|
|
local hashed_name
|
|
local directory
|
|
validate_path "$path"
|
|
|
|
# most directories have the same hash, so we only need one directory
|
|
# in the files directory, if there is already one just return the path/name
|
|
directory=$(find "$path"/* -type d 2> /dev/null)
|
|
if [ ! "$directory" ]; then
|
|
sudo mkdir "$path"/testdir
|
|
hashed_name=$(sudo "$SWUPD" hashdump "$path"/testdir 2> /dev/null)
|
|
sudo mv "$path"/testdir "$path"/"$hashed_name"
|
|
# since tar is all we use, create a tar for the new dir
|
|
create_tar "$path"/"$hashed_name"
|
|
directory="$path"/"$hashed_name"
|
|
fi
|
|
echo "$directory"
|
|
|
|
}
|
|
|
|
# Generates a file with a hashed name in the specified path
|
|
# Parameters:
|
|
# - PATH: the path where the file will be created
|
|
create_file() {
|
|
|
|
local path=$1
|
|
local hashed_name
|
|
validate_path "$path"
|
|
|
|
generate_random_content | sudo tee "$path/testfile" > /dev/null
|
|
hashed_name=$(sudo "$SWUPD" hashdump "$path"/testfile 2> /dev/null)
|
|
sudo mv "$path"/testfile "$path"/"$hashed_name"
|
|
# since tar is all we use, create a tar for the new file
|
|
create_tar "$path"/"$hashed_name"
|
|
echo "$path/$hashed_name"
|
|
|
|
}
|
|
|
|
# Creates a symbolic link with a hashed name to the specified file in the specified path.
|
|
# If no existing file is specified to point to, a new file will be created and pointed to
|
|
# by the link.
|
|
# If a file is provided but doesn't exist, then a dangling file will be created
|
|
# Parameters:
|
|
# - PATH: the path where the symbolic link will be created
|
|
# - FILE: the path to the file to point to
|
|
create_link() {
|
|
|
|
local path=$1
|
|
local pfile=$2
|
|
local hashed_name
|
|
validate_path "$path"
|
|
|
|
# if no file is specified, create one
|
|
if [ -z "$pfile" ]; then
|
|
pfile=$(create_file "$path")
|
|
fi
|
|
sudo ln -rs "$pfile" "$path"/testlink
|
|
hashed_name=$(sudo "$SWUPD" hashdump "$path"/testlink 2> /dev/null)
|
|
sudo mv "$path"/testlink "$path"/"$hashed_name"
|
|
create_tar --skip-validation "$path"/"$hashed_name"
|
|
echo "$path/$hashed_name"
|
|
|
|
}
|
|
|
|
# Creates a tar for the specified item in the same location
|
|
# Parameters:
|
|
# - --skip-validation: if this flag is set (as first parameter) the other parameter
|
|
# is not validated, so use this option carefully
|
|
# - ITEM: the relative path to the item (file, directory, link, manifest)
|
|
create_tar() {
|
|
|
|
local path
|
|
local item_name
|
|
local skip_param_validation=false
|
|
[ "$1" = "--skip-validation" ] && { skip_param_validation=true ; shift ; }
|
|
local item=$1
|
|
|
|
if [ "$skip_param_validation" = false ]; then
|
|
validate_item "$item"
|
|
fi
|
|
|
|
path=$(dirname "$(realpath "$item")")
|
|
item_name=$(basename "$item")
|
|
# if the item is a directory exclude its content when taring
|
|
if [ -d "$item" ]; then
|
|
sudo tar -C "$path" -cf "$path"/"$item_name".tar --exclude="$item_name"/* "$item_name"
|
|
else
|
|
sudo tar -C "$path" -cf "$path"/"$item_name".tar "$item_name"
|
|
fi
|
|
|
|
}
|
|
|
|
# Creates an empty manifest in the specified path
|
|
# Parameters:
|
|
# - PATH: the path where the manifest will be created
|
|
# - BUNDLE_NAME: the name of the bundle which this manifest will be for
|
|
create_manifest() {
|
|
|
|
local path=$1
|
|
local name=$2
|
|
local version
|
|
validate_path "$path"
|
|
validate_param "$name"
|
|
|
|
version=$(basename "$path")
|
|
{
|
|
printf 'MANIFEST\t1\n'
|
|
printf 'version:\t%s\n' "$version"
|
|
printf 'previous:\t0\n'
|
|
printf 'filecount:\t0\n'
|
|
printf 'timestamp:\t%s\n' "$(date +"%s")"
|
|
printf 'contentsize:\t0\n'
|
|
printf '\n'
|
|
} | sudo tee "$path"/Manifest."$name" > /dev/null
|
|
echo "$path/Manifest.$name"
|
|
|
|
}
|
|
|
|
# Adds the specified item to an existing bundle manifest
|
|
# Parameters:
|
|
# - --skip-validation: if this flag is set (as first parameter) the other parameters
|
|
# are not validated, so use this option carefully
|
|
# - MANIFEST: the relative path to the manifest file
|
|
# - ITEM: the relative path to the item (file, directory, symlink) to be added
|
|
# - ITEM_PATH: the absolute path of the item in the target system when installed
|
|
add_to_manifest() {
|
|
|
|
local item_type
|
|
local item_size
|
|
local name
|
|
local version
|
|
local filecount
|
|
local contentsize
|
|
local linked_file
|
|
local boot_type="."
|
|
local file_path
|
|
local skip_param_validation=false
|
|
[ "$1" = "--skip-validation" ] && { skip_param_validation=true ; shift ; }
|
|
local manifest=$1
|
|
local item=$2
|
|
local item_path=$3
|
|
|
|
if [ "$skip_param_validation" = false ]; then
|
|
validate_item "$manifest"
|
|
validate_item "$item"
|
|
validate_param "$item_path"
|
|
fi
|
|
|
|
item_size=$(stat -c "%s" "$item")
|
|
name=$(basename "$item")
|
|
version=$(basename "$(dirname "$manifest")")
|
|
# add to filecount
|
|
filecount=$(awk '/filecount/ { print $2}' "$manifest")
|
|
filecount=$((filecount + 1))
|
|
sudo sed -i "s/filecount:.*/filecount:\\t$filecount/" "$manifest"
|
|
# add to contentsize
|
|
contentsize=$(sudo cat "$manifest" | grep contentsize | awk '{ print $2 }')
|
|
contentsize=$((contentsize + item_size))
|
|
# get the item type
|
|
if [ "$(basename "$manifest")" = Manifest.MoM ]; then
|
|
item_type=M
|
|
# MoM has a contentsize of 0, so don't increase this for MoM
|
|
contentsize=0
|
|
# files, directories and links are stored already hashed, but since
|
|
# manifests are not stored hashed, we need to calculate the hash
|
|
# of the manifest before adding it to the MoM
|
|
name=$(sudo "$SWUPD" hashdump "$item" 2> /dev/null)
|
|
elif [ -L "$item" ]; then
|
|
item_type=L
|
|
# when adding a link to a bundle, we need to make sure we add
|
|
# its associated file too, unless it is a dangling link
|
|
linked_file=$(readlink "$item")
|
|
if [ -e "$(dirname "$item")"/"$linked_file" ]; then
|
|
if [ ! "$(sudo cat "$manifest" | grep "$linked_file")" ]; then
|
|
file_path="$(dirname "$item_path")"
|
|
if [ "$file_path" = "/" ]; then
|
|
file_path=""
|
|
fi
|
|
add_to_manifest "$manifest" "$(dirname "$item")"/"$linked_file" "$file_path"/"$(generate_random_name test-file-)"
|
|
fi
|
|
fi
|
|
elif [ -f "$item" ]; then
|
|
item_type=F
|
|
elif [ -d "$item" ]; then
|
|
item_type=D
|
|
fi
|
|
# if the file is in the /usr/lib/kernel dir then it is a boot file
|
|
if [ "$(dirname "$item_path")" = "/usr/lib/kernel" ] || [ "$(dirname "$item_path")" = "/usr/lib/modules/" ]; then
|
|
boot_type="b"
|
|
fi
|
|
sudo sed -i "s/contentsize:.*/contentsize:\\t$contentsize/" "$manifest"
|
|
# add to manifest content
|
|
write_to_protected_file -a "$manifest" "$item_type.$boot_type.\\t$name\\t$version\\t$item_path\\n"
|
|
# If a manifest tar already exists for that manifest, renew the manifest tar
|
|
sudo rm -f "$manifest".tar
|
|
create_tar "$manifest"
|
|
# if the modified manifest is the MoM, sign it again since it has changed
|
|
if [ "$(basename "$manifest")" = Manifest.MoM ]; then
|
|
sudo rm -f "$manifest".sig
|
|
sign_manifest "$manifest"
|
|
fi
|
|
|
|
}
|
|
|
|
# Adds the specified bundle dependency to an existing bundle manifest
|
|
# Parameters:
|
|
# - MANIFEST: the relative path to the manifest file
|
|
# - DEPENDENCY: the name of the bundle to be included as a dependency
|
|
add_dependency_to_manifest() {
|
|
|
|
local manifest=$1
|
|
local dependency=$2
|
|
local path
|
|
local manifest_name
|
|
local bundle_name
|
|
validate_item "$manifest"
|
|
path=$(dirname "$manifest")
|
|
manifest_name=$(basename "$manifest")
|
|
bundle_name=${manifest_name#Manifest.}
|
|
|
|
sudo sed -i "/contentsize:.*/a includes:\\t$dependency" "$manifest"
|
|
# If a manifest tar already exists for that manifest, renew the manifest tar
|
|
sudo rm -f "$manifest".tar
|
|
create_tar "$manifest"
|
|
|
|
}
|
|
|
|
# Removes the specified item from an existing bundle manifest
|
|
# Parameters:
|
|
# - MANIFEST: the relative path to the manifest file
|
|
# - ITEM: either the hash or filename of the item to be removed
|
|
remove_from_manifest() {
|
|
|
|
local manifest=$1
|
|
local item=$2
|
|
validate_item "$manifest"
|
|
validate_param "$item"
|
|
|
|
# replace every / with \/ in item (if any)
|
|
item="${item////\\/}"
|
|
# remove the lines that match from the manifest
|
|
sudo sed -i "/\\t$item$/d" "$manifest"
|
|
sudo sed -i "/\\t$item\\t/d" "$manifest"
|
|
# If a manifest tar already exists for that manifest, renew the manifest tar
|
|
sudo rm -f "$manifest".tar
|
|
create_tar "$manifest"
|
|
# if the modified manifest is the MoM, sign it again
|
|
if [ "$(basename "$manifest")" = Manifest.MoM ]; then
|
|
sudo rm -f "$manifest".sig
|
|
sign_manifest "$manifest"
|
|
fi
|
|
|
|
}
|
|
|
|
# Recalculate the hashes of the elements in the specified MoM and updates it
|
|
# if there are changes in hashes.
|
|
# Parameters:
|
|
# - MANIFEST: the path to the MoM to be updated
|
|
update_hashes_in_mom() {
|
|
|
|
local manifest=$1
|
|
local path
|
|
local bundle
|
|
local manifest_name
|
|
validate_item "$manifest"
|
|
path=$(dirname "$manifest")
|
|
|
|
IFS=$'\n'
|
|
if [ $(basename "$manifest") = Manifest.MoM ]; then
|
|
bundles=($(sudo cat "$manifest" | grep -x "M\.\.\..*" | awk '{ print $4 }'))
|
|
for bundle in ${bundles[*]}; do
|
|
remove_from_manifest "$manifest" $bundle
|
|
add_to_manifest "$manifest" "$path"/Manifest.$bundle $bundle
|
|
done
|
|
# since the MoM has changed, sign it again
|
|
sudo rm -f "$manifest".sig
|
|
sign_manifest "$manifest"
|
|
else
|
|
echo "The provided manifest is not the MoM"
|
|
return 1
|
|
fi
|
|
unset IFS
|
|
|
|
}
|
|
|
|
# Signs a manifest with a PEM key and generates the signed manifest in the same location
|
|
# Parameters:
|
|
# - MANIFEST: the path to the manifest to be signed
|
|
sign_manifest() {
|
|
|
|
local manifest=$1
|
|
validate_item "$manifest"
|
|
|
|
sudo openssl smime -sign -binary -in "$manifest" \
|
|
-signer "$FUNC_DIR"/Swupd_Root.pem \
|
|
-inkey "$FUNC_DIR"/private.pem \
|
|
-outform DER -out "$(dirname "$manifest")"/Manifest.MoM.sig
|
|
}
|
|
|
|
# Retrieves the hash value of a file or directory in a manifest
|
|
# Parameters:
|
|
# - MANIFEST: the manifest in which it will be looked at
|
|
# - ITEM: the dir or file to look for in the manifest
|
|
get_hash_from_manifest() {
|
|
|
|
local manifest=$1
|
|
local item=$2
|
|
validate_item "$manifest"
|
|
validate_param "$item"
|
|
|
|
hash=$(sudo cat "$manifest" | grep "$item" | awk '{ print $2 }')
|
|
echo "$hash"
|
|
|
|
}
|
|
|
|
# Sets the current version of the target system to the desired version
|
|
# Parameters:
|
|
# - ENVIRONMENT_NAME: the name of the test environmnt to act upon
|
|
# - NEW_VERSION: the version for the target to be set to
|
|
set_current_version() {
|
|
|
|
local env_name=$1
|
|
local new_version=$2
|
|
validate_path "$env_name"
|
|
|
|
sudo sed -i "s/VERSION_ID=.*/VERSION_ID=$new_version/" "$env_name"/target-dir/usr/lib/os-release
|
|
|
|
}
|
|
|
|
# Sets the latest version on the "server" to the desired version
|
|
# Parameters:
|
|
# - ENVIRONMENT_NAME: the name of the test environmnt to act upon
|
|
# - NEW_VERSION: the version for the target to be set to
|
|
set_latest_version() {
|
|
|
|
local env_name=$1
|
|
local new_version=$2
|
|
validate_path "$env_name"
|
|
|
|
write_to_protected_file "$env_name"/web-dir/version/formatstaging/latest "$new_version"
|
|
|
|
}
|
|
|
|
# Creates a test environment with the basic directory structure needed to
|
|
# validate the swupd client
|
|
# Parameters:
|
|
# - ENVIRONMENT_NAME: the name of the test environment, this should be typically the test name
|
|
# - VERSION: the version to use for the test environment, if not specified the default is 10
|
|
create_test_environment() {
|
|
|
|
local env_name=$1
|
|
local version=${2:-10}
|
|
local mom
|
|
validate_param "$env_name"
|
|
|
|
# create all the files and directories needed
|
|
# web-dir files & dirs
|
|
sudo mkdir -p "$env_name"/web-dir/version/formatstaging
|
|
write_to_protected_file "$env_name"/web-dir/version/formatstaging/latest "$version"
|
|
sudo mkdir -p "$env_name"/web-dir/"$version"/files
|
|
sudo mkdir -p "$env_name"/web-dir/"$version"/staged
|
|
mom=$(create_manifest "$env_name"/web-dir/"$version" MoM)
|
|
|
|
# target-dir files & dirs
|
|
sudo mkdir -p "$env_name"/target-dir/usr/lib
|
|
{
|
|
printf 'NAME="Clear Linux Software for Intel Architecture"\n'
|
|
printf 'VERSION=1\n'
|
|
printf 'ID=clear-linux-os\n'
|
|
printf 'VERSION_ID=%s\n' "$version"
|
|
printf 'PRETTY_NAME="Clear Linux Software for Intel Architecture"\n'
|
|
printf 'ANSI_COLOR="1;35"\n'
|
|
printf 'HOME_URL="https://clearlinux.org"\n'
|
|
printf 'SUPPORT_URL="https://clearlinux.org"\n'
|
|
printf 'BUG_REPORT_URL="https://bugs.clearlinux.org/jira"\n'
|
|
} | sudo tee "$env_name"/target-dir/usr/lib/os-release > /dev/null
|
|
sudo mkdir -p "$env_name"/target-dir/usr/share/clear/bundles
|
|
sudo mkdir -p "$env_name"/target-dir/usr/share/defaults/swupd
|
|
printf '1' | sudo tee "$env_name"/target-dir/usr/share/defaults/swupd/format > /dev/null
|
|
sudo mkdir -p "$env_name"/target-dir/etc
|
|
|
|
# state files & dirs
|
|
sudo mkdir -p "$env_name"/state/{staged,download,delta,telemetry}
|
|
sudo chmod -R 0700 "$env_name"/state
|
|
|
|
# export environment variables that are dependent of the test env
|
|
set_env_variables "$env_name"
|
|
|
|
# every environment needs to have at least the os-core bundle so this should be
|
|
# added by default to every test environment
|
|
create_bundle -L -n os-core -v "$version" -f /usr/bin/core "$env_name"
|
|
|
|
}
|
|
|
|
# Destroys a test environment
|
|
# Parameters:
|
|
# - ENVIRONMENT_NAME: the name of the test environment to be deleted
|
|
destroy_test_environment() {
|
|
|
|
local env_name=$1
|
|
validate_path "$env_name"
|
|
|
|
# since the action to be performed is very destructive, at least
|
|
# make sure the directory does look like a test environment
|
|
for var in "state" "target-dir" "web-dir"; do
|
|
if [ ! -d "$env_name/$var" ]; then
|
|
echo "The name provided doesn't seem to be a valid test environment"
|
|
return 1
|
|
fi
|
|
done
|
|
sudo rm -rf "$env_name"
|
|
|
|
}
|
|
|
|
# Creates a bundle in the test environment. The bundle can contain files, directories or symlinks.
|
|
create_bundle() {
|
|
|
|
cb_usage() {
|
|
echo $(cat <<-EOF
|
|
Usage:
|
|
create_bundle [-L] [-n] <bundle_name> [-v] <version> [-d] <list of dirs> [-f] <list of files> [-l] <list of links> ENV_NAME
|
|
|
|
Options:
|
|
-L When the flag is selected the bundle will be 'installed' in the target-dir, otherwise it will only be created in web-dir
|
|
-n The name of the bundle to be created, if not specified a name will be autogenerated
|
|
-v The version for the bundle, if non selected version 10 will be used
|
|
-d Comma-separated list of directories to be included in the bundle
|
|
-f Comma-separated list of files to be created and included in the bundle
|
|
-l Comma-separated list of symlinks to be created and included in the bundle
|
|
-b Comma-separated list of dangling (broken) symlinks to be created and included in the bundle
|
|
|
|
Notes:
|
|
- if no option is selected, a minimal bundle will be created with only one directory
|
|
- for every symlink created a related file will be created and added to the bundle as well (except for dangling links)
|
|
- if the '-f' or '-l' options are used, and the directories where the files live don't exist,
|
|
they will be automatically created and added to the bundle for each file
|
|
|
|
Example of usage:
|
|
|
|
The following command will create a bundle named 'test-bundle', which will include three directories,
|
|
four files, and one symlink (they will be added to the bundle's manifest), all these resources will also
|
|
be tarred. The manifest will be added to the MoM.
|
|
|
|
create_bundle -n test-bundle -f /usr/bin/test-1,/usr/bin/test-2,/etc/systemd/test-3 -l /etc/test-link my_test_env
|
|
|
|
EOF
|
|
)
|
|
}
|
|
|
|
local OPTIND
|
|
local opt
|
|
local dir_list
|
|
local file_list
|
|
local link_list
|
|
local dangling_link_list
|
|
local version
|
|
local bundle_name
|
|
local env_name
|
|
local files_path
|
|
local version_path
|
|
local manifest
|
|
local local_bundle=false
|
|
|
|
set -f # turn off globbing
|
|
while getopts :v:d:f:l:b:n:L opt; do
|
|
case "$opt" in
|
|
d) IFS=, read -r -a dir_list <<< "$OPTARG" ;;
|
|
f) IFS=, read -r -a file_list <<< "$OPTARG" ;;
|
|
l) IFS=, read -r -a link_list <<< "$OPTARG" ;;
|
|
b) IFS=, read -r -a dangling_link_list <<< "$OPTARG" ;;
|
|
n) bundle_name="$OPTARG" ;;
|
|
v) version="$OPTARG" ;;
|
|
L) local_bundle=true ;;
|
|
*) cb_usage
|
|
return ;;
|
|
esac
|
|
done
|
|
set +f # turn globbing back on
|
|
env_name=${@:$OPTIND:1}
|
|
|
|
# set default values
|
|
bundle_name=${bundle_name:-$(generate_random_name test-bundle-)}
|
|
version=${version:-10}
|
|
if [ -z "$dir_list" ] && [ -z "$file_list" ] && [ -z "$link_list" ] && [ -z "$dangling_link_list" ] ; then
|
|
# if nothing was specified to be created, at least create
|
|
# one directory which is the bare minimum for a bundle
|
|
dir_list=(/usr/bin)
|
|
fi
|
|
# all bundles should include their own tracking file, so append it to the
|
|
# list of files to be created in the bundle
|
|
file_list+=(/usr/share/clear/bundles/"$bundle_name")
|
|
|
|
# get useful paths
|
|
validate_path "$env_name"
|
|
version_path="$env_name"/web-dir/"$version"
|
|
files_path="$version_path"/files
|
|
target_path="$env_name"/target-dir
|
|
|
|
# 1) create the initial manifest
|
|
manifest=$(create_manifest "$version_path" "$bundle_name")
|
|
if [ "$DEBUG" == true ]; then
|
|
echo "Manifest -> $manifest"
|
|
fi
|
|
|
|
# 2) Create one directory for the bundle and add it the requested
|
|
# times to the manifest.
|
|
# Every bundle has to have at least one directory,
|
|
# hashes in directories vary depending on owner and permissions,
|
|
# so one directory hash can be reused many times
|
|
bundle_dir=$(create_dir "$files_path")
|
|
if [ "$DEBUG" == true ]; then
|
|
echo "Directory -> $bundle_dir"
|
|
fi
|
|
# Create a zero pack for the bundle and add the directory to it
|
|
sudo tar -cf "$version_path"/pack-"$bundle_name"-from-0.tar --exclude="$bundle_dir"/* "$bundle_dir"
|
|
for val in "${dir_list[@]}"; do
|
|
# the "/" directory is not allowed in the manifest
|
|
if [ val != "/" ]; then
|
|
add_to_manifest "$manifest" "$bundle_dir" "$val"
|
|
if [ "$local_bundle" = true ]; then
|
|
sudo mkdir -p "$target_path$val"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# 3) Create the requested file(s)
|
|
for val in "${file_list[@]}"; do
|
|
# if the directories the file is don't exist, add them to the bundle
|
|
# there are 2 exceptions, the dir of the tracking file and "\"
|
|
fdir=$(dirname "$val")
|
|
if [ ! "$(sudo cat "$manifest" | grep -x "D\\.\\.\\..*$fdir")" ] && [ "$fdir" != "/usr/share/clear/bundles" ] && [ "$fdir" != "/" ]; then
|
|
bundle_dir=$(create_dir "$files_path")
|
|
add_to_manifest "$manifest" "$bundle_dir" "$fdir"
|
|
# add each one of the directories of the path if they are not in the manifest already
|
|
while [ "$(dirname "$fdir")" != "/" ]; do
|
|
fdir=$(dirname "$fdir")
|
|
if [ ! "$(sudo cat "$manifest" | grep -x "D\\.\\.\\..*$fdir")" ]; then
|
|
add_to_manifest "$manifest" "$bundle_dir" "$fdir"
|
|
fi
|
|
done
|
|
fi
|
|
bundle_file=$(create_file "$files_path")
|
|
if [ "$DEBUG" == true ]; then
|
|
echo "file -> $bundle_file"
|
|
fi
|
|
add_to_manifest "$manifest" "$bundle_file" "$val"
|
|
# Add the file to the zero pack of the bundle
|
|
sudo tar -rf "$version_path"/pack-"$bundle_name"-from-0.tar "$bundle_file"
|
|
# if the local_bundle flag is set, copy the files to the target-dir as if the
|
|
# bundle had been locally installed
|
|
if [ "$local_bundle" = true ]; then
|
|
sudo mkdir -p "$target_path$(dirname "$val")"
|
|
sudo cp "$bundle_file" "$target_path$val"
|
|
fi
|
|
done
|
|
|
|
# 4) Create the requested link(s) in the bundle
|
|
for val in "${link_list[@]}"; do
|
|
# if the directory the link is doesn't exist,
|
|
# add it to the bundle (except if the directory is "/")
|
|
fdir=$(dirname "$val")
|
|
if [ "$fdir" != "/" ]; then
|
|
if [ ! "$(sudo cat "$manifest" | grep -x "D\\.\\.\\..*$fdir")" ]; then
|
|
bundle_dir=$(create_dir "$files_path")
|
|
add_to_manifest "$manifest" "$bundle_dir" "$fdir"
|
|
fi
|
|
fi
|
|
bundle_link=$(create_link "$files_path")
|
|
sudo tar -rf "$version_path"/pack-"$bundle_name"-from-0.tar "$bundle_link"
|
|
add_to_manifest "$manifest" "$bundle_link" "$val"
|
|
# Add the file pointed by the link to the zero pack of the bundle
|
|
pfile=$(basename "$(readlink -f "$bundle_link")")
|
|
sudo tar -rf "$version_path"/pack-"$bundle_name"-from-0.tar "$files_path"/"$pfile"
|
|
if [ "$DEBUG" == true ]; then
|
|
echo "link -> $bundle_link"
|
|
echo "file pointed to -> $(readlink -f "$bundle_link")"
|
|
fi
|
|
if [ "$local_bundle" = true ]; then
|
|
sudo mkdir -p "$target_path$(dirname "$val")"
|
|
# if local_bundle is enabled copy the link to target-dir but also
|
|
# copy the file it points to
|
|
pfile_path=$(awk "/$(basename $pfile)/"'{ print $4 }' "$manifest")
|
|
sudo cp "$files_path"/"$pfile" "$target_path$pfile_path"
|
|
sudo ln -rs "$target_path$pfile_path" "$target_path$val"
|
|
fi
|
|
done
|
|
|
|
# 5) Create the requested dangling link(s) in the bundle
|
|
for val in "${dangling_link_list[@]}"; do
|
|
# if the directory the link is doesn't exist,
|
|
# add it to the bundle (except if the directory is "/")
|
|
fdir=$(dirname "$val")
|
|
if [ "$fdir" != "/" ]; then
|
|
if [ ! "$(sudo cat "$manifest" | grep -x "D\\.\\.\\..*$fdir")" ]; then
|
|
bundle_dir=$(create_dir "$files_path")
|
|
add_to_manifest "$manifest" "$bundle_dir" "$fdir"
|
|
fi
|
|
fi
|
|
# Create a link passing a file that does not exits
|
|
bundle_link=$(create_link "$files_path" "$files_path"/"$(generate_random_name does_not_exist-)")
|
|
sudo tar -rf "$version_path"/pack-"$bundle_name"-from-0.tar "$bundle_link"
|
|
add_to_manifest --skip-validation "$manifest" "$bundle_link" "$val"
|
|
# Add the file pointed by the link to the zero pack of the bundle
|
|
if [ "$DEBUG" == true ]; then
|
|
echo "dangling link -> $bundle_link"
|
|
fi
|
|
if [ "$local_bundle" = true ]; then
|
|
sudo mkdir -p "$target_path$(dirname "$val")"
|
|
# if local_bundle is enabled since we cannot copy a bad link create a new one
|
|
# in the appropriate location in target-dir with the corrent name
|
|
sudo ln -s "$(generate_random_name /does_not_exist-)" "$target_path$val"
|
|
fi
|
|
done
|
|
|
|
# 6) Add the bundle to the MoM
|
|
add_to_manifest "$version_path"/Manifest.MoM "$manifest" "$bundle_name"
|
|
|
|
# 7) Create/renew manifest tars
|
|
sudo rm -f "$version_path"/Manifest.MoM.tar
|
|
create_tar "$version_path"/Manifest.MoM
|
|
|
|
# 8) Sign the manifest MoM
|
|
sign_manifest "$version_path"/Manifest.MoM
|
|
|
|
# 9) Create the subscription to the bundle if the local_bundle flag is enabled
|
|
if [ "$local_bundle" = true ]; then
|
|
sudo touch "$target_path"/usr/share/clear/bundles/"$bundle_name"
|
|
fi
|
|
|
|
}
|
|
|
|
# Removes a bundle from the target-dir and/or the web-dir
|
|
# Parameters
|
|
# - -L: if this option is set the bundle is removed from the target-dir only,
|
|
# otherwise it is removed from target-dir and web-dir
|
|
# - BUNDLE_MANIFEST: the manifest of the bundle to be removed
|
|
remove_bundle() {
|
|
|
|
local remove_local=false
|
|
[ "$1" = "-L" ] && { remove_local=true ; shift ; }
|
|
local bundle_manifest=$1
|
|
local target_path
|
|
local version_path
|
|
local bundle_name
|
|
local file_names
|
|
local dir_names
|
|
local manifest_file
|
|
|
|
# if the bundle's manifest is not found just return
|
|
if [ ! -e "$bundle_manifest" ]; then
|
|
echo "$(basename $bundle_manifest) not found, maybe the bundle was already removed"
|
|
return
|
|
fi
|
|
|
|
target_path=$(dirname "$bundle_manifest" | cut -d "/" -f1)/target-dir
|
|
version_path=$(dirname "$bundle_manifest")
|
|
manifest_file=$(basename "$bundle_manifest")
|
|
bundle_name=${manifest_file#Manifest.}
|
|
|
|
# remove all files that are in the manifest from target-dir first
|
|
file_names=($(awk '/^[FL]...\t/ { print $4 }' "$bundle_manifest"))
|
|
for fname in ${file_names[@]}; do
|
|
sudo rm -f "$target_path$fname"
|
|
done
|
|
# now remove all directories in the manifest (only if empty else they
|
|
# may be used by another bundle)
|
|
dir_names=($(awk '/^D...\t/ { print $4 }' "$bundle_manifest"))
|
|
for dname in ${dir_names[@]}; do
|
|
sudo rmdir "$target_path$dname" 2> /dev/null
|
|
done
|
|
if [ "$remove_local" = false ]; then
|
|
# remove all files that are in the manifest from web-dir
|
|
file_names=($(awk '/^[FL]...\t/ { print $2 }' "$bundle_manifest"))
|
|
for fname in ${file_names[@]}; do
|
|
sudo rm "$version_path"/files/"$fname"
|
|
sudo rm "$version_path"/files/"$fname".tar
|
|
done
|
|
# remove zero pack
|
|
sudo rm "$version_path"/pack-"$bundle_name"-from-0.tar
|
|
# finally remove the manifest
|
|
sudo rm "$version_path"/"$manifest_file"
|
|
sudo rm "$version_path"/"$manifest_file".tar
|
|
fi
|
|
|
|
}
|
|
|
|
# Installs a bundle in target-dir
|
|
# Parameters:
|
|
# - BUNDLE_MANIFEST: the manifest of the bundle to be installed
|
|
|
|
install_bundle() {
|
|
|
|
local bundle_manifest=$1
|
|
local target_path
|
|
local file_names
|
|
local dir_names
|
|
local link_names
|
|
local fhash
|
|
local lhash
|
|
local fdir
|
|
local manifest_file
|
|
local bundle_name
|
|
|
|
validate_item "$bundle_manifest"
|
|
target_path=$(dirname "$bundle_manifest" | cut -d "/" -f1)/target-dir
|
|
files_path=$(dirname "$bundle_manifest")/files
|
|
manifest_file=$(basename "$bundle_manifest")
|
|
bundle_name=${manifest_file#Manifest.}
|
|
|
|
# make sure the bundle is not already installed
|
|
if [ -e "$target_path"/usr/share/clear/bundles/"$bundle_name" ]; then
|
|
return
|
|
fi
|
|
|
|
# iterate through the manifest and copy all the files in its
|
|
# correct place, start with directories
|
|
dir_names=($(awk '/^D...\t/ { print $4 }' "$bundle_manifest"))
|
|
for dname in ${dir_names[@]}; do
|
|
sudo mkdir -p "$target_path$dname"
|
|
done
|
|
# now files
|
|
file_names=($(awk '/^F...\t/ { print $4 }' "$bundle_manifest"))
|
|
for fname in ${file_names[@]}; do
|
|
fhash=$(get_hash_from_manifest "$bundle_manifest" "$fname")
|
|
sudo cp "$files_path"/"$fhash" "$target_path$fname"
|
|
done
|
|
# finally links
|
|
link_names=($(awk '/^L...\t/ { print $4 }' "$bundle_manifest"))
|
|
for lname in ${link_names[@]}; do
|
|
lhash=$(get_hash_from_manifest "$bundle_manifest" "$lname")
|
|
fhash=$(readlink "$files_path"/"$lhash")
|
|
# is the original link dangling?
|
|
if [[ $fhash = *"does_not_exist"* ]]; then
|
|
sudo ln -s "$fhash" "$target_path$lname"
|
|
else
|
|
fname=$(awk "/$fhash/ "'{ print $4 }' "$bundle_manifest")
|
|
sudo ln -s $(basename "$fname") "$target_path$lname"
|
|
fi
|
|
done
|
|
|
|
}
|
|
|
|
# Cleans up the directories in the state dir
|
|
# Parameters:
|
|
# - ENV_NAME: the name of the test environment to have the state dir cleaned up
|
|
clean_state_dir() {
|
|
|
|
local env_name=$1
|
|
validate_path "$env_name"
|
|
|
|
sudo rm -rf "$env_name"/state/{staged,download,delta,telemetry}
|
|
sudo mkdir -p "$env_name"/state/{staged,download,delta,telemetry}
|
|
sudo chmod -R 0700 "$env_name"/state
|
|
|
|
}
|
|
|
|
# Creates a new test case based on a template
|
|
# Parameters:
|
|
# - NAME: the name (and path) of the test to be generated
|
|
generate_test() {
|
|
|
|
local name=$1
|
|
local path
|
|
validate_param "$name"
|
|
|
|
path=$(dirname "$name")/
|
|
name=$(basename "$name")
|
|
|
|
{
|
|
printf '#!/usr/bin/env bats\n\n'
|
|
printf 'load "../testlib"\n\n'
|
|
printf 'global_setup() {\n\n'
|
|
printf '\t# global setup\n\n'
|
|
printf '}\n\n'
|
|
printf 'test_setup() {\n\n'
|
|
printf '\t# create_test_environment "$TEST_NAME"\n'
|
|
printf '\t# create_bundle -n <bundle_name> -f <file_1>,<file_2>,<file_N> "$TEST_NAME"\n\n'
|
|
printf '}\n\n'
|
|
printf 'test_teardown() {\n\n'
|
|
printf '\t# destroy_test_environment "$TEST_NAME"\n\n'
|
|
printf '}\n\n'
|
|
printf 'global_teardown() {\n\n'
|
|
printf '\t# global cleanup\n\n'
|
|
printf '}\n\n'
|
|
printf '@test "<test description>" {\n\n'
|
|
printf '\trun sudo sh -c "$SWUPD <swupd_command> $SWUPD_OPTS <command_options>"\n'
|
|
printf '\t# <validations>\n\n'
|
|
printf '}\n\n'
|
|
} > "$path$name".bats
|
|
# make the test script executable
|
|
chmod +x "$path$name".bats
|
|
|
|
}
|
|
|
|
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
# The section below contains test fixtures that can be used from tests to create and
|
|
# cleanup test dependencies, these functions can be overwritten in the test script.
|
|
# The intention of these is to try reducing the amount of boilerplate included in
|
|
# tests since all tests require at least the creation of a test environment
|
|
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
setup() {
|
|
|
|
# the first time setup runs, run the global_setup
|
|
if [ "$BATS_TEST_NUMBER" -eq 1 ]; then
|
|
global_setup
|
|
fi
|
|
# in case the env was created in global_setup set environment variables
|
|
if [ -d "$TEST_NAME" ]; then
|
|
set_env_variables "$TEST_NAME"
|
|
fi
|
|
test_setup
|
|
|
|
}
|
|
|
|
teardown() {
|
|
|
|
test_teardown
|
|
# if the last test just ran, run the global teardown
|
|
if [ "$BATS_TEST_NUMBER" -eq "${#BATS_TEST_NAMES[@]}" ]; then
|
|
global_teardown
|
|
fi
|
|
|
|
}
|
|
|
|
global_setup() {
|
|
|
|
# dummy value in case function is not defined
|
|
return
|
|
|
|
}
|
|
|
|
global_teardown() {
|
|
|
|
# dummy value in case function is not defined
|
|
return
|
|
|
|
}
|
|
|
|
# Default test_setup
|
|
test_setup() {
|
|
|
|
create_test_environment "$TEST_NAME"
|
|
|
|
}
|
|
|
|
# Default test_teardown
|
|
test_teardown() {
|
|
|
|
destroy_test_environment "$TEST_NAME"
|
|
|
|
}
|
|
|
|
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
# The section below contains functions useful for consistent test validation and output
|
|
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
sep="------------------------------------------------------------------"
|
|
|
|
print_assert_failure() {
|
|
|
|
local message=$1
|
|
validate_param "$message"
|
|
|
|
echo -e "\\nAssertion Failed"
|
|
echo -e "$message"
|
|
echo "Command output:"
|
|
echo "------------------------------------------------------------------"
|
|
echo "$output"
|
|
echo "------------------------------------------------------------------"
|
|
|
|
}
|
|
|
|
use_ignore_list() {
|
|
|
|
local ignore_enabled=$1
|
|
local filtered_output
|
|
validate_param "$ignore_enabled"
|
|
|
|
# if selected, remove things in the ignore list from the actual output
|
|
if [ "$ignore_enabled" = true ]; then
|
|
# always remove blank lines and lines with only dots
|
|
filtered_output=$(echo "$output" | sed -E '/^$/d' | sed -E '/^\.+$/d')
|
|
# now remove lines that are included in any of the ignore-lists
|
|
# there are 3 possible ignore-lists that the function is going
|
|
# to recognize (in order of precedence):
|
|
# - <functional_tests_directory>/<test_theme_directory>/<test_name>.ignore-list
|
|
# - <functional_tests_directory>/<test_theme_directory>/ignore-list
|
|
# - <functional_tests_directory>/ignore-list
|
|
if [ -f "$THEME_DIRNAME"/"$TEST_NAME".ignore-list ]; then
|
|
ignore_list="$THEME_DIRNAME"/"$TEST_NAME".ignore-list
|
|
elif [ -f "$THEME_DIRNAME"/ignore-list ]; then
|
|
ignore_list="$THEME_DIRNAME"/ignore-list
|
|
elif [ -f "$FUNC_DIR"/ignore-list ]; then
|
|
ignore_list="$FUNC_DIR"/ignore-list.global
|
|
fi
|
|
while IFS= read -r line; do
|
|
# if the pattern from the file has a "/" escape it first so it does
|
|
# not confuses the sed command
|
|
line="${line////\\/}"
|
|
filtered_output=$(echo "$filtered_output" | sed -E "/^$line$/d")
|
|
done < "$ignore_list"
|
|
else
|
|
filtered_output="$output"
|
|
fi
|
|
echo "$filtered_output"
|
|
|
|
}
|
|
|
|
assert_status_is() {
|
|
|
|
local expected_status=$1
|
|
validate_param expected_status
|
|
|
|
if [ -z "$status" ]; then
|
|
echo "The \$status environment variable is empty."
|
|
echo "Please make sure this assertion is used inside a BATS test after a 'run' command."
|
|
return 1
|
|
fi
|
|
|
|
if [ ! "$status" -eq "$expected_status" ]; then
|
|
print_assert_failure "Expected status: $expected_status\\nActual status: $status"
|
|
return 1
|
|
else
|
|
# if the assertion was successful show the output only if the user
|
|
# runs the test with the -t flag
|
|
echo -e "\\nCommand output:" >&3
|
|
echo "------------------------------------------------------------------" >&3
|
|
echo "$output" >&3
|
|
echo -e "------------------------------------------------------------------\\n" >&3
|
|
fi
|
|
|
|
}
|
|
|
|
assert_status_is_not() {
|
|
|
|
local not_expected_status=$1
|
|
validate_param not_expected_status
|
|
|
|
if [ -z "$status" ]; then
|
|
echo "The \$status environment variable is empty."
|
|
echo "Please make sure this assertion is used inside a BATS test after a 'run' command."
|
|
return 1
|
|
fi
|
|
|
|
if [ "$status" -eq "$not_expected_status" ]; then
|
|
print_assert_failure "Status expected to be different than: $not_expected_status\\nActual status: $status"
|
|
return 1
|
|
else
|
|
# if the assertion was successful show the output only if the user
|
|
# runs the test with the -t flag
|
|
echo -e "\\nCommand output:" >&3
|
|
echo "------------------------------------------------------------------" >&3
|
|
echo "$output" >&3
|
|
echo -e "------------------------------------------------------------------\\n" >&3
|
|
fi
|
|
|
|
}
|
|
|
|
assert_dir_exists() {
|
|
|
|
local vdir=$1
|
|
validate_param vdir
|
|
|
|
if [ ! -d "$vdir" ]; then
|
|
print_assert_failure "Directory $vdir should exist, but it does not"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_dir_not_exists() {
|
|
|
|
local vdir=$1
|
|
validate_param vdir
|
|
|
|
if [ -d "$vdir" ]; then
|
|
print_assert_failure "Directory $vdir should not exist, but it does"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_file_exists() {
|
|
|
|
local vfile=$1
|
|
validate_param vfile
|
|
|
|
if [ ! -f "$vfile" ]; then
|
|
print_assert_failure "File $vfile should exist, but it does not"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_file_not_exists() {
|
|
|
|
local vfile=$1
|
|
validate_param vfile
|
|
|
|
if [ -f "$vfile" ]; then
|
|
print_assert_failure "File $vfile should not exist, but it does"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_in_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ ! "$actual_output" == *"$expected_output"* ]]; then
|
|
print_assert_failure "The following text was not found in the command output:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_not_in_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ "$actual_output" == *"$expected_output"* ]]; then
|
|
print_assert_failure "The following text was found in the command output and should not have:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_is_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ ! "$actual_output" == "$expected_output" ]]; then
|
|
print_assert_failure "The following text was not the command output:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_is_not_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ "$actual_output" == "$expected_output" ]]; then
|
|
print_assert_failure "The following text was the command output and should not have:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_regex_in_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ ! "$actual_output" =~ $expected_output ]]; then
|
|
print_assert_failure "The following text (regex) was not found in the command output:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_regex_not_in_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ "$actual_output" =~ $expected_output ]]; then
|
|
print_assert_failure "The following text (regex) was found in the command output and should not have:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_regex_is_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ ! "$actual_output" =~ ^$expected_output$ ]]; then
|
|
print_assert_failure "The following text (regex) was not the command output:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_regex_is_not_output() {
|
|
|
|
local actual_output
|
|
local ignore_switch=true
|
|
local ignore_list
|
|
[ "$1" = "--identical" ] && { ignore_switch=false ; shift ; }
|
|
local expected_output=$1
|
|
validate_param "$expected_output"
|
|
|
|
actual_output=$(use_ignore_list "$ignore_switch")
|
|
if [[ "$actual_output" =~ ^$expected_output$ ]]; then
|
|
print_assert_failure "The following text (regex) was the command output and should not have:\\n$sep\\n$expected_output\\n$sep"
|
|
echo -e "Difference:\\n$sep"
|
|
echo "$(diff -u <(echo "$expected_output") <(echo "$actual_output"))"
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_equal() {
|
|
|
|
local val1=$1
|
|
local val2=$2
|
|
validate_param val1
|
|
validate_param val2
|
|
|
|
if [ "$val1" != "$val2" ]; then
|
|
return 1
|
|
fi
|
|
|
|
}
|
|
|
|
assert_not_equal() {
|
|
|
|
local val1=$1
|
|
local val2=$2
|
|
validate_param val1
|
|
validate_param val2
|
|
|
|
if [ "$val1" = "$val2" ]; then
|
|
return 1
|
|
fi
|
|
|
|
}
|