Fix some expected boot slot fields are optional (#4964)

* Fix some expected boot slot fields are optional

* Move stuff around to make pylint happy
This commit is contained in:
Mike Degatano 2024-03-18 13:30:10 -04:00 committed by GitHub
parent 5426bd4392
commit 0e0fadd72d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 297 additions and 162 deletions

View File

@ -28,17 +28,17 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
SlotStatusDataType = TypedDict( SlotStatusDataType = TypedDict(
"SlotStatusDataType", "SlotStatusDataType",
{ {
"bundle.compatible": str,
"sha256": str,
"state": str,
"size": c_uint64,
"installed.count": c_uint32,
"class": str, "class": str,
"device": str,
"type": str, "type": str,
"bundle.version": str, "state": str,
"installed.timestamp": str, "device": str,
"status": str, "bundle.compatible": NotRequired[str],
"sha256": NotRequired[str],
"size": NotRequired[c_uint64],
"installed.count": NotRequired[c_uint32],
"bundle.version": NotRequired[str],
"installed.timestamp": NotRequired[str],
"status": NotRequired[str],
"activated.count": NotRequired[c_uint32], "activated.count": NotRequired[c_uint32],
"activated.timestamp": NotRequired[str], "activated.timestamp": NotRequired[str],
"boot-status": NotRequired[str], "boot-status": NotRequired[str],

View File

@ -33,17 +33,17 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
class SlotStatus: class SlotStatus:
"""Status of a slot.""" """Status of a slot."""
bundle_compatible: str
sha256: str
state: str
size: int
installed_count: int
class_: str class_: str
device: PurePath
type_: str type_: str
bundle_version: AwesomeVersion state: str
installed_timestamp: datetime device: PurePath
status: str bundle_compatible: str | None = None
sha256: str | None = None
size: int | None = None
installed_count: int | None = None
bundle_version: AwesomeVersion | None = None
installed_timestamp: datetime | None = None
status: str | None = None
activated_count: int | None = None activated_count: int | None = None
activated_timestamp: datetime | None = None activated_timestamp: datetime | None = None
boot_status: RaucState | None = None boot_status: RaucState | None = None
@ -54,17 +54,21 @@ class SlotStatus:
def from_dict(cls, data: SlotStatusDataType) -> "SlotStatus": def from_dict(cls, data: SlotStatusDataType) -> "SlotStatus":
"""Create SlotStatus from dictionary.""" """Create SlotStatus from dictionary."""
return cls( return cls(
bundle_compatible=data["bundle.compatible"],
sha256=data["sha256"],
state=data["state"],
size=data["size"],
installed_count=data["installed.count"],
class_=data["class"], class_=data["class"],
device=PurePath(data["device"]),
type_=data["type"], type_=data["type"],
bundle_version=AwesomeVersion(data["bundle.version"]), state=data["state"],
installed_timestamp=datetime.fromisoformat(data["installed.timestamp"]), device=PurePath(data["device"]),
status=data["status"], bundle_compatible=data.get("bundle.compatible"),
sha256=data.get("sha256"),
size=data.get("size"),
installed_count=data.get("installed.count"),
bundle_version=AwesomeVersion(data["bundle.version"])
if "bundle.version" in data
else None,
installed_timestamp=datetime.fromisoformat(data["installed.timestamp"])
if "installed.timestamp" in data
else None,
status=data.get("status"),
activated_count=data.get("activated.count"), activated_count=data.get("activated.count"),
activated_timestamp=datetime.fromisoformat(data["activated.timestamp"]) activated_timestamp=datetime.fromisoformat(data["activated.timestamp"])
if "activated.timestamp" in data if "activated.timestamp" in data
@ -77,19 +81,26 @@ class SlotStatus:
def to_dict(self) -> SlotStatusDataType: def to_dict(self) -> SlotStatusDataType:
"""Get dictionary representation.""" """Get dictionary representation."""
out: SlotStatusDataType = { out: SlotStatusDataType = {
"bundle.compatible": self.bundle_compatible,
"sha256": self.sha256,
"state": self.state,
"size": self.size,
"installed.count": self.installed_count,
"class": self.class_, "class": self.class_,
"device": self.device.as_posix(),
"type": self.type_, "type": self.type_,
"bundle.version": str(self.bundle_version), "state": self.state,
"installed.timestamp": str(self.installed_timestamp), "device": self.device.as_posix(),
"status": self.status,
} }
if self.bundle_compatible is not None:
out["bundle.compatible"] = self.bundle_compatible
if self.sha256 is not None:
out["sha256"] = self.sha256
if self.size is not None:
out["size"] = self.size
if self.installed_count is not None:
out["installed.count"] = self.installed_count
if self.bundle_version is not None:
out["bundle.version"] = str(self.bundle_version)
if self.installed_timestamp is not None:
out["installed.timestamp"] = str(self.installed_timestamp)
if self.status is not None:
out["status"] = self.status
if self.activated_count is not None: if self.activated_count is not None:
out["activated.count"] = self.activated_count out["activated.count"] = self.activated_count
if self.activated_timestamp: if self.activated_timestamp:

View File

@ -7,6 +7,133 @@ from .base import DBusServiceMock, dbus_method
BUS_NAME = "de.pengutronix.rauc" BUS_NAME = "de.pengutronix.rauc"
SLOT_STATUS_FIXTURE: list[tuple[str | dict[str, Variant]]] = [
(
"kernel.0",
{
"activated.count": Variant("u", 9),
"activated.timestamp": Variant("s", "2022-08-23T21:03:22Z"),
"boot-status": Variant("s", "good"),
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"c624db648b8401fae37ee5bb1a6ec90bdf4183aef364b33314a73c7198e49d5b",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 10371072),
"installed.count": Variant("u", 9),
"class": Variant("s", "kernel"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-kernel0"),
"type": Variant("s", "raw"),
"bootname": Variant("s", "A"),
"bundle.version": Variant("s", "9.0.dev20220818"),
"installed.timestamp": Variant("s", "2022-08-23T21:03:16Z"),
"status": Variant("s", "ok"),
},
),
(
"boot.0",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"a5019b335f33be2cf89c96bb2d0695030adb72c1d13d650a5bbe1806dd76d6cc",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 25165824),
"installed.count": Variant("u", 19),
"class": Variant("s", "boot"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-boot"),
"type": Variant("s", "vfat"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:46Z"),
},
),
(
"rootfs.0",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"parent": Variant("s", "kernel.0"),
"state": Variant("s", "inactive"),
"size": Variant("t", 117456896),
"sha256": Variant(
"s",
"7d908b4d578d072b1b0f75de8250fd97b6e119bff09518a96fffd6e4aec61721",
),
"class": Variant("s", "rootfs"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-system0"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220818"),
"installed.timestamp": Variant("s", "2022-08-23T21:03:21Z"),
"installed.count": Variant("u", 9),
},
),
(
"spl.0",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"9856a94df1d6abbc672adaf95746ec76abd3a8191f9d08288add6bb39e63ef45",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 8388608),
"installed.count": Variant("u", 19),
"class": Variant("s", "spl"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-boot"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:51Z"),
},
),
(
"kernel.1",
{
"activated.count": Variant("u", 10),
"activated.timestamp": Variant("s", "2022-08-25T21:11:52Z"),
"boot-status": Variant("s", "good"),
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"f57e354b8bd518022721e71fafaf278972af966d8f6cbefb4610db13785801c8",
),
"state": Variant("s", "booted"),
"size": Variant("t", 10371072),
"installed.count": Variant("u", 10),
"class": Variant("s", "kernel"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-kernel1"),
"type": Variant("s", "raw"),
"bootname": Variant("s", "B"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:46Z"),
"status": Variant("s", "ok"),
},
),
(
"rootfs.1",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"parent": Variant("s", "kernel.1"),
"state": Variant("s", "active"),
"size": Variant("t", 117456896),
"sha256": Variant(
"s",
"55936b64d391954ae1aed24dd1460e191e021e78655470051fa7939d12fff68a",
),
"class": Variant("s", "rootfs"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-system1"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:51Z"),
"installed.count": Variant("u", 10),
},
),
]
def setup(object_path: str | None = None) -> DBusServiceMock: def setup(object_path: str | None = None) -> DBusServiceMock:
"""Create dbus mock object.""" """Create dbus mock object."""
@ -22,6 +149,7 @@ class Rauc(DBusServiceMock):
object_path = "/" object_path = "/"
interface = "de.pengutronix.rauc.Installer" interface = "de.pengutronix.rauc.Installer"
response_mark: list[str] | DBusError = ["kernel.1", "marked slot kernel.1 as good"] response_mark: list[str] | DBusError = ["kernel.1", "marked slot kernel.1 as good"]
response_get_slot_status = SLOT_STATUS_FIXTURE
@dbus_property(access=PropertyAccess.READ) @dbus_property(access=PropertyAccess.READ)
def Operation(self) -> "s": def Operation(self) -> "s":
@ -81,129 +209,4 @@ class Rauc(DBusServiceMock):
@dbus_method() @dbus_method()
def GetSlotStatus(self) -> "a(sa{sv})": def GetSlotStatus(self) -> "a(sa{sv})":
"""Get slot status.""" """Get slot status."""
return [ return self.response_get_slot_status
(
"kernel.0",
{
"activated.count": Variant("u", 9),
"activated.timestamp": Variant("s", "2022-08-23T21:03:22Z"),
"boot-status": Variant("s", "good"),
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"c624db648b8401fae37ee5bb1a6ec90bdf4183aef364b33314a73c7198e49d5b",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 10371072),
"installed.count": Variant("u", 9),
"class": Variant("s", "kernel"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-kernel0"),
"type": Variant("s", "raw"),
"bootname": Variant("s", "A"),
"bundle.version": Variant("s", "9.0.dev20220818"),
"installed.timestamp": Variant("s", "2022-08-23T21:03:16Z"),
"status": Variant("s", "ok"),
},
),
(
"boot.0",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"a5019b335f33be2cf89c96bb2d0695030adb72c1d13d650a5bbe1806dd76d6cc",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 25165824),
"installed.count": Variant("u", 19),
"class": Variant("s", "boot"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-boot"),
"type": Variant("s", "vfat"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:46Z"),
},
),
(
"rootfs.0",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"parent": Variant("s", "kernel.0"),
"state": Variant("s", "inactive"),
"size": Variant("t", 117456896),
"sha256": Variant(
"s",
"7d908b4d578d072b1b0f75de8250fd97b6e119bff09518a96fffd6e4aec61721",
),
"class": Variant("s", "rootfs"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-system0"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220818"),
"installed.timestamp": Variant("s", "2022-08-23T21:03:21Z"),
"installed.count": Variant("u", 9),
},
),
(
"spl.0",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"9856a94df1d6abbc672adaf95746ec76abd3a8191f9d08288add6bb39e63ef45",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 8388608),
"installed.count": Variant("u", 19),
"class": Variant("s", "spl"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-boot"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:51Z"),
},
),
(
"kernel.1",
{
"activated.count": Variant("u", 10),
"activated.timestamp": Variant("s", "2022-08-25T21:11:52Z"),
"boot-status": Variant("s", "good"),
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"sha256": Variant(
"s",
"f57e354b8bd518022721e71fafaf278972af966d8f6cbefb4610db13785801c8",
),
"state": Variant("s", "booted"),
"size": Variant("t", 10371072),
"installed.count": Variant("u", 10),
"class": Variant("s", "kernel"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-kernel1"),
"type": Variant("s", "raw"),
"bootname": Variant("s", "B"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:46Z"),
"status": Variant("s", "ok"),
},
),
(
"rootfs.1",
{
"bundle.compatible": Variant("s", "haos-odroid-n2"),
"parent": Variant("s", "kernel.1"),
"state": Variant("s", "active"),
"size": Variant("t", 117456896),
"sha256": Variant(
"s",
"55936b64d391954ae1aed24dd1460e191e021e78655470051fa7939d12fff68a",
),
"class": Variant("s", "rootfs"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-system1"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "9.0.dev20220824"),
"installed.timestamp": Variant("s", "2022-08-25T21:11:51Z"),
"installed.count": Variant("u", 10),
},
),
]

View File

@ -3,12 +3,16 @@
from unittest.mock import PropertyMock, patch from unittest.mock import PropertyMock, patch
from awesomeversion import AwesomeVersion from awesomeversion import AwesomeVersion
from dbus_fast import Variant
import pytest import pytest
from supervisor.const import CoreState from supervisor.const import CoreState
from supervisor.coresys import CoreSys from supervisor.coresys import CoreSys
from supervisor.exceptions import HassOSJobError from supervisor.exceptions import HassOSJobError
from tests.dbus_service_mocks.base import DBusServiceMock
from tests.dbus_service_mocks.rauc import Rauc as RaucService
# pylint: disable=protected-access # pylint: disable=protected-access
@ -78,3 +82,120 @@ async def test_board_name_supervised(coresys: CoreSys) -> None:
await coresys.dbus.hostname.connect(coresys.dbus.bus) await coresys.dbus.hostname.connect(coresys.dbus.bus)
await coresys.os.load() await coresys.os.load()
assert coresys.os.board == "supervised" assert coresys.os.board == "supervised"
async def test_load_slot_status_fresh_install(
coresys: CoreSys,
all_dbus_services: dict[str, DBusServiceMock | dict[str, DBusServiceMock]],
) -> None:
"""Test load works when slot status returns minimal fresh install response."""
rauc_service: RaucService = all_dbus_services["rauc"]
rauc_service.response_get_slot_status = [
(
"kernel.0",
{
"class": Variant("s", "kernel"),
"boot-status": Variant("s", "good"),
"type": Variant("s", "raw"),
"bootname": Variant("s", "A"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-kernel0"),
"state": Variant("s", "inactive"),
},
),
(
"boot.0",
{
"bundle.compatible": Variant("s", "haos-green"),
"sha256": Variant(
"s",
"f0b8a08d9bc49acbb230cf709beb0aa214cbee09969566755dff52fb8b3cc29b",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 16777216),
"installed.count": Variant("u", 1),
"class": Variant("s", "boot"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-boot"),
"type": Variant("s", "vfat"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "12.2.dev20240313"),
"installed.timestamp": Variant("s", "2024-03-15T17:27:38Z"),
},
),
(
"rootfs.0",
{
"class": Variant("s", "rootfs"),
"parent": Variant("s", "kernel.0"),
"type": Variant("s", "raw"),
"state": Variant("s", "inactive"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-system0"),
},
),
(
"spl.0",
{
"bundle.compatible": Variant("s", "haos-green"),
"sha256": Variant(
"s",
"97e4f1616250e7f9d2b20d98a972cf3aab03849a8cf50a8630f96a183b64384f",
),
"state": Variant("s", "inactive"),
"size": Variant("t", 16777216),
"installed.count": Variant("u", 1),
"class": Variant("s", "spl"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-boot"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "12.2.dev20240313"),
"installed.timestamp": Variant("s", "2024-03-15T17:27:47Z"),
},
),
(
"kernel.1",
{
"activated.count": Variant("u", 1),
"activated.timestamp": Variant("s", "2024-03-15T17:27:47Z"),
"boot-status": Variant("s", "good"),
"bundle.compatible": Variant("s", "haos-green"),
"sha256": Variant(
"s",
"c327b3c2ac4f56926d0d7c4693fe79c67dc05ed49c4abd020da981bf4faf977f",
),
"state": Variant("s", "booted"),
"size": Variant("t", 13410304),
"installed.count": Variant("u", 1),
"class": Variant("s", "kernel"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-kernel1"),
"type": Variant("s", "raw"),
"bootname": Variant("s", "B"),
"bundle.version": Variant("s", "12.2.dev20240313"),
"installed.timestamp": Variant("s", "2024-03-15T17:27:39Z"),
"status": Variant("s", "ok"),
},
),
(
"rootfs.1",
{
"bundle.compatible": Variant("s", "haos-green"),
"parent": Variant("s", "kernel.1"),
"state": Variant("s", "active"),
"size": Variant("t", 194560000),
"sha256": Variant(
"s",
"151dbfff469a7f1252cb8482e7a9439c5164f52c53ed141e377c10e6858208cb",
),
"class": Variant("s", "rootfs"),
"device": Variant("s", "/dev/disk/by-partlabel/hassos-system1"),
"type": Variant("s", "raw"),
"status": Variant("s", "ok"),
"bundle.version": Variant("s", "12.2.dev20240313"),
"installed.timestamp": Variant("s", "2024-03-15T17:27:45Z"),
"installed.count": Variant("u", 1),
},
),
]
await coresys.os.load()
assert len(coresys.os.slots) == 6
assert coresys.os.get_slot_name("A") == "kernel.0"
assert coresys.os.get_slot_name("B") == "kernel.1"