updater/test/test_core.py

165 lines
8.2 KiB
Python
Raw Normal View History

2022-02-18 18:17:59 +01:00
import sys
import os
import pytest
import requests_mock
from unittest import mock
from json.decoder import JSONDecodeError
from requests.exceptions import HTTPError
from updater import core
app_name: str = "a simple app"
current_version: str = "0.15"
endpoint: str = "https://gitlab.mcvsoftware.com"
# Fake a win32api module, as this fails on non-windows platforms without this hack.
# ToDo: Find a way to do this better.
win32api = mock.Mock(name="win32api")
win32api.__name__ = "win32api"
sys.modules["win32api"] = win32api
def test_requests_session():
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
updater.create_session()
assert hasattr(updater, "session")
assert app_name in updater.session.headers.get("User-Agent")
assert current_version in updater.session.headers.get("User-Agent")
def test_get_update_information_valid_json(file_data, json_data):
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
updater.create_session()
with requests_mock.Mocker(session=updater.session) as mocked:
mocked.get(endpoint, json=json_data)
contents = updater.get_update_information()
assert contents == json_data
def test_get_update_information_invalid_json(file_data, json_data):
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
updater.create_session()
with requests_mock.Mocker(session=updater.session) as mocked:
mocked.get(endpoint, text="thisisnotjson")
with pytest.raises(JSONDecodeError):
contents = updater.get_update_information()
def test_get_update_information_not_found():
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
updater.create_session()
with requests_mock.Mocker(session=updater.session) as mocked:
mocked.get(endpoint, status_code=404)
with pytest.raises(HTTPError):
contents = updater.get_update_information()
def test_version_data_no_update(json_data):
global app_name, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=json_data.get("current_version"))
updater.create_session()
results = updater.get_version_data(json_data)
assert results == (False, False, False)
@pytest.mark.parametrize("platform, architecture", [
("Windows", ("32bit", "")),
("Windows", ("64bit", "")),
])
def test_version_data_update_available(json_data, platform, architecture):
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
updater.create_session()
with mock.patch("platform.system", return_value=platform):
with mock.patch("platform.architecture", return_value=architecture):
results = updater.get_version_data(json_data)
k = platform+architecture[0][:2]
assert results == (json_data["current_version"], json_data["description"], json_data["downloads"][k])
def test_version_data_architecture_not_found(json_data):
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
updater.create_session()
with mock.patch("platform.system", return_value="nonos"):
with mock.patch("platform.architecture", return_value=("31bits", "")):
with pytest.raises(KeyError):
results = updater.get_version_data(json_data)
def test_download_update():
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
updater.create_session()
with mock.patch("pubsub.pub.sendMessage") as sendMessage_mock:
with mock.patch("io.open") as open_mock:
with requests_mock.Mocker(session=updater.session) as mocker:
updatefile = os.path.join(os.path.dirname(__file__), "helloworld_v2_win64.zip")
mocker.get("http://downloads.update.org/update.zip", body=open(updatefile, "rb"))
result = updater.download_update(update_url="http://downloads.update.org/update.zip", update_destination="update.zip")
open_mock.assert_called_once_with("update.zip", "w+b")
assert result == "update.zip"
assert sendMessage_mock.call_count > 0
def test_extract_archive():
# This only tests if archive extraction methods were called successfully and with the right parameters.
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
zipfile_opened = mock.MagicMock()
with mock.patch("zipfile.ZipFile", return_value=zipfile_opened) as zipfile_mock:
result = updater.extract_update("update.zip", os.path.dirname(__file__))
assert result == os.path.dirname(__file__)
zipfile_mock.called_once_with("update.zip")
zipfile_opened.extractall.assert_called_once()
# Test a password protected update file.
zipfile_opened_with_password = mock.MagicMock()
with mock.patch("zipfile.ZipFile", return_value=zipfile_opened_with_password) as zipfile_mock:
# Set a password manually.
updater.password = "MyLongPassword"
result2 = updater.extract_update("update.zip", os.path.dirname(__file__))
assert result2 == os.path.dirname(__file__)
zipfile_mock.called_once_with("update.zip")
zipfile_opened_with_password.setpassword.called_once_with("MyLongPassword")
zipfile_opened_with_password.extractall.assert_called_once()
@pytest.mark.parametrize("system", [("Windows"), ("Darwin"), ("Linux")])
def test_move_bootstrap(system):
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
# provide a fake extraction path.
extracted_path = os.path.dirname(__file__)
# supposedly, the bootstrap file should be moved to the parent path.
with mock.patch("platform.system", return_value=system):
with mock.patch("os.rename") as os_rename:
expected_path = os.path.abspath(os.path.join(extracted_path, "..", updater.bootstrap_name()))
result = updater.move_bootstrap(extracted_path)
assert result == expected_path
os_rename.assert_called_once()
@pytest.mark.parametrize("system", [("Windows"), ("Darwin"), ("Linux")])
def test_execute_bootstrap(system):
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
with mock.patch("platform.system", return_value=system):
with mock.patch("os.stat") as os_stat:
with mock.patch("subprocess.Popen") as subprocess_popen:
with mock.patch("os.chmod") as os_chmod:
with mock.patch("win32api.ShellExecute") as win32api_ShellExecute:
bootstrap_path = os.path.join(os.path.dirname(__file__), updater.bootstrap_name())
source_path = os.path.dirname(__file__)
updater.execute_bootstrap(bootstrap_path, source_path)
if system == "Windows":
win32api_ShellExecute.assert_called_once()
else:
os_chmod.assert_called_once()
os_stat.assert_called_once()
subprocess_popen.assert_called_once()
@pytest.mark.parametrize("system, bootstrap_file", [
("Windows", "bootstrap.exe"),
("Darwin", "bootstrap-mac.sh"),
("Linux", "bootstrap-lin.sh")
])
def test_bootstrap_name(system, bootstrap_file):
global app_name, current_version, endpoint
updater = core.updaterCore(endpoint=endpoint, app_name=app_name, current_version=current_version)
with mock.patch("platform.system", return_value=system):
result = updater.bootstrap_name()
assert result == bootstrap_file