diff options
-rw-r--r-- | unittest/test_storage.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/unittest/test_storage.py b/unittest/test_storage.py index 04b0581..b125aa9 100644 --- a/unittest/test_storage.py +++ b/unittest/test_storage.py @@ -395,3 +395,187 @@ def test_struct_multiline_prodtest(C): fwb=info_st.FirmwareVersionInternal_u8 ) print(info) + +@pytest.mark.other +@pytest.mark.firmware +def test_export_firmware_extended_fedora29(C): + """ + Check, whether the firmware file is exported correctly, and in correct size. + Apparently, the auto-remounting side effect of the v0.46 change, is disturbing the export process. + Unmounting the UV just before the export gives the device 20/20 success rate. + Test case for issue https://github.com/Nitrokey/nitrokey-app/issues/399 + """ + + skip_if_device_version_lower_than({'S': 43}) + skip_if_not_fedora('Tested on Fedora only. To check on other distros.') + + from time import sleep + import os + from os.path import exists as exist + import re + try: + import pyudev as pu + import pexpect + except: + pytest.skip('Skipping due to missing required packages: pyudev and pexpect.') + + ctx = pu.Context() + devices = ctx.list_devices(subsystem='block', ID_VENDOR='Nitrokey') + device = None + for d in devices: + if d.device_type == 'partition': + device = '/dev/{}'.format(d.sys_name) + break + assert device, 'Device could not be found' + + pexpect.run(f'udisksctl unmount -b {device}').decode() + sleep(1) + _res = pexpect.run(f'udisksctl mount -b {device}').decode() + firmware_abs_path = re.findall('at (/.*)\.', _res) + assert firmware_abs_path, 'Cannot get mount point' + firmware_abs_path = firmware_abs_path[0] + + print('path: {}, device: {}'.format(firmware_abs_path, device)) + assert firmware_abs_path, 'Cannot get mount point' + firmware_abs_path = firmware_abs_path + '/firmware.bin' + + checks = 0 + checks_add = 0 + + if exist(firmware_abs_path): + os.remove(firmware_abs_path) + + assert not exist(firmware_abs_path) + + ATTEMPTS = 20 + for i in range(ATTEMPTS): + # if umount is disabled, success rate is 3/10, enabled: 10/10 + pexpect.run(f'udisksctl unmount -b {device}') + assert C.NK_export_firmware(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK + pexpect.run(f'udisksctl mount -b {device}') + sleep(1) + firmware_file_exist = exist(firmware_abs_path) + if firmware_file_exist: + checks += 1 + getsize = os.path.getsize(firmware_abs_path) + print('Firmware file exist, size: {}'.format(getsize)) + checks_add += 1 if getsize >= 100 * 1024 else 0 + # checks_add += 1 if os.path.getsize(firmware_abs_path) == 256*1024 else 0 + os.remove(firmware_abs_path) + assert not exist(firmware_abs_path) + + print('CHECK {} ; CHECK ADDITIONAL {}'.format(checks, checks_add)) + + assert checks == ATTEMPTS + assert checks_add == checks + + +def skip_if_not_fedora(message:str) -> None: + import os + from os.path import exists as exist + + def skip(): + pytest.skip(message) + + os_release_fp = '/etc/os-release' + if not exist(os_release_fp): + skip() + with open(os_release_fp) as f: + os_release_lines = f.readlines() + if 'Fedora' not in os_release_lines[0]: + skip() + + +@pytest.mark.other +@pytest.mark.firmware +def test_export_firmware_extended_macos(C): + """ + Check, whether the firmware file is exported correctly, and in correct size. + Apparently, the auto-remounting side effect of the v0.46 change, is disturbing the export process. + Unmounting the UV just before the export gives the device 20/20 success rate. + Test case for issue https://github.com/Nitrokey/nitrokey-app/issues/399 + """ + + skip_if_device_version_lower_than({'S': 43}) + skip_if_not_macos('macOS specific test, due to the mount path and command.') + + import pexpect + from time import sleep + import os + from os.path import exists as exist + import plistlib + + usb_devices = pexpect.run('system_profiler -xml SPUSBDataType') + assert b'Nitrokey' in usb_devices, 'No Nitrokey devices connected' + usb_devices_parsed = plistlib.loads(usb_devices) + + assert isinstance(usb_devices_parsed, list), 'usb_devices_parsed has unexpected type' + + # Try to get all USB devices + try: + devices = usb_devices_parsed[0]['_items'][0]['_items'] + except KeyError: + devices = None + + assert devices is not None, 'could not list USB devices' + + device_item = None + + for item in devices: + if '_items' in item: + # Fix for macOS 10.13.6, Python 3.6.2 + item = item['_items'][0] + if 'manufacturer' in item and item['manufacturer'] == 'Nitrokey': + device_item = item + + # Try to get first volume of USB device + try: + volume = device_item['Media'][0]['volumes'][0] + except (KeyError, TypeError): + volume = None + + assert volume is not None, 'could not determine volume' + assert 'bsd_name' in volume, 'could not get BSD style device name' + + device = '/dev/' + volume['bsd_name'] + pexpect.run(f'diskutil mount {device}') + sleep(3) + assert 'mount_point' in volume, 'could not get mount point' + firmware_abs_path = volume['mount_point'] + '/firmware.bin' + checks = 0 + print('path: {}, device: {}'.format(firmware_abs_path, device)) + checks_add = 0 + + if exist(firmware_abs_path): + os.remove(firmware_abs_path) + + assert not exist(firmware_abs_path) + + ATTEMPTS = 20 + for i in range(ATTEMPTS): + # if umount is disabled, success rate is 3/10, enabled: 10/10 + pexpect.run(f'diskutil unmount {device}') + assert C.NK_export_firmware(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK + pexpect.run(f'diskutil mount {device}') + sleep(1) + firmware_file_exist = exist(firmware_abs_path) + if firmware_file_exist: + checks += 1 + getsize = os.path.getsize(firmware_abs_path) + print('Firmware file exist, size: {}'.format(getsize)) + checks_add += 1 if getsize >= 100 * 1024 else 0 + # checks_add += 1 if os.path.getsize(firmware_abs_path) == 256*1024 else 0 + os.remove(firmware_abs_path) + assert not exist(firmware_abs_path) + + print('CHECK {} ; CHECK ADDITIONAL {}'.format(checks, checks_add)) + + assert checks == ATTEMPTS + assert checks_add == checks + + +def skip_if_not_macos(message:str) -> None: + import platform + + if platform.system() != 'Darwin': + pytest.skip(message) |