Skip to content

Commit

Permalink
Update for latest ragger
Browse files Browse the repository at this point in the history
  • Loading branch information
fbeutin-ledger committed Mar 23, 2023
1 parent e891ce5 commit 9fa8573
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 217 deletions.
81 changes: 13 additions & 68 deletions .github/workflows/ci-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,75 +10,20 @@ on:

jobs:
build_application:
strategy:
matrix:
sdk:
- path: $NANOS_SDK
name: nanos
- path: $NANOX_SDK
name: nanox
- path: $NANOSP_SDK
name: nanosp

runs-on: ubuntu-latest

container:
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest

steps:
- name: Clone
uses: actions/checkout@v3

- name: Build application
run: |
make BOLOS_SDK=${{ matrix.sdk.path }} DEBUG=1
cp bin/app.elf bin/solana_${{ matrix.sdk.name }}.elf
- name: Upload application binaries
uses: actions/upload-artifact@v3
with:
name: solana_binaries
path: ./bin/solana_${{ matrix.sdk.name }}.elf
if-no-files-found: error

job_scan_build:
name: Clang Static Analyzer
needs: build_application
runs-on: ubuntu-latest
container:
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
steps:
- uses: actions/checkout@v3
- name: Build with Clang Static Analyzer
run: |
make clean
scan-build --use-cc=clang -analyze-headers -enable-checker security -enable-checker unix -enable-checker valist -o scan-build --status-bugs make default
- uses: actions/upload-artifact@v3
if: failure()
with:
name: scan-build
path: scan-build

python_tests_nano:
name: Ragger tests
name: Build application using the reusable workflow
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1
with:
upload_app_binaries_artifact: compiled_app_binaries
run_for_devices: '["nanos", "nanox", "nanosp"]'

ragger_tests:
name: Run ragger tests using the reusable workflow
needs: build_application
runs-on: ubuntu-latest
steps:
- name: Clone
uses: actions/checkout@v3
- name: Download all binaries
uses: actions/download-artifact@v3
- name: Gather artifacts
run: |
mkdir tests/elfs
mv *_binaries/*.elf tests/elfs
- name: Install APT dependencies
run: sudo apt-get update && sudo apt-get install -y qemu-user-static
- name: Install Ragger
run: |
pip install --extra-index-url https://test.pypi.org/simple/ -r tests/python/requirements.txt
- name: Run tests
run: pytest tests/python/ -v --tb=short --device all
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1
with:
download_app_binaries_artifact: compiled_app_binaries
test_dir: tests/python
run_for_devices: '["nanos", "nanox", "nanosp"]'

job_C_test:
name: C tests
Expand Down
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
build
bin
debug
dep
obj
dev-env
src/glyphs.c
src/glyphs.h
.idea
.vscode
gitignore
Expand All @@ -17,5 +16,4 @@ __pycache__
.pyc
*~

tests/elfs/
tests/python/snapshots-tmp/
158 changes: 12 additions & 146 deletions tests/python/conftest.py
Original file line number Diff line number Diff line change
@@ -1,151 +1,17 @@
import pytest
from typing import Optional
from pathlib import Path
from ragger.firmware import Firmware
from ragger.backend import SpeculosBackend, LedgerCommBackend, LedgerWalletBackend
from ragger.navigator import NanoNavigator
from ragger.utils import app_path_from_app_name
from ragger.conftest import configuration

###########################
### CONFIGURATION START ###
###########################

# This variable is needed for Speculos only (physical tests need the application to be already installed)
# Adapt this path to your 'tests/elfs' directory
APPS_DIRECTORY = (Path(__file__).parent.parent / "elfs").resolve()
# You can configure optional parameters by overriding the value of ragger.configuration.OPTIONAL_CONFIGURATION
# Please refer to ragger/conftest/configuration.py for their descriptions and accepted values

# Adapt this name part of the compiled app <name>_<device>.elf in the APPS_DIRECTORY
APP_NAME = "solana"
configuration.OPTIONAL.BACKEND_SCOPE = "function"

BACKENDS = ["speculos", "ledgercomm", "ledgerwallet"]
#########################
### CONFIGURATION END ###
#########################

DEVICES = ["nanos", "nanox", "nanosp", "all"]

FIRMWARES = [Firmware('nanos', '2.1'),
Firmware('nanox', '2.0.2'),
Firmware('nanosp', '1.0.3')]


def pytest_addoption(parser):
parser.addoption("--device", choices=DEVICES, required=True)
parser.addoption("--backend", choices=BACKENDS, default="speculos")
parser.addoption("--display", action="store_true", default=False)
parser.addoption("--golden_run", action="store_true", default=False)
parser.addoption("--log_apdu_file", action="store", default=None)


@pytest.fixture(scope="session")
def backend_name(pytestconfig):
return pytestconfig.getoption("backend")


@pytest.fixture(scope="session")
def display(pytestconfig):
return pytestconfig.getoption("display")


@pytest.fixture(scope="session")
def golden_run(pytestconfig):
return pytestconfig.getoption("golden_run")


@pytest.fixture(scope="session")
def log_apdu_file(pytestconfig):
filename = pytestconfig.getoption("log_apdu_file")
return Path(filename).resolve() if filename is not None else None


@pytest.fixture
def test_name(request):
# Get the name of current pytest test
test_name = request.node.name

# Remove firmware suffix:
# - test_xxx_transaction_ok[nanox 2.0.2]
# => test_xxx_transaction_ok
return test_name.split("[")[0]


# Glue to call every test that depends on the firmware once for each required firmware
def pytest_generate_tests(metafunc):
if "firmware" in metafunc.fixturenames:
fw_list = []
ids = []

device = metafunc.config.getoption("device")
backend_name = metafunc.config.getoption("backend")

if device == "all":
if backend_name != "speculos":
raise ValueError("Invalid device parameter on this backend")

# Add all supported firmwares
for fw in FIRMWARES:
fw_list.append(fw)
ids.append(fw.device + " " + fw.version)

else:
# Enable firmware for demanded device
for fw in FIRMWARES:
if device == fw.device:
fw_list.append(fw)
ids.append(fw.device + " " + fw.version)

metafunc.parametrize("firmware", fw_list, ids=ids, scope="session")


def prepare_speculos_args(firmware: Firmware, display: bool):
speculos_args = []

if display:
speculos_args += ["--display", "qt"]

app_path = app_path_from_app_name(APPS_DIRECTORY, APP_NAME, firmware.device)

return ([app_path], {"args": speculos_args})


# Depending on the "--backend" option value, a different backend is
# instantiated, and the tests will either run on Speculos or on a physical
# device depending on the backend
def create_backend(backend_name: str, firmware: Firmware, display: bool, log_apdu_file: Optional[Path]):
if backend_name.lower() == "ledgercomm":
return LedgerCommBackend(firmware=firmware, interface="hid", log_apdu_file=log_apdu_file)
elif backend_name.lower() == "ledgerwallet":
return LedgerWalletBackend(firmware=firmware, log_apdu_file=log_apdu_file)
elif backend_name.lower() == "speculos":
args, kwargs = prepare_speculos_args(firmware, display)
return SpeculosBackend(*args, firmware=firmware, log_apdu_file=log_apdu_file, **kwargs)
else:
raise ValueError(f"Backend '{backend_name}' is unknown. Valid backends are: {BACKENDS}")


# This fixture will return the properly configured backend, to be used in tests.
# As Speculos instantiation takes some time, this fixture scope is by default "session".
# If your tests needs to be run on independent Speculos instances (in case they affect
# settings for example), then you should change this fixture scope and choose between
# function, class, module or session.
# @pytest.fixture(scope="session")
@pytest.fixture(scope="function")
def backend(backend_name, firmware, display, log_apdu_file):
with create_backend(backend_name, firmware, display, log_apdu_file) as b:
yield b


@pytest.fixture
def navigator(backend, firmware, golden_run):
if firmware.device.startswith("nano"):
return NanoNavigator(backend, firmware, golden_run)
else:
raise ValueError(f"Device '{firmware.device}' is unsupported.")


@pytest.fixture(autouse=True)
def use_only_on_backend(request, backend):
if request.node.get_closest_marker('use_on_backend'):
current_backend = request.node.get_closest_marker('use_on_backend').args[0]
if current_backend != backend:
pytest.skip(f'skipped on this backend: "{current_backend}"')


def pytest_configure(config):
config.addinivalue_line(
"markers", "use_only_on_backend(backend): skip test if not on the specified backend",
)
# Pull all features from the base ragger conftest using the overridden configuration
pytest_plugins = ("ragger.conftest.base_conftest", )

0 comments on commit 9fa8573

Please sign in to comment.