Skip to content

Commit bb2657e

Browse files
committed
test
1 parent 3fd11d2 commit bb2657e

File tree

2 files changed

+284
-74
lines changed

2 files changed

+284
-74
lines changed

packaging/homebrew/mfc.rb

Lines changed: 80 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -80,80 +80,86 @@ def install
8080
# Create wrapper script in buildpath first, then install it
8181
wrapper_script = buildpath/"mfc_wrapper"
8282
wrapper_script.write <<~EOS
83-
#!/bin/bash
84-
set -euo pipefail
85-
86-
# Unset VIRTUAL_ENV to ensure mfc.sh uses the copied venv, not the Cellar one
87-
unset VIRTUAL_ENV || true
88-
89-
# Save original working directory
90-
ORIGINAL_PWD="${PWD}"
91-
92-
# Convert relative file paths to absolute paths before changing directories
93-
# This handles cases where users run: mfc run case.py
94-
ARGS=("$@")
95-
for i in "${!ARGS[@]}"; do
96-
arg="${ARGS[$i]}"
97-
# If argument looks like a file path (ends with .py or .json) and is relative
98-
if [[ "$arg" =~ \.(py|json)$ ]] && [[ "$arg" != /* ]]; then
99-
# Convert to absolute path using original working directory
100-
ARGS[$i]="${ORIGINAL_PWD}/${arg}"
101-
fi
102-
done
103-
104-
# Create a temporary working directory (Cellar is read-only)
105-
TMPDIR="$(mktemp -d)"
106-
trap 'rm -rf "${TMPDIR}"' EXIT
107-
108-
# Copy mfc.sh to temp dir (it may try to write build artifacts)
109-
cp "#{libexec}/mfc.sh" "${TMPDIR}/"
110-
chmod +x "${TMPDIR}/mfc.sh"
111-
112-
# Copy CMakeLists.txt (needed by toolchain/bootstrap/cmake.sh)
113-
cp "#{prefix}/CMakeLists.txt" "${TMPDIR}/CMakeLists.txt"
114-
115-
cd "${TMPDIR}"
116-
117-
# Copy toolchain directory (not symlink) so Python paths resolve correctly
118-
# This prevents paths from resolving back to read-only Cellar
119-
cp -R "#{prefix}/toolchain" "toolchain"
120-
121-
# Patch toolchain in place to use Homebrew-installed binaries
122-
# Write patch directly to file to avoid heredoc temp file issues
123-
{
124-
echo ""
125-
echo " # Homebrew patch: Override get_install_binpath to use pre-installed binaries"
126-
echo " _original_get_install_binpath = MFCTarget.get_install_binpath"
127-
echo " def _homebrew_get_install_binpath(self, case):"
128-
echo " return \"#{bin}/\" + self.name"
129-
echo " MFCTarget.get_install_binpath = _homebrew_get_install_binpath"
130-
echo ""
131-
echo " # Override is_buildable to skip building main targets and syscheck"
132-
echo " _original_is_buildable = MFCTarget.is_buildable"
133-
echo " def _homebrew_is_buildable(self):"
134-
echo " if self.name in [\"pre_process\", \"simulation\", \"post_process\", \"syscheck\"]:"
135-
echo " return False # Skip building - use pre-installed binaries"
136-
echo " return _original_is_buildable(self)"
137-
echo " MFCTarget.is_buildable = _homebrew_is_buildable"
138-
} >> "toolchain/mfc/build.py"
139-
140-
# Copy examples directory (required by mfc.sh Python code)
141-
cp -R "#{prefix}/examples" "examples"
142-
143-
# Create build directory and copy venv (not symlink - needs to be writable)
144-
# Use cp -R for a full recursive copy
145-
mkdir -p "build"
146-
cp -R "#{venv}" "build/venv"
147-
148-
# Copy pyproject.toml to build/ so mfc.sh thinks dependencies are already installed
149-
cp "#{prefix}/toolchain/pyproject.toml" "build/pyproject.toml"
150-
151-
# For 'mfc run', add --no-build flag to skip compilation
152-
if [ "${ARGS[0]-}" = "run" ]; then
153-
exec ./mfc.sh "${ARGS[@]}" --no-build
154-
else
155-
exec ./mfc.sh "${ARGS[@]}"
156-
fi
83+
#!/bin/bash
84+
set -euo pipefail
85+
86+
# Unset VIRTUAL_ENV to ensure mfc.sh uses the copied venv, not the Cellar one
87+
unset VIRTUAL_ENV || true
88+
89+
# Save original working directory
90+
ORIGINAL_PWD="${PWD}"
91+
92+
# Convert relative file paths to absolute paths before changing directories
93+
# This handles cases where users run: mfc run case.py
94+
ARGS=("$@")
95+
for i in "${!ARGS[@]}"; do
96+
arg="${ARGS[$i]}"
97+
# If argument looks like a file path (ends with .py or .json) and is relative
98+
if [[ "$arg" =~ \\.(py|json)$ ]] && [[ "$arg" != /* ]]; then
99+
# Convert to absolute path using original working directory
100+
ARGS[$i]="${ORIGINAL_PWD}/${arg}"
101+
fi
102+
done
103+
104+
# Create a temporary working directory (Cellar is read-only)
105+
TMPDIR="$(mktemp -d)"
106+
trap 'rm -rf "${TMPDIR}"' EXIT
107+
108+
# Copy mfc.sh to temp dir (it may try to write build artifacts)
109+
cp "#{libexec}/mfc.sh" "${TMPDIR}/"
110+
chmod +x "${TMPDIR}/mfc.sh"
111+
112+
# Copy CMakeLists.txt (needed by toolchain/bootstrap/cmake.sh)
113+
if [ -f "#{prefix}/CMakeLists.txt" ]; then
114+
cp "#{prefix}/CMakeLists.txt" "${TMPDIR}/CMakeLists.txt"
115+
else
116+
# Fallback: create minimal CMakeLists.txt if not found
117+
echo "cmake_minimum_required(VERSION 3.15)" > "${TMPDIR}/CMakeLists.txt"
118+
echo "project(MFC)" >> "${TMPDIR}/CMakeLists.txt"
119+
fi
120+
121+
cd "${TMPDIR}"
122+
123+
# Copy toolchain directory using hard links for speed (much faster than copying)
124+
# Use cp -al to create hard links, fall back to cp -R if not supported
125+
cp -al "#{prefix}/toolchain" "toolchain" 2>/dev/null || cp -R "#{prefix}/toolchain" "toolchain"
126+
127+
# Patch toolchain in place to use Homebrew-installed binaries
128+
# Write patch directly to file to avoid heredoc temp file issues
129+
{
130+
echo ""
131+
echo " # Homebrew patch: Override get_install_binpath to use pre-installed binaries"
132+
echo " _original_get_install_binpath = MFCTarget.get_install_binpath"
133+
echo " def _homebrew_get_install_binpath(self, case):"
134+
echo " return '#{bin}/' + self.name"
135+
echo " MFCTarget.get_install_binpath = _homebrew_get_install_binpath"
136+
echo ""
137+
echo " # Override is_buildable to skip building main targets and syscheck"
138+
echo " _original_is_buildable = MFCTarget.is_buildable"
139+
echo " def _homebrew_is_buildable(self):"
140+
echo " if self.name in ['pre_process', 'simulation', 'post_process', 'syscheck']:"
141+
echo " return False # Skip building - use pre-installed binaries"
142+
echo " return _original_is_buildable(self)"
143+
echo " MFCTarget.is_buildable = _homebrew_is_buildable"
144+
} >> "toolchain/mfc/build.py"
145+
146+
# Copy examples directory using hard links for speed
147+
cp -al "#{prefix}/examples" "examples" 2>/dev/null || cp -R "#{prefix}/examples" "examples"
148+
149+
# Create build directory and copy venv using hard links (much faster!)
150+
# Use cp -al to create hard links, fall back to cp -R if not supported
151+
mkdir -p "build"
152+
cp -al "#{venv}" "build/venv" 2>/dev/null || cp -R "#{venv}" "build/venv"
153+
154+
# Copy pyproject.toml to build/ so mfc.sh thinks dependencies are already installed
155+
cp "#{prefix}/toolchain/pyproject.toml" "build/pyproject.toml"
156+
157+
# For 'mfc run', add --no-build flag to skip compilation
158+
if [ "${ARGS[0]-}" = "run" ]; then
159+
exec ./mfc.sh "${ARGS[@]}" --no-build
160+
else
161+
exec ./mfc.sh "${ARGS[@]}"
162+
fi
157163
EOS
158164

159165
# Make wrapper executable and install it

packaging/homebrew/run-tests.sh

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
#!/bin/bash
2+
# run-tests.sh - Run MFC Homebrew tests with timeout protection
3+
4+
set -e
5+
6+
TIMEOUT_CMD="timeout"
7+
if ! command -v timeout >/dev/null 2>&1; then
8+
# macOS doesn't have timeout by default, use gtimeout if available, or implement our own
9+
if command -v gtimeout >/dev/null 2>&1; then
10+
TIMEOUT_CMD="gtimeout"
11+
else
12+
# Simple timeout function for macOS
13+
timeout() {
14+
local duration=$1
15+
shift
16+
( "$@" & )
17+
local pid=$!
18+
sleep "$duration"
19+
if kill -0 "$pid" 2>/dev/null; then
20+
echo "Command timed out after ${duration}s"
21+
kill "$pid" 2>/dev/null
22+
return 124
23+
fi
24+
wait "$pid"
25+
return $?
26+
}
27+
TIMEOUT_CMD="timeout"
28+
fi
29+
fi
30+
31+
run_with_timeout() {
32+
local timeout_sec=$1
33+
shift
34+
local cmd="$*"
35+
36+
echo "Running: $cmd (timeout: ${timeout_sec}s)"
37+
38+
if $TIMEOUT_CMD "$timeout_sec" bash -c "$cmd" 2>&1; then
39+
echo "✅ Command completed successfully"
40+
return 0
41+
else
42+
local exit_code=$?
43+
if [ $exit_code -eq 124 ] || [ $exit_code -eq 143 ]; then
44+
echo "❌ Command timed out after ${timeout_sec}s"
45+
return 1
46+
else
47+
echo "❌ Command failed with exit code $exit_code"
48+
return $exit_code
49+
fi
50+
fi
51+
}
52+
53+
echo "🧪 MFC Homebrew Test Suite with Timeout Protection"
54+
echo "=================================================="
55+
echo ""
56+
57+
# Test 1: Check installation
58+
echo "Test 1: Checking MFC installation..."
59+
if command -v mfc >/dev/null 2>&1; then
60+
echo "✅ mfc command found: $(which mfc)"
61+
else
62+
echo "❌ mfc command not found"
63+
exit 1
64+
fi
65+
66+
# Test 2: Check binaries
67+
echo ""
68+
echo "Test 2: Checking binaries..."
69+
for bin in pre_process simulation post_process; do
70+
if command -v "$bin" >/dev/null 2>&1; then
71+
echo "$bin found: $(which $bin)"
72+
else
73+
echo "$bin not found"
74+
fi
75+
done
76+
77+
# Test 3: Quick help test (with timeout)
78+
echo ""
79+
echo "Test 3: Testing mfc --help (15s timeout)..."
80+
if run_with_timeout 15 "mfc --help >/dev/null 2>&1"; then
81+
echo "✅ mfc --help works"
82+
else
83+
echo "❌ mfc --help failed or timed out"
84+
fi
85+
86+
# Test 4: Check for CMakeLists.txt error
87+
echo ""
88+
echo "Test 4: Checking for CMakeLists.txt errors..."
89+
if run_with_timeout 15 "mfc --help 2>&1" | grep -q "cat: CMakeLists.txt"; then
90+
echo "❌ CMakeLists.txt error still present"
91+
else
92+
echo "✅ No CMakeLists.txt errors"
93+
fi
94+
95+
# Test 5: Test basic commands
96+
echo ""
97+
echo "Test 5: Testing basic MFC commands (15s timeout each)..."
98+
for cmd in "mfc --help" "mfc build --help" "mfc run --help"; do
99+
if run_with_timeout 15 "$cmd >/dev/null 2>&1"; then
100+
echo "$cmd works"
101+
else
102+
echo "$cmd failed or timed out"
103+
fi
104+
done
105+
106+
# Test 6: Test individual binaries
107+
echo ""
108+
echo "Test 6: Testing individual binaries (5s timeout each)..."
109+
for bin in pre_process simulation post_process; do
110+
if run_with_timeout 5 "$bin --version >/dev/null 2>&1 || $bin --help >/dev/null 2>&1"; then
111+
echo "$bin works"
112+
else
113+
echo "$bin failed or timed out"
114+
fi
115+
done
116+
117+
# Test 7: Performance test
118+
echo ""
119+
echo "Test 7: Performance test (measuring startup time)..."
120+
if command -v bc >/dev/null 2>&1; then
121+
TIMES=()
122+
for i in {1..3}; do
123+
START=$(date +%s.%N)
124+
if run_with_timeout 20 "mfc --help >/dev/null 2>&1"; then
125+
END=$(date +%s.%N)
126+
ELAPSED=$(echo "$END - $START" | bc)
127+
TIMES+=($ELAPSED)
128+
echo " Run $i: ${ELAPSED}s"
129+
else
130+
echo " Run $i: TIMED OUT"
131+
fi
132+
done
133+
134+
if [ ${#TIMES[@]} -gt 0 ]; then
135+
TOTAL=0
136+
for t in "${TIMES[@]}"; do
137+
TOTAL=$(echo "$TOTAL + $t" | bc)
138+
done
139+
AVG=$(echo "scale=3; $TOTAL / ${#TIMES[@]}" | bc)
140+
echo " Average: ${AVG}s"
141+
if (( $(echo "$AVG < 5.0" | bc -l) )); then
142+
echo "✅ Startup time is reasonable (< 5s)"
143+
else
144+
echo "⚠️ Startup time is slow (${AVG}s)"
145+
fi
146+
fi
147+
else
148+
echo "⚠️ bc not available, skipping performance measurement"
149+
fi
150+
151+
# Test 8: Test with example case
152+
echo ""
153+
echo "Test 8: Testing with example case..."
154+
EXAMPLE_CASE=$(brew --prefix mfc)/examples/1D_sodshocktube/case.py 2>/dev/null || echo ""
155+
if [ -n "$EXAMPLE_CASE" ] && [ -f "$EXAMPLE_CASE" ]; then
156+
echo "✅ Example case found: $EXAMPLE_CASE"
157+
if run_with_timeout 20 "mfc run '$EXAMPLE_CASE' --help >/dev/null 2>&1"; then
158+
echo "✅ mfc run with example case works"
159+
else
160+
echo "❌ mfc run with example case failed or timed out"
161+
fi
162+
else
163+
echo "⚠️ Example case not found, skipping"
164+
fi
165+
166+
# Test 9: Homebrew test suite
167+
echo ""
168+
echo "Test 9: Running Homebrew's built-in tests (60s timeout)..."
169+
if run_with_timeout 60 "brew test mfc"; then
170+
echo "✅ Homebrew test suite passed"
171+
else
172+
echo "❌ Homebrew test suite failed or timed out"
173+
fi
174+
175+
# Test 10: Verify hard links
176+
echo ""
177+
echo "Test 10: Verifying hard link optimization..."
178+
TMP_TEST=$(mktemp -d)
179+
MFC_PREFIX=$(brew --prefix mfc 2>/dev/null || echo "")
180+
181+
if [ -n "$MFC_PREFIX" ] && [ -d "${MFC_PREFIX}/libexec/venv" ]; then
182+
if cp -al "${MFC_PREFIX}/libexec/venv" "${TMP_TEST}/venv" 2>/dev/null; then
183+
if [ -f "${MFC_PREFIX}/libexec/venv/bin/python" ] && [ -f "${TMP_TEST}/venv/bin/python" ]; then
184+
INODE1=$(stat -f %i "${MFC_PREFIX}/libexec/venv/bin/python" 2>/dev/null || stat -c %i "${MFC_PREFIX}/libexec/venv/bin/python" 2>/dev/null || echo "unknown")
185+
INODE2=$(stat -f %i "${TMP_TEST}/venv/bin/python" 2>/dev/null || stat -c %i "${TMP_TEST}/venv/bin/python" 2>/dev/null || echo "unknown")
186+
if [ "$INODE1" = "$INODE2" ] && [ "$INODE1" != "unknown" ]; then
187+
echo "✅ Hard links are working (same inode: $INODE1)"
188+
else
189+
echo "⚠️ Hard links created but inodes differ (may be on different filesystem)"
190+
fi
191+
fi
192+
rm -rf "${TMP_TEST}"
193+
else
194+
echo "⚠️ Hard links not supported (will use regular copy)"
195+
fi
196+
else
197+
echo "⚠️ Cannot verify hard links (MFC not installed or path not found)"
198+
fi
199+
200+
echo ""
201+
echo "=================================================="
202+
echo "✅ Test suite completed!"
203+
echo "=================================================="
204+

0 commit comments

Comments
 (0)