Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions e2e/assert.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ timeout() {
run_with_timeout "$seconds" "$@"
}

wait_for_file() {
local file="$1"
local description="${2:-file}"
local attempts="${3:-30}"
local pid="${4:-}"

for ((i = 0; i < attempts; i++)); do
if [[ -f $file ]]; then
return 0
fi
if [[ -n $pid ]] && ! kill -0 "$pid" 2>/dev/null; then
fail "$description process $pid exited before writing $file"
fi
sleep 1
done

fail "$description did not appear within ${attempts}s: $file"
}

# Safeguard against running the test directly, which would execute in the actual user home
[[ -n ${TEST_NAME:-} ]] || fail "tests should be called using run_test"

Expand Down
13 changes: 8 additions & 5 deletions e2e/backend/test_bun_cross_device_install
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
set -euo pipefail

TEST_DIR="$(mktemp -d)"
HTTP_PORT=8765
HTTP_PORT_FILE="$TEST_DIR/http_port"
SERVER_PID=""

if [[ ! -d /dev/shm ]]; then
Expand All @@ -28,7 +28,7 @@ trap cleanup EXIT

# Serve a tiny Bun release fixture with a Python HTTP server so the test can
# exercise the real Bun download + checksum + unzip path without relying on GitHub.
python3 -u - "$TEST_DIR" "$HTTP_PORT" <<'PY' >/dev/null 2>&1 &
python3 -u - "$TEST_DIR" "$HTTP_PORT_FILE" <<'PY' >/dev/null 2>&1 &
import hashlib
import io
import sys
Expand All @@ -37,7 +37,7 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path

root = Path(sys.argv[1])
port = int(sys.argv[2])
port_file = Path(sys.argv[2])
# Remember the most recent archive request so SHASUMS256.txt can match it.
state_file = root / "last-requested-zip.txt"
script = b"""#!/usr/bin/env bash
Expand Down Expand Up @@ -90,10 +90,13 @@ class Handler(BaseHTTPRequestHandler):

self.send_error(404)

HTTPServer(("127.0.0.1", port), Handler).serve_forever()
server = HTTPServer(("127.0.0.1", 0), Handler)
port_file.write_text(str(server.server_address[1]))
server.serve_forever()
PY
SERVER_PID=$!
sleep 1
wait_for_file "$HTTP_PORT_FILE" "HTTP test server port file" 30 "$SERVER_PID"
HTTP_PORT=$(cat "$HTTP_PORT_FILE")

rm -rf "$MISE_DATA_DIR/installs/bun/1.3.10"
MISE_URL_REPLACEMENTS="$(printf '{\"https://github.com/oven-sh/bun/releases/download\":\"http://127.0.0.1:%s\"}' "$HTTP_PORT")"
Expand Down
26 changes: 18 additions & 8 deletions e2e/backend/test_http_compressed_binaries
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set -euo pipefail

# Create a temporary directory for test artifacts
TEST_DIR="$(mktemp -d)"
HTTP_PORT=8765
HTTP_PORT_FILE="$TEST_DIR/http_port"
SERVER_PID=""

# Cleanup function
Expand Down Expand Up @@ -37,16 +37,26 @@ if command -v zstd >/dev/null 2>&1; then
fi

# Start a simple HTTP server
echo "Starting HTTP server on port $HTTP_PORT..."
cd "$TEST_DIR"
python3 -m http.server $HTTP_PORT --bind 127.0.0.1 >/dev/null 2>&1 &
echo "Starting HTTP server..."
python3 -u - "$TEST_DIR" "$HTTP_PORT_FILE" <<'PY' >/dev/null 2>&1 &
import functools
import http.server
import socketserver
import sys
from pathlib import Path

root = sys.argv[1]
port_file = Path(sys.argv[2])
handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory=root)
with socketserver.TCPServer(("127.0.0.1", 0), handler) as httpd:
port_file.write_text(str(httpd.server_address[1]))
httpd.serve_forever()
PY
SERVER_PID=$!

# Go back to original directory
cd -

# Wait for server to start
sleep 2
wait_for_file "$HTTP_PORT_FILE" "HTTP test server port file" 30 "$SERVER_PID"
HTTP_PORT=$(cat "$HTTP_PORT_FILE")

# Test with different compressed formats
echo "Testing .gz compressed binary..."
Expand Down
30 changes: 17 additions & 13 deletions e2e/backend/test_npm_package_manager
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ cat >.mise.toml <<EOF
"npm:tiny" = { version = "latest", npm_args = "--foreground-scripts" }
EOF
mise uninstall npm:tiny@latest >/dev/null 2>&1 || true
assert_succeed "MISE_DEBUG=1 mise install >/tmp/npm_debug.log 2>&1"
NPM_DEBUG_LOG="$TMPDIR/npm_debug.log"
assert_succeed "MISE_DEBUG=1 mise install >'$NPM_DEBUG_LOG' 2>&1"
# npm 11.10.0+ uses `--min-release-age={days}`; older npm uses `--before {ts}`.
# Accept either since the underlying npm version varies between environments.
assert_matches "cat /tmp/npm_debug.log" "--(before|min-release-age)"
assert_contains "cat /tmp/npm_debug.log" "--foreground-scripts"
assert_matches "cat '$NPM_DEBUG_LOG'" "--(before|min-release-age)"
assert_contains "cat '$NPM_DEBUG_LOG'" "--foreground-scripts"
echo "✓ npm backend successfully installs package using npm"
mise uninstall npm:tiny@latest >/dev/null 2>&1 || true

Expand All @@ -58,9 +59,10 @@ cat >.mise.toml <<EOF
[tools]
"npm:tiny" = { version = "latest", bun_args = "--verbose" }
EOF
assert_succeed "MISE_DEBUG=1 mise install >/tmp/bun_debug.log 2>&1"
assert_contains "cat /tmp/bun_debug.log" "--minimum-release-age"
assert_contains "cat /tmp/bun_debug.log" "--verbose"
BUN_DEBUG_LOG="$TMPDIR/bun_debug.log"
assert_succeed "MISE_DEBUG=1 mise install >'$BUN_DEBUG_LOG' 2>&1"
assert_contains "cat '$BUN_DEBUG_LOG'" "--minimum-release-age"
assert_contains "cat '$BUN_DEBUG_LOG'" "--verbose"
echo "✓ npm backend successfully installs package using bun (package_manager=bun)"
mise uninstall npm:tiny@latest >/dev/null 2>&1 || true

Expand All @@ -72,13 +74,14 @@ cat >.mise.toml <<EOF
[tools]
"npm:tiny" = { version = "latest", pnpm_args = "--loglevel=warn" }
EOF
if ! MISE_DEBUG=1 mise install >/tmp/pnpm_debug.log 2>&1; then
PNPM_DEBUG_LOG="$TMPDIR/pnpm_debug.log"
if ! MISE_DEBUG=1 mise install >"$PNPM_DEBUG_LOG" 2>&1; then
echo "Command failed. Output:"
cat /tmp/pnpm_debug.log
cat "$PNPM_DEBUG_LOG"
exit 1
fi
assert_contains "cat /tmp/pnpm_debug.log" "--config.minimumReleaseAge="
assert_contains "cat /tmp/pnpm_debug.log" "--loglevel=warn"
assert_contains "cat '$PNPM_DEBUG_LOG'" "--config.minimumReleaseAge="
assert_contains "cat '$PNPM_DEBUG_LOG'" "--loglevel=warn"
echo "✓ npm backend successfully installs package using pnpm (package_manager=pnpm)"
mise uninstall npm:tiny@latest >/dev/null 2>&1 || true

Expand All @@ -100,9 +103,10 @@ cat >.mise.toml <<EOF
[tools]
"npm:tiny" = { version = "latest", aube_args = "--reporter append-only" }
EOF
assert_succeed "MISE_DEBUG=1 mise install >/tmp/aube_debug.log 2>&1"
assert_contains "cat /tmp/aube_debug.log" "--reporter"
assert_contains "cat /tmp/aube_debug.log" "append-only"
AUBE_DEBUG_LOG="$TMPDIR/aube_debug.log"
assert_succeed "MISE_DEBUG=1 mise install >'$AUBE_DEBUG_LOG' 2>&1"
assert_contains "cat '$AUBE_DEBUG_LOG'" "--reporter"
assert_contains "cat '$AUBE_DEBUG_LOG'" "append-only"
echo "✓ npm backend successfully installs package using aube (package_manager=aube)"
mise uninstall npm:tiny@latest >/dev/null 2>&1 || true

Expand Down
78 changes: 50 additions & 28 deletions e2e/backend/test_s3_minio_slow
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,19 @@
# Install MinIO server and client
mise install minio@latest mc@latest

# MinIO configuration
MINIO_PORT=19000
MINIO_CONSOLE_PORT=19001
find_available_port() {
python3 -c "import socket; s=socket.socket(); s.bind(('127.0.0.1',0)); print(s.getsockname()[1]); s.close()"
}

MINIO_ROOT_USER="minioadmin"
MINIO_ROOT_PASSWORD="minioadmin"
MINIO_ENDPOINT="http://127.0.0.1:$MINIO_PORT"
# Use /tmp directly to avoid disk space issues in isolated test tmp dir
MINIO_DATA_DIR="/tmp/mise-minio-test-$$"
MINIO_PID=""

# Create data directory
mkdir -p "$MINIO_DATA_DIR"

# Start MinIO server in the background using mise x
# MINIO_CI_CD=1 relaxes storage constraints for CI/CD environments
MINIO_ROOT_USER="$MINIO_ROOT_USER" \
MINIO_ROOT_PASSWORD="$MINIO_ROOT_PASSWORD" \
MINIO_CI_CD=1 \
mise x minio@latest -- minio server "$MINIO_DATA_DIR" \
--address ":$MINIO_PORT" \
--console-address ":$MINIO_CONSOLE_PORT" \
>/dev/null 2>&1 &
MINIO_PID=$!

# Cleanup function
cleanup() {
if [[ -n ${MINIO_PID:-} ]]; then
Expand All @@ -39,19 +29,51 @@ cleanup() {
}
trap cleanup EXIT

# Wait for MinIO to be ready
echo "Waiting for MinIO to start..."
for i in {1..30}; do
if curl -s "$MINIO_ENDPOINT/minio/health/ready" >/dev/null 2>&1; then
echo "MinIO is ready"
break
fi
if [[ $i -eq 30 ]]; then
echo "MinIO failed to start"
exit 1
fi
sleep 1
done
start_minio() {
for attempt in {1..5}; do
MINIO_PORT=$(find_available_port)
MINIO_CONSOLE_PORT=$(find_available_port)
if [[ $MINIO_CONSOLE_PORT == "$MINIO_PORT" ]]; then
continue
fi
MINIO_ENDPOINT="http://127.0.0.1:$MINIO_PORT"

# Start MinIO server in the background using mise x
# MINIO_CI_CD=1 relaxes storage constraints for CI/CD environments
MINIO_ROOT_USER="$MINIO_ROOT_USER" \
MINIO_ROOT_PASSWORD="$MINIO_ROOT_PASSWORD" \
MINIO_CI_CD=1 \
mise x minio@latest -- minio server "$MINIO_DATA_DIR" \
--address ":$MINIO_PORT" \
--console-address ":$MINIO_CONSOLE_PORT" \
>/dev/null 2>&1 &
MINIO_PID=$!

echo "Waiting for MinIO to start on port $MINIO_PORT..."
for _ in {1..10}; do
if curl -s "$MINIO_ENDPOINT/minio/health/ready" >/dev/null 2>&1; then
echo "MinIO is ready"
return 0
fi
if ! kill -0 "$MINIO_PID" 2>/dev/null; then
break
fi
sleep 1
done

kill "$MINIO_PID" 2>/dev/null || true
wait "$MINIO_PID" 2>/dev/null || true
MINIO_PID=""
echo "MinIO did not start on attempt $attempt, retrying with new ports..."
done

echo "MinIO failed to start"
return 1
}

if ! start_minio; then
exit 1
fi

# Configure mc (MinIO client) using mise x
mise x mc@latest -- mc alias set testminio "$MINIO_ENDPOINT" "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" --api S3v4
Expand Down
9 changes: 5 additions & 4 deletions e2e/cli/test_install_inactive_hint
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ mise use --rm dummy
# Test: Installing a tool that's only configured via MISE_<TOOL>_VERSION env
# var should NOT show the hint (regression test for #9522 review feedback —
# the config-files-only check was missing env-var-configured tools).
MISE_DUMMY_VERSION=1.0.0 mise install dummy 2>&1 | tee /tmp/mise-install-env.log
assert_not_contains "cat /tmp/mise-install-env.log" "not activated"
MISE_DUMMY_VERSION=1.0.0 mise install dummy@1.0.0 2>&1 | tee /tmp/mise-install-env.log
assert_not_contains "cat /tmp/mise-install-env.log" "not activated"
INSTALL_ENV_LOG="$TMPDIR/mise-install-env.log"
MISE_DUMMY_VERSION=1.0.0 mise install dummy 2>&1 | tee "$INSTALL_ENV_LOG"
assert_not_contains "cat '$INSTALL_ENV_LOG'" "not activated"
MISE_DUMMY_VERSION=1.0.0 mise install dummy@1.0.0 2>&1 | tee "$INSTALL_ENV_LOG"
assert_not_contains "cat '$INSTALL_ENV_LOG'" "not activated"
# (Backend-alias coverage for env-var-configured tools — e.g. that
# MISE_NODEJS_VERSION matches `node` — lives in the tool_env_vars unit test
# in src/toolset/tool_request_set.rs; we don't repeat it here because
Expand Down
22 changes: 11 additions & 11 deletions e2e/config/test_netrc
Original file line number Diff line number Diff line change
Expand Up @@ -100,26 +100,26 @@ else
echo "SKIP: Permission check test (non-Unix OS)"
fi

# Find available port
find_available_port() {
python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()"
}

# Start local HTTP test server with header logging
HEADERS_LOG_DIR=$(mktemp -d)
SERVER_PORT=$(find_available_port)
python3 "${TEST_ROOT}/helpers/scripts/http_test_server.py" "$SERVER_PORT" "$HEADERS_LOG_DIR" &
SERVER_PID=$!
sleep 1
HTTP_PORT_FILE="$TMPDIR/mise_http_test_port"
SERVER_PID=""

# Ensure cleanup on exit
cleanup() {
kill "$SERVER_PID" 2>/dev/null || true
if [[ -n $SERVER_PID ]]; then
kill "$SERVER_PID" 2>/dev/null || true
fi
rm -rf "$HEADERS_LOG_DIR"
rm -f /tmp/mise_http_test_port
rm -f "${MISE_HTTP_TEST_PORT_FILE:-$TMPDIR/mise_http_test_port}"
Comment thread
cursor[bot] marked this conversation as resolved.
}
trap cleanup EXIT

MISE_HTTP_TEST_PORT_FILE="$HTTP_PORT_FILE" python3 "${TEST_ROOT}/helpers/scripts/http_test_server.py" 0 "$HEADERS_LOG_DIR" &
SERVER_PID=$!
wait_for_file "$HTTP_PORT_FILE" "HTTP test server port file" 30 "$SERVER_PID"
SERVER_PORT=$(cat "$HTTP_PORT_FILE")

# Test 8: Verify Authorization header is sent when netrc has matching credentials
cat >"$HOME/.netrc" <<EOF
machine 127.0.0.1
Expand Down
12 changes: 4 additions & 8 deletions e2e/generate/test_generate_tool_stub
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@
# Disable GPG verification to avoid test failures
export MISE_GPG_VERIFY=false

# Find available port
find_available_port() {
python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()"
}

# Start local HTTP test server
SERVER_PORT=$(find_available_port)
python3 "${TEST_ROOT}/helpers/scripts/tool_stub_test_server.py" "$SERVER_PORT" &
SERVER_PORT_FILE="$TMPDIR/tool_stub_test_port"
MISE_TOOL_STUB_TEST_PORT_FILE="$SERVER_PORT_FILE" python3 "${TEST_ROOT}/helpers/scripts/tool_stub_test_server.py" 0 &
SERVER_PID=$!

# Wait for server to start
sleep 1
wait_for_file "$SERVER_PORT_FILE" "tool stub test server port file" 30 "$SERVER_PID"
SERVER_PORT=$(cat "$SERVER_PORT_FILE")

# Ensure cleanup on exit
cleanup() {
Expand Down
16 changes: 11 additions & 5 deletions e2e/helpers/scripts/git_http_backend_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,21 @@ def handler(*args, **kwargs):
print(f"Git HTTP server running on port {actual_port}")
print(f"Repository URL: http://localhost:{actual_port}/repo.git")

# Write the actual port to a file for the test to read
port_file = Path('/tmp/mise_git_http_port')
# Write server state to files for the test to read. Allow the e2e
# harness to place these under the per-test TMPDIR for parallel runs.
port_file = Path(os.environ.get('MISE_GIT_HTTP_PORT_FILE', '/tmp/mise_git_http_port'))
ready_file = Path(os.environ.get('MISE_GIT_HTTP_READY_FILE', '/tmp/mise_git_http_ready'))
info_file = Path(os.environ.get('MISE_GIT_HTTP_INFO_FILE', '/tmp/mise_git_http_info'))
port_file.parent.mkdir(parents=True, exist_ok=True)
ready_file.parent.mkdir(parents=True, exist_ok=True)
info_file.parent.mkdir(parents=True, exist_ok=True)
port_file.write_text(str(actual_port))

# Also write a ready marker file
ready_file = Path('/tmp/mise_git_http_ready')
ready_file.write_text('ready')

# Save cleanup info
with open('/tmp/mise_git_http_info', 'w') as f:
with open(info_file, 'w') as f:
f.write(f"{temp_dir}\n")

try:
Expand All @@ -178,8 +183,9 @@ def handler(*args, **kwargs):
finally:
shutil.rmtree(temp_dir, ignore_errors=True)
port_file.unlink(missing_ok=True)
info_file.unlink(missing_ok=True)
ready_file.unlink(missing_ok=True)

if __name__ == '__main__':
port = int(sys.argv[1]) if len(sys.argv) > 1 else 0
start_server(port)
start_server(port)
Loading
Loading