Skip to content

Commit 7009d5f

Browse files
authored
Fix HEAD / returning 405 and add port auto-increment test (#15)
* Fix HEAD / returning 405 and add port auto-increment test (#15) The CI setup action health check uses `curl -sf -I` (HEAD request) to verify spiceio is ready. HEAD on the root path returned 405 MethodNotAllowed, and curl's -f flag suppresses output on 4xx errors, causing the Server header grep to find nothing and the 30s timeout loop to expire. - Handle HEAD at root path alongside GET (ListBuckets) - Add port auto-increment integration test: starts a second instance on the same bind address, verifies it auto-increments, and confirms both instances serve S3 requests * Fix action health check: remove curl -f flag from HEAD requests The -f flag makes curl suppress output on 4xx responses. Since HEAD / returns 405 on existing releases, the Server header grep finds nothing and the startup loop times out after 30s. Removing -f lets curl output headers regardless of status code. * Use simple connectivity check for startup health probe Older spiceio binaries may not set the Server header at all. The startup health check only needs to confirm the process we just started is responding — drop the Server header requirement and use a plain GET. * Bump version to v0.4.2 * Address review feedback on port test and health check - Port assertion: accept any port in auto-increment range, not just +1 - Summary label: fix misleading per-section counter display - Health check: add -f back now that HEAD / returns 200
1 parent 3fce49d commit 7009d5f

5 files changed

Lines changed: 116 additions & 21 deletions

File tree

.github/actions/setup/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ runs:
8282
8383
# Check if spiceio is already listening on the requested address
8484
WANT_VERSION=$(spiceio --version | awk '{print $2}')
85-
RUNNING_HEADER=$(curl -sf -I "http://${SPICEIO_BIND}/" 2>/dev/null | grep -i '^server:.*spiceio' | tr -d '\r' || true)
85+
RUNNING_HEADER=$(curl -s -I "http://${SPICEIO_BIND}/" 2>/dev/null | grep -i '^server:.*spiceio' | tr -d '\r' || true)
8686
if [[ -n "$RUNNING_HEADER" ]]; then
8787
# Extract version from "Server: spiceio/X.Y.Z"; bare "Server: spiceio"
8888
# (no slash) means a pre-versioned build — treat as outdated.
@@ -160,7 +160,7 @@ runs:
160160
exit 1
161161
fi
162162
ENDPOINT=$(grep 'listening on' "$SPICEIO_LOG" 2>/dev/null | grep -o 'http://[^ ]*' | tail -1 || true)
163-
if [[ -n "$ENDPOINT" ]] && curl -sf -I "$ENDPOINT/" 2>/dev/null | grep -qi "server: spiceio"; then
163+
if [[ -n "$ENDPOINT" ]] && curl -fsS -o /dev/null "$ENDPOINT/" 2>/dev/null; then
164164
echo "spiceio ready at $ENDPOINT (PID $PID)"
165165
echo "endpoint=$ENDPOINT" >> "$GITHUB_OUTPUT"
166166
exit 0

Cargo.lock

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "spiceio"
3-
version = "0.4.1"
3+
version = "0.4.2"
44
edition = "2024"
55
description = "S3-compatible API proxy to SMB file shares"
66
license = "Apache-2.0"

scripts/test-sccache.sh

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,17 @@ FAIL=0
2525
# ── Cleanup on exit ─────────────────────────────────────────────────────────
2626

2727
SPICEIO_PID=""
28+
SPICEIO_PID2=""
2829
cleanup() {
2930
echo ""
3031
echo "[test] cleaning up..."
3132
sccache --stop-server 2>/dev/null || true
3233
# Remove test objects
3334
$AWS s3 rm "s3://${BUCKET}/${TEST_PREFIX}/" --recursive 2>/dev/null || true
35+
if [[ -n "$SPICEIO_PID2" ]]; then
36+
kill "$SPICEIO_PID2" 2>/dev/null || true
37+
wait "$SPICEIO_PID2" 2>/dev/null || true
38+
fi
3439
if [[ -n "$SPICEIO_PID" ]]; then
3540
kill "$SPICEIO_PID" 2>/dev/null || true
3641
wait "$SPICEIO_PID" 2>/dev/null || true
@@ -237,6 +242,96 @@ if [[ "$FAIL" -gt 0 ]]; then
237242
exit 1
238243
fi
239244

245+
# ════════════════════════════════════════════════════════════════════════════
246+
# Port auto-increment test
247+
# ════════════════════════════════════════════════════════════════════════════
248+
249+
echo ""
250+
echo "======================================="
251+
echo "[test] port auto-increment test"
252+
echo "======================================="
253+
254+
# Start a second instance requesting the same bind address.
255+
# It should auto-increment to the next port.
256+
SPICEIO_LOG2=$(mktemp /tmp/spiceio-test-log2.XXXXXX)
257+
258+
SPICEIO_BIND="$BIND" \
259+
SPICEIO_SMB_SERVER="$SMB_SERVER" \
260+
SPICEIO_SMB_PORT="$SMB_PORT" \
261+
SPICEIO_SMB_USER="$SPICEIO_SMB_USER" \
262+
SPICEIO_SMB_PASS="$SPICEIO_SMB_PASS" \
263+
SPICEIO_SMB_DOMAIN="$SMB_DOMAIN" \
264+
SPICEIO_SMB_SHARE="$SMB_SHARE" \
265+
SPICEIO_BUCKET="$BUCKET" \
266+
SPICEIO_REGION="$REGION" \
267+
SPICEIO_LOG_FILE="$SPICEIO_LOG2" \
268+
"$SPICEIO_BIN" &
269+
SPICEIO_PID2=$!
270+
271+
echo "[test] waiting for second spiceio instance..."
272+
ENDPOINT2=""
273+
for i in $(seq 1 30); do
274+
ENDPOINT2=$(grep 'listening on' "$SPICEIO_LOG2" 2>/dev/null | grep -o 'http://[^ ]*' | tail -1 || true)
275+
if [[ -n "$ENDPOINT2" ]] && curl -sf -o /dev/null "${ENDPOINT2}/" 2>/dev/null; then
276+
break
277+
fi
278+
if ! kill -0 "$SPICEIO_PID2" 2>/dev/null; then
279+
echo " FAIL: second spiceio exited unexpectedly"
280+
FAIL=$((FAIL + 1))
281+
SPICEIO_PID2=""
282+
break
283+
fi
284+
sleep 0.5
285+
done
286+
287+
if [[ -n "$ENDPOINT2" ]]; then
288+
echo "[test] second instance at $ENDPOINT2"
289+
290+
PORT1="${BIND##*:}"
291+
PORT2="${ENDPOINT2##*:}"
292+
if [[ "$PORT2" =~ ^[0-9]+$ ]] && (( PORT2 > PORT1 && PORT2 <= PORT1 + 100 )); then
293+
echo " PASS: port auto-incremented ($PORT1 -> $PORT2)"
294+
PASS=$((PASS + 1))
295+
else
296+
echo " FAIL: port should differ from $PORT1 and be within auto-increment range (got $PORT2)"
297+
FAIL=$((FAIL + 1))
298+
fi
299+
300+
# Both instances should serve requests
301+
assert_ok "first instance health check" curl -sf -o /dev/null "${ENDPOINT}/"
302+
assert_ok "second instance health check" curl -sf -o /dev/null "${ENDPOINT2}/"
303+
304+
# Both should serve S3 operations (same SMB share)
305+
GOT1=$($AWS s3 cp "s3://${BUCKET}/${TEST_PREFIX}/small.txt" - 2>/dev/null || echo "FAIL")
306+
assert_eq "first instance S3 read" "version2" "$GOT1"
307+
308+
AWS2="aws --endpoint-url $ENDPOINT2 --no-sign-request"
309+
GOT2=$($AWS2 s3 cp "s3://${BUCKET}/${TEST_PREFIX}/small.txt" - 2>/dev/null || echo "FAIL")
310+
assert_eq "second instance S3 read" "version2" "$GOT2"
311+
else
312+
echo " FAIL: second instance did not start"
313+
FAIL=$((FAIL + 1))
314+
fi
315+
316+
# Stop the second instance
317+
if [[ -n "$SPICEIO_PID2" ]]; then
318+
kill "$SPICEIO_PID2" 2>/dev/null || true
319+
wait "$SPICEIO_PID2" 2>/dev/null || true
320+
SPICEIO_PID2=""
321+
fi
322+
rm -f "$SPICEIO_LOG2"
323+
324+
echo ""
325+
echo "======================================="
326+
echo "[test] port auto-increment complete"
327+
echo "[test] cumulative assertions: $PASS passed, $FAIL failed"
328+
echo "======================================="
329+
330+
if [[ "$FAIL" -gt 0 ]]; then
331+
echo "[test] ABORTING — port auto-increment test failed"
332+
exit 1
333+
fi
334+
240335
# ════════════════════════════════════════════════════════════════════════════
241336
# sccache integration test
242337
# ════════════════════════════════════════════════════════════════════════════

src/s3/router.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub async fn handle_request(req: Request<Incoming>, state: &AppState) -> Respons
5555
// Service-level operations (no bucket)
5656
if req_bucket.is_empty() {
5757
match method {
58-
Method::GET => {
58+
Method::GET | Method::HEAD => {
5959
return with_common_headers(
6060
list_buckets_response(&state.bucket),
6161
&request_id,

0 commit comments

Comments
 (0)