Files
KX-Bridge-Release/tests/test_update_check.py
viewit 0c520ffa00 feat(update): treat the testing channel as docker-only in the update check
A testing-<sha> build has no Gitea releases (the testing workflow builds only
a Docker image), so the in-app update check must not fall through to the
stable path - which would wrongly offer a stable "update". handle_api_update_check
now short-circuits for a "testing" version with docker_only:true and nothing
to update (no Gitea round-trip at all), and handle_api_update_apply refuses
self-update on the testing channel the same way it already does for nightly.

Two new tests cover both. (Mirrors the same fix already on the testing
branch, applied here to the pre-refactor monolithic module.)
2026-08-05 09:35:26 +02:00

101 lines
3.7 KiB
Python

"""Update-check regression for Issue #104.
STABLE_RELEASE_API used limit=1, so it only ever saw the single newest
release on Gitea regardless of type. Since nightly/dev prereleases publish
far more often than stable releases, that newest release is almost always a
prerelease - the stable_releases filter (not prerelease) then found nothing
and /api/update/check returned "no stable releases found" even though older
stable releases exist.
"""
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
@pytest.mark.asyncio
async def test_update_apply_invalid_json_returns_400(client):
"""A malformed/non-JSON body must be a clean 400, not an unhandled 500
with a raw JSONDecodeError traceback (code review finding)."""
c, _ = client
resp = await c.post("/api/update/apply", data=b"not json", headers={"Content-Type": "application/json"})
assert resp.status == 400
@pytest.mark.asyncio
async def test_update_check_testing_channel_is_docker_only(client):
"""A testing-<sha> build has no Gitea releases at all - the check must
report a docker-only channel with nothing to update, NOT fall through to
the stable path and wrongly offer a stable "update". Must not even call
the Gitea API."""
c, bridge = client
bridge._read_version = lambda: "testing-2e4dbf0"
with patch("aiohttp.ClientSession.get") as mock_get:
resp = await c.get("/api/update/check")
data = await resp.json()
assert resp.status == 200
assert data["update_available"] is False
assert data["docker_only"] is True
assert data["current"] == "testing-2e4dbf0"
mock_get.assert_not_called() # no Gitea round-trip for the testing channel
@pytest.mark.asyncio
async def test_update_apply_testing_channel_blocked(client):
"""Self-update must be refused on the testing channel, same as nightly -
testing images are delivered via Docker only."""
c, bridge = client
bridge._read_version = lambda: "testing-2e4dbf0"
resp = await c.post("/api/update/apply", json={"tag": "whatever"})
data = await resp.json()
assert resp.status == 400
assert "testing" in data["error"]
assert "docker" in data["error"].lower()
def _fake_releases_response(payload):
resp = MagicMock()
resp.status = 200
resp.json = AsyncMock(return_value=payload)
ctx = MagicMock()
ctx.__aenter__ = AsyncMock(return_value=resp)
ctx.__aexit__ = AsyncMock(return_value=False)
return ctx
@pytest.mark.asyncio
async def test_stable_update_check_finds_release_behind_newer_prereleases(client):
c, bridge = client
bridge._read_version = lambda: "0.9.27"
releases = (
[{"tag_name": f"nightly-0.9.30-nightly{i}", "prerelease": True} for i in range(1, 7)]
+ [{"tag_name": "v0.9.29", "prerelease": False, "body": "changelog"}]
)
with patch("aiohttp.ClientSession.get", return_value=_fake_releases_response(releases)):
resp = await c.get("/api/update/check")
data = await resp.json()
assert resp.status == 200
assert data["latest"] == "0.9.29"
assert data["update_available"] is True
@pytest.mark.asyncio
async def test_stable_update_check_requests_enough_releases_to_skip_prereleases(client):
"""The API URL itself must ask for more than the single newest release -
a limit=1 request can never find a stable release behind a run of
prereleases no matter how the response is parsed."""
c, bridge = client
bridge._read_version = lambda: "0.9.27"
import re
assert not re.search(r"limit=1(?!\d)", bridge.STABLE_RELEASE_API), (
"STABLE_RELEASE_API must request more than 1 release, otherwise a "
"recent nightly/dev prerelease being the newest release hides all "
"stable releases behind it (Issue #104)"
)