Files
tfaour 684225422c
Build and push server image / test (push) Successful in 37s
Build and push server image / build-and-push (push) Successful in 2m36s
Build and push server image / deploy (push) Successful in 57s
Distinguish "staged, not yet applied" from "up to date" in firmware check
update_available only compared the latest Gitea release against what's
staged, not what the frame is actually running -- so once a release
was staged (manually or via auto-update) but the frame hadn't woken up
and applied it yet, "Check now" reported "Up to date" even though the
device was still on the old version. Report the frame's actual running
version and use it to show a distinct "staged, applies on next wake"
message instead.
2026-07-27 22:55:40 +00:00

90 lines
3.4 KiB
Python

"""POST /api/frames/{id}/firmware/check -- the "Check now" button's
endpoint. update_available compares the latest Gitea release against
what's *staged* (firmware_available_version), not what the device is
actually running (device_firmware_version) -- those can differ once a
release has been staged/auto-applied but the frame hasn't woken up and
picked it up yet. running_version lets the UI tell "up to date" apart
from "staged, waiting for the frame to apply it" instead of collapsing
both into the same message."""
from __future__ import annotations
from app import gitea_releases
from app.models import Frame
from .conftest import csrf_headers
def _setup_frame(db_session, monkeypatch, latest_version, **overrides):
"""firmware_update_checked_at starts at 0, so the endpoint always
tries a real Gitea fetch on a fresh frame regardless of force= --
stub it out rather than hitting the network."""
monkeypatch.setattr(
gitea_releases, "fetch_latest_release", lambda *a, **k: {"version": latest_version, "assets": {}}
)
frame = db_session.get(Frame, 1)
frame.firmware_update_repo_url = "https://git.example.com/owner/repo"
frame.device_board_variant = "devkit"
for key, value in overrides.items():
setattr(frame, key, value)
db_session.commit()
return frame
def test_up_to_date_when_running_matches_latest(client, db_session, monkeypatch):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
_setup_frame(
db_session,
monkeypatch,
"1.4.1",
firmware_available_version="1.4.1",
device_firmware_version="1.4.1",
)
resp = client.post("/api/frames/1/firmware/check", headers=csrf_headers(client))
assert resp.status_code == 200
data = resp.json()
assert data["update_available"] is False
assert data["latest_version"] == "1.4.1"
assert data["running_version"] == "1.4.1"
def test_staged_but_not_yet_running_is_not_update_available(client, db_session, monkeypatch):
"""A release already staged (e.g. by a previous auto-update) but not
yet applied by the device isn't "an update is available" -- there's
nothing left to fetch/stage -- but it also isn't silently "up to
date" from the UI's perspective, since running_version still lags."""
client.post("/setup", data={"username": "alice", "password": "hunter22"})
_setup_frame(
db_session,
monkeypatch,
"1.4.1",
firmware_available_version="1.4.1",
device_firmware_version="1.3.0",
)
resp = client.post("/api/frames/1/firmware/check", headers=csrf_headers(client))
assert resp.status_code == 200
data = resp.json()
assert data["update_available"] is False
assert data["latest_version"] == "1.4.1"
assert data["staged_version"] == "1.4.1"
assert data["running_version"] == "1.3.0"
def test_update_available_reports_running_version(client, db_session, monkeypatch):
client.post("/setup", data={"username": "alice", "password": "hunter22"})
_setup_frame(
db_session,
monkeypatch,
"1.4.1",
firmware_available_version="1.3.0",
device_firmware_version="1.3.0",
)
resp = client.post("/api/frames/1/firmware/check", headers=csrf_headers(client))
assert resp.status_code == 200
data = resp.json()
assert data["update_available"] is True
assert data["running_version"] == "1.3.0"