Skip to content

If simulator install ios app failed, reset simulator and try again #733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ jobs:
npm install -g firebase-tools
firebase emulators:start --only firestore --project demo-example &
- name: Run Android integration tests on Emulator locally
timeout-minutes: 60
timeout-minutes: 90
if: steps.get-device-type.outputs.device_type == 'virtual'
run: |
python scripts/gha/test_simulator.py --testapp_dir testapps \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ allprojects {

ext {
compileSdk = 28
buildTools = '28.0.3'
buildTools = '29.0.2'
minSdk = 16
targetSdk = 28
}
Expand Down
114 changes: 82 additions & 32 deletions scripts/gha/test_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@
Device Information is stored in TEST_DEVICES in print_matrix_configuration.py
Example:
sdk id "system-images;android-29;google_apis;x86":
--android_sdk "system-images;android-29;google_apis;x86" --build_tools_version "28.0.3"
--android_sdk "system-images;android-29;google_apis;x86" --build_tools_version "29.0.2"

Alternatively, to set an Android device, use the one of the values below:
[emulator_min, emulator_target, emulator_latest]
Example:
--android_device "emulator_target" --build_tools_version "28.0.3"
--android_device "emulator_target" --build_tools_version "29.0.2"

Returns:
1: No iOS/Android integration_test apps found
Expand Down Expand Up @@ -92,6 +92,14 @@
_GAMELOOP_PACKAGE = "com.google.firebase.gameloop"
_RESULT_FILE = "Results1.json"
_TEST_RETRY = 3
_CMD_TIMEOUT = 300

_DEVICE_NONE = "None"
_DEVICE_ANDROID = "Android"
_DEVICE_APPLE = "Apple"

_RESET_TYPE_REBOOT = 1
_RESET_TYPE_WIPE_REBOOT = 2

FLAGS = flags.FLAGS

Expand Down Expand Up @@ -129,7 +137,7 @@
"android_sdk", "system-images;android-29;google_apis;x86",
"See module docstring for details on how to set and get this id.")
flags.DEFINE_string(
"build_tools_version", "28.0.3",
"build_tools_version", "29.0.2",
"android build_tools_version")
flags.DEFINE_string(
"logfile_name", "simulator-test",
Expand Down Expand Up @@ -411,6 +419,20 @@ def _delete_simulator(device_id):
subprocess.run(args=args, check=True)


def _reset_simulator_on_error(device_id, type=_RESET_TYPE_REBOOT):
_shutdown_simulator()

if type == _RESET_TYPE_WIPE_REBOOT:
args = ["xcrun", "simctl", "erase", device_id]
logging.info("Erase my simulator: %s", " ".join(args))
subprocess.run(args=args, check=True)

# reboot simulator: _RESET_TYPE_WIPE_REBOOT, _RESET_TYPE_REBOOT
args = ["xcrun", "simctl", "boot", device_id]
logging.info("Reboot my simulator: %s", " ".join(args))
subprocess.run(args=args, check=True)


def _get_bundle_id(app_path, config):
"""Get app bundle id from build_testapps.json file."""
for api in config["apis"]:
Expand Down Expand Up @@ -438,14 +460,14 @@ def _install_apple_app(app_path, device_id):
"""Install integration_test app into the simulator."""
args = ["xcrun", "simctl", "install", device_id, app_path]
logging.info("Install testapp: %s", " ".join(args))
subprocess.run(args=args, check=True)
_run_with_retry(args, device=device_id, type=_RESET_TYPE_WIPE_REBOOT)


def _uninstall_apple_app(bundle_id, device_id):
"""Uninstall integration_test app from the simulator."""
args = ["xcrun", "simctl", "uninstall", device_id, bundle_id]
logging.info("Uninstall testapp: %s", " ".join(args))
subprocess.run(args=args, check=True)
_run_with_retry(args, device=device_id, type=_RESET_TYPE_REBOOT)


def _get_apple_test_log(bundle_id, app_path, device_id):
Expand Down Expand Up @@ -501,19 +523,19 @@ def _setup_android(platform_version, build_tool_version, sdk_id):
"platforms;%s" % platform_version,
"build-tools;%s" % build_tool_version]
logging.info("Install packages: %s", " ".join(args))
subprocess.run(args=args, check=True)
_run_with_retry(args)

command = "yes | sdkmanager --licenses"
logging.info("Accept all licenses: %s", command)
subprocess.run(command, shell=True, check=False)
_run_with_retry(command, shell=True, check=False)

args = ["sdkmanager", sdk_id]
logging.info("Download an emulator: %s", " ".join(args))
subprocess.run(args=args, check=True)
_run_with_retry(args)

args = ["sdkmanager", "--update"]
logging.info("Update all installed packages: %s", " ".join(args))
subprocess.run(args=args, check=True)
_run_with_retry(args, check=False)


def _shutdown_emulator():
Expand Down Expand Up @@ -549,27 +571,33 @@ def _create_and_boot_emulator(sdk_id):
logging.info("Wait for emulator to boot: %s", " ".join(args))
subprocess.run(args=args, check=True)
if FLAGS.ci:
# wait extra 90 seconds to ensure emulator fully booted.
time.sleep(180)
# wait extra 210 seconds to ensure emulator fully booted.
time.sleep(210)
else:
time.sleep(45)


def _reset_emulator_on_error(instrumented_test_result):
logging.info("game-loop test result: %s", instrumented_test_result)
if "FAILURES!!!" in instrumented_test_result:
logging.info("game-loop test error!!! reboot emualtor...")
args = ["adb", "-e", "reboot"]
logging.info("Reboot android emulator: %s", " ".join(args))
def _reset_emulator_on_error(type=_RESET_TYPE_REBOOT):
if type == _RESET_TYPE_WIPE_REBOOT:
# wipe emulator data
args = ["adb", "shell", "recovery", "--wipe_data"]
logging.info("Erase my Emulator: %s", " ".join(args))
subprocess.run(args=args, check=True)
args = ["adb", "wait-for-device"]
logging.info("Wait for emulator to boot: %s", " ".join(args))
subprocess.run(args=args, check=True)
if FLAGS.ci:
# wait extra 90 seconds to ensure emulator booted.
time.sleep(90)
else:
time.sleep(45)
_reset_emulator_on_error()

# reboot emulator: _RESET_TYPE_WIPE_REBOOT, _RESET_TYPE_REBOOT
logging.info("game-loop test error!!! reboot emualtor...")
args = ["adb", "-e", "reboot"]
logging.info("Reboot android emulator: %s", " ".join(args))
subprocess.run(args=args, check=True)
args = ["adb", "wait-for-device"]
logging.info("Wait for emulator to boot: %s", " ".join(args))
subprocess.run(args=args, check=True)
if FLAGS.ci:
# wait extra 210 seconds to ensure emulator booted.
time.sleep(210)
else:
time.sleep(45)


def _get_package_name(app_path):
Expand Down Expand Up @@ -599,26 +627,29 @@ def _install_android_app(app_path):
"""Install integration_test app into the emulator."""
args = ["adb", "install", app_path]
logging.info("Install testapp: %s", " ".join(args))
subprocess.run(args=args, check=False)
_run_with_retry(args, device=_DEVICE_ANDROID, type=_RESET_TYPE_WIPE_REBOOT)


def _uninstall_android_app(package_name):
"""Uninstall integration_test app from the emulator."""
args = ["adb", "uninstall", package_name]
logging.info("Uninstall testapp: %s", " ".join(args))
subprocess.run(args=args, check=False)
_run_with_retry(args, device=_DEVICE_ANDROID, type=_RESET_TYPE_REBOOT)


def _install_android_gameloop_app(gameloop_project):
os.chdir(gameloop_project)
logging.info("CD to gameloop_project: %s", gameloop_project)
_uninstall_android_app("com.google.firebase.gameloop")
logging.info("cd to gameloop_project: %s", gameloop_project)
args = ["adb", "uninstall", "com.google.firebase.gameloop"]
_run_with_retry(args, check=False, device=_DEVICE_ANDROID, type=_RESET_TYPE_REBOOT)

args = ["./gradlew", "clean"]
logging.info("Clean game-loop cache: %s", " ".join(args))
subprocess.run(args=args, check=False)
_run_with_retry(args, check=False, device=_DEVICE_ANDROID, type=_RESET_TYPE_REBOOT)

args = ["./gradlew", "installDebug", "installDebugAndroidTest"]
logging.info("Installing game-loop app and test: %s", " ".join(args))
subprocess.run(args=args, check=True)
_run_with_retry(args, device=_DEVICE_ANDROID, type=_RESET_TYPE_REBOOT)


def _run_instrumented_test():
Expand All @@ -629,7 +660,8 @@ def _run_instrumented_test():
"-w", "%s.test/androidx.test.runner.AndroidJUnitRunner" % _GAMELOOP_PACKAGE]
logging.info("Running game-loop test: %s", " ".join(args))
result = subprocess.run(args=args, capture_output=True, text=True, check=False)
_reset_emulator_on_error(result.stdout)
if "FAILURES!!!" in result.stdout:
_reset_emulator_on_error(_RESET_TYPE_REBOOT)


def _get_android_test_log(test_package):
Expand All @@ -643,6 +675,24 @@ def _get_android_test_log(test_package):
return result.stdout


def _run_with_retry(args, shell=False, check=True, timeout=_CMD_TIMEOUT, retry_time=_TEST_RETRY, device=_DEVICE_NONE, type=_RESET_TYPE_REBOOT):
if retry_time > 1:
try:
subprocess.run(args, shell=shell, check=check, timeout=timeout)
except:
if device == _DEVICE_NONE:
pass
elif device == _DEVICE_ANDROID:
# Android
_reset_emulator_on_error(type)
else:
# Apple
_reset_simulator_on_error(device, type)
_run_with_retry(args, shell, check, timeout, retry_time-1, device, type)
else:
subprocess.run(args, shell=shell, check=check, timeout=timeout)


if __name__ == '__main__':
flags.mark_flag_as_required("testapp_dir")
app.run(main)