forked from viewit/KX-Bridge-Release
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.)
101 lines
3.7 KiB
Python
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)"
|
|
)
|