#!/bin/bash
echo -e "Loads functions from testing_process.sh"
#=================================================
# Globals variables
#=================================================
# A complete list of backup hooks is available at /usr/share/yunohost/hooks/backup/
backup_hooks="conf_ssowat data_home conf_ynh_firewall conf_cron"
#=================================================
break_before_continue () {
# Make a break if auto_remove is set
if [ $auto_remove -eq 0 ] && [ $bash_mode -ne 1 ]
then
LXC_CONNECT_INFO # Print access information
read -p "Press a key to delete the application and continue...." < /dev/tty
fi
}
check_false_positive_error () {
# Check if FALSE_ERRORS_DETECTION has detected an false positive error.
# We will use
# check_false_positive_error || return $?
# to check the result of the function of propagate the result to parent functions.
if [ $false_positive_error -eq 1 ] && [ $false_positive_error_loop -lt $max_false_positive_error_loop ]; then
# Return 75, for EX_TEMPFAIL from sysexits.h
return 75
fi
}
#=================================================
git_wait_for_pull () {
local_git_repo="$1"
min_time_between_pull=$2
last_pull=$(cat "$local_git_repo/last_pull")
last_pull=${last_pull:-0}
if [ $(( $(date +%s) - $last_pull )) -ge $min_time_between_pull ]
then
date +%s > "$local_git_repo/last_pull"
return 0
else
return 1
fi
}
#=================================================
# In complement of all checks done by Linter, check if the template is respected.
CHECK_TEMPLATE () {
template_error=0
app_scripts_dir="$package_path/scripts"
# For some check, we don't want to look at the standard scripts.
app_scripts="backup|change_url|config|install|remove|restore|upgrade"
grep_command="grep --extended-regexp --dereference-recursive --line-number"
grep_ignore_scripts="grep --invert-match --extended-regexp $app_scripts"
show_error () {
messageL1="$1"
messageL2="$2"
messageL3="$3"
# Keep only the first line found as evidence
evidence="$(echo "$template_output" | head --lines=1)"
evidence="${evidence##$package_path/}"
if [ -n "$template_output" ]
then
if [ $template_error -eq 0 ]
then
all_test=$((all_test+1))
unit_test_title "Compare the syntax to the packaging template..."
ECHO_FORMAT "\nLooks like your package does not respect the template of the example app...\n" "red" "bold"
ECHO_FORMAT "Please follow the template https://github.com/YunoHost/example_ynh\n\n" "lyellow"
fi
template_error=1
ECHO_FORMAT "\n$messageL1\n" "red" "bold"
if [ -n "$messageL2" ]; then
ECHO_FORMAT "$messageL2\n" "red" "bold"
fi
if [ -n "$messageL3" ]; then
ECHO_FORMAT "$messageL3\n" "red" "bold"
fi
ECHO_FORMAT "Here the culprit:\n" "red" "bold"
ECHO_FORMAT "$evidence\n" "lyellow"
fi
}
### Detect common functions that are not helpers
template_output="$($grep_command "^[[:blank:]]*[[:alnum:][:punct:]]+[[:blank:]]*\([[:blank:]]*\)" "$app_scripts_dir" | $grep_ignore_scripts)"
# Put aside ynh_ like helpers
helper_like="$(echo "$template_output" | sed -n '/:[[:blank:]]*ynh_/p')"
# Remove ynh_ like helpers
template_output="$(echo "$template_output" | sed '/:[[:blank:]]*ynh_/d')"
# Ignore known functions
# Remove find_mails, which is a part of ynh_send_readme_to_admin
template_output="$(echo "$template_output" | sed '/find_mails/d')"
# And at_least_one, part of ynh_get_scalable_phpfpm
template_output="$(echo "$template_output" | sed '/at_least_one/d')"
show_error "Do not use specific functions aside of ynh helpers." "Keep your code linear directly into the scripts to ease the reading of your scripts"
# Ignore known helpers
# Remove ynh_clean_setup, an official helper defined only in comment into official helpers
helper_like="$(echo "$helper_like" | sed '/ynh_clean_setup/d')"
### Detect functions that looks like YunoHost helpers
if [ -n "$helper_like" ]
then
# Download official helpers and YunoHost helpers
# Get officials helpers
official_helper_dir="$script_dir/helpers/Officials"
mkdir -p "$official_helper_dir"
( cd "$official_helper_dir"
# If we don't already have the .git directory
if [ ! -d .git ]
then
# Set the git clone
git init > /dev/null 2>&1
git remote add origin -f https://github.com/YunoHost/yunohost > /dev/null 2>&1
git config core.sparseCheckout true
# Get only the helper directory
echo "/data/helpers.d" > .git/info/sparse-checkout
fi
# To not pull more than once a hour
if git_wait_for_pull "$official_helper_dir" 3600; then
git pull origin HEAD > /dev/null 2>&1
fi )
# And get experimentals helpers
experimental_helper_dir="$script_dir/helpers/Experimental_helpers"
( cd "$script_dir/helpers"
# If we don't already have the repository
if [ ! -d Experimental_helpers ]
then
# Clone the repository
git clone https://github.com/YunoHost-Apps/Experimental_helpers > /dev/null 2>&1
fi
cd Experimental_helpers
# To not pull more than once a hour
if git_wait_for_pull "$experimental_helper_dir" 3600; then
git pull origin HEAD > /dev/null 2>&1
fi )
# Check each helper found
while read helper
do
# Keep only the name of the helper
helper_name=$(echo "$helper" | sed 's/.*:\([[:alnum:][:punct:]]*\).*/\1/' | sed 's/()//')
# Try to find the helper whether in officials or experimentals
if ! $grep_command --quiet "^$helper_name" "$script_dir/helpers"
then
template_output="$helper"
show_error "This helper does not look like an existing helper." "Do not use specific functions aside of ynh helpers." "Keep your code linear directly into the scripts to ease the reading of your scripts"
break
fi
done <<< "$(echo "$helper_like")"
fi
### Detect usage of ynh_render_template
template_output="$($grep_command --word-regexp "ynh_render_template" "$app_scripts_dir")"
show_error "Do not use ynh_render_template in app scripts." "Use ynh_replace_string instead to keep clear all modifications made on files"
### Detect presence of comment separators
for script in ${app_scripts//|/ }
do
if [ -e "$app_scripts_dir/$script" ]
then
template_output="$($grep_command --count "#=================" "$app_scripts_dir/$script")"
if [ $template_output -lt 12 ]
then
template_output="$app_scripts_dir/$script"
show_error "Looks like there isn't many comment separators in your script" "Consider adding more separators to clarify the steps in your script"
fi
fi
done
### Detect presence of progression indicators
for script in ${app_scripts//|/ }
do
if [ -e "$app_scripts_dir/$script" ] && [ "$script" != "config" ]
then
template_output="$($grep_command --count "ynh_script_progression|ynh_print_info" "$app_scripts_dir/$script")"
if [ $template_output -lt 5 ] || ( [ "$script" = "change_url" ] && [ $template_output -lt 3 ] )
then
template_output="$app_scripts_dir/$script"
show_error "Looks like there isn't many comment progression indicators in your script" "Consider adding more indicators to help your users know the progression of the scripts"
fi
fi
done
### Detect usage of ynh_restore
template_output="$($grep_command --word-regexp "ynh_restore" "$app_scripts_dir")"
show_error "Do not use ynh_restore in app scripts." "Use ynh_restore_file instead to keep clear all files that are restored and in which order."
### Detect usage of set -u or set -e in remove script
template_output="$($grep_command --word-regexp "set -u|set -e" "$app_scripts_dir/remove")"
show_error "Do not use 'set -e' or 'set -u' in a remove script." "If an error happen during the script, the app will be half removed !"
if [ $template_error -eq 1 ]
then
echo ""
RESULT_template=1
check_failed
fi
}
#=================================================
PRINT_YUNOHOST_VERSION () {
ECHO_FORMAT ">> YunoHost versions:\n" "white" "bold" clog
# Be sure that the container is running
LXC_START "true"
# Print the version of YunoHost from the LXC container
ssh $arg_ssh $lxc_name "sudo yunohost --version"
# Get the version of YunoHost from the LXC container
ynh_version=$(ssh -q $lxc_name "sudo yunohost --version --output-as plain | grep -A4 moulinette | tail -n1 | sed 's@\.@@g' | cut -d+ -f1")
}
#=================================================
# Install and remove an app
#=================================================
SETUP_APP () {
# Install an application in a LXC container
# Uses the default snapshot
current_snapshot=snap0
# Exec the pre-install instruction, if there one
if [ -n "$pre_install" ]
then
ECHO_FORMAT "Pre installation request\n" "white" "bold" clog
# Start the lxc container
LXC_START "true"
# Copy all the instructions into a script
echo "$pre_install" > "$script_dir/preinstall.sh"
chmod +x "$script_dir/preinstall.sh"
# Replace variables
sed -i "s/\$USER/$test_user/" "$script_dir/preinstall.sh"
sed -i "s/\$DOMAIN/$main_domain/" "$script_dir/preinstall.sh"
sed -i "s/\$SUBDOMAIN/$sub_domain/" "$script_dir/preinstall.sh"
sed -i "s/\$PASSWORD/$yuno_pwd/" "$script_dir/preinstall.sh"
# Copy the pre-install script into the container.
scp -rq "$script_dir/preinstall.sh" "$lxc_name":
# Then execute the script to execute the pre-install commands.
LXC_START "./preinstall.sh >&2"
# Print the log to print the results
ECHO_FORMAT "$(cat "$temp_log")\n" clog
fi
# Install the application in a LXC container
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app install --force \"$package_dir\" -a \"$manifest_args_mod\""
# yunohost_result gets the return code of the installation
yunohost_result=$?
# Print the result of the install command
if [ $yunohost_result -eq 0 ]; then
ECHO_FORMAT "Installation successful. ($yunohost_result)\n" "white" clog
else
ECHO_FORMAT "Installation failed. ($yunohost_result)\n" "white" clog
fi
# Check all the witness files, to verify if them still here
check_witness_files
# Retrieve the app id in the log. To manage the app after
ynh_app_id=$(sudo tac "$yunohost_log" | grep --only-matching --max-count=1 "YNH_APP_INSTANCE_NAME=[^ ]*" | cut --delimiter='=' --fields=2)
# Analyse the log to extract "warning" and "error" lines
LOG_EXTRACTOR
check_false_positive_error || return $?
}
STANDARD_SETUP_APP () {
# Try to find an existing snapshot for this install, or make an install
# If it's a root install
if [ "$check_path" = "/" ]
then
# Check if a snapshot already exist for this install
if [ -z "$root_snapshot" ]
then
# Make an installation
SETUP_APP
check_false_positive_error || return $?
# Create a snapshot for this installation, to be able to reuse it instead of a new installation.
# But only if this installation has worked fine
if [ $yunohost_result -eq 0 ]; then
# Check if a snapshot already exist for a root install
if [ -z "$root_snapshot" ]
then
ECHO_FORMAT "\nCreate a snapshot for root installation.\n" "white" clog
create_temp_backup 2
root_snapshot=snap2
fi
fi
else
# Or uses an existing snapshot
ECHO_FORMAT "Uses an existing snapshot for root installation.\n" "white" clog
use_temp_snapshot $root_snapshot
fi
# In case of sub path install, use another snapshot
else
# Check if a snapshot already exist for this install
if [ -z "$subpath_snapshot" ]
then
# Make an installation
SETUP_APP
check_false_positive_error || return $?
# Create a snapshot for this installation, to be able to reuse it instead of a new installation.
# But only if this installation has worked fine
if [ $yunohost_result -eq 0 ]; then
# Check if a snapshot already exist for a subpath (or no_url) install
if [ -z "$subpath_snapshot" ]
then
ECHO_FORMAT "\nCreate a snapshot for sub path installation.\n" "white" clog
create_temp_backup 1
root_snapshot=snap1
fi
fi
else
# Or uses an existing snapshot
ECHO_FORMAT "Uses an existing snapshot for sub path installation.\n" "white" clog
use_temp_snapshot $subpath_snapshot
fi
fi
}
REMOVE_APP () {
# Remove an application
# Make a break if auto_remove is set
break_before_continue
ECHO_FORMAT "\nDeleting...\n" "white" "bold" clog
# Remove the application from the LXC container
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app remove \"$ynh_app_id\""
# yunohost_remove gets the return code of the deletion
yunohost_remove=$?
# Print the result of the remove command
if [ "$yunohost_remove" -eq 0 ]; then
ECHO_FORMAT "Deleting successful. ($yunohost_remove)\n" "white" clog
else
ECHO_FORMAT "Deleting failed. ($yunohost_remove)\n" "white" clog
fi
# Check all the witness files, to verify if them still here
check_witness_files
}
#=================================================
# Try to access the app by its url
#=================================================
CHECK_URL () {
# Try to access the app by its url
if [ $use_curl -eq 1 ]
then
ECHO_FORMAT "\nTry to access by url...\n" "white" "bold"
# Force a skipped_uris if public mode is not set
if [ "$install_type" != "private" ] && [ "$install_type" != "public" ] && [ -z "$public_arg" ]
then
# Add a skipped_uris on / for the app
LXC_START "sudo yunohost app setting \"$ynh_app_id\" skipped_uris -v \"/\""
# Regen the config of sso
LXC_START "sudo yunohost app ssowatconf"
ECHO_FORMAT "Public access forced by a skipped_uris to check.\n" "lyellow" "bold"
fi
# Inform /etc/hosts with the IP of LXC to resolve the domain.
# This is set only here and not before to prevent to help the app's scripts
echo -e "$ip_range.2 $main_domain #package_check\n$ip_range.2 $sub_domain #package_check" | sudo tee --append /etc/hosts > /dev/null
# Try to resolv the domain during 10 seconds maximum.
local i=0
for i in `seq 1 10`; do
curl --location --insecure $check_domain > /dev/null 2>&1
# If curl return 6, it's an error "Could not resolve host"
if [ $? -ne 6 ]; then
# If not, curl is ready to work.
break
fi
echo -n .
sleep 1
done
# curl_error indicate the result of curl test
curl_error=0
# 503 Service Unavailable can would have some time to work.
local http503=0
# yuno_portal equal 1 if the test fall on the portal
yuno_portal=0
# Try to access to the url in 2 times, with a final / and without
i=1; while [ $i -ne 3 ]
do
# First time, try without final /
if [ $i -eq 1 ]
then
# If the last character is /
if [ "${check_path: -1}" = "/" ]
then
# Remove it
local curl_check_path="${check_path:0:${#check_path}-1}"
else
curl_check_path=$check_path
fi
# The next loop will try the second test
i=2
elif [ $i -eq 2 ]
then
# Second time, try with the final /
# If the last character isn't /
if [ "${check_path: -1}" != "/" ]
then
# Add it
curl_check_path="$check_path/"
else
curl_check_path=$check_path
fi
# The next loop will break the while loop
i=3
fi
# Remove the previous curl output
rm -f "$script_dir/url_output"
# Call curl to try to access to the url of the app
curl --location --insecure --silent --show-error --write-out "%{http_code};%{url_effective}\n" $check_domain$curl_check_path --output "$script_dir/url_output" > "$script_dir/curl_print"
# Analyze the result of curl command
if [ $? -ne 0 ]
then
ECHO_FORMAT "Connection error...\n" "red" "bold"
curl_error=1
fi
# Print informations about the connection
ECHO_FORMAT "Test url: $check_domain$curl_check_path\n" "white"
ECHO_FORMAT "Real url: $(cat "$script_dir/curl_print" | cut --delimiter=';' --fields=2)\n" "white"
local http_code=$(cat "$script_dir/curl_print" | cut -d ';' -f1)
ECHO_FORMAT "HTTP code: $http_code\n" "white"
# Analyze the http code
if [ "${http_code:0:1}" = "0" ] || [ "${http_code:0:1}" = "4" ] || [ "${http_code:0:1}" = "5" ]
then
# If the http code is a 0xx 4xx or 5xx, it's an error code.
curl_error=1
# 401 is "Unauthorized", so is a answer of the server. So, it works!
test "${http_code}" = "401" && curl_error=0
# 503 is Service Unavailable, it's a temporary error.
if [ "${http_code}" = "503" ]
then
curl_error=0
ECHO_FORMAT "Service temporarily unavailable\n" "lyellow" "bold"
# 3 successive error are allowed
http503=$(( http503 + 1 ))
if [ $http503 -ge 3 ]; then
# Over 3, it's definitively an error
curl_error=1
else
# Below 3 times, retry.
# Decrease the value of 'i' to retry the same test
i=$(( i - 1 ))
# Wait 1 second to let's some time to the 503 error
sleep 1
# And retry immediately
continue
fi
fi
if [ $curl_error -eq 1 ]; then
ECHO_FORMAT "The HTTP code show an error.\n" "white" "bold" clog
fi
fi
# Analyze the output of curl
if [ -e "$script_dir/url_output" ]
then
# Print the title of the page
local url_title=$(grep "
" "$script_dir/url_output" | cut --delimiter='>' --fields=2 | cut --delimiter='<' --fields=1)
ECHO_FORMAT "Title of the page: $url_title\n" "white"
# Check if the page title is neither the YunoHost portail or default nginx page
if [ "$url_title" = "YunoHost Portal" ]
then
ECHO_FORMAT "The connection attempt fall on the YunoHost portal.\n" "white" "bold" clog
yuno_portal=1
else
yuno_portal=0
if [ "$url_title" = "Welcome to nginx on Debian!" ]
then
# Falling on nginx default page is an error.
curl_error=1
ECHO_FORMAT "The connection attempt fall on nginx default page.\n" "white" "bold" clog
fi
# Print the first 20 lines of the page
ECHO_FORMAT "Extract of the page:\n" "white"
echo -en "\e[37m" # Write in 'light grey'
lynx -dump -force_html "$script_dir/url_output" | head --lines 20 | tee --append "$test_result"
echo -e "\e[0m"
if [ $show_resources -eq 1 ]
then
# Get all the resources for the main page of the app.
local HTTP_return
local moved=0
local ignored=0
while read HTTP_return
do
# Ignore robots.txt and ynhpanel.js. They always redirect to the portal.
if echo "$HTTP_return" | grep --quiet "$check_domain/robots.txt\|$check_domain/ynhpanel.js"; then
ECHO_FORMAT "Ressource ignored:" "white"
ECHO_FORMAT " ${HTTP_return##*http*://}\n"
ignored=1
fi
# If it's the line with the resource to get
if echo "$HTTP_return" | grep --quiet "^--.*-- http"
then
# Get only the resource itself.
local resource=${HTTP_return##*http*://}
# Else, if would be the HTTP return code.
else
# If the return code is different than 200.
if ! echo "$HTTP_return" | grep --quiet "200 OK$"
then
# Skipped the check of ignored ressources.
if [ $ignored -eq 1 ]
then
ignored=0
continue
fi
# Isolate the http return code.
http_code="${HTTP_return##*awaiting response... }"
http_code="${http_code:0:3}"
# If the return code is 301 or 302, let's check the redirection.
if echo "$HTTP_return" | grep --quiet "30[12] Moved"
then
ECHO_FORMAT "Ressource moved:" "white"
ECHO_FORMAT " $resource\n"
moved=1
else
ECHO_FORMAT "Resource unreachable (Code $http_code)" "red" "bold"
ECHO_FORMAT " $resource\n"
# curl_error=1
moved=0
fi
else
if [ $moved -eq 1 ]
then
if echo "$resource" | grep --quiet "/yunohost/sso/"
then
ECHO_FORMAT "The previous resource is redirected to the YunoHost portal\n" "red"
# curl_error=1
fi
fi
moved=0
fi
fi
done <<< "$(cd "$package_path"; LC_ALL=C wget --adjust-extension --page-requisites --no-check-certificate $check_domain$curl_check_path 2>&1 | grep "^--.*-- http\|^HTTP request sent")"
fi
echo ""
fi
fi
done
# Detect the issue alias_traversal, https://github.com/yandex/gixy/blob/master/docs/en/plugins/aliastraversal.md
# Create a file to get for alias_traversal
echo "
alias_traversal test
alias_traversal test
If you see this page, you have failed the test for alias_traversal issue." \
| sudo tee /var/lib/lxc/$lxc_name/rootfs/var/www/html/alias_traversal.html > /dev/null
curl --location --insecure --silent $check_domain$check_path../html/alias_traversal.html \
| grep "title" | grep --quiet "alias_traversal test" \
&& ECHO_FORMAT "Issue alias_traversal detected ! Please see here https://github.com/YunoHost/example_ynh/pull/45 to fix that.\n" "red" "bold" && RESULT_alias_traversal=1
# Remove the entries in /etc/hosts for the test domain
sudo sed --in-place '/#package_check/d' /etc/hosts
else
# If use_curl is set to 0, the url will not tried
ECHO_FORMAT "Connexion attempt aborted.\n" "white"
curl_error=0
yuno_portal=0
fi
}
#=================================================
# Generic functions for unit tests
#=================================================
unit_test_title () {
# Print a title for the test
# $1 = Name of the test
ECHO_FORMAT "\n\n>> $1 [Test $cur_test/$all_test]\n" "white" "bold" clog
# Increment the value of the current test
cur_test=$((cur_test+1))
}
check_manifest_key () {
# Check if a manifest key is set
# $1 = manifest key
if [ -z "${1}_arg" ]
then
ECHO_FORMAT "Unable to find a manifest key for '${1,,}' in the check_process file. Impossible to perform this test\n" "red" clog
return 1
fi
}
replace_manifest_key () {
# Replace a generic manifest key by another
# $1 = Manifest key
# $2 = Replacement value
# Build the variable name by concatenate $1 and _arg
local manifest_key=$(eval echo \$${1}_arg)
if [ -n "$manifest_key" ]
then
manifest_args_mod=$(echo $manifest_args_mod | sed "s@$manifest_key=[^&]*\&@${manifest_key}=${2}\&@")
fi
}
check_success () {
ECHO_FORMAT "--- SUCCESS ---\n" "lgreen" "bold"
}
check_failed () {
ECHO_FORMAT "--- FAIL ---\n" "red" "bold"
}
check_test_result () {
# Check the result and print SUCCESS or FAIL
if [ $yunohost_result -eq 0 ] && [ $curl_error -eq 0 ] && [ $yuno_portal -eq 0 ]
then
check_success
return 0
else
check_failed
return 1
fi
}
check_test_result_remove () {
# Check the result of a remove and print SUCCESS or FAIL
if [ $yunohost_remove -eq 0 ]
then
check_success
return 0
else
check_failed
return 1
fi
}
is_install_failed () {
# Check if an install have previously work
# If the test for install in sub dir isn't desactivated
sub_dir_install=0
if [ $setup_sub_dir -ne 0 ]
then
# If a test succeed or if force_install_ok is set
# Or if $setup_sub_dir isn't set in the check_process
if [ $RESULT_check_sub_dir -eq 1 ] || [ $force_install_ok -eq 1 ] || [ $setup_sub_dir -eq -1 ]
then
# Validate installation in sub dir.
sub_dir_install=1
fi
else
sub_dir_install=0
fi
# If the test for install on root isn't desactivated
root_install=0
if [ $setup_root -ne 0 ] || [ $setup_nourl -eq 1 ]
then
# If a test succeed or if force_install_ok is set
# Or if $setup_root isn't set in the check_process
if [ $RESULT_check_root -eq 1 ] || [ $force_install_ok -eq 1 ] || [ $setup_root -eq -1 ]
then
# Validate installation on root.
root_install=1
fi
else
root_install=0
fi
if [ $sub_dir_install -eq 0 ] && [ $root_install -eq 0 ]
then
ECHO_FORMAT "All installs have failed, impossible to perform this test...\n" "red" clog
return 1
fi
}
#=================================================
# Unit tests
#=================================================
CHECK_SETUP () {
# Try to install in a sub path, on root or without url access
# $1 = install type
local install_type=$1
if [ "$install_type" = "subdir" ]; then
unit_test_title "Installation in a sub path..."
elif [ "$install_type" = "root" ]; then
unit_test_title "Installation on the root..."
else
unit_test_title "Installation without url access..."
# Disable the curl test
use_curl=0
fi
# Check if the needed manifest key are set or abort the test
if [ "$install_type" != "no_url" ]; then
check_manifest_key "domain" || return
check_manifest_key "path" || return
fi
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
check_domain=$sub_domain
replace_manifest_key "domain" "$check_domain"
if [ "$install_type" = "subdir" ]; then
local check_path=$test_path
elif [ "$install_type" = "root" ]; then
local check_path=/
fi
replace_manifest_key "path" "$check_path"
replace_manifest_key "user" "$test_user"
replace_manifest_key "public" "$public_public_arg"
# Install the application in a LXC container
SETUP_APP
check_false_positive_error || return $?
# Try to access the app by its url
CHECK_URL
# Check the result and print SUCCESS or FAIL
if check_test_result
then # Success
RESULT_global_setup=1 # Installation succeed
local check_result_setup=1 # Installation succeed
else # Fail
# The global success for a installation can't be failed if another installation succeed
if [ $RESULT_global_setup -ne 1 ]; then
RESULT_global_setup=-1 # Installation failed
fi
local check_result_setup=-1 # Installation failed
fi
# Create a snapshot for this installation, to be able to reuse it instead of a new installation.
# But only if this installation has worked fine
if [ $check_result_setup -eq 1 ]; then
if [ "$check_path" = "/" ]
then
# Check if a snapshot already exist for a root install
if [ -z "$root_snapshot" ]
then
ECHO_FORMAT "Create a snapshot for root installation.\n" "white" clog
create_temp_backup 2
root_snapshot=snap2
fi
else
# Check if a snapshot already exist for a subpath (or no_url) install
if [ -z "$subpath_snapshot" ]
then
# Then create a snapshot
ECHO_FORMAT "Create a snapshot for sub path installation.\n" "white" clog
create_temp_backup 1
subpath_snapshot=snap1
fi
fi
fi
# Remove the application
REMOVE_APP
# Analyse the log to extract "warning" and "error" lines
LOG_EXTRACTOR
check_false_positive_error || return $?
# Check the result and print SUCCESS or FAIL
if check_test_result_remove
then # Success
local check_result_remove=1 # Remove in sub path succeed
RESULT_global_remove=1 # Remove succeed
else # Fail
# The global success for a deletion can't be failed if another remove succeed
if [ $RESULT_global_remove -ne 1 ]; then
RESULT_global_remove=-1 # Remove failed
fi
local check_result_remove=-1 # Remove in sub path failed
fi
# Reinstall the application after the removing
# Try to resintall only if the first install is a success.
if [ $check_result_setup -eq 1 ]
then
ECHO_FORMAT "\nReinstall the application after a removing.\n" "white" "bold" clog
SETUP_APP
check_false_positive_error || return $?
# Try to access the app by its url
CHECK_URL
# Check the result and print SUCCESS or FAIL
if check_test_result
then # Success
local check_result_setup=1 # Installation succeed
else # Fail
local check_result_setup=-1 # Installation failed
fi
fi
# Fill the correct variable depend on the type of test
if [ "$install_type" = "subdir" ]
then
RESULT_check_sub_dir=$check_result_setup
RESULT_check_remove_sub_dir=$check_result_remove
else # root and no_url
RESULT_check_root=$check_result_setup
RESULT_check_remove_root=$check_result_remove
fi
# Make a break if auto_remove is set
break_before_continue
}
CHECK_UPGRADE () {
# Try the upgrade script
# Do an upgrade test for each commit in the upgrade list
while read <&4 commit
do
if [ "$commit" == "current" ]
then
unit_test_title "Upgrade from the same version..."
else
# Get the specific section for this upgrade from the check_process
extract_section "^; commit=$commit" "^;" "$check_process"
# Get the name for this upgrade.
upgrade_name=$(grep "^name=" "$partial_check_process" | cut -d'=' -f2)
# Or use the commit if there's no name.
if [ -z "$upgrade_name" ]; then
unit_test_title "Upgrade from the commit $commit..."
else
unit_test_title "Upgrade from $upgrade_name..."
fi
fi
# Check if an install have previously work
# Abort if none install worked
is_install_failed || return
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
check_domain=$sub_domain
replace_manifest_key "domain" "$check_domain"
# Use a path according to previous succeeded installs
if [ $sub_dir_install -eq 1 ]; then
local check_path=$test_path
else
local check_path=/
fi
replace_manifest_key "path" "$check_path"
replace_manifest_key "user" "$test_user"
replace_manifest_key "public" "$public_public_arg"
# Install the application in a LXC container
ECHO_FORMAT "\nPreliminary install...\n" "white" "bold" clog
if [ "$commit" == "current" ]
then
# If no commit is specified, use the current version.
STANDARD_SETUP_APP
check_false_positive_error || return $?
else
# Otherwise, use a specific commit
# Backup the modified arguments
update_manifest_args="$manifest_args_mod"
# Get the arguments of the manifest for this upgrade.
manifest_args_mod="$(grep "^manifest_arg=" "$partial_check_process" | cut -d'=' -f2-)"
if [ -z "$manifest_args_mod" ]; then
# If there's no specific arguments, use the previous one.
manifest_args_mod="$update_manifest_args"
else
# Otherwise, keep the new arguments, and replace the variables.
manifest_args_mod="${manifest_args_mod//DOMAIN/$check_domain}"
manifest_args_mod="${manifest_args_mod//PATH/$check_path}"
manifest_args_mod="${manifest_args_mod//USER/$test_user}"
fi
# Make a backup of the directory
sudo cp -a "$package_path" "${package_path}_back"
# Change to the specified commit
(cd "$package_path"; git checkout --force --quiet "$commit")
# Install the application
SETUP_APP
check_false_positive_error || return $?
# Then replace the backup
sudo rm -r "$package_path"
sudo mv "${package_path}_back" "$package_path"
# And restore the arguments for the manifest
manifest_args_mod="$update_manifest_args"
fi
# Check if the install had work
if [ $yunohost_result -ne 0 ]
then
ECHO_FORMAT "\nInstallation failed...\n" "red" "bold"
ECHO_FORMAT "\nUpgrade test ignored...\n" "red" "bold"
else
ECHO_FORMAT "\nUpgrade...\n" "white" "bold" clog
# Upgrade the application in a LXC container
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app upgrade $ynh_app_id -f \"$package_dir\""
# yunohost_result gets the return code of the upgrade
yunohost_result=$?
# Print the result of the upgrade command
if [ $yunohost_result -eq 0 ]; then
ECHO_FORMAT "Upgrade successful. ($yunohost_result)\n" "white" clog
else
ECHO_FORMAT "Upgrade failed. ($yunohost_result)\n" "white" clog
fi
# Check all the witness files, to verify if them still here
check_witness_files
# Analyse the log to extract "warning" and "error" lines
LOG_EXTRACTOR
check_false_positive_error || return $?
# Try to access the app by its url
CHECK_URL
# Check the result and print SUCCESS or FAIL
if check_test_result
then # Success
# The global success for an upgrade can't be a success if another upgrade failed
if [ $RESULT_check_upgrade -ne -1 ]; then
RESULT_check_upgrade=1 # Upgrade succeed
fi
else # Fail
RESULT_check_upgrade=-1 # Upgrade failed
fi
# Remove the application
REMOVE_APP
fi
# Uses the default snapshot
current_snapshot=snap0
# Stop and restore the LXC container
LXC_STOP
done 4< "$script_dir/upgrade_list"
}
CHECK_PUBLIC_PRIVATE () {
# Try to install in public or private mode
# $1 = install type
local install_type=$1
if [ "$install_type" = "private" ]; then
unit_test_title "Installation in private mode..."
else [ "$install_type" = "public" ]
unit_test_title "Installation in public mode..."
fi
# Check if the needed manifest key are set or abort the test
check_manifest_key "public" || return
check_manifest_key "public_public" || return
check_manifest_key "public_private" || return
# Check if an install have previously work
is_install_failed || return
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
check_domain=$sub_domain
replace_manifest_key "domain" "$check_domain"
replace_manifest_key "user" "$test_user"
# Set public or private according to type of test requested
if [ "$install_type" = "private" ]; then
replace_manifest_key "public" "$public_private_arg"
elif [ "$install_type" = "public" ]; then
replace_manifest_key "public" "$public_public_arg"
fi
# Initialize the value
local check_result_public_private=0
# Try in 2 times, first in root and second in sub path.
local i=0
for i in 0 1
do
# First, try with a root install
if [ $i -eq 0 ]
then
# Check if root installation worked
if [ $root_install -eq 1 ]
then
# Replace manifest key for path
local check_path=/
replace_manifest_key "path" "$check_path"
else
# Jump to the second path if this check cannot be do
ECHO_FORMAT "Root install failed, impossible to perform this test...\n" "lyellow" clog
continue
fi
# Second, try with a sub path install
elif [ $i -eq 1 ]
then
# Check if sub path installation worked, or if force_install_ok is setted.
if [ $sub_dir_install -eq 1 ]
then
# Replace manifest key for path
local check_path=$test_path
replace_manifest_key "path" "$check_path"
else
# Jump to the second path if this check cannot be do
ECHO_FORMAT "Sub path install failed, impossible to perform this test...\n" "lyellow" clog
return
fi
fi
# Install the application in a LXC container
SETUP_APP
check_false_positive_error || return $?
# Try to access the app by its url
CHECK_URL
# Change the result according to the results of the curl test
if [ "$install_type" = "private" ]
then
# In private mode, if curl doesn't fell on the ynh portal, it's a fail.
if [ $yuno_portal -eq 0 ]; then
ECHO_FORMAT "App is not private: it should redirect to the Yunohost portal, but is publicly accessible instead\n" "lyellow" clog
yunohost_result=1
fi
elif [ "$install_type" = "public" ]
then
# In public mode, if curl fell on the ynh portal, it's a fail.
if [ $yuno_portal -eq 1 ]; then
ECHO_FORMAT "App page is not public: it should be publicly accessible, but redirects to the Yunohost portal instead\n" "lyellow" clog
yunohost_result=1
fi
fi
# Check the result and print SUCCESS or FAIL
if [ $yunohost_result -eq 0 ] && [ $curl_error -eq 0 ]
then # Success
check_success
# The global success for public/private mode can't be a success if another installation failed
if [ $check_result_public_private -ne -1 ]; then
check_result_public_private=1 # Installation succeed
fi
else # Fail
check_failed
check_result_public_private=-1 # Installation failed
fi
# Fill the correct variable depend on the type of test
if [ "$install_type" = "private" ]
then
RESULT_check_private=$check_result_public_private
else # public
RESULT_check_public=$check_result_public_private
fi
# Make a break if auto_remove is set
break_before_continue
# Stop and restore the LXC container
LXC_STOP
done
}
CHECK_MULTI_INSTANCE () {
# Try multi-instance installations
unit_test_title "Multi-instance installations..."
# Check if an install have previously work
is_install_failed || return
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
if [ $sub_dir_install -eq 1 ]; then
local check_path=$test_path
else
local check_path=/
fi
replace_manifest_key "path" "$check_path"
replace_manifest_key "user" "$test_user"
replace_manifest_key "public" "$public_public_arg"
# Install 2 times the same app
local i=0
for i in 1 2
do
# First installation
if [ $i -eq 1 ]
then
check_domain=$main_domain
ECHO_FORMAT "First installation: path=$check_domain$check_path\n" clog
# Second installation
elif [ $i -eq 2 ]
then
check_domain=$sub_domain
ECHO_FORMAT "Second installation: path=$check_domain$check_path\n" clog
fi
# Replace path and domain manifest keys for the test
replace_manifest_key "domain" "$check_domain"
# Install the application in a LXC container
SETUP_APP
check_false_positive_error || return $?
# Store the result in the correct variable
# First installation
if [ $i -eq 1 ]
then
local multi_yunohost_result_1=$yunohost_result
local ynh_app_id_1=$ynh_app_id
# Second installation
elif [ $i -eq 2 ]
then
local multi_yunohost_result_2=$yunohost_result
local ynh_app_id_2=$ynh_app_id
fi
done
# Try to access to the 2 apps by theirs url
for i in 1 2
do
# First app
if [ $i -eq 1 ]
then
check_domain=$main_domain
ynh_app_id=$ynh_app_id_1
# Second app
elif [ $i -eq 2 ]
then
check_domain=$sub_domain
ynh_app_id=$ynh_app_id_2
fi
# Try to access the app by its url
CHECK_URL
# Check the result of curl test
if [ $curl_error -ne 0 ] || [ $yuno_portal -ne 0 ]
then
# The test failed if curl fell on ynh portal or had an error.
# First app
if [ $i -eq 1 ]
then
multi_yunohost_result_1=1
# Second app
elif [ $i -eq 2 ]
then
multi_yunohost_result_2=1
fi
fi
done
# Check the result and print SUCCESS or FAIL
# Succeed if the 2 installations work;
if [ $multi_yunohost_result_1 -eq 0 ] && [ $multi_yunohost_result_2 -eq 0 ]
then # Success
check_success
RESULT_check_multi_instance=1
else # Fail
check_failed
RESULT_check_multi_instance=-1
fi
# Make a break if auto_remove is set
break_before_continue
}
CHECK_COMMON_ERROR () {
# Try to install with specific complications
# $1 = install type
local install_type=$1
if [ "$install_type" = "incorrect_path" ]; then
unit_test_title "Malformed path..."
# Check if the needed manifest key are set or abort the test
check_manifest_key "path" || return
else [ "$install_type" = "port_already_use" ]
unit_test_title "Port already used..."
# Check if the needed manifest key are set or abort the test
check_manifest_key "port" || return
fi
# Check if an install have previously work
is_install_failed || return
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
check_domain=$sub_domain
replace_manifest_key "domain" "$check_domain"
replace_manifest_key "user" "$test_user"
replace_manifest_key "public" "$public_public_arg"
# Replace path manifest key for the test
if [ "$install_type" = "incorrect_path" ]; then
# Change the path from /path to path/
local wrong_path=${test_path#/}/
# Use this wrong path only for the arguments that will give to yunohost for installation.
replace_manifest_key "path" "$wrong_path"
local check_path=$test_path
else [ "$install_type" = "port_already_use" ]
# Use a path according to previous succeeded installs
if [ $sub_dir_install -eq 1 ]; then
local check_path=$test_path
else
local check_path=/
fi
replace_manifest_key "path" "$check_path"
fi
# Open the specified port to force the script to find another
if [ "$install_type" = "port_already_use" ]
then
# If the first character is a #, that means it this port number is not in the manifest
if [ "${port_arg:0:1}" = "#" ]
then
# Retrieve the port number
local check_port="${port_arg:1}"
# Else, the port number is in the manifest. So the port number is set at a fixed value.
else
local check_port=6660
# Replace port manifest key for the test
replace_manifest_key "port" "$check_port"
fi
# Build a service with netcat for use this port before the app.
echo -e "[Service]\nExecStart=/bin/netcat -l -k -p $check_port\n
[Install]\nWantedBy=multi-user.target" | \
sudo tee "/var/lib/lxc/$lxc_name/rootfs/etc/systemd/system/netcat.service" \
> /dev/null
# Then start this service to block this port.
LXC_START "sudo systemctl enable netcat & sudo systemctl start netcat"
fi
# Install the application in a LXC container
SETUP_APP
check_false_positive_error || return $?
# Try to access the app by its url
CHECK_URL
# Check the result and print SUCCESS or FAIL
if check_test_result
then # Success
local check_result_setup=1
else # Fail
local check_result_setup=-1
fi
# Fill the correct variable depend on the type of test
if [ "$install_type" = "incorrect_path" ]
then
RESULT_check_path=$check_result_setup
elif [ "$install_type" = "port_already_use" ]; then
RESULT_check_port=$check_result_setup
fi
# Make a break if auto_remove is set
break_before_continue
}
CHECK_BACKUP_RESTORE () {
# Try to backup then restore the app
unit_test_title "Backup/Restore..."
# Check if an install have previously work
is_install_failed || return
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
check_domain=$sub_domain
replace_manifest_key "domain" "$check_domain"
replace_manifest_key "user" "$test_user"
replace_manifest_key "public" "$public_public_arg"
# Try in 2 times, first in root and second in sub path.
local i=0
for i in 0 1
do
# First, try with a root install
if [ $i -eq 0 ]
then
# Check if root installation worked, or if force_install_ok is setted.
if [ $root_install -eq 1 ]
then
# Replace manifest key for path
local check_path=/
replace_manifest_key "path" "$check_path"
ECHO_FORMAT "\nPreliminary installation on the root...\n" "white" "bold" clog
else
# Jump to the second path if this check cannot be do
ECHO_FORMAT "Root install failed, impossible to perform this test...\n" "lyellow" clog
continue
fi
# Second, try with a sub path install
elif [ $i -eq 1 ]
then
# Check if sub path installation worked, or if force_install_ok is setted.
if [ $sub_dir_install -eq 1 ]
then
# Replace manifest key for path
local check_path=$test_path
replace_manifest_key "path" "$check_path"
ECHO_FORMAT "\nPreliminary installation in a sub path...\n" "white" "bold" clog
else
# Jump to the second path if this check cannot be do
ECHO_FORMAT "Sub path install failed, impossible to perform this test...\n" "lyellow" clog
return
fi
fi
# Install the application in a LXC container
STANDARD_SETUP_APP
check_false_positive_error || return $?
# Remove the previous residual backups
sudo rm -rf /var/lib/lxc/$lxc_name/rootfs/home/yunohost.backup/archives
sudo rm -rf /var/lib/lxcsnaps/$lxc_name/$current_snapshot/rootfs/home/yunohost.backup/archives
# BACKUP
# Made a backup if the installation succeed
if [ $yunohost_result -ne 0 ]
then
ECHO_FORMAT "\nInstallation failed...\n" "red" "bold"
else
ECHO_FORMAT "\nBackup of the application...\n" "white" "bold" clog
# Made a backup of the application
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug backup create -n Backup_test --apps $ynh_app_id --system $backup_hooks"
# yunohost_result gets the return code of the backup
yunohost_result=$?
# Print the result of the backup command
if [ $yunohost_result -eq 0 ]; then
ECHO_FORMAT "Backup successful. ($yunohost_result)\n" "white" clog
else
ECHO_FORMAT "Backup failed. ($yunohost_result)\n" "white" clog
fi
# Check all the witness files, to verify if them still here
check_witness_files
# Analyse the log to extract "warning" and "error" lines
LOG_EXTRACTOR
check_false_positive_error || return $?
fi
# Check the result and print SUCCESS or FAIL
if [ $yunohost_result -eq 0 ]
then # Success
check_success
# The global success for a backup can't be a success if another backup failed
if [ $RESULT_check_backup -ne -1 ]; then
RESULT_check_backup=1 # Backup succeed
fi
else # Fail
check_failed
RESULT_check_backup=-1 # Backup failed
fi
# Grab the backup archive into the LXC container, and keep a copy
sudo cp -a /var/lib/lxc/$lxc_name/rootfs/home/yunohost.backup/archives ./
# RESTORE
# Try the restore process in 2 times, first after removing the app, second after a restore of the container.
local j=0
for j in 0 1
do
# First, simply remove the application
if [ $j -eq 0 ]
then
# Remove the application
REMOVE_APP
ECHO_FORMAT "\nRestore after removing the application...\n" "white" "bold" clog
# Second, restore the whole container to remove completely the application
elif [ $j -eq 1 ]
then
# Uses the default snapshot
current_snapshot=snap0
# Remove the previous residual backups
sudo rm -rf /var/lib/lxcsnaps/$lxc_name/$current_snapshot/rootfs/home/yunohost.backup/archives
# Place the copy of the backup archive in the container.
sudo mv -f ./archives /var/lib/lxcsnaps/$lxc_name/$current_snapshot/rootfs/home/yunohost.backup/
# Stop and restore the LXC container
LXC_STOP
ECHO_FORMAT "\nRestore on a clean YunoHost system...\n" "white" "bold" clog
fi
# Restore the application from the previous backup
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug backup restore Backup_test --force --apps $ynh_app_id"
# yunohost_result gets the return code of the restore
yunohost_result=$?
# Print the result of the backup command
if [ $yunohost_result -eq 0 ]; then
ECHO_FORMAT "Restore successful. ($yunohost_result)\n" "white" clog
else
ECHO_FORMAT "Restore failed. ($yunohost_result)\n" "white" clog
fi
# Check all the witness files, to verify if them still here
check_witness_files
# Analyse the log to extract "warning" and "error" lines
LOG_EXTRACTOR
check_false_positive_error || return $?
# Try to access the app by its url
CHECK_URL
# Check the result and print SUCCESS or FAIL
if check_test_result
then # Success
# The global success for a restore can't be a success if another restore failed
if [ $RESULT_check_restore -ne -1 ]; then
RESULT_check_restore=1 # Restore succeed
fi
else # Fail
RESULT_check_restore=-1 # Restore failed
fi
# Make a break if auto_remove is set
break_before_continue
# Stop and restore the LXC container
LXC_STOP
done
done
}
CHECK_CHANGE_URL () {
# Try the change_url script
unit_test_title "Change URL..."
# Check if the needed manifest key are set or abort the test
check_manifest_key "domain" || return
# Check if an install have previously work
is_install_failed || return
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
check_domain=$sub_domain
replace_manifest_key "domain" "$check_domain"
replace_manifest_key "user" "$test_user"
replace_manifest_key "public" "$public_public_arg"
# Try in 6 times !
# Without modify the domain, root to path, path to path and path to root.
# And then, same with a domain change
local i=0
for i in `seq 1 7`
do
if [ $i -eq 1 ]; then
# Same domain, root to path
check_path=/
local new_path=$test_path
local new_domain=$sub_domain
elif [ $i -eq 2 ]; then
# Same domain, path to path
check_path=$test_path
local new_path=${test_path}_2
local new_domain=$sub_domain
elif [ $i -eq 3 ]; then
# Same domain, path to root
check_path=$test_path
local new_path=/
local new_domain=$sub_domain
elif [ $i -eq 4 ]; then
# Other domain, root to path
check_path=/
local new_path=$test_path
local new_domain=$main_domain
elif [ $i -eq 5 ]; then
# Other domain, path to path
check_path=$test_path
local new_path=${test_path}_2
local new_domain=$main_domain
elif [ $i -eq 6 ]; then
# Other domain, path to root
check_path=$test_path
local new_path=/
local new_domain=$main_domain
elif [ $i -eq 7 ]; then
# Other domain, root to root
check_path=/
local new_path=/
local new_domain=$main_domain
fi
replace_manifest_key "path" "$check_path"
# Ignore the test if it tries to move to the same address
if [ "$check_path" == "$new_path" ] && [ "$new_domain" == "$sub_domain" ]; then
continue
fi
# Check if root or subpath installation worked, or if force_install_ok is setted.
# Try with a sub path install
if [ "$check_path" = "/" ]
then
if [ $root_install -eq 0 ]
then
# Jump this test
ECHO_FORMAT "Root install failed, impossible to perform this test...\n" "lyellow" clog
continue
elif [ "$new_path" != "/" ] && [ $sub_dir_install -eq 0 ]
then
# Jump this test
ECHO_FORMAT "Sub path install failed, impossible to perform this test...\n" "lyellow" clog
continue
fi
# And with a sub path install
else
if [ $sub_dir_install -eq 0 ]
then
# Jump this test
ECHO_FORMAT "Sub path install failed, impossible to perform this test...\n" "lyellow" clog
continue
elif [ "$new_path" = "/" ] && [ $root_install -eq 0 ]
then
# Jump this test
ECHO_FORMAT "Root install failed, impossible to perform this test...\n" "lyellow" clog
continue
fi
fi
# Install the application in a LXC container
ECHO_FORMAT "\nPreliminary install...\n" "white" "bold" clog
STANDARD_SETUP_APP
check_false_positive_error || return $?
# Check if the install had work
if [ $yunohost_result -ne 0 ]
then
ECHO_FORMAT "Installation failed...\n" "red" "bold"
else
ECHO_FORMAT "Change the url from $sub_domain$check_path to $new_domain$new_path...\n" "white" "bold" clog
# Change the url
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app change-url $ynh_app_id -d \"$new_domain\" -p \"$new_path\""
# yunohost_result gets the return code of the change-url script
yunohost_result=$?
# Print the result of the change_url command
if [ $yunohost_result -eq 0 ]; then
ECHO_FORMAT "Change_url script successful. ($yunohost_result)\n" "white" clog
else
ECHO_FORMAT "Change_url script failed. ($yunohost_result)\n" "white" clog
fi
# Check all the witness files, to verify if them still here
check_witness_files
# Analyse the log to extract "warning" and "error" lines
LOG_EXTRACTOR
check_false_positive_error || return $?
# Try to access the app by its url
check_path=$new_path
check_domain=$new_domain
CHECK_URL
fi
# Check the result and print SUCCESS or FAIL
if check_test_result
then # Success
# The global success for a change_url can't be a success if another change_url failed
if [ $RESULT_change_url -ne -1 ]; then
RESULT_change_url=1 # Change_url succeed
fi
else # Fail
RESULT_change_url=-1 # Change_url failed
fi
# Make a break if auto_remove is set
break_before_continue
# Uses the default snapshot
current_snapshot=snap0
# Stop and restore the LXC container
LXC_STOP
done
}
# Define a function to split a file in multiple parts. Used for actions and config-panel toml
splitterAA()
{
local bound="$1"
local file="$2"
# If $2 is a real file
if [ -e "$file" ]
then
# Replace name of the file by its content
file="$(cat "$file")"
fi
local file_lenght=$(echo "$file" | wc --lines | awk '{print $1}')
bounds=($(echo "$file" | grep --line-number --extended-regexp "$bound" | cut -d':' -f1))
# Go for each line number (boundary) into the array
for line_number in $(seq 0 $(( ${#bounds[@]} -1 )))
do
# The first bound is the next line number in the array
# That the low bound on which we cut
first_bound=$(( ${bounds[$line_number+1]} - 1 ))
# If there's no next cell in the array, we got -1, in such case, use the lenght of the file.
# We cut at the end of the file
test $first_bound -lt 0 && first_bound=$file_lenght
# The second bound is the current line number in the array minus the next one.
# The the upper bound in the file.
second_bound=$(( ${bounds[$line_number]} - $first_bound - 1 ))
# Cut the file a first time from the beginning to the first bound
# And a second time from the end, back to the second bound.
parts[line_number]="$(echo "$file" | head --lines=$first_bound \
| tail --lines=$second_bound)"
done
}
ACTIONS_CONFIG_PANEL () {
# Try the actions and config-panel features
test_type=$1
if [ "$test_type" == "actions" ]
then
unit_test_title "Actions..."
toml_file="$package_path/actions.toml"
if [ ! -e "$toml_file" ]
then
ECHO_FORMAT "\nNo actions.toml found !\n" "red" "bold"
return 1
fi
elif [ "$test_type" == "config_panel" ]
then
unit_test_title "Config-panel..."
toml_file="$package_path/config_panel.toml"
if [ ! -e "$toml_file" ]
then
ECHO_FORMAT "\nNo config_panel.toml found !\n" "red" "bold"
return 1
fi
fi
# Check if the needed manifest key are set or abort the test
check_manifest_key "domain" || return
# Check if an install have previously work
is_install_failed || return
# Copy original arguments
local manifest_args_mod="$manifest_arguments"
# Replace manifest key for the test
check_domain=$sub_domain
replace_manifest_key "domain" "$check_domain"
replace_manifest_key "user" "$test_user"
replace_manifest_key "public" "$public_public_arg"
# Use a path according to previous succeeded installs
if [ $sub_dir_install -eq 1 ]; then
local check_path=$test_path
else
local check_path=/
fi
replace_manifest_key "path" "$check_path"
# Install the application in a LXC container
ECHO_FORMAT "\nPreliminary install...\n" "white" "bold" clog
STANDARD_SETUP_APP
check_false_positive_error || return $?
validate_action_config_panel()
{
# yunohost_result gets the return code of the command
yunohost_result=$?
local message="$1"
# Print the result of the command
if [ $yunohost_result -eq 0 ]; then
ECHO_FORMAT "$message succeed. ($yunohost_result)\n" "white" clog
else
ECHO_FORMAT "$message failed. ($yunohost_result)\n" "white" clog
fi
# Check all the witness files, to verify if they're still there
check_witness_files
# Analyse the log to extract "warning" and "error" lines
LOG_EXTRACTOR
check_false_positive_error || return $?
# Check the result and print SUCCESS or FAIL
if check_test_result
then # Success
# The global success for a actions can't be a success if another iteration failed
if [ $RESULT_action_config_panel -ne -1 ]; then
RESULT_action_config_panel=1 # Actions succeed
fi
else # Fail
RESULT_action_config_panel=-1 # Actions failed
fi
# Make a break if auto_remove is set
break_before_continue
}
# List first, then execute
local i=0
for i in `seq 1 2`
do
# Do a test if the installation succeed
if [ $yunohost_result -ne 0 ]
then
ECHO_FORMAT "\nThe previous test has failed...\n" "red" "bold"
else
if [ $i -eq 1 ]
then
if [ "$test_type" == "actions" ]
then
ECHO_FORMAT "\n> List the available actions...\n" "white" "bold" clog
# List the actions
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app action list $ynh_app_id"
validate_action_config_panel "yunohost app action list"
elif [ "$test_type" == "config_panel" ]
then
ECHO_FORMAT "\n> Show the config panel...\n" "white" "bold" clog
# Show the config-panel
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app config show-panel $ynh_app_id"
validate_action_config_panel "yunohost app config show-panel"
fi
elif [ $i -eq 2 ]
then
local parts
if [ "$test_type" == "actions" ]
then
ECHO_FORMAT "\n> Execute the actions...\n" "white" "bold" clog
# Split the actions.toml file to separate each actions
splitterAA "^[[:blank:]]*\[[^.]*\]" "$toml_file"
elif [ "$test_type" == "config_panel" ]
then
ECHO_FORMAT "\n> Apply configurations...\n" "white" "bold" clog
# Split the config_panel.toml file to separate each configurations
splitterAA "^[[:blank:]]*\[.*\]" "$toml_file"
fi
# Read each part, each action, one by one
for part in $(seq 0 $(( ${#parts[@]} -1 )))
do
local action_config_argument_name=""
local action_config_argument_type=""
local action_config_argument_default=""
local actions_config_arguments_specifics=""
local nb_actions_config_arguments_specifics=1
# Ignore part of the config_panel which are only titles
if [ "$test_type" == "config_panel" ]
then
# A real config_panel part should have a `ask = ` line. Ignore the part if not.
if ! echo "${parts[$part]}" | grep --quiet --extended-regexp "^[[:blank:]]*ask ="
then
continue
fi
# Get the name of the config. ask = "Config ?"
local action_config_name="$(echo "${parts[$part]}" | grep "ask *= *" | sed 's/^.* = \"\(.*\)\"/\1/')"
# Get the config argument name "YNH_CONFIG_part1_part2.part3.partx"
local action_config_argument_name="$(echo "${parts[$part]}" | grep "^[[:blank:]]*\[.*\]$")"
# Remove []
action_config_argument_name="${action_config_argument_name//[\[\]]/}"
# And remove spaces
action_config_argument_name="${action_config_argument_name// /}"
elif [ "$test_type" == "actions" ]
then
# Get the name of the action. name = "Name of the action"
local action_config_name="$(echo "${parts[$part]}" | grep "name" | sed 's/^.* = \"\(.*\)\"/\1/')"
# Get the action. [action]
local action_config_action="$(echo "${parts[$part]}" | grep "^\[.*\]$" | sed 's/\[\(.*\)\]/\1/')"
fi
# Check if there's any [action.arguments]
# config_panel always have arguments.
if echo "${parts[$part]}" | grep --quiet "$action_config_action\.arguments" || [ "$test_type" == "config_panel" ]
then local action_config_has_arguments=1
else local action_config_has_arguments=0
fi
# If there's arguments for this action.
if [ $action_config_has_arguments -eq 1 ]
then
if [ "$test_type" == "actions" ]
then
# Get the argument [action.arguments.name_of_the_argument]
action_config_argument_name="$(echo "${parts[$part]}" | grep "$action_config_action\.arguments\." | sed 's/.*\.\(.*\)]/\1/')"
fi
# Get the type of the argument. type = "type"
action_config_argument_type="$(echo "${parts[$part]}" | grep "type" | sed 's/^.* = \"\(.*\)\"/\1/')"
# Get the default value of this argument. default = true
action_config_argument_default="$(echo "${parts[$part]}" | grep "default" | sed 's/^.* = \(.*\)/\1/')"
# Do not use true or false, use 1/0 instead
if [ "$action_config_argument_default" == "true" ] && [ "$action_config_argument_type" == "boolean" ]; then
action_config_argument_default=1
elif [ "$action_config_argument_default" == "false" ] && [ "$action_config_argument_type" == "boolean" ]; then
action_config_argument_default=0
fi
if [ "$test_type" == "config_panel" ]
then
local check_process_arguments="$config_panel_arguments"
elif [ "$test_type" == "actions" ]
then
local check_process_arguments="$actions_arguments"
fi
# Look for arguments into the check_process
if echo "$check_process_arguments" | grep --quiet "$action_config_argument_name"
then
# If there's arguments for this actions into the check_process
# Isolate the values
actions_config_arguments_specifics="$(echo "$check_process_arguments" | sed "s/.*$action_config_argument_name=\(.*\)/\1/")"
# And remove values of the following action
actions_config_arguments_specifics="${actions_config_arguments_specifics%%\:*}"
nb_actions_config_arguments_specifics=$(( $(echo "$actions_config_arguments_specifics" | tr --complement --delete "|" | wc --chars) + 1 ))
fi
if [ "$test_type" == "config_panel" ]
then
# Finish to format the name
# Remove . by _
action_config_argument_name="${action_config_argument_name//./_}"
# Move all characters to uppercase
action_config_argument_name="${action_config_argument_name^^}"
# Add YNH_CONFIG_
action_config_argument_name="YNH_CONFIG_$action_config_argument_name"
fi
fi
# Loop on the number of values into the check_process.
# Or loop once for the default value
for j in `seq 1 $nb_actions_config_arguments_specifics`
do
local action_config_argument_built=""
if [ $action_config_has_arguments -eq 1 ]
then
# If there's values into the check_process
if [ -n "$actions_config_arguments_specifics" ]
then
# Build the argument from a value from the check_process
local action_config_actual_argument="$(echo "$actions_config_arguments_specifics" | cut -d'|' -f $j)"
action_config_argument_built="--args $action_config_argument_name=\"$action_config_actual_argument\""
elif [ -n "$action_config_argument_default" ]
then
# Build the argument from the default value
local action_config_actual_argument="$action_config_argument_default"
action_config_argument_built="--args $action_config_argument_name=\"$action_config_actual_argument\""
else
ECHO_FORMAT "\n> No argument into the check_process to use or default argument for \"$action_config_name\"..." "lyellow" "bold" clog
action_config_actual_argument=""
fi
if [ "$test_type" == "config_panel" ]
then
ECHO_FORMAT "\n> Apply the configuration for \"$action_config_name\" with the argument \"$action_config_actual_argument\"...\n" "white" "bold" clog
elif [ "$test_type" == "actions" ]
then
ECHO_FORMAT "\n> Execute the action \"$action_config_name\" with the argument \"$action_config_actual_argument\"...\n" "white" "bold" clog
fi
else
ECHO_FORMAT "\n> Execute the action \"$action_config_name\"...\n" "white" "bold" clog
fi
if [ "$test_type" == "config_panel" ]
then
# Aply a configuration
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app config apply $ynh_app_id $action_config_action $action_config_argument_built"
elif [ "$test_type" == "actions" ]
then
# Execute an action
LXC_START "sudo PACKAGE_CHECK_EXEC=1 yunohost --debug app action run $ynh_app_id $action_config_action $action_config_argument_built"
fi
validate_action_config_panel "yunohost action $action_config_action"
done
done
fi
fi
done
# Uses the default snapshot
current_snapshot=snap0
# Stop and restore the LXC container
LXC_STOP
}
PACKAGE_LINTER () {
# Package linter
unit_test_title "Package linter..."
# Execute package linter and linter_result gets the return code of the package linter
"$script_dir/package_linter/package_linter.py" "$package_path" > "$temp_result"
# linter_result gets the return code of the package linter
local linter_result=$?
# Print the results of package linter and copy these result in the complete log
cat "$temp_result" | tee --append "$complete_log"
# Check the result and print SUCCESS or FAIL
if [ $linter_result -eq 0 ]
then # Success
check_success
RESULT_linter=1
else # Fail
check_failed
RESULT_linter=-1
# If return code is 2, this is critical failure, app should be considered as broken (level 0)
if [ $linter_result -eq 2 ]
then
RESULT_linter=-2
fi
fi
}
TEST_LAUNCHER () {
# Abstract for test execution.
# $1 = Name of the function to execute
# $2 = Argument for the function
# Intialize values
yunohost_result=-1
yunohost_remove=-1
false_positive_error=0
max_false_positive_error_loop=3
for false_positive_error_loop in $( seq 1 $max_false_positive_error_loop )
do
# Start the timer for this test
start_timer
# And keep this value separately
local global_start_timer=$starttime
# Execute the test
$1 $2
if [ $false_positive_error -eq 1 ]
then
ECHO_FORMAT "This test was aborted because of a $false_positive_error_cond error.\n" "red" "bold" clog
if [ $false_positive_error_loop -lt $max_false_positive_error_loop ]
then
ECHO_FORMAT "The test will restart.\n" "lyellow" "bold" clog
cur_test=$((cur_test-1))
fi
fi
# Uses the default snapshot
current_snapshot=snap0
# Stop and restore the LXC container
LXC_STOP
# Restore the started time for the timer
starttime=$global_start_timer
# End the timer for the test
stop_timer 2
# Update the lock file with the date of the last finished test.
# $$ is the PID of package_check itself.
echo "$1 $2:$(date +%s):$$" > "$lock_file"
# Exit the loop if there's no temporary errors detected.
if [ $false_positive_error -eq 0 ]
then
break
fi
done
}
set_witness_files () {
# Create files to check if the remove script does not remove them accidentally
echo "Create witness files..." | tee --append "$test_result"
lxc_dir="/var/lib/lxc/$lxc_name/rootfs"
create_witness_file () {
[ "$2" = "file" ] && local action="touch" || local action="mkdir -p"
sudo $action "${lxc_dir}${1}"
}
# Nginx conf
create_witness_file "/etc/nginx/conf.d/$main_domain.d/witnessfile.conf" file
create_witness_file "/etc/nginx/conf.d/$sub_domain.d/witnessfile.conf" file
# /etc
create_witness_file "/etc/witnessfile" file
# /opt directory
create_witness_file "/opt/witnessdir" directory
# /var/www directory
create_witness_file "/var/www/witnessdir" directory
# /home/yunohost.app/
create_witness_file "/home/yunohost.app/witnessdir" directory
# /var/log
create_witness_file "/var/log/witnessfile" file
# Config fpm
if [ -d "${lxc_dir}/etc/php5/fpm" ]; then
create_witness_file "/etc/php5/fpm/pool.d/witnessfile.conf" file
fi
if [ -d "${lxc_dir}/etc/php/7.0/fpm" ]; then
create_witness_file "/etc/php/7.0/fpm/pool.d/witnessfile.conf" file
fi
# Config logrotate
create_witness_file "/etc/logrotate.d/witnessfile" file
# Config systemd
create_witness_file "/etc/systemd/system/witnessfile.service" file
# Database
sudo lxc-attach --name=$lxc_name -- mysqladmin --user=root --password=$(sudo cat "$lxc_dir/etc/yunohost/mysql") --wait status > /dev/null 2>&1
sudo lxc-attach --name=$lxc_name -- mysql --user=root --password=$(sudo cat "$lxc_dir/etc/yunohost/mysql") --wait --execute="CREATE DATABASE witnessdb" > /dev/null 2>&1
}
check_witness_files () {
# Check all the witness files, to verify if them still here
lxc_dir="/var/lib/lxc/$lxc_name/rootfs"
check_file_exist () {
if sudo test ! -e "${lxc_dir}${1}"
then
ECHO_FORMAT "The file $1 is missing ! Something gone wrong !\n" "red" "bold"
RESULT_witness=1
fi
}
# Nginx conf
check_file_exist "/etc/nginx/conf.d/$main_domain.d/witnessfile.conf"
check_file_exist "/etc/nginx/conf.d/$sub_domain.d/witnessfile.conf"
# /etc
check_file_exist "/etc/witnessfile"
# /opt directory
check_file_exist "/opt/witnessdir"
# /var/www directory
check_file_exist "/var/www/witnessdir"
# /home/yunohost.app/
check_file_exist "/home/yunohost.app/witnessdir"
# /var/log
check_file_exist "/var/log/witnessfile"
# Config fpm
if [ -d "${lxc_dir}/etc/php5/fpm" ]; then
check_file_exist "/etc/php5/fpm/pool.d/witnessfile.conf" file
fi
if [ -d "${lxc_dir}/etc/php/7.0/fpm" ]; then
check_file_exist "/etc/php/7.0/fpm/pool.d/witnessfile.conf" file
fi
# Config logrotate
check_file_exist "/etc/logrotate.d/witnessfile"
# Config systemd
check_file_exist "/etc/systemd/system/witnessfile.service"
# Database
if ! sudo lxc-attach --name=$lxc_name -- mysqlshow --user=root --password=$(sudo cat "$lxc_dir/etc/yunohost/mysql") | grep --quiet '^| witnessdb' > /dev/null 2>&1
then
ECHO_FORMAT "The database witnessdb is missing ! Something gone wrong !\n" "red" "bold"
RESULT_witness=1
fi
if [ $RESULT_witness -eq 1 ]
then
yunohost_result=1
yunohost_remove=1
fi
}
TESTING_PROCESS () {
# Launch all tests successively
ECHO_FORMAT "\nTests serie: ${tests_serie#;; }\n\n" "white" "underlined" clog
PRINT_YUNOHOST_VERSION
# Init the value for the current test
cur_test=1
# By default, all tests will try to access the app with curl
use_curl=1
# Check the package with package linter
if [ $pkg_linter -eq 1 ]; then
PACKAGE_LINTER
fi
CHECK_TEMPLATE
# Try to install in a sub path
if [ $setup_sub_dir -eq 1 ]; then
TEST_LAUNCHER CHECK_SETUP subdir
fi
# Try to install on root
if [ $setup_root -eq 1 ]; then
TEST_LAUNCHER CHECK_SETUP root
fi
# Try to install without url access
if [ $setup_nourl -eq 1 ]; then
TEST_LAUNCHER CHECK_SETUP no_url
fi
# Try the upgrade script
if [ $upgrade -eq 1 ]; then
TEST_LAUNCHER CHECK_UPGRADE
fi
# Try to install in private mode
if [ $setup_private -eq 1 ]; then
TEST_LAUNCHER CHECK_PUBLIC_PRIVATE private
fi
# Try to install in public mode
if [ $setup_public -eq 1 ]; then
TEST_LAUNCHER CHECK_PUBLIC_PRIVATE public
fi
# Try multi-instance installations
if [ $multi_instance -eq 1 ]; then
TEST_LAUNCHER CHECK_MULTI_INSTANCE
fi
# Try to install with an malformed path
if [ $incorrect_path -eq 1 ]; then
TEST_LAUNCHER CHECK_COMMON_ERROR incorrect_path
fi
# Try to install with a port already used
if [ $port_already_use -eq 1 ]; then
TEST_LAUNCHER CHECK_COMMON_ERROR port_already_use
fi
# Try to backup then restore the app
if [ $backup_restore -eq 1 ]; then
TEST_LAUNCHER CHECK_BACKUP_RESTORE
fi
# Try the change_url script
if [ $change_url -eq 1 ]; then
TEST_LAUNCHER CHECK_CHANGE_URL
fi
# Try the actions
if [ $actions -eq 1 ]; then
TEST_LAUNCHER ACTIONS_CONFIG_PANEL actions
fi
# Try the config-panel
if [ $config_panel -eq 1 ]; then
TEST_LAUNCHER ACTIONS_CONFIG_PANEL config_panel
fi
}