-
Notifications
You must be signed in to change notification settings - Fork 126
test(starry,nginx): implement alpine app nginx CI #1014
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
2b5ecb7
f2d0b2c
6f8d79e
da9d4ea
14fe46e
68491fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Starry Nginx App | ||
|
|
||
| This app organizes nginx tests into four directories: | ||
|
|
||
| - `smoke/`: CI entry smoke test (the only connected nginx test in tgoskits) | ||
| - `phase/`: stage-unit tests named by `x-x`, such as `nginx-1-3-lifecycle-tests.sh` | ||
| - `stress/`: pressure test planning and future scripts | ||
| - `debug/`: flexible issue-focused scripts | ||
|
|
||
| ## CI-Connected Entry | ||
|
|
||
| Only smoke is connected: | ||
|
|
||
| ```bash | ||
| cargo xtask starry app run -t nginx --arch riscv64 | ||
| ``` | ||
|
|
||
| `qemu-*.toml` starts `/usr/bin/nginx-smoke-tests.sh` only. | ||
|
|
||
| ## Local Development CLI | ||
|
|
||
| Unified local CLI script: | ||
|
|
||
| ```bash | ||
| ./apps/starry/nginx/nginx-cli-tests.sh smoke | ||
| ./apps/starry/nginx/nginx-cli-tests.sh phase1 | ||
| ./apps/starry/nginx/nginx-cli-tests.sh phase2 | ||
| ./apps/starry/nginx/nginx-cli-tests.sh all | ||
| ``` | ||
|
|
||
| ## Build/Prepare Logic | ||
|
|
||
| `prebuild.sh` injects only smoke entry and shared mirror helper into guest overlay: | ||
|
|
||
| - `/usr/bin/nginx-smoke-tests.sh` | ||
| - `/usr/bin/nginx-alpine-mirror.sh` | ||
|
|
||
| Mirror helper: `apps/starry/nginx/nginx-alpine-mirror.sh`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| target = "riscv64gc-unknown-none-elf" | ||
| env = { AX_IP = "10.0.2.15", AX_GW = "10.0.2.2" } | ||
| log = "Warn" | ||
| features = [ | ||
| "ax-hal/riscv64-qemu-virt", | ||
| "qemu", | ||
| "ax-driver/pci", | ||
| "ax-driver/virtio-blk", | ||
| "ax-driver/virtio-net", | ||
| "ax-driver/virtio-gpu", | ||
| "ax-driver/virtio-input", | ||
| "ax-driver/virtio-socket", | ||
| ] | ||
| plat_dyn = false | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| target = "x86_64-unknown-none" | ||
| env = { AX_IP = "10.0.2.15", AX_GW = "10.0.2.2" } | ||
| log = "Warn" | ||
| features = [ | ||
| "ax-hal/x86-pc", | ||
| "qemu", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
另外,riscv64 侧的 feature 集也需要参照 dev 分支上的 test-suit 共享 build config 重新对齐(注意 dev 分支上 riscv64 使用
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 已修改 |
||
| "ax-driver/pci", | ||
| "ax-driver/virtio-blk", | ||
| "ax-driver/virtio-net", | ||
| "ax-driver/virtio-gpu", | ||
| "ax-driver/virtio-input", | ||
| "ax-driver/virtio-socket", | ||
| ] | ||
| plat_dyn = false | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Nginx Debug Tests | ||
|
|
||
| This directory stores flexible debug scripts for single issue reproduction and diagnosis. | ||
|
|
||
| Current scripts: | ||
|
|
||
| - `nginx-http-basic-tests.sh`: early HTTP basic script kept for issue-level debugging. | ||
|
|
||
| Rule: | ||
|
|
||
| - Debug scripts are free-form and can focus on one syscall or one behavior path. | ||
| - Debug scripts are not connected to tgoskits nginx CI entry. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| #!/bin/sh | ||
|
|
||
| BASE=/tmp/nginx-http-basic | ||
| CONF="$BASE/conf/http-basic.conf" | ||
| WWW="$BASE/www" | ||
| LOGDIR="$BASE/logs" | ||
| OUT="$BASE/out" | ||
| NGINX_PID= | ||
| FAILURES=0 | ||
| TIMEOUT_CMD= | ||
|
|
||
| . /usr/bin/nginx-alpine-mirror.sh | ||
|
|
||
| log() { printf 'NGINX_HTTP_BASIC_LOG: %s\n' "$*"; } | ||
| pass() { printf 'NGINX_HTTP_BASIC_STEP_PASS: %s\n' "$*"; } | ||
| fail() { printf 'NGINX_HTTP_BASIC_STEP_FAIL: %s\n' "$*"; FAILURES=$((FAILURES + 1)); } | ||
|
|
||
| run_step() { | ||
| step_name=$1 | ||
| shift | ||
| log "BEGIN $step_name" | ||
| if "$@"; then | ||
| pass "$step_name" | ||
| return 0 | ||
| fi | ||
| fail "$step_name" | ||
| return 1 | ||
| } | ||
|
|
||
| init_timeout_cmd() { | ||
| if command -v timeout >/dev/null 2>&1; then | ||
| TIMEOUT_CMD='timeout' | ||
| return 0 | ||
| fi | ||
| if busybox timeout 2>&1 | grep -qi 'usage'; then | ||
| TIMEOUT_CMD='busybox timeout' | ||
| return 0 | ||
| fi | ||
| TIMEOUT_CMD= | ||
| return 0 | ||
| } | ||
|
|
||
| run_with_timeout() { | ||
| timeout_sec=$1 | ||
| shift | ||
| if [ -n "$TIMEOUT_CMD" ]; then | ||
| $TIMEOUT_CMD "$timeout_sec" "$@" | ||
| return $? | ||
| fi | ||
| "$@" | ||
| } | ||
|
|
||
| cleanup() { | ||
| if [ -n "$NGINX_PID" ] && kill -0 "$NGINX_PID" 2>/dev/null; then | ||
| kill -TERM "$NGINX_PID" 2>/dev/null || true | ||
| sleep 1 | ||
| kill -KILL "$NGINX_PID" 2>/dev/null || true | ||
| fi | ||
| } | ||
|
|
||
| finish() { | ||
| status=$? | ||
| cleanup | ||
| if [ "$FAILURES" -eq 0 ] && [ "$status" -eq 0 ]; then | ||
| printf 'NGINX_HTTP_BASIC_PASSED\n' | ||
| exit 0 | ||
| fi | ||
| printf 'NGINX_HTTP_BASIC_FAILED failures=%s status=%s\n' "$FAILURES" "$status" | ||
| exit 1 | ||
| } | ||
|
|
||
| trap finish EXIT | ||
|
|
||
| prepare_packages() { | ||
| nginx_apk_add_with_fallback nginx curl busybox-extras || { | ||
| printf 'NGINX_HTTP_BASIC_PREPARE_FAILED: all mirrors failed\n' | ||
| return 1 | ||
| } | ||
| } | ||
|
|
||
| prepare_tree() { | ||
| rm -rf "$BASE" | ||
| mkdir -p "$BASE/conf" "$WWW/dir" "$LOGDIR" "$OUT" "$BASE/client_temp" | ||
| printf 'HTTP_BASIC_INDEX_OK\n' > "$WWW/index.html" | ||
| printf 'small static file\n' > "$WWW/small.txt" | ||
| : > "$WWW/empty.txt" | ||
| printf 'HTTP_BASIC_DIR_INDEX_OK\n' > "$WWW/dir/index.html" | ||
|
|
||
| cat > "$CONF" <<'EOF_CONF' | ||
| daemon off; | ||
| master_process off; | ||
| worker_processes 1; | ||
| error_log /tmp/nginx-http-basic/logs/error.log debug; | ||
| pid /tmp/nginx-http-basic/nginx.pid; | ||
|
|
||
| events { worker_connections 64; } | ||
|
|
||
| http { | ||
| include /etc/nginx/mime.types; | ||
| default_type application/octet-stream; | ||
| access_log /tmp/nginx-http-basic/logs/access.log; | ||
| sendfile off; | ||
| keepalive_timeout 5; | ||
| client_body_temp_path /tmp/nginx-http-basic/client_temp; | ||
| server { | ||
| listen 127.0.0.1:8080; | ||
| server_name localhost; | ||
| root /tmp/nginx-http-basic/www; | ||
| location / { index index.html; } | ||
| } | ||
| } | ||
| EOF_CONF | ||
| } | ||
|
|
||
| test_config() { nginx -t -c "$CONF" -p "$BASE/"; } | ||
|
|
||
| start_nginx() { | ||
| nginx -c "$CONF" -p "$BASE/" > "$LOGDIR/nginx-stdout.log" 2>&1 & | ||
| NGINX_PID=$! | ||
| i=0 | ||
| while [ "$i" -lt 90 ]; do | ||
| if ! kill -0 "$NGINX_PID" 2>/dev/null; then return 1; fi | ||
| if run_with_timeout 8 curl -fsS -o "$OUT/startup.body" http://127.0.0.1:8080/ >/dev/null 2>&1; then return 0; fi | ||
| sleep 1 | ||
| i=$((i + 1)) | ||
| done | ||
| return 1 | ||
| } | ||
|
|
||
| test_get_small() { | ||
| code=$(run_with_timeout 12 curl -sS -D "$OUT/small.headers" -o "$OUT/small.body" -w '%{http_code}' http://127.0.0.1:8080/small.txt || printf 'curl_failed') | ||
| [ "$code" = "200" ] && grep -qx 'small static file' "$OUT/small.body" && grep -qi '^Content-Length: 18' "$OUT/small.headers" | ||
| } | ||
|
|
||
| test_get_empty() { | ||
| code=$(run_with_timeout 12 curl -sS -D "$OUT/empty.headers" -o "$OUT/empty.body" -w '%{http_code}' http://127.0.0.1:8080/empty.txt || printf 'curl_failed') | ||
| [ "$code" = "200" ] && [ "$(wc -c < "$OUT/empty.body")" -eq 0 ] && grep -qi '^Content-Length: 0' "$OUT/empty.headers" | ||
| } | ||
|
|
||
| test_get_dir_slash() { | ||
| code=$(run_with_timeout 12 curl -sS -D "$OUT/dir-slash.headers" -o "$OUT/dir-slash.body" -w '%{http_code}' http://127.0.0.1:8080/dir/ || printf 'curl_failed') | ||
| [ "$code" = "200" ] && grep -qx 'HTTP_BASIC_DIR_INDEX_OK' "$OUT/dir-slash.body" | ||
| } | ||
|
|
||
| test_get_dir_redirect() { | ||
| code=$(run_with_timeout 12 curl -sS -D "$OUT/dir.headers" -o "$OUT/dir.body" -w '%{http_code}' http://127.0.0.1:8080/dir || printf 'curl_failed') | ||
| [ "$code" = "301" ] || [ "$code" = "302" ] | ||
| } | ||
|
|
||
| test_bad_method() { | ||
| if command -v nc >/dev/null 2>&1; then | ||
| NC='nc' | ||
| elif busybox nc 2>&1 | grep -qi 'usage'; then | ||
| NC='busybox nc' | ||
| else | ||
| return 0 | ||
| fi | ||
| { printf 'BAD / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n'; } | run_with_timeout 12 sh -c "$NC 127.0.0.1 8080" > "$OUT/bad-method.raw" | ||
| tr -d '\r' < "$OUT/bad-method.raw" > "$OUT/bad-method.normalized" | ||
| grep -Eq '^HTTP/1.1 (400|405)' "$OUT/bad-method.normalized" | ||
| } | ||
|
|
||
| stop_nginx() { | ||
| kill -TERM "$NGINX_PID" | ||
| i=0 | ||
| while kill -0 "$NGINX_PID" 2>/dev/null && [ "$i" -lt 30 ]; do | ||
| sleep 1 | ||
| i=$((i + 1)) | ||
| done | ||
| ! kill -0 "$NGINX_PID" 2>/dev/null | ||
| } | ||
|
|
||
| run_step "prepare packages" prepare_packages || exit 1 | ||
| run_step "prepare nginx files" prepare_tree || exit 1 | ||
| run_step "init timeout helper" init_timeout_cmd || exit 1 | ||
| run_step "nginx config test" test_config || exit 1 | ||
| run_step "start nginx" start_nginx || exit 1 | ||
| run_step "GET /small.txt" test_get_small | ||
| run_step "GET /empty.txt" test_get_empty | ||
| run_step "GET /dir/" test_get_dir_slash | ||
| run_step "GET /dir redirect" test_get_dir_redirect | ||
| run_step "BAD method returns 400/405" test_bad_method | ||
| run_step "stop nginx" stop_nginx |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #!/bin/sh | ||
|
|
||
| set -eu | ||
|
|
||
| NGINX_APK_MIRROR_TIMEOUT_SEC="${NGINX_APK_MIRROR_TIMEOUT_SEC:-45}" | ||
| NGINX_APK_REPO_FILE="/tmp/nginx-apk-repositories" | ||
| NGINX_APK_ATTEMPT_LOG="/tmp/nginx-apk-attempt.log" | ||
|
|
||
| write_repo_file() { | ||
| mirror="$1" | ||
| cat >"$NGINX_APK_REPO_FILE" <<EOF | ||
| $mirror/main | ||
| $mirror/community | ||
| EOF | ||
| } | ||
|
|
||
| run_apk_add() { | ||
| mirror="$1" | ||
| shift | ||
| packages="$*" | ||
|
|
||
| echo "NGINX_APK_MIRROR_TRY: $mirror" | ||
| write_repo_file "$mirror" | ||
|
|
||
| if timeout "$NGINX_APK_MIRROR_TIMEOUT_SEC" apk --no-progress --update-cache --repositories-file "$NGINX_APK_REPO_FILE" add $packages >"$NGINX_APK_ATTEMPT_LOG" 2>&1; then | ||
| echo "NGINX_APK_MIRROR_OK: $mirror" | ||
| return 0 | ||
| fi | ||
|
|
||
| rc=$? | ||
| if [ "$rc" -eq 124 ]; then | ||
| echo "NGINX_APK_MIRROR_FAIL: $mirror (timeout ${NGINX_APK_MIRROR_TIMEOUT_SEC}s)" | ||
| else | ||
| echo "NGINX_APK_MIRROR_FAIL: $mirror (apk rc=$rc)" | ||
| fi | ||
| sed -n '1,120p' "$NGINX_APK_ATTEMPT_LOG" || true | ||
| return 1 | ||
| } | ||
|
|
||
| nginx_apk_add_with_fallback() { | ||
| mirror_cn="https://mirrors.tuna.tsinghua.edu.cn/alpine/latest-stable" | ||
| mirror_global="https://dl-cdn.alpinelinux.org/alpine/latest-stable" | ||
|
|
||
| if run_apk_add "$mirror_cn" "$@"; then | ||
| return 0 | ||
| fi | ||
| if run_apk_add "$mirror_global" "$@"; then | ||
| return 0 | ||
| fi | ||
|
|
||
| echo "NGINX_APK_ALL_MIRRORS_FAILED" | ||
| return 1 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| #!/bin/sh | ||
| set -eu | ||
|
|
||
| cmd=${1:-all} | ||
|
|
||
| case "$cmd" in | ||
| smoke) | ||
| sh ./smoke/nginx-smoke-tests.sh | ||
| ;; | ||
| phase1) | ||
| sh ./phase/nginx-1-3-lifecycle-tests.sh | ||
| ;; | ||
| phase2) | ||
| sh ./phase/nginx-2-0-http-basic-tests.sh | ||
| ;; | ||
| all) | ||
| sh ./smoke/nginx-smoke-tests.sh | ||
| sh ./phase/nginx-1-3-lifecycle-tests.sh | ||
| sh ./phase/nginx-2-0-http-basic-tests.sh | ||
| printf 'NGINX_CLI_ALL_PASSED\n' | ||
| ;; | ||
| *) | ||
| printf 'usage: %s [smoke|phase1|phase2|all]\n' "$0" | ||
| exit 2 | ||
| ;; | ||
| esac |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # Nginx Phase Tests | ||
|
|
||
| Phase tests are organized by stage unit `x-x`. | ||
|
|
||
| Current scripts: | ||
|
|
||
| - `nginx-1-3-lifecycle-tests.sh`: covers phase 1.1, 1.2, and 1.3 lifecycle checks. | ||
| - `nginx-2-0-http-basic-tests.sh`: covers phase 2 HTTP basic semantics. | ||
|
|
||
| Rule: | ||
|
|
||
| - Each phase script must include all checks of that phase, including checks already covered by smoke. | ||
| - Phase scripts are managed for development iteration and are not connected as tgoskits nginx CI entry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
同上,
ax-driver/pcifeature 不存在。请参照test-suit/starryos/normal/qemu-smp1/build-riscv64gc-unknown-none-elf.toml的 feature 集修正。当前 dev 分支上 riscv64 的正确组合为:ax-feat/rtc、ax-driver/rtc、ax-driver/serial、ax-driver/virtio-*、starry-kernel/input,plat_dyn = true。There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
已修改