diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-05-09 16:34:50 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-05-09 16:34:50 +0000 |
commit | 71d6d9c582e1d2365a72b3a3a56dcce66f1cf468 (patch) | |
tree | 20d06cc9926650c2b659b19870100dacff75e6b1 | |
parent | 5aa6a42b7b18f32c84ab85bb03a9985ec5c7a3be (diff) | |
parent | 7e6447c3d38923189ebc0442bad21e2878555074 (diff) | |
download | adt-infra-emu-35-1-release.tar.gz |
Snap for 11819808 from 7e6447c3d38923189ebc0442bad21e2878555074 to emu-35-1-releaseemu-35-1-release
Change-Id: I48cfca2cab46c2ef9248ec4777763192b86b7ded
29 files changed, 191 insertions, 157 deletions
diff --git a/emu_test/utils/run_sys_img_test.sh b/emu_test/utils/run_sys_img_test.sh index d7eb0181..97905c47 100755 --- a/emu_test/utils/run_sys_img_test.sh +++ b/emu_test/utils/run_sys_img_test.sh @@ -38,6 +38,7 @@ function run_with_timeout () { TARGET="$(echo $DIST_DIR | sed "s/.*git_devtools-test-.*-\(api.*\)\/.*/\1/g")" export ADT_INFRA='/buildbot/src/android/emu-master-dev/external/adt-infra' export ANDROID_SDK_ROOT="$SDK_EMULATOR" +export JAVA_HOME="$PWD/prebuilts/studio/jdk/jdk17/linux/" rm -rf "$ANDROID_SDK_ROOT/system-images" ln -sf "/buildbot/src/android/emu-master-dev/prebuilts/android-emulator-build/system-images/linux/system-images" "$ANDROID_SDK_ROOT" ls $SDK_EMULATOR diff --git a/pytest/test_embedded/cfg/emulator_darwin_tests.json b/pytest/test_embedded/cfg/emulator_darwin_tests.json index 780cf813..6be85eb4 100644 --- a/pytest/test_embedded/cfg/emulator_darwin_tests.json +++ b/pytest/test_embedded/cfg/emulator_darwin_tests.json @@ -323,14 +323,14 @@ }, "status": "enabled" }, - "sanity_test_suite_api_25": { + "sanity_test_suite_api_28": { "description": "Set of tests we want to run as a part of emulator sanity test suite", "launch_flags": [], "pytest_flags": [ "-m oldapiboot" ], "avd_config": { - "api": "25", + "api": "28", "tag.id": "google_apis" }, "status": "enabled" @@ -375,7 +375,7 @@ "description": "Set of tests we want to run as part of presubmit, it merely boots the emulator and does some basic checks.", "launch_flags": [], "pytest_flags": [ - "-m boot and not slow" + "-m boot and not slow and not flaky" ], "avd_config": { "api": "31", @@ -387,7 +387,7 @@ "description": "Set of tests we want to run as part of presubmit, it merely boots the emulator and does some basic checks.", "launch_flags": [], "pytest_flags": [ - "-m boot and not slow" + "-m boot and not slow and not flaky" ], "avd_config": { "api": "34", diff --git a/pytest/test_embedded/cfg/emulator_linux_tests.json b/pytest/test_embedded/cfg/emulator_linux_tests.json index 780cf813..6be85eb4 100644 --- a/pytest/test_embedded/cfg/emulator_linux_tests.json +++ b/pytest/test_embedded/cfg/emulator_linux_tests.json @@ -323,14 +323,14 @@ }, "status": "enabled" }, - "sanity_test_suite_api_25": { + "sanity_test_suite_api_28": { "description": "Set of tests we want to run as a part of emulator sanity test suite", "launch_flags": [], "pytest_flags": [ "-m oldapiboot" ], "avd_config": { - "api": "25", + "api": "28", "tag.id": "google_apis" }, "status": "enabled" @@ -375,7 +375,7 @@ "description": "Set of tests we want to run as part of presubmit, it merely boots the emulator and does some basic checks.", "launch_flags": [], "pytest_flags": [ - "-m boot and not slow" + "-m boot and not slow and not flaky" ], "avd_config": { "api": "31", @@ -387,7 +387,7 @@ "description": "Set of tests we want to run as part of presubmit, it merely boots the emulator and does some basic checks.", "launch_flags": [], "pytest_flags": [ - "-m boot and not slow" + "-m boot and not slow and not flaky" ], "avd_config": { "api": "34", diff --git a/pytest/test_embedded/cfg/emulator_windows_tests.json b/pytest/test_embedded/cfg/emulator_windows_tests.json index 8045cec4..bd396362 100644 --- a/pytest/test_embedded/cfg/emulator_windows_tests.json +++ b/pytest/test_embedded/cfg/emulator_windows_tests.json @@ -323,14 +323,14 @@ }, "status": "enabled" }, - "sanity_test_suite_api_25": { + "sanity_test_suite_api_28": { "description": "Set of tests we want to run as a part of emulator sanity test suite", "launch_flags": [], "pytest_flags": [ "-m oldapiboot" ], "avd_config": { - "api": "25", + "api": "28", "tag.id": "google_apis" }, "status": "enabled" @@ -375,7 +375,7 @@ "description": "Set of tests we want to run as part of presubmit, it merely boots the emulator and does some basic checks.", "launch_flags": [], "pytest_flags": [ - "-m boot and not slow" + "-m boot and not slow and not flaky" ], "avd_config": { "api": "31", @@ -387,7 +387,7 @@ "description": "Set of tests we want to run as part of presubmit, it merely boots the emulator and does some basic checks.", "launch_flags": [], "pytest_flags": [ - "-m boot and not slow" + "-m boot and not slow and not flaky" ], "avd_config": { "api": "34", diff --git a/pytest/test_embedded/src/emu/console/emulator_connection.py b/pytest/test_embedded/src/emu/console/emulator_connection.py index 9c3da43b..036a4eaf 100644 --- a/pytest/test_embedded/src/emu/console/emulator_connection.py +++ b/pytest/test_embedded/src/emu/console/emulator_connection.py @@ -55,6 +55,10 @@ class EmulatorClient: await self.send(msg) async def send(self, command) -> (bool, [str]): + if self._writer.is_closing() or self._reader.at_eof(): + self.logger.info("-- Disconnected.. attempting to reconnect") + await self.login() + self.logger.info("-S-> %s", command) self._writer.write(f"{command}\n".encode(encoding="utf-8")) @@ -79,6 +83,10 @@ class EmulatorClient: f"EOF before receiving complete emulator response: {msg}" ) + async def close(self): + self._writer.close() + await self._writer.wait_closed() + @staticmethod async def connect( port: int, diff --git a/pytest/test_embedded/src/emu/emulator.py b/pytest/test_embedded/src/emu/emulator.py index 62403c5d..33d03ca0 100644 --- a/pytest/test_embedded/src/emu/emulator.py +++ b/pytest/test_embedded/src/emu/emulator.py @@ -254,14 +254,21 @@ class BaseEmulator(object): """ count = 0 try: - while not await self.adb.is_installed(package_name) and count < 10: + while not await self.adb.is_installed(package_name) and count < 3: await self.adb.install(apk.absolute()) - await asyncio.sleep(1) + await asyncio.sleep(2) count += 1 - finally: return await self.adb.is_installed(package_name) + async def pgrep(self, process_name: str) -> bool: + shell = await self.adb.shell(f"ps -A | grep {process_name}") + return process_name in shell + + async def activity_is_running(self, activity: str): + """Returns true if the given activity is running.""" + return await self.pgrep(activity[: activity.find("/")]) + async def start_activity(self, activity: str, params=None) -> bool: """Attempts to start the given activity. @@ -278,28 +285,19 @@ class BaseEmulator(object): True if the activity was started successfully, False otherwise. """ - async def activity_is_running(): - """Returns true if the given activity is running.""" - return await self.pgrep(activity[: activity.find("/")]) - shell = f"am start -n {activity}" if params: shell += f" {params}" - await self.adb.shell(shell, timeout=2) count = 0 - while count < 10: - await self.adb.shell(shell, timeout=2) - await asyncio.sleep(1) - if await activity_is_running(): + while count < 3: + await self.adb.shell(shell) + await asyncio.sleep(2) + if await self.activity_is_running(activity): return True count += 1 - return await activity_is_running() - - async def pgrep(self, process_name: str) -> bool: - shell = await self.adb.shell(f"ps -A | grep {process_name}", timeout=2) - return process_name in shell + return await self.activity_is_running(activity) async def stop_activity(self, activity: str) -> bool: """Attempts to stop the given activity. @@ -316,20 +314,17 @@ class BaseEmulator(object): True if the activity is not running, False otherwise. """ - async def activity_is_running(): - """Returns true if the given activity is running.""" - return await self.pgrep(activity) + shell = f"am force-stop {activity}" - await self.adb.shell(f"am force-stop {activity}", timeout=1) count = 0 - running = await activity_is_running() - while running and count < 10: - await self.adb.shell(f"am force-stop {activity}", timeout=1) - await asyncio.sleep(1) - running = await activity_is_running() + while count < 3: + await self.adb.shell(shell) + await asyncio.sleep(2) + if not await self.activity_is_running(activity): + return True count += 1 - return not running + return not await self.activity_is_running(activity) async def reset_state(self): """Resets this emulator to a well known state. diff --git a/pytest/test_embedded/tests/battery/test_battery.py b/pytest/test_embedded/tests/battery/test_battery.py index 3b360c4f..330566ea 100644 --- a/pytest/test_embedded/tests/battery/test_battery.py +++ b/pytest/test_embedded/tests/battery/test_battery.py @@ -43,8 +43,6 @@ async def set_and_get_battery(emu_controller, battery_state): @pytest.mark.e2e @pytest.mark.hardware -@pytest.mark.timeout_win(timeout=60) -@pytest.mark.async_timeout(30) @pytest.mark.parametrize( "test_name, battery_status, battery_health", [ diff --git a/pytest/test_embedded/tests/clipboard/test_clipboard.py b/pytest/test_embedded/tests/clipboard/test_clipboard.py index 2f38b525..07df7c6e 100644 --- a/pytest/test_embedded/tests/clipboard/test_clipboard.py +++ b/pytest/test_embedded/tests/clipboard/test_clipboard.py @@ -56,7 +56,6 @@ async def set_clip_data(emulator_controller, clipboard_data="Hello there!"): @pytest.mark.e2e @pytest.mark.embedded @pytest.mark.fast -@pytest.mark.async_timeout(10) @pytest.mark.skipos("win", "reason: b/303295516 - error at setup.") @pytest.mark.parametrize( "clipboard_data", @@ -85,7 +84,6 @@ async def test_clipboard_data(emulator_controller, clipboard_data): @pytest.mark.e2e @pytest.mark.embedded -@pytest.mark.async_timeout(10) @pytest.mark.skipos("win", "reason=b/305040235 - error at setup.") async def test_stream_clipboard_immediately_sends_data(emulator_controller): """Validate that the streaming call will immediately send the current clipboard status.""" @@ -104,7 +102,6 @@ async def test_stream_clipboard_immediately_sends_data(emulator_controller): @pytest.mark.e2e @pytest.mark.embedded -@pytest.mark.async_timeout(10) @pytest.mark.skipos("win", "reason=b/305040856 - error at setup.") async def test_stream_clipboard_sends_updated_data(emulator_controller, avd): """Validate that the streaming call will immediately send the current clipboard status and @@ -149,7 +146,6 @@ def get_test_channel(desc, max_length=4096): @pytest.mark.e2e @pytest.mark.embedded -@pytest.mark.async_timeout(60) async def test_stream_clipboard_sends_updated_data_to_other_channel(avd): # We forcefully create 2 different channel configurations to make # sure that python is not going to "cleverly" re-use an existing channel. @@ -181,7 +177,6 @@ async def test_stream_clipboard_sends_updated_data_to_other_channel(avd): @pytest.mark.e2e @pytest.mark.embedded -@pytest.mark.async_timeout(60) async def test_stream_clipboard_sends_updated_data_to_other_channel_only_once(avd): # We forcefully create 2 different channel configurations to make # sure that python is not going to "cleverly" re-use an existing channel. @@ -224,7 +219,6 @@ async def test_stream_clipboard_sends_updated_data_to_other_channel_only_once(av @pytest.mark.e2e @pytest.mark.embedded -@pytest.mark.async_timeout(60) async def test_stream_clipboard_from_android_immediately_sends_data( avd, emulator_controller ): diff --git a/pytest/test_embedded/tests/conftest.py b/pytest/test_embedded/tests/conftest.py index 164d5958..b29aebd5 100644 --- a/pytest/test_embedded/tests/conftest.py +++ b/pytest/test_embedded/tests/conftest.py @@ -180,25 +180,6 @@ def pytest_runtest_setup(item: pytest.Item) -> None: else: pytest.skip() - # Process the 'timeout_win' marker - timeout_win = item.get_closest_marker("timeout_win") - if timeout_win and pytest.os == "win": - timeout_win_sec = ( - timeout_win.args[0] - if timeout_win.args - else timeout_win.kwargs.get("timeout") - ) - # Remove existing timeout marker - timeout = [ - m - for m, marker in enumerate(item.iter_markers()) - if marker.name == "timeout" - ] - if timeout: - item.own_markers.pop(timeout[0]) - - item.add_marker(pytest.mark.async_timeout([timeout_win_sec])) - item.user_properties.append(("flaky", "flaky" in item.keywords)) logging.info("=============== Setup: %s ===============", item.name) @@ -257,11 +238,11 @@ def pytest_configure(config): # Current skipos platform pytest.os = os_map.get(pytest.system, "unknown") - # Register the 'timeout_win' marker + # Register the 'flaky' marker config.addinivalue_line( "markers", - "timeout_win(timeout): " - "Set a timeout for Windows platforms (overrides an existing timeout).", + "flaky: " + "Set a test as flaky, and exclude it from test failures on the dashboard.", ) @@ -284,7 +265,6 @@ def get_crash_reporter(pytestconfig): @pytest.fixture(autouse=True) -@pytest.mark.async_timeout(5) async def crash_reporter(pytestconfig): """A fixture to handle crash reports in the emulator. @@ -490,7 +470,6 @@ async def emulator_log(avd: BaseEmulator): return avd.log -@pytest.mark.async_timeout(20) async def launch_animiation_app(avd: BaseEmulator): """Launches the debug animation app. @@ -502,8 +481,6 @@ async def launch_animiation_app(avd: BaseEmulator): - Force stop any existing running animation app - Start the activity - Wait for the welcome message to appear on logcat. - - It will wait for at most 20 seconds before continuing. """ logging.info("--> launch_animiation_app") assert avd.is_alive() diff --git a/pytest/test_embedded/tests/console/test_console_avd.py b/pytest/test_embedded/tests/console/test_console_avd.py index 52f92262..f7e91381 100644 --- a/pytest/test_embedded/tests/console/test_console_avd.py +++ b/pytest/test_embedded/tests/console/test_console_avd.py @@ -8,7 +8,6 @@ import emu.console.emulator_connection @pytest.mark.console @pytest.mark.fast @pytest.mark.e2e -@pytest.mark.async_timeout(10) async def test_avd_canonical_path(avd, telnet): """Test adb emu avd path returns a canonical path""" expected_path = Path( @@ -22,7 +21,6 @@ async def test_avd_canonical_path(avd, telnet): @pytest.mark.console @pytest.mark.fast @pytest.mark.e2e -@pytest.mark.async_timeout(10) async def test_avd_snapshots_path_has_no_dots(telnet): """Exposes b/299320133, paths should be normalized.""" path = await telnet.send("avd snapshotspath") @@ -32,7 +30,6 @@ async def test_avd_snapshots_path_has_no_dots(telnet): @pytest.mark.boot @pytest.mark.console @pytest.mark.e2e -@pytest.mark.async_timeout(10) async def test_avd_tracing_is_mounted(avd, telnet): """Test adb shell ls /sys/kernel/tracing/trace_marker valid""" no_file = "No such file or directory" @@ -58,7 +55,6 @@ def read_property_file(from_file) -> str: @pytest.mark.boot @pytest.mark.console @pytest.mark.e2e -@pytest.mark.async_timeout(10) async def test_avd_dir_is_canonical_in_pid_xxx_ini(avd, telnet): """Test pid_xxx.ini contains canonical path for avd.dir @@ -121,3 +117,14 @@ async def test_emulator_exit_console_command(telnet): assert False, "Emulator client connection did not close as expected" except emu.console.emulator_connection.EmulatorClientEOF: pass # Connection closed successfully + + +@pytest.mark.e2e +@pytest.mark.sanity +async def test_telnet_will_reconnect_after_exit(telnet): + try: + await telnet.send("exit") + assert False, "Emulator client connection did not close as expected" + except emu.console.emulator_connection.EmulatorClientEOF: + hello = await telnet.send("ping") + assert hello == ["I am alive!", "OK"] diff --git a/pytest/test_embedded/tests/console/test_multidisplay_console.py b/pytest/test_embedded/tests/console/test_multidisplay_console.py index 20f04ae3..2a8f0dc8 100644 --- a/pytest/test_embedded/tests/console/test_multidisplay_console.py +++ b/pytest/test_embedded/tests/console/test_multidisplay_console.py @@ -20,7 +20,6 @@ def ui_controller(service): @pytest.mark.console @pytest.mark.multidisplay @pytest.mark.e2e -@pytest.mark.async_timeout(10) async def test_multidisplay_out_of_order_add_no_crash(avd, telnet, ui_controller): """Test adb emu multidisplay add 3 does not crash emulator""" diff --git a/pytest/test_embedded/tests/console/test_screen_capture.py b/pytest/test_embedded/tests/console/test_screen_capture.py index e22cb4ba..f27a9d32 100644 --- a/pytest/test_embedded/tests/console/test_screen_capture.py +++ b/pytest/test_embedded/tests/console/test_screen_capture.py @@ -27,7 +27,6 @@ def tmp_test_file(tmp_path): @pytest.mark.adb @pytest.mark.sanity @pytest.mark.flaky -@pytest.mark.async_timeout(30) async def test_adb_screencapture_creates_a_file( avd, log_adb_interactions, tmp_test_file ): @@ -39,7 +38,6 @@ async def test_adb_screencapture_creates_a_file( @pytest.mark.adb @pytest.mark.flaky -@pytest.mark.async_timeout(30) async def test_adb_screencapture_is_a_png(avd, log_adb_interactions, tmp_test_file): device_file = f"/sdcard/{tmp_test_file.name}" await avd.adb.shell(f"rm {device_file}") diff --git a/pytest/test_embedded/tests/console/test_sleep_awake.py b/pytest/test_embedded/tests/console/test_sleep_awake.py index 46c9d55e..6782b20d 100644 --- a/pytest/test_embedded/tests/console/test_sleep_awake.py +++ b/pytest/test_embedded/tests/console/test_sleep_awake.py @@ -81,7 +81,6 @@ async def emulator_off(adb_shell): @pytest.mark.adb -@pytest.mark.async_timeout(60) async def test_power_down_sleeps_the_device(adb_shell, emulator_on): """Test case to verify that sending the power-down command to an awake device will put the device to sleep.""" @@ -94,7 +93,6 @@ async def test_power_down_sleeps_the_device(adb_shell, emulator_on): @pytest.mark.adb -@pytest.mark.async_timeout(60) async def test_wake_up_wakes_the_device(adb_shell, emulator_off): """Test case to verify that sending the wake-up command to a sleeping device will wake the device.""" @@ -108,7 +106,6 @@ async def test_wake_up_wakes_the_device(adb_shell, emulator_off): @pytest.mark.e2e @pytest.mark.adb @pytest.mark.flaky # b/322557339 -@pytest.mark.async_timeout(60) async def test_power_down_turns_off_the_screen(emulator_off, get_screenshot): """Test case to verify that a powered-down device has a black screen. diff --git a/pytest/test_embedded/tests/display/test_brightness.py b/pytest/test_embedded/tests/display/test_brightness.py index 411070f7..5823892a 100644 --- a/pytest/test_embedded/tests/display/test_brightness.py +++ b/pytest/test_embedded/tests/display/test_brightness.py @@ -34,7 +34,6 @@ async def set_and_get_brightness(emu_controller, brightness_value): @pytest.mark.e2e @pytest.mark.hardware -@pytest.mark.async_timeout(10) @pytest.mark.parametrize( "test_name, brightness_value", [ diff --git a/pytest/test_embedded/tests/display/test_multi_display.py b/pytest/test_embedded/tests/display/test_multi_display.py index 4b16fc65..a9bf6301 100644 --- a/pytest/test_embedded/tests/display/test_multi_display.py +++ b/pytest/test_embedded/tests/display/test_multi_display.py @@ -15,6 +15,7 @@ import logging import asyncio import pytest import re +import json from aemu.proto.emulator_controller_pb2 import ( DisplayConfiguration, DisplayConfigurations, @@ -88,7 +89,6 @@ async def emu_snapshot_service(avd, service): @pytest.mark.e2e -@pytest.mark.timeout_win(timeout=60) @pytest.mark.graphics @pytest.mark.multidisplay async def test_multidisplay_none(avd, no_displays, emulator_controller, is_landscape): @@ -360,22 +360,23 @@ async def test_multidisplay_error_too_many( @pytest.mark.graphics @pytest.mark.multidisplay @pytest.mark.fast -@pytest.mark.async_timeout(120) -async def test_disable_multidisplay(avd, is_landscape): +@pytest.mark.async_timeout(510) +async def test_disable_multidisplay(avd, no_displays, is_landscape, emulator_controller): """Ensure an app is moved to the primary display when multidisplay is disabled. Args: - emulator (BaseEmulator): Fixture that gives access to the running emulator. + avd (BaseEmulator): Fixture that gives access to the running emulator. + no_displays (callable): Fixture to make sure the emulator has no multi displays configured. is_landscape (bool): Fixture that indicates whether the emulator is in landscape orientation. emulator_controller (EmulatorControllerStub): An instance of the emulator controller fixture. Test UUID: d0114791-2781-45ee-b4fa-b496d767604e Test Steps: - 1. Configure the emulator to support multiple display resolutions. - 2. Launch a dummy app (e.g., calendar) on the current display. + 1. Configure multiple display resolutions. + 2. Launch the animation APK on the current display. 3. Disable multidisplay functionality - 4. confirm the dummy app moved to the primary display (Verify). + 4. Confirm the animation APK moved to the primary display (Verify). 5. Repeat the steps 2-4 for all display resolutions Verify: @@ -385,8 +386,6 @@ async def test_disable_multidisplay(avd, is_landscape): if is_landscape: pytest.skip("Cannot run multi display tests in landscape mode.") - emulator_controller = EmulatorControllerStub(avd.channel) - # Displays configurations to be tested. resolutions = [(720, 1280), (1080, 1920)] displays = [ @@ -404,45 +403,135 @@ async def test_disable_multidisplay(avd, is_landscape): return cfg async def enable_multidisplay(displays): - # Set the display configuration according to `displays` + # Set the display configuration from 'displays'. to_set = DisplayConfigurations(displays=displays) logging.info('Enabling multidisplay mode') cfg = await emulator_controller.setDisplayConfigurations(to_set) return cfg async def get_display_id(package): - # Get the display id where `package` is running - windows_dump = await avd.adb.shell("dumpsys window", timeout=30) + # Get the id of the display where 'package' is running. + # Return 'None' if the package is not present in the window system dump. + windows_dump = await avd.adb.shell("dumpsys window", timeout=60) display_lines = re.search(f"Window.*{package}.*mDisplayId=([0-9]*)", windows_dump) + if display_lines is None: + return None return int(display_lines.groups()[0]) - dummy_pkg = "com.android.contacts" - dummy_activity = f"{dummy_pkg}/.activities.PeopleActivity" - - # Make sure we start with the primary display only. - cfg = await emulator_controller.getDisplayConfigurations(empty_pb2.Empty()) - if len(cfg.displays) > 1: - await disable_multidisplay() - - for idx in range(len(resolutions)): + async def get_displays_ids(): + # Get the displays ID's. + # Return None if there are no displays avaiable or if there is a single display. + windows_dump = await avd.adb.shell("dumpsys window", timeout=60) + display_ids = re.findall('displayId=([0-9]+)', windows_dump) + if display_ids is None: + return None + display_ids_list = sorted(set(display_ids)) + if len(display_ids_list) == 1: + return None + return list(display_ids_list) + + async def start_on_display(activity, id_): + # Start an activity on a given display. + return await avd.start_activity(activity, params=f"--display {id_}") + + async def app_is_on_primary_display(pkg): + # Return True if 'pkg' is detected on the primary display. + display_id = await get_display_id(pkg) + return display_id == 0 + + dummy_pkg = "com.google.AnimateBox" + dummy_activity = f"{dummy_pkg}/com.google.emu.MainActivity" + pkg_name = dummy_pkg.split('.')[-1] + await avd.stop_activity(dummy_pkg) + + for i in range(len(resolutions)): # Enable multidisplay. await enable_multidisplay(displays) - await asyncio.sleep(10) + await asyncio.sleep(20) + + # Get the current displays list. + assert await eventually(get_displays_ids,timeout=60), \ + "Couldn't retrieve the displays Ids" + ids = await get_displays_ids() - # Start app on current display. - await avd.start_activity(dummy_activity, params=f"--display {idx + 1}") - await asyncio.sleep(10) + # Start app on the display 'ids[i + 1]'. + assert await eventually(partial(start_on_display, dummy_activity, ids[i + 1]), timeout=60), \ + f"Couldn't launch package '{pkg_name}' on display {ids[i + 1]}" # Disable multidisplay. - logging.info(f'Disable multidisplay while contacts app is on display {idx + 1}') - cfg = await disable_multidisplay() - await asyncio.sleep(10) + logging.info(f'Disable multidisplay while app {pkg_name} is on display {ids[i + 1]}') + await disable_multidisplay() # Verify if the app is present in the primary display. - display_id = await get_display_id(dummy_pkg) - assert display_id == 0, f"Contacts app was detected in display {display_id}" + assert await eventually(partial(app_is_on_primary_display, dummy_pkg)), \ + f"App {pkg_name} was not found on display 0" # Stop the app. - await avd.stop_activity("com.android.contacts") - await asyncio.sleep(5) + await avd.stop_activity(dummy_pkg) + + +@pytest.mark.graphics +@pytest.mark.multidisplay +@pytest.mark.fast +@pytest.mark.async_timeout(510) +async def test_add_multidisplay_from_config(emulator, tmp_path): + """Adding displays from config file should work + + Args: + emulator (BaseEmulator): Fixture that gives access to the running emulator. + tmp_path (Path): Fixture that provides a temporary working folder. + + Test UUID: ea5ede9a-8cdf-4e56-bae1-1b56c2d7ae71 + + Test Steps: + 1. Create an AVD with two secondary displays. + 2. Launch a new emulator based on the newly created AVD (Verify). + + Verify: + Three logical displays should appear in the emulator display dump. + """ + if emulator.is_alive(): + await emulator.stop() # The test will configure its own emulator. + + # Avd configuration containing two secondary displays. + config = {"abi": "x86", + "api": "29", + "tag.id":"google_apis", + "hw.display1.width": 800, + "hw.display1.height": 1200, + "hw.display1.density": 320, + "hw.display1.xOffset": -1, + "hw.display1.yOffset": -1, + "hw.display1.flag": 0, + "hw.display2.width": 800, + "hw.display2.height": 1200, + "hw.display2.density": 320, + "hw.display2.xOffset": -1, + "hw.display2.yOffset": -1, + "hw.display2.flag": 0} + + n_displays = 3 # primary plus two secondary displays. + + # Launch the emulator with the specificed multidisplay configuration. + logging.info("Launching emulator ...") + myflags = ["-no-snapshot-save"] + emulator = Emulator( + android_home=emulator.android_home, + android_avd_home=tmp_path, + exe=emulator.exe, + avd_config=config, + ) + await emulator.launch(flags=myflags) + await emulator.wait_for_boot(timeout=180) + + async def ensure_logical_displays(n_displays): + # Return True if 'n_displays' logical displays are present. + display_dump = await emulator.adb.shell("dumpsys display", timeout=30) + display_size_pattern = re.search('Logical Displays: size=([0-9]*).*', display_dump) + return display_size_pattern.groups()[0] == str(n_displays) + + assert await eventually(partial(ensure_logical_displays, n_displays), timeout=180), \ + 'Wrong number of displays detected' + + await emulator.stop() diff --git a/pytest/test_embedded/tests/display/test_rotation.py b/pytest/test_embedded/tests/display/test_rotation.py index 7da0bd15..0a063e82 100644 --- a/pytest/test_embedded/tests/display/test_rotation.py +++ b/pytest/test_embedded/tests/display/test_rotation.py @@ -77,8 +77,6 @@ async def for_each_rotation(emulator_controller): @pytest.mark.e2e -@pytest.mark.async_timeout(10) -@pytest.mark.timeout_win(timeout=60) @pytest.mark.graphics @pytest.mark.flaky async def test_rotation_observable_through_screenshot( @@ -125,7 +123,6 @@ async def test_rotation_observable_through_adbstream( @pytest.mark.e2e -@pytest.mark.async_timeout(10) @pytest.mark.graphics @pytest.mark.flaky async def test_rotation_observable_through_stream_screenshot( @@ -255,8 +252,6 @@ async def rotation_through_console_observable_through_stream_screenshot( @pytest.mark.graphics @pytest.mark.sanity @pytest.mark.fast -@pytest.mark.async_timeout(10) -@pytest.mark.timeout_win(timeout=60) @pytest.mark.parametrize( "rotation, quadrant", [(0, 1), (90, 2), (-180, 3), (-90, 4)], @@ -294,7 +289,6 @@ async def test_rotation_pixels_in_the_right_place( @pytest.mark.e2e -@pytest.mark.async_timeout(10) @pytest.mark.graphics @pytest.mark.flaky async def test_rotation_through_console_observable_through_physical_model( @@ -324,7 +318,6 @@ async def test_rotation_through_console_observable_through_physical_model( @pytest.mark.e2e @pytest.mark.graphics -@pytest.mark.async_timeout(10) @pytest.mark.flaky async def test_rotation_through_console_observable_through_screenshot( at_home, emulator_controller, telnet @@ -339,7 +332,6 @@ async def test_rotation_through_console_observable_through_screenshot( @pytest.mark.e2e @pytest.mark.graphics -@pytest.mark.async_timeout(10) @pytest.mark.flaky async def test_rotation_through_console_observable_through_stream_screenshot( at_home, animation_app, emulator_controller, telnet, stream_screenshot @@ -356,7 +348,6 @@ async def test_rotation_through_console_observable_through_stream_screenshot( @pytest.mark.e2e @pytest.mark.embedded @pytest.mark.sanity -@pytest.mark.async_timeout(10) @pytest.mark.flaky async def test_rotation_observable_through_screenshot_embedded_mode( emulator_controller, telnet, avd, at_home @@ -368,7 +359,6 @@ async def test_rotation_observable_through_screenshot_embedded_mode( @pytest.mark.e2e @pytest.mark.embedded -@pytest.mark.async_timeout(10) @pytest.mark.flaky async def test_rotation_observable_through_stream_screenshot_embedded_mode( emulator_controller, telnet, avd, at_home, stream_screenshot diff --git a/pytest/test_embedded/tests/display/test_screenshot.py b/pytest/test_embedded/tests/display/test_screenshot.py index 70203e78..e2f62490 100644 --- a/pytest/test_embedded/tests/display/test_screenshot.py +++ b/pytest/test_embedded/tests/display/test_screenshot.py @@ -169,7 +169,7 @@ async def all_orientations(emulator_controller, request): # bug 299344829 @pytest.mark.graphics @pytest.mark.embedded -@pytest.mark.timeout_win(timeout=120) +@pytest.mark.async_timeout(120) @pytest.mark.flaky async def test_screenshot_valid_width_and_height( avd, get_screenshot, default_display_config diff --git a/pytest/test_embedded/tests/display/test_stream_screenshot.py b/pytest/test_embedded/tests/display/test_stream_screenshot.py index 5767047f..f490f17d 100644 --- a/pytest/test_embedded/tests/display/test_stream_screenshot.py +++ b/pytest/test_embedded/tests/display/test_stream_screenshot.py @@ -35,7 +35,6 @@ def read_pixel(width, height, pack, arr): "win", "reason: b/305252175 - error at setup. Only the parameter [2-1] fails." ) @pytest.mark.flaky -@pytest.mark.timeout_win(timeout=60) @pytest.mark.parametrize( "fmt,channel", [ diff --git a/pytest/test_embedded/tests/events/needs_debug_events/test_keys.py b/pytest/test_embedded/tests/events/needs_debug_events/test_keys.py index 5978f258..816134c1 100644 --- a/pytest/test_embedded/tests/events/needs_debug_events/test_keys.py +++ b/pytest/test_embedded/tests/events/needs_debug_events/test_keys.py @@ -66,7 +66,6 @@ async def keypress_expects(avd, log, jskey, expected_code): @pytest.mark.e2e @pytest.mark.hardware -@pytest.mark.timeout_win(timeout=60) async def test_hardware_keys(avd, at_home, emulator_log): """Checks that the hardware key events that studio sends are working.""" if not emulator_log: diff --git a/pytest/test_embedded/tests/events/test_input_events_in_animation.py b/pytest/test_embedded/tests/events/test_input_events_in_animation.py index cb042143..88c1086e 100644 --- a/pytest/test_embedded/tests/events/test_input_events_in_animation.py +++ b/pytest/test_embedded/tests/events/test_input_events_in_animation.py @@ -114,7 +114,6 @@ async def send_event(avd, emulator_controller): return send_single_event -@pytest.mark.async_timeout(10) async def test_send_a_sequence_of_single_mouse_events( animation_app, send_event, retrieve_events ): @@ -129,7 +128,6 @@ async def test_send_a_sequence_of_single_mouse_events( assert expected == retrieved -@pytest.mark.async_timeout(10) async def test_send_a_sequence_of_single_key_events( animation_app, send_event, retrieve_events ): @@ -146,7 +144,6 @@ async def test_send_a_sequence_of_single_key_events( assert expected == retrieved -@pytest.mark.async_timeout(10) async def test_stream_a_sequence_of_key_events( animation_app, emulator_controller, retrieve_events ): diff --git a/pytest/test_embedded/tests/events/test_touch_event.py b/pytest/test_embedded/tests/events/test_touch_event.py index c4ff5c29..25db9b95 100644 --- a/pytest/test_embedded/tests/events/test_touch_event.py +++ b/pytest/test_embedded/tests/events/test_touch_event.py @@ -41,7 +41,6 @@ async def test_touch_event_identifier_ranges(at_home, emulator_controller): @pytest.mark.e2e @pytest.mark.hardware -@pytest.mark.timeout_win(timeout=60) async def test_touch_event_identifier_to_many(at_home, emulator_controller): """Tests that we properly handle too many registered identifiers.""" x = 1 diff --git a/pytest/test_embedded/tests/foldable/test_foldable.py b/pytest/test_embedded/tests/foldable/test_foldable.py index c766c3a9..73503c50 100644 --- a/pytest/test_embedded/tests/foldable/test_foldable.py +++ b/pytest/test_embedded/tests/foldable/test_foldable.py @@ -53,7 +53,6 @@ async def snapshot_service(avd, service): @pytest.mark.parametrize( "fmt,fold_angle,unfold_angle", [(ImageFormat.RGB888, 15.0, 180.0)] ) -@pytest.mark.async_timeout(30) async def test_foldable(emulator_controller, fmt, fold_angle, unfold_angle): set_device_hinge_angle(emulator_controller, unfold_angle) await asyncio.sleep(5) @@ -186,7 +185,6 @@ async def test_unfolded_snapshot_sanity( @pytest.mark.parametrize( "fmt,fold_angle,unfold_angle", [(ImageFormat.RGB888, 5.0, 180.0)] ) -@pytest.mark.async_timeout(30) async def test_foldable_notifications( emulator_controller, fmt, fold_angle, unfold_angle ): diff --git a/pytest/test_embedded/tests/foldable/test_new_foldable.py b/pytest/test_embedded/tests/foldable/test_new_foldable.py index 40641590..988c7c44 100644 --- a/pytest/test_embedded/tests/foldable/test_new_foldable.py +++ b/pytest/test_embedded/tests/foldable/test_new_foldable.py @@ -67,7 +67,6 @@ async def set_device_hinge_angle(emu, angle): @pytest.mark.parametrize( "fmt,fold_angle,unfold_angle", [(ImageFormat.RGB888, 15.0, 180.0)] ) -@pytest.mark.async_timeout(60) async def test_new_foldable(emulator_controller, fmt, fold_angle, unfold_angle): await set_device_hinge_angle(emulator_controller, unfold_angle) await asyncio.sleep(5) @@ -108,7 +107,6 @@ async def test_new_foldable(emulator_controller, fmt, fold_angle, unfold_angle): @pytest.mark.parametrize( "fmt,fold_angle,unfold_angle", [(ImageFormat.RGB888, 5.0, 180.0)] ) -@pytest.mark.async_timeout(60) async def test_new_foldable_notifications( emulator_controller, fmt, fold_angle, unfold_angle ): diff --git a/pytest/test_embedded/tests/graphics/test_app.py b/pytest/test_embedded/tests/graphics/test_app.py index 5764ddc6..d4bfbd56 100644 --- a/pytest/test_embedded/tests/graphics/test_app.py +++ b/pytest/test_embedded/tests/graphics/test_app.py @@ -22,7 +22,6 @@ from emu.timing import eventually @pytest.mark.e2e @pytest.mark.graphics -@pytest.mark.async_timeout(60) @pytest.mark.flaky async def test_android_app_dialog_has_dimmed_background(avd, get_screenshot, log_adb_interactions): """ diff --git a/pytest/test_embedded/tests/graphics/test_chrome.py b/pytest/test_embedded/tests/graphics/test_chrome.py index cf373de3..3bf09169 100644 --- a/pytest/test_embedded/tests/graphics/test_chrome.py +++ b/pytest/test_embedded/tests/graphics/test_chrome.py @@ -70,23 +70,23 @@ async def request_page_in_chrome(avd): @pytest.mark.e2e @pytest.mark.graphics @pytest.mark.xpass -@pytest.mark.flaky +@pytest.mark.async_timeout(120) async def test_launch_chrome_google(avd, get_screenshot): """ This test launches Chrome on an Android device, opens a html snippet, - captures a screenshot, and verifies that at least 60% of the image pixels are purple. + captures a screenshot, and verifies that at least 40% of the image pixels are purple. """ - async def at_least_60_percent_of_image_is_purple(): + async def at_least_40_percent_of_image_is_purple(): """ - Helper function to check if at least 60% of the image pixels are purple. + Helper function to check if at least 40% of the image pixels are purple. Returns: - bool: True if at least 60% of the image pixels are blue, False otherwise. + bool: True if at least 40% of the image pixels are blue, False otherwise. """ _, rgb_image = await get_screenshot(ImageFormat()) rgb_image = rgb_image.convert("RGB") - percent_purple = 60 + percent_purple = 40 purple_count = 0 # Iterate over each pixel in the image @@ -106,9 +106,9 @@ async def test_launch_chrome_google(avd, get_screenshot): max_retries = 3 for _ in range(0, max_retries): await request_page_in_chrome(avd) - if await wait_until(at_least_60_percent_of_image_is_purple, timeout=5): + if await wait_until(at_least_40_percent_of_image_is_purple, timeout=20): saw_purple = True break - assert (saw_purple), f"Did not see a screenshot with 60%% purple pixels" + assert (saw_purple), f"Did not see a screenshot with 40% purple pixels" await avd.stop_activity(chrome_pkg) diff --git a/pytest/test_embedded/tests/recording/test_recording.py b/pytest/test_embedded/tests/recording/test_recording.py index dee9904c..81284038 100644 --- a/pytest/test_embedded/tests/recording/test_recording.py +++ b/pytest/test_embedded/tests/recording/test_recording.py @@ -24,7 +24,6 @@ from emu.timing import eventually @pytest.fixture -@pytest.mark.async_timeout(15) async def screen_service(service): """A screen service fixture that will stop any active recording on test completion.""" screen_service: ScreenRecordingStub = service(ScreenRecordingStub) diff --git a/pytest/test_embedded/tests/resizable/test_new_resizable.py b/pytest/test_embedded/tests/resizable/test_new_resizable.py index 710fad4e..882679c7 100644 --- a/pytest/test_embedded/tests/resizable/test_new_resizable.py +++ b/pytest/test_embedded/tests/resizable/test_new_resizable.py @@ -93,7 +93,6 @@ async def set_display_mode(emulator_controller, mode, timeout=5): (1920, 1080, DisplayModeValue.DESKTOP), ], ) -@pytest.mark.timeout_win(timeout=60) @pytest.mark.flaky @pytest.mark.sanity # @pytest.mark.skipos("all", "reason: b/309463427") diff --git a/pytest/test_embedded/tests/resizable/test_resizable.py b/pytest/test_embedded/tests/resizable/test_resizable.py index 0dfec498..7f9db787 100644 --- a/pytest/test_embedded/tests/resizable/test_resizable.py +++ b/pytest/test_embedded/tests/resizable/test_resizable.py @@ -58,7 +58,6 @@ async def set_display_mode(emulator_controller, mode, timeout=5): (1920, 1080, DisplayModeValue.DESKTOP), ], ) -@pytest.mark.timeout_win(timeout=60) @pytest.mark.flaky @pytest.mark.sanity @pytest.mark.skipos("all", "reason: b/309463427") diff --git a/pytest/test_embedded/tests/test_boot.py b/pytest/test_embedded/tests/test_boot.py index 7250003e..168d2df5 100644 --- a/pytest/test_embedded/tests/test_boot.py +++ b/pytest/test_embedded/tests/test_boot.py @@ -145,8 +145,7 @@ def check_boot_from_snapshot(avdpath) -> bool: @pytest.mark.boot @pytest.mark.e2e @pytest.mark.sanity -@pytest.mark.timeout_win(timeout=120) -@pytest.mark.skipos("all", "Test fails in presubmit") +@pytest.mark.async_timeout(120) async def test_snapshot_booted(emulator): """Make sure the emulator status is able to boot from snapshot. @@ -222,7 +221,6 @@ async def test_emulator_should_idle(emulator): @pytest.mark.boot @pytest.mark.e2e -@pytest.mark.timeout_win(timeout=60) async def test_a_booted_emulator_immediately_notifies_it_has_booted(avd): assert await avd.has_booted() assert await asyncio.wait_for(get_booted_notification_time(avd), timeout=10) @@ -293,11 +291,9 @@ async def test_first_time_booted_old_api(emulator): assert await emulator.launch(flags=myflags) logging.info("Waiting for it to boot up ...") - logging.info("Booting up emulator ...") - assert await emulator.wait_for_boot(timeout=900) - - # wait till it settle down a bit - await asyncio.sleep(30) + await asyncio.wait_for( + get_booted_notification_time(emulator), timeout=1080 + ) logging.info("Shutting down the emulator ...") if emulator.is_alive(): |