200 lines
6.1 KiB
Python
Executable File
200 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Run automatic Maestro groups and guarded destructive manual targets."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import sys
|
|
from collections.abc import Sequence
|
|
|
|
import run_maestro
|
|
|
|
|
|
ANDROID_15_INSTRUMENTATION_CLASSES = (
|
|
"androidx.media3.decoder.ffmpeg.PlezyFfmpegPlaybackTest,"
|
|
"com.edde746.plezy.exoplayer.PlezyAudioModePlaybackTest"
|
|
)
|
|
ANDROID_15_INSTRUMENTATION_TARGET = "android-15-instrumentation"
|
|
|
|
|
|
GROUPS: dict[str, tuple[tuple[str, ...], ...]] = {
|
|
"android-15": (
|
|
("basic",),
|
|
("catalog",),
|
|
("media",),
|
|
(
|
|
"basic",
|
|
"--flow",
|
|
".maestro/regression_flows/03_tv_library_focus.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-tv/library-focus.log",
|
|
"--diagnostics-dir",
|
|
"build/maestro-tv/library-focus-diagnostics",
|
|
),
|
|
(
|
|
"basic",
|
|
"--flow",
|
|
".maestro/regression_flows/04_tv_player_keys.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-tv/player-keys.log",
|
|
"--diagnostics-dir",
|
|
"build/maestro-tv/player-keys-diagnostics",
|
|
),
|
|
(
|
|
"basic",
|
|
"--flow",
|
|
".maestro/regression_flows/05_tv_next_episode_back.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-tv/next-episode.log",
|
|
"--diagnostics-dir",
|
|
"build/maestro-tv/next-episode-diagnostics",
|
|
),
|
|
(
|
|
"basic",
|
|
"--fault",
|
|
"music-failure",
|
|
"--flow",
|
|
".maestro/real_flows/02_music_browse.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-recovery/music-jellyfin.log",
|
|
"--proxy-journal",
|
|
"build/maestro-recovery/music-proxy-journal.jsonl",
|
|
"--diagnostics-dir",
|
|
"build/maestro-recovery/music-diagnostics",
|
|
),
|
|
(
|
|
"basic",
|
|
"--fault",
|
|
"offline",
|
|
"--flow",
|
|
".maestro/flows/09_download_offline_playback.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-offline/jellyfin.log",
|
|
"--proxy-log",
|
|
"build/maestro-offline/jellyfin-proxy.log",
|
|
"--proxy-journal",
|
|
"build/maestro-offline/proxy-journal.jsonl",
|
|
"--diagnostics-dir",
|
|
"build/maestro-offline/diagnostics",
|
|
),
|
|
(
|
|
"basic",
|
|
"--fault",
|
|
"recovery",
|
|
"--flow",
|
|
".maestro/regression_flows/06_playback_recovery.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-recovery/jellyfin.log",
|
|
"--proxy-journal",
|
|
"build/maestro-recovery/proxy-journal.jsonl",
|
|
"--diagnostics-dir",
|
|
"build/maestro-recovery/diagnostics",
|
|
),
|
|
),
|
|
"android-9": (
|
|
(
|
|
"basic",
|
|
"--flow",
|
|
".maestro/flows/05_playback.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-legacy/jellyfin.log",
|
|
"--diagnostics-dir",
|
|
"build/maestro-legacy/diagnostics",
|
|
),
|
|
),
|
|
}
|
|
|
|
|
|
DESTRUCTIVE_MANUAL_TARGETS: dict[str, tuple[tuple[str, ...], ...]] = {
|
|
"profile-regressions": (
|
|
(
|
|
"basic",
|
|
"--flow",
|
|
".maestro/regression_flows/01_profile_switch_isolation.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-profile-regressions/profile-switch-isolation-jellyfin.log",
|
|
"--diagnostics-dir",
|
|
"build/maestro-profile-regressions/profile-switch-isolation-diagnostics",
|
|
),
|
|
(
|
|
"basic",
|
|
"--flow",
|
|
".maestro/regression_flows/02_profile_teardown.yaml",
|
|
"--jellyfin-log",
|
|
"build/maestro-profile-regressions/profile-teardown-jellyfin.log",
|
|
"--diagnostics-dir",
|
|
"build/maestro-profile-regressions/profile-teardown-diagnostics",
|
|
),
|
|
),
|
|
}
|
|
|
|
|
|
def run_android_15_instrumentation() -> None:
|
|
print("==> Android 15 filtered instrumentation", flush=True)
|
|
run_maestro._run_checked(
|
|
(
|
|
"android/gradlew",
|
|
"-p",
|
|
"android",
|
|
":app:connectedDebugAndroidTest",
|
|
"-x",
|
|
":app:compileFlutterBuildDebug",
|
|
f"-Pandroid.testInstrumentationRunnerArguments.class={ANDROID_15_INSTRUMENTATION_CLASSES}",
|
|
)
|
|
)
|
|
|
|
|
|
def run_recipes(recipes: tuple[tuple[str, ...], ...]) -> int:
|
|
failed = False
|
|
for arguments in recipes:
|
|
print(f"==> Maestro {' '.join(arguments)}", flush=True)
|
|
exit_status = run_maestro.main(arguments)
|
|
if exit_status >= 128:
|
|
return exit_status
|
|
failed = failed or exit_status != 0
|
|
return 1 if failed else 0
|
|
|
|
|
|
def run_group(name: str) -> int:
|
|
return run_recipes(GROUPS[name])
|
|
|
|
|
|
def run_target(name: str, *, disposable_emulator: bool = False) -> int:
|
|
if name in DESTRUCTIVE_MANUAL_TARGETS:
|
|
if not disposable_emulator:
|
|
print(
|
|
f"Refusing destructive manual target {name!r}: "
|
|
"re-run with --disposable-emulator only on a disposable emulator.",
|
|
file=sys.stderr,
|
|
)
|
|
return 2
|
|
print(f"==> DESTRUCTIVE manual Maestro target: {name}", flush=True)
|
|
return run_recipes(DESTRUCTIVE_MANUAL_TARGETS[name])
|
|
if name == ANDROID_15_INSTRUMENTATION_TARGET:
|
|
run_android_15_instrumentation()
|
|
return 0
|
|
return run_group(name)
|
|
|
|
|
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
"target",
|
|
choices=(
|
|
*GROUPS,
|
|
ANDROID_15_INSTRUMENTATION_TARGET,
|
|
*DESTRUCTIVE_MANUAL_TARGETS,
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--disposable-emulator",
|
|
action="store_true",
|
|
help="opt in to a destructive manual target on a disposable emulator",
|
|
)
|
|
args = parser.parse_args(argv)
|
|
return run_target(args.target, disposable_emulator=args.disposable_emulator)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|