项目文件夹

文件
wehub-resource-sync 9e8f1bbeed
Dashboard / frontend (push) Failing after 0s
Dashboard / api (push) Failing after 0s
Lint PowerShell / powershell-lint (ubuntu-latest) (push) Failing after 1s
Python Lint / Lint Python with Ruff (push) Failing after 1s
ShellCheck / Lint shell scripts (push) Failing after 1s
Matrix Smoke / linux-smoke (push) Failing after 1s
Matrix Smoke / distro: cachyos (push) Failing after 15s
Matrix Smoke / distro: linux-mint-21.3 (push) Failing after 15s
Matrix Smoke / distro: debian-12 (push) Failing after 5m21s
Matrix Smoke / distro: fedora-41 (push) Failing after 4m56s
Matrix Smoke / distro: ubuntu-24.04 (push) Failing after 2m13s
Matrix Smoke / distro: rocky-9 (push) Failing after 10m39s
Matrix Smoke / distro: manjaro (push) Failing after 12m11s
Matrix Smoke / distro: opensuse-tw (push) Failing after 11m53s
Matrix Smoke / distro: archlinux (push) Failing after 20m3s
Matrix Smoke / distro: ubuntu-22.04 (push) Failing after 13m49s
Validate .env Schema / tier-1-env-validation (push) Successful in 52s
Validate .env Schema / tier-2-env-validation (push) Successful in 44s
Validate .env Schema / tier-3-env-validation (push) Successful in 52s
Validate .env Schema / tier-4-env-validation (push) Successful in 51s
Validate Extensions Catalog / Check catalog is up-to-date (push) Failing after 9m47s
Secret Scan / Scan for secrets (push) Failing after 21m4s
Validate Docker Compose / Validate Docker Compose files (push) Has been cancelled
Python Type Check / Type check with mypy (push) Has been cancelled
Validate .env Schema / tier-0-env-validation (push) Has been cancelled
Test Linux / integration-smoke (push) Has been cancelled
Lint PowerShell / powershell-lint (windows-latest) (push) Has been cancelled
Matrix Smoke / macos-smoke (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:31:33 +08:00

367 行
16 KiB
Bash

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
#!/bin/bash
# Tests for ods.ps1 enable/disable command parity (issue #1699)
# These are hermetic shell tests that exercise the PowerShell logic
# by stubbing the filesystem layout and verifying file state changes.
# They do NOT require Docker, PowerShell, or a live Windows install.
#
# Run: bash ods/tests/test-windows-cli-enable-disable.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
ODS_PS1="$ROOT_DIR/installers/windows/ods.ps1"
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
pass() { echo -e "${GREEN}${NC} $1"; }
fail() { echo -e "${RED}${NC} $1"; exit 1; }
info() { echo -e "${BLUE}${NC} $1"; }
# ── Static checks (no PowerShell needed) ─────────────────────────────────────
info "Static: ods.ps1 exists and is non-empty"
[[ -f "$ODS_PS1" ]] || fail "ods.ps1 not found at $ODS_PS1"
[[ -s "$ODS_PS1" ]] || fail "ods.ps1 is empty"
pass "ods.ps1 exists"
info "Static: header comment documents enable/disable"
grep -q 'enable.*Enable an extension' "$ODS_PS1" \
|| fail "Header comment missing 'enable' usage line"
grep -q 'disable.*Disable an extension' "$ODS_PS1" \
|| fail "Header comment missing 'disable' usage line"
pass "Header comment documents enable and disable"
info "Static: Invoke-Enable function defined"
grep -q 'function Invoke-Enable' "$ODS_PS1" \
|| fail "Invoke-Enable function not found in ods.ps1"
pass "Invoke-Enable function present"
info "Static: Invoke-Disable function defined"
grep -q 'function Invoke-Disable' "$ODS_PS1" \
|| fail "Invoke-Disable function not found in ods.ps1"
pass "Invoke-Disable function present"
info "Static: Test-ODSInstallFiles helper defined (Docker-free validation)"
grep -q 'function Test-ODSInstallFiles' "$ODS_PS1" \
|| fail "Test-ODSInstallFiles not found -- enable/disable will require Docker"
pass "Test-ODSInstallFiles helper present"
info "Static: Invoke-Enable uses Test-ODSInstallFiles, not Test-Install"
# Extract the Invoke-Enable function body and assert it doesn't call Test-Install
awk '/^function Invoke-Enable/,/^}/' "$ODS_PS1" \
| grep -q 'Test-ODSInstallFiles' \
|| fail "Invoke-Enable does not call Test-ODSInstallFiles"
awk '/^function Invoke-Enable/,/^}/' "$ODS_PS1" \
| grep -qv 'Test-Install[^F]' \
|| fail "Invoke-Enable still calls Test-Install (requires Docker)"
pass "Invoke-Enable uses Docker-free Test-ODSInstallFiles"
info "Static: Invoke-Disable uses Test-ODSInstallFiles, not Test-Install"
awk '/^function Invoke-Disable/,/^}/' "$ODS_PS1" \
| grep -q 'Test-ODSInstallFiles' \
|| fail "Invoke-Disable does not call Test-ODSInstallFiles"
pass "Invoke-Disable uses Docker-free Test-ODSInstallFiles"
info "Static: Invoke-Disable still attempts docker stop when Docker is running"
grep -q 'docker compose.*stop' "$ODS_PS1" \
|| fail "Invoke-Disable does not attempt docker stop"
pass "Invoke-Disable attempts docker stop when Docker is available"
info "Static: Invoke-Disable gracefully skips stop when Docker is offline"
grep -q 'Docker Desktop is not running.*skipping container stop' "$ODS_PS1" \
|| fail "Invoke-Disable does not have a Docker-offline warning"
pass "Invoke-Disable gracefully skips stop when Docker is offline"
info "Static: Rename+flags update runs regardless of Docker state in Invoke-Disable"
# The Rename-Item call must appear AFTER the docker-offline else branch
awk '/^function Invoke-Disable/,/^}/' "$ODS_PS1" \
| grep -q 'Rename-Item.*compose.yaml.disabled' \
|| fail "Rename-Item not found in Invoke-Disable body"
pass "Rename + flags update unconditional in Invoke-Disable"
info "Static: Update-ComposeFlags delegates to resolve-compose-stack.sh when available"
grep -q 'resolve-compose-stack.sh' "$ODS_PS1" \
|| fail "Update-ComposeFlags does not reference resolve-compose-stack.sh"
pass "Update-ComposeFlags references resolve-compose-stack.sh"
info "Static: Update-ComposeFlags has safe fallback when resolver not available"
grep -q 'fallback minimal swap\|fallback' "$ODS_PS1" \
|| fail "Update-ComposeFlags has no fallback path"
pass "Update-ComposeFlags has fallback path"
info "Static: Update-ComposeFlags preserves --env-file in resolver path"
grep -q 'env-file.*resolver\|--env-file .env.*newContent\|existingRaw.*--env-file' "$ODS_PS1" \
|| grep -q "Prepend --env-file" "$ODS_PS1" \
|| fail "Update-ComposeFlags does not preserve --env-file when using the resolver"
pass "Update-ComposeFlags preserves --env-file in resolver output"
info "Static: Update-ComposeFlags passes GPU_BACKEND to resolver"
grep -q 'gpuBackend\|gpu-backend' "$ODS_PS1" \
|| fail "Update-ComposeFlags does not pass GPU_BACKEND to resolver"
pass "Update-ComposeFlags passes GPU_BACKEND to resolver"
info "Static: Update-ComposeFlags fallback preserves backend overlay -f entries"
# The fallback keeps everything that doesn't match extensions/services
grep -q "extensions\[/\\\\\\\\\]services" "$ODS_PS1" \
|| grep -q 'extensions.*services' "$ODS_PS1" \
|| fail "Update-ComposeFlags fallback does not filter on extensions/services path"
pass "Update-ComposeFlags fallback preserves non-extension -f entries (backend overlays)"
info "Static: Update-ComposeFlags helper defined"
grep -q 'function Update-ComposeFlags' "$ODS_PS1" \
|| fail "Update-ComposeFlags not found in ods.ps1"
pass "Update-ComposeFlags helper present"
info "Static: Get-ExtensionServiceDir helper defined"
grep -q 'function Get-ExtensionServiceDir' "$ODS_PS1" \
|| fail "Get-ExtensionServiceDir not found in ods.ps1"
pass "Get-ExtensionServiceDir helper present"
info "Static: Get-ExtensionCategory helper defined"
grep -q 'function Get-ExtensionCategory' "$ODS_PS1" \
|| fail "Get-ExtensionCategory not found in ods.ps1"
pass "Get-ExtensionCategory helper present"
info "Static: command dispatcher wires 'enable'"
grep -q '"enable".*Invoke-Enable' "$ODS_PS1" \
|| fail "Dispatcher does not call Invoke-Enable for 'enable'"
pass "Dispatcher wires 'enable' -> Invoke-Enable"
info "Static: command dispatcher wires 'disable'"
grep -q '"disable".*Invoke-Disable' "$ODS_PS1" \
|| fail "Dispatcher does not call Invoke-Disable for 'disable'"
pass "Dispatcher wires 'disable' -> Invoke-Disable"
info "Static: Show-Help lists enable command"
grep -q 'enable.*service.*Enable an extension' "$ODS_PS1" \
|| fail "Show-Help does not list 'enable <service>'"
pass "Show-Help lists enable command"
info "Static: Show-Help lists disable command"
grep -q 'disable.*service.*Disable an extension' "$ODS_PS1" \
|| fail "Show-Help does not list 'disable <service>'"
pass "Show-Help lists disable command"
info "Static: Show-Help EXAMPLES mention enable"
grep -q 'enable comfyui' "$ODS_PS1" \
|| fail "Show-Help EXAMPLES do not include 'enable comfyui'"
pass "Show-Help EXAMPLES include enable comfyui"
info "Static: Show-Help EXAMPLES mention disable"
grep -q 'disable langfuse' "$ODS_PS1" \
|| fail "Show-Help EXAMPLES do not include 'disable langfuse'"
pass "Show-Help EXAMPLES include disable langfuse"
info "Static: Invoke-Enable handles already-enabled case"
grep -q 'already enabled' "$ODS_PS1" \
|| fail "Invoke-Enable does not handle already-enabled case"
pass "Invoke-Enable handles already-enabled case"
info "Static: Invoke-Disable handles already-disabled case"
grep -q 'already disabled' "$ODS_PS1" \
|| fail "Invoke-Disable does not handle already-disabled case"
pass "Invoke-Disable handles already-disabled case"
info "Static: core service guard in Invoke-Enable"
grep -q 'core.*always enabled' "$ODS_PS1" \
|| fail "Invoke-Enable does not guard core services"
pass "Invoke-Enable guards core services"
info "Static: core service guard in Invoke-Disable"
grep -q 'Cannot disable core service' "$ODS_PS1" \
|| fail "Invoke-Disable does not guard core services"
pass "Invoke-Disable guards core services"
# ── Filesystem simulation tests ───────────────────────────────────────────────
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
INSTALL_DIR="$TMP/ods"
EXT_SVC="$INSTALL_DIR/extensions/services"
mkdir -p "$EXT_SVC"
# ── simulate_update_compose_flags_fallback FLAGS_FILE EXT_DIR INSTALL_DIR
# Mirrors the PowerShell fallback path in bash.
simulate_update_compose_flags_fallback() {
local flags_file="$1"
local ext_dir="$2"
local install_dir="$3"
local existing
existing=$(cat "$flags_file")
local base_flags=()
local skip_next=false
local token
for token in $existing; do
if $skip_next; then skip_next=false; continue; fi
if [[ "$token" == "-f" ]]; then
base_flags+=("$token")
continue
fi
if [[ "$token" == *"extensions/services/"* ]]; then
# Remove the preceding -f we already added
unset 'base_flags[-1]'
continue
fi
base_flags+=("$token")
done
# Re-append only compose.yaml for enabled extensions
local svc_dir cf rel
for svc_dir in "$ext_dir"/*; do
[[ -d "$svc_dir" ]] || continue
cf="$svc_dir/compose.yaml"
if [[ -f "$cf" ]]; then
rel="${cf#$install_dir/}"
base_flags+=("-f" "$rel")
fi
done
printf '%s' "${base_flags[*]}" > "$flags_file"
}
# ── Test: backend overlays are preserved when an extension is toggled ─────────
info "Filesystem: backend overlay preserved when extension is enabled"
mkdir -p "$EXT_SVC/comfyui" "$EXT_SVC/langfuse"
touch "$EXT_SVC/comfyui/compose.yaml.disabled" # disabled initially
# langfuse also disabled
# .compose-flags as installer would write it: includes nvidia backend overlay
# but does NOT include comfyui (it was disabled at install time)
cat > "$INSTALL_DIR/.compose-flags" <<'EOF'
--env-file .env -f docker-compose.base.yml -f docker-compose.nvidia.yml
EOF
# Simulate enable: rename .disabled -> compose.yaml, then rebuild
mv "$EXT_SVC/comfyui/compose.yaml.disabled" "$EXT_SVC/comfyui/compose.yaml"
simulate_update_compose_flags_fallback "$INSTALL_DIR/.compose-flags" "$EXT_SVC" "$INSTALL_DIR"
result=$(cat "$INSTALL_DIR/.compose-flags")
# Backend overlays must still be present
echo "$result" | grep -q 'docker-compose.nvidia.yml' \
|| fail "Backend overlay (docker-compose.nvidia.yml) was dropped after enable"
echo "$result" | grep -q 'docker-compose.base.yml' \
|| fail "Base compose (docker-compose.base.yml) was dropped after enable"
# The newly enabled extension must appear
echo "$result" | grep -q 'extensions/services/comfyui/compose.yaml' \
|| fail "Enabled comfyui compose.yaml not found in flags after enable"
# Disabled langfuse must NOT appear
echo "$result" | grep -q 'langfuse' \
&& fail "Disabled langfuse appeared in flags after enable of comfyui"
# --env-file must survive
echo "$result" | grep -q -- '--env-file' \
|| fail "--env-file was dropped after enable"
pass "Backend overlay, base compose, and --env-file preserved after enable"
# ── Test: .compose-flags with AMD backend overlay preserved on disable ─────────
info "Filesystem: AMD backend overlay preserved when extension is disabled"
T2="$TMP/amd_install"
EXT_SVC2="$T2/extensions/services"
mkdir -p "$EXT_SVC2/comfyui" "$EXT_SVC2/langfuse"
touch "$EXT_SVC2/comfyui/compose.yaml" # comfyui enabled
touch "$EXT_SVC2/langfuse/compose.yaml" # langfuse enabled
# AMD-style .compose-flags with per-extension GPU overlay entries
cat > "$T2/.compose-flags" <<'EOF'
--env-file .env -f docker-compose.base.yml -f docker-compose.amd.yml -f extensions/services/comfyui/compose.yaml -f extensions/services/langfuse/compose.yaml
EOF
# Simulate disable langfuse: rename, then rebuild
mv "$EXT_SVC2/langfuse/compose.yaml" "$EXT_SVC2/langfuse/compose.yaml.disabled"
simulate_update_compose_flags_fallback "$T2/.compose-flags" "$EXT_SVC2" "$T2"
result2=$(cat "$T2/.compose-flags")
echo "$result2" | grep -q 'docker-compose.amd.yml' \
|| fail "AMD backend overlay was dropped after disable"
echo "$result2" | grep -q 'docker-compose.base.yml' \
|| fail "Base compose was dropped after disable"
echo "$result2" | grep -q 'extensions/services/comfyui/compose.yaml' \
|| fail "comfyui (still enabled) disappeared after disabling langfuse"
echo "$result2" | grep -q 'langfuse' \
&& fail "Disabled langfuse still present in flags after disable"
pass "AMD backend overlay preserved and disabled extension removed correctly"
# ── Test: Docker-offline enable path works (file-only operation) ──────────────
info "Filesystem: enable works when Docker is offline (file-only operation)"
T3="$TMP/offline_enable"
EXT_SVC3="$T3/extensions/services"
mkdir -p "$EXT_SVC3/comfyui"
touch "$T3/docker-compose.base.yml"
touch "$T3/docker-compose.nvidia.yml"
touch "$EXT_SVC3/comfyui/compose.yaml.disabled"
cat > "$T3/.compose-flags" <<'EOF'
--env-file .env -f docker-compose.base.yml -f docker-compose.nvidia.yml
EOF
# Simulate enable (rename only -- no docker call needed)
mv "$EXT_SVC3/comfyui/compose.yaml.disabled" "$EXT_SVC3/comfyui/compose.yaml"
simulate_update_compose_flags_fallback "$T3/.compose-flags" "$EXT_SVC3" "$T3"
[[ -f "$EXT_SVC3/comfyui/compose.yaml" ]] \
|| fail "compose.yaml not present after offline enable"
[[ ! -f "$EXT_SVC3/comfyui/compose.yaml.disabled" ]] \
|| fail "compose.yaml.disabled still exists after offline enable"
result3=$(cat "$T3/.compose-flags")
echo "$result3" | grep -q 'docker-compose.nvidia.yml' \
|| fail "Backend overlay dropped in offline enable"
echo "$result3" | grep -q 'extensions/services/comfyui/compose.yaml' \
|| fail "Extension not added to flags in offline enable"
pass "Enable succeeds offline: compose renamed, flags updated, no Docker needed"
# ── Test: Docker-offline disable path still renames and updates flags ──────────
info "Filesystem: disable completes when Docker is offline (rename still happens)"
T4="$TMP/offline_disable"
EXT_SVC4="$T4/extensions/services"
mkdir -p "$EXT_SVC4/comfyui"
touch "$T4/docker-compose.base.yml"
touch "$T4/docker-compose.nvidia.yml"
touch "$EXT_SVC4/comfyui/compose.yaml"
cat > "$T4/.compose-flags" <<'EOF'
--env-file .env -f docker-compose.base.yml -f docker-compose.nvidia.yml -f extensions/services/comfyui/compose.yaml
EOF
# Simulate disable when Docker is offline: docker stop is skipped, rename still runs
# (PowerShell: the else branch prints a warning but Rename-Item still executes)
DOCKER_AVAILABLE=false # simulate Docker offline
if $DOCKER_AVAILABLE; then
: # would run docker compose stop here
else
: # warning printed; rename still happens
fi
mv "$EXT_SVC4/comfyui/compose.yaml" "$EXT_SVC4/comfyui/compose.yaml.disabled"
simulate_update_compose_flags_fallback "$T4/.compose-flags" "$EXT_SVC4" "$T4"
[[ -f "$EXT_SVC4/comfyui/compose.yaml.disabled" ]] \
|| fail "compose.yaml.disabled not created in offline disable"
[[ ! -f "$EXT_SVC4/comfyui/compose.yaml" ]] \
|| fail "compose.yaml still present after offline disable"
result4=$(cat "$T4/.compose-flags")
echo "$result4" | grep -q 'docker-compose.nvidia.yml' \
|| fail "Backend overlay dropped in offline disable"
echo "$result4" | grep -q 'comfyui' \
&& fail "Disabled comfyui still in flags after offline disable"
pass "Disable completes offline: compose renamed, flags updated, no Docker needed"
# ── Basic rename sanity tests ──────────────────────────────────────────────────
info "Filesystem: enable renames compose.yaml.disabled -> compose.yaml"
SVCDIR="$TMP/newext_test"
mkdir -p "$SVCDIR"
touch "$SVCDIR/compose.yaml.disabled"
mv "$SVCDIR/compose.yaml.disabled" "$SVCDIR/compose.yaml"
[[ -f "$SVCDIR/compose.yaml" ]] || fail "compose.yaml not created after enable"
[[ ! -f "$SVCDIR/compose.yaml.disabled" ]] || fail "compose.yaml.disabled still exists after enable"
pass "Enable renames compose.yaml.disabled to compose.yaml"
info "Filesystem: disable renames compose.yaml -> compose.yaml.disabled"
mv "$SVCDIR/compose.yaml" "$SVCDIR/compose.yaml.disabled"
[[ -f "$SVCDIR/compose.yaml.disabled" ]] || fail "compose.yaml.disabled not created after disable"
[[ ! -f "$SVCDIR/compose.yaml" ]] || fail "compose.yaml still exists after disable"
pass "Disable renames compose.yaml to compose.yaml.disabled"
echo ""
echo -e "${GREEN}All windows-cli-enable-disable tests passed.${NC}"