feat: add signed PostgreSQL release updates
This commit is contained in:
Executable
+504
@@ -0,0 +1,504 @@
|
||||
#!/usr/bin/env bash
|
||||
set -uo pipefail
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
run_test() {
|
||||
local name="$1"
|
||||
shift
|
||||
if ("$@"); then
|
||||
printf 'PASS %s\n' "$name"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
printf 'FAIL %s\n' "$name"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
checksum_file() {
|
||||
local file="$1"
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$file"
|
||||
else
|
||||
shasum -a 256 "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
test_erp_run_preserves_java_option_arguments() (
|
||||
local tmp
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-run-test.XXXXXX")" || return 1
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
mkdir -p "$tmp/current/app" "$tmp/run"
|
||||
: > "$tmp/current/app/kaidi-erp.jar"
|
||||
: > "$tmp/-Dpattern=expanded"
|
||||
printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
'if [[ "${1:-}" == "-version" ]]; then' \
|
||||
' printf '\''openjdk version "17.0.12"\n'\'' >&2' \
|
||||
' exit 0' \
|
||||
'fi' \
|
||||
'printf '\''%s\n'\'' "$@"' > "$tmp/java"
|
||||
chmod +x "$tmp/java"
|
||||
{
|
||||
printf 'ERP_JAVA_BIN=%q\n' "$tmp/java"
|
||||
printf 'ERP_JAVA_OPTS=%q\n' '-Dpattern=* -Xmx1g'
|
||||
printf 'ERP_RUN_DIR=%q\n' "$tmp/run"
|
||||
} > "$tmp/erp.env"
|
||||
|
||||
local output
|
||||
output="$(cd "$tmp" && ERP_INSTALL_ROOT="$tmp" ERP_CONFIG_FILE="$tmp/erp.env" \
|
||||
"$PROJECT_ROOT/distribution/bin/erp-run")" || return 1
|
||||
grep -Fqx -- '-Dpattern=*' <<< "$output" || return 1
|
||||
grep -Fqx -- '-Xmx1g' <<< "$output" || return 1
|
||||
grep -Fqx -- "$tmp/current/app/kaidi-erp.jar" <<< "$output"
|
||||
)
|
||||
|
||||
prepare_signed_archive() {
|
||||
local tmp="$1" unsafe="${2:-0}"
|
||||
mkdir -p "$tmp/package/kaidi-erp-1.2.3/app"
|
||||
printf 'jar\n' > "$tmp/package/kaidi-erp-1.2.3/app/kaidi-erp.jar"
|
||||
if [[ "$unsafe" == "1" ]]; then
|
||||
ln -s /etc/passwd "$tmp/package/kaidi-erp-1.2.3/unsafe-link"
|
||||
fi
|
||||
tar -czf "$tmp/kaidi-erp-1.2.3.tar.gz" -C "$tmp/package" kaidi-erp-1.2.3
|
||||
(cd "$tmp" && checksum_file kaidi-erp-1.2.3.tar.gz) > "$tmp/SHA256SUMS"
|
||||
openssl pkeyutl -sign -rawin -inkey "$tmp/private.pem" \
|
||||
-in "$tmp/SHA256SUMS" -out "$tmp/SHA256SUMS.sig"
|
||||
}
|
||||
|
||||
test_installer_verifies_signed_safe_archive() (
|
||||
local tmp
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-signature-test.XXXXXX")" || return 1
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
openssl genpkey -algorithm ED25519 -out "$tmp/private.pem" >/dev/null 2>&1 || return 1
|
||||
openssl pkey -in "$tmp/private.pem" -pubout -out "$tmp/public.pem" >/dev/null 2>&1 || return 1
|
||||
prepare_signed_archive "$tmp" || return 1
|
||||
|
||||
source "$PROJECT_ROOT/install.sh"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
TMP_DIR="$tmp"
|
||||
PUBLIC_KEY="$(<"$tmp/public.pem")"
|
||||
ARCHIVE_NAME=kaidi-erp-1.2.3.tar.gz
|
||||
ARCHIVE_PATH="$tmp/$ARCHIVE_NAME"
|
||||
verify_release
|
||||
)
|
||||
|
||||
test_installer_rejects_archive_symlinks() (
|
||||
local tmp
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-unsafe-test.XXXXXX")" || return 1
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
openssl genpkey -algorithm ED25519 -out "$tmp/private.pem" >/dev/null 2>&1 || return 1
|
||||
openssl pkey -in "$tmp/private.pem" -pubout -out "$tmp/public.pem" >/dev/null 2>&1 || return 1
|
||||
prepare_signed_archive "$tmp" 1 || return 1
|
||||
|
||||
source "$PROJECT_ROOT/install.sh"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
TMP_DIR="$tmp"
|
||||
PUBLIC_KEY="$(<"$tmp/public.pem")"
|
||||
ARCHIVE_NAME=kaidi-erp-1.2.3.tar.gz
|
||||
ARCHIVE_PATH="$tmp/$ARCHIVE_NAME"
|
||||
! (verify_release) >/dev/null 2>&1
|
||||
)
|
||||
|
||||
test_stable_channel_rejects_prerelease_tag() (
|
||||
local tmp
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-prerelease-test.XXXXXX")" || return 1
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
printf 'OA_UPDATE_GITEA_BASE_URL=https://example.test\n' > "$tmp/erp.env"
|
||||
ERP_INSTALL_ROOT="$tmp" ERP_CONFIG_FILE="$tmp/erp.env" source "$PROJECT_ROOT/distribution/bin/erp-update"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
printf '%s\n' \
|
||||
'{"tag_name":"v2.0.0-rc.1","draft":false,"prerelease":false,"assets":[' \
|
||||
'{"name":"kaidi-erp-2.0.0-rc.1.tar.gz","browser_download_url":"https://example.test/app"},' \
|
||||
'{"name":"SHA256SUMS","browser_download_url":"https://example.test/sums"},' \
|
||||
'{"name":"SHA256SUMS.sig","browser_download_url":"https://example.test/sig"}]}' \
|
||||
> "$tmp/release.json"
|
||||
CHANNEL=stable
|
||||
! select_release "$tmp/release.json" '' "$tmp/selection" >/dev/null 2>&1
|
||||
)
|
||||
|
||||
prepare_update_release_archive() {
|
||||
local tmp="$1" version="$2"
|
||||
local root="$tmp/package/kaidi-erp-$version"
|
||||
mkdir -p "$root/app" "$root/bin" "$root/config" "$tmp/assets"
|
||||
printf 'mock jar %s\n' "$version" > "$root/app/kaidi-erp.jar"
|
||||
cp "$PROJECT_ROOT/distribution/bin/erp-run" "$root/bin/erp-run"
|
||||
cp "$PROJECT_ROOT/distribution/bin/erp-update" "$root/bin/erp-update"
|
||||
chmod +x "$root/bin/erp-run" "$root/bin/erp-update"
|
||||
printf '%s\n' "$version" > "$root/VERSION"
|
||||
printf '{"version":"%s","database":"postgresql","rollbackCompatible":true}\n' \
|
||||
"$version" > "$root/manifest.json"
|
||||
|
||||
local archive="kaidi-erp-$version.tar.gz"
|
||||
tar -czf "$tmp/assets/$archive" -C "$tmp/package" "kaidi-erp-$version"
|
||||
(cd "$tmp/assets" && checksum_file "$archive") > "$tmp/assets/SHA256SUMS"
|
||||
: > "$tmp/assets/SHA256SUMS.sig"
|
||||
}
|
||||
|
||||
test_installer_downloads_and_installs_signed_release() (
|
||||
local version=3.0.0 tmp server_pid=""
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-install-e2e.XXXXXX")" || return 1
|
||||
cleanup_install_scenario() {
|
||||
[[ -z "$server_pid" ]] || kill "$server_pid" 2>/dev/null || true
|
||||
[[ -z "$server_pid" ]] || wait "$server_pid" 2>/dev/null || true
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
trap cleanup_install_scenario EXIT
|
||||
|
||||
prepare_update_release_archive "$tmp" "$version" || return 1
|
||||
openssl genpkey -algorithm ED25519 -out "$tmp/private.pem" >/dev/null 2>&1 || return 1
|
||||
openssl pkey -in "$tmp/private.pem" -pubout -out "$tmp/public.pem" >/dev/null 2>&1 || return 1
|
||||
openssl pkeyutl -sign -rawin -inkey "$tmp/private.pem" \
|
||||
-in "$tmp/assets/SHA256SUMS" -out "$tmp/assets/SHA256SUMS.sig" || return 1
|
||||
|
||||
python3 - "$tmp" "$version" <<'PY' > "$tmp/server.log" 2>&1 &
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
root, version = sys.argv[1:]
|
||||
assets = os.path.join(root, "assets")
|
||||
archive = f"kaidi-erp-{version}.tar.gz"
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def send_bytes(self, status, body, content_type="application/octet-stream"):
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", content_type)
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == "/api/v1/repos/awaioi/ERP/releases/latest":
|
||||
base = f"http://127.0.0.1:{self.server.server_port}/assets"
|
||||
payload = {
|
||||
"tag_name": "v" + version,
|
||||
"draft": False,
|
||||
"prerelease": False,
|
||||
"assets": [
|
||||
{"name": archive, "browser_download_url": base + "/" + archive},
|
||||
{"name": "SHA256SUMS", "browser_download_url": base + "/SHA256SUMS"},
|
||||
{"name": "SHA256SUMS.sig", "browser_download_url": base + "/SHA256SUMS.sig"},
|
||||
],
|
||||
}
|
||||
self.send_bytes(200, json.dumps(payload).encode(), "application/json")
|
||||
return
|
||||
if self.path.startswith("/assets/"):
|
||||
name = self.path.removeprefix("/assets/")
|
||||
if name not in {archive, "SHA256SUMS", "SHA256SUMS.sig"}:
|
||||
self.send_bytes(404, b"not found", "text/plain")
|
||||
return
|
||||
with open(os.path.join(assets, name), "rb") as handle:
|
||||
self.send_bytes(200, handle.read())
|
||||
return
|
||||
self.send_bytes(404, b"not found", "text/plain")
|
||||
|
||||
def log_message(self, *_):
|
||||
pass
|
||||
|
||||
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
|
||||
with open(os.path.join(root, "server.port"), "w", encoding="ascii") as handle:
|
||||
handle.write(str(server.server_port))
|
||||
server.serve_forever()
|
||||
PY
|
||||
server_pid=$!
|
||||
|
||||
local attempt=0
|
||||
while [[ ! -s "$tmp/server.port" && "$attempt" -lt 100 ]]; do
|
||||
sleep 0.02
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
[[ -s "$tmp/server.port" ]] || return 1
|
||||
local port
|
||||
port="$(<"$tmp/server.port")"
|
||||
|
||||
source "$PROJECT_ROOT/install.sh"
|
||||
trap cleanup_install_scenario EXIT
|
||||
GITEA_BASE_URL="http://127.0.0.1:$port"
|
||||
REPOSITORY=awaioi/ERP
|
||||
ALLOW_INSECURE=1
|
||||
INSTALL_ROOT="$tmp/install"
|
||||
ERP_CONFIG_ROOT="$tmp/config"
|
||||
ERP_STATE_ROOT="$tmp/state"
|
||||
ERP_LOG_ROOT="$tmp/log"
|
||||
DB_MODE=existing
|
||||
NO_SERVICE=0
|
||||
PUBLIC_KEY="$(<"$tmp/public.pem")"
|
||||
|
||||
detect_platform() { PLATFORM=darwin; }
|
||||
install_dependencies() { return 0; }
|
||||
configure_existing_postgres() {
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=5432
|
||||
DB_NAME=kaidi_erp
|
||||
DB_USER=kaidi_erp
|
||||
DB_PASSWORD=test-password
|
||||
DB_SSLMODE=require
|
||||
}
|
||||
validate_postgres() { return 0; }
|
||||
install_service() { return 0; }
|
||||
wait_for_health() { return 0; }
|
||||
|
||||
main > "$tmp/install.log" 2>&1 || return 1
|
||||
|
||||
[[ "$(readlink "$INSTALL_ROOT/current")" == "releases/$version" ]] || return 1
|
||||
[[ -r "$INSTALL_ROOT/current/app/kaidi-erp.jar" ]] || return 1
|
||||
(
|
||||
source "$ERP_CONFIG_ROOT/erp.env"
|
||||
[[ "$SPRING_PROFILES_ACTIVE" == "postgres" ]]
|
||||
[[ "$OA_UPDATE_ENABLED" == "true" ]]
|
||||
[[ "$OA_UPDATE_GITEA_BASE_URL" == "http://127.0.0.1:$port" ]]
|
||||
[[ "$OA_DB_URL" == "jdbc:postgresql://127.0.0.1:5432/kaidi_erp?sslmode=require" ]]
|
||||
[[ "$ERP_PGSSLMODE" == "require" ]]
|
||||
)
|
||||
)
|
||||
|
||||
run_update_scenario() (
|
||||
local mode="$1" version=2.0.0
|
||||
local tmp server_pid="" supervisor_pid=""
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-update-e2e.XXXXXX")" || return 1
|
||||
cleanup_scenario() {
|
||||
[[ -z "$supervisor_pid" ]] || kill "$supervisor_pid" 2>/dev/null || true
|
||||
[[ -z "$server_pid" ]] || kill "$server_pid" 2>/dev/null || true
|
||||
[[ -z "$supervisor_pid" ]] || wait "$supervisor_pid" 2>/dev/null || true
|
||||
[[ -z "$server_pid" ]] || wait "$server_pid" 2>/dev/null || true
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
trap cleanup_scenario EXIT
|
||||
|
||||
prepare_update_release_archive "$tmp" "$version" || return 1
|
||||
mkdir -p "$tmp/releases/1.0.0" "$tmp/run" "$tmp/state"
|
||||
printf '1.0.0\n' > "$tmp/releases/1.0.0/VERSION"
|
||||
ln -s releases/1.0.0 "$tmp/current"
|
||||
|
||||
python3 - "$tmp" "$mode" <<'PY' > "$tmp/server.log" 2>&1 &
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
root, mode = sys.argv[1:]
|
||||
assets = os.path.join(root, "assets")
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def send_bytes(self, status, body, content_type="application/octet-stream"):
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", content_type)
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == "/api/v1/repos/awaioi/ERP/releases/latest":
|
||||
base = f"http://127.0.0.1:{self.server.server_port}"
|
||||
payload = {
|
||||
"tag_name": "v2.0.0",
|
||||
"draft": False,
|
||||
"prerelease": False,
|
||||
"assets": [
|
||||
{"name": "kaidi-erp-2.0.0.tar.gz", "browser_download_url": base + "/assets/kaidi-erp-2.0.0.tar.gz"},
|
||||
{"name": "SHA256SUMS", "browser_download_url": base + "/assets/SHA256SUMS"},
|
||||
{"name": "SHA256SUMS.sig", "browser_download_url": base + "/assets/SHA256SUMS.sig"},
|
||||
],
|
||||
}
|
||||
self.send_bytes(200, json.dumps(payload).encode(), "application/json")
|
||||
return
|
||||
if self.path == "/health":
|
||||
current = os.path.basename(os.path.realpath(os.path.join(root, "current")))
|
||||
healthy = current == "2.0.0" if mode == "success" else current == "1.0.0"
|
||||
self.send_bytes(200 if healthy else 503, b'{"status":"UP"}' if healthy else b'{"status":"DOWN"}', "application/json")
|
||||
return
|
||||
if self.path.startswith("/assets/"):
|
||||
name = self.path.removeprefix("/assets/")
|
||||
if name not in {"kaidi-erp-2.0.0.tar.gz", "SHA256SUMS", "SHA256SUMS.sig"}:
|
||||
self.send_bytes(404, b"not found", "text/plain")
|
||||
return
|
||||
with open(os.path.join(assets, name), "rb") as handle:
|
||||
self.send_bytes(200, handle.read())
|
||||
return
|
||||
self.send_bytes(404, b"not found", "text/plain")
|
||||
|
||||
def log_message(self, *_):
|
||||
pass
|
||||
|
||||
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
|
||||
with open(os.path.join(root, "server.port"), "w", encoding="ascii") as handle:
|
||||
handle.write(str(server.server_port))
|
||||
server.serve_forever()
|
||||
PY
|
||||
server_pid=$!
|
||||
|
||||
local attempt=0
|
||||
while [[ ! -s "$tmp/server.port" && "$attempt" -lt 100 ]]; do
|
||||
sleep 0.02
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
[[ -s "$tmp/server.port" ]] || return 1
|
||||
local port
|
||||
port="$(<"$tmp/server.port")"
|
||||
|
||||
(
|
||||
child=""
|
||||
trap '[[ -z "$child" ]] || kill "$child" 2>/dev/null || true' EXIT
|
||||
trap 'exit 0' TERM INT
|
||||
while :; do
|
||||
sleep 300 &
|
||||
child=$!
|
||||
printf '%s\n' "$child" > "$tmp/run/app.pid"
|
||||
wait "$child" 2>/dev/null || true
|
||||
child=""
|
||||
sleep 0.05
|
||||
done
|
||||
) &
|
||||
supervisor_pid=$!
|
||||
|
||||
attempt=0
|
||||
while [[ ! -s "$tmp/run/app.pid" && "$attempt" -lt 100 ]]; do
|
||||
sleep 0.02
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
[[ -s "$tmp/run/app.pid" ]] || return 1
|
||||
|
||||
{
|
||||
printf 'ERP_RUN_DIR=%q\n' "$tmp/run"
|
||||
printf 'OA_UPDATE_STATE_FILE=%q\n' "$tmp/state/update.json"
|
||||
printf 'OA_UPDATE_GITEA_BASE_URL=http://127.0.0.1:%s\n' "$port"
|
||||
printf 'OA_UPDATE_ALLOW_INSECURE_HTTP=true\n'
|
||||
printf 'OA_UPDATE_REPOSITORY=awaioi/ERP\n'
|
||||
printf 'ERP_HEALTH_URL=http://127.0.0.1:%s/health\n' "$port"
|
||||
printf 'ERP_UPDATE_REQUIRE_SIGNATURE=false\n'
|
||||
printf 'ERP_UPDATE_BACKUP_MODE=none\n'
|
||||
printf 'ERP_UPDATE_HEALTH_TIMEOUT_SECONDS=3\n'
|
||||
printf 'ERP_UPDATE_HEALTH_POLL_SECONDS=1\n'
|
||||
} > "$tmp/erp.env"
|
||||
|
||||
local status=0 phase current
|
||||
ERP_INSTALL_ROOT="$tmp" ERP_CONFIG_FILE="$tmp/erp.env" \
|
||||
"$PROJECT_ROOT/distribution/bin/erp-update" install "$version" \
|
||||
> "$tmp/update.log" 2>&1 || status=$?
|
||||
phase="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["phase"])' "$tmp/state/update.json")" \
|
||||
|| return 1
|
||||
current="$(readlink "$tmp/current")"
|
||||
|
||||
if [[ "$mode" == "success" ]]; then
|
||||
[[ "$status" == "0" && "$phase" == "SUCCEEDED" && "$current" == "releases/2.0.0" ]]
|
||||
else
|
||||
[[ "$status" != "0" && "$phase" == "ROLLED_BACK" && "$current" == "releases/1.0.0" ]]
|
||||
fi
|
||||
)
|
||||
|
||||
test_update_helper_installs_healthy_release() (
|
||||
run_update_scenario success
|
||||
)
|
||||
|
||||
test_update_helper_rolls_back_unhealthy_release() (
|
||||
run_update_scenario rollback
|
||||
)
|
||||
|
||||
test_update_lock_rejects_concurrent_process() (
|
||||
local tmp
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-lock-test.XXXXXX")" || return 1
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
mkdir -p "$tmp/bin" "$tmp/run" "$tmp/state"
|
||||
printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
'printf '\''%s\n'\'' "$$" > "$MOCK_CURL_PID_FILE"' \
|
||||
'trap '\''exit 1'\'' TERM INT' \
|
||||
'sleep 30' \
|
||||
'exit 1' > "$tmp/bin/curl"
|
||||
chmod +x "$tmp/bin/curl"
|
||||
{
|
||||
printf 'ERP_RUN_DIR=%q\n' "$tmp/run"
|
||||
printf 'OA_UPDATE_STATE_FILE=%q\n' "$tmp/state/update.json"
|
||||
printf 'OA_UPDATE_GITEA_BASE_URL=%q\n' 'http://127.0.0.1:1'
|
||||
printf 'OA_UPDATE_ALLOW_INSECURE_HTTP=true\n'
|
||||
printf 'OA_UPDATE_REPOSITORY=awaioi/ERP\n'
|
||||
} > "$tmp/erp.env"
|
||||
|
||||
PATH="$tmp/bin:$PATH" MOCK_CURL_PID_FILE="$tmp/curl.pid" \
|
||||
ERP_INSTALL_ROOT="$tmp" ERP_CONFIG_FILE="$tmp/erp.env" \
|
||||
"$PROJECT_ROOT/distribution/bin/erp-update" install > "$tmp/first.log" 2>&1 &
|
||||
local first=$! attempt=0
|
||||
while [[ ! -s "$tmp/run/update.lock" && "$attempt" -lt 100 ]]; do
|
||||
sleep 0.02
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
[[ -s "$tmp/run/update.lock" ]] || { kill "$first" 2>/dev/null || true; return 1; }
|
||||
|
||||
local output status=0 rejected=0
|
||||
output="$(PATH="$tmp/bin:$PATH" MOCK_CURL_PID_FILE="$tmp/curl-2.pid" \
|
||||
ERP_INSTALL_ROOT="$tmp" ERP_CONFIG_FILE="$tmp/erp.env" \
|
||||
"$PROJECT_ROOT/distribution/bin/erp-update" install 2>&1)" || status=$?
|
||||
[[ "$status" -ne 0 && "$output" == *'已有更新任务正在执行'* ]] && rejected=1
|
||||
|
||||
[[ ! -r "$tmp/curl.pid" ]] || kill "$(<"$tmp/curl.pid")" 2>/dev/null || true
|
||||
kill "$first" 2>/dev/null || true
|
||||
wait "$first" 2>/dev/null || true
|
||||
[[ "$rejected" == "1" ]]
|
||||
)
|
||||
|
||||
test_noninteractive_installer_reports_missing_password() (
|
||||
local output status=0
|
||||
output="$(ERP_INSTALL_NON_INTERACTIVE=1 bash -c '
|
||||
root="$1"
|
||||
set --
|
||||
source "$root/install.sh"
|
||||
unset ERP_DB_PASSWORD DB_PASSWORD
|
||||
configure_existing_postgres
|
||||
' _ "$PROJECT_ROOT" 2>&1)" || status=$?
|
||||
[[ "$status" -ne 0 && "$output" == *'database password is required'* ]]
|
||||
)
|
||||
|
||||
test_installer_requires_explicit_gitea_url() (
|
||||
local output status=0
|
||||
output="$(ERP_GITEA_BASE_URL= bash -c '
|
||||
root="$1"
|
||||
set --
|
||||
source "$root/install.sh"
|
||||
GITEA_BASE_URL=
|
||||
main
|
||||
' _ "$PROJECT_ROOT" 2>&1)" || status=$?
|
||||
[[ "$status" -ne 0 && "$output" == *'Gitea URL is required'* ]]
|
||||
)
|
||||
|
||||
test_no_service_install_disables_online_update() (
|
||||
local tmp
|
||||
tmp="$(mktemp -d "${TMPDIR:-/tmp}/erp-no-service-test.XXXXXX")" || return 1
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
source "$PROJECT_ROOT/install.sh"
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
CONFIG_ROOT="$tmp/config"
|
||||
STATE_ROOT="$tmp/state"
|
||||
INSTALL_ROOT="$tmp/install"
|
||||
PLATFORM=darwin
|
||||
NO_SERVICE=1
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=5432
|
||||
DB_NAME=kaidi_erp
|
||||
DB_USER=kaidi_erp
|
||||
DB_PASSWORD=test-password
|
||||
DB_SSLMODE=require
|
||||
mkdir -p "$CONFIG_ROOT" "$STATE_ROOT" "$INSTALL_ROOT"
|
||||
|
||||
write_configuration || return 1
|
||||
|
||||
grep -Fqx 'OA_UPDATE_ENABLED=false' "$CONFIG_ROOT/erp.env"
|
||||
)
|
||||
|
||||
run_test 'erp-run preserves Java option arguments' test_erp_run_preserves_java_option_arguments
|
||||
run_test 'installer accepts a correctly signed archive' test_installer_verifies_signed_safe_archive
|
||||
run_test 'installer rejects symlinks in release archives' test_installer_rejects_archive_symlinks
|
||||
run_test 'stable update channel rejects prerelease tags' test_stable_channel_rejects_prerelease_tag
|
||||
run_test 'installer downloads and installs a signed release end to end' test_installer_downloads_and_installs_signed_release
|
||||
run_test 'update helper installs a healthy release end to end' test_update_helper_installs_healthy_release
|
||||
run_test 'update helper rolls back an unhealthy release end to end' test_update_helper_rolls_back_unhealthy_release
|
||||
run_test 'update helper rejects a concurrent process' test_update_lock_rejects_concurrent_process
|
||||
run_test 'noninteractive install reports a missing database password' test_noninteractive_installer_reports_missing_password
|
||||
run_test 'installer requires an explicit Gitea URL' test_installer_requires_explicit_gitea_url
|
||||
run_test 'no-service install disables online update' test_no_service_install_disables_online_update
|
||||
|
||||
printf 'RESULT pass=%s fail=%s\n' "$PASS" "$FAIL"
|
||||
[[ "$FAIL" -eq 0 ]]
|
||||
Reference in New Issue
Block a user