This is an automated email from the ASF dual-hosted git repository.

jungm pushed a commit to branch ee11
in repository https://gitbox.apache.org/repos/asf/tomee-tck.git

commit beed181f4892d01d105c39aec3d3968272838787
Author: Markus Jung <[email protected]>
AuthorDate: Sun Jul 19 16:28:54 2026 +0200

    Add a shared free-port selector and harden the TomEE port guard
    
    select-free-port.sh echoes the preferred port when free and otherwise scans
    upward for the first free port not in the avoid list, with the same TCP
    probe as require-tomee-ports-free.sh so selection and the final assertion
    agree on what free means. Both scripts fail closed when neither nc nor bash
    is available, run the /dev/tcp fallback through an explicit bash (an inline
    redirect under dash silently marks every port free), and the guard accepts
    additional positional ports beyond http/https/shutdown.
---
 environment/ports/select-free-port.sh         | 75 +++++++++++++++++++++++++++
 environment/tomee/require-tomee-ports-free.sh | 36 ++++++++++---
 2 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/environment/ports/select-free-port.sh 
b/environment/ports/select-free-port.sh
new file mode 100755
index 0000000..bece560
--- /dev/null
+++ b/environment/ports/select-free-port.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0.
+
+# Selects a free TCP port for a runner to bind. Echoes the preferred port when
+# it is free, otherwise scans upward for the first free port not in the avoid
+# list. The probe is kept identical to
+# environment/tomee/require-tomee-ports-free.sh so that selection and the final
+# refuse-if-busy assertion agree on what "free" means. Only the chosen port
+# reaches stdout; all diagnostics go to stderr so callers can capture it with
+# a simple command substitution.
+#
+#   select-free-port.sh <preferred-port> [port-to-avoid ...]
+
+set -eu
+
+# Resolve a TCP probe once, up front, and fail closed if none is usable. This
+# script runs under dash on the CI agents, where /dev/tcp is not wired, so the
+# /dev/tcp fallback must run through an explicit bash rather than inline -- an
+# inline redirect under dash silently succeeds and makes every port look free.
+# With neither nc nor bash available the script cannot tell a bound port from a
+# free one; picking or approving an unverifiable port would let the Arquillian
+# adapter attach to a foreign server already on it, so refuse instead.
+NC=$(command -v nc 2>/dev/null || true)
+BASH=$(command -v bash 2>/dev/null || true)
+if [ -z "$NC" ] && [ -z "$BASH" ]; then
+  echo "no working TCP probe available (need nc, or bash with /dev/tcp); 
refusing to select an unverifiable port" >&2
+  exit 1
+fi
+
+# A connect that succeeds means something already listens on the port.
+port_in_use() {
+  port=$1
+  if [ -n "$NC" ]; then
+    "$NC" -z localhost "$port" >/dev/null 2>&1
+  else
+    "$BASH" -c 'exec 3<>"/dev/tcp/localhost/$1" && exec 3>&- 3<&-' _ "$port" 
>/dev/null 2>&1
+  fi
+}
+
+preferred=${1:?usage: select-free-port.sh <preferred-port> [port-to-avoid ...]}
+shift
+
+# Ports this selection must not reuse (e.g. this branch's other picks). Ports
+# are space-safe tokens, so a single captured copy iterates cleanly.
+avoid="$*"
+
+attempts=0
+port=$preferred
+while [ "$attempts" -lt 500 ]; do
+  skip=0
+  for a in $avoid; do
+    if [ "$a" = "$port" ]; then
+      skip=1
+      break
+    fi
+  done
+
+  if [ "$skip" -eq 0 ] && ! port_in_use "$port"; then
+    if [ "$port" != "$preferred" ]; then
+      echo "port $preferred is busy or reserved; selected $port instead" >&2
+    fi
+    echo "$port"
+    exit 0
+  fi
+
+  port=$((port + 1))
+  attempts=$((attempts + 1))
+done
+
+echo "no free TCP port found scanning upward from $preferred" >&2
+exit 1
diff --git a/environment/tomee/require-tomee-ports-free.sh 
b/environment/tomee/require-tomee-ports-free.sh
index 929eb9c..792732c 100755
--- a/environment/tomee/require-tomee-ports-free.sh
+++ b/environment/tomee/require-tomee-ports-free.sh
@@ -11,20 +11,35 @@
 # green without ever exercising the TomEE under test. Mirrors
 # environment/database/require-derby-port-free.sh for the container ports.
 #
-#   require-tomee-ports-free.sh <http-port> [https-port] [shutdown-port]
+#   require-tomee-ports-free.sh <http-port> [https-port] [shutdown-port] 
[additional-port ...]
 
 set -eu
 
 busy=0
 
-# A connect that succeeds means something already listens on the port. Prefer
-# nc, fall back to bash's /dev/tcp; both are present on the CI agents.
+# Resolve a TCP probe once, up front, and fail closed if none is usable. This
+# script runs under dash on the CI agents, where /dev/tcp is not wired, so the
+# /dev/tcp fallback must run through an explicit bash rather than inline -- an
+# inline redirect under dash silently succeeds and makes every port look free.
+# With neither nc nor bash available the guard cannot tell a bound port from a
+# free one; approving an unverifiable port would let the Arquillian adapter
+# attach to a foreign server already on it, so refuse instead. Kept identical
+# to environment/ports/select-free-port.sh so selection and this final
+# assertion agree on what "free" means.
+NC=$(command -v nc 2>/dev/null || true)
+BASH=$(command -v bash 2>/dev/null || true)
+if [ -z "$NC" ] && [ -z "$BASH" ]; then
+  echo "Refusing to start: no working TCP probe available (need nc, or bash 
with /dev/tcp)" >&2
+  exit 1
+fi
+
+# A connect that succeeds means something already listens on the port.
 port_in_use() {
   port=$1
-  if command -v nc >/dev/null 2>&1; then
-    nc -z localhost "$port" >/dev/null 2>&1
+  if [ -n "$NC" ]; then
+    "$NC" -z localhost "$port" >/dev/null 2>&1
   else
-    (exec 3<>"/dev/tcp/localhost/$port") 2>/dev/null && exec 3>&- 3<&-
+    "$BASH" -c 'exec 3<>"/dev/tcp/localhost/$1" && exec 3>&- 3<&-' _ "$port" 
>/dev/null 2>&1
   fi
 }
 
@@ -40,10 +55,17 @@ check_port() {
   fi
 }
 
-check_port "HTTP" "${1:?usage: require-tomee-ports-free.sh <http-port> 
[https-port] [shutdown-port]}"
+check_port "HTTP" "${1:?usage: require-tomee-ports-free.sh <http-port> 
[https-port] [shutdown-port] [additional-port ...]}"
 check_port "HTTPS" "${2:-}"
 check_port "shutdown" "${3:-}"
 
+if [ "$#" -ge 4 ]; then
+  shift 3
+  for extra in "$@"; do
+    check_port "additional" "$extra"
+  done
+fi
+
 if [ "$busy" -ne 0 ]; then
   exit 1
 fi

Reply via email to