test(版本計算): 補上分頁與 semver 取最大的測試並調整 mock jq/curl
AI / Code Review (pull_request) Failing after 6s

This commit is contained in:
Jeffery
2026-06-23 17:09:25 +08:00
parent 51605b09ea
commit 2cab970059
+150 -45
View File
@@ -33,7 +33,6 @@ assert_eq() {
make_mock_curl() { make_mock_curl() {
local bin_dir="$1" local bin_dir="$1"
local response_file="$2"
cat >"$bin_dir/curl" <<'EOF' cat >"$bin_dir/curl" <<'EOF'
#!/bin/sh #!/bin/sh
@@ -45,6 +44,26 @@ if [ "${FAKE_CURL_STATUS:-0}" != "0" ]; then
exit "$FAKE_CURL_STATUS" exit "$FAKE_CURL_STATUS"
fi fi
# 分頁模式:依 URL 上的 page=N 回傳對應的 page 檔,超出範圍回傳空陣列
if [ -n "${FAKE_CURL_PAGES_DIR:-}" ]; then
page=1
for arg in "$@"; do
case "$arg" in
*page=*)
page=${arg##*page=}
page=${page%%&*}
;;
esac
done
page_file="$FAKE_CURL_PAGES_DIR/$page.json"
if [ -f "$page_file" ]; then
cat "$page_file"
else
printf '[]'
fi
exit 0
fi
cat "${FAKE_CURL_RESPONSE_FILE:?}" cat "${FAKE_CURL_RESPONSE_FILE:?}"
EOF EOF
chmod +x "$bin_dir/curl" chmod +x "$bin_dir/curl"
@@ -55,42 +74,63 @@ make_mock_jq() {
cat >"$bin_dir/jq" <<'EOF' cat >"$bin_dir/jq" <<'EOF'
#!/bin/sh #!/bin/sh
is_beta="" python3 -c '
query="" import json, re, sys
while [ "$#" -gt 0 ]; do args = sys.argv[1:]
case "$1" in named = {}
-r) use_stdin = True
shift i = 0
;; while i < len(args):
--arg) a = args[i]
if [ "$2" = "is_beta" ]; then if a == "-r":
is_beta="$3" i += 1
fi elif a == "-n":
shift 3 use_stdin = False
;; i += 1
*) elif a in ("--arg", "--argjson"):
query="$1" value = args[i + 2]
shift named[args[i + 1]] = json.loads(value) if a == "--argjson" else value
break i += 3
;; else:
esac i += 1
done
python3 -c 'import json, sys payload = sys.stdin.read() if use_stdin else ""
query = sys.argv[1]
is_beta = sys.argv[2] def parse_or_exit(text):
payload = sys.stdin.read() try:
try: return json.loads(text)
data = json.loads(payload) except Exception:
except Exception: sys.exit(4)
sys.exit(4)
# merge 模式:$acc + $page
if "acc" in named and "page" in named:
sys.stdout.write(json.dumps(named["acc"] + named["page"]))
sys.exit(0)
# count 模式:陣列長度,非陣列回 -1
if "is_beta" not in named:
data = parse_or_exit(payload)
sys.stdout.write(str(len(data)) if isinstance(data, list) else "-1")
sys.exit(0)
# calculate 模式
data = parse_or_exit(payload)
is_beta = named.get("is_beta", "")
def to_tuple(ver):
nums = []
for part in ver.split("."):
try:
nums.append(int(part))
except Exception:
nums.append(0)
while len(nums) < 3:
nums.append(0)
return tuple(nums[:3])
def next_version(latest): def next_version(latest):
parts = [int(p or 0) for p in latest.split(".")] major, minor, patch = to_tuple(latest)
while len(parts) < 3:
parts.append(0)
major, minor, patch = parts[:3]
patch += 1 patch += 1
if patch >= 10: if patch >= 10:
patch = 0 patch = 0
@@ -98,18 +138,17 @@ def next_version(latest):
if minor >= 10: if minor >= 10:
minor = 0 minor = 0
major += 1 major += 1
return f"{major}.{minor}.{patch}" return "{}.{}.{}".format(major, minor, patch)
def beta_max(data, prefix): def beta_max(items, prefix):
values = [] values = []
for item in data: for item in items:
if not isinstance(item, dict): if not isinstance(item, dict):
continue continue
tag = item.get("tag_name") tag = item.get("tag_name")
if isinstance(tag, str) and tag.startswith(prefix): if isinstance(tag, str) and tag.startswith(prefix):
suffix = tag[len(prefix):]
try: try:
values.append(int(suffix)) values.append(int(tag[len(prefix):]))
except Exception: except Exception:
pass pass
return max(values) if values else 0 return max(values) if values else 0
@@ -117,22 +156,24 @@ def beta_max(data, prefix):
if not isinstance(data, list): if not isinstance(data, list):
base = "0.0.0" base = "0.0.0"
else: else:
base = "0.0.0" stable = []
for item in data: for item in data:
if not isinstance(item, dict): if not isinstance(item, dict):
continue continue
tag = item.get("tag_name") tag = item.get("tag_name")
if isinstance(tag, str) and "-beta." not in tag: if isinstance(tag, str) and "-beta." not in tag:
base = tag[1:] if tag.startswith("v") else tag ver = tag[1:] if tag.startswith("v") else tag
break if re.match(r"^[0-9]+(\.[0-9]+)*$", ver):
stable.append(ver)
base = max(stable, key=to_tuple) if stable else "0.0.0"
next_ver = next_version(base) next_ver = next_version(base)
if is_beta == "true": if is_beta == "true":
beta = beta_max(data, f"v{next_ver}-beta.") + 1 beta = beta_max(data, "v{}-beta.".format(next_ver)) + 1
sys.stdout.write(f"{base}\t{next_ver}-beta.{beta}") sys.stdout.write("{}\t{}-beta.{}".format(base, next_ver, beta))
else: else:
sys.stdout.write(f"{base}\t{next_ver}") sys.stdout.write("{}\t{}".format(base, next_ver))
' "$query" "$is_beta" ' "$@"
EOF EOF
chmod +x "$bin_dir/jq" chmod +x "$bin_dir/jq"
} }
@@ -281,6 +322,69 @@ test_null_release_payload() {
assert_eq "version=0.0.1" "$(cat "$output_file")" "null release payload" assert_eq "version=0.0.1" "$(cat "$output_file")" "null release payload"
} }
test_pagination_collects_all_pages() {
local workdir
local pages_dir
local bin_dir
local output_file
local stdout_file
local stderr_file
local curl_args
local i
workdir="$(mktemp -d)"
CLEANUP_PATHS+=("$workdir")
pages_dir="$workdir/pages"
mkdir -p "$pages_dir"
# 第 1 頁滿載 10 筆,且全部是 beta(重現「最新一整頁都是 beta」的情境)
{
printf '['
for i in $(seq 1 10); do
if [ "$i" -gt 1 ]; then printf ','; fi
printf '{"tag_name":"v1.9.0-beta.%s"}' "$i"
done
printf ']'
} >"$pages_dir/1.json"
# 第 2 頁才出現穩定版,且故意讓最大值不是第一筆(驗證 semver 取最大)
cat >"$pages_dir/2.json" <<'JSON'
[
{"tag_name":"v1.2.3"},
{"tag_name":"v1.3.1"},
{"tag_name":"v1.2.9"}
]
JSON
bin_dir="$workdir/bin"
mkdir -p "$bin_dir"
make_mock_curl "$bin_dir"
make_mock_jq "$bin_dir"
output_file="$workdir/github_output"
stdout_file="$workdir/stdout"
stderr_file="$workdir/stderr"
FAKE_CURL_STATUS=0 \
FAKE_CURL_PAGES_DIR="$pages_dir" \
FAKE_CURL_LOG_FILE="$workdir/curl_args" \
PATH="$bin_dir:$PATH" \
GITEA_SERVER_URL="https://gitea.example.com" \
GITEA_REPOSITORY="org/repo" \
IS_BETA="false" \
GITHUB_OUTPUT="$output_file" \
bash "$ROOT_DIR/entrypoint.sh" >"$stdout_file" 2>"$stderr_file"
# 穩定版在第 2 頁、最大為 1.3.1 -> 下一版 1.3.2
assert_eq "version=1.3.2" "$(cat "$output_file")" "pagination + semver max output"
# 確認確實翻到第 2 頁
curl_args="$workdir/curl_args"
if ! grep -q 'page=2' "$curl_args"; then
fail "pagination: expected a request for page=2"
fi
}
test_token_auth_header() { test_token_auth_header() {
local workdir local workdir
local response_file local response_file
@@ -392,6 +496,7 @@ test_beta_release_flow
test_empty_release_list test_empty_release_list
test_only_beta_releases test_only_beta_releases
test_null_release_payload test_null_release_payload
test_pagination_collects_all_pages
test_token_auth_header test_token_auth_header
test_malformed_release_payload test_malformed_release_payload
test_curl_failure test_curl_failure