mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 14:28:07 +00:00
feat(tests): support UI testing for persistence tests
Added new global `emulator_core` fixture that supports UI recording. [no changelog]
This commit is contained in:
parent
923b1c42b0
commit
b6ce90dc73
@ -18,7 +18,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Generator
|
||||
from typing import TYPE_CHECKING, Generator, Iterator
|
||||
|
||||
import pytest
|
||||
import xdist
|
||||
@ -46,6 +46,28 @@ HERE = Path(__file__).resolve().parent
|
||||
pytest.register_assert_rewrite("tests.common")
|
||||
|
||||
|
||||
def _emulator_wrapper_main_args() -> list[str]:
|
||||
"""Look at TREZOR_PROFILING env variable, so that we can generate coverage reports."""
|
||||
do_profiling = os.environ.get("TREZOR_PROFILING") == "1"
|
||||
if do_profiling:
|
||||
core_dir = HERE.parent / "core"
|
||||
profiling_wrapper = core_dir / "prof" / "prof.py"
|
||||
# So that the coverage reports have the correct paths
|
||||
os.environ["TREZOR_SRC"] = str(core_dir / "src")
|
||||
return [str(profiling_wrapper)]
|
||||
else:
|
||||
return ["-m", "main"]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def core_emulator(request: pytest.FixtureRequest) -> Iterator[Emulator]:
|
||||
"""Fixture returning default core emulator with possibility of screen recording."""
|
||||
with EmulatorWrapper("core", main_args=_emulator_wrapper_main_args()) as emu:
|
||||
# Modifying emu.client to add screen recording (when --ui=test is used)
|
||||
with ui_tests.screen_recording(emu.client, request) as _:
|
||||
yield emu
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def emulator(request: pytest.FixtureRequest) -> Generator["Emulator", None, None]:
|
||||
"""Fixture for getting emulator connection in case tests should operate it on their own.
|
||||
@ -88,23 +110,12 @@ def emulator(request: pytest.FixtureRequest) -> Generator["Emulator", None, None
|
||||
# 1. normal link, 2. debug link and 3. webauthn fake interface
|
||||
return 20000 + int(worker_id[2:]) * 3
|
||||
|
||||
# So that we can generate coverage reports
|
||||
profiling = os.environ.get("TREZOR_PROFILING") == "1"
|
||||
if profiling:
|
||||
core_dir = HERE.parent / "core"
|
||||
profiling_wrapper = core_dir / "prof" / "prof.py"
|
||||
main_args = [str(profiling_wrapper)]
|
||||
# So that the coverage reports have the correct paths
|
||||
os.environ["TREZOR_SRC"] = str(core_dir / "src")
|
||||
else:
|
||||
main_args = ["-m", "main"]
|
||||
|
||||
with EmulatorWrapper(
|
||||
model,
|
||||
port=_get_port(),
|
||||
headless=True,
|
||||
auto_interact=not interact,
|
||||
main_args=main_args,
|
||||
main_args=_emulator_wrapper_main_args(),
|
||||
) as emu:
|
||||
yield emu
|
||||
|
||||
|
@ -1,21 +1,13 @@
|
||||
from typing import Iterator
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import debuglink, device
|
||||
from trezorlib.messages import SafetyCheckLevel
|
||||
|
||||
from ..common import MNEMONIC12
|
||||
from ..emulators import Emulator, EmulatorWrapper
|
||||
from ..emulators import Emulator
|
||||
from ..upgrade_tests import core_only
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def emulator() -> Iterator[Emulator]:
|
||||
with EmulatorWrapper("core") as emu:
|
||||
yield emu
|
||||
|
||||
|
||||
@core_only
|
||||
@pytest.mark.parametrize(
|
||||
"set_level,after_level",
|
||||
@ -26,20 +18,20 @@ def emulator() -> Iterator[Emulator]:
|
||||
],
|
||||
)
|
||||
def test_safety_checks_level_after_reboot(
|
||||
emulator: Emulator, set_level: SafetyCheckLevel, after_level: SafetyCheckLevel
|
||||
core_emulator: Emulator, set_level: SafetyCheckLevel, after_level: SafetyCheckLevel
|
||||
):
|
||||
device.wipe(emulator.client)
|
||||
device.wipe(core_emulator.client)
|
||||
debuglink.load_device(
|
||||
emulator.client,
|
||||
core_emulator.client,
|
||||
mnemonic=MNEMONIC12,
|
||||
pin="",
|
||||
passphrase_protection=False,
|
||||
label="SAFETYLEVEL",
|
||||
)
|
||||
|
||||
device.apply_settings(emulator.client, safety_checks=set_level)
|
||||
assert emulator.client.features.safety_checks == set_level
|
||||
device.apply_settings(core_emulator.client, safety_checks=set_level)
|
||||
assert core_emulator.client.features.safety_checks == set_level
|
||||
|
||||
emulator.restart()
|
||||
core_emulator.restart()
|
||||
|
||||
assert emulator.client.features.safety_checks == after_level
|
||||
assert core_emulator.client.features.safety_checks == after_level
|
||||
|
@ -14,10 +14,6 @@
|
||||
# You should have received a copy of the License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
from typing import Iterator
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import device
|
||||
from trezorlib.debuglink import DebugLink
|
||||
|
||||
@ -25,24 +21,20 @@ from .. import buttons
|
||||
from ..click_tests import recovery
|
||||
from ..common import MNEMONIC_SLIP39_ADVANCED_20, MNEMONIC_SLIP39_BASIC_20_3of6
|
||||
from ..device_handler import BackgroundDeviceHandler
|
||||
from ..emulators import Emulator, EmulatorWrapper
|
||||
from ..emulators import Emulator
|
||||
from ..upgrade_tests import core_only
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def emulator() -> Iterator[Emulator]:
|
||||
with EmulatorWrapper("core") as emu:
|
||||
yield emu
|
||||
|
||||
|
||||
def _restart(device_handler: BackgroundDeviceHandler, emulator: Emulator):
|
||||
device_handler.restart(emulator)
|
||||
def _restart(
|
||||
device_handler: BackgroundDeviceHandler, core_emulator: Emulator
|
||||
) -> DebugLink:
|
||||
device_handler.restart(core_emulator)
|
||||
return device_handler.debuglink()
|
||||
|
||||
|
||||
@core_only
|
||||
def test_abort(emulator: Emulator):
|
||||
device_handler = BackgroundDeviceHandler(emulator.client)
|
||||
def test_abort(core_emulator: Emulator):
|
||||
device_handler = BackgroundDeviceHandler(core_emulator.client)
|
||||
debug = device_handler.debuglink()
|
||||
features = device_handler.features()
|
||||
|
||||
@ -55,8 +47,7 @@ def test_abort(emulator: Emulator):
|
||||
layout = debug.click(buttons.OK, wait=True)
|
||||
assert "Select number of words" in layout.get_content()
|
||||
|
||||
device_handler.restart(emulator)
|
||||
debug = device_handler.debuglink()
|
||||
debug = _restart(device_handler, core_emulator)
|
||||
features = device_handler.features()
|
||||
|
||||
assert features.recovery_mode is True
|
||||
@ -75,8 +66,8 @@ def test_abort(emulator: Emulator):
|
||||
|
||||
|
||||
@core_only
|
||||
def test_recovery_single_reset(emulator: Emulator):
|
||||
device_handler = BackgroundDeviceHandler(emulator.client)
|
||||
def test_recovery_single_reset(core_emulator: Emulator):
|
||||
device_handler = BackgroundDeviceHandler(core_emulator.client)
|
||||
debug = device_handler.debuglink()
|
||||
features = device_handler.features()
|
||||
|
||||
@ -88,7 +79,7 @@ def test_recovery_single_reset(emulator: Emulator):
|
||||
|
||||
recovery.select_number_of_words(debug)
|
||||
|
||||
debug = _restart(device_handler, emulator)
|
||||
debug = _restart(device_handler, core_emulator)
|
||||
features = device_handler.features()
|
||||
assert features.recovery_mode is True
|
||||
|
||||
@ -103,7 +94,7 @@ def test_recovery_single_reset(emulator: Emulator):
|
||||
|
||||
|
||||
@core_only
|
||||
def test_recovery_on_old_wallet(emulator: Emulator):
|
||||
def test_recovery_on_old_wallet(core_emulator: Emulator):
|
||||
"""Check that the recovery workflow started on a disconnected device can survive
|
||||
handling by the old Wallet.
|
||||
|
||||
@ -112,7 +103,7 @@ def test_recovery_on_old_wallet(emulator: Emulator):
|
||||
Initialize+GetFeatures). At minimum, these two messages must not interrupt the
|
||||
running recovery.
|
||||
"""
|
||||
device_handler = BackgroundDeviceHandler(emulator.client)
|
||||
device_handler = BackgroundDeviceHandler(core_emulator.client)
|
||||
debug = device_handler.debuglink()
|
||||
features = device_handler.features()
|
||||
|
||||
@ -124,7 +115,7 @@ def test_recovery_on_old_wallet(emulator: Emulator):
|
||||
recovery.confirm_recovery(debug)
|
||||
|
||||
# restart to get into stand-alone recovery
|
||||
debug = _restart(device_handler, emulator)
|
||||
debug = _restart(device_handler, core_emulator)
|
||||
features = device_handler.features()
|
||||
assert features.recovery_mode is True
|
||||
|
||||
@ -171,7 +162,7 @@ def test_recovery_on_old_wallet(emulator: Emulator):
|
||||
|
||||
|
||||
@core_only
|
||||
def test_recovery_multiple_resets(emulator: Emulator):
|
||||
def test_recovery_multiple_resets(core_emulator: Emulator):
|
||||
def enter_shares_with_restarts(debug: DebugLink) -> None:
|
||||
shares = MNEMONIC_SLIP39_ADVANCED_20
|
||||
layout = debug.read_layout()
|
||||
@ -182,11 +173,11 @@ def test_recovery_multiple_resets(emulator: Emulator):
|
||||
layout = recovery.enter_share(debug, share)
|
||||
remaining -= 1
|
||||
expected_text = "You have entered"
|
||||
debug = _restart(device_handler, emulator)
|
||||
debug = _restart(device_handler, core_emulator)
|
||||
|
||||
assert "You have successfully recovered your wallet" in layout.get_content()
|
||||
|
||||
device_handler = BackgroundDeviceHandler(emulator.client)
|
||||
device_handler = BackgroundDeviceHandler(core_emulator.client)
|
||||
debug = device_handler.debuglink()
|
||||
features = device_handler.features()
|
||||
|
||||
@ -201,7 +192,7 @@ def test_recovery_multiple_resets(emulator: Emulator):
|
||||
recovery.select_number_of_words(debug)
|
||||
|
||||
# restart
|
||||
debug = _restart(device_handler, emulator)
|
||||
debug = _restart(device_handler, core_emulator)
|
||||
features = device_handler.features()
|
||||
assert features.recovery_mode is True
|
||||
|
||||
|
@ -2,7 +2,7 @@ from trezorlib import debuglink, device, messages
|
||||
from trezorlib.debuglink import TrezorClientDebugLink as Client
|
||||
|
||||
from ..common import MNEMONIC12
|
||||
from ..emulators import EmulatorWrapper
|
||||
from ..emulators import Emulator, EmulatorWrapper
|
||||
from ..upgrade_tests import core_only, legacy_only
|
||||
|
||||
PIN = "1234"
|
||||
@ -48,34 +48,38 @@ def setup_device_core(client: Client, pin: str, wipe_code: str) -> None:
|
||||
|
||||
|
||||
@core_only
|
||||
def test_wipe_code_activate_core():
|
||||
with EmulatorWrapper("core") as emu:
|
||||
# set up device
|
||||
setup_device_core(emu.client, PIN, WIPE_CODE)
|
||||
def test_wipe_code_activate_core(core_emulator: Emulator):
|
||||
# set up device
|
||||
setup_device_core(core_emulator.client, PIN, WIPE_CODE)
|
||||
|
||||
emu.client.init_device()
|
||||
device_id = emu.client.features.device_id
|
||||
core_emulator.client.init_device()
|
||||
device_id = core_emulator.client.features.device_id
|
||||
|
||||
# Initiate Change pin process
|
||||
ret = emu.client.call_raw(messages.ChangePin(remove=False))
|
||||
assert isinstance(ret, messages.ButtonRequest)
|
||||
emu.client.debug.press_yes()
|
||||
ret = emu.client.call_raw(messages.ButtonAck())
|
||||
# Initiate Change pin process
|
||||
ret = core_emulator.client.call_raw(messages.ChangePin(remove=False))
|
||||
assert isinstance(ret, messages.ButtonRequest)
|
||||
core_emulator.client.debug.press_yes()
|
||||
ret = core_emulator.client.call_raw(messages.ButtonAck())
|
||||
|
||||
# Enter the wipe code instead of the current PIN
|
||||
assert ret == messages.ButtonRequest(code=messages.ButtonRequestType.PinEntry)
|
||||
emu.client._raw_write(messages.ButtonAck())
|
||||
emu.client.debug.input(WIPE_CODE)
|
||||
# Enter the wipe code instead of the current PIN
|
||||
assert ret == messages.ButtonRequest(code=messages.ButtonRequestType.PinEntry)
|
||||
core_emulator.client._raw_write(messages.ButtonAck())
|
||||
core_emulator.client.debug.input(WIPE_CODE)
|
||||
|
||||
# wait 30 seconds for emulator to shut down
|
||||
# this will raise a TimeoutError if the emulator doesn't die.
|
||||
emu.wait(30)
|
||||
# preserving screenshots even after it dies and starts again
|
||||
prev_screenshot_dir = core_emulator.client.debug.screenshot_recording_dir
|
||||
|
||||
emu.start()
|
||||
assert emu.client.features.initialized is False
|
||||
assert emu.client.features.pin_protection is False
|
||||
assert emu.client.features.wipe_code_protection is False
|
||||
assert emu.client.features.device_id != device_id
|
||||
# wait 30 seconds for emulator to shut down
|
||||
# this will raise a TimeoutError if the emulator doesn't die.
|
||||
core_emulator.wait(30)
|
||||
|
||||
core_emulator.start()
|
||||
if prev_screenshot_dir:
|
||||
core_emulator.client.debug.start_recording(prev_screenshot_dir, refresh_index=1)
|
||||
assert core_emulator.client.features.initialized is False
|
||||
assert core_emulator.client.features.pin_protection is False
|
||||
assert core_emulator.client.features.wipe_code_protection is False
|
||||
assert core_emulator.client.features.device_id != device_id
|
||||
|
||||
|
||||
@legacy_only
|
||||
|
Loading…
Reference in New Issue
Block a user