Skip to content

Commit 9900dfc

Browse files
authored
Do not skip messages in pull progress log due to rounding (#6129)
1 parent 3a1ebc9 commit 9900dfc

File tree

2 files changed

+131
-2
lines changed

2 files changed

+131
-2
lines changed

supervisor/jobs/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ class SupervisorJob:
9797
default=0,
9898
validator=[ge(0), le(100), _invalid_if_done],
9999
on_setattr=_on_change,
100-
converter=lambda val: round(val, 1),
101100
)
102101
stage: str | None = field(
103102
default=None, validator=[_invalid_if_done], on_setattr=_on_change
@@ -118,7 +117,7 @@ def as_dict(self) -> dict[str, Any]:
118117
"name": self.name,
119118
"reference": self.reference,
120119
"uuid": self.uuid,
121-
"progress": self.progress,
120+
"progress": round(self.progress, 1),
122121
"stage": self.stage,
123122
"done": self.done,
124123
"parent_id": self.parent_id,

tests/docker/test_interface.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,136 @@ def make_sub_log(layer_id: str):
600600
]
601601

602602

603+
async def test_install_progress_rounding_does_not_cause_misses(
604+
coresys: CoreSys, test_docker_interface: DockerInterface, ha_ws_client: AsyncMock
605+
):
606+
"""Test extremely close progress events do not create rounding issues."""
607+
coresys.core.set_state(CoreState.RUNNING)
608+
coresys.docker.docker.api.pull.return_value = [
609+
{
610+
"status": "Pulling from home-assistant/odroid-n2-homeassistant",
611+
"id": "2025.7.1",
612+
},
613+
{"status": "Pulling fs layer", "progressDetail": {}, "id": "1e214cd6d7d0"},
614+
{
615+
"status": "Downloading",
616+
"progressDetail": {"current": 432700000, "total": 436480882},
617+
"progress": "[=================================================> ] 432.7MB/436.5MB",
618+
"id": "1e214cd6d7d0",
619+
},
620+
{
621+
"status": "Downloading",
622+
"progressDetail": {"current": 432800000, "total": 436480882},
623+
"progress": "[=================================================> ] 432.8MB/436.5MB",
624+
"id": "1e214cd6d7d0",
625+
},
626+
{"status": "Verifying Checksum", "progressDetail": {}, "id": "1e214cd6d7d0"},
627+
{"status": "Download complete", "progressDetail": {}, "id": "1e214cd6d7d0"},
628+
{
629+
"status": "Extracting",
630+
"progressDetail": {"current": 432700000, "total": 436480882},
631+
"progress": "[=================================================> ] 432.7MB/436.5MB",
632+
"id": "1e214cd6d7d0",
633+
},
634+
{
635+
"status": "Extracting",
636+
"progressDetail": {"current": 432800000, "total": 436480882},
637+
"progress": "[=================================================> ] 432.8MB/436.5MB",
638+
"id": "1e214cd6d7d0",
639+
},
640+
{"status": "Pull complete", "progressDetail": {}, "id": "1e214cd6d7d0"},
641+
{
642+
"status": "Digest: sha256:7d97da645f232f82a768d0a537e452536719d56d484d419836e53dbe3e4ec736"
643+
},
644+
{
645+
"status": "Status: Downloaded newer image for ghcr.io/home-assistant/odroid-n2-homeassistant:2025.7.1"
646+
},
647+
]
648+
649+
with (
650+
patch.object(
651+
type(coresys.supervisor), "arch", PropertyMock(return_value="i386")
652+
),
653+
):
654+
# Schedule job so we can listen for the end. Then we can assert against the WS mock
655+
event = asyncio.Event()
656+
job, install_task = coresys.jobs.schedule_job(
657+
test_docker_interface.install,
658+
JobSchedulerOptions(),
659+
AwesomeVersion("1.2.3"),
660+
"test",
661+
)
662+
663+
async def listen_for_job_end(reference: SupervisorJob):
664+
if reference.uuid != job.uuid:
665+
return
666+
event.set()
667+
668+
coresys.bus.register_event(BusEvent.SUPERVISOR_JOB_END, listen_for_job_end)
669+
await install_task
670+
await event.wait()
671+
672+
events = [
673+
evt.args[0]["data"]["data"]
674+
for evt in ha_ws_client.async_send_command.call_args_list
675+
if "data" in evt.args[0]
676+
and evt.args[0]["data"]["event"] == WSEvent.JOB
677+
and evt.args[0]["data"]["data"]["reference"] == "1e214cd6d7d0"
678+
and evt.args[0]["data"]["data"]["stage"] in {"Downloading", "Extracting"}
679+
]
680+
681+
assert events == [
682+
{
683+
"name": "Pulling container image layer",
684+
"stage": "Downloading",
685+
"progress": 49.6,
686+
"done": False,
687+
"extra": {"current": 432700000, "total": 436480882},
688+
"reference": "1e214cd6d7d0",
689+
"parent_id": job.uuid,
690+
"errors": [],
691+
"uuid": ANY,
692+
"created": ANY,
693+
},
694+
{
695+
"name": "Pulling container image layer",
696+
"stage": "Downloading",
697+
"progress": 49.6,
698+
"done": False,
699+
"extra": {"current": 432800000, "total": 436480882},
700+
"reference": "1e214cd6d7d0",
701+
"parent_id": job.uuid,
702+
"errors": [],
703+
"uuid": ANY,
704+
"created": ANY,
705+
},
706+
{
707+
"name": "Pulling container image layer",
708+
"stage": "Extracting",
709+
"progress": 99.6,
710+
"done": False,
711+
"extra": {"current": 432700000, "total": 436480882},
712+
"reference": "1e214cd6d7d0",
713+
"parent_id": job.uuid,
714+
"errors": [],
715+
"uuid": ANY,
716+
"created": ANY,
717+
},
718+
{
719+
"name": "Pulling container image layer",
720+
"stage": "Extracting",
721+
"progress": 99.6,
722+
"done": False,
723+
"extra": {"current": 432800000, "total": 436480882},
724+
"reference": "1e214cd6d7d0",
725+
"parent_id": job.uuid,
726+
"errors": [],
727+
"uuid": ANY,
728+
"created": ANY,
729+
},
730+
]
731+
732+
603733
@pytest.mark.parametrize(
604734
("error_log", "exc_type", "exc_msg"),
605735
[

0 commit comments

Comments
 (0)