777 lines
24 KiB
Bash
Executable file
777 lines
24 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -u
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: run_matrix.sh [--all|--unit|--cross|--proto]
|
|
|
|
Runs Proto Socket proto schema sync, unit/same-language tests, and/or
|
|
cross-language communication tests, then prints Markdown PASS/FAIL tables.
|
|
Each run also writes a local result record under agent-test/runs/.
|
|
Defaults to --all.
|
|
USAGE
|
|
}
|
|
|
|
mode="all"
|
|
case "${1:-}" in
|
|
""|--all) mode="all" ;;
|
|
--unit) mode="unit" ;;
|
|
--cross) mode="cross" ;;
|
|
--proto) mode="proto" ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) usage >&2; exit 2 ;;
|
|
esac
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "$script_dir/../../../../.." && pwd)"
|
|
log_dir="$(mktemp -d "${TMPDIR:-/tmp}/proto-socket-matrix.XXXXXX")"
|
|
run_started_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
run_record_stamp="$(date -u +%Y%m%d-%H%M%S)"
|
|
remote_web_host="${PROTO_SOCKET_DART_WEB_REMOTE:-toki@toki-labs.com}"
|
|
remote_web_root_expr="${PROTO_SOCKET_DART_WEB_REMOTE_ROOT:-~/works}"
|
|
remote_web_repo_name="${PROTO_SOCKET_DART_WEB_REMOTE_REPO:-proto-socket-dart-web}"
|
|
remote_web_repo_url="${PROTO_SOCKET_DART_WEB_REMOTE_URL:-$(git -C "$repo_root" config --get remote.origin.url 2>/dev/null || true)}"
|
|
remote_web_ref="${PROTO_SOCKET_DART_WEB_REF:-$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo master)}"
|
|
remote_web_execution="local"
|
|
remote_web_prepare_summary=""
|
|
|
|
case "$mode" in
|
|
all) record_profile="proto-socket-full-matrix" ;;
|
|
unit) record_profile="proto-socket-unit-matrix" ;;
|
|
cross) record_profile="proto-socket-cross-matrix" ;;
|
|
proto) record_profile="proto-socket-proto-sync" ;;
|
|
esac
|
|
|
|
languages=("Dart" "Go" "Kotlin" "Python" "TypeScript")
|
|
|
|
declare -A unit_cmds=(
|
|
["Dart"]="dart pub get && dart test && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js"
|
|
["Go"]="go test ./..."
|
|
["Kotlin"]="./gradlew test"
|
|
["Python"]="python3 -m pytest -q"
|
|
["TypeScript"]="npm run check && npm test"
|
|
)
|
|
declare -A unit_dirs=(
|
|
["Dart"]="$repo_root/dart"
|
|
["Go"]="$repo_root/go"
|
|
["Kotlin"]="$repo_root/kotlin"
|
|
["Python"]="$repo_root/python"
|
|
["TypeScript"]="$repo_root/typescript"
|
|
)
|
|
declare -A unit_result
|
|
declare -A unit_status
|
|
declare -A unit_summary
|
|
|
|
proto_cmd="tools/check_proto_sync.sh"
|
|
proto_dir="$repo_root"
|
|
proto_result="-"
|
|
proto_status=""
|
|
proto_summary=""
|
|
|
|
cross_cases=(
|
|
"Go|Dart|$repo_root/go|go run ./crosstest/go_dart.go"
|
|
"Go|Kotlin|$repo_root/go|go run ./crosstest/go_kotlin.go"
|
|
"Go|Python|$repo_root/go|go run ./crosstest/go_python.go"
|
|
"Go|TypeScript|$repo_root/go|go run ./crosstest/go_typescript.go"
|
|
"Dart|Go|$repo_root/dart|dart run crosstest/dart_go.dart"
|
|
"Dart|Kotlin|$repo_root/dart|dart run crosstest/dart_kotlin.dart"
|
|
"Dart|Python|$repo_root/dart|dart run crosstest/dart_python.dart"
|
|
"Dart|TypeScript|$repo_root/dart|dart run crosstest/dart_typescript.dart"
|
|
"Kotlin|Dart|$repo_root/kotlin|./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinDartKt"
|
|
"Kotlin|Go|$repo_root/kotlin|./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinGoKt"
|
|
"Kotlin|Python|$repo_root/kotlin|./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinPythonKt"
|
|
"Kotlin|TypeScript|$repo_root/kotlin|./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinTypescriptKt"
|
|
"Python|Dart|$repo_root/python|python3 crosstest/python_dart.py"
|
|
"Python|Go|$repo_root/python|python3 crosstest/python_go.py"
|
|
"Python|Kotlin|$repo_root/python|python3 crosstest/python_kotlin.py"
|
|
"Python|TypeScript|$repo_root/python|python3 crosstest/python_typescript.py"
|
|
"TypeScript|Dart|$repo_root/typescript|./node_modules/.bin/tsx crosstest/typescript_dart.ts"
|
|
"TypeScript|Go|$repo_root/typescript|./node_modules/.bin/tsx crosstest/typescript_go.ts"
|
|
"TypeScript|Kotlin|$repo_root/typescript|./node_modules/.bin/tsx crosstest/typescript_kotlin.ts"
|
|
"TypeScript|Python|$repo_root/typescript|./node_modules/.bin/tsx crosstest/typescript_python.ts"
|
|
)
|
|
declare -A cross_result
|
|
declare -A cross_status
|
|
declare -A cross_pass_lines
|
|
declare -A cross_fail_lines
|
|
declare -A cross_cmds
|
|
|
|
expected_cross_pass_lines=16
|
|
|
|
web_cases=(
|
|
"Dart.io|$repo_root/dart|dart run crosstest/dart_web.dart"
|
|
"Go|$repo_root/go|go run ./crosstest/go_dart_web.go"
|
|
"Kotlin|$repo_root/kotlin|./gradlew run -PmainClass=com.tokilabs.proto_socket.crosstest.KotlinDartWebKt"
|
|
"Python|$repo_root/python|python3 crosstest/python_dart_web.py"
|
|
"TypeScript|$repo_root/typescript|./node_modules/.bin/tsx crosstest/typescript_dart_web.ts"
|
|
)
|
|
declare -A web_result
|
|
declare -A web_ws_result
|
|
declare -A web_wss_result
|
|
declare -A web_status
|
|
declare -A web_pass_lines
|
|
declare -A web_ws_pass_lines
|
|
declare -A web_wss_pass_lines
|
|
declare -A web_fail_lines
|
|
declare -A web_cmds
|
|
declare -A web_block_reason
|
|
|
|
expected_web_pass_lines=4
|
|
expected_web_transport_pass_lines=2
|
|
|
|
count_lines() {
|
|
local pattern="$1"
|
|
local file="$2"
|
|
local count
|
|
if command -v rg >/dev/null 2>&1; then
|
|
count="$(rg -c "$pattern" "$file" 2>/dev/null || true)"
|
|
else
|
|
count="$(grep -Ec "$pattern" "$file" 2>/dev/null || true)"
|
|
fi
|
|
echo "${count:-0}"
|
|
}
|
|
|
|
single_quote() {
|
|
printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
|
|
}
|
|
|
|
remote_exec() {
|
|
local cmd="$1"
|
|
ssh -o BatchMode=yes -o ConnectTimeout=10 "$remote_web_host" "zsh -lc $(single_quote "$cmd")"
|
|
}
|
|
|
|
run_logged() {
|
|
local name="$1"
|
|
local dir="$2"
|
|
local cmd="$3"
|
|
local log_file="$4"
|
|
|
|
printf 'RUN %s\n' "$name" >&2
|
|
(
|
|
cd "$dir" &&
|
|
bash -c "$cmd"
|
|
) >"$log_file" 2>&1
|
|
}
|
|
|
|
chrome_available() {
|
|
if [ -n "${CHROME_EXECUTABLE:-}" ] && [ -x "$CHROME_EXECUTABLE" ]; then
|
|
return 0
|
|
fi
|
|
command -v google-chrome >/dev/null 2>&1
|
|
}
|
|
|
|
remote_chrome_export_command() {
|
|
cat <<'REMOTE_CHROME'
|
|
if [ -n "${CHROME_EXECUTABLE:-}" ] && [ -x "$CHROME_EXECUTABLE" ]; then
|
|
:
|
|
elif [ -n "${repo_dir:-}" ] && [ -x "$repo_dir/.agent-test/chrome-proto-socket-wss" ]; then
|
|
export CHROME_EXECUTABLE="$repo_dir/.agent-test/chrome-proto-socket-wss"
|
|
elif [ -x "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ]; then
|
|
export CHROME_EXECUTABLE="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
elif command -v google-chrome >/dev/null 2>&1; then
|
|
export CHROME_EXECUTABLE="$(command -v google-chrome)"
|
|
elif command -v chromium >/dev/null 2>&1; then
|
|
export CHROME_EXECUTABLE="$(command -v chromium)"
|
|
elif command -v chromium-browser >/dev/null 2>&1; then
|
|
export CHROME_EXECUTABLE="$(command -v chromium-browser)"
|
|
else
|
|
echo "Chrome executable not found on remote." >&2
|
|
exit 90
|
|
fi
|
|
REMOTE_CHROME
|
|
}
|
|
|
|
remote_chrome_wrapper_setup_command() {
|
|
cat <<'REMOTE_CHROME_WRAPPER'
|
|
if [ -x "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ] &&
|
|
command -v openssl >/dev/null 2>&1 &&
|
|
[ -f dart/test/certs/server.crt ]; then
|
|
mkdir -p "$repo_dir/.agent-test"
|
|
spki="$(openssl x509 -in dart/test/certs/server.crt -pubkey -noout |
|
|
openssl pkey -pubin -outform DER |
|
|
openssl dgst -sha256 -binary |
|
|
openssl base64)"
|
|
cat > "$repo_dir/.agent-test/chrome-proto-socket-wss" <<WRAPPER
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
exec "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --ignore-certificate-errors-spki-list="$spki" --allow-insecure-localhost "\$@"
|
|
WRAPPER
|
|
chmod +x "$repo_dir/.agent-test/chrome-proto-socket-wss"
|
|
fi
|
|
REMOTE_CHROME_WRAPPER
|
|
}
|
|
|
|
prepare_remote_web_repo() {
|
|
local repo_name_q repo_url_q repo_ref_q chrome_cmd chrome_wrapper_cmd
|
|
|
|
if [ -z "$remote_web_repo_url" ]; then
|
|
echo "remote repository URL is not configured" >&2
|
|
return 1
|
|
fi
|
|
|
|
repo_name_q="$(single_quote "$remote_web_repo_name")"
|
|
repo_url_q="$(single_quote "$remote_web_repo_url")"
|
|
repo_ref_q="$(single_quote "$remote_web_ref")"
|
|
chrome_cmd="$(remote_chrome_export_command)"
|
|
chrome_wrapper_cmd="$(remote_chrome_wrapper_setup_command)"
|
|
|
|
remote_exec "
|
|
set -e
|
|
repo_parent=$remote_web_root_expr
|
|
repo_name=$repo_name_q
|
|
repo_url=$repo_url_q
|
|
repo_ref=$repo_ref_q
|
|
mkdir -p \"\$repo_parent\"
|
|
repo_dir=\"\$repo_parent/\$repo_name\"
|
|
if [ ! -d \"\$repo_dir/.git\" ]; then
|
|
git clone \"\$repo_url\" \"\$repo_dir\"
|
|
fi
|
|
cd \"\$repo_dir\"
|
|
if ! git diff --quiet || ! git diff --cached --quiet || [ -n \"\$(git ls-files --others --exclude-standard)\" ]; then
|
|
git stash push -u -m \"proto-socket matrix remote test stash \$(date -u +%Y%m%d-%H%M%S)\" >/dev/null
|
|
fi
|
|
git fetch origin --prune
|
|
git checkout \"\$repo_ref\"
|
|
git pull --ff-only origin \"\$repo_ref\"
|
|
(cd dart && dart pub get)
|
|
if [ -f typescript/package.json ]; then
|
|
(cd typescript && npm install)
|
|
fi
|
|
if [ -f python/pyproject.toml ]; then
|
|
(cd python && python3 -m pip install -e '.[dev]')
|
|
fi
|
|
$chrome_wrapper_cmd
|
|
$chrome_cmd
|
|
printf 'remote Dart.web repo: %s\n' \"\$repo_dir\"
|
|
printf 'remote Dart.web git ref: %s\n' \"\$(git rev-parse --short HEAD)\"
|
|
"
|
|
}
|
|
|
|
sync_remote_web_worktree() {
|
|
local changed_list sync_count
|
|
changed_list="$log_dir/remote_web_changed_files.zlist"
|
|
{
|
|
git -C "$repo_root" diff --name-only -z
|
|
git -C "$repo_root" diff --cached --name-only -z
|
|
git -C "$repo_root" ls-files --others --exclude-standard -z
|
|
} | sort -zu >"$changed_list"
|
|
|
|
if [ ! -s "$changed_list" ]; then
|
|
return 0
|
|
fi
|
|
|
|
sync_count="$(tr '\0' '\n' <"$changed_list" | sed '/^$/d' | wc -l | tr -d ' ')"
|
|
(
|
|
cd "$repo_root" &&
|
|
tar --null -T "$changed_list" -cf -
|
|
) | remote_exec "
|
|
set -e
|
|
repo_parent=$remote_web_root_expr
|
|
repo_name=$(single_quote "$remote_web_repo_name")
|
|
repo_dir=\"\$repo_parent/\$repo_name\"
|
|
cd \"\$repo_dir\"
|
|
tar -xf -
|
|
"
|
|
remote_web_prepare_summary="${remote_web_prepare_summary} local worktree sync: ${sync_count} files "
|
|
}
|
|
|
|
run_remote_web_logged() {
|
|
local server="$1"
|
|
local dir="$2"
|
|
local cmd="$3"
|
|
local log_file="$4"
|
|
local rel_dir chrome_cmd rel_dir_q
|
|
|
|
rel_dir="${dir#$repo_root/}"
|
|
rel_dir_q="$(single_quote "$rel_dir")"
|
|
chrome_cmd="$(remote_chrome_export_command)"
|
|
|
|
printf 'RUN remote web %s->Dart.web: %s\n' "$server" "$cmd" >&2
|
|
remote_exec "
|
|
set -e
|
|
repo_parent=$remote_web_root_expr
|
|
repo_name=$(single_quote "$remote_web_repo_name")
|
|
repo_dir=\"\$repo_parent/\$repo_name\"
|
|
$chrome_cmd
|
|
cd \"\$repo_dir\"/$rel_dir_q
|
|
$cmd
|
|
" >"$log_file" 2>&1
|
|
}
|
|
|
|
run_unit_tests() {
|
|
local lang cmd dir log_file status
|
|
for lang in "${languages[@]}"; do
|
|
cmd="${unit_cmds[$lang]}"
|
|
dir="${unit_dirs[$lang]}"
|
|
log_file="$log_dir/unit_${lang}.log"
|
|
run_logged "unit $lang: $cmd" "$dir" "$cmd" "$log_file"
|
|
status=$?
|
|
unit_status[$lang]="$status"
|
|
if [ "$status" -eq 0 ]; then
|
|
unit_result[$lang]="PASS"
|
|
else
|
|
unit_result[$lang]="FAIL"
|
|
fi
|
|
unit_summary[$lang]="$(tail -n 1 "$log_file" | tr '\n' ' ')"
|
|
done
|
|
}
|
|
|
|
run_proto_sync() {
|
|
local log_file status
|
|
log_file="$log_dir/proto_sync.log"
|
|
run_logged "proto sync: $proto_cmd" "$proto_dir" "$proto_cmd" "$log_file"
|
|
status=$?
|
|
proto_status="$status"
|
|
if [ "$status" -eq 0 ]; then
|
|
proto_result="PASS"
|
|
else
|
|
proto_result="FAIL"
|
|
fi
|
|
proto_summary="$(tail -n 1 "$log_file" | tr '\n' ' ')"
|
|
}
|
|
|
|
run_cross_tests() {
|
|
local item server client dir cmd key log_file status pass_count fail_count
|
|
for item in "${cross_cases[@]}"; do
|
|
IFS='|' read -r server client dir cmd <<<"$item"
|
|
key="$server|$client"
|
|
log_file="$log_dir/cross_${server}_${client}.log"
|
|
cross_cmds[$key]="(cd ${dir#$repo_root/} && $cmd)"
|
|
run_logged "cross $server->$client: $cmd" "$dir" "$cmd" "$log_file"
|
|
status=$?
|
|
pass_count="$(count_lines '^PASS scenario=' "$log_file")"
|
|
fail_count="$(count_lines '^FAIL ' "$log_file")"
|
|
cross_status[$key]="$status"
|
|
cross_pass_lines[$key]="$pass_count"
|
|
cross_fail_lines[$key]="$fail_count"
|
|
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$pass_count" -eq "$expected_cross_pass_lines" ]; then
|
|
cross_result[$key]="PASS"
|
|
else
|
|
cross_result[$key]="FAIL"
|
|
fi
|
|
done
|
|
}
|
|
|
|
set_web_result() {
|
|
local key="$1"
|
|
local status="$2"
|
|
local log_file="$3"
|
|
local pass_count fail_count ws_pass_count wss_pass_count
|
|
|
|
pass_count="$(count_lines '^PASS scenario=' "$log_file")"
|
|
ws_pass_count="$(count_lines '^PASS scenario=ws-' "$log_file")"
|
|
wss_pass_count="$(count_lines '^PASS scenario=wss-' "$log_file")"
|
|
fail_count="$(count_lines '^FAIL ' "$log_file")"
|
|
web_status[$key]="$status"
|
|
web_pass_lines[$key]="$pass_count"
|
|
web_ws_pass_lines[$key]="$ws_pass_count"
|
|
web_wss_pass_lines[$key]="$wss_pass_count"
|
|
web_fail_lines[$key]="$fail_count"
|
|
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$pass_count" -eq "$expected_web_pass_lines" ]; then
|
|
web_result[$key]="PASS"
|
|
else
|
|
web_result[$key]="FAIL"
|
|
fi
|
|
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$ws_pass_count" -eq "$expected_web_transport_pass_lines" ]; then
|
|
web_ws_result[$key]="PASS"
|
|
else
|
|
web_ws_result[$key]="FAIL"
|
|
fi
|
|
if [ "$status" -eq 0 ] && [ "$fail_count" -eq 0 ] && [ "$wss_pass_count" -eq "$expected_web_transport_pass_lines" ]; then
|
|
web_wss_result[$key]="PASS"
|
|
else
|
|
web_wss_result[$key]="FAIL"
|
|
fi
|
|
}
|
|
|
|
run_web_tests() {
|
|
local item server dir cmd key log_file status remote_reason
|
|
if ! chrome_available; then
|
|
if ! prepare_remote_web_repo >"$log_dir/remote_web_prepare.log" 2>&1; then
|
|
remote_reason="$(tail -n 20 "$log_dir/remote_web_prepare.log" | tr '\n' ' ')"
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
web_cmds[$key]="ssh $remote_web_host '(cd $remote_web_root_expr/$remote_web_repo_name/${dir#$repo_root/} && $cmd)'"
|
|
web_status[$key]="127"
|
|
web_pass_lines[$key]="0"
|
|
web_ws_pass_lines[$key]="0"
|
|
web_wss_pass_lines[$key]="0"
|
|
web_fail_lines[$key]="0"
|
|
web_result[$key]="BLOCKED"
|
|
web_ws_result[$key]="BLOCKED"
|
|
web_wss_result[$key]="BLOCKED"
|
|
web_block_reason[$key]="Remote Dart.web environment unavailable: $remote_reason"
|
|
printf 'BLOCKED remote web %s->Dart.web: %s\n' "$server" "$remote_reason" >&2
|
|
done
|
|
return
|
|
fi
|
|
remote_web_execution="remote"
|
|
remote_web_prepare_summary="$(grep '^remote Dart.web ' "$log_dir/remote_web_prepare.log" 2>/dev/null | tr '\n' ' ')"
|
|
if ! sync_remote_web_worktree >"$log_dir/remote_web_sync.log" 2>&1; then
|
|
remote_reason="$(tail -n 20 "$log_dir/remote_web_sync.log" | tr '\n' ' ')"
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
web_cmds[$key]="ssh $remote_web_host '(cd $remote_web_root_expr/$remote_web_repo_name/${dir#$repo_root/} && $cmd)'"
|
|
web_status[$key]="127"
|
|
web_pass_lines[$key]="0"
|
|
web_ws_pass_lines[$key]="0"
|
|
web_wss_pass_lines[$key]="0"
|
|
web_fail_lines[$key]="0"
|
|
web_result[$key]="BLOCKED"
|
|
web_ws_result[$key]="BLOCKED"
|
|
web_wss_result[$key]="BLOCKED"
|
|
web_block_reason[$key]="Remote Dart.web worktree sync failed: $remote_reason"
|
|
printf 'BLOCKED remote web %s->Dart.web: %s\n' "$server" "$remote_reason" >&2
|
|
done
|
|
return
|
|
fi
|
|
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
log_file="$log_dir/web_${server}.log"
|
|
web_cmds[$key]="ssh $remote_web_host '(cd $remote_web_root_expr/$remote_web_repo_name/${dir#$repo_root/} && $cmd)'"
|
|
run_remote_web_logged "$server" "$dir" "$cmd" "$log_file"
|
|
status=$?
|
|
set_web_result "$key" "$status" "$log_file"
|
|
done
|
|
return
|
|
fi
|
|
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
log_file="$log_dir/web_${server}.log"
|
|
web_cmds[$key]="(cd ${dir#$repo_root/} && $cmd)"
|
|
run_logged "web $server->Dart.web: $cmd" "$dir" "$cmd" "$log_file"
|
|
status=$?
|
|
set_web_result "$key" "$status" "$log_file"
|
|
done
|
|
}
|
|
|
|
print_proto_table() {
|
|
printf '\n**Proto 동기화**\n'
|
|
printf '| 검사 | 명령 | 결과 |\n'
|
|
printf '|---|---|---|\n'
|
|
printf '| schema sync | `%s` | %s |\n' "$proto_cmd" "$proto_result"
|
|
}
|
|
|
|
print_unit_table() {
|
|
local lang
|
|
printf '\n**동일언어**\n'
|
|
printf '| 언어 | 명령 | 결과 |\n'
|
|
printf '|---|---|---|\n'
|
|
for lang in "${languages[@]}"; do
|
|
printf '| %s | `%s` | %s |\n' "$lang" "${unit_cmds[$lang]}" "${unit_result[$lang]:--}"
|
|
done
|
|
}
|
|
|
|
language_key() {
|
|
local label="$1"
|
|
if [ "$label" = "Dart.io" ]; then
|
|
echo "Dart"
|
|
return
|
|
fi
|
|
echo "$label"
|
|
}
|
|
|
|
display_language_label() {
|
|
local label="$1"
|
|
if [ "$label" = "Dart" ]; then
|
|
echo "Dart.io"
|
|
return
|
|
fi
|
|
echo "$label"
|
|
}
|
|
|
|
language_matrix_cell() {
|
|
local server_label="$1"
|
|
local client_label="$2"
|
|
local server client key
|
|
|
|
if [ "$client_label" = "Dart.web" ]; then
|
|
echo "${web_ws_result[$server_label]:--}"
|
|
return
|
|
fi
|
|
|
|
if [ "$client_label" = "Dart.web(WSS)" ]; then
|
|
echo "${web_wss_result[$server_label]:--}"
|
|
return
|
|
fi
|
|
|
|
server="$(language_key "$server_label")"
|
|
client="$(language_key "$client_label")"
|
|
key="$server|$client"
|
|
|
|
if [ "$server" = "$client" ]; then
|
|
if [ "$mode" = "all" ] || [ "$mode" = "unit" ]; then
|
|
echo "${unit_result[$server]:--}"
|
|
else
|
|
echo "-"
|
|
fi
|
|
return
|
|
fi
|
|
|
|
echo "${cross_result[$key]:--}"
|
|
}
|
|
|
|
print_language_pass_matrix() {
|
|
local server client
|
|
local servers=("Dart.io" "Go" "Kotlin" "Python" "TypeScript")
|
|
local clients=("Dart.io" "Dart.web" "Dart.web(WSS)" "Go" "Kotlin" "Python" "TypeScript")
|
|
|
|
printf '\n**언어 PASS 매트릭스**\n'
|
|
printf '| 서버 \\ 클라이언트'
|
|
for client in "${clients[@]}"; do
|
|
printf ' | %s' "$client"
|
|
done
|
|
printf ' |\n'
|
|
printf '|---'
|
|
for client in "${clients[@]}"; do
|
|
printf '|---'
|
|
done
|
|
printf '|\n'
|
|
for server in "${servers[@]}"; do
|
|
printf '| %s' "$server"
|
|
for client in "${clients[@]}"; do
|
|
printf ' | %s' "$(language_matrix_cell "$server" "$client")"
|
|
done
|
|
printf ' |\n'
|
|
done
|
|
}
|
|
|
|
print_cross_detail_table() {
|
|
local item server client dir cmd key
|
|
printf '\n**크로스테스트 상세**\n'
|
|
printf '| 방향 | 결과 | PASS scenarios | Expected | FAIL lines |\n'
|
|
printf '|---|---:|---:|---:|---:|\n'
|
|
for item in "${cross_cases[@]}"; do
|
|
IFS='|' read -r server client dir cmd <<<"$item"
|
|
key="$server|$client"
|
|
printf '| %s -> %s | %s | %s | %s | %s |\n' \
|
|
"$(display_language_label "$server")" "$(display_language_label "$client")" \
|
|
"${cross_result[$key]:--}" "${cross_pass_lines[$key]:--}" "$expected_cross_pass_lines" "${cross_fail_lines[$key]:--}"
|
|
done
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
printf '| %s -> Dart.web | %s | %s | %s | %s |\n' \
|
|
"$server" "${web_ws_result[$key]:--}" "${web_ws_pass_lines[$key]:--}" "$expected_web_transport_pass_lines" "${web_fail_lines[$key]:--}"
|
|
printf '| %s -> Dart.web(WSS) | %s | %s | %s | %s |\n' \
|
|
"$server" "${web_wss_result[$key]:--}" "${web_wss_pass_lines[$key]:--}" "$expected_web_transport_pass_lines" "${web_fail_lines[$key]:--}"
|
|
done
|
|
}
|
|
|
|
print_failures() {
|
|
local failed=0
|
|
local lang item server client dir cmd key log_file
|
|
|
|
if [ "${proto_result:-}" = "FAIL" ]; then
|
|
failed=1
|
|
log_file="$log_dir/proto_sync.log"
|
|
printf '\n**실패: Proto 동기화 검사**\n'
|
|
printf '재현 명령: `(cd . && %s)`\n\n' "$proto_cmd"
|
|
tail -n 80 "$log_file"
|
|
printf '\n'
|
|
fi
|
|
|
|
for lang in "${languages[@]}"; do
|
|
if [ "${unit_result[$lang]:-}" = "FAIL" ]; then
|
|
failed=1
|
|
log_file="$log_dir/unit_${lang}.log"
|
|
printf '\n**실패: %s 유닛/동일언어 테스트**\n' "$lang"
|
|
printf '재현 명령: `(cd %s && %s)`\n\n' "${unit_dirs[$lang]#$repo_root/}" "${unit_cmds[$lang]}"
|
|
tail -n 80 "$log_file"
|
|
printf '\n'
|
|
fi
|
|
done
|
|
|
|
for item in "${cross_cases[@]}"; do
|
|
IFS='|' read -r server client dir cmd <<<"$item"
|
|
key="$server|$client"
|
|
if [ "${cross_result[$key]:-}" = "FAIL" ]; then
|
|
failed=1
|
|
log_file="$log_dir/cross_${server}_${client}.log"
|
|
printf '\n**실패: %s -> %s 크로스테스트**\n' "$server" "$client"
|
|
printf '재현 명령: `%s`\n\n' "${cross_cmds[$key]}"
|
|
tail -n 80 "$log_file"
|
|
printf '\n'
|
|
fi
|
|
done
|
|
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
if [ "${web_result[$key]:-}" = "BLOCKED" ]; then
|
|
failed=1
|
|
printf '\n**차단: %s -> Dart.web 크로스테스트**\n' "$server"
|
|
printf '재현 명령: `%s`\n' "${web_cmds[$key]}"
|
|
printf '차단 사유: %s\n\n' "${web_block_reason[$key]:-unknown}"
|
|
elif [ "${web_result[$key]:-}" = "FAIL" ]; then
|
|
failed=1
|
|
log_file="$log_dir/web_${server}.log"
|
|
printf '\n**실패: %s -> Dart.web 크로스테스트**\n' "$server"
|
|
printf '재현 명령: `%s`\n\n' "${web_cmds[$key]}"
|
|
tail -n 80 "$log_file"
|
|
printf '\n'
|
|
fi
|
|
done
|
|
|
|
return "$failed"
|
|
}
|
|
|
|
has_blocked_results() {
|
|
local item server dir cmd key
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
if [ "${web_result[$key]:-}" = "BLOCKED" ]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
has_fail_results() {
|
|
local lang item server client dir cmd key
|
|
if [ "${proto_result:-}" = "FAIL" ]; then
|
|
return 0
|
|
fi
|
|
for lang in "${languages[@]}"; do
|
|
if [ "${unit_result[$lang]:-}" = "FAIL" ]; then
|
|
return 0
|
|
fi
|
|
done
|
|
for item in "${cross_cases[@]}"; do
|
|
IFS='|' read -r server client dir cmd <<<"$item"
|
|
key="$server|$client"
|
|
if [ "${cross_result[$key]:-}" = "FAIL" ]; then
|
|
return 0
|
|
fi
|
|
done
|
|
for item in "${web_cases[@]}"; do
|
|
IFS='|' read -r server dir cmd <<<"$item"
|
|
key="$server"
|
|
if [ "${web_result[$key]:-}" = "FAIL" ]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
overall_result_value() {
|
|
if has_fail_results; then
|
|
echo "FAIL"
|
|
elif has_blocked_results; then
|
|
echo "BLOCKED"
|
|
else
|
|
echo "PASS"
|
|
fi
|
|
}
|
|
|
|
print_report_body() {
|
|
if [ "$mode" = "all" ] || [ "$mode" = "proto" ]; then
|
|
print_proto_table
|
|
fi
|
|
if [ "$mode" = "all" ] || [ "$mode" = "unit" ]; then
|
|
print_unit_table
|
|
fi
|
|
if [ "$mode" = "all" ] || [ "$mode" = "cross" ]; then
|
|
print_language_pass_matrix
|
|
print_cross_detail_table
|
|
fi
|
|
|
|
printf '\n로그 디렉터리: `%s`\n' "$log_dir"
|
|
|
|
if print_failures; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
write_result_record() {
|
|
local report_body="$1"
|
|
local exit_code="$2"
|
|
local overall_result record_dir record_file git_ref
|
|
|
|
overall_result="$(overall_result_value)"
|
|
|
|
record_dir="$repo_root/agent-test/runs"
|
|
mkdir -p "$record_dir"
|
|
record_file="$record_dir/${run_record_stamp}-${record_profile}.md"
|
|
git_ref="$(git -C "$repo_root" rev-parse --short HEAD 2>/dev/null || echo "unknown")"
|
|
|
|
{
|
|
printf '%s\n' '---'
|
|
printf 'test_env: local\n'
|
|
printf 'record_type: test-result\n'
|
|
printf 'test_profile: %s\n' "$record_profile"
|
|
printf 'created_at: %s\n' "$run_started_at"
|
|
printf 'overall_result: %s\n' "$overall_result"
|
|
printf '%s\n\n' '---'
|
|
printf '# %s local 결과 기록\n\n' "$record_profile"
|
|
printf '## 실행 정보\n\n'
|
|
printf -- '- 실행 일시: %s\n' "$run_started_at"
|
|
printf -- '- git ref: %s\n' "$git_ref"
|
|
printf -- '- 실행 명령: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --%s`\n' "$mode"
|
|
printf -- '- exit code: %s\n' "$exit_code"
|
|
printf -- '- 로그 디렉터리: `%s`\n' "$log_dir"
|
|
if [ "$mode" = "all" ] || [ "$mode" = "cross" ]; then
|
|
printf -- '- Dart.web 실행 환경: %s\n' "$remote_web_execution"
|
|
if [ "$remote_web_execution" = "remote" ]; then
|
|
printf -- '- Dart.web remote host: `%s`\n' "$remote_web_host"
|
|
printf -- '- Dart.web remote path: `%s/%s`\n' "$remote_web_root_expr" "$remote_web_repo_name"
|
|
printf -- '- Dart.web remote 준비: %s\n' "$remote_web_prepare_summary"
|
|
fi
|
|
fi
|
|
printf -- '- 전체 결과값: %s\n\n' "$overall_result"
|
|
printf '## git status 요약\n\n'
|
|
printf '```text\n'
|
|
git -C "$repo_root" status --short 2>/dev/null || true
|
|
printf '```\n\n'
|
|
cat "$report_body"
|
|
} >"$record_file"
|
|
|
|
printf '%s' "$record_file"
|
|
}
|
|
|
|
main() {
|
|
local report_body exit_code record_file display_record_file
|
|
|
|
case "$mode" in
|
|
all)
|
|
run_proto_sync
|
|
run_unit_tests
|
|
run_cross_tests
|
|
run_web_tests
|
|
;;
|
|
unit)
|
|
run_unit_tests
|
|
;;
|
|
cross)
|
|
run_cross_tests
|
|
run_web_tests
|
|
;;
|
|
proto)
|
|
run_proto_sync
|
|
;;
|
|
esac
|
|
|
|
report_body="$log_dir/report.md"
|
|
if print_report_body >"$report_body"; then
|
|
exit_code=0
|
|
else
|
|
exit_code=1
|
|
fi
|
|
|
|
record_file="$(write_result_record "$report_body" "$exit_code")"
|
|
cat "$report_body"
|
|
display_record_file="${record_file#$repo_root/}"
|
|
printf '\n결과 기록 파일: `%s`\n' "$display_record_file"
|
|
|
|
exit "$exit_code"
|
|
}
|
|
|
|
main "$@"
|