migrate from unittest to pytest

This commit is contained in:
Andreas Zweili 2019-04-21 22:27:25 +02:00
parent 1e7b87bc01
commit 5d80c72384
7 changed files with 258 additions and 289 deletions

View File

@ -36,7 +36,7 @@ test:
@. venv/bin/activate
@( \
cd tests/; \
python3 -m unittest; \
pytest; \
)
clean: distclean

View File

@ -1,3 +1,4 @@
pyinstaller
PyQt5
borgbackup[fuse]==1.1.8
pytest

69
tests/conftest.py Normal file
View File

@ -0,0 +1,69 @@
import json
import os
import pytest
import subprocess
from shutil import copyfile
import context
import borg_interface as borg
from main_window import MainWindow
from helper import remove_path
def example_config():
return '/tmp/test.conf'
@pytest.fixture
def mock_home(tmpdir):
envs = {
'HOME': tmpdir.strpath,
}
yield envs
remove_path(envs['HOME'])
@pytest.fixture
def setup_config():
tmp_path = '/tmp/test.conf'
dir_path = os.path.dirname(os.path.realpath(__file__))
config_path = os.path.join(dir_path,
'../docs/borg_qt.conf.example')
copyfile(config_path, tmp_path)
yield tmp_path
os.remove(tmp_path)
@pytest.fixture
def form(setup_config, monkeypatch):
form = MainWindow()
monkeypatch.setattr(form.config, '_get_path', example_config)
form.config.read()
return form
@pytest.fixture(scope='session')
def repository(tmpdir_factory):
repository_path = tmpdir_factory.mktemp('test-borgqt')
os.environ['BORG_REPO'] = repository_path.strpath
os.environ['BORG_PASSPHRASE'] = 'foo'
os.environ['BORG_DISPLAY_PASSPHRASE'] = 'no'
subprocess.run(['borg', 'init',
'--encryption=repokey-blake2'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
yield
remove_path(repository_path)
@pytest.fixture
def archives(repository):
backup_thread = borg.BackupThread(['.'])
backup_thread.run()
list_thread = borg.ListThread()
output = list_thread.run()
return output
@pytest.fixture
def target_path(tmpdir):
yield str(tmpdir)
remove_path(str(tmpdir))

View File

@ -6,86 +6,55 @@ from time import strftime
from PyQt5.QtWidgets import QApplication
import context
from testcase import BorgInterfaceTest
import borg_interface as borg
from helper import create_path, remove_path
from helper import create_path
app = QApplication(sys.argv)
class BackupTestCase(BorgInterfaceTest):
def test_backup(self):
self.backup_thread = borg.BackupThread(['.'])
self.backup_thread.run()
output = subprocess.check_output(['borg', 'list'], encoding='utf8')
self.assertNotEqual(-1, output.find(strftime('%Y-%m-%d_%H:')))
def test_backup_with_prefix(self):
self.backup_thread = borg.BackupThread(['.'], prefix='test')
self.backup_thread.run()
output = subprocess.check_output(['borg', 'list'], encoding='utf8')
self.assertNotEqual(-1, output.find(strftime('test_%Y-%m-%d_%H:')))
def test_backup(repository):
backup_thread = borg.BackupThread(['.'])
backup_thread.run()
output = subprocess.check_output(['borg', 'list'], encoding='utf8')
assert -1 != output.find(strftime('%Y-%m-%d_%H:'))
class RestoreTestCase(BorgInterfaceTest):
def setUp(self):
super().setUp()
self.backup_thread = borg.BackupThread(['.'])
self.backup_thread.run()
self.target_path = '/tmp/restore/'
self.list_thread = borg.ListThread()
repo_archives = self.list_thread.run()
self.archive_name = repo_archives[0]['name']
self.restore_path = os.path.join(self.target_path, self.archive_name)
create_path(self.restore_path)
def tearDown(self):
remove_path(self.target_path)
super().tearDown()
def test_restore(self):
thread = borg.RestoreThread(self.archive_name, self.restore_path)
thread.run()
self.assertTrue(os.path.exists(
os.path.join(self.restore_path, os.path.realpath(__file__))))
def test_backup_with_prefix(repository):
backup_thread = borg.BackupThread(['.'], prefix='test')
backup_thread.run()
output = subprocess.check_output(['borg', 'list'], encoding='utf8')
assert -1 != output.find(strftime('test_%Y-%m-%d_%H:'))
class DeleteTestCase(BorgInterfaceTest):
def setUp(self):
super().setUp()
self.backup_thread = borg.BackupThread(['.'])
self.backup_thread.run()
self.list_thread = borg.ListThread()
repo_archives = self.list_thread.run()
self.archive_name = repo_archives[0]['name']
def test_delete(self):
thread = borg.DeleteThread(self.archive_name)
thread.run()
self.list_thread = borg.ListThread()
repo_archives = self.list_thread.run()
self.assertEqual(repo_archives, [])
def test_restore(target_path, archives):
archive_list = archives
archive_name = archive_list[0]['name']
restore_path = os.path.join(target_path, archive_name)
create_path(restore_path)
thread = borg.RestoreThread(archive_name, restore_path)
thread.run()
assert os.path.exists(
os.path.join(restore_path, os.path.realpath(__file__)))
class MountTestCase(BorgInterfaceTest):
def setUp(self):
super().setUp()
self.backup_thread = borg.BackupThread(['.'])
self.backup_thread.run()
self.list_thread = borg.ListThread()
repo_archives = self.list_thread.run()
self.archive_name = repo_archives[0]['name']
self.mount_path = os.path.join('/tmp/', self.archive_name)
create_path(self.mount_path)
def test_delete(target_path, archives):
archive_list = archives
archive_name = archive_list[0]['name']
thread = borg.DeleteThread(archive_name)
thread.run()
list_thread = borg.ListThread()
repo_archives = list_thread.run()
assert archive_name not in repo_archives
def tearDown(self):
os.system('borg umount ' + self.mount_path)
remove_path(self.mount_path)
super().tearDown()
def test_mount(self):
thread = borg.MountThread(self.archive_name, self.mount_path)
thread.run()
self.assertTrue(os.path.exists(
os.path.join(self.mount_path, os.path.realpath(__file__))))
def test_mount(target_path, archives):
archive_list = archives
archive_name = archive_list[0]['name']
mount_path = os.path.join(target_path, archive_name)
create_path(mount_path)
thread = borg.MountThread(archive_name, mount_path)
thread.run()
assert os.path.exists(
os.path.join(mount_path, os.path.realpath(__file__)))
os.system('borg umount ' + mount_path)

View File

@ -1,147 +1,123 @@
import os
import sys
import configparser
import unittest
from unittest.mock import MagicMock, patch
import warnings
from shutil import copyfile
import pytest
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtTest import QTest
import context
from main_window import MainWindow
from helper import BorgException
from testcase import BorgQtTestCase
app = QApplication(sys.argv)
class TestConfiguration(BorgQtTestCase):
def test_read_configuration(self):
self.form.config._get_path = MagicMock(return_value=self.config_path)
self.form.config.read()
parser = configparser.ConfigParser()
parser.read(self.config_path)
self.assertEqual(parser, self.form.config.config)
@patch('config.os.path')
def test_absent_config_file(self, mock_path):
mock_path.exists.return_value = False
with self.assertRaises(BorgException):
self.form.config._get_path()
def test_empty_port(self):
self.form.config._get_path = MagicMock(return_value=self.config_path)
self.form.config.read()
self.form.config.config['borgqt']['port'] = ""
with self.assertRaises(BorgException):
self.form.config._create_server_path()
def test_absent_port(self):
self.form.config._get_path = MagicMock(return_value=self.config_path)
self.form.config.read()
if 'port' in self.form.config.config['DEFAULT']:
self.form.config.config['DEFAULT'].pop('port', None)
if 'port' in self.form.config.config['borgqt']:
self.form.config.config['borgqt'].pop('port', None)
with self.assertRaises(BorgException):
self.form.config._create_server_path()
def test_empty_user(self):
self.form.config._get_path = MagicMock(return_value=self.config_path)
self.form.config.read()
self.form.config.config['borgqt']['user'] = ""
with self.assertRaises(BorgException):
self.form.config._create_server_path()
def test_absent_user(self):
self.form.config._get_path = MagicMock(return_value=self.config_path)
self.form.config.read()
if 'user' in self.form.config.config['DEFAULT']:
self.form.config.config['DEFAULT'].pop('user', None)
if 'user' in self.form.config.config['borgqt']:
self.form.config.config['borgqt'].pop('user', None)
with self.assertRaises(BorgException):
self.form.config._create_server_path()
def test_apply_settings(self):
self.form.config._get_path = MagicMock(return_value=self.config_path)
self.form.config.read()
self.form.config.apply_options()
self.assertIs(type(self.form.config.excludes), list)
self.assertEqual(self.form.config.full_path,
os.environ['BORG_REPO'])
self.assertEqual(self.form.config.password,
os.environ['BORG_PASSPHRASE'])
def test_read_configuration(form):
parser = configparser.ConfigParser()
parser.read(form.config.path)
assert parser == form.config.config
class TestWriteConfiguration(BorgQtTestCase):
def tearDown(self):
if os.path.exists(self.form.config.path):
os.remove(self.form.config.path)
def test_absent_config_file(monkeypatch):
def mock_path(path):
return False
def test_write_config(self):
self.form.config._get_path = MagicMock(return_value=self.config_path)
self.form.config.read()
self.form.config.path = '/tmp/test.conf'
self.form.config.write()
config = configparser.ConfigParser()
config.read(self.form.config.path)
for value in config['borgqt']:
self.assertEqual(self.form.config.config['borgqt'][value],
config['borgqt'][value])
form = MainWindow()
monkeypatch.setattr(os.path, 'exists', mock_path)
with pytest.raises(BorgException):
form.config._get_path()
class TestGuiConfiguration(BorgQtTestCase):
def setUp(self):
super().setUp()
copyfile(self.config_path, '/tmp/test.conf')
self.form.config._get_path = MagicMock(return_value='/tmp/test.conf')
self.form.config.read()
def test_empty_port(form):
form.config.config['borgqt']['port'] = ""
with pytest.raises(BorgException):
form.config._create_server_path()
def tearDown(self):
if os.path.exists(self.form.config.path):
os.remove(self.form.config.path)
def test_set_form_values(self):
self.form.config.set_form_values()
self.assertEqual(self.form.config.password,
self.form.config.line_edit_password.text())
def test_absent_port(form):
if 'port' in form.config.config['DEFAULT']:
form.config.config['DEFAULT'].pop('port', None)
if 'port' in form.config.config['borgqt']:
form.config.config['borgqt'].pop('port', None)
with pytest.raises(BorgException):
form.config._create_server_path()
def test_cancel_settings(self):
self.form.config.line_edit_password.clear()
QTest.keyClicks(self.form.config.line_edit_password, "bar")
cancel_button = self.form.config.button_box.button(
self.form.config.button_box.Cancel)
QTest.mouseClick(cancel_button, Qt.LeftButton)
self.assertEqual(self.form.config.password,
self.form.config.config['borgqt']['password'])
def test_ok_settings(self):
self.form.config.line_edit_password.clear()
QTest.keyClicks(self.form.config.line_edit_password, "bar")
ok_button = self.form.config.button_box.button(
self.form.config.button_box.Ok)
QTest.mouseClick(ok_button, Qt.LeftButton)
parser = configparser.ConfigParser()
parser.read(self.form.config.path)
self.assertEqual(self.form.config.line_edit_password.text(),
parser['borgqt']['password'])
def test_empty_user(form):
form.config.config['borgqt']['user'] = ""
with pytest.raises(BorgException):
form.config._create_server_path()
def test_include_remove(self):
self.form.config.set_form_values()
counter = self.form.config.list_include.count()
self.form.config.list_include.setCurrentRow(0)
self.form.config.remove_include()
self.assertGreaterEqual(counter, self.form.config.list_include.count())
def test_exclude_remove(self):
self.form.config.set_form_values()
counter = self.form.config.list_exclude.count()
self.form.config.list_exclude.setCurrentRow(0)
self.form.config.remove_exclude()
self.assertGreaterEqual(counter, self.form.config.list_exclude.count())
def test_absent_user(form):
if 'user' in form.config.config['DEFAULT']:
form.config.config['DEFAULT'].pop('user', None)
if 'user' in form.config.config['borgqt']:
form.config.config['borgqt'].pop('user', None)
with pytest.raises(BorgException):
form.config._create_server_path()
def test_apply_settings(form):
form.config.apply_options()
assert type(form.config.excludes) == list
assert form.config.full_path == os.environ['BORG_REPO']
assert form.config.password == os.environ['BORG_PASSPHRASE']
def test_write_config(form):
form.config.config['borgqt']['password'] == 'Test String'
form.config.write()
config = configparser.ConfigParser()
config.read(form.config.path)
for value in config['borgqt']:
assert (form.config.config['borgqt'][value]
== config['borgqt'][value])
def test_set_form_values(form):
form.config.set_form_values()
assert (form.config.password
== form.config.line_edit_password.text())
def test_cancel_settings(form):
form.config.line_edit_password.clear()
QTest.keyClicks(form.config.line_edit_password, "bar")
cancel_button = form.config.button_box.button(
form.config.button_box.Cancel)
QTest.mouseClick(cancel_button, Qt.LeftButton)
assert (form.config.password
== form.config.config['borgqt']['password'])
def test_ok_settings(form):
form.config.line_edit_password.clear()
QTest.keyClicks(form.config.line_edit_password, "bar")
ok_button = form.config.button_box.button(
form.config.button_box.Ok)
QTest.mouseClick(ok_button, Qt.LeftButton)
parser = configparser.ConfigParser()
parser.read(form.config.path)
assert (form.config.line_edit_password.text()
== parser['borgqt']['password'])
def test_include_remove(form):
form.config.set_form_values()
counter = form.config.list_include.count()
form.config.list_include.setCurrentRow(0)
form.config.remove_include()
assert (counter >= form.config.list_include.count())
def test_exclude_remove(form):
form.config.set_form_values()
counter = form.config.list_exclude.count()
form.config.list_exclude.setCurrentRow(0)
form.config.remove_exclude()
assert (counter >= form.config.list_exclude.count())

View File

@ -1,63 +1,64 @@
import os
import unittest
from testcase import TestSystemd
import context
from systemd import SystemdFile
class TestSystemdUnit(TestSystemd):
def setUp(self):
self.path = os.path.join(os.environ['HOME'],
'.config/systemd/user/borg_qt.service')
def test_write_unit(self):
systemd_unit = SystemdFile('borg_qt.service')
systemd_unit.write()
self.assertTrue(os.path.exists(self.path))
def test_write_unit(mock_home, monkeypatch):
monkeypatch.setattr(os, 'environ', mock_home)
systemd_unit = SystemdFile('borg_qt.service')
systemd_unit.write()
assert os.path.exists(systemd_unit.path)
class TestSystemdTimer(TestSystemd):
def setUp(self):
self.path = os.path.join(os.environ['HOME'],
'.config/systemd/user/borg_qt.timer')
def test_write_timer(self):
systemd_timer = SystemdFile('borg_qt.timer')
systemd_timer.write()
self.assertTrue(os.path.exists(self.path))
def test_write_timer(mock_home, monkeypatch):
monkeypatch.setattr(os, 'environ', mock_home)
systemd_timer = SystemdFile('borg_qt.timer')
systemd_timer.write()
assert os.path.exists(systemd_timer.path)
class TestSystemdEnabledTimer(TestSystemd):
def setUp(self):
self.symlink_path = os.path.join(os.environ['HOME'],
'.config/systemd/user/timers.target.wants/borg_qt.timer')
self.path = os.path.join(os.environ['HOME'],
'.config/systemd/user/borg_qt.timer')
# This test currently runs against the real home directory of the current user.
# Since this can cause problems with a productive Borg-Qt setup I'm commenting
# out this test for the moment. The long time target is to replace it with a
# test which mocks the call to systemd.
#
# class TestSystemdEnabledTimer():
# def setup_method(self):
# self.unit_path = os.path.join(os.environ['HOME'],
# '.config/systemd/user/borg_qt.service')
# self.timer_path = os.path.join(os.environ['HOME'],
# '.config/systemd/user/borg_qt.timer')
# self.symlink_path = os.path.join(os.environ['HOME'],
# '.config/systemd/user/timers.target.wants/borg_qt.timer')
def tearDown(self):
super().tearDown()
os.remove(self.symlink_path)
# def teardown_method(self):
# if os.path.exists(self.unit_path):
# os.remove(self.unit_path)
# if os.path.exists(self.symlink_path):
# os.remove(self.symlink_path)
# if os.path.exists(self.timer_path):
# os.remove(self.timer_path)
def test_enable_timer(self):
systemd_unit = SystemdFile('borg_qt.service')
systemd_timer = SystemdFile('borg_qt.timer')
systemd_unit.content['Unit'] = {}
systemd_unit.content['Unit']['After'] = 'default.target'
systemd_unit.content['Install'] = {}
systemd_unit.content['Install']['Wanted'] = 'default.target'
systemd_unit.content['Service'] = {}
systemd_unit.content['Service']['Type'] = 'forking'
systemd_unit.content['Service']['ExecStart'] = '/bin/echo "test"'
systemd_unit.write()
systemd_timer.content['Unit'] = {}
systemd_timer.content['Unit']['Description'] = 'Test Timer'
systemd_timer.content['Timer'] = {}
systemd_timer.content['Timer']['OnCalendar'] = 'daily'
systemd_timer.content['Timer']['Persistent'] = 'true'
systemd_timer.content['Install'] = {}
systemd_timer.content['Install']['WantedBy'] = 'timers.target'
systemd_timer.write()
systemd_timer.enable()
self.assertTrue(os.path.exists(self.symlink_path))
# def test_enable_timer(self):
# systemd_unit = SystemdFile('borg_qt.service')
# systemd_unit.path = self.unit_path
# systemd_timer = SystemdFile('borg_qt.timer')
# systemd_timer.path = self.timer_path
# systemd_unit.content['Unit'] = {}
# systemd_unit.content['Unit']['After'] = 'default.target'
# systemd_unit.content['Install'] = {}
# systemd_unit.content['Install']['Wanted'] = 'default.target'
# systemd_unit.content['Service'] = {}
# systemd_unit.content['Service']['Type'] = 'forking'
# systemd_unit.content['Service']['ExecStart'] = '/bin/echo "test"'
# systemd_unit.write()
# systemd_timer.content['Unit'] = {}
# systemd_timer.content['Unit']['Description'] = 'Test Timer'
# systemd_timer.content['Timer'] = {}
# systemd_timer.content['Timer']['OnCalendar'] = 'daily'
# systemd_timer.content['Timer']['Persistent'] = 'true'
# systemd_timer.content['Install'] = {}
# systemd_timer.content['Install']['WantedBy'] = 'timers.target'
# systemd_timer.write()
# systemd_timer.enable()
# assert os.path.exists(self.symlink_path)

View File

@ -1,47 +0,0 @@
import os
import subprocess
import shutil
import unittest
import warnings
import context
from main_window import MainWindow
from helper import remove_path
def fxn():
warnings.warn("deprecated", DeprecationWarning)
class BorgQtTestCase(unittest.TestCase):
def setUp(self):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
self.form = MainWindow()
self.dir_path = os.path.dirname(os.path.realpath(__file__))
self.config_path = os.path.join(self.dir_path,
'../docs/borg_qt.conf.example')
class BorgInterfaceTest(unittest.TestCase):
def setUp(self):
super().setUp()
self.repository_path = '/tmp/test-borgqt'
os.environ['BORG_REPO'] = self.repository_path
os.environ['BORG_PASSPHRASE'] = 'foo'
os.environ['BORG_DISPLAY_PASSPHRASE'] = 'no'
subprocess.run(['borg', 'init',
'--encryption=repokey-blake2'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
def tearDown(self):
remove_path(self.repository_path)
class TestSystemd(unittest.TestCase):
def tearDown(self):
os.remove(self.path)