mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-12-25 04:46:25 +00:00
Allow client to change boot slot via API (#4945)
* Allow client to change boot slot via API * Wrap call to rauc in job that checks for OS * Reboot after changing the active boot slot * Add test cases and clean up * BootName to BootSlot * Fix test * Rename boot_name to boot_slot * Fix tests after field change
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
"""Test OS API."""
|
||||
|
||||
from unittest.mock import PropertyMock, patch
|
||||
from unittest.mock import Mock, PropertyMock, patch
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
from dbus_fast import DBusError, ErrorType
|
||||
import pytest
|
||||
|
||||
from supervisor.coresys import CoreSys
|
||||
@@ -19,6 +20,7 @@ from tests.dbus_service_mocks.agent_boards_yellow import Yellow as YellowService
|
||||
from tests.dbus_service_mocks.agent_datadisk import DataDisk as DataDiskService
|
||||
from tests.dbus_service_mocks.agent_system import System as SystemService
|
||||
from tests.dbus_service_mocks.base import DBusServiceMock
|
||||
from tests.dbus_service_mocks.rauc import Rauc as RaucService
|
||||
|
||||
|
||||
@pytest.fixture(name="boards_service")
|
||||
@@ -30,7 +32,7 @@ async def fixture_boards_service(
|
||||
|
||||
|
||||
async def test_api_os_info(api_client: TestClient):
|
||||
"""Test docker info api."""
|
||||
"""Test os info api."""
|
||||
resp = await api_client.get("/os/info")
|
||||
result = await resp.json()
|
||||
|
||||
@@ -41,18 +43,37 @@ async def test_api_os_info(api_client: TestClient):
|
||||
"board",
|
||||
"boot",
|
||||
"data_disk",
|
||||
"boot_slots",
|
||||
):
|
||||
assert attr in result["data"]
|
||||
|
||||
|
||||
async def test_api_os_info_with_agent(api_client: TestClient, coresys: CoreSys):
|
||||
"""Test docker info api."""
|
||||
"""Test os info api for data disk."""
|
||||
resp = await api_client.get("/os/info")
|
||||
result = await resp.json()
|
||||
|
||||
assert result["data"]["data_disk"] == "BJTD4R-0x97cde291"
|
||||
|
||||
|
||||
async def test_api_os_info_boot_slots(
|
||||
api_client: TestClient, coresys: CoreSys, os_available
|
||||
):
|
||||
"""Test os info api for boot slots."""
|
||||
await coresys.os.load()
|
||||
resp = await api_client.get("/os/info")
|
||||
result = await resp.json()
|
||||
|
||||
assert result["data"]["boot_slots"] == {
|
||||
"A": {
|
||||
"state": "inactive",
|
||||
"status": "good",
|
||||
"version": "9.0.dev20220818",
|
||||
},
|
||||
"B": {"state": "booted", "status": "good", "version": "9.0.dev20220824"},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"new_disk",
|
||||
["/dev/sdaaaa", "/dev/mmcblk1", "Generic-Flash-Disk-61BCDDB6"],
|
||||
@@ -131,6 +152,56 @@ async def test_api_os_datadisk_wipe(
|
||||
reboot.assert_called_once()
|
||||
|
||||
|
||||
async def test_api_set_boot_slot(
|
||||
api_client: TestClient,
|
||||
all_dbus_services: dict[str, DBusServiceMock],
|
||||
coresys: CoreSys,
|
||||
os_available,
|
||||
):
|
||||
"""Test changing the boot slot via API."""
|
||||
rauc_service: RaucService = all_dbus_services["rauc"]
|
||||
await coresys.os.load()
|
||||
|
||||
with patch.object(SystemControl, "reboot") as reboot:
|
||||
resp = await api_client.post("/os/boot-slot", json={"boot_slot": "A"})
|
||||
assert resp.status == 200
|
||||
|
||||
reboot.assert_called_once()
|
||||
assert rauc_service.Mark.calls == [("active", "kernel.0")]
|
||||
|
||||
|
||||
async def test_api_set_boot_slot_invalid(api_client: TestClient):
|
||||
"""Test invalid calls to set boot slot."""
|
||||
resp = await api_client.post("/os/boot-slot", json={"boot_slot": "C"})
|
||||
assert resp.status == 400
|
||||
result = await resp.json()
|
||||
assert "expected BootSlot or one of 'A', 'B'" in result["message"]
|
||||
|
||||
resp = await api_client.post("/os/boot-slot", json={"boot_slot": "A"})
|
||||
assert resp.status == 400
|
||||
result = await resp.json()
|
||||
assert "no Home Assistant OS available" in result["message"]
|
||||
|
||||
|
||||
async def test_api_set_boot_slot_error(
|
||||
api_client: TestClient,
|
||||
all_dbus_services: dict[str, DBusServiceMock],
|
||||
coresys: CoreSys,
|
||||
capture_exception: Mock,
|
||||
os_available,
|
||||
):
|
||||
"""Test changing the boot slot via API."""
|
||||
rauc_service: RaucService = all_dbus_services["rauc"]
|
||||
rauc_service.response_mark = DBusError(ErrorType.FAILED, "fail")
|
||||
await coresys.os.load()
|
||||
|
||||
resp = await api_client.post("/os/boot-slot", json={"boot_slot": "A"})
|
||||
assert resp.status == 400
|
||||
result = await resp.json()
|
||||
assert result["message"] == "Can't mark A as active!"
|
||||
capture_exception.assert_called_once()
|
||||
|
||||
|
||||
async def test_api_board_yellow_info(api_client: TestClient, coresys: CoreSys):
|
||||
"""Test yellow board info."""
|
||||
resp = await api_client.get("/os/boards/yellow")
|
||||
|
||||
Reference in New Issue
Block a user