Skip to content

Commit 085abe0

Browse files
committed
Enable KVM before running Android emulator
1 parent 6df5ea6 commit 085abe0

File tree

3 files changed

+167
-1
lines changed

3 files changed

+167
-1
lines changed

.github/workflows/scripts-android.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,18 @@ jobs:
2222
- name: Build Android port
2323
run: ./scripts/build-android-port.sh -q -DskipTests
2424
- name: Build Hello Codename One Android app
25+
id: build-android-app
2526
run: ./scripts/build-android-app.sh -q -DskipTests
27+
- name: Enable KVM for Android emulator
28+
run: |
29+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
30+
sudo udevadm control --reload-rules
31+
sudo udevadm trigger --name-match=kvm
32+
- name: Run Android instrumentation tests
33+
uses: reactivecircus/android-emulator-runner@v2
34+
with:
35+
api-level: 31
36+
arch: x86_64
37+
target: google_apis
38+
script: |
39+
./scripts/run-android-instrumentation-tests.sh "${{ steps.build-android-app.outputs.gradle_project_dir }}"

scripts/build-android-app.sh

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,85 @@ if [ -z "$GRADLE_PROJECT_DIR" ]; then
265265
exit 1
266266
fi
267267

268+
ba_log "Configuring instrumentation test sources in $GRADLE_PROJECT_DIR"
269+
APP_BUILD_GRADLE="$GRADLE_PROJECT_DIR/app/build.gradle"
270+
if [ -f "$APP_BUILD_GRADLE" ]; then
271+
python3 - "$APP_BUILD_GRADLE" <<'PYTHON'
272+
import pathlib
273+
import re
274+
import sys
275+
276+
path = pathlib.Path(sys.argv[1])
277+
text = path.read_text()
278+
modified = False
279+
280+
if "androidx.test.runner.AndroidJUnitRunner" not in text:
281+
def add_runner(match):
282+
prefix = match.group(0)
283+
return prefix + "\n testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\""
284+
285+
new_text, count = re.subn(r"(defaultConfig\s*\{)", add_runner, text, count=1, flags=re.MULTILINE)
286+
if count:
287+
text = new_text
288+
modified = True
289+
else:
290+
raise SystemExit("defaultConfig block not found while adding instrumentation runner")
291+
292+
dependencies_to_add = (
293+
' androidTestImplementation "androidx.test.ext:junit:1.1.5"\n'
294+
' androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"'
295+
)
296+
297+
if "androidx.test.ext:junit" not in text and "androidx.test.espresso:espresso-core" not in text:
298+
def add_dependencies(match):
299+
prefix = match.group(0)
300+
return prefix + "\n" + dependencies_to_add
301+
302+
new_text, count = re.subn(r"(dependencies\s*\{)", add_dependencies, text, count=1, flags=re.MULTILINE)
303+
if count:
304+
text = new_text
305+
modified = True
306+
else:
307+
raise SystemExit("dependencies block not found while adding androidTest dependencies")
308+
309+
if modified:
310+
if not text.endswith("\n"):
311+
text += "\n"
312+
path.write_text(text)
313+
PYTHON
314+
ba_log "Ensured instrumentation runner and dependencies are declared"
315+
else
316+
ba_log "Warning: Gradle build file not found at $APP_BUILD_GRADLE; skipping instrumentation dependency configuration" >&2
317+
fi
318+
319+
TEST_SRC_DIR="$GRADLE_PROJECT_DIR/app/src/androidTest/java/${PACKAGE_PATH}"
320+
mkdir -p "$TEST_SRC_DIR"
321+
TEST_CLASS="$TEST_SRC_DIR/HelloCodenameOneInstrumentedTest.java"
322+
cat >"$TEST_CLASS" <<EOF
323+
package $PACKAGE_NAME;
324+
325+
import android.content.Context;
326+
327+
import androidx.test.ext.junit.runners.AndroidJUnit4;
328+
import androidx.test.platform.app.InstrumentationRegistry;
329+
330+
import org.junit.Test;
331+
import org.junit.runner.RunWith;
332+
333+
import static org.junit.Assert.assertEquals;
334+
335+
@RunWith(AndroidJUnit4.class)
336+
public class HelloCodenameOneInstrumentedTest {
337+
338+
@Test
339+
public void useAppContext() {
340+
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
341+
assertEquals("$PACKAGE_NAME", appContext.getPackageName());
342+
}
343+
}
344+
EOF
345+
ba_log "Created instrumentation test at $TEST_CLASS"
346+
268347
ba_log "Invoking Gradle build in $GRADLE_PROJECT_DIR"
269348
chmod +x "$GRADLE_PROJECT_DIR/gradlew"
270349
ORIGINAL_JAVA_HOME="$JAVA_HOME"
@@ -282,4 +361,13 @@ export JAVA_HOME="$ORIGINAL_JAVA_HOME"
282361

283362
APK_PATH=$(find "$GRADLE_PROJECT_DIR" -path "*/outputs/apk/debug/*.apk" | head -n 1 || true)
284363
[ -n "$APK_PATH" ] || { ba_log "Gradle build completed but no APK was found" >&2; exit 1; }
285-
ba_log "Successfully built Android APK at $APK_PATH"
364+
ba_log "Successfully built Android APK at $APK_PATH"
365+
366+
if [ -n "${GITHUB_OUTPUT:-}" ]; then
367+
{
368+
echo "gradle_project_dir=$GRADLE_PROJECT_DIR"
369+
echo "apk_path=$APK_PATH"
370+
echo "instrumentation_test_class=$PACKAGE_NAME.HelloCodenameOneInstrumentedTest"
371+
} >> "$GITHUB_OUTPUT"
372+
ba_log "Published GitHub Actions outputs for downstream steps"
373+
fi
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env bash
2+
# Run instrumentation tests against the generated Codename One Android project
3+
set -euo pipefail
4+
5+
ra_log() { echo "[run-android-instrumentation-tests] $1"; }
6+
7+
if [ $# -lt 1 ]; then
8+
ra_log "Usage: $0 <gradle_project_dir>" >&2
9+
exit 1
10+
fi
11+
12+
GRADLE_PROJECT_DIR="$1"
13+
14+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
16+
cd "$REPO_ROOT"
17+
18+
TMPDIR="${TMPDIR:-/tmp}"; TMPDIR="${TMPDIR%/}"
19+
DOWNLOAD_DIR="${TMPDIR%/}/codenameone-tools"
20+
ENV_DIR="$DOWNLOAD_DIR/tools"
21+
ENV_FILE="$ENV_DIR/env.sh"
22+
23+
ra_log "Loading workspace environment from $ENV_FILE"
24+
if [ -f "$ENV_FILE" ]; then
25+
# shellcheck disable=SC1090
26+
source "$ENV_FILE"
27+
else
28+
ra_log "Workspace environment file not found. Run scripts/setup-workspace.sh before this script." >&2
29+
exit 1
30+
fi
31+
32+
if [ -z "${JAVA17_HOME:-}" ] || [ ! -x "$JAVA17_HOME/bin/java" ]; then
33+
ra_log "JAVA17_HOME validation failed. Current value: ${JAVA17_HOME:-<unset>}" >&2
34+
exit 1
35+
fi
36+
37+
ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}"
38+
if [ -z "$ANDROID_SDK_ROOT" ]; then
39+
if [ -d "/usr/local/lib/android/sdk" ]; then ANDROID_SDK_ROOT="/usr/local/lib/android/sdk"
40+
elif [ -d "$HOME/Android/Sdk" ]; then ANDROID_SDK_ROOT="$HOME/Android/Sdk"; fi
41+
fi
42+
if [ -z "$ANDROID_SDK_ROOT" ] || [ ! -d "$ANDROID_SDK_ROOT" ]; then
43+
ra_log "Android SDK not found. Set ANDROID_SDK_ROOT or ANDROID_HOME to a valid installation." >&2
44+
exit 1
45+
fi
46+
export ANDROID_SDK_ROOT ANDROID_HOME="$ANDROID_SDK_ROOT"
47+
48+
if [ ! -d "$GRADLE_PROJECT_DIR" ]; then
49+
ra_log "Gradle project directory not found: $GRADLE_PROJECT_DIR" >&2
50+
exit 1
51+
fi
52+
53+
if [ ! -x "$GRADLE_PROJECT_DIR/gradlew" ]; then
54+
chmod +x "$GRADLE_PROJECT_DIR/gradlew"
55+
fi
56+
57+
ra_log "Running instrumentation tests from $GRADLE_PROJECT_DIR"
58+
ORIGINAL_JAVA_HOME="${JAVA_HOME:-}"; export JAVA_HOME="$JAVA17_HOME"
59+
(
60+
cd "$GRADLE_PROJECT_DIR"
61+
./gradlew --no-daemon connectedDebugAndroidTest
62+
)
63+
export JAVA_HOME="$ORIGINAL_JAVA_HOME"
64+
ra_log "Instrumentation tests completed successfully"

0 commit comments

Comments
 (0)