Skip to content

Commit a5e243a

Browse files
authored
Run Java SE device-runner tests in PR CI (#4147)
* Add Java SE device runner tests to PR workflow * Harden Java SE device runner test script * Ensure simulator run is forcibly timed out * Force-timeout Java SE simulator with log tailing * Download JMF media jar for Java SE tests * Improve Java SE device-runner handling
1 parent 47558a4 commit a5e243a

File tree

2 files changed

+256
-0
lines changed

2 files changed

+256
-0
lines changed

.github/workflows/pr.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,20 @@ jobs:
300300
- name: Build Android Port
301301
run: ant -noinput -buildfile Ports/Android/build.xml jar
302302

303+
- name: Run Java SE device-runner tests
304+
env:
305+
ARTIFACTS_DIR: ${{ github.workspace }}/artifacts/desktop-device-runner
306+
run: ./scripts/run-javase-device-tests.sh
307+
308+
- name: Upload Java SE device-runner artifacts
309+
if: ${{ always() }}
310+
uses: actions/upload-artifact@v4
311+
with:
312+
name: javase-device-runner
313+
path: artifacts/desktop-device-runner
314+
if-no-files-found: warn
315+
retention-days: 14
316+
303317
- name: Packaging Everything
304318
run: zip -j result.zip CodenameOne/javadocs.zip CodenameOne/dist/CodenameOne.jar CodenameOne/updatedLibs.zip Ports/JavaSE/dist/JavaSE.jar build/CodenameOneDist/CodenameOne/demos/CodenameOne_SRC.zip
305319

scripts/run-javase-device-tests.sh

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
#!/usr/bin/env bash
2+
# Run Codename One device-runner tests on the Java SE (desktop) target
3+
set -euo pipefail
4+
5+
jd_log() { echo "[run-javase-device-tests] $1"; }
6+
ensure_dir() { mkdir -p "$1" 2>/dev/null || true; }
7+
download_file() {
8+
local url="$1" dest="$2"
9+
curl -fL --retry 3 --retry-delay 2 --connect-timeout 10 -o "$dest" "$url"
10+
}
11+
12+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
14+
cd "$REPO_ROOT"
15+
16+
CN1SS_HELPER_SOURCE_DIR="$SCRIPT_DIR/android/tests"
17+
if [ ! -f "$CN1SS_HELPER_SOURCE_DIR/Cn1ssChunkTools.java" ]; then
18+
jd_log "CN1SS helper sources not found at $CN1SS_HELPER_SOURCE_DIR" >&2
19+
exit 2
20+
fi
21+
22+
source "$SCRIPT_DIR/lib/cn1ss.sh"
23+
cn1ss_log() { jd_log "$1"; }
24+
25+
if [ -z "${JAVA_BIN:-}" ]; then
26+
if [ -n "${JAVA_HOME_17_X64:-}" ] && [ -x "$JAVA_HOME_17_X64/bin/java" ]; then
27+
JAVA_BIN="$JAVA_HOME_17_X64/bin/java"
28+
elif [ -n "${JAVA_HOME_17:-}" ] && [ -x "$JAVA_HOME_17/bin/java" ]; then
29+
JAVA_BIN="$JAVA_HOME_17/bin/java"
30+
else
31+
JAVA_BIN="$(command -v java || true)"
32+
fi
33+
fi
34+
35+
if [ -z "$JAVA_BIN" ]; then
36+
jd_log "java binary not found on PATH" >&2
37+
exit 2
38+
fi
39+
40+
JAVA_VERSION_RAW="$($JAVA_BIN -version 2>&1 | head -n1 | sed -E 's/.*version \"([^\"]+)\".*/\1/' || true)"
41+
JAVA_VERSION_MAJOR="${JAVA_VERSION_RAW%%.*}"
42+
if [ "$JAVA_VERSION_MAJOR" = "1" ]; then
43+
JAVA_VERSION_MAJOR="$(echo "$JAVA_VERSION_RAW" | cut -d. -f2)"
44+
fi
45+
46+
if [ -z "$JAVA_VERSION_MAJOR" ] || [ "$JAVA_VERSION_MAJOR" -lt 17 ]; then
47+
jd_log "Java 17 or newer is required for CN1SS helpers (detected: ${JAVA_VERSION_RAW:-unknown})" >&2
48+
exit 2
49+
fi
50+
51+
JAVAC_BIN="${JAVAC_BIN:-${JAVA_BIN%/*}/javac}"
52+
if [ -z "$JAVAC_BIN" ] || [ ! -x "$JAVAC_BIN" ]; then
53+
JAVAC_BIN="$(command -v javac || true)"
54+
fi
55+
if [ -z "$JAVAC_BIN" ] || [ ! -x "$JAVAC_BIN" ]; then
56+
jd_log "javac binary not found" >&2
57+
exit 2
58+
fi
59+
60+
JAVAC_VERSION_RAW="$($JAVAC_BIN -version 2>&1 | head -n1 | sed -E 's/.* ([0-9]+(\.[0-9]+)*).*/\1/' || true)"
61+
JAVAC_VERSION_MAJOR="${JAVAC_VERSION_RAW%%.*}"
62+
if [ "$JAVAC_VERSION_MAJOR" = "1" ]; then
63+
JAVAC_VERSION_MAJOR="$(echo "$JAVAC_VERSION_RAW" | cut -d. -f2)"
64+
fi
65+
66+
if [ -z "$JAVAC_VERSION_MAJOR" ] || [ "$JAVAC_VERSION_MAJOR" -lt 17 ]; then
67+
jd_log "Java 17 or newer is required for compilation (javac detected: ${JAVAC_VERSION_RAW:-unknown})" >&2
68+
exit 2
69+
fi
70+
71+
CN1SS_JAVAC_BIN="$JAVAC_BIN"
72+
73+
if ! command -v python3 >/dev/null 2>&1; then
74+
jd_log "python3 binary not found" >&2
75+
exit 2
76+
fi
77+
78+
cn1ss_setup "$JAVA_BIN" "$CN1SS_HELPER_SOURCE_DIR"
79+
80+
CN1_HOME_DIR="${HOME}/.codenameone"
81+
CN1_MEDIA_JAR="$CN1_HOME_DIR/jmf-2.1.1e.jar"
82+
CN1_MEDIA_JAR_URL="https://github.com/codenameone/cn1-binaries/raw/refs/heads/master/javase/jmf-2.1.1e.jar"
83+
84+
jd_log "Ensuring Java SE media libraries are available"
85+
ensure_dir "$CN1_HOME_DIR"
86+
if [ ! -f "$CN1_MEDIA_JAR" ]; then
87+
jd_log "Downloading JMF media support to $CN1_MEDIA_JAR"
88+
download_file "$CN1_MEDIA_JAR_URL" "$CN1_MEDIA_JAR"
89+
else
90+
jd_log "Using cached media jar at $CN1_MEDIA_JAR"
91+
fi
92+
93+
ARTIFACTS_DIR_BASE="${ARTIFACTS_DIR:-${GITHUB_WORKSPACE:-$REPO_ROOT}/artifacts}"
94+
ARTIFACTS_DIR="${ARTIFACTS_DIR_BASE%/}/desktop-device-runner"
95+
ensure_dir "$ARTIFACTS_DIR"
96+
LOG_FILE="$ARTIFACTS_DIR/javase-device-runner.log"
97+
SCREENSHOT_DIR="$ARTIFACTS_DIR/screenshots"
98+
PREVIEW_DIR="$ARTIFACTS_DIR/previews"
99+
ensure_dir "$SCREENSHOT_DIR"
100+
ensure_dir "$PREVIEW_DIR"
101+
102+
jd_log "Ensuring Java SE port is built"
103+
ant -noinput -buildfile Ports/JavaSE/build.xml jar
104+
105+
CN1_CLASSPATH="CodenameOne/dist/CodenameOne.jar:Ports/JavaSE/dist/JavaSE.jar:Ports/CLDC11/dist/CLDC11.jar"
106+
if [ -d "Ports/JavaSE/dist/lib" ]; then
107+
CN1_CLASSPATH+="$(printf ':%s' Ports/JavaSE/dist/lib/*)"
108+
fi
109+
110+
BUILD_DIR="$(mktemp -d "${TMPDIR:-/tmp}/cn1-javase-tests-XXXXXX" 2>/dev/null || echo "${TMPDIR:-/tmp}/cn1-javase-tests")"
111+
SRC_ROOT="$SCRIPT_DIR/device-runner-app"
112+
MAIN_SRC="$SRC_ROOT/main"
113+
TEST_SRC="$SRC_ROOT/tests"
114+
115+
if [ ! -d "$MAIN_SRC" ] || [ ! -d "$TEST_SRC" ]; then
116+
jd_log "Device runner sources missing under $SRC_ROOT" >&2
117+
exit 2
118+
fi
119+
120+
mkdir -p "$BUILD_DIR/src"
121+
rsync -a "$MAIN_SRC/" "$BUILD_DIR/src/"
122+
rsync -a "$TEST_SRC/" "$BUILD_DIR/src/"
123+
124+
jd_log "Compiling device-runner application sources"
125+
find "$BUILD_DIR/src" -name '*.java' -print0 | xargs -0 "$JAVAC_BIN" -cp "$CN1_CLASSPATH" -d "$BUILD_DIR/classes"
126+
127+
SIM_TIMEOUT_SECONDS=${SIM_TIMEOUT_SECONDS:-420}
128+
SIM_KILL_GRACE_SECONDS=${SIM_KILL_GRACE_SECONDS:-30}
129+
JAVA_CMD=(xvfb-run -a "$JAVA_BIN" \
130+
-cp "$CN1_CLASSPATH:$BUILD_DIR/classes" \
131+
com.codename1.impl.javase.Simulator com.codenameone.examples.hellocodenameone.HelloCodenameOne)
132+
133+
run_with_timeout() {
134+
python3 - "$@" <<'PY'
135+
import os
136+
import signal
137+
import subprocess
138+
import sys
139+
140+
def kill_process_group(proc, sig):
141+
try:
142+
os.killpg(proc.pid, sig)
143+
except ProcessLookupError:
144+
pass
145+
146+
def main():
147+
if len(sys.argv) < 4:
148+
raise SystemExit(2)
149+
timeout_seconds = int(sys.argv[1])
150+
kill_grace = int(sys.argv[2])
151+
log_path = sys.argv[3]
152+
cmd = sys.argv[4:]
153+
with open(log_path, 'ab', buffering=0) as log_file:
154+
proc = subprocess.Popen(
155+
cmd,
156+
stdout=log_file,
157+
stderr=subprocess.STDOUT,
158+
preexec_fn=os.setsid,
159+
)
160+
try:
161+
proc.wait(timeout=timeout_seconds)
162+
sys.exit(proc.returncode)
163+
except subprocess.TimeoutExpired:
164+
kill_process_group(proc, signal.SIGTERM)
165+
try:
166+
proc.wait(timeout=kill_grace)
167+
except subprocess.TimeoutExpired:
168+
kill_process_group(proc, signal.SIGKILL)
169+
proc.wait()
170+
sys.exit(124)
171+
172+
if __name__ == '__main__':
173+
main()
174+
PY
175+
}
176+
177+
jd_log "Launching Java SE simulator for device-runner app"
178+
: >"$LOG_FILE"
179+
set +e
180+
run_with_timeout "$SIM_TIMEOUT_SECONDS" "$SIM_KILL_GRACE_SECONDS" "$LOG_FILE" "${JAVA_CMD[@]}"
181+
rc=$?
182+
set -e
183+
184+
if [ $rc -ne 0 ]; then
185+
jd_log "Simulator exited with status $rc (see log at $LOG_FILE)"
186+
fi
187+
188+
SIM_EXIT_CODE=$rc
189+
190+
TEST_NAMES_RAW="$(cn1ss_list_tests "$LOG_FILE" 2>/dev/null | awk 'NF' | sort -u || true)"
191+
declare -a TEST_NAMES=()
192+
if [ -n "$TEST_NAMES_RAW" ]; then
193+
while IFS= read -r name; do
194+
[ -n "$name" ] || continue
195+
TEST_NAMES+=("$name")
196+
done <<< "$TEST_NAMES_RAW"
197+
else
198+
TEST_NAMES+=("default")
199+
fi
200+
201+
jd_log "Detected CN1SS test streams: ${TEST_NAMES[*]}"
202+
203+
declare -a SOURCES=("LOG:$LOG_FILE")
204+
205+
for test in "${TEST_NAMES[@]}"; do
206+
png_dest="$SCREENSHOT_DIR/${test}.png"
207+
if cn1ss_decode_test_png "$test" "$png_dest" "${SOURCES[@]}"; then
208+
jd_log "Decoded screenshot for '$test' -> $png_dest"
209+
else
210+
jd_log "No screenshot payload detected for '$test'"
211+
rm -f "$png_dest" 2>/dev/null || true
212+
fi
213+
214+
preview_dest="$PREVIEW_DIR/${test}.jpg"
215+
if cn1ss_decode_test_preview "$test" "$preview_dest" "${SOURCES[@]}"; then
216+
jd_log "Decoded preview for '$test' -> $preview_dest"
217+
else
218+
rm -f "$preview_dest" 2>/dev/null || true
219+
fi
220+
221+
done
222+
223+
if [ "$SIM_EXIT_CODE" -eq 124 ]; then
224+
screenshot_count=$(find "$SCREENSHOT_DIR" -maxdepth 1 -type f -name '*.png' | wc -l | tr -d '[:space:]')
225+
if [ "${screenshot_count:-0}" -gt 0 ]; then
226+
jd_log "Simulator timed out but CN1SS artifacts were captured; marking run as successful"
227+
SIM_EXIT_CODE=0
228+
fi
229+
fi
230+
231+
# Emit a simple summary for debugging
232+
SUMMARY_FILE="$ARTIFACTS_DIR/summary.txt"
233+
{
234+
echo "Simulator exit code: $SIM_EXIT_CODE"
235+
echo "Log file: $LOG_FILE"
236+
echo "Screenshots:"
237+
find "$SCREENSHOT_DIR" -maxdepth 1 -type f -name '*.png' -printf ' - %f\n' 2>/dev/null || true
238+
} > "$SUMMARY_FILE"
239+
240+
jd_log "Desktop device-runner artifacts stored in $ARTIFACTS_DIR"
241+
242+
exit $SIM_EXIT_CODE

0 commit comments

Comments
 (0)