Skip to content

Commit

Permalink
Add fwupdmgr attachment job (New) (#1089)
Browse files Browse the repository at this point in the history
* Add fwupdmgr test job and plans

* Add it to client-cert-desktop test plan

* modified the workaround

modified the workaround

* Update providers/base/units/firmware/jobs.pxu

Co-authored-by: kissiel <kissiel@gmail.com>

* removed the step to restore SNAP environ var

removed the step to restore the SNAP env

* retrieve firmware by debian and snap fwupd

implement a script to be able to retrieve frimware information by debian
fwupd and snap fwupd

* Restructure scripts and added unittest cases

restructure scripts and added unittest cases

---------

Co-authored-by: Patrick Liu <patrick.liu@canonical.com>
Co-authored-by: kissiel <kissiel@gmail.com>
  • Loading branch information
3 people authored Apr 11, 2024
1 parent 18d9bd8 commit 6e64f92
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 0 deletions.
108 changes: 108 additions & 0 deletions providers/base/bin/get_firmware_info_fwupd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env python3
# This file is part of Checkbox.
#
# Copyright 2024 Canonical Ltd.
# Written by:
# Stanley Huang <stanley.huang@canonical.com>
#
# Checkbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3,
# as published by the Free Software Foundation.
#
# Checkbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.

import os
import sys
import json
import shlex
import logging
import subprocess
from checkbox_support.snap_utils.snapd import Snapd


def get_fwupdmgr_services_versions():
"""Show fwupd client and daemon versions
Returns:
list: fwupd client and daemon versions
"""
fwupd_vers = subprocess.run(
shlex.split("fwupdmgr --version --json"),
capture_output=True)
fwupd_vers = json.loads(fwupd_vers.stdout).get("Versions", [])

return fwupd_vers


def get_fwupd_runtime_version():
"""Get fwupd runtime version
Returns:
tuple: fwupd runtime version
"""
runtime_ver = ()

for ver in get_fwupdmgr_services_versions():
if (ver.get("Type") == "runtime" and
ver.get("AppstreamId") == "org.freedesktop.fwupd"):
runtime_ver = tuple(map(int, ver.get("Version").split(".")))

return runtime_ver


def get_firmware_info_fwupd():
"""
Dump firmware information for all devices detected by fwupd
"""
if Snapd().list("fwupd"):
# Dump firmware info by fwupd snap
subprocess.run(shlex.split("fwupd.fwupdmgr get-devices --json"))
else:
# Dump firmware info by fwupd debian package
runtime_ver = get_fwupd_runtime_version()
# Apply workaround to unset the SNAP for the fwupd issue
# See details from following PR
# https://github.com/canonical/checkbox/pull/1089

# SNAP environ is avaialble, so it's running on checkbox snap
# Unset the environ variable if debian fwupd lower than 1.9.14
if os.environ.get("SNAP") and runtime_ver < (1, 9, 14):
del os.environ["SNAP"]

subprocess.run(shlex.split("fwupdmgr get-devices --json"))


if __name__ == "__main__":

root_logger = logging.getLogger()
root_logger.setLevel(logging.INFO)
logger_format = "%(asctime)s %(levelname)-8s %(message)s"
date_format = "%Y-%m-%d %H:%M:%S"

# Log DEBUG and INFO to stdout, others to stderr
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setFormatter(logging.Formatter(logger_format, date_format))

stderr_handler = logging.StreamHandler(sys.stderr)
stderr_handler.setFormatter(logging.Formatter(logger_format, date_format))

stdout_handler.setLevel(logging.DEBUG)
stderr_handler.setLevel(logging.WARNING)

# Add a filter to the stdout handler to limit log records to
# INFO level and below
stdout_handler.addFilter(lambda record: record.levelno <= logging.INFO)

root_logger.addHandler(stderr_handler)
root_logger.addHandler(stdout_handler)

try:
get_firmware_info_fwupd()
except Exception as err:
logging.error(err)
178 changes: 178 additions & 0 deletions providers/base/tests/test_get_firmware_info_fwupd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import os
import json
import unittest
import subprocess
from unittest.mock import patch
import get_firmware_info_fwupd


class TestGetFirmwareInfo(unittest.TestCase):

@patch("json.loads")
@patch("subprocess.run")
def test_get_deb_fwupd_version_success(self, mock_subporcess, mock_json):

dict_resp = {
"Versions": [
{
"Type": "runtime",
"AppstreamId": "org.freedesktop.fwupd",
"Version": "1.9.14"
},
{
"Type": "compile",
"AppstreamId": "org.freedesktop.fwupd",
"Version": "1.7.9"
}
]
}
json_resp = json.dumps(dict_resp)
mock_subporcess.return_value = subprocess.CompletedProcess(
returncode=0,
stdout=json_resp,
args=["fwupdmgr", "--version", "--json"]
)
mock_json.return_value = dict_resp

fwupd_vers = get_firmware_info_fwupd.get_fwupdmgr_services_versions()
mock_subporcess.assert_called_with(
['fwupdmgr', '--version', '--json'],
capture_output=True)
mock_json.assert_called_with(json_resp)
self.assertListEqual(dict_resp["Versions"], fwupd_vers)

@patch("json.loads")
@patch("subprocess.run")
def test_get_deb_fwupd_version_key_not_match(
self, mock_subporcess, mock_json):

dict_resp = {
"Services": [
{
"Type": "runtime",
"AppstreamId": "org.freedesktop.fwupd",
"Version": "1.9.14"
},
{
"Type": "compile",
"AppstreamId": "org.freedesktop.fwupd",
"Version": "1.7.9"
}
]
}
json_resp = json.dumps(dict_resp)
mock_subporcess.return_value = subprocess.CompletedProcess(
returncode=0,
stdout=json_resp,
args=["fwupdmgr", "--version", "--json"]
)
mock_json.return_value = dict_resp

fwupd_vers = get_firmware_info_fwupd.get_fwupdmgr_services_versions()
mock_subporcess.assert_called_with(
['fwupdmgr', '--version', '--json'], capture_output=True)
mock_json.assert_called_with(json_resp)
self.assertListEqual([], fwupd_vers)

@patch("get_firmware_info_fwupd.get_fwupdmgr_services_versions")
def test_get_deb_fwupd_runtime_version_success(self, mock_fwupd_vers):

expected_fwupd_ver = (1, 7, 9)
fwupd_vers_resp = [
{
"Type": "runtime",
"AppstreamId": "org.freedesktop.fwupd",
"Version": "1.7.9"
},
{
"Type": "compile",
"AppstreamId": "org.freedesktop.fwupd",
"Version": "1.7.9"
}
]

mock_fwupd_vers.return_value = fwupd_vers_resp
runtime_ver = get_firmware_info_fwupd.get_fwupd_runtime_version()
self.assertEqual(expected_fwupd_ver, runtime_ver)

@patch("get_firmware_info_fwupd.get_fwupdmgr_services_versions")
def test_get_deb_fwupd_runtime_version_failed(self, mock_fwupd_vers):

fwupd_vers_resp = [
{
"Type": "compile",
"AppstreamId": "org.freedesktop.fwupd",
"Version": "1.7.9"
}
]

mock_fwupd_vers.return_value = fwupd_vers_resp
runtime_ver = get_firmware_info_fwupd.get_fwupd_runtime_version()
self.assertEqual((), runtime_ver)

@patch("subprocess.run")
@patch("checkbox_support.snap_utils.snapd.Snapd.list")
def test_get_firmware_data_by_fwupd_snap(
self, mock_snapd, mock_subporcess):

mock_snapd.return_value = {
"id": "HpOj37PuyuaMUZY0NQhtwnp7oS5P8u5R",
"title": "fwupd",
"summary": "Firmware updates for Linux"
}
get_firmware_info_fwupd.get_firmware_info_fwupd()
mock_snapd.assert_called_with("fwupd")
mock_subporcess.assert_called_with(
['fwupd.fwupdmgr', 'get-devices', '--json'])

@patch.dict(os.environ, {"SNAP": "checkbox-snap"})
@patch("subprocess.run")
@patch("get_firmware_info_fwupd.get_fwupd_runtime_version")
@patch("checkbox_support.snap_utils.snapd.Snapd.list")
def test_get_firmware_data_by_fwupd1914_deb_on_checkbox_snap(
self, mock_snapd, mock_fwupd_ver, mock_subporcess):

mock_snapd.return_value = None
mock_fwupd_ver.return_value = (1, 9, 14)

get_firmware_info_fwupd.get_firmware_info_fwupd()
mock_snapd.assert_called_with("fwupd")
self.assertEqual(
os.environ.get("SNAP"), "checkbox-snap")
mock_subporcess.assert_called_with(
['fwupdmgr', 'get-devices', '--json'])

@patch.dict(os.environ, {"SNAP": "checkbox-snap"})
@patch("subprocess.run")
@patch("get_firmware_info_fwupd.get_fwupd_runtime_version")
@patch("checkbox_support.snap_utils.snapd.Snapd.list")
def test_get_firmware_data_by_fwupd_deb179_on_checkbox_snap(
self, mock_snapd, mock_fwupd_ver, mock_subporcess):

mock_snapd.return_value = False
mock_fwupd_ver.return_value = (1, 7, 9)

# SNAP env is available before get_firmware_info_fwupd been called
self.assertEqual(os.environ.get("SNAP"), "checkbox-snap")
get_firmware_info_fwupd.get_firmware_info_fwupd()
mock_snapd.assert_called_with("fwupd")
# SNAP env is empty after get_firmware_info_fwupd been called
self.assertIsNone(os.environ.get("SNAP"))
mock_subporcess.assert_called_with(
['fwupdmgr', 'get-devices', '--json'])

@patch("subprocess.run")
@patch("get_firmware_info_fwupd.get_fwupd_runtime_version")
@patch("checkbox_support.snap_utils.snapd.Snapd.list")
def test_get_firmware_data_by_fwupd_deb_on_checkbox_deb(
self, mock_snapd, mock_fwupd_ver, mock_subporcess):

mock_snapd.return_value = False
mock_fwupd_ver.return_value = (1, 7, 9)

# SNAP env is empty
self.assertIsNone(os.environ.get("SNAP"))
get_firmware_info_fwupd.get_firmware_info_fwupd()
mock_snapd.assert_called_with("fwupd")
mock_subporcess.assert_called_with(
['fwupdmgr', 'get-devices', '--json'])
10 changes: 10 additions & 0 deletions providers/base/units/firmware/jobs.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,13 @@ plugin: attachment
depends: firmware/fwts_dump
command:
[ -f "$PLAINBOX_SESSION_SHARE/acpidump.log" ] && gzip -c "$PLAINBOX_SESSION_SHARE/acpidump.log"

id: firmware/fwupdmgr_get_devices
plugin: attachment
category_id: com.canonical.plainbox::firmware
_summary: Collect the device firmware update information
_purpose: Attach information about the devices, as reported by the fwupdmgr
requires:
executable.name in ("fwupdmgr", "fwupd.fwupdmgr")
command:
get_firmware_info_fwupd.py
25 changes: 25 additions & 0 deletions providers/base/units/firmware/test-plan.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,28 @@ include:
firmware/fwts_desktop_diagnosis
firmware/fwts_desktop_diagnosis_results.log.gz


id: firmware-fwupdmgr-full
unit: test plan
_name: fwupdmgr test
_description: Firmware update manager tests
include:
nested_part:
firmware-fwupdmgr-automated
firmware-fwupdmgr-manual

id: firmware-fwupdmgr-automated
unit: test plan
_name: Auto fwupdmgr tests
_description: Automated firmware update manager tests
bootstrap_include:
executable
environment
include:
firmware/fwupdmgr_get_devices

id: firmware-fwupdmgr-manual
unit: test plan
_name: Manual fwupdmgr tests
_description: Manual firmware update manager tests
include:
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ nested_part:
disk-cert-automated
misc-client-cert-automated
fingerprint-automated
firmware-fwupdmgr-automated
keys-cert-automated
led-cert-automated
mediacard-cert-automated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ nested_part:
disk-cert-automated
misc-client-cert-automated
fingerprint-automated
firmware-fwupdmgr-automated
keys-cert-automated
led-cert-automated
mediacard-cert-automated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ nested_part:
disk-cert-automated
misc-client-cert-automated
fingerprint-automated
firmware-fwupdmgr-automated
keys-cert-automated
led-cert-automated
mediacard-cert-automated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ nested_part:
disk-cert-automated
misc-client-cert-automated
fingerprint-automated
firmware-fwupdmgr-automated
keys-cert-automated
led-cert-automated
mediacard-cert-automated
Expand Down

0 comments on commit 6e64f92

Please sign in to comment.