1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 07:28:10 +00:00

ci: add hardware tests for T1

This enables to run device tests against an actual device connected to
our CI. It uses https://github.com/mmahut/tpmb to enter bootloader and
then it uploads a debug firmware to the device. The debug mode is the
used to "click" the buttons but we might improve this and actually use
the hardware buttons instead.
This commit is contained in:
Marek Mahut 2019-10-04 15:22:39 +02:00 committed by Tomas Susanka
parent bc4e8eaa16
commit 4264e87319
8 changed files with 181 additions and 0 deletions

View File

@ -0,0 +1,8 @@
# Hardware tests
Hardware tests are device tests that run against an actual device instead of an emulator.
This works thanks to [tpmb](https://github.com/mmahut/tpmb), which is a small arduino
device capable of pushing an actual buttons on the device. Currently T1 is supported
but TT might follow.
See `ci/test.yml` "hardware legacy device test" what exactly is run.

20
ci/hardware_tests/bootstrap.py Executable file
View File

@ -0,0 +1,20 @@
import configparser
import sys
from device.t1 import TrezorOne
def main(file: str = None):
config = configparser.ConfigParser()
config.read_file(open("hardware.cfg"))
t1 = TrezorOne(
config["t1"]["location"], config["t1"]["port"], config["t1"]["arduino_serial"],
)
t1.update_firmware(file)
if __name__ == "__main__":
file = None
if len(sys.argv) == 2:
file = sys.argv[1]
main(file)

View File

@ -0,0 +1,14 @@
with import <nixpkgs> {};
stdenv.mkDerivation rec {
name = "trezor-firmware-hardware-tests";
buildInputs = [
uhubctl
ffmpeg
pipenv
libusb1
dejavu_fonts
];
LD_LIBRARY_PATH = "${libusb1}/lib";
NIX_ENFORCE_PURITY = 0;
}

View File

@ -0,0 +1,46 @@
import datetime
import os
import time
import serial
class Device:
def __init__(self, uhub_location, uhub_port, arduino_serial):
self.uhub_location = uhub_location
self.uhub_port = uhub_port
self.arduino_serial = arduino_serial
self.serial = serial.Serial(arduino_serial, 9600)
def power_on(self):
self.now()
print("[hardware/usb] Turning power on...")
os.system(
"uhubctl -l {} -p {} -a on > /dev/null".format(
self.uhub_location, self.uhub_port
)
)
self.wait(3)
def power_off(self):
self.now()
print("[hardware/usb] Turning power off...")
os.system(
"uhubctl -l {} -p {} -r 100 -a off > /dev/null".format(
self.uhub_location, self.uhub_port
)
)
self.wait(3)
def touch(self, location, action):
raise NotImplementedError
@staticmethod
def wait(seconds):
Device.now()
print("[software] Waiting for {} seconds...".format(seconds))
time.sleep(seconds)
@staticmethod
def now():
print("\n[timestamp] {}".format(datetime.datetime.now()))

View File

@ -0,0 +1,47 @@
import os
from .device import Device
class TrezorOne(Device):
def touch(self, location, action):
self.now()
print(
"[hardware/trezor] Touching the {} button by {}...".format(location, action)
)
self.serial.write(("{} {}\n".format(location, action)).encode())
def update_firmware(self, file=None):
if file:
unofficial = True
trezorctlcmd = "trezorctl firmware-update -s -f {} &".format(file)
print("[software/trezorctl] Updating the firmware to {}...".format(file))
else:
unofficial = False
trezorctlcmd = "trezorctl firmware-update &"
print("[software/trezorctl] Updating the firmware to latest...")
self._enter_bootloader()
os.system(trezorctlcmd)
self.wait(3)
self.touch("right", "click")
self.wait(20)
if unofficial:
self.touch("right", "click")
self.wait(10)
self.power_off()
self.power_on()
if unofficial:
self.touch("right", "click")
self.wait(5)
self.touch("right", "click")
self.wait(5)
os.system("trezorctl get-features|grep version")
def _enter_bootloader(self):
self.power_off()
self.touch("all", "press")
self.wait(2)
self.power_on()
self.wait(2)
self.touch("all", "unpress")

View File

@ -0,0 +1,4 @@
[t1]
location = 3-1.4
port = 3
arduino_serial = /dev/ttyACM0

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
if [ $# -ne 2 ]
then
echo "Usage: $0 commit_id [start|stop]"
fi
OUTPUTFILE=video_$1_$(date +%s).mp4
INPUTDEVICE=/dev/video0
if [ "$2" == "start" ]; then
echo "[software/video] Starting record to $OUTPUTFILE"
ffmpeg -loglevel panic -f oss -f video4linux2 -i $INPUTDEVICE \
-vf "drawtext=font=Dejavu Sans: \
text='$1 | %{localtime} | %{pts}': x=(w-tw)/2: y=h-(2*lh): fontcolor=white: box=1: boxcolor=0x00000000@1: fontsize=15" $OUTPUTFILE &
export VPID=$!
elif [ "$2" == "stop" ]; then
echo "[software/video] Stopping the recording of $OUTPUTFILE"
pkill ffmpeg
sync
fi

View File

@ -319,3 +319,25 @@ storage test:
junit: tests/junit.xml junit: tests/junit.xml
expire_in: 1 week expire_in: 1 week
when: always when: always
# Hardware
hardware legacy device test:
stage: test
extends: .legacy_job
tags:
- tpmb
dependencies:
- legacy fw debug build
script:
- cd ci/hardware_tests
- nix-shell --run "./record_video.sh ${CI_COMMIT_SHORT_SHA} start"
- nix-shell --run "cd ../.. && pipenv sync"
- nix-shell --run "pipenv run python bootstrap.py"
- nix-shell --run "pipenv run python bootstrap.py ../../trezor-*.bin"
- nix-shell --run "pipenv run pytest ../../tests/device_tests"
- nix-shell --run "./record_video.sh ${CI_COMMIT_SHORT_SHA} stop"
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA"
paths:
- ci/hardware_tests/video*.mp4
expire_in: 2 days