diff options
Diffstat (limited to 'python/mozperftest/mozperftest/tests/test_android.py')
-rw-r--r-- | python/mozperftest/mozperftest/tests/test_android.py | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/python/mozperftest/mozperftest/tests/test_android.py b/python/mozperftest/mozperftest/tests/test_android.py new file mode 100644 index 0000000000..881fcb1cd8 --- /dev/null +++ b/python/mozperftest/mozperftest/tests/test_android.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python +import pathlib +from unittest import mock + +import mozunit +import pytest + +from mozperftest.environment import SYSTEM +from mozperftest.system.android import DeviceError +from mozperftest.system.android_perf_tuner import PerformanceTuner +from mozperftest.tests.support import get_running_env, requests_content, temp_file +from mozperftest.utils import silence + + +class FakeDevice: + def __init__(self, **args): + self.apps = [] + self._logger = mock.MagicMock() + self._have_su = True + self._have_android_su = True + self._have_root_shell = True + self.is_rooted = True + + def clear_logcat(self, *args, **kwargs): + return True + + def shell_output(self, *args, **kwargs): + return "A Fake Device" + + def shell_bool(self, *args, **kwargs): + return True + + def uninstall_app(self, apk_name): + return True + + def install_app(self, apk, replace=True): + if apk not in self.apps: + self.apps.append(apk) + + def is_app_installed(self, app_name): + return True + + +@mock.patch("mozperftest.system.android.ADBLoggedDevice", new=FakeDevice) +def test_android(): + args = { + "flavor": "mobile-browser", + "android-install-apk": ["this.apk"], + "android": True, + "android-timeout": 30, + "android-capture-adb": "stdout", + "android-app-name": "org.mozilla.fenix", + } + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + with system as android, silence(system): + android(metadata) + + +@mock.patch("mozperftest.system.android.ADBLoggedDevice") +def test_android_perf_tuning_rooted(device): + # Check to make sure that performance tuning runs + # on rooted devices correctly + device._have_su = True + device._have_android_su = True + device._have_root_shell = True + device.is_rooted = True + with mock.patch( + "mozperftest.system.android_perf_tuner.PerformanceTuner.set_kernel_performance_parameters" + ) as mockfunc: + tuner = PerformanceTuner(device) + tuner.tune_performance() + mockfunc.assert_called() + + +@mock.patch("mozperftest.system.android.ADBLoggedDevice") +def test_android_perf_tuning_nonrooted(device): + # Check to make sure that performance tuning runs + # on non-rooted devices correctly + device._have_su = False + device._have_android_su = False + device._have_root_shell = False + device.is_rooted = False + with mock.patch( + "mozperftest.system.android_perf_tuner.PerformanceTuner.set_kernel_performance_parameters" + ) as mockfunc: + tuner = PerformanceTuner(device) + tuner.tune_performance() + mockfunc.assert_not_called() + + +class Device: + def __init__(self, name, rooted=True): + self.device_name = name + self.is_rooted = rooted + self.call_counts = 0 + + @property + def _logger(self): + return self + + def noop(self, *args, **kw): + pass + + debug = error = info = clear_logcat = noop + + def shell_bool(self, *args, **kw): + self.call_counts += 1 + return True + + def shell_output(self, *args, **kw): + self.call_counts += 1 + return self.device_name + + +def test_android_perf_tuning_all_calls(): + # Check without mocking PerformanceTuner functions + for name in ("Moto G (5)", "Pixel 2", "?"): + device = Device(name) + tuner = PerformanceTuner(device) + tuner.tune_performance() + assert device.call_counts > 1 + + +@mock.patch("mozperftest.system.android_perf_tuner.PerformanceTuner") +@mock.patch("mozperftest.system.android.ADBLoggedDevice") +def test_android_with_perftuning(device, tuner): + args = { + "flavor": "mobile-browser", + "android-install-apk": ["this.apk"], + "android": True, + "android-timeout": 30, + "android-capture-adb": "stdout", + "android-app-name": "org.mozilla.fenix", + "android-perf-tuning": True, + } + tuner.return_value = tuner + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + with system as android, silence(system): + android(metadata) + + # Make sure the tuner was actually called + tuner.tune_performance.assert_called() + + +def test_android_failure(): + # no patching so it'll try for real and fail + args = { + "flavor": "mobile-browser", + "android-install-apk": ["this"], + "android": True, + "android-timeout": 120, + "android-app-name": "org.mozilla.fenix", + "android-capture-adb": "stdout", + } + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + with system as android, silence(system), pytest.raises(DeviceError): + android(metadata) + + +@mock.patch( + "mozperftest.system.android.AndroidDevice.custom_apk_exists", new=lambda x: False +) +@mock.patch("mozperftest.utils.requests.get", new=requests_content()) +@mock.patch("mozperftest.system.android.ADBLoggedDevice") +def test_android_apk_alias(device): + args = { + "flavor": "mobile-browser", + "android-install-apk": ["fenix_nightly_armeabi_v7a"], + "android": True, + "android-app-name": "org.mozilla.fenix", + "android-capture-adb": "stdout", + } + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + with system as android, silence(system): + android(metadata) + + assert device.mock_calls[1][1][0] == "org.mozilla.fenix" + assert device.mock_calls[2][1][0].endswith("target.apk") + + +@mock.patch("mozperftest.utils.requests.get", new=requests_content()) +@mock.patch("mozperftest.system.android.ADBLoggedDevice") +def test_android_timeout(device): + args = { + "flavor": "mobile-browser", + "android-install-apk": ["gve_nightly_api16"], + "android": True, + "android-timeout": 60, + "android-app-name": "org.mozilla.geckoview_example", + "android-capture-adb": "stdout", + } + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + with system as android, silence(system): + android(metadata) + options = device.mock_calls[0][-1] + assert options["timeout"] == 60 + + +@mock.patch("mozperftest.utils.requests.get", new=requests_content()) +def test_android_log_adb(): + with temp_file() as log_adb: + args = { + "flavor": "mobile-browser", + "android-install-apk": ["gve_nightly_api16"], + "android": True, + "android-timeout": 60, + "android-app-name": "org.mozilla.geckoview_example", + "android-capture-adb": log_adb, + } + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + with system as android, silence(system), pytest.raises(DeviceError): + android(metadata) + with open(log_adb) as f: + assert "DEBUG ADBLoggedDevice" in f.read() + + +@mock.patch("mozperftest.utils.requests.get", new=requests_content()) +@mock.patch("mozperftest.system.android.ADBLoggedDevice") +def test_android_log_cat(device): + with temp_file() as log_cat: + args = { + "flavor": "mobile-browser", + "android-install-apk": ["gve_nightly_api16"], + "android": True, + "android-timeout": 60, + "android-app-name": "org.mozilla.geckoview_example", + "android-capture-logcat": log_cat, + "android-clear-logcat": True, + "android-capture-adb": "stdout", + } + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + andro = system.layers[1] + + with system as layer, silence(system): + andro.device = device + andro.device.get_logcat = mock.Mock(result_value=[]) + layer(metadata) + + andro.device.get_logcat.assert_called() + andro.device.clear_logcat.assert_called() + + +@mock.patch("mozperftest.system.android.AndroidDevice.setup", new=mock.MagicMock) +@mock.patch("mozperftest.system.android.Path") +@mock.patch("mozperftest.system.android.ADBLoggedDevice", new=FakeDevice) +def test_android_custom_apk(mozperftest_android_path): + args = { + "flavor": "mobile-browser", + "android": True, + } + + with temp_file(name="user_upload.apk", content="") as sample_apk: + sample_apk = pathlib.Path(sample_apk) + mozperftest_android_path.return_value = sample_apk + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + android = system.layers[1] + + with system as _, silence(system): + assert android._custom_apk_path is None + assert android.custom_apk_exists() + assert android.custom_apk_path == sample_apk + + mozperftest_android_path.assert_called_once() + + +@mock.patch("mozperftest.system.android.AndroidDevice.setup", new=mock.MagicMock) +@mock.patch("mozperftest.system.android.Path.exists") +@mock.patch("mozperftest.system.android.ADBLoggedDevice", new=FakeDevice) +def test_android_custom_apk_nonexistent(path_exists): + args = { + "flavor": "mobile-browser", + "android": True, + } + + path_exists.return_value = False + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + android = system.layers[1] + + with system as _, silence(system): + assert android._custom_apk_path is None + assert not android.custom_apk_exists() + assert android.custom_apk_path is None + + path_exists.assert_called() + + +@mock.patch("mozperftest.system.android.Path") +@mock.patch("mozperftest.system.android.ADBLoggedDevice", new=FakeDevice) +def test_android_setup_custom_apk(mozperftest_android_path): + args = { + "flavor": "mobile-browser", + "android": True, + } + + with temp_file(name="user_upload.apk", content="") as sample_apk: + sample_apk = pathlib.Path(sample_apk) + mozperftest_android_path.return_value = sample_apk + + mach_cmd, metadata, env = get_running_env(**args) + system = env.layers[SYSTEM] + android = system.layers[1] + + with system as _, silence(system): + # The custom apk should be found immediately, and it + # should replace any --android-install-apk settings + assert android._custom_apk_path == sample_apk + assert env.get_arg("android-install-apk") == [sample_apk] + + mozperftest_android_path.assert_called_once() + + +if __name__ == "__main__": + mozunit.main() |