Skip to content

Commit 28a2e7a

Browse files
committed
Merge tag 'refs/tags/2025.05.1'
2 parents 8c98e22 + da0ae75 commit 28a2e7a

15 files changed

+96
-31
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ["setuptools~=80.3.1", "wheel~=0.46.1"]
2+
requires = ["setuptools~=80.4.0", "wheel~=0.46.1"]
33
build-backend = "setuptools.build_meta"
44

55
[project]

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
aiodns==3.3.0
1+
aiodns==3.4.0
22
aiohttp==3.11.18
33
atomicwrites-homeassistant==1.4.1
44
attrs==25.3.0
@@ -23,8 +23,8 @@ pyudev==0.24.3
2323
PyYAML==6.0.2
2424
requests==2.32.3
2525
securetar==2025.2.1
26-
sentry-sdk==2.27.0
27-
setuptools==80.3.1
26+
sentry-sdk==2.28.0
27+
setuptools==80.4.0
2828
voluptuous==0.15.2
2929
dbus-fast==2.44.1
3030
zlib-fast==0.2.1

requirements_tests.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
astroid==3.3.9
1+
astroid==3.3.10
22
coverage==7.8.0
33
pre-commit==4.2.0
44
pylint==3.3.7
@@ -7,6 +7,6 @@ pytest-asyncio==0.25.2
77
pytest-cov==6.1.1
88
pytest-timeout==2.4.0
99
pytest==8.3.5
10-
ruff==0.11.8
10+
ruff==0.11.9
1111
time-machine==2.16.0
1212
urllib3==2.4.0

supervisor/addons/addon.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,8 +1322,8 @@ def _addon_backup(
13221322
arcname="data",
13231323
)
13241324

1325-
# Backup config
1326-
if addon_config_used:
1325+
# Backup config (if used and existing, restore handles this gracefully)
1326+
if addon_config_used and self.path_config.is_dir():
13271327
atomic_contents_add(
13281328
backup,
13291329
self.path_config,

supervisor/coresys.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from typing import TYPE_CHECKING, Any, Self, TypeVar
1414

1515
import aiohttp
16+
from pycares import AresError
1617

1718
from .config import CoreConfig
1819
from .const import (
@@ -121,13 +122,17 @@ async def init_websession(self) -> None:
121122
if self._websession:
122123
await self._websession.close()
123124

124-
resolver = aiohttp.AsyncResolver()
125+
try:
126+
resolver = aiohttp.AsyncResolver(loop=self.loop)
127+
# pylint: disable=protected-access
128+
_LOGGER.debug(
129+
"Initializing ClientSession with AsyncResolver. Using nameservers %s",
130+
resolver._resolver.nameservers,
131+
)
132+
except AresError as err:
133+
_LOGGER.exception("Unable to initialize async DNS resolver: %s", err)
134+
resolver = aiohttp.ThreadedResolver(loop=self.loop)
125135

126-
# pylint: disable=protected-access
127-
_LOGGER.debug(
128-
"Initializing ClientSession with AsyncResolver. Using nameservers %s",
129-
resolver._resolver.nameservers,
130-
)
131136
connector = aiohttp.TCPConnector(loop=self.loop, resolver=resolver)
132137

133138
session = aiohttp.ClientSession(

tests/addons/test_addon.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,27 @@ async def test_backup(
446446
assert await install_addon_ssh.backup(tarfile) is None
447447

448448

449+
@pytest.mark.parametrize("status", ["running", "stopped"])
450+
async def test_backup_no_config(
451+
coresys: CoreSys,
452+
install_addon_ssh: Addon,
453+
container: MagicMock,
454+
status: str,
455+
tmp_supervisor_data,
456+
path_extern,
457+
) -> None:
458+
"""Test backing up an addon with deleted config directory."""
459+
container.status = status
460+
461+
install_addon_ssh.data["map"].append({"type": "addon_config", "read_only": False})
462+
assert not install_addon_ssh.path_config.exists()
463+
install_addon_ssh.path_data.mkdir()
464+
await install_addon_ssh.load()
465+
466+
tarfile = SecureTarFile(coresys.config.path_tmp / "test.tar.gz", "w")
467+
assert await install_addon_ssh.backup(tarfile) is None
468+
469+
449470
async def test_backup_with_pre_post_command(
450471
coresys: CoreSys,
451472
install_addon_ssh: Addon,
@@ -709,6 +730,7 @@ async def test_local_example_start(
709730
container: MagicMock,
710731
tmp_supervisor_data: Path,
711732
install_addon_example: Addon,
733+
path_extern,
712734
):
713735
"""Test start of an addon."""
714736
install_addon_example.path_data.mkdir()

tests/backups/test_manager.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ async def test_do_backup_partial_maximal(
217217
assert coresys.core.state == CoreState.RUNNING
218218

219219

220-
async def test_do_restore_full(coresys: CoreSys, full_backup_mock, install_addon_ssh):
220+
async def test_do_restore_full(
221+
coresys: CoreSys, supervisor_internet, full_backup_mock, install_addon_ssh
222+
):
221223
"""Test restoring full Backup."""
222224
await coresys.core.set_state(CoreState.RUNNING)
223225
coresys.hardware.disk.get_disk_free_space = lambda x: 5000
@@ -247,7 +249,7 @@ async def test_do_restore_full(coresys: CoreSys, full_backup_mock, install_addon
247249

248250

249251
async def test_do_restore_full_different_addon(
250-
coresys: CoreSys, full_backup_mock, install_addon_ssh
252+
coresys: CoreSys, supervisor_internet, full_backup_mock, install_addon_ssh
251253
):
252254
"""Test restoring full Backup with different addons than installed."""
253255
await coresys.core.set_state(CoreState.RUNNING)
@@ -279,7 +281,7 @@ async def test_do_restore_full_different_addon(
279281

280282

281283
async def test_do_restore_partial_minimal(
282-
coresys: CoreSys, partial_backup_mock, install_addon_ssh
284+
coresys: CoreSys, supervisor_internet, partial_backup_mock, install_addon_ssh
283285
):
284286
"""Test restoring partial Backup minimal."""
285287
await coresys.core.set_state(CoreState.RUNNING)
@@ -303,7 +305,9 @@ async def test_do_restore_partial_minimal(
303305
assert coresys.core.state == CoreState.RUNNING
304306

305307

306-
async def test_do_restore_partial_maximal(coresys: CoreSys, partial_backup_mock):
308+
async def test_do_restore_partial_maximal(
309+
coresys: CoreSys, supervisor_internet, partial_backup_mock
310+
):
307311
"""Test restoring partial Backup minimal."""
308312
await coresys.core.set_state(CoreState.RUNNING)
309313
coresys.hardware.disk.get_disk_free_space = lambda x: 5000
@@ -333,7 +337,10 @@ async def test_do_restore_partial_maximal(coresys: CoreSys, partial_backup_mock)
333337

334338

335339
async def test_fail_invalid_full_backup(
336-
coresys: CoreSys, full_backup_mock: MagicMock, partial_backup_mock: MagicMock
340+
coresys: CoreSys,
341+
supervisor_internet,
342+
full_backup_mock: MagicMock,
343+
partial_backup_mock: MagicMock,
337344
):
338345
"""Test restore fails with invalid backup."""
339346
await coresys.core.set_state(CoreState.RUNNING)
@@ -365,7 +372,7 @@ async def test_fail_invalid_full_backup(
365372

366373

367374
async def test_fail_invalid_partial_backup(
368-
coresys: CoreSys, partial_backup_mock: MagicMock
375+
coresys: CoreSys, supervisor_internet, partial_backup_mock: MagicMock
369376
):
370377
"""Test restore fails with invalid backup."""
371378
await coresys.core.set_state(CoreState.RUNNING)
@@ -415,7 +422,10 @@ async def test_backup_error(
415422

416423

417424
async def test_restore_error(
418-
coresys: CoreSys, full_backup_mock: MagicMock, capture_exception: Mock
425+
coresys: CoreSys,
426+
supervisor_internet,
427+
full_backup_mock: MagicMock,
428+
capture_exception: Mock,
419429
):
420430
"""Test restoring full Backup with errors."""
421431
await coresys.core.set_state(CoreState.RUNNING)
@@ -437,6 +447,7 @@ async def test_restore_error(
437447

438448
async def test_backup_media_with_mounts(
439449
coresys: CoreSys,
450+
supervisor_internet,
440451
all_dbus_services: dict[str, DBusServiceMock],
441452
tmp_supervisor_data,
442453
path_extern,
@@ -499,6 +510,7 @@ async def test_backup_media_with_mounts(
499510

500511
async def test_backup_media_with_mounts_retains_files(
501512
coresys: CoreSys,
513+
supervisor_internet,
502514
all_dbus_services: dict[str, DBusServiceMock],
503515
tmp_supervisor_data,
504516
path_extern,
@@ -553,6 +565,7 @@ async def test_backup_media_with_mounts_retains_files(
553565

554566
async def test_backup_share_with_mounts(
555567
coresys: CoreSys,
568+
supervisor_internet,
556569
all_dbus_services: dict[str, DBusServiceMock],
557570
tmp_supervisor_data,
558571
path_extern,
@@ -622,6 +635,7 @@ async def test_backup_share_with_mounts(
622635

623636
async def test_full_backup_to_mount(
624637
coresys: CoreSys,
638+
supervisor_internet,
625639
tmp_supervisor_data,
626640
path_extern,
627641
mount_propagation,
@@ -668,6 +682,7 @@ async def test_full_backup_to_mount(
668682

669683
async def test_partial_backup_to_mount(
670684
coresys: CoreSys,
685+
supervisor_internet,
671686
tmp_supervisor_data,
672687
path_extern,
673688
mount_propagation,
@@ -985,6 +1000,7 @@ async def container_events_task(*args, **kwargs):
9851000

9861001
async def test_restore_with_healthcheck(
9871002
coresys: CoreSys,
1003+
supervisor_internet,
9881004
install_addon_ssh: Addon,
9891005
container: MagicMock,
9901006
tmp_supervisor_data,
@@ -1185,6 +1201,7 @@ async def test_backup_progress(
11851201

11861202
async def test_restore_progress(
11871203
coresys: CoreSys,
1204+
supervisor_internet,
11881205
install_addon_ssh: Addon,
11891206
container: MagicMock,
11901207
ha_ws_client: AsyncMock,
@@ -1483,6 +1500,7 @@ async def test_cannot_manually_thaw_normal_freeze(coresys: CoreSys):
14831500

14841501
async def test_restore_only_reloads_ingress_on_change(
14851502
coresys: CoreSys,
1503+
supervisor_internet,
14861504
install_addon_ssh: Addon,
14871505
tmp_supervisor_data,
14881506
path_extern,
@@ -1543,6 +1561,7 @@ async def mock_is_running(*_) -> bool:
15431561

15441562
async def test_restore_new_addon(
15451563
coresys: CoreSys,
1564+
supervisor_internet,
15461565
install_addon_example: Addon,
15471566
container: MagicMock,
15481567
tmp_supervisor_data,
@@ -1574,6 +1593,7 @@ async def test_restore_new_addon(
15741593

15751594
async def test_restore_preserves_data_config(
15761595
coresys: CoreSys,
1596+
supervisor_internet,
15771597
install_addon_example: Addon,
15781598
container: MagicMock,
15791599
tmp_supervisor_data,
@@ -1819,7 +1839,11 @@ def mock_is_dir(path: Path) -> bool:
18191839

18201840

18211841
async def test_monitoring_after_full_restore(
1822-
coresys: CoreSys, full_backup_mock, install_addon_ssh, container
1842+
coresys: CoreSys,
1843+
supervisor_internet,
1844+
full_backup_mock,
1845+
install_addon_ssh,
1846+
container,
18231847
):
18241848
"""Test monitoring of addon state still works after full restore."""
18251849
await coresys.core.set_state(CoreState.RUNNING)
@@ -1840,7 +1864,11 @@ async def test_monitoring_after_full_restore(
18401864

18411865

18421866
async def test_monitoring_after_partial_restore(
1843-
coresys: CoreSys, partial_backup_mock, install_addon_ssh, container
1867+
coresys: CoreSys,
1868+
supervisor_internet,
1869+
partial_backup_mock,
1870+
install_addon_ssh,
1871+
container,
18441872
):
18451873
"""Test monitoring of addon state still works after full restore."""
18461874
await coresys.core.set_state(CoreState.RUNNING)
@@ -2040,7 +2068,9 @@ async def test_backup_remove_one_location_of_multiple(coresys: CoreSys):
20402068

20412069

20422070
@pytest.mark.usefixtures("tmp_supervisor_data")
2043-
async def test_addon_backup_excludes(coresys: CoreSys, install_addon_example: Addon):
2071+
async def test_addon_backup_excludes(
2072+
coresys: CoreSys, supervisor_internet, install_addon_example: Addon
2073+
):
20442074
"""Test backup excludes option for addons."""
20452075
await coresys.core.set_state(CoreState.RUNNING)
20462076
coresys.hardware.disk.get_disk_free_space = lambda x: 5000

tests/resolution/check/test_check_addon_pwned.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ async def test_check(coresys: CoreSys):
5858
assert coresys.resolution.suggestions[-1].reference == addon.slug
5959

6060

61-
async def test_approve(coresys: CoreSys):
61+
async def test_approve(coresys: CoreSys, supervisor_internet):
6262
"""Test check."""
6363
addon_pwned = CheckAddonPwned(coresys)
6464
await coresys.core.set_state(CoreState.RUNNING)

tests/resolution/check/test_check_dns_server_failure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ async def test_check(coresys: CoreSys, dns_query: AsyncMock, capture_exception:
6262
capture_exception.assert_called_once_with(err)
6363

6464

65-
async def test_approve(coresys: CoreSys, dns_query: AsyncMock):
65+
async def test_approve(coresys: CoreSys, supervisor_internet, dns_query: AsyncMock):
6666
"""Test approve existing DNS Server failure issues."""
6767
dns_server = CheckDNSServer(coresys)
6868
await coresys.core.set_state(CoreState.RUNNING)

tests/resolution/check/test_check_dns_server_ipv6_error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ async def test_check(coresys: CoreSys, dns_query: AsyncMock, capture_exception:
6868
capture_exception.assert_called_once_with(err)
6969

7070

71-
async def test_approve(coresys: CoreSys, dns_query: AsyncMock):
71+
async def test_approve(coresys: CoreSys, supervisor_internet, dns_query: AsyncMock):
7272
"""Test approve existing DNS Server IPv6 error issues."""
7373
dns_server_ipv6 = CheckDNSServerIPv6(coresys)
7474
await coresys.core.set_state(CoreState.RUNNING)

0 commit comments

Comments
 (0)