mirror of https://github.com/borgbase/vorta
Unit test improvements and coverage increase. By @bigtedde (#1787)
This commit is contained in:
parent
c807f93faf
commit
60f9fc27b4
|
@ -325,7 +325,7 @@ class VortaApp(QtSingleApplication):
|
|||
# No fail
|
||||
logger.warning('VortaApp.check_failed_response was called with returncode 0')
|
||||
elif returncode == 130:
|
||||
# Keyboard interupt
|
||||
# Keyboard interrupt
|
||||
pass
|
||||
else: # Real error
|
||||
# Create QMessageBox
|
||||
|
|
|
@ -1489,11 +1489,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<location filename="../../views/import_window.py" line="69"/>
|
||||
<source>Schema upgrade failure, file a bug report with the link in the Misc tab with the following error:
|
||||
{0}
|
||||
<source>Schema upgrade failure, file a bug report with the link in the Misc tab with the following error:
|
||||
{0}
|
||||
{1}</source>
|
||||
<translation>Schema-Upgrade Fehler, erstelle einen Bugreport auf dem Link um "Misc"-Tab, mit folgendem Fehler:
|
||||
{0}
|
||||
<translation>Schema-Upgrade Fehler, erstelle einen Bugreport auf dem Link um "Misc"-Tab, mit folgendem Fehler:
|
||||
{0}
|
||||
{1}</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
@ -2267,4 +2267,4 @@
|
|||
<translation>Speichere Kennwort in der Vortakonfiguration</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -1491,8 +1491,8 @@
|
|||
</message>
|
||||
<message>
|
||||
<location filename="../../views/import_window.py" line="69"/>
|
||||
<source>Schema upgrade failure, file a bug report with the link in the Misc tab with the following error:
|
||||
{0}
|
||||
<source>Schema upgrade failure, file a bug report with the link in the Misc tab with the following error:
|
||||
{0}
|
||||
{1}</source>
|
||||
<translation>Fallo al actualizar el esquema, rellene un informe de error con el enlace de la pestaña «Varios» con el siguiente error:
|
||||
{0}
|
||||
|
@ -2269,4 +2269,4 @@
|
|||
<translation>Guardar contraseñas con los ajustes de Vorta.</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -1491,11 +1491,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<location filename="../../views/import_window.py" line="69"/>
|
||||
<source>Schema upgrade failure, file a bug report with the link in the Misc tab with the following error:
|
||||
{0}
|
||||
<source>Schema upgrade failure, file a bug report with the link in the Misc tab with the following error:
|
||||
{0}
|
||||
{1}</source>
|
||||
<translation>Skeeman päivitys epäonnistui, lähetä virheraportti Sekalaiset-välilehdellä olevasta linkistä. Liitä raporttiin seuraavat tiedot:
|
||||
{0}
|
||||
<translation>Skeeman päivitys epäonnistui, lähetä virheraportti Sekalaiset-välilehdellä olevasta linkistä. Liitä raporttiin seuraavat tiedot:
|
||||
{0}
|
||||
{1}</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
@ -2269,4 +2269,4 @@
|
|||
<translation>Tallennetaan salasana Vortan asetuksiin.</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -6,6 +6,7 @@ import vorta.borg
|
|||
import vorta.utils
|
||||
import vorta.views.archive_tab
|
||||
from PyQt6 import QtCore
|
||||
from PyQt6.QtWidgets import QMenu
|
||||
from vorta.store.models import ArchiveModel, BackupProfileModel
|
||||
|
||||
|
||||
|
@ -202,3 +203,18 @@ def test_inline_archive_rename(qapp, qtbot, mocker, borg_json_output, archive_en
|
|||
# Successful rename case
|
||||
qtbot.waitUntil(lambda: tab.archiveTable.model().index(0, 4).data() == new_archive_name, **pytest._wait_defaults)
|
||||
assert tab.archiveTable.model().index(0, 4).data() == new_archive_name
|
||||
|
||||
|
||||
def test_archiveitem_contextmenu(qapp, qtbot, archive_env):
|
||||
main, tab = archive_env
|
||||
|
||||
pos = tab.archiveTable.visualRect(tab.archiveTable.model().index(0, 0)).center()
|
||||
tab.archiveTable.customContextMenuRequested.emit(pos)
|
||||
qtbot.waitUntil(lambda: tab.archiveTable.findChild(QMenu) is not None, timeout=2000)
|
||||
|
||||
context_menu = tab.archiveTable.findChild(QMenu)
|
||||
|
||||
assert context_menu is not None
|
||||
expected_actions = ['Copy', 'Recalculate', 'Mount…', 'Extract…', 'Rename…', 'Delete', 'Diff']
|
||||
for action in expected_actions:
|
||||
assert any(menu_actions.text() == action for menu_actions in context_menu.actions())
|
||||
|
|
|
@ -5,6 +5,7 @@ import vorta.borg
|
|||
import vorta.utils
|
||||
import vorta.views.archive_tab
|
||||
from PyQt6.QtCore import QDateTime, QItemSelectionModel, Qt
|
||||
from PyQt6.QtWidgets import QMenu
|
||||
from vorta.views.diff_result import (
|
||||
ChangeType,
|
||||
DiffData,
|
||||
|
@ -15,12 +16,8 @@ from vorta.views.diff_result import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'json_mock_file,folder_root', [('diff_archives', 'test'), ('diff_archives_dict_issue', 'Users')]
|
||||
)
|
||||
def test_archive_diff(qapp, qtbot, mocker, borg_json_output, json_mock_file, folder_root, archive_env):
|
||||
main, tab = archive_env
|
||||
|
||||
def setup_diff_result_window(qtbot, mocker, tab, borg_json_output, json_mock_file="diff_archives"):
|
||||
"""Sets up the diff result window."""
|
||||
stdout, stderr = borg_json_output(json_mock_file)
|
||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||
|
@ -46,14 +43,70 @@ def test_archive_diff(qapp, qtbot, mocker, borg_json_output, json_mock_file, fol
|
|||
tab.diff_action()
|
||||
|
||||
qtbot.waitUntil(lambda: hasattr(tab, '_resultwindow'), **pytest._wait_defaults)
|
||||
assert hasattr(tab, '_resultwindow')
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'json_mock_file, folder_root', [('diff_archives', 'test'), ('diff_archives_dict_issue', 'Users')]
|
||||
)
|
||||
def test_archive_diff(qapp, qtbot, mocker, borg_json_output, json_mock_file, folder_root, archive_env):
|
||||
"""Tests basic functionality of archive diff."""
|
||||
main, tab = archive_env
|
||||
setup_diff_result_window(qtbot, mocker, tab, borg_json_output, json_mock_file)
|
||||
|
||||
model = tab._resultwindow.treeView.model().sourceModel()
|
||||
assert model.root.children[0].subpath == folder_root
|
||||
|
||||
assert tab._resultwindow.archiveNameLabel_1.text() == 'test-archive'
|
||||
tab._resultwindow.accept()
|
||||
|
||||
|
||||
def test_diff_item_copy(qapp, qtbot, mocker, borg_json_output, archive_env):
|
||||
"""Tests copy action by row selection and when passed an index."""
|
||||
main, tab = archive_env
|
||||
setup_diff_result_window(qtbot, mocker, tab, borg_json_output)
|
||||
|
||||
# mock the clipboard to ensure no changes are made to it during testing
|
||||
mocker.patch.object(qapp.clipboard(), "setMimeData")
|
||||
clipboard_spy = mocker.spy(qapp.clipboard(), "setMimeData")
|
||||
|
||||
# test 'diff_item_copy()' by passing it an item to copy
|
||||
index = tab._resultwindow.treeView.model().index(0, 0)
|
||||
assert index is not None
|
||||
tab._resultwindow.diff_item_copy(index)
|
||||
clipboard_data = clipboard_spy.call_args[0][0]
|
||||
assert clipboard_data.hasText()
|
||||
assert clipboard_data.text() == "/test"
|
||||
|
||||
clipboard_spy.reset_mock()
|
||||
|
||||
# test 'diff_item_copy()' by selecting a row to copy
|
||||
flags = QItemSelectionModel.SelectionFlag.Rows
|
||||
flags |= QItemSelectionModel.SelectionFlag.Select
|
||||
tab._resultwindow.treeView.selectionModel().select(tab._resultwindow.treeView.model().index(0, 0), flags)
|
||||
tab._resultwindow.diff_item_copy()
|
||||
clipboard_data = clipboard_spy.call_args[0][0]
|
||||
assert clipboard_data.hasText()
|
||||
assert clipboard_data.text() == "/test"
|
||||
|
||||
|
||||
def test_treeview_context_menu(qapp, qtbot, mocker, borg_json_output, archive_env):
|
||||
"""Tests the diff result window context menu for expected actions."""
|
||||
main, tab = archive_env
|
||||
setup_diff_result_window(qtbot, mocker, tab, borg_json_output)
|
||||
|
||||
# Load the context menu at the first result in window
|
||||
pos = tab._resultwindow.treeView.visualRect(tab._resultwindow.treeView.model().index(0, 0)).center()
|
||||
tab._resultwindow.treeview_context_menu(pos)
|
||||
qtbot.waitUntil(lambda: tab._resultwindow.findChild(QMenu) is not None, **pytest._wait_defaults)
|
||||
context_menu = tab._resultwindow.findChild(QMenu)
|
||||
assert context_menu is not None
|
||||
|
||||
# assert the actions are available in the context menu
|
||||
expected_actions = ['Copy', 'Expand recursively']
|
||||
for action in expected_actions:
|
||||
assert any(menu_actions.text() == action for menu_actions in context_menu.actions())
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'line, expected',
|
||||
[
|
||||
|
@ -404,59 +457,3 @@ def test_archive_diff_json_parser(line, expected):
|
|||
|
||||
assert item.path == PurePath(expected[0]).parts
|
||||
assert item.data == DiffData(*expected[1:])
|
||||
|
||||
|
||||
def test_diff_item_copy(qapp, qtbot, mocker, borg_json_output):
|
||||
main = qapp.main_window
|
||||
tab = main.archiveTab
|
||||
main.tabWidget.setCurrentIndex(3)
|
||||
|
||||
tab.populate_from_profile()
|
||||
qtbot.waitUntil(lambda: tab.archiveTable.rowCount() == 2)
|
||||
|
||||
stdout, stderr = borg_json_output("diff_archives")
|
||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||
|
||||
compat = vorta.utils.borg_compat
|
||||
|
||||
def check(feature_name):
|
||||
if feature_name == 'DIFF_JSON_LINES':
|
||||
return False
|
||||
return vorta.utils.BorgCompatibility.check(compat, feature_name)
|
||||
|
||||
mocker.patch.object(vorta.utils.borg_compat, 'check', check)
|
||||
|
||||
selection_model: QItemSelectionModel = tab.archiveTable.selectionModel()
|
||||
model = tab.archiveTable.model()
|
||||
|
||||
flags = QItemSelectionModel.SelectionFlag.Rows
|
||||
flags |= QItemSelectionModel.SelectionFlag.Select
|
||||
|
||||
selection_model.select(model.index(0, 0), flags)
|
||||
selection_model.select(model.index(1, 0), flags)
|
||||
|
||||
tab.diff_action()
|
||||
|
||||
qtbot.waitUntil(lambda: hasattr(tab, '_resultwindow'), **pytest._wait_defaults)
|
||||
|
||||
# mock the clipboard to ensure no changes are made to it during testing
|
||||
mocker.patch.object(qapp.clipboard(), "setMimeData")
|
||||
clipboard_spy = mocker.spy(qapp.clipboard(), "setMimeData")
|
||||
|
||||
# test 'diff_item_copy()' by passing it an item to copy
|
||||
index = tab._resultwindow.treeView.model().index(0, 0)
|
||||
assert index is not None
|
||||
tab._resultwindow.diff_item_copy(index)
|
||||
clipboard_data = clipboard_spy.call_args[0][0]
|
||||
assert clipboard_data.hasText()
|
||||
assert clipboard_data.text() == "/test"
|
||||
|
||||
clipboard_spy.reset_mock()
|
||||
|
||||
# test 'diff_item_copy()' by selecting a row to copy
|
||||
tab._resultwindow.treeView.selectionModel().select(tab._resultwindow.treeView.model().index(0, 0), flags)
|
||||
tab._resultwindow.diff_item_copy()
|
||||
clipboard_data = clipboard_spy.call_args[0][0]
|
||||
assert clipboard_data.hasText()
|
||||
assert clipboard_data.text() == "/test"
|
||||
|
|
|
@ -6,33 +6,74 @@ from unittest.mock import Mock
|
|||
import pytest
|
||||
import vorta.store.models
|
||||
from PyQt6 import QtCore
|
||||
from PyQt6.QtWidgets import QCheckBox, QFormLayout
|
||||
from PyQt6.QtGui import QCloseEvent
|
||||
from PyQt6.QtWidgets import QCheckBox, QFormLayout, QMessageBox
|
||||
from vorta.store.models import SettingsModel
|
||||
|
||||
|
||||
def test_autostart(qapp, qtbot):
|
||||
"""Check if file exists only on Linux, otherwise just check it doesn't crash"""
|
||||
def test_toggle_all_settings(qapp, qtbot):
|
||||
"""Toggle each setting twice as a basic sanity test to ensure app does crash."""
|
||||
groups = (
|
||||
SettingsModel.select(SettingsModel.group)
|
||||
.distinct(True)
|
||||
.where(SettingsModel.group != '')
|
||||
.order_by(SettingsModel.group.asc())
|
||||
)
|
||||
|
||||
settings = [
|
||||
setting
|
||||
for group in groups
|
||||
for setting in SettingsModel.select().where(
|
||||
SettingsModel.type == 'checkbox', SettingsModel.group == group.group
|
||||
)
|
||||
]
|
||||
|
||||
for setting in settings:
|
||||
for _ in range(2):
|
||||
_click_toggle_setting(setting.label, qapp, qtbot)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "linux", reason="testing autostart path for Linux only")
|
||||
def test_autostart_linux(qapp, qtbot):
|
||||
"""Checks that autostart path is added correctly on Linux when setting is enabled."""
|
||||
setting = "Automatically start Vorta at login"
|
||||
|
||||
# ensure file is present when autostart is enabled
|
||||
_click_toggle_setting(setting, qapp, qtbot)
|
||||
autostart_path = (
|
||||
Path(os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~") + '/.config') + "/autostart") / "vorta.desktop"
|
||||
)
|
||||
qtbot.waitUntil(lambda: autostart_path.exists(), **pytest._wait_defaults)
|
||||
with open(autostart_path) as desktop_file:
|
||||
desktop_file_text = desktop_file.read()
|
||||
assert desktop_file_text.startswith("[Desktop Entry]")
|
||||
|
||||
if sys.platform == 'linux':
|
||||
autostart_path = (
|
||||
Path(os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~") + '/.config') + "/autostart")
|
||||
/ "vorta.desktop"
|
||||
)
|
||||
qtbot.waitUntil(lambda: autostart_path.exists(), **pytest._wait_defaults)
|
||||
|
||||
with open(autostart_path) as desktop_file:
|
||||
desktop_file_text = desktop_file.read()
|
||||
|
||||
assert desktop_file_text.startswith("[Desktop Entry]")
|
||||
|
||||
# ensure file is removed when autostart is disabled
|
||||
_click_toggle_setting(setting, qapp, qtbot)
|
||||
|
||||
if sys.platform == 'linux':
|
||||
assert not os.path.exists(autostart_path)
|
||||
|
||||
|
||||
def test_enable_background_question(qapp, monkeypatch, mocker):
|
||||
"""Tests that 'enable background question' correctly prompts user."""
|
||||
main = qapp.main_window
|
||||
close_event = Mock(value=QCloseEvent())
|
||||
|
||||
# disable system trey and enable setting to test
|
||||
monkeypatch.setattr("vorta.views.main_window.is_system_tray_available", lambda: False)
|
||||
mocker.patch.object(vorta.store.models.SettingsModel, "get", return_value=Mock(value=True))
|
||||
mocker.patch.object(QMessageBox, "exec") # prevent QMessageBox from stopping test
|
||||
|
||||
# Create a mock for QMessageBox and its setText method
|
||||
mock_msgbox = mocker.Mock(spec=QMessageBox)
|
||||
mocker.patch("vorta.views.main_window.QMessageBox", return_value=mock_msgbox)
|
||||
|
||||
main.closeEvent(close_event)
|
||||
|
||||
mock_msgbox.setText.assert_called_once_with("Should Vorta continue to run in the background?")
|
||||
close_event.accept.assert_called_once()
|
||||
|
||||
|
||||
def test_enable_fixed_units(qapp, qtbot, mocker):
|
||||
"""Tests the 'enable fixed units' setting to ensure the archive tab sizes are displayed correctly."""
|
||||
tab = qapp.main_window.archiveTab
|
||||
|
@ -61,14 +102,13 @@ def test_enable_fixed_units(qapp, qtbot, mocker):
|
|||
assert kwargs_list['fixed_unit'] is None
|
||||
|
||||
# use the qt bot to click the setting and see that the refresh_archive emit works as intended.
|
||||
with qtbot.waitSignal(qapp.main_window.miscTab.refresh_archive, timeout=5000):
|
||||
with qtbot.waitSignal(qapp.main_window.miscTab.refresh_archive, **pytest._wait_defaults):
|
||||
_click_toggle_setting(setting, qapp, qtbot)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != 'darwin', reason="Full Disk Access check only on Darwin")
|
||||
def test_check_full_disk_access(qapp, qtbot, mocker):
|
||||
"""Enables/disables 'Check for Full Disk Access on startup' setting and ensures functionality"""
|
||||
setting = "Check for Full Disk Access on startup"
|
||||
"""Tests if the full disk access warning is properly silenced with the setting enabled"""
|
||||
|
||||
# Set mocks for setting enabled
|
||||
mocker.patch.object(vorta.store.models.SettingsModel, "get", return_value=Mock(value=True))
|
||||
|
@ -88,10 +128,6 @@ def test_check_full_disk_access(qapp, qtbot, mocker):
|
|||
qapp.check_darwin_permissions()
|
||||
mock_qmessagebox.assert_not_called()
|
||||
|
||||
# Checks that setting doesn't crash program when click toggled on then off"""
|
||||
_click_toggle_setting(setting, qapp, qtbot)
|
||||
_click_toggle_setting(setting, qapp, qtbot)
|
||||
|
||||
|
||||
def _click_toggle_setting(setting, qapp, qtbot):
|
||||
"""Toggle setting checkbox in the misc tab"""
|
||||
|
|
|
@ -1,37 +1,49 @@
|
|||
from PyQt6 import QtCore
|
||||
from PyQt6.QtWidgets import QDialogButtonBox
|
||||
from PyQt6.QtWidgets import QDialogButtonBox, QMessageBox, QToolTip
|
||||
from vorta.store.models import BackupProfileModel
|
||||
|
||||
|
||||
def test_profile_add(qapp, qtbot):
|
||||
def test_profile_add_delete(qapp, qtbot, mocker):
|
||||
"""Tests adding and deleting profiles."""
|
||||
main = qapp.main_window
|
||||
|
||||
# add profile and ensure it is created as intended
|
||||
qtbot.mouseClick(main.profileAddButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
|
||||
add_profile_window = main.window
|
||||
# qtbot.addWidget(add_profile_window)
|
||||
|
||||
qtbot.keyClicks(add_profile_window.profileNameField, 'Test Profile')
|
||||
qtbot.mouseClick(
|
||||
add_profile_window.buttonBox.button(QDialogButtonBox.StandardButton.Save), QtCore.Qt.MouseButton.LeftButton
|
||||
)
|
||||
|
||||
save_button = add_profile_window.buttonBox.button(QDialogButtonBox.StandardButton.Save)
|
||||
qtbot.mouseClick(save_button, QtCore.Qt.MouseButton.LeftButton)
|
||||
assert BackupProfileModel.get_or_none(name='Test Profile') is not None
|
||||
assert main.profileSelector.currentText() == 'Test Profile'
|
||||
|
||||
# delete the new profile and ensure it is no longer available.
|
||||
mocker.patch.object(QMessageBox, 'question', return_value=QMessageBox.StandardButton.Yes)
|
||||
qtbot.mouseClick(main.profileDeleteButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
assert BackupProfileModel.get_or_none(name='Test Profile') is None
|
||||
assert main.profileSelector.currentText() == 'Default'
|
||||
|
||||
# attempt to delete the last remaining profile
|
||||
# see that it cannot be deleted, a warning is displayed, and the profile remains
|
||||
warning = mocker.patch.object(QToolTip, 'showText')
|
||||
qtbot.mouseClick(main.profileDeleteButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
assert "Cannot delete the last profile." in warning.call_args[0][1]
|
||||
assert BackupProfileModel.get_or_none(name='Default') is not None
|
||||
assert main.profileSelector.currentText() == 'Default'
|
||||
|
||||
|
||||
def test_profile_edit(qapp, qtbot):
|
||||
"""Tests editing/renaming a profile"""
|
||||
main = qapp.main_window
|
||||
|
||||
# click to rename profile, clear the name field, type new profile name
|
||||
qtbot.mouseClick(main.profileRenameButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
|
||||
edit_profile_window = main.window
|
||||
# qtbot.addWidget(edit_profile_window)
|
||||
|
||||
edit_profile_window.profileNameField.setText("")
|
||||
qtbot.keyClicks(edit_profile_window.profileNameField, 'Test Profile')
|
||||
qtbot.mouseClick(
|
||||
edit_profile_window.buttonBox.button(QDialogButtonBox.StandardButton.Save), QtCore.Qt.MouseButton.LeftButton
|
||||
)
|
||||
save_button = edit_profile_window.buttonBox.button(QDialogButtonBox.StandardButton.Save)
|
||||
qtbot.mouseClick(save_button, QtCore.Qt.MouseButton.LeftButton)
|
||||
|
||||
# assert a profile by the old name no longer exists, and the newly named profile does exist and is selected.
|
||||
assert BackupProfileModel.get_or_none(name='Default') is None
|
||||
assert BackupProfileModel.get_or_none(name='Test Profile') is not None
|
||||
assert main.profileSelector.currentText() == 'Test Profile'
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
import uuid
|
||||
from typing import Any, Dict
|
||||
|
||||
import pytest
|
||||
import vorta.borg.borg_job
|
||||
|
@ -187,6 +188,55 @@ def test_ssh_dialog_failure(qapp, qtbot, mocker, monkeypatch, tmpdir):
|
|||
assert tab.sshComboBox.count() == 1
|
||||
|
||||
|
||||
def test_ssh_copy_to_clipboard_action(qapp, qtbot, mocker, tmpdir):
|
||||
"""Testing the proper QMessageBox dialogue appears depending on the copy action circumstances."""
|
||||
tab = qapp.main_window.repoTab
|
||||
|
||||
# set mocks to test assertions and prevent test interruptions
|
||||
text = mocker.patch.object(QMessageBox, "setText")
|
||||
mocker.patch.object(QMessageBox, "show")
|
||||
mocker.patch.object(qapp.clipboard(), "setText")
|
||||
|
||||
qtbot.mouseClick(tab.bAddSSHKey, QtCore.Qt.MouseButton.LeftButton)
|
||||
ssh_dialog = tab._window
|
||||
ssh_dialog_closed = mocker.spy(ssh_dialog, 'reject')
|
||||
ssh_dir = tmpdir
|
||||
key_tmpfile = ssh_dir.join("id_rsa-test")
|
||||
pub_tmpfile = ssh_dir.join("id_rsa-test.pub")
|
||||
key_tmpfile_full = os.path.join(key_tmpfile.dirname, key_tmpfile.basename)
|
||||
ssh_dialog.outputFileTextBox.setText(key_tmpfile_full)
|
||||
ssh_dialog.generate_key()
|
||||
|
||||
# Ensure new key file was created
|
||||
qtbot.waitUntil(lambda: ssh_dialog_closed.called, **pytest._wait_defaults)
|
||||
assert len(ssh_dir.listdir()) == 2
|
||||
# populate the ssh combobox with the ssh key we created in tmpdir
|
||||
mock_expanduser = mocker.patch('os.path.expanduser', return_value=str(tmpdir))
|
||||
tab.init_ssh()
|
||||
assert tab.sshComboBox.count() == 2
|
||||
|
||||
# test when no ssh key is selected to copy
|
||||
assert tab.sshComboBox.currentIndex() == 0
|
||||
qtbot.mouseClick(tab.sshKeyToClipboardButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
message = "Select a public key from the dropdown first."
|
||||
text.assert_called_with(message)
|
||||
|
||||
# Select a key and copy it
|
||||
mock_expanduser.return_value = pub_tmpfile
|
||||
tab.sshComboBox.setCurrentIndex(1)
|
||||
assert tab.sshComboBox.currentIndex() == 1
|
||||
qtbot.mouseClick(tab.sshKeyToClipboardButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
message = "The selected public SSH key was copied to the clipboard. Use it to set up remote repo permissions."
|
||||
text.assert_called_with(message)
|
||||
|
||||
# handle ssh key file not found
|
||||
mock_expanduser.return_value = "foobar"
|
||||
assert tab.sshComboBox.currentIndex() == 1
|
||||
qtbot.mouseClick(tab.sshKeyToClipboardButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
message = "Could not find public key."
|
||||
text.assert_called_with(message)
|
||||
|
||||
|
||||
def test_create(qapp, borg_json_output, mocker, qtbot):
|
||||
main = qapp.main_window
|
||||
stdout, stderr = borg_json_output('create')
|
||||
|
@ -202,3 +252,56 @@ def test_create(qapp, borg_json_output, mocker, qtbot):
|
|||
assert main.createStartBtn.isEnabled()
|
||||
assert main.archiveTab.archiveTable.rowCount() == 3
|
||||
assert main.scheduleTab.logTableWidget.rowCount() == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"response",
|
||||
[
|
||||
{
|
||||
"return_code": 0, # no error
|
||||
"error": "",
|
||||
"icon": None,
|
||||
"info": None,
|
||||
},
|
||||
{
|
||||
"return_code": 1, # warning
|
||||
"error": "Borg exited with warning status (rc 1).",
|
||||
"icon": QMessageBox.Icon.Warning,
|
||||
"info": "",
|
||||
},
|
||||
{
|
||||
"return_code": 2, # critical error
|
||||
"error": "Repository data check for repo test_repo_url failed. Error code 2",
|
||||
"icon": QMessageBox.Icon.Critical,
|
||||
"info": "Consider repairing or recreating the repository soon to avoid missing data.",
|
||||
},
|
||||
{
|
||||
"return_code": 135, # 128 + n = kill signal n
|
||||
"error": "killed by signal 7",
|
||||
"icon": QMessageBox.Icon.Critical,
|
||||
"info": "The process running the check job got a kill signal. Try again.",
|
||||
},
|
||||
{"return_code": 130, "error": "", "icon": None, "info": None}, # keyboard interrupt
|
||||
],
|
||||
)
|
||||
def test_repo_check_failed_response(qapp, qtbot, mocker, response):
|
||||
"""Test the processing of the signal that a repo consistency check has failed."""
|
||||
mock_result: Dict[str, Any] = {
|
||||
'params': {'repo_url': 'test_repo_url'},
|
||||
'returncode': response["return_code"],
|
||||
'errors': [(0, 'test_error_message')] if response["return_code"] not in [0, 130] else None,
|
||||
}
|
||||
|
||||
mock_exec = mocker.patch.object(QMessageBox, "exec")
|
||||
mock_text = mocker.patch.object(QMessageBox, "setText")
|
||||
mock_info = mocker.patch.object(QMessageBox, "setInformativeText")
|
||||
mock_icon = mocker.patch.object(QMessageBox, "setIcon")
|
||||
|
||||
qapp.check_failed_response(mock_result)
|
||||
|
||||
# return codes 0 and 130 do not provide a message
|
||||
# for all other return codes, assert the message is formatted correctly
|
||||
if mock_exec.call_count != 0:
|
||||
mock_icon.assert_called_with(response["icon"])
|
||||
assert response["error"] in mock_text.call_args[0][0]
|
||||
assert response["info"] in mock_info.call_args[0][0]
|
||||
|
|
|
@ -2,6 +2,8 @@ import pytest
|
|||
import vorta.views
|
||||
from PyQt6 import QtCore
|
||||
from PyQt6.QtWidgets import QMessageBox
|
||||
from vorta.views.main_window import MainWindow
|
||||
from vorta.views.source_tab import SourceTab
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
@ -9,11 +11,11 @@ def source_env(qapp, qtbot, monkeypatch, choose_file_dialog):
|
|||
"""
|
||||
Handles common setup and teardown for unit tests involving the source tab.
|
||||
"""
|
||||
monkeypatch.setattr(vorta.views.source_tab, "choose_file_dialog", choose_file_dialog)
|
||||
main = qapp.main_window
|
||||
main: MainWindow = qapp.main_window
|
||||
tab: SourceTab = main.sourceTab
|
||||
main.tabWidget.setCurrentIndex(1)
|
||||
tab = main.sourceTab
|
||||
qtbot.waitUntil(lambda: tab.sourceFilesWidget.rowCount() == 1, timeout=2000)
|
||||
monkeypatch.setattr(vorta.views.source_tab, "choose_file_dialog", choose_file_dialog)
|
||||
|
||||
yield main, tab
|
||||
|
||||
|
@ -100,3 +102,27 @@ def test_sources_update(qapp, qtbot, mocker, source_env):
|
|||
qtbot.mouseClick(tab.updateButton, QtCore.Qt.MouseButton.LeftButton)
|
||||
assert tab.sourceFilesWidget.rowCount() == 2
|
||||
assert update_path_info_spy.call_count == 2
|
||||
|
||||
|
||||
def test_source_copy(qapp, qtbot, monkeypatch, mocker, source_env):
|
||||
"""
|
||||
Test source_copy() with and without an index passed.
|
||||
If no index is passed, it should copy the first selected source
|
||||
"""
|
||||
main, tab = source_env
|
||||
|
||||
mock_clipboard = mocker.patch.object(qapp.clipboard(), "setMimeData")
|
||||
tab.source_add(want_folder=True)
|
||||
qtbot.waitUntil(lambda: tab.sourceFilesWidget.rowCount() == 2, **pytest._wait_defaults)
|
||||
|
||||
tab.sourceFilesWidget.selectRow(0)
|
||||
tab.source_copy()
|
||||
assert mock_clipboard.call_count == 1
|
||||
source = mock_clipboard.call_args[0][0] # retrieves the QMimeData() object used in method call
|
||||
assert source.text() == "/tmp"
|
||||
|
||||
index = tab.sourceFilesWidget.model().index(1, 0)
|
||||
tab.source_copy(index)
|
||||
assert mock_clipboard.call_count == 2
|
||||
source = mock_clipboard.call_args[0][0] # retrieves the QMimeData() object used in method call
|
||||
assert source.text() == "/tmp/another"
|
||||
|
|
|
@ -9,6 +9,7 @@ from vorta.utils import (
|
|||
is_system_tray_available,
|
||||
normalize_path,
|
||||
pretty_bytes,
|
||||
sort_sizes,
|
||||
)
|
||||
|
||||
|
||||
|
@ -21,6 +22,33 @@ def test_keyring():
|
|||
assert keyring.get_password("vorta-repo", REPO) == UNICODE_PW
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_sizes, expected_sorted",
|
||||
[
|
||||
# Basic ordering
|
||||
(["1.0 GB", "2.0 MB", "3.0 KB"], ["3.0 KB", "2.0 MB", "1.0 GB"]),
|
||||
# Multiple same units
|
||||
(["3.0 GB", "2.0 GB", "1.0 GB"], ["1.0 GB", "2.0 GB", "3.0 GB"]),
|
||||
# Multiple different units
|
||||
(["2.0 MB", "3.0 GB", "1.0 KB", "5.0 GB"], ["1.0 KB", "2.0 MB", "3.0 GB", "5.0 GB"]),
|
||||
# Larger to smaller units
|
||||
(["1.0 YB", "1.0 ZB", "1.0 EB", "1.0 PB"], ["1.0 PB", "1.0 EB", "1.0 ZB", "1.0 YB"]),
|
||||
# Skipping non-numeric sizes
|
||||
(["2x MB", "3.0 KB", "apple GB", "1.0 GB"], ["3.0 KB", "1.0 GB"]),
|
||||
# Skipping invalid suffix
|
||||
(["1.0 XX", "5.0 YY", "9.0 ZZ", "1.0 MB"], ["1.0 MB"]),
|
||||
# Floats with decimals
|
||||
(["2.5 GB", "2.3 GB", "1.1 MB"], ["1.1 MB", "2.3 GB", "2.5 GB"]),
|
||||
# Checking the same sizes across different units
|
||||
(["1.0 MB", "1000.0 KB"], ["1000.0 KB", "1.0 MB"]),
|
||||
# Handle empty lists
|
||||
([], []),
|
||||
],
|
||||
)
|
||||
def test_sort_sizes(input_sizes, expected_sorted):
|
||||
assert sort_sizes(input_sizes) == expected_sorted
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"precision, expected_unit",
|
||||
[
|
||||
|
@ -60,7 +88,7 @@ def test_best_unit_for_sizes_nonmetric(sizes, expected_unit):
|
|||
)
|
||||
def test_pretty_bytes_fixed_units(size, metric, precision, fixed_unit, expected_output):
|
||||
"""
|
||||
test pretty bytes when specifying a fixed unit of measurement
|
||||
Test pretty bytes when specifying a fixed unit of measurement
|
||||
"""
|
||||
output = pretty_bytes(size, metric=metric, precision=precision, fixed_unit=fixed_unit)
|
||||
assert output == expected_output
|
||||
|
@ -131,7 +159,7 @@ def test_get_path_datasize(tmpdir):
|
|||
|
||||
def test_is_system_tray_available(mocker):
|
||||
"""
|
||||
sanity check to ensure proper behavior
|
||||
Sanity check to ensure proper behavior
|
||||
"""
|
||||
mocker.patch('PyQt6.QtWidgets.QSystemTrayIcon.isSystemTrayAvailable', return_value=False)
|
||||
assert is_system_tray_available() is False
|
||||
|
|
Loading…
Reference in New Issue