Merge pull request #132 from YunoHost/support-v2-apps

Support for appsv2
This commit is contained in:
Alexandre Aubin 2023-01-19 22:31:58 +01:00 committed by GitHub
commit 8d57b15810
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 474 additions and 280 deletions

View file

@ -25,10 +25,10 @@ def test_notes(test):
if test["test_type"] == "TEST_UPGRADE" and test["test_arg"]:
return
if test["test_type"] == "PACKAGE_LINTER" and test['results']['main_result'] == 'success' and test['results'].get("warning"):
if test["test_type"] == "TEST_PACKAGE_LINTER" and test['results']['main_result'] == 'success' and test['results'].get("warning"):
yield '<style=warning>%s warnings</style>' % len(test['results'].get("warning"))
if test["test_type"] == "PACKAGE_LINTER" and test['results']['main_result'] == 'success' and test['results'].get("info"):
if test["test_type"] == "TEST_PACKAGE_LINTER" and test['results']['main_result'] == 'success' and test['results'].get("info"):
yield '%s possible improvements' % len(set(test['results'].get("info")))
if test['results'].get("witness"):
@ -71,7 +71,7 @@ def level_1(tests):
And there are no critical issues in the linter
"""
linter_tests = [t for t in tests if t["test_type"] == "PACKAGE_LINTER"]
linter_tests = [t for t in tests if t["test_type"] == "TEST_PACKAGE_LINTER"]
install_tests = [t for t in tests if t["test_type"] == "TEST_INSTALL"]
witness_missing_detected = any(t["results"].get("witness") for t in tests)
@ -126,7 +126,7 @@ def level_5(tests):
"""
alias_traversal_detected = any(t["results"].get("alias_traversal") for t in tests)
linter_tests = [t for t in tests if t["test_type"] == "PACKAGE_LINTER"]
linter_tests = [t for t in tests if t["test_type"] == "TEST_PACKAGE_LINTER"]
return not alias_traversal_detected \
and linter_tests != [] \
@ -140,7 +140,7 @@ def level_6(tests):
(the linter will report a warning named "is_in_github_org" if it's not)
"""
linter_tests = [t for t in tests if t["test_type"] == "PACKAGE_LINTER"]
linter_tests = [t for t in tests if t["test_type"] == "TEST_PACKAGE_LINTER"]
return linter_tests != [] \
and "is_in_github_org" not in linter_tests[0]["results"]["warning"]
@ -153,7 +153,7 @@ def level_7(tests):
linter which will report a "qualify_for_level_7" in successes)
"""
linter_tests = [t for t in tests if t["test_type"] == "PACKAGE_LINTER"]
linter_tests = [t for t in tests if t["test_type"] == "TEST_PACKAGE_LINTER"]
# For runtime warnings, ignore stuff happening during upgrades from previous versions
tests_on_which_to_check_for_runtime_warnings = [t for t in tests if not (t["test_type"] == "TEST_UPGRADE" and t["test_arg"])]
@ -178,7 +178,7 @@ def level_8(tests):
which will report a "qualify_for_level_8")
"""
linter_tests = [t for t in tests if t["test_type"] == "PACKAGE_LINTER"]
linter_tests = [t for t in tests if t["test_type"] == "TEST_PACKAGE_LINTER"]
return linter_tests != [] \
and "App.qualify_for_level_8" in linter_tests[0]["results"]["success"]
@ -190,7 +190,7 @@ def level_9(tests):
App is flagged high-quality in the app catalog (this is tested by the linter
which will rpeort a "qualify_for_level_9")
"""
linter_tests = [t for t in tests if t["test_type"] == "PACKAGE_LINTER"]
linter_tests = [t for t in tests if t["test_type"] == "TEST_PACKAGE_LINTER"]
return linter_tests != [] \
and "App.qualify_for_level_9" in linter_tests[0]["results"]["success"]
@ -199,7 +199,7 @@ def level_9(tests):
def make_summary():
test_types = {
"PACKAGE_LINTER": "Package linter",
"TEST_PACKAGE_LINTER": "Package linter",
"TEST_INSTALL": "Install",
"TEST_UPGRADE": "Upgrade",
"TEST_BACKUP_RESTORE": "Backup/restore",

View file

@ -0,0 +1,53 @@
#!/usr/bin/python3
import sys
import json
import toml
def get_default_values_for_questions(manifest):
base_default_value_per_arg_type = {
("domain", "domain"): "domain.tld",
("path", "path"): "/" + manifest["id"],
("user", "admin"): "package_checker",
("group", "init_main_permission"): "visitors",
("group", "init_admin_permission"): "admins",
("password", "password"): "MySuperComplexPassword"
}
if manifest.get("packaging_format", 1) <= 1:
questions = {q["name"]:q for q in manifest["arguments"]["install"]}
else:
questions = manifest["install"]
for name, question in questions.items():
type_and_name = (question["type"], name)
base_default = base_default_value_per_arg_type.get(type_and_name)
if base_default:
yield (name, base_default)
elif question.get("default"):
if isinstance(question.get("default"), bool):
yield (name, str(int(question.get("default"))))
else:
yield (name, str(question.get("default")))
elif question["type"] == "boolean":
yield (name, "1")
elif question.get("choices"):
if isinstance(question["choices"]):
choices = str(question["choices"])
else:
choices = list(question["choices"].keys())
yield (name, question["choices"][0])
else:
raise Exception("No default value could be computed for arg " + name)
if __name__ == '__main__':
manifest_path = sys.argv[1:][0]
if manifest_path.endswith(".json"):
manifest = json.load(open(manifest_path, "r"))
else:
manifest = toml.load(open(manifest_path, "r"))
querystring = '&'.join([k + "=" + v for k, v in get_default_values_for_questions(manifest)])
print(querystring)

198
lib/legacy.sh Normal file
View file

@ -0,0 +1,198 @@
#=======================================================================
# Parse the check_process and generate jsons that describe tests to run
#=======================================================================
# Extract a section found between $1 and $2 from the file $3
extract_check_process_section () {
local source_file="${3:-$check_process}"
local extract=0
local line=""
while read line
do
# Extract the line
if [ $extract -eq 1 ]
then
# Check if the line is the second line to found
if echo $line | grep -q "$2"; then
# Break the loop to finish the extract process
break;
fi
# Copy the line in the partial check_process
echo "$line"
fi
# Search for the first line
if echo $line | grep -q "$1"; then
# Activate the extract process
extract=1
fi
done < "$source_file"
}
parse_check_process() {
log_info "Parsing check_process file"
# Remove all commented lines in the check_process
sed --in-place '/^#/d' "$check_process"
# Remove all spaces at the beginning of the lines
sed --in-place 's/^[ \t]*//g' "$check_process"
# Extract the Upgrade infos
extract_check_process_section "^;;; Upgrade options" ";; " > $TEST_CONTEXT/check_process.upgrade_options
mkdir -p $TEST_CONTEXT/upgrades
local commit
for commit in $(cat $TEST_CONTEXT/check_process.upgrade_options | grep "^; commit=.*" | awk -F= '{print $2}')
do
cat $TEST_CONTEXT/check_process.upgrade_options | sed -n -e "/^; commit=$commit/,/^;/ p" | grep -v "^;;" > $TEST_CONTEXT/upgrades/$commit
done
rm $TEST_CONTEXT/check_process.upgrade_options
local test_serie_id="0"
# Parse each tests serie
while read <&3 tests_serie
do
test_serie_id=$((test_serie_id+1))
local test_id=$((test_serie_id * 100))
local test_serie_rawconf=$TEST_CONTEXT/raw_test_serie_config
# Extract the section of the current tests serie
extract_check_process_section "^$tests_serie" "^;;" > $test_serie_rawconf
# This is the arg list to be later fed to "yunohost app install"
# Looking like domain=foo.com&path=/bar&password=stuff
# "Standard" arguments like domain/path will later be overwritten
# during tests
local install_args=$( extract_check_process_section "^; Manifest" "^; " $test_serie_rawconf | sed 's/\s*(.*)$//g' | tr -d '"' | tr '\n' '&')
local preinstall_template=$(extract_check_process_section "^; pre-install" "^; " $test_serie_rawconf)
local preupgrade_template=$(extract_check_process_section "^; pre-upgrade" "^; " $test_serie_rawconf)
# Add (empty) special args if they ain't provided in check_process
echo "$install_args" | tr '&' '\n' | grep -q "^domain=" ||install_args+="domain=&"
echo "$install_args" | tr '&' '\n' | grep -q "^path=" ||install_args+="path=&"
echo "$install_args" | tr '&' '\n' | grep -q "^admin=" ||install_args+="admin=&"
echo "$install_args" | tr '&' '\n' | grep -q "^is_public=" ||install_args+="is_public=&"
echo "$install_args" | tr '&' '\n' | grep -q "^init_main_permission=" ||install_args+="init_main_permission=&"
extract_check_process_section "^; Checks" "^; " $test_serie_rawconf > $TEST_CONTEXT/check_process.tests_infos
is_test_enabled () {
# Find the line for the given check option
local value=$(grep -m1 -o "^$1=." "$TEST_CONTEXT/check_process.tests_infos" | awk -F= '{print $2}')
# And return this value
[ "${value:0:1}" = "1" ]
}
add_test() {
local test_type="$1"
local test_arg="$2"
test_id="$((test_id+1))"
local extra="{}"
local _install_args="$install_args"
# Upgrades with a specific commit
if [[ "$test_type" == "TEST_UPGRADE" ]] && [[ -n "$test_arg" ]]
then
if [ -f "$TEST_CONTEXT/upgrades/$test_arg" ]; then
local specific_upgrade_install_args="$(grep "^manifest_arg=" "$TEST_CONTEXT/upgrades/$test_arg" | cut -d'=' -f2-)"
[[ -n "$specific_upgrade_install_args" ]] && _install_args="$specific_upgrade_install_args"
local upgrade_name="$(grep "^name=" "$TEST_CONTEXT/upgrades/$test_arg" | cut -d'=' -f2)"
else
local upgrade_name="$test_arg"
fi
extra="$(jq -n --arg upgrade_name "$upgrade_name" '{ $upgrade_name }')"
fi
jq -n \
--arg test_serie "$test_serie" \
--arg test_type "$test_type" \
--arg test_arg "$test_arg" \
--arg preinstall_template "$preinstall_template" \
--arg preupgrade_template "$preupgrade_template" \
--arg install_args "${_install_args//\"}" \
--argjson extra "$extra" \
'{ $test_serie, $test_type, $test_arg, $preinstall_template, $preupgrade_template, $install_args, $extra }' \
> "$TEST_CONTEXT/tests/$test_id.json"
}
test_serie=${tests_serie//;; }
is_test_enabled pkg_linter && add_test "TEST_PACKAGE_LINTER"
is_test_enabled setup_root && add_test "TEST_INSTALL" "root"
is_test_enabled setup_sub_dir && add_test "TEST_INSTALL" "subdir"
is_test_enabled setup_nourl && add_test "TEST_INSTALL" "nourl"
is_test_enabled setup_private && add_test "TEST_INSTALL" "private"
is_test_enabled multi_instance && add_test "TEST_INSTALL" "multi"
is_test_enabled backup_restore && add_test "TEST_BACKUP_RESTORE"
# Upgrades
while IFS= read -r LINE;
do
commit="$(echo $LINE | grep -o "from_commit=.*" | awk -F= '{print $2}')"
add_test "TEST_UPGRADE" "$commit"
done < <(grep "^upgrade=1" "$TEST_CONTEXT/check_process.tests_infos")
# "Advanced" features
is_test_enabled change_url && add_test "TEST_CHANGE_URL"
# Port already used ... do we really need this ...
if grep -q -m1 "port_already_use=1" "$TEST_CONTEXT/check_process.tests_infos"
then
local check_port=$(grep -m1 "port_already_use=1" "$TEST_CONTEXT/check_process.tests_infos" | grep -o -E "\([0-9]+\)" | tr -d '()')
else
local check_port=6660
fi
is_test_enabled port_already_use && add_test "TEST_PORT_ALREADY_USED" "$check_port"
done 3<<< "$(grep "^;; " "$check_process")"
return 0
}
guess_test_configuration() {
log_error "No tests.toml file found."
log_warning "Package check will attempt to automatically guess what tests to run."
local test_id=100
add_test() {
local test_type="$1"
local test_arg="$2"
test_id="$((test_id+1))"
local extra="{}"
local preupgrade_template=""
jq -n \
--arg test_serie "default" \
--arg test_type "$test_type" \
--arg test_arg "$test_arg" \
--arg preinstall_template "" \
--arg preupgrade_template "$preupgrade_template" \
--arg install_args "$install_args" \
--argjson extra "$extra" \
'{ $test_serie, $test_type, $test_arg, $preinstall_template, $preupgrade_template, $install_args, $extra }' \
> "$TEST_CONTEXT/tests/$test_id.json"
}
local install_args=$(python3 "./lib/default_install_args.py" "$package_path"/manifest.*)
add_test "TEST_PACKAGE_LINTER"
add_test "TEST_INSTALL" "root"
add_test "TEST_INSTALL" "subdir"
if echo $install_args | grep -q "is_public=\|init_main_permission="
then
add_test "TEST_INSTALL" "private"
fi
if grep multi_instance "$package_path"/manifest.* | grep -q true
then
add_test "TEST_INSTALL" "multi"
fi
add_test "TEST_BACKUP_RESTORE"
add_test "TEST_UPGRADE"
}

View file

@ -1,56 +0,0 @@
#!/usr/bin/python3
import sys
import json
def argument_for_question(question, all_choices=False):
question_type = question.get("type")
if question_type is None and question.get("choices"):
question_type = "boolean"
elif question_type in [None, "string"] and question.get("default"):
question_type = "with_default"
elif question_type is None and question["name"] == "admin":
question_type = "user"
elif question_type is None and question["name"] == "domain":
question_type = "domain"
if question_type == "domain":
return (question["name"], "ynh.local")
elif question_type == "path":
if all_choices:
return (question["name"], question["default"], "/")
else:
return (question["name"], question["default"])
elif question_type == "with_default":
return (question["name"], question["default"])
elif question_type == "boolean":
if not all_choices:
if isinstance(question["default"], bool):
if question["default"]:
question["default"] = "1"
else:
question["default"] = "0"
return (question["name"], question["default"])
else:
if isinstance(question["default"], bool) :
return (question["name"], "1", "0")
if question.get("choices"):
return (question["name"],) + tuple(question["choices"])
return (question["name"], question["default"])
elif question_type == "password":
return (question["name"], "ynh")
elif question_type == "user":
return (question["name"], "johndoe")
else:
raise Exception("Unknow question type: %s\n" % question_type, question)
if __name__ == '__main__':
manifest_path = sys.argv[1:][0]
manifest = json.load(open(manifest_path, "r"))
for question in manifest["arguments"]["install"]:
print(":".join(argument_for_question(question, all_choices=True)))

163
lib/parse_tests_toml.py Normal file
View file

@ -0,0 +1,163 @@
import sys
import os
import toml
import copy
import json
def generate_test_list_base(test_manifest, default_install_args, is_webapp, is_multi_instance):
assert test_manifest["test_format"] == 1.0, "Only test_format 1.0 is supported for now"
assert isinstance(test_manifest["default"], dict), "You should at least defined the 'default' test suite"
is_full_domain_app = "domain" in default_install_args and "path" not in default_install_args
for test_suite_id, test_suite in test_manifest.items():
# Ignore non-testsuite stuff like "test_format"
if not isinstance(test_suite, dict):
continue
install_args = copy.copy(default_install_args)
install_args.update(test_suite.get("args", {}))
default_meta = {
"preinstall_template": test_suite.get("preinstall_template", ""),
"preupgrade_template": test_suite.get("preupgrade_template", ""),
"install_args": install_args,
}
yield test_suite_id, "package_linter", default_meta
if is_webapp:
yield test_suite_id, "install.root", default_meta
if not is_full_domain_app:
yield test_suite_id, "install.subdir", default_meta
else:
yield test_suite_id, "install.nourl", default_meta
if is_webapp and ("is_public" in install_args or "init_main_permission" in install_args):
yield test_suite_id, "install.private", default_meta
if is_multi_instance:
yield test_suite_id, "install.multi", default_meta
yield test_suite_id, "backup_restore", default_meta
yield test_suite_id, "upgrade", default_meta
for commit, infos in test_suite.get("test_upgrade_from", {}).items():
upgrade_meta = copy.copy(default_meta)
upgrade_meta.update(infos)
yield test_suite_id, "upgrade." + commit, upgrade_meta
if is_webapp:
yield test_suite_id, "change_url", default_meta
def filter_test_list(test_manifest, base_test_list):
for test_suite_id, test_suite in test_manifest.items():
# Ignore non-testsuite stuff like "test_format"
if not isinstance(test_suite, dict):
continue
exclude = test_suite.get("exclude", [])
only = test_suite.get("only")
if test_suite_id == "default" and only:
raise Exception("'only' is not allowed on the default test suite")
if only:
tests_for_this_suite = {test_id: meta
for suite_id, test_id, meta in base_test_list
if suite_id == test_suite_id and test_id in only}
elif exclude:
tests_for_this_suite = {test_id: meta
for suite_id, test_id, meta in base_test_list
if suite_id == test_suite_id and test_id not in exclude}
else:
tests_for_this_suite = {test_id: meta
for suite_id, test_id, meta in base_test_list
if suite_id == test_suite_id}
yield test_suite_id, tests_for_this_suite
def dump_for_package_check(test_list, package_check_tests_dir):
test_suite_i = 0
for test_suite_id, subtest_list in test_list.items():
test_suite_i += 1
subtest_i = 0
for test, meta in subtest_list.items():
meta = copy.copy(meta)
subtest_i += 1
if "." in test:
test_type, test_arg = test.split(".")
else:
test_type = test
test_arg = ""
J = {
"test_serie": test_suite_id,
"test_type": "TEST_" + test_type.upper(),
"test_arg": test_arg,
"preinstall_template": meta.pop("preinstall_template", ""),
"preupgrade_template": meta.pop("preupgrade_template", ""),
"install_args": '&'.join([k + "=" + str(v) for k, v in meta.pop("install_args").items()]),
"extra": meta # Boring logic just to ship the upgrade-from-commit's name ...
}
test_file_id = test_suite_i * 100 + subtest_i
json.dump(J, open(package_check_tests_dir + f"/{test_file_id}.json", "w"))
def build_test_list(basedir):
test_manifest = toml.load(open(basedir + "/tests.toml", "r"))
if os.path.exists(basedir + "/manifest.json"):
manifest = json.load(open(basedir + "/manifest.json", "r"))
is_multi_instance = manifest.get("multi_instance") is True
else:
manifest = toml.load(open(basedir + "/manifest.toml", "r"))
is_multi_instance = manifest.get("integration").get("multi_instance") is True
is_webapp = os.system(f"grep -q '^ynh_add_nginx_config' '{basedir}/scripts/install'") == 0
from default_install_args import get_default_values_for_questions
default_install_args = {k: v for k, v in get_default_values_for_questions(manifest)}
base_test_list = list(generate_test_list_base(test_manifest, default_install_args, is_webapp, is_multi_instance))
test_list = {test_suite_id: tests for test_suite_id, tests in filter_test_list(test_manifest, base_test_list)}
return test_list
if __name__ == '__main__':
test_list = build_test_list(sys.argv[1])
if len(sys.argv) <= 1 or sys.argv[1] in ["-h", "--help"]:
print("""Usage:
Display generated test list:
python3 parse_tests_toml.py /path/to/app/folder/ | jq
Dump the list (only relevant from inside package_checker's code ...)
python3 parse_tests_toml.py /path/to/app/folder/ /tmp/dir/for/package/check/....
""")
elif len(sys.argv) == 2:
print(json.dumps(test_list, indent=4))
else:
dump_for_package_check(test_list, sys.argv[2])

View file

@ -76,13 +76,14 @@ _INSTALL_APP () {
# We have default values for domain, admin and is_public, but these
# may still be overwritten by the args ($@)
for arg_override in "domain=$SUBDOMAIN" "admin=$TEST_USER" "is_public=1" "$@"
for arg_override in "domain=$SUBDOMAIN" "admin=$TEST_USER" "is_public=1" "init_main_permission=visitors" "$@"
do
key="$(echo $arg_override | cut -d '=' -f 1)"
value="$(echo $arg_override | cut -d '=' -f 2-)"
# (Legacy stuff ... We don't override is_public if its type is not boolean)
[[ "$key" == "is_public" ]] \
[[ -e $package_path/manifest.json ]] \
&& [[ "$key" == "is_public" ]] \
&& [[ "$(jq -r '.arguments.install[] | select(.name=="is_public") | .type' $package_path/manifest.json)" != "boolean" ]] \
&& continue
@ -90,14 +91,27 @@ _INSTALL_APP () {
done
# Note : we do this at this stage and not during the parsing of check_process
# because this also applies to upgrades ...
# For all manifest arg
for ARG in $(jq -r '.arguments.install[].name' $package_path/manifest.json)
# because this also applies to upgrades ... ie older version may have different args and default values
# Fetch and loop over all manifest arg
if [[ -e $package_path/manifest.json ]]
then
local manifest_args="$(jq -r '.arguments.install[].name' $package_path/manifest.json)"
else
local manifest_args="$(grep '^\s*\[install\.' $package_path/manifest.toml | tr -d '[]' | awk -F. '{print $2}')"
fi
for ARG in $manifest_args
do
# If the argument is not yet in install args, add its default value
if ! echo "$install_args" | grep -q -E "\<$ARG="
then
local default_value=$(jq -e -r --arg ARG $ARG '.arguments.install[] | select(.name==$ARG) | .default' $package_path/manifest.json)
if [[ -e $package_path/manifest.json ]]
then
local default_value=$(jq -e -r --arg ARG $ARG '.arguments.install[] | select(.name==$ARG) | .default' $package_path/manifest.json)
else
local default_value=$(python3 -c "import toml, sys; t = toml.loads(sys.stdin.read()); d = t['install']['$ARG'].get('default'); assert d is not None, 'Missing default value'; print(d)" < $package_path/manifest.toml)
fi
[[ $? -eq 0 ]] || { log_error "Missing install arg $ARG ?"; return 1; }
[[ ${install_args: -1} == '&' ]] || install_args+="&"
install_args+="$ARG=$default_value"
@ -177,7 +191,14 @@ _VALIDATE_THAT_APP_CAN_BE_ACCESSED () {
# private by default For "regular" apps (with a is_public arg) they are
# installed as public, and we precisely want to check they are publicly
# accessible *without* tweaking skipped_uris...
if [ "$install_type" != 'private' ] && [[ -z "$(jq -r '.arguments.install[] | select(.name=="is_public")' $package_path/manifest.json)" ]]
if [[ -e $package_path/manifest.json ]]
then
local has_public_arg=$([[ -n "$(jq -r '.arguments.install[] | select(.name=="is_public")' $package_path/manifest.json)" ]] && echo true || echo false)
else
local has_public_arg=$(grep -q '\[install.init_main_permission\]' $package_path/manifest.toml && echo true || echo false)
fi
if [ "$install_type" != 'private' ] && [[ $has_public_arg == "false" ]]
then
log_debug "Forcing public access using a skipped_uris setting"
# Add a skipped_uris on / for the app
@ -329,7 +350,7 @@ Page extract:\n$page_extract" > $TEST_CONTEXT/curl_result
# Tests
#=================================================
PACKAGE_LINTER () {
TEST_PACKAGE_LINTER () {
start_test "Package linter"
@ -350,10 +371,11 @@ TEST_INSTALL () {
local check_path="/"
local is_public="1"
local init_main_permission="visitors"
[ "$install_type" = "subdir" ] && { start_test "Installation in a sub path"; local check_path=/path; }
[ "$install_type" = "root" ] && { start_test "Installation on the root"; }
[ "$install_type" = "nourl" ] && { start_test "Installation without URL access"; local check_path=""; }
[ "$install_type" = "private" ] && { start_test "Installation in private mode"; local is_public="0"; }
[ "$install_type" = "private" ] && { start_test "Installation in private mode"; local is_public="0"; local init_main_permission="all_users"; }
local snapname=snap_${install_type}install
LOAD_LXC_SNAPSHOT snap0
@ -361,7 +383,7 @@ TEST_INSTALL () {
_PREINSTALL
# Install the application in a LXC container
_INSTALL_APP "path=$check_path" "is_public=$is_public" \
_INSTALL_APP "path=$check_path" "is_public=$is_public" "init_main_permission=$init_main_permission" \
&& _VALIDATE_THAT_APP_CAN_BE_ACCESSED "$SUBDOMAIN" "$check_path" "$install_type" \
local install=$?
@ -377,7 +399,7 @@ TEST_INSTALL () {
# Remove and reinstall the application
_REMOVE_APP \
&& log_small_title "Reinstalling after removal." \
&& _INSTALL_APP "path=$check_path" "is_public=$is_public" \
&& _INSTALL_APP "path=$check_path" "is_public=$is_public" "init_main_permission=$init_main_permission" \
&& _VALIDATE_THAT_APP_CAN_BE_ACCESSED "$SUBDOMAIN" "$check_path" "$install_type"
return $?

View file

@ -3,6 +3,7 @@
source lib/lxc.sh
source lib/tests.sh
source lib/witness.sh
source lib/legacy.sh
readonly complete_log="./Complete-${WORKER_ID}.log"
@ -12,204 +13,6 @@ rm -f "$complete_log" && touch "$complete_log"
# Redirect fd 3 (=debug steam) to complete log
exec 3>>$complete_log
#=======================================================================
# Parse the check_process and generate jsons that describe tests to run
#=======================================================================
# Extract a section found between $1 and $2 from the file $3
extract_check_process_section () {
local source_file="${3:-$check_process}"
local extract=0
local line=""
while read line
do
# Extract the line
if [ $extract -eq 1 ]
then
# Check if the line is the second line to found
if echo $line | grep -q "$2"; then
# Break the loop to finish the extract process
break;
fi
# Copy the line in the partial check_process
echo "$line"
fi
# Search for the first line
if echo $line | grep -q "$1"; then
# Activate the extract process
extract=1
fi
done < "$source_file"
}
parse_check_process() {
log_info "Parsing check_process file"
# Remove all commented lines in the check_process
sed --in-place '/^#/d' "$check_process"
# Remove all spaces at the beginning of the lines
sed --in-place 's/^[ \t]*//g' "$check_process"
# Extract the Upgrade infos
extract_check_process_section "^;;; Upgrade options" ";; " > $TEST_CONTEXT/check_process.upgrade_options
mkdir -p $TEST_CONTEXT/upgrades
local commit
for commit in $(cat $TEST_CONTEXT/check_process.upgrade_options | grep "^; commit=.*" | awk -F= '{print $2}')
do
cat $TEST_CONTEXT/check_process.upgrade_options | sed -n -e "/^; commit=$commit/,/^;/ p" | grep -v "^;;" > $TEST_CONTEXT/upgrades/$commit
done
rm $TEST_CONTEXT/check_process.upgrade_options
local test_serie_id="0"
# Parse each tests serie
while read <&3 tests_serie
do
test_serie_id=$((test_serie_id+1))
local test_id=$((test_serie_id * 100))
local test_serie_rawconf=$TEST_CONTEXT/raw_test_serie_config
# Extract the section of the current tests serie
extract_check_process_section "^$tests_serie" "^;;" > $test_serie_rawconf
# This is the arg list to be later fed to "yunohost app install"
# Looking like domain=foo.com&path=/bar&password=stuff
# "Standard" arguments like domain/path will later be overwritten
# during tests
local install_args=$( extract_check_process_section "^; Manifest" "^; " $test_serie_rawconf | sed 's/\s*(.*)$//g' | tr -d '"' | tr '\n' '&')
local preinstall_template=$(extract_check_process_section "^; pre-install" "^; " $test_serie_rawconf)
local preupgrade_template=$(extract_check_process_section "^; pre-upgrade" "^; " $test_serie_rawconf)
# Add (empty) special args if they ain't provided in check_process
echo "$install_args" | tr '&' '\n' | grep -q "^domain=" ||install_args+="domain=&"
echo "$install_args" | tr '&' '\n' | grep -q "^path=" ||install_args+="path=&"
echo "$install_args" | tr '&' '\n' | grep -q "^admin=" ||install_args+="admin=&"
echo "$install_args" | tr '&' '\n' | grep -q "^is_public=" ||install_args+="is_public=&"
extract_check_process_section "^; Checks" "^; " $test_serie_rawconf > $TEST_CONTEXT/check_process.tests_infos
is_test_enabled () {
# Find the line for the given check option
local value=$(grep -m1 -o "^$1=." "$TEST_CONTEXT/check_process.tests_infos" | awk -F= '{print $2}')
# And return this value
[ "${value:0:1}" = "1" ]
}
add_test() {
local test_type="$1"
local test_arg="$2"
test_id="$((test_id+1))"
local extra="{}"
local _install_args="$install_args"
# Upgrades with a specific commit
if [[ "$test_type" == "TEST_UPGRADE" ]] && [[ -n "$test_arg" ]]
then
if [ -f "$TEST_CONTEXT/upgrades/$test_arg" ]; then
local specific_upgrade_install_args="$(grep "^manifest_arg=" "$TEST_CONTEXT/upgrades/$test_arg" | cut -d'=' -f2-)"
[[ -n "$specific_upgrade_install_args" ]] && _install_args="$specific_upgrade_install_args"
local upgrade_name="$(grep "^name=" "$TEST_CONTEXT/upgrades/$test_arg" | cut -d'=' -f2)"
else
local upgrade_name="$test_arg"
fi
extra="$(jq -n --arg upgrade_name "$upgrade_name" '{ $upgrade_name }')"
fi
jq -n \
--arg test_serie "$test_serie" \
--arg test_type "$test_type" \
--arg test_arg "$test_arg" \
--arg preinstall_template "$preinstall_template" \
--arg preupgrade_template "$preupgrade_template" \
--arg install_args "${_install_args//\"}" \
--argjson extra "$extra" \
'{ $test_serie, $test_type, $test_arg, $preinstall_template, $preupgrade_template, $install_args, $extra }' \
> "$TEST_CONTEXT/tests/$test_id.json"
}
test_serie=${tests_serie//;; }
is_test_enabled pkg_linter && add_test "PACKAGE_LINTER"
is_test_enabled setup_root && add_test "TEST_INSTALL" "root"
is_test_enabled setup_sub_dir && add_test "TEST_INSTALL" "subdir"
is_test_enabled setup_nourl && add_test "TEST_INSTALL" "nourl"
is_test_enabled setup_private && add_test "TEST_INSTALL" "private"
is_test_enabled multi_instance && add_test "TEST_INSTALL" "multi"
is_test_enabled backup_restore && add_test "TEST_BACKUP_RESTORE"
# Upgrades
while IFS= read -r LINE;
do
commit="$(echo $LINE | grep -o "from_commit=.*" | awk -F= '{print $2}')"
add_test "TEST_UPGRADE" "$commit"
done < <(grep "^upgrade=1" "$TEST_CONTEXT/check_process.tests_infos")
# "Advanced" features
is_test_enabled change_url && add_test "TEST_CHANGE_URL"
# Port already used ... do we really need this ...
if grep -q -m1 "port_already_use=1" "$TEST_CONTEXT/check_process.tests_infos"
then
local check_port=$(grep -m1 "port_already_use=1" "$TEST_CONTEXT/check_process.tests_infos" | grep -o -E "\([0-9]+\)" | tr -d '()')
else
local check_port=6660
fi
is_test_enabled port_already_use && add_test "TEST_PORT_ALREADY_USED" "$check_port"
done 3<<< "$(grep "^;; " "$check_process")"
return 0
}
guess_test_configuration() {
log_error "Not check_process file found."
log_warning "Package check will attempt to automatically guess what tests to run."
local test_id=100
add_test() {
local test_type="$1"
local test_arg="$2"
test_id="$((test_id+1))"
local extra="{}"
local preupgrade_template=""
jq -n \
--arg test_serie "default" \
--arg test_type "$test_type" \
--arg test_arg "$test_arg" \
--arg preinstall_template "" \
--arg preupgrade_template "$preupgrade_template" \
--arg install_args "$install_args" \
--argjson extra "$extra" \
'{ $test_serie, $test_type, $test_arg, $preinstall_template, $preupgrade_template, $install_args, $extra }' \
> "$TEST_CONTEXT/tests/$test_id.json"
}
local install_args=$(python3 "./lib/manifest_parsing.py" "$package_path/manifest.json" | cut -d ':' -f1,2 | tr ':' '=' | tr '\n' '&')
add_test "PACKAGE_LINTER"
add_test "TEST_INSTALL" "root"
add_test "TEST_INSTALL" "subdir"
if echo $install_args | grep -q "is_public="
then
add_test "TEST_INSTALL" "private"
fi
if grep multi_instance "$package_path/manifest.json" | grep -q true
then
add_test "TEST_INSTALL" "multi"
fi
add_test "TEST_BACKUP_RESTORE"
add_test "TEST_UPGRADE"
}
#=================================================
# Misc test helpers & coordination
#=================================================
@ -220,14 +23,25 @@ run_all_tests() {
mkdir -p $TEST_CONTEXT/results
mkdir -p $TEST_CONTEXT/logs
readonly app_id="$(jq -r .id $package_path/manifest.json)"
if [ -e $package_path/manifest.json ]
then
readonly app_id="$(jq -r .id $package_path/manifest.json)"
else
readonly app_id="$(grep '^id = ' $package_path/manifest.toml | tr -d '" ' | awk -F= '{print $2}')"
fi
# Parse the check_process only if it's exist
check_process="$package_path/check_process"
tests_toml="$package_path/tests.toml"
if [ -e "$tests_toml" ]
then
python3 "./lib/parse_tests_toml.py" "$package_path" "$TEST_CONTEXT/tests"
else
# Parse the check_process only if it's exist
check_process="$package_path/check_process"
[ -e "$check_process" ] \
&& parse_check_process \
|| guess_test_configuration
[ -e "$check_process" ] \
&& parse_check_process \
|| guess_test_configuration
fi
# Start the timer for this test
start_timer