diff --git a/integrations/opencode/marmot/tests/test_installer.sh b/integrations/opencode/marmot/tests/test_installer.sh index 6535692f..8c1040e7 100755 --- a/integrations/opencode/marmot/tests/test_installer.sh +++ b/integrations/opencode/marmot/tests/test_installer.sh @@ -8,6 +8,149 @@ allow_hex="$(printf '11%.0s' {1..32})" [ -x "$installer" ] bash -n "$installer" +assert_log_contains() { + local log_file="$1" + local expected="$2" + local line + while IFS= read -r line; do + [ "$line" != "$expected" ] || return 0 + done <"$log_file" + echo "missing systemctl call: $expected" >&2 + return 1 +} + +assert_log_excludes() { + local log_file="$1" + local unexpected="$2" + local line + while IFS= read -r line; do + if [ "$line" = "$unexpected" ]; then + echo "unexpected systemctl call: $unexpected" >&2 + return 1 + fi + done <"$log_file" +} + +run_linux_service_case() { + local fixture_root="$1" + local active="$2" + local log_file="$3" + local mock_bin="$fixture_root/mock-bin" + shift 3 + + : >"$log_file" + SYSTEMCTL_ACTIVE="$active" \ + SYSTEMCTL_LOG="$log_file" \ + HOME="$fixture_root/home" \ + MARMOT_HOME="$fixture_root/marmot-home" \ + MARMOT_INSTALL_PREFIX="$fixture_root/install" \ + PATH="$mock_bin:/usr/bin:/bin" \ + WN_AGENT_SHA="9.9.9" \ + MARMOT_RELEASE_TAG="wn-agent-v9.9.9-test" \ + WN_OPENCODE_BIN="/bin/echo" \ + "$installer" --yes --allow-welcomer "$allow_hex" "$@" >/dev/null 2>&1 +} + +if [ "$(uname -s)" = Linux ]; then + fixture_root="$(mktemp -d)" + trap 'rm -rf "$fixture_root"' EXIT + mock_bin="$fixture_root/mock-bin" + mkdir -p "$mock_bin" + + cat >"$mock_bin/curl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +destination="" +url="" +while [ "$#" -gt 0 ]; do + case "$1" in + -o) destination="$2"; shift 2 ;; + http*) url="$1"; shift ;; + *) shift ;; + esac +done +if [[ "$url" == *.sha256 ]]; then + printf '%s\n' fixture-hash >"$destination" +else + : >"$destination" +fi +EOF + + cat >"$mock_bin/shasum" <<'EOF' +#!/usr/bin/env bash +printf '%s\n' fixture-hash +EOF + + cat >"$mock_bin/tar" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +archive="" +destination="" +while [ "$#" -gt 0 ]; do + case "$1" in + -xzf) archive="$2"; shift 2 ;; + -C) destination="$2"; shift 2 ;; + *) shift ;; + esac +done +archive_name="$(basename "$archive")" +case "$archive_name" in + wn-agent-*) binary=wn-agent ;; + wn-opencode-*) binary=wn-opencode ;; + *) exit 1 ;; +esac +platform="${archive_name#"$binary-"}" +platform="${platform%-9.9.9.tar.gz}" +mkdir -p "$destination/$binary-$platform" +cat >"$destination/$binary-$platform/$binary" <<'SCRIPT' +#!/usr/bin/env bash +if [ "${1:-}" = bootstrap ]; then + printf '%s\n' '{"account_id_hex":"aa","welcomer_account_ids_hex":["bb"]}' +fi +SCRIPT +chmod +x "$destination/$binary-$platform/$binary" +EOF + + cat >"$mock_bin/systemctl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +printf '%s\n' "$*" >>"$SYSTEMCTL_LOG" +if [ "${1:-}" = --user ] && [ "${2:-}" = is-active ]; then + [ "$SYSTEMCTL_ACTIVE" = 1 ] +fi +EOF + + cat >"$mock_bin/sleep" <<'EOF' +#!/usr/bin/env bash +exit 0 +EOF + chmod +x "$mock_bin"/* + + fresh_log="$fixture_root/systemctl-fresh.log" + run_linux_service_case "$fixture_root" 0 "$fresh_log" + assert_log_contains "$fresh_log" "--user enable --now wn-agent-harnesses.service" + assert_log_contains "$fresh_log" "--user enable --now wn-opencode.service" + assert_log_excludes "$fresh_log" "--user restart wn-agent-harnesses.service" + assert_log_excludes "$fresh_log" "--user restart wn-opencode.service" + + upgrade_log="$fixture_root/systemctl-upgrade.log" + run_linux_service_case "$fixture_root" 1 "$upgrade_log" + assert_log_contains "$upgrade_log" "--user enable wn-agent-harnesses.service" + assert_log_contains "$upgrade_log" "--user restart wn-agent-harnesses.service" + assert_log_contains "$upgrade_log" "--user enable wn-opencode.service" + assert_log_contains "$upgrade_log" "--user restart wn-opencode.service" + assert_log_excludes "$upgrade_log" "--user enable --now wn-agent-harnesses.service" + assert_log_excludes "$upgrade_log" "--user enable --now wn-opencode.service" + + no_start_opencode_log="$fixture_root/systemctl-no-start-opencode.log" + run_linux_service_case "$fixture_root" 1 "$no_start_opencode_log" --no-start-wn-opencode + assert_log_contains "$no_start_opencode_log" "--user restart wn-agent-harnesses.service" + assert_log_excludes "$no_start_opencode_log" "--user is-active --quiet wn-opencode.service" + assert_log_excludes "$no_start_opencode_log" "--user enable wn-opencode.service" + assert_log_excludes "$no_start_opencode_log" "--user enable --now wn-opencode.service" + assert_log_excludes "$no_start_opencode_log" "--user restart wn-opencode.service" +fi + installer_dry_run="$( env -u MARMOT_HOME -u MARMOT_AGENT_SOCKET \ WN_AGENT_SHA="9.9.9" \ @@ -138,6 +281,14 @@ case "$(uname -s)" in *"would install systemd user unit"*"wn-opencode.service"* ) ;; *) echo "opencode installer service dry-run did not plan wn-opencode systemd unit" >&2; exit 1;; esac + case "$installer_service_dry_run" in + *"would enable/start, or restart if already active, systemd user service: wn-agent-harnesses.service"* ) ;; + *) echo "opencode installer service dry-run did not describe wn-agent upgrade restart" >&2; exit 1;; + esac + case "$installer_service_dry_run" in + *"would enable/start, or restart if already active, systemd user service: wn-opencode.service"* ) ;; + *) echo "opencode installer service dry-run did not describe wn-opencode upgrade restart" >&2; exit 1;; + esac ;; esac case "$installer_no_start_dry_run" in diff --git a/scripts/install-opencode-marmot.sh b/scripts/install-opencode-marmot.sh index 4b261ba5..2bf05eaa 100755 --- a/scripts/install-opencode-marmot.sh +++ b/scripts/install-opencode-marmot.sh @@ -473,6 +473,16 @@ systemd_quote() { printf '"%s"' "$value" } +enable_or_restart_systemd_user_service() { + local service="$1" + if systemctl --user is-active --quiet "$service"; then + run systemctl --user enable "$service" || return 1 + run systemctl --user restart "$service" || return 1 + else + run systemctl --user enable --now "$service" || return 1 + fi +} + install_linux_wn_agent_service() { local service_dir service program relay service_dir="$HOME/.config/systemd/user" @@ -481,7 +491,7 @@ install_linux_wn_agent_service() { if [ "$DRY_RUN" -eq 1 ]; then log "would install systemd user unit $service" - log "would run: systemctl --user enable --now $MARMOT_AGENT_SERVICE_NAME.service" + log "would enable/start, or restart if already active, systemd user service: $MARMOT_AGENT_SERVICE_NAME.service" return 0 fi @@ -510,7 +520,7 @@ install_linux_wn_agent_service() { chmod 600 "$service" || return 1 run systemctl --user daemon-reload || return 1 - run systemctl --user enable --now "$MARMOT_AGENT_SERVICE_NAME.service" || return 1 + enable_or_restart_systemd_user_service "$MARMOT_AGENT_SERVICE_NAME.service" || return 1 log "installed and started systemd user service: $MARMOT_AGENT_SERVICE_NAME.service" } @@ -522,7 +532,7 @@ install_linux_opencode_service() { if [ "$DRY_RUN" -eq 1 ]; then log "would install systemd user unit $service" - log "would run: systemctl --user enable --now wn-opencode.service" + log "would enable/start, or restart if already active, systemd user service: wn-opencode.service" return 0 fi @@ -557,7 +567,7 @@ install_linux_opencode_service() { chmod 600 "$service" || return 1 run systemctl --user daemon-reload || return 1 - run systemctl --user enable --now wn-opencode.service || return 1 + enable_or_restart_systemd_user_service wn-opencode.service || return 1 log "installed and started systemd user service: wn-opencode.service" }