mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-29 06:30:19 +00:00

This allows us to run the device tests with all 4 supported types of unifying dongles plugged in at the same time.
159 lines
5.1 KiB
Python
Executable File
159 lines
5.1 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# pylint: disable=wrong-import-position,too-many-locals,unused-argument,wrong-import-order
|
|
#
|
|
# Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
|
#
|
|
# SPDX-License-Identifier: LGPL-2.1+
|
|
|
|
import gi
|
|
import os
|
|
import requests
|
|
import time
|
|
import sys
|
|
import glob
|
|
import json
|
|
from termcolor import colored
|
|
|
|
gi.require_version('Fwupd', '2.0')
|
|
|
|
from gi.repository import Fwupd
|
|
from gi.repository import Gio
|
|
from gi.repository import GLib
|
|
|
|
|
|
def _get_cache_file(fn):
|
|
cachedir = os.path.expanduser('~/.cache/fwupdmgr')
|
|
if not os.path.exists(cachedir):
|
|
os.makedirs(cachedir)
|
|
cachefn = os.path.join(cachedir, fn)
|
|
if not os.path.exists(cachefn):
|
|
url = 'https://fwupd.org/downloads/' + fn
|
|
print("Downloading", url)
|
|
r = requests.get(url)
|
|
r.raise_for_status()
|
|
f = open(cachefn, 'wb')
|
|
f.write(r.content)
|
|
f.close()
|
|
return cachefn
|
|
|
|
|
|
class DeviceTest:
|
|
def __init__(self, obj):
|
|
self.client = Fwupd.Client.new()
|
|
self.name = obj.get('name', 'Unknown')
|
|
self.guids = obj.get('guids', [])
|
|
self.releases = obj.get('releases', [])
|
|
self.has_runtime = obj.get('runtime', True)
|
|
self.interactive = obj.get('interactive', False)
|
|
self.disabled = obj.get('disabled', False)
|
|
self.protocol = obj.get('protocol', None)
|
|
|
|
def _info(self, msg):
|
|
print(colored('[INFO]'.ljust(10), 'blue'), msg)
|
|
|
|
def _warn(self, msg):
|
|
print(colored('[WARN]'.ljust(10), 'yellow'), msg)
|
|
|
|
def _failed(self, msg):
|
|
print(colored('[FAILED]'.ljust(10), 'red'), msg)
|
|
|
|
def _success(self, msg):
|
|
print(colored('[SUCCESS]'.ljust(10), 'green'), msg)
|
|
|
|
def _get_by_device_guids(self):
|
|
cancellable = Gio.Cancellable.new()
|
|
for d in self.client.get_devices(cancellable):
|
|
for guid in self.guids:
|
|
if d.has_guid(guid):
|
|
if self.protocol and self.protocol != d.get_protocol():
|
|
continue
|
|
return d
|
|
return None
|
|
|
|
def run(self):
|
|
|
|
print('Running test on {}'.format(self.name))
|
|
dev = self._get_by_device_guids()
|
|
if not dev:
|
|
self._warn('no {} attached'.format(self.name))
|
|
return
|
|
|
|
self._info('Current version {}'.format(dev.get_version()))
|
|
|
|
# apply each file
|
|
for obj in self.releases:
|
|
ver = obj.get('version')
|
|
fn = obj.get('file')
|
|
repeat = obj.get('repeat', 1)
|
|
try:
|
|
fn_cache = _get_cache_file(fn)
|
|
except requests.exceptions.HTTPError as e:
|
|
self._failed('Failed to download: {}'.format(str(e)))
|
|
return
|
|
|
|
# some hardware updates more than one partition with the same firmware
|
|
for cnt in range(0, repeat):
|
|
if dev.get_version() == ver:
|
|
flags = Fwupd.InstallFlags.ALLOW_REINSTALL
|
|
self._info('Reinstalling version {}'.format(ver))
|
|
else:
|
|
flags = Fwupd.InstallFlags.ALLOW_OLDER
|
|
self._info('Installing version {}'.format(ver))
|
|
cancellable = Gio.Cancellable.new()
|
|
|
|
try:
|
|
self.client.install(dev.get_id(), fn_cache, flags, cancellable)
|
|
except GLib.Error as e:
|
|
if str(e).find('no HWIDs matched') != -1:
|
|
self._info('Skipping as {}'.format(e))
|
|
continue
|
|
self._failed('Could not install: {}'.format(e))
|
|
return
|
|
|
|
# verify version
|
|
if self.has_runtime:
|
|
dev = self._get_by_device_guids()
|
|
if not dev:
|
|
self._failed('Device did not come back: ' + self.name)
|
|
return
|
|
if not dev.get_version():
|
|
self._failed('No version set after flash for: ' + self.name)
|
|
return
|
|
if cnt == repeat - 1 and dev.get_version() != ver:
|
|
self._failed('Got: ' + dev.get_version() + ', expected: ' + ver)
|
|
return
|
|
self._success('Installed {}'.format(dev.get_version()))
|
|
else:
|
|
self._success('Assumed success (no runtime)')
|
|
|
|
# wait for device to settle?
|
|
time.sleep(2)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
# get manifests to parse
|
|
device_fns = []
|
|
if len(sys.argv) == 1:
|
|
device_fns.extend(glob.glob('devices/*.json'))
|
|
else:
|
|
for fn in sys.argv[1:]:
|
|
device_fns.append(fn)
|
|
|
|
# run each test
|
|
for fn in sorted(device_fns):
|
|
print('{}:'.format(fn))
|
|
with open(fn, 'r') as f:
|
|
try:
|
|
obj = json.load(f)
|
|
except json.decoder.JSONDecodeError as e:
|
|
print('Failed to parse {}: {}'.format(fn, e))
|
|
continue
|
|
t = DeviceTest(obj)
|
|
if t.disabled:
|
|
continue
|
|
if t.interactive and len(device_fns) > 1:
|
|
continue
|
|
t.run()
|
|
sys.exit(0)
|