diff --git a/openandroidinstaller/tooling.py b/openandroidinstaller/tooling.py index f4105f4f..9ee97f3c 100644 --- a/openandroidinstaller/tooling.py +++ b/openandroidinstaller/tooling.py @@ -17,7 +17,6 @@ from pathlib import Path import subprocess from subprocess import ( - Popen, PIPE, STDOUT, CalledProcessError, @@ -52,7 +51,7 @@ def run_command( if enable_logging: logger.info(f"Run command: {full_command}") # run the command - with Popen( + with subprocess.Popen( full_command, stdout=PIPE, stderr=STDOUT, @@ -82,6 +81,7 @@ def logging(*args, **kwargs): if (type(line) == bool) and not line: logger.error(f"{step_desc} Failed!") if return_if_fail: + yield False return yield line diff --git a/poetry.lock b/poetry.lock index 2bfe37ac..307a3078 100644 --- a/poetry.lock +++ b/poetry.lock @@ -554,6 +554,22 @@ pytest = ">=5.0" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] +[[package]] +name = "pytest-subprocess" +version = "1.5.0" +description = "A plugin to fake subprocess for pytest" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pytest = ">=4.0.0" + +[package.extras] +dev = ["changelogd", "nox"] +docs = ["changelogd", "furo", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-napoleon"] +test = ["Pygments (>=2.0)", "anyio", "coverage", "docutils (>=0.12)", "pytest (>=4.0)", "pytest-asyncio (>=0.15.1)", "pytest-rerunfailures"] + [[package]] name = "pywin32-ctypes" version = "0.2.0" @@ -749,7 +765,7 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "1.1" python-versions = "<3.11,>=3.9" -content-hash = "79178593143974480efa33e2fd27c48a5bb01438a09873a93b389496541b2834" +content-hash = "68d8e8e1fffc47b22e117cba8553b7a9577b91b706f752c43e317a45cc9a46bd" [metadata.files] altgraph = [ @@ -1570,6 +1586,10 @@ pytest-mock = [ {file = "pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"}, {file = "pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"}, ] +pytest-subprocess = [ + {file = "pytest-subprocess-1.5.0.tar.gz", hash = "sha256:d7693b96f588f39b84c7b2b5c04287459246dfae6be1dd4098937a728ad4fbe3"}, + {file = "pytest_subprocess-1.5.0-py3-none-any.whl", hash = "sha256:dfd75b10af6800a89a9b758f2e2eceff9de082a27bd1388521271b6e8bde298b"}, +] pywin32-ctypes = [ {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, diff --git a/pyproject.toml b/pyproject.toml index a698a6bf..5b78472f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ py7zr = "^0.20.0" pytest-cov = "^4.0.0" pytest-mock = "^3.10.0" bandit = "^1.7.4" +pytest-subprocess = "^1.5.0" [tool.poetry.dev-dependencies] diff --git a/tests/conftest.py b/tests/conftest.py index 2bf0c8d9..f7640b61 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,9 @@ # If not, see .""" # Author: Tobias Sterbak +import os import pytest +import subprocess from pathlib import Path diff --git a/tests/test_tooling.py b/tests/test_tooling.py index 0a3225ce..c2195d67 100644 --- a/tests/test_tooling.py +++ b/tests/test_tooling.py @@ -16,7 +16,42 @@ from pathlib import Path from subprocess import CalledProcessError -from openandroidinstaller.tooling import search_device +from openandroidinstaller.tooling import adb_reboot, search_device, check_ab_partition + + +def test_adb_reboot_success(fp): + """Test if rebooting with adb works fine.""" + + with fp.context() as nested_process: + nested_process.register( + ["test/path/to/tools/adb", "reboot"], stdout=bytes.fromhex("00") + ) + for line in adb_reboot(bin_path=Path("test/path/to/tools")): + print(line) + for_later = "error: no devices/emulators found" + assert line + + +def test_adb_reboot_failure(fp): + """Test if a fail in rebooting with adb is handled properly.""" + + def callback_function_with_kwargs(process, return_code): + process.returncode = return_code + + return_code = 1 + + with fp.context() as nested_process: + nested_process.register( + ["test/path/to/tools/adb", "reboot"], + stdout=[ + bytes("error: no devices/emulators found", encoding="utf-8"), + ], + callback=callback_function_with_kwargs, + callback_kwargs={"return_code": return_code}, + ) + for line in adb_reboot(bin_path=Path("test/path/to/tools")): + print(line) + assert not line def test_search_device_success(mocker): @@ -57,3 +92,43 @@ def patched_check_output(*args, **kwargs): ) assert device_code == None + + +def test_check_ab_device_is_ab(mocker): + """Test if checking for ab device works fine.""" + mocker.patch( + "openandroidinstaller.tooling.check_output", + return_value=b"[ro.boot.slot_suffix]: [_b]", + ) + + # test linux + is_ab = check_ab_partition( + platform="linux", bin_path=Path("openandroidinstaller/bin/") + ) + + assert is_ab + + # test windows + is_ab = check_ab_partition( + platform="windows", bin_path=Path("openandroidinstaller/bin/") + ) + + assert is_ab + + +def test_check_ab_device_not_ab(mocker): + """Test if checking for ab device returns False if it fails.""" + + def patched_check_output(*args, **kwargs): + raise CalledProcessError(returncode=1, cmd="output is None") + + mocker.patch( + "openandroidinstaller.tooling.check_output", + patched_check_output, + ) + + is_ab = check_ab_partition( + platform="linux", bin_path=Path("openandroidinstaller/bin/") + ) + + assert not is_ab