def test_verify_install_on_non_installed_app(self, device: Device,
                                              in_tmp_dir: Path):
     with pytest.raises(expected_exception=Exception) as excinfo:
         device._verify_install("fake/app/path", "com.linkedin.fake.app",
                                "test_screenshots")
     assert "Failed to verify installation of app 'com.linkedin.fake.app'" in str(
         excinfo.value)
     assert (in_tmp_dir / "test_screenshots" /
             "install_failure-com.linkedin.fake.app.png").is_file()
    def test_install_uninstall_app(self, device: Device, support_app: str):
        app = Application.from_apk(support_app, device)
        app.uninstall()
        assert app.package_name not in device.list_installed_packages()

        app = Application.from_apk(support_app, device)
        assert app.package_name in device.list_installed_packages()
        app.uninstall()
        assert app.package_name not in device.list_installed_packages()
 def test_get_invalid_device_setting(self, device: Device):
     try:
         if int(device.get_system_property(
                 "ro.product.first_api_level")) < 26:
             assert device.get_device_setting("invalid", "nosuchkey") is ''
         else:
             assert device.get_device_setting("invalid",
                                              "nosuchkey") is None
     except:
         assert device.get_device_setting("invalid", "nosuchkey") is None
Exemple #4
0
    def test_process_set_property_cmd(self, device: Device, listener: PropertyListener,
                                      test_setup: Tuple[ServiceApplication, Application]):
        butler_service, app = test_setup

        device.set_system_property(key="debug.mock_key", value="mock_value")
        assert device.get_system_property("debug.mock_key") == "mock_value"

        TestButlerCommandParser(butler_service, app_under_test=app, listener=listener).\
            _process_set_property_cmd("debug.mock_key mock_new_value")
        if listener:
            assert listener.property_change_detected is True
        assert device.get_system_property("debug.mock_key") == "mock_new_value"
 def test_get_device_datetime(self, device: Device):
     import time
     import datetime
     host_datetime = datetime.datetime.utcnow()
     dtime = device.get_device_datetime()
     host_delta = (host_datetime - dtime).total_seconds()
     time.sleep(1)
     host_datetime_delta = (datetime.datetime.utcnow() -
                            device.get_device_datetime()).total_seconds()
     timediff = device.get_device_datetime() - dtime
     assert timediff.total_seconds() >= 0.99
     assert host_datetime_delta - host_delta < 0.01
Exemple #6
0
 def test_reverse_port_forward(self, device: Device):
     device_network = DeviceConnectivity(device)
     device_network.reverse_port_forward(32451, 29323)
     completed = device.execute_remote_cmd("reverse",
                                           "--list",
                                           stdout=subprocess.PIPE)
     assert "29323" in completed.stdout
     device_network.remove_reverse_port_forward(32451)
     completed = device.execute_remote_cmd("reverse",
                                           "--list",
                                           stdout=subprocess.PIPE)
     assert "29323" not in completed.stdout
     assert "32451" not in completed.stdout
Exemple #7
0
    def test_process_set_device_setting_cmd(self, device: Device, listener: Optional[SettingListener],
                                            test_setup: Tuple[ServiceApplication, Application]):
        butler_service, app = test_setup
        # start with a known confirmed value
        device.set_device_setting(namespace="system", key="volume_music", value=SettingListener.START_VALUE)
        assert device.get_device_setting(namespace="system", key="volume_music") == SettingListener.START_VALUE

        # now set it through test butler to known different value
        TestButlerCommandParser(butler_service, app_under_test=app, listener=listener).\
            _process_set_device_setting_cmd("system volume_music %s" % SettingListener.NEW_VALUE)
        # Listener will assert on keys and values and will set a flag to test here:
        if listener is not None:
            assert listener.setting_change_detected

        assert device.get_device_setting(namespace="system", key="volume_music") == "6"
 def test_oneshot_cpu_mem(self, device: Device, support_app: str):
     app = Application.from_apk(support_app, device)
     app.monkey()
     time.sleep(1)
     cpu, mem = device.oneshot_cpu_mem(app.package_name)
     app.stop(force=True)
     assert cpu is not None
     assert mem is not None
 def test_foreground_and_activity_detection(self, install_app,
                                            device: Device,
                                            support_app: str):
     app = install_app(Application, support_app)
     device_nav = DeviceInteraction(device)
     # By default, emulators should always start into the home screen
     assert device_nav.home_screen_active()
     # Start up an app and test home screen is no longer active, and foreground app is correct
     app.start(activity=".MainActivity")
     assert not device_nav.home_screen_active()
     assert device.foreground_activity() == app.package_name
Exemple #10
0
def device_queue():
    m = multiprocessing.Manager()
    AVD = "MTO_emulator"
    CONFIG = EmulatorBundleConfiguration(
        sdk=Path(support.find_sdk()),
        boot_timeout=10 * 60  # seconds
    )
    ARGS = [
        "-no-window",
        "-no-audio",
        "-wipe-data",
        "-gpu",
        "off",
        "-no-boot-anim",
        "-skin",
        "320x640",
        "-partition-size",
        "1024",
    ]
    support.ensure_avd(str(CONFIG.sdk), AVD)
    if TAG_MTO_DEVICE_ID in os.environ:
        queue = m.Queue(1)
        queue.put(Device(TAG_MTO_DEVICE_ID, adb_path=find_sdk()))
    else:
        if IS_CIRCLECI:
            Device.TIMEOUT_ADB_CMD *= 10  # slow machine
            ARGS.append("-no-accel")
            # on circleci, do build first to not take up too much
            # memory if emulator were started first
            count = 1
        else:
            max_count = min(multiprocessing.cpu_count(), 6)
            count = int(os.environ.get("MTO_EMULATOR_COUNT", f"{max_count}"))

        queue = m.Queue(count)

        # launch emulators in parallel and wait for all to boot:
        async def launch(index: int):
            if index:
                await asyncio.sleep(
                    index * 2
                )  # stabilizes the launches spacing them out (otherwise, intermittend fail to boot)
            return await Emulator.launch(Emulator.PORTS[index], AVD, CONFIG,
                                         *ARGS)

        ems = asyncio.get_event_loop().run_until_complete(
            asyncio.gather(*[launch(index) for index in range(count)]))
        for em in ems:
            queue.put(em)
    try:
        yield queue
    finally:
        for em in ems:
            em.kill()
Exemple #11
0
    def test_invalid_output_path(self, fake_sdk, tmpdir):
        device = Device("fakeid", os.path.join(fake_sdk, "platform-tools", "adb"))
        tmpfile = os.path.join(str(tmpdir), "somefile")
        with open(tmpfile, 'w')as f:
            pass
        with pytest.raises(Exception) as exc_info:
            DeviceLog.LogCapture(device, tmpfile)
        assert "Path %s already exists; will not overwrite" % tmpfile in str(exc_info)

        with pytest.raises(Exception):
            logcap = DeviceLog.LogCapture(device, os.path.join(tmpdir, "newfile"))
            logcap.mark_end("proc_not_started_so_throw_exception")
 def test_get_set_locale(self, device: Device, local_changer_apk):  # noqa
     app = Application.from_apk(local_changer_apk, device)
     app.grant_permissions([" android.permission.CHANGE_CONFIGURATION"])
     device.set_locale("en_US")
     assert device.get_locale() == "en_US"
     device.set_locale("fr_FR")
     assert device.get_locale() == "fr_FR"
Exemple #13
0
    def test_process_grant_permission_cmd(self, device: Device, test_setup: Tuple[ServiceApplication, Application]):
        butler_service, app = test_setup

        grant_permissions_invoked = False
        output = device.execute_remote_cmd("shell", "dumpsys", "package", app.package_name, capture_stdout=True)
        permission_to_grant = "android.permission.WRITE_EXTERNAL_STORAGE"

        # first make sure permission not already granted:
        for line in output.splitlines():
            assert "%s: granted=true" % permission_to_grant not in line

        # process commdand through parser
        parser = TestButlerCommandParser(butler_service, app_under_test=app, listener=None)
        assert parser._process_grant_permission_cmd(cmd=json.dumps({'type': 'permission',
                                                                    'package': app.package_name,
                                                                    'permissions': [permission_to_grant]
                                                                   })) == (0, "Success")

        # ensure permission was indeed granted
        output = device.execute_remote_cmd("shell", "dumpsys", "package", app.package_name, capture_stdout=True)
        for line in output.splitlines():
            if "%s: granted=true" % permission_to_grant in line:
                grant_permissions_invoked = True
        assert grant_permissions_invoked is True
 def test_set_invalid_system_property(self, device: Device):
     try:
         api_is_old = int(
             device.get_system_property("ro.build.version.sdk")) < 26
     except:
         api_is_old = False
     if api_is_old:
         device.set_system_property("nosuchkey", "value")
         assert device.get_system_property("nosuchkey") is ""
     else:
         with pytest.raises(Exception) as exc_info:
             device.set_system_property("nosuchkey", "value")
         assert f"setprop nosuchkey value' on device {device.device_id}" in str(
             exc_info.value)
    def test_foreign_apk_install(self, device: Device, support_app: str,
                                 support_test_app: str):
        with EspressoTestPreparation(device=device, path_to_test_apk=support_test_app, path_to_apk=support_app) as prep, \
             DevicePreparation(device) as device_prep:
            now = device.get_device_setting("system", "dim_screen")
            new = {"1": "0", "0": "1"}[now]
            prep.test_app.uninstall()
            assert prep.test_app.package_name not in device.list_installed_packages(
            )
            prep.setup_foreign_apps(paths_to_foreign_apks=[support_test_app])
            assert prep.test_app.package_name in device.list_installed_packages(
            )
            device.set_system_property("debug.mock2", "\"\"\"\"")
            device_prep.configure_device(settings={'system:dim_screen': new},
                                         properties={"debug.mock2": "5555"})

            assert device.get_system_property("debug.mock2") == "5555"
            assert device.get_device_setting("system", "dim_screen") == new
Exemple #16
0
    def test_parse_line(self, device: Device, test_butler_service: str, support_test_app: str):
        butler_service = ServiceApplication.from_apk(test_butler_service, device)
        app = Application.from_apk(support_test_app, device)
        # start with a known confirmed value
        device.set_device_setting(namespace="system", key="volume_music", value=SettingAndPropertyListener.START_VALUE)
        assert device.get_device_setting(namespace="system", key="volume_music") == \
            SettingAndPropertyListener.START_VALUE
        device.set_system_property(key="debug.mock", value="mock_value")
        assert device.get_system_property("debug.mock") == "mock_value"

        listener = SettingAndPropertyListener()
        parser = TestButlerCommandParser(butler_service, app_under_test=app, listener=listener)

        for line in [
            "I/TestButler( ): 1 TEST_BUTLER_SETTING: system volume_music %s" % SettingAndPropertyListener.NEW_VALUE,
            "I/TestButler( ): 2 TEST_BUTLER_PROPERTY: debug.mock 42"]:
            parser.parse_line(line)

        assert listener.setting_change_detected
        assert device.get_device_setting("system", "volume_music") == "1"
        assert listener.property_change_detected
        assert device.get_system_property("debug.mock") == "42"
Exemple #17
0
    async def launch(cls, port: int, avd: str,
                     config: EmulatorBundleConfiguration,
                     *args: str) -> "Emulator":
        """
        Launch an emulator on the given port, with named avd and configuration

        :param args:  add'l arguments to pass to emulator command
        """
        if port not in cls.PORTS:
            raise ValueError(f"Port must be one of {cls.PORTS}")
        device_id = f"emulator-{port}"
        device = Device(device_id, str(config.adb_path()))
        with suppress(Exception):
            device.execute_remote_cmd(
                "emu",
                "kill")  # attempt to kill any existing emulator at this port
            await asyncio.sleep(2)
        emulator_cmd = config.sdk.joinpath("emulator").joinpath("emulator")
        if not emulator_cmd.is_file():
            raise Exception(
                f"Could not find emulator cmd to launch emulator @ {emulator_cmd}"
            )
        if not config.adb_path().is_file():
            raise Exception(f"Could not find adb cmd @ {config.adb_path()}")
        cmd = [
            str(emulator_cmd), "-avd", avd, "-port",
            str(port), "-read-only"
        ]
        if sys.platform.lower() == 'win32':
            cmd[0] += ".bat"
        if config.system_img:
            cmd += ["-system", str(config.system_img)]
        if config.kernel:
            cmd += ["-kernel", str(config.kernel)]
        if config.ramdisk:
            cmd += ["-ramdisk", str(config.ramdisk)]
        cmd += args
        environ = dict(os.environ)
        environ["ANDROID_AVD_HOME"] = str(config.avd_dir)
        environ["ANDROID_SDK_HOME"] = str(config.sdk)
        booted = False
        proc = subprocess.Popen(cmd,
                                stderr=subprocess.STDOUT,
                                stdout=subprocess.PIPE,
                                env=environ)
        try:

            async def wait_for_boot() -> None:
                nonlocal booted
                nonlocal proc
                nonlocal device_id

                while device.get_state().strip() != 'device':
                    await asyncio.sleep(1)
                if proc.poll() is not None:
                    stdout, _ = proc.communicate()
                    raise Emulator.FailedBootError(port,
                                                   stdout.decode('utf-8'))
                start = time.time()
                while not booted:
                    booted = device.get_system_property(
                        "sys.boot_completed", ) == "1"
                    await asyncio.sleep(1)
                    duration = time.time() - start
                    print(
                        f">>> {device.device_id} [{duration}] Booted?: {booted}"
                    )

            await asyncio.wait_for(wait_for_boot(), config.boot_timeout)
            return Emulator(device_id,
                            config=config,
                            launch_cmd=cmd,
                            env=environ)
        except Exception as e:
            raise Emulator.FailedBootError(port, str(e)) from e
        finally:
            if not booted:
                with suppress(Exception):
                    proc.kill()
 def test_take_screenshot(self, device: Device, mp_tmp_dir):
     path = os.path.join(str(mp_tmp_dir), "test_screenshot.png")
     device.take_screenshot(os.path.join(str(mp_tmp_dir), path))
     assert os.path.isfile(path)
     assert os.stat(path).st_size != 0
 def test_take_screenshot_file_already_exists(self, device: Device,
                                              mp_tmp_dir):
     path = os.path.join(str(mp_tmp_dir), "created_test_screenshot.png")
     open(path, 'w+b')  # create the file
     with pytest.raises(FileExistsError):
         device.take_screenshot(os.path.join(str(mp_tmp_dir), path))
 def test_list_packages(self, install_app, device: Device,
                        support_app: str):
     app = install_app(Application, support_app)
     pkgs = device.list_installed_packages()
     assert app.package_name in pkgs
 def test_list_packages(self, device: Device, support_app: str):
     app = Application.from_apk(support_app, device)
     pkgs = device.list_installed_packages()
     assert app.package_name in pkgs
def sole_emulator(emulator):  # kicks off emulator launch
    android_sdk = support.find_sdk()
    return Device(adb_path=os.path.join(android_sdk, "platform-tools",
                                        add_ext("adb")),
                  device_id=emulator)
 def test_get_set_system_property(self, device: Device):
     device.set_system_property("debug.mock2", "5555")
     assert device.get_system_property("debug.mock2") == "5555"
     device.set_system_property("debug.mock2", "\"\"\"\"")
 def test_set_invalid_system_property(self, device: Device):
     with pytest.raises(Exception) as exc_info:
         device.set_system_property("nosuchkey", "value")
     assert "setprop: failed to set property 'nosuchkey' to 'value'" in str(
         exc_info.value)
 def test_get_invalid_decvice_setting(self, device: Device):
     assert device.get_device_setting("invalid", "nosuchkey") is None
 def test_get_set_device_setting(self, device: Device):
     now = device.get_device_setting("system", "dim_screen")
     new = {"1": "0", "0": "1"}[now]
     device.set_device_setting("system", "dim_screen", new)
     assert device.get_device_setting("system", "dim_screen") == new
 def test_take_screenshot(self, device: Device, tmpdir):
     path = os.path.join(str(tmpdir), "test_screenshot.png")
     device.take_screenshot(os.path.join(str(tmpdir), path))
     assert os.path.isfile(path)
 def test_check_network_connect(self, device: Device):
     assert device.check_network_connection("localhost", count=3) == 0
 def test_get_locale(self, device: Device):
     locale = device.get_locale()
     assert locale == "en_US"
    def test_add_background_task(self, device: Device, support_app: str,
                                 support_test_app: str, tmpdir: str):
        # ensure applications are not already installed as precursor to running tests
        with suppress(Exception):
            Application(device, {'package_name': support_app}).uninstall()
        with suppress(Exception):
            Application(device, {'package_name': support_test_app}).uninstall()

        def test_generator():
            yield (TestSuite(
                name='test_suite1',
                arguments=[
                    "-e", "class",
                    "com.linkedin.mtotestapp.InstrumentedTestAllSuccess#useAppContext"
                ]))

        # noinspection PyMissingOrEmptyDocstring
        class EmptyListener(TestRunListener):
            _call_count = {}

            def test_run_started(self, test_run_name: str, count: int = 0):
                EmptyListener._call_count.setdefault(test_run_name, 0)
                EmptyListener._call_count[test_run_name] += 1

            def test_run_ended(self, duration: float, **kwargs):
                pass

            def test_run_failed(self, error_message: str):
                pass

            def test_failed(self, class_name: str, test_name: str,
                            stack_trace: str):
                pass

            def test_ignored(self, class_name: str, test_name: str):
                pass

            def test_assumption_failure(self, class_name: str, test_name: str,
                                        stack_trace: str):
                pass

            def test_started(self, class_name: str, test_name: str):
                pass

            def test_ended(self, class_name: str, test_name: str, **kwargs):
                pass

        was_called = False

        async def some_task(orchestrator: AndroidTestOrchestrator):
            """
            For testing that user-defined background task was indeed executed
            """
            nonlocal was_called
            was_called = True

            with pytest.raises(Exception):
                orchestrator.add_logcat_monitor("BogusTag", None)

        test_vectors = os.path.join(str(tmpdir), "test_vectors")
        os.makedirs(test_vectors)
        with open(os.path.join(test_vectors, "file"), 'w') as f:
            f.write("TEST VECTOR DATA")

        with AndroidTestOrchestrator(artifact_dir=str(tmpdir)) as orchestrator, \
                EspressoTestPreparation(device=device,
                                        path_to_apk=support_app,
                                        path_to_test_apk=support_test_app,
                                        grant_all_user_permissions=True) as test_prep, \
                DevicePreparation(device) as device_prep:
            device_prep.verify_network_connection("localhost", 4)
            device_prep.port_forward(5748, 5749)
            completed = device.execute_remote_cmd("forward",
                                                  "--list",
                                                  stdout=subprocess.PIPE)
            forwarded_ports = completed.stdout
            assert "5748" in forwarded_ports and "5749" in forwarded_ports
            device_prep.reverse_port_forward(5432, 5431)
            completed = device.execute_remote_cmd("reverse",
                                                  "--list",
                                                  stdout=subprocess.PIPE)
            reverse_forwarded_ports = completed.stdout
            assert "5432" in reverse_forwarded_ports and "5431" in reverse_forwarded_ports
            test_prep.upload_test_vectors(test_vectors)
            orchestrator.add_test_suite_listeners(
                [EmptyListener(), EmptyListener()])
            orchestrator.add_background_task(some_task(orchestrator))
            orchestrator.execute_test_plan(test_plan=test_generator(),
                                           test_application=test_prep.test_app)
        assert was_called, "Failed to call user-define background task"
        # listener was added a second time, so expect call counts of 2
        assert all([v == 2 for v in EmptyListener._call_count.values()])
        completed = device.execute_remote_cmd("forward",
                                              "--list",
                                              stdout=subprocess.PIPE)
        forwarded_ports = completed.stdout
        assert forwarded_ports.strip() == ""
        completed = device.execute_remote_cmd("reverse",
                                              "--list",
                                              stdout=subprocess.PIPE)
        reverse_forwarded_ports = completed.stdout
        assert reverse_forwarded_ports.strip() == ""