feat: support http update checks

This commit is contained in:
2026-06-18 09:38:44 +08:00
parent 6bc27f5180
commit 813e569639
3 changed files with 155 additions and 14 deletions
+85
View File
@@ -1,10 +1,13 @@
"""Tests for services.update_service — no GUI dependency."""
import json
import base64
import shutil
import sys
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
from urllib import error
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
@@ -100,6 +103,88 @@ class TestCheckForUpdate(unittest.TestCase):
info = check_for_update(str(self.tmp), "1.0.0")
self.assertEqual(info.source, str(self.tmp))
def test_http_source_appends_manifest_name(self):
calls = {}
def fake_urlopen(req, timeout=0):
calls["url"] = req.full_url
return _FakeResponse({
"version": "1.2.0",
"url": "https://example.test/CMBot-1.2.0.zip",
"notes": "http update",
})
with patch("services.update_service.request.urlopen", fake_urlopen):
info = check_for_update("https://example.test/releases", "1.0.0")
self.assertIsInstance(info, UpdateInfo)
self.assertEqual(calls["url"], "https://example.test/releases/manifest.json")
self.assertEqual(info.source, "https://example.test/CMBot-1.2.0.zip")
def test_http_source_accepts_full_manifest_url(self):
calls = {}
def fake_urlopen(req, timeout=0):
calls["url"] = req.full_url
return _FakeResponse({"version": "1.2.0"})
manifest_url = "https://example.test/releases/manifest.json"
with patch("services.update_service.request.urlopen", fake_urlopen):
info = check_for_update(manifest_url, "1.0.0")
self.assertIsInstance(info, UpdateInfo)
self.assertEqual(calls["url"], manifest_url)
self.assertEqual(info.source, manifest_url)
def test_http_basic_auth_header(self):
calls = {}
def fake_urlopen(req, timeout=0):
calls["auth"] = req.get_header("Authorization")
return _FakeResponse({"version": "2.0.0"})
with patch("services.update_service.request.urlopen", fake_urlopen):
check_for_update(
"https://example.test",
"1.0.0",
update_user="readonly",
update_pass="secret",
)
token = base64.b64encode(b"readonly:secret").decode("ascii")
self.assertEqual(calls["auth"], "Basic {}".format(token))
def test_http_error_returns_none(self):
def fake_urlopen(req, timeout=0):
raise error.URLError("offline")
with patch("services.update_service.request.urlopen", fake_urlopen):
self.assertIsNone(check_for_update("https://example.test", "1.0.0"))
def test_http_malformed_json_returns_none(self):
def fake_urlopen(req, timeout=0):
return _FakeResponse("{ not valid json", raw=True)
with patch("services.update_service.request.urlopen", fake_urlopen):
self.assertIsNone(check_for_update("https://example.test", "1.0.0"))
class _FakeResponse:
def __init__(self, data, raw=False):
if raw:
self._payload = data.encode("utf-8")
else:
self._payload = json.dumps(data).encode("utf-8")
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
def read(self):
return self._payload
if __name__ == "__main__":
unittest.main()