Files
callstack__agent-device/test/scripts/android-snapshot-helper-release-smoke.sh
Michał Pierzchała 35f54a863c fix: resolve Maestro taps from regular snapshots (#709)
* fix: resolve Maestro taps from regular snapshots

* fix: tighten Maestro snapshot compatibility

* test: align Maestro snapshot freshness fixtures
2026-06-08 18:12:09 +02:00

166 lines
5.6 KiB
Bash
Executable File

#!/bin/sh
set -eu
PROJECT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)"
PACKAGE_NAME="com.callstack.agentdevice.snapshotsmoke"
APP_LABEL="Agent Device Snapshot Smoke"
# Keep these in sync with the Android workflow SDK packages and emulator API level.
MIN_SDK=23
TARGET_SDK=36
SDK_ROOT="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
if [ -z "$SDK_ROOT" ] || [ ! -d "$SDK_ROOT" ]; then
echo "ANDROID_HOME or ANDROID_SDK_ROOT must point to an Android SDK" >&2
exit 1
fi
ANDROID_JAR="$SDK_ROOT/platforms/android-$TARGET_SDK/android.jar"
if [ ! -f "$ANDROID_JAR" ]; then
echo "Missing Android platform jar: $ANDROID_JAR" >&2
exit 1
fi
BUILD_TOOLS_DIR="$(
find "$SDK_ROOT/build-tools" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sort -V | tail -n 1
)"
if [ -z "$BUILD_TOOLS_DIR" ] || [ ! -x "$BUILD_TOOLS_DIR/aapt2" ]; then
echo "Missing Android build tools under $SDK_ROOT/build-tools" >&2
exit 1
fi
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/agent-device-android-helper-smoke.XXXXXX")"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
SRC_DIR="$WORK_DIR/src/com/callstack/agentdevice/snapshotsmoke"
CLASSES_DIR="$WORK_DIR/classes"
DEX_DIR="$WORK_DIR/dex"
UNSIGNED_APK="$WORK_DIR/app-unsigned.apk"
ALIGNED_APK="$WORK_DIR/app-aligned.apk"
APK_PATH="$WORK_DIR/app-release.apk"
KEYSTORE="$PROJECT_DIR/android-snapshot-helper/debug.keystore"
# This APK is throwaway test code signed with the helper debug keystore only for CI smoke coverage.
mkdir -p "$SRC_DIR" "$CLASSES_DIR" "$DEX_DIR"
cat > "$WORK_DIR/AndroidManifest.xml" <<EOF_MANIFEST
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="$PACKAGE_NAME">
<application android:theme="@style/AppTheme" android:label="$APP_LABEL" android:allowBackup="false" android:supportsRtl="true">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
EOF_MANIFEST
mkdir -p "$WORK_DIR/res/values"
cat > "$WORK_DIR/res/values/styles.xml" <<EOF_STYLES
<resources>
<style name="AppTheme" parent="@android:style/Theme.Material.Light.NoActionBar" />
</resources>
EOF_STYLES
cat > "$SRC_DIR/MainActivity.java" <<'EOF_JAVA'
package com.callstack.agentdevice.snapshotsmoke;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
public final class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setGravity(Gravity.CENTER);
layout.setPadding(32, 32, 32, 32);
TextView title = new TextView(this);
title.setText("Snapshot helper release smoke");
title.setTextSize(22);
title.setGravity(Gravity.CENTER);
layout.addView(
title,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Button button = new Button(this);
button.setText("Release smoke ready");
layout.addView(
button,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
setContentView(layout);
}
}
EOF_JAVA
javac \
--release 11 \
-classpath "$ANDROID_JAR" \
-d "$CLASSES_DIR" \
"$SRC_DIR/MainActivity.java"
"$BUILD_TOOLS_DIR/d8" \
--min-api "$MIN_SDK" \
--classpath "$ANDROID_JAR" \
--output "$DEX_DIR" \
$(find "$CLASSES_DIR" -name '*.class' | sort)
"$BUILD_TOOLS_DIR/aapt2" compile \
--dir "$WORK_DIR/res" \
-o "$WORK_DIR/compiled.zip"
"$BUILD_TOOLS_DIR/aapt2" link \
--manifest "$WORK_DIR/AndroidManifest.xml" \
-I "$ANDROID_JAR" \
--min-sdk-version "$MIN_SDK" \
--target-sdk-version "$TARGET_SDK" \
--version-code 1 \
--version-name 1.0 \
-o "$UNSIGNED_APK" \
"$WORK_DIR/compiled.zip"
zip -q -j "$UNSIGNED_APK" "$DEX_DIR/classes.dex"
"$BUILD_TOOLS_DIR/zipalign" -f 4 "$UNSIGNED_APK" "$ALIGNED_APK"
"$BUILD_TOOLS_DIR/apksigner" sign \
--ks "$KEYSTORE" \
--ks-pass pass:android \
--key-pass pass:android \
--out "$APK_PATH" \
"$ALIGNED_APK"
"$BUILD_TOOLS_DIR/apksigner" verify --min-sdk-version "$MIN_SDK" "$APK_PATH"
node --experimental-strip-types "$PROJECT_DIR/src/bin.ts" install "$PACKAGE_NAME" "$APK_PATH" --platform android
node --experimental-strip-types "$PROJECT_DIR/src/bin.ts" open "$PACKAGE_NAME" --platform android --relaunch
node --experimental-strip-types "$PROJECT_DIR/src/bin.ts" wait 'label="Release smoke ready" || text="Release smoke ready"' 10000 --platform android
node --experimental-strip-types "$PROJECT_DIR/src/bin.ts" snapshot -i --platform android --json > "$WORK_DIR/snapshot.json"
node - "$WORK_DIR/snapshot.json" <<'EOF_NODE'
const fs = require('node:fs');
const snapshot = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
const nodes = snapshot?.data?.nodes ?? snapshot?.nodes ?? [];
const androidSnapshot = snapshot?.data?.androidSnapshot ?? snapshot?.androidSnapshot;
const labels = nodes.map((node) => String(node.label ?? node.text ?? ''));
if (androidSnapshot?.backend !== 'android-helper') {
throw new Error(`Expected android-helper backend, received ${androidSnapshot?.backend}`);
}
if (!labels.some((label) => label.toLowerCase().includes('release smoke ready'))) {
throw new Error(`Expected release smoke label in snapshot labels: ${labels.join(', ')}`);
}
EOF_NODE