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. # This allows us to make QSS rules conditional on the OS color mode.
self.setProperty("OSColorMode", self.dangerzone.app.os_color_mode.value) self.setProperty("OSColorMode", self.dangerzone.app.os_color_mode.value)
self.show() if isinstance(self.dangerzone.isolation_provider, Container):
print("Checking Docker Desktop version")
is_version_valid, version = ( is_version_valid, version = (
self.dangerzone.isolation_provider.check_docker_desktop_version() self.dangerzone.isolation_provider.check_docker_desktop_version()
) )
if not is_version_valid: if not is_version_valid:
self.handle_docker_desktop_version_check(is_version_valid, version) self.handle_docker_desktop_version_check(is_version_valid, version)
self.show()
def show_update_success(self) -> None: def show_update_success(self) -> None:
"""Inform the user about a new Dangerzone release.""" """Inform the user about a new Dangerzone release."""
version = self.dangerzone.settings.get("updater_latest_version") version = self.dangerzone.settings.get("updater_latest_version")
@ -299,8 +300,8 @@ class MainWindow(QtWidgets.QMainWindow):
) -> None: ) -> None:
hamburger_menu = self.hamburger_button.menu() hamburger_menu = self.hamburger_button.menu()
sep = hamburger_menu.insertSeparator(hamburger_menu.actions()[0]) sep = hamburger_menu.insertSeparator(hamburger_menu.actions()[0])
error_action = QAction("Docker Desktop should be upgraded", hamburger_menu) upgrade_action = QAction("Docker Desktop should be upgraded", hamburger_menu)
error_action.setIcon( upgrade_action.setIcon(
QtGui.QIcon( QtGui.QIcon(
load_svg_image( load_svg_image(
"hamburger_menu_update_dot_error.svg", width=64, height=64 "hamburger_menu_update_dot_error.svg", width=64, height=64
@ -308,23 +309,21 @@ class MainWindow(QtWidgets.QMainWindow):
) )
) )
def _show_alert() -> None:
message = """ 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> <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, self.dangerzone,
title="Your Docker Desktop version should be upgraded", title="Upgrade Docker Desktop",
message=message, message=message,
ok_text="Ok", ok_text="Ok",
has_cancel=False, has_cancel=False,
) )
widget.launch()
error_action.triggered.connect(_show_alert) upgrade_action.triggered.connect(lambda: widget.launch())
hamburger_menu.insertAction(sep, error_action) hamburger_menu.insertAction(sep, upgrade_action)
self.hamburger_button.setIcon( self.hamburger_button.setIcon(
QtGui.QIcon( QtGui.QIcon(

View file

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

View file

@ -7,7 +7,6 @@ from typing import List
from pytest import MonkeyPatch, fixture from pytest import MonkeyPatch, fixture
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from pytest_subprocess import FakeProcess
from pytestqt.qtbot import QtBot from pytestqt.qtbot import QtBot
from dangerzone.document import Document 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 following error occured" in widget.label.text()
assert "The image cannot be found" in widget.traceback.toPlainText() 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 dangerzone.isolation_provider.qubes import is_qubes_native_conversion
from .base import IsolationProviderTermination, IsolationProviderTest from .base import IsolationProviderTermination, IsolationProviderTest
import platform
# Run the tests in this module only if we can spawn containers. # Run the tests in this module only if we can spawn containers.
if is_qubes_native_conversion(): if is_qubes_native_conversion():
@ -116,6 +117,92 @@ class TestContainer(IsolationProviderTest):
with pytest.raises(ImageNotPresentException): with pytest.raises(ImageNotPresentException):
provider.install() 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): class TestContainerTermination(IsolationProviderTermination):
pass pass