|
| 1 | +import { spawnSync } from "node:child_process"; |
| 2 | +import { chmodSync, mkdirSync, writeFileSync } from "node:fs"; |
| 3 | +import path from "node:path"; |
| 4 | +import { afterEach, describe, expect, it } from "vitest"; |
| 5 | +import { cleanupTempDirs, makeTempDir } from "../helpers/temp-dir.js"; |
| 6 | + |
| 7 | +const BUILD_INFO_COMMIT_SCRIPT = path.resolve( |
| 8 | + "scripts/e2e/lib/parallels-package/build-info-commit.mjs", |
| 9 | +); |
| 10 | +const tempDirs: string[] = []; |
| 11 | + |
| 12 | +afterEach(() => { |
| 13 | + cleanupTempDirs(tempDirs); |
| 14 | +}); |
| 15 | + |
| 16 | +function shellQuote(value: string): string { |
| 17 | + return `'${value.replaceAll("'", "'\\''")}'`; |
| 18 | +} |
| 19 | + |
| 20 | +function runBash(script: string, env: NodeJS.ProcessEnv = {}) { |
| 21 | + return spawnSync("/bin/bash", ["-c", script], { |
| 22 | + cwd: process.cwd(), |
| 23 | + encoding: "utf8", |
| 24 | + env: { ...process.env, ...env }, |
| 25 | + }); |
| 26 | +} |
| 27 | + |
| 28 | +describe("Parallels lib helpers", () => { |
| 29 | + it("reads build-info commit metadata from the current package cwd", () => { |
| 30 | + const root = makeTempDir(tempDirs, "openclaw-parallels-build-info-"); |
| 31 | + |
| 32 | + const missingResult = spawnSync(process.execPath, [BUILD_INFO_COMMIT_SCRIPT], { |
| 33 | + cwd: root, |
| 34 | + encoding: "utf8", |
| 35 | + env: { ...process.env }, |
| 36 | + }); |
| 37 | + expect(missingResult.status).toBe(0); |
| 38 | + expect(missingResult.stdout).toBe("\n"); |
| 39 | + |
| 40 | + mkdirSync(path.join(root, "dist")); |
| 41 | + writeFileSync( |
| 42 | + path.join(root, "dist", "build-info.json"), |
| 43 | + `${JSON.stringify({ commit: "abc123" })}\n`, |
| 44 | + ); |
| 45 | + const result = spawnSync(process.execPath, [BUILD_INFO_COMMIT_SCRIPT], { |
| 46 | + cwd: root, |
| 47 | + encoding: "utf8", |
| 48 | + env: { ...process.env }, |
| 49 | + }); |
| 50 | + |
| 51 | + expect(result.status).toBe(0); |
| 52 | + expect(result.stdout).toBe("abc123\n"); |
| 53 | + }); |
| 54 | + |
| 55 | + it("reclaims stale package shell locks and releases current locks", () => { |
| 56 | + const root = makeTempDir(tempDirs, "openclaw-parallels-package-lock-"); |
| 57 | + const lockDir = path.join(root, "build.lock"); |
| 58 | + const result = runBash(` |
| 59 | +set -euo pipefail |
| 60 | +source scripts/e2e/lib/parallels-package-common.sh |
| 61 | +lock_dir=${shellQuote(lockDir)} |
| 62 | +mkdir -p "$lock_dir" |
| 63 | +printf '%s\\n' 999999999 >"$lock_dir/pid" |
| 64 | +parallels_package_acquire_build_lock "$lock_dir" |
| 65 | +owner="$(cat "$lock_dir/pid")" |
| 66 | +parallels_package_release_build_lock "$lock_dir" |
| 67 | +printf 'owner=%s exists=%s\\n' "$owner" "$([[ -e "$lock_dir" ]] && echo yes || echo no)" |
| 68 | +`); |
| 69 | + |
| 70 | + expect(result.status).toBe(0); |
| 71 | + expect(result.stderr).toContain("warn: Removing stale Parallels build lock"); |
| 72 | + expect(result.stdout).toMatch(/^owner=\d+ exists=no\n$/u); |
| 73 | + expect(result.stdout).not.toContain("owner=999999999"); |
| 74 | + }); |
| 75 | + |
| 76 | + it("resolves macOS desktop users through prlctl fallbacks", () => { |
| 77 | + const root = makeTempDir(tempDirs, "openclaw-parallels-macos-common-"); |
| 78 | + const binDir = path.join(root, "bin"); |
| 79 | + const macHome = `${"/"}Users/alice`; |
| 80 | + mkdirSync(binDir); |
| 81 | + const prlctlShim = path.join(binDir, "prlctl"); |
| 82 | + writeFileSync( |
| 83 | + prlctlShim, |
| 84 | + `#!/usr/bin/env bash |
| 85 | +args="$*" |
| 86 | +if [[ "$args" == *"/usr/bin/stat -f %Su /dev/console"* ]]; then |
| 87 | + printf 'loginwindow\\r\\n' |
| 88 | + exit 0 |
| 89 | +fi |
| 90 | +if [[ "$args" == *"/usr/bin/dscl . -list /Users NFSHomeDirectory"* ]]; then |
| 91 | + printf '_daemon /var/root\\r\\nShared %s\\r\\nalice %s\\r\\n' "${`${"/"}Users/Shared`}" "${macHome}" |
| 92 | + exit 0 |
| 93 | +fi |
| 94 | +if [[ "$args" == *"-read ${macHome} NFSHomeDirectory"* ]]; then |
| 95 | + printf 'NFSHomeDirectory: %s\\r\\n' "${macHome}" |
| 96 | + exit 0 |
| 97 | +fi |
| 98 | +exit 1 |
| 99 | +`, |
| 100 | + ); |
| 101 | + chmodSync(prlctlShim, 0o755); |
| 102 | + |
| 103 | + const result = runBash( |
| 104 | + ` |
| 105 | +set -euo pipefail |
| 106 | +source scripts/e2e/lib/parallels-macos-common.sh |
| 107 | +printf 'user=%s\\n' "$(parallels_macos_resolve_desktop_user macos-vm)" |
| 108 | +printf 'home=%s\\n' "$(parallels_macos_resolve_desktop_home macos-vm alice)" |
| 109 | +`, |
| 110 | + { PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ""}` }, |
| 111 | + ); |
| 112 | + |
| 113 | + expect(result.status).toBe(0); |
| 114 | + expect(result.stdout).toBe(`user=alice\nhome=${macHome}\n`); |
| 115 | + }); |
| 116 | +}); |
0 commit comments