fixup: tests, WIP

This commit is contained in:
Alexis Métaireau 2024-12-04 13:34:45 +01:00
parent dac41a87f8
commit 33d9d89e42
No known key found for this signature in database
GPG key ID: C65C7A89A8FFC56E
4 changed files with 165 additions and 31 deletions

View file

@ -235,14 +235,15 @@ class MainWindow(QtWidgets.QMainWindow):
# This allows us to make QSS rules conditional on the OS color mode.
self.setProperty("OSColorMode", self.dangerzone.app.os_color_mode.value)
self.show()
print("Checking Docker Desktop version")
if isinstance(self.dangerzone.isolation_provider, Container):
is_version_valid, version = (
self.dangerzone.isolation_provider.check_docker_desktop_version()
)
if not is_version_valid:
self.handle_docker_desktop_version_check(is_version_valid, version)
self.show()
def show_update_success(self) -> None:
"""Inform the user about a new Dangerzone release."""
version = self.dangerzone.settings.get("updater_latest_version")
@ -299,8 +300,8 @@ class MainWindow(QtWidgets.QMainWindow):
) -> None:
hamburger_menu = self.hamburger_button.menu()
sep = hamburger_menu.insertSeparator(hamburger_menu.actions()[0])
error_action = QAction("Docker Desktop should be upgraded", hamburger_menu)
error_action.setIcon(
upgrade_action = QAction("Docker Desktop should be upgraded", hamburger_menu)
upgrade_action.setIcon(
QtGui.QIcon(
load_svg_image(
"hamburger_menu_update_dot_error.svg", width=64, height=64
@ -308,23 +309,21 @@ class MainWindow(QtWidgets.QMainWindow):
)
)
def _show_alert() -> None:
message = """
<p>Your Docker Desktop version is too old. Please upgrade to a more recent version.</p>
<p>A new version of Docker Desktop is available. Please upgrade your system.</p>
<p>Visit the <a href="https://www.docker.com/products/docker-desktop">Docker Desktop website</a> to download the latest version.</p>
<em>Updating Docker Desktop allows you to have more confidence that you can process your documents safely.</em>
<em>Keeping Docker Desktop up to date allows you to have more confidence that your documents are processed safely.</em>
"""
widget = Alert(
self.alert = Alert(
self.dangerzone,
title="Your Docker Desktop version should be upgraded",
title="Upgrade Docker Desktop",
message=message,
ok_text="Ok",
has_cancel=False,
)
widget.launch()
error_action.triggered.connect(_show_alert)
hamburger_menu.insertAction(sep, error_action)
upgrade_action.triggered.connect(lambda: widget.launch())
hamburger_menu.insertAction(sep, upgrade_action)
self.hamburger_button.setIcon(
QtGui.QIcon(

View file

@ -12,9 +12,9 @@ from ..util import get_resource_path, get_subprocess_startupinfo
from .base import IsolationProvider, terminate_process_group
TIMEOUT_KILL = 5 # Timeout in seconds until the kill command returns.
MINIMUM_DOCKER_VERSION = {
"Darwin": "4.35.1",
"Windows": "4.35.1",
MINIMUM_DOCKER_DESKTOP = {
"Darwin": "4.36.0",
"Windows": "4.36.0",
}
# Define startupinfo for subprocesses
@ -203,6 +203,7 @@ class Container(IsolationProvider):
@staticmethod
def check_docker_desktop_version() -> Tuple[bool, str]:
# On windows and darwin, check that the minimum version is met
version = ""
if platform.system() != "Linux":
with subprocess.Popen(
["docker", "version", "--format", "{{.Server.Platform.Name}}"],
@ -212,12 +213,15 @@ class Container(IsolationProvider):
) as p:
stdout, stderr = p.communicate()
if p.returncode != 0:
raise NotAvailableContainerTechException("docker", stderr.decode())
# In the case where there were an error, consider that
# the check went trough, as we're checking for installation
# compatibiliy somewhere else already
return True, version
# The output is like "Docker Desktop 4.35.1 (173168)"
version = stdout.decode().replace("Docker Desktop", "").split()[0]
if version < MINIMUM_DOCKER_VERSION[platform.system()]:
if version < MINIMUM_DOCKER_DESKTOP[platform.system()]:
return False, version
return True, ""
return True, version
@staticmethod
def is_runtime_available() -> bool:

View file

@ -7,7 +7,6 @@ from typing import List
from pytest import MonkeyPatch, fixture
from pytest_mock import MockerFixture
from pytest_subprocess import FakeProcess
from pytestqt.qtbot import QtBot
from dangerzone.document import Document
@ -590,3 +589,48 @@ def test_installation_failure_return_false(qtbot: QtBot, mocker: MockerFixture)
assert "the following error occured" in widget.label.text()
assert "The image cannot be found" in widget.traceback.toPlainText()
def test_up_to_date_docker_desktop_does_nothing(
qtbot: QtBot, mocker: MockerFixture
) -> None:
# Setup install to return False
mock_app = mocker.MagicMock()
dummy = mocker.MagicMock(spec=Container)
dummy.check_docker_desktop_version.return_value = (True, "1.0.0")
dz = DangerzoneGui(mock_app, dummy)
window = MainWindow(dz)
qtbot.addWidget(window)
menu_actions = window.hamburger_button.menu().actions()
assert "Docker Desktop should be upgraded" not in [
a.toolTip() for a in menu_actions
]
def test_outdated_docker_desktop_displays_warning(
qtbot: QtBot, mocker: MockerFixture
) -> None:
# Setup install to return False
mock_app = mocker.MagicMock()
dummy = mocker.MagicMock(spec=Container)
dummy.check_docker_desktop_version.return_value = (False, "1.0.0")
dz = DangerzoneGui(mock_app, dummy)
load_svg_spy = mocker.spy(main_window_module, "load_svg_image")
window = MainWindow(dz)
qtbot.addWidget(window)
menu_actions = window.hamburger_button.menu().actions()
assert menu_actions[0].toolTip() == "Docker Desktop should be upgraded"
# Check that the hamburger icon has changed with the expected SVG image.
assert load_svg_spy.call_count == 4
assert (
load_svg_spy.call_args_list[2].args[0] == "hamburger_menu_update_dot_error.svg"
)
# Clicking the menu item should open a warning message
menu_actions[0].trigger()

View file

@ -13,6 +13,7 @@ from dangerzone.isolation_provider.container import (
from dangerzone.isolation_provider.qubes import is_qubes_native_conversion
from .base import IsolationProviderTermination, IsolationProviderTest
import platform
# Run the tests in this module only if we can spawn containers.
if is_qubes_native_conversion():
@ -116,6 +117,92 @@ class TestContainer(IsolationProviderTest):
with pytest.raises(ImageNotPresentException):
provider.install()
@pytest.mark.skipif(
platform.system() not in ("Windows", "Darwin"),
reason="macOS and Windows specific",
)
def test_old_docker_desktop_version_is_detected(
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
):
fp.register_subprocess(
[
"docker",
"version",
"--format",
"{{.Server.Platform.Name}}",
],
stdout="Docker Desktop 1.0.0 (173100)",
)
mocker.patch(
"dangerzone.isolation_provider.container.MINIMUM_DOCKER_DESKTOP",
{"Darwin": "1.0.1", "Windows": "1.0.1"},
)
assert (False, "1.0.0") == provider.check_docker_desktop_version()
@pytest.mark.skipif(
platform.system() not in ("Windows", "Darwin"),
reason="macOS and Windows specific",
)
def test_up_to_date_docker_desktop_version_is_detected(
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
):
fp.register_subprocess(
[
"docker",
"version",
"--format",
"{{.Server.Platform.Name}}",
],
stdout="Docker Desktop 1.0.1 (173100)",
)
# Require version 1.0.1
mocker.patch(
"dangerzone.isolation_provider.container.MINIMUM_DOCKER_DESKTOP",
{"Darwin": "1.0.1", "Windows": "1.0.1"},
)
assert (True, "1.0.1") == provider.check_docker_desktop_version()
fp.register_subprocess(
[
"docker",
"version",
"--format",
"{{.Server.Platform.Name}}",
],
stdout="Docker Desktop 2.0.0 (173100)",
)
assert (True, "2.0.0") == provider.check_docker_desktop_version()
@pytest.mark.skipif(
platform.system() not in ("Windows", "Darwin"),
reason="macOS and Windows specific",
)
def test_docker_desktop_version_failure_returns_true(
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
):
fp.register_subprocess(
[
"docker",
"version",
"--format",
"{{.Server.Platform.Name}}",
],
stderr="Oopsie",
returncode=1,
)
assert provider.check_docker_desktop_version() == (True, "")
@pytest.mark.skipif(
platform.system() != "Linux",
reason="Linux specific",
)
def test_linux_skips_desktop_version_check_returns_true(
self, mocker: MockerFixture, provider: Container
):
assert (True, "") == provider.check_docker_desktop_version()
class TestContainerTermination(IsolationProviderTermination):
pass