Files
hakorune/tools/smokes/v2/run.sh
nyash-codex dd6876e1c6 Phase 20.12b: quick green + structural cleanup
- Deprecations: add warn-once for nyash.toml (runtime::deprecations); apply in plugin loader v2 (singletons/method_resolver)
- Child env + runner hygiene: unify Stage‑3/quiet/disable-fallback env in test/runner; expand LLVM noise filters
- Docs/branding: prefer  and hako.toml in README.md/README.ja.md and smokes README
- VM: implement Map.clear in MIR interpreter (boxes_map)
- Stage‑B: gate bundle/alias/require smokes behind SMOKES_ENABLE_STAGEB; fix include cwd and resolve() call even for require-only cases
- Core‑Direct: gate rc boundary canary behind SMOKES_ENABLE_CORE_DIRECT
- Smokes: inject Stage‑3 and disable selfhost fallback for LLVM runs; filter using/* logs
- Quick profile: 168/168 PASS locally

This commit accelerates Phase 20.33 (80/20) by stabilizing quick suite, reducing noise, and gating heavy/experimental paths for speed.
2025-11-02 17:50:06 +09:00

461 lines
12 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# run.sh - スモークテストv2 単一エントリポイント
# Usage: ./run.sh --profile {quick|integration|full} [options]
set -euo pipefail
# スクリプトディレクトリ
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# デフォルト値
PROFILE="quick"
FORMAT="text"
JOBS=1
TIMEOUT=""
VERBOSE=false
DRY_RUN=false
FILTER=""
FORCE_CONFIG=""
# カラー定義
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly BOLD='\033[1m'
readonly NC='\033[0m'
# ログ関数
log_info() {
echo -e "${BLUE}[INFO]${NC} $*" >&2
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $*" >&2
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $*" >&2
}
log_error() {
echo -e "${RED}[ERROR]${NC} $*" >&2
}
log_header() {
echo -e "${BOLD}$*${NC}" >&2
}
# ヘルプ表示
show_help() {
cat << 'EOF'
Smoke Tests v2 - Nyash 2-Pillar Testing System
Usage:
./run.sh --profile PROFILE [options]
Profiles:
quick Development-time fast checks (1-2 min)
integration Basic VM ↔ LLVM parity checks (5-10 min)
full Complete matrix testing (15-30 min)
Options:
--profile PROFILE Test profile to run
--filter "PATTERN" Test filter (e.g., "boxes:string")
--format FORMAT Output format: text|json|junit
--jobs N Parallel execution count
--timeout SEC Timeout per test in seconds
--force-config CONFIG Force configuration: rust_vm_dynamic|llvm_static
--verbose Enable verbose output
--dry-run Show test list without execution
--help Show this help
Examples:
# Quick development check
./run.sh --profile quick
# Integration with filter
./run.sh --profile integration --filter "plugins:*"
# Full testing with JSON output
./run.sh --profile full --format json --jobs 4 --timeout 300
# Dry run to see what would be tested
./run.sh --profile integration --dry-run
Environment Variables:
SMOKES_FORCE_CONFIG Force specific configuration
SMOKES_PLUGIN_MODE Plugin mode: dynamic|static
CI CI environment detection
EOF
}
# 引数パース
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
--profile)
PROFILE="$2"
shift 2
;;
--filter)
FILTER="$2"
shift 2
;;
--format)
FORMAT="$2"
shift 2
;;
--jobs)
JOBS="$2"
shift 2
;;
--timeout)
TIMEOUT="$2"
shift 2
;;
--force-config)
FORCE_CONFIG="$2"
shift 2
;;
--verbose)
VERBOSE=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
--help)
show_help
exit 0
;;
*)
log_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
# プロファイル検証
case "$PROFILE" in
quick|integration|full|plugins)
;;
*)
log_error "Invalid profile: $PROFILE"
log_error "Valid profiles: quick, integration, full, plugins"
exit 1
;;
esac
# フォーマット検証
case "$FORMAT" in
text|json|junit)
;;
*)
log_error "Invalid format: $FORMAT"
log_error "Valid formats: text, json, junit"
exit 1
;;
esac
}
# 環境設定
setup_environment() {
log_info "Setting up environment for profile: $PROFILE"
# 共通ライブラリ読み込み
source "$SCRIPT_DIR/lib/test_runner.sh"
source "$SCRIPT_DIR/lib/plugin_manager.sh"
source "$SCRIPT_DIR/lib/result_checker.sh"
source "$SCRIPT_DIR/lib/preflight.sh"
# 設定読み込み
if [ -n "$FORCE_CONFIG" ]; then
export SMOKES_FORCE_CONFIG="$FORCE_CONFIG"
log_info "Forced configuration: $FORCE_CONFIG"
fi
source "$SCRIPT_DIR/configs/auto_detect.conf"
auto_configure "$PROFILE"
# プロファイル専用設定
export SMOKES_CURRENT_PROFILE="$PROFILE"
# コマンドライン引数の環境変数設定
if [ -n "$TIMEOUT" ]; then
export SMOKES_DEFAULT_TIMEOUT="$TIMEOUT"
fi
if [ "$VERBOSE" = true ]; then
export NYASH_CLI_VERBOSE=1
export SMOKES_LOG_LEVEL="debug"
fi
export SMOKES_PARALLEL_JOBS="$JOBS"
export SMOKES_OUTPUT_FORMAT="$FORMAT"
export SMOKES_TEST_FILTER="$FILTER"
# 作業ディレクトリ移動Nyashプロジェクトルートへ
cd "$SCRIPT_DIR/../../.."
log_info "Working directory: $(pwd)"
}
# プリフライトチェック
run_preflight() {
log_info "Running preflight checks..."
if ! preflight_all; then
log_error "Preflight checks failed"
log_error "Run with --verbose for detailed information"
exit 1
fi
log_success "Preflight checks passed"
}
# テストファイル検索
find_test_files() {
local profile_dir="$SCRIPT_DIR/profiles/$PROFILE"
local test_files=()
local have_llvm=0
if [ "${SMOKES_FORCE_LLVM:-0}" = "1" ]; then
have_llvm=1
fi
if [ -x "./target/release/nyash" ]; then
if ./target/release/nyash --version 2>/dev/null | grep -q "features.*llvm"; then
have_llvm=1
else
# Fallback detection: check for LLVM harness symbols in the binary
if strings ./target/release/nyash 2>/dev/null | grep -E -q 'ny-llvmc|NYASH_LLVM_USE_HARNESS'; then
have_llvm=1
fi
fi
fi
if [ ! -d "$profile_dir" ]; then
log_error "Profile directory not found: $profile_dir"
exit 1
fi
# テストファイル検索
while IFS= read -r -d '' file; do
# フィルタ適用
if [ -n "$FILTER" ]; then
local relative_path
relative_path=$(realpath --relative-to="$profile_dir" "$file")
if ! echo "$relative_path" | grep -q "$FILTER"; then
continue
fi
fi
# LLVM未ビルド時は AST(LLVM) 系テストをスキップ
if [ $have_llvm -eq 0 ] && echo "$file" | grep -q "_ast\.sh$"; then
log_warn "Skipping (no LLVM): $file"
continue
fi
test_files+=("$file")
done < <(find "$profile_dir" -name "*.sh" -type f -print0)
printf '%s\n' "${test_files[@]}"
}
# 単一テスト実行
run_single_test() {
local test_file="$1"
local test_name
test_name=$(basename "$test_file" .sh)
if [ "$FORMAT" = "text" ]; then
echo -n "Running $test_name... "
fi
local start_time end_time duration exit_code
start_time=$(date +%s.%N)
# タイムアウト付きテスト実行
local timeout_cmd=""
if [ -n "${SMOKES_DEFAULT_TIMEOUT:-}" ]; then
timeout_cmd="timeout ${SMOKES_DEFAULT_TIMEOUT}"
fi
# 詳細ログ: 失敗時のみテイル表示
local log_file
log_file="/tmp/nyash_smoke_$(date +%s)_$$.log"
if $timeout_cmd bash "$test_file" >"$log_file" 2>&1; then
exit_code=0
else
exit_code=$?
fi
end_time=$(date +%s.%N)
duration=$(echo "$end_time - $start_time" | bc -l)
# 結果出力
case "$FORMAT" in
text)
if [ $exit_code -eq 0 ]; then
echo -e "${GREEN}PASS${NC} (${duration}s)"
else
echo -e "${RED}FAIL${NC} (exit=$exit_code, ${duration}s)"
echo -e "${YELLOW}[WARN]${NC} Test file: $test_file"
local TAIL_N="${SMOKES_NOTIFY_TAIL:-80}"
echo "----- LOG (tail -n $TAIL_N) -----"
tail -n "$TAIL_N" "$log_file" || true
echo "----- END LOG -----"
fi
;;
json)
local status_json
status_json=$([ $exit_code -eq 0 ] && echo "pass" || echo "fail")
echo "{\"name\":\"$test_name\",\"path\":\"$test_file\",\"status\":\"$status_json\",\"duration\":$duration,\"exit\":$exit_code}"
;;
junit)
# JUnit形式は後でまとめて出力pathも保持
echo "$test_name:$exit_code:$duration:$test_file" >> /tmp/junit_results.txt
;;
esac
# 後始末
rm -f "$log_file" 2>/dev/null || true
return $exit_code
}
# テスト実行
run_tests() {
local test_files
mapfile -t test_files < <(find_test_files)
if [ ${#test_files[@]} -eq 0 ]; then
log_warn "No test files found for profile: $PROFILE"
if [ -n "$FILTER" ]; then
log_warn "Filter applied: $FILTER"
fi
exit 0
fi
log_info "Found ${#test_files[@]} test files"
# Dry run
if [ "$DRY_RUN" = true ]; then
log_header "Test files that would be executed:"
for file in "${test_files[@]}"; do
echo " $(realpath --relative-to="$SCRIPT_DIR" "$file")"
done
exit 0
fi
# テスト実行開始
log_header "Starting $PROFILE profile tests"
local passed=0
local failed=0
local start_time
start_time=$(date +%s.%N)
# JSON形式の場合はヘッダー出力
if [ "$FORMAT" = "json" ]; then
echo '{"profile":"'$PROFILE'","tests":['
fi
# JUnit用ファイル初期化
if [ "$FORMAT" = "junit" ]; then
echo -n > /tmp/junit_results.txt
fi
# テスト実行
local first_test=true
for test_file in "${test_files[@]}"; do
if [ "$FORMAT" = "json" ] && [ "$first_test" = false ]; then
echo ","
fi
first_test=false
if run_single_test "$test_file"; then
passed=$((passed+1))
else
failed=$((failed+1))
# Fast fail モード
if [ "${SMOKES_FAST_FAIL:-0}" = "1" ]; then
log_warn "Fast fail enabled, stopping on first failure"
break
fi
fi
done
# 結果出力
local end_time total_duration
end_time=$(date +%s.%N)
total_duration=$(echo "$end_time - $start_time" | bc -l)
case "$FORMAT" in
text)
echo ""
log_header "Test Results Summary"
echo "Profile: $PROFILE"
echo "Total: $((passed + failed))"
echo "Passed: $passed"
echo "Failed: $failed"
echo "Duration: ${total_duration}s"
if [ $failed -eq 0 ]; then
log_success "All tests passed! ✨"
else
log_error "$failed test(s) failed"
fi
;;
json)
echo '],"summary":{"total":'$((passed + failed))',"passed":'$passed',"failed":'$failed',"duration":'$total_duration'}}'
;;
junit)
cat << EOF
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="smokes_$PROFILE" tests="$((passed + failed))" failures="$failed" time="$total_duration">
EOF
while IFS=':' read -r name exit_code duration path; do
if [ "$exit_code" = "0" ]; then
echo " <testcase name=\"$name\" time=\"$duration\" classname=\"$path\"/>"
else
echo " <testcase name=\"$name\" time=\"$duration\" classname=\"$path\"><failure message=\"exit=$exit_code\"/></testcase>"
fi
done < /tmp/junit_results.txt
echo "</testsuite>"
rm -f /tmp/junit_results.txt
;;
esac
# 終了コード
[ $failed -eq 0 ]
}
# メイン処理
main() {
# 引数パース
parse_arguments "$@"
# バナー表示
if [ "$FORMAT" = "text" ]; then
log_header "🔥 Hakorune Smoke Tests v2 - 2-Pillar Testing System"
log_info "Profile: $PROFILE | Format: $FORMAT | Jobs: $JOBS"
if [ -n "$FILTER" ]; then
log_info "Filter: $FILTER"
fi
echo ""
fi
# 環境設定
setup_environment
# プリフライト
run_preflight
# テスト実行
run_tests
}
# エラーハンドリング
trap 'log_error "Script interrupted"; exit 130' INT TERM
# メイン実行
main "$@"