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 @. venv/bin/activate
@( \ @( \
cd tests/; \ cd tests/; \
python3 -m unittest; \ pytest; \
) )
clean: distclean clean: distclean

View File

@ -1,3 +1,4 @@
pyinstaller pyinstaller
PyQt5 PyQt5
borgbackup[fuse]==1.1.8 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 from PyQt5.QtWidgets import QApplication
import context import context
from testcase import BorgInterfaceTest
import borg_interface as borg import borg_interface as borg
from helper import create_path, remove_path from helper import create_path
app = QApplication(sys.argv) app = QApplication(sys.argv)
class BackupTestCase(BorgInterfaceTest): def test_backup(repository):
def test_backup(self): backup_thread = borg.BackupThread(['.'])
self.backup_thread = borg.BackupThread(['.']) backup_thread.run()
self.backup_thread.run() output = subprocess.check_output(['borg', 'list'], encoding='utf8')
output = subprocess.check_output(['borg', 'list'], encoding='utf8') assert -1 != output.find(strftime('%Y-%m-%d_%H:'))
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:')))
class RestoreTestCase(BorgInterfaceTest): def test_backup_with_prefix(repository):
def setUp(self): backup_thread = borg.BackupThread(['.'], prefix='test')
super().setUp() backup_thread.run()
self.backup_thread = borg.BackupThread(['.']) output = subprocess.check_output(['borg', 'list'], encoding='utf8')
self.backup_thread.run() assert -1 != output.find(strftime('test_%Y-%m-%d_%H:'))
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__))))
class DeleteTestCase(BorgInterfaceTest): def test_restore(target_path, archives):
def setUp(self): archive_list = archives
super().setUp() archive_name = archive_list[0]['name']
self.backup_thread = borg.BackupThread(['.']) restore_path = os.path.join(target_path, archive_name)
self.backup_thread.run() create_path(restore_path)
self.list_thread = borg.ListThread() thread = borg.RestoreThread(archive_name, restore_path)
repo_archives = self.list_thread.run() thread.run()
self.archive_name = repo_archives[0]['name'] assert os.path.exists(
os.path.join(restore_path, os.path.realpath(__file__)))
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, [])
class MountTestCase(BorgInterfaceTest): def test_delete(target_path, archives):
def setUp(self): archive_list = archives
super().setUp() archive_name = archive_list[0]['name']
self.backup_thread = borg.BackupThread(['.']) thread = borg.DeleteThread(archive_name)
self.backup_thread.run() thread.run()
self.list_thread = borg.ListThread() list_thread = borg.ListThread()
repo_archives = self.list_thread.run() repo_archives = list_thread.run()
self.archive_name = repo_archives[0]['name'] assert archive_name not in repo_archives
self.mount_path = os.path.join('/tmp/', self.archive_name)
create_path(self.mount_path)
def tearDown(self):
os.system('borg umount ' + self.mount_path)
remove_path(self.mount_path)
super().tearDown()
def test_mount(self): def test_mount(target_path, archives):
thread = borg.MountThread(self.archive_name, self.mount_path) archive_list = archives
thread.run() archive_name = archive_list[0]['name']
self.assertTrue(os.path.exists( mount_path = os.path.join(target_path, archive_name)
os.path.join(self.mount_path, os.path.realpath(__file__)))) 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 os
import sys import sys
import configparser import configparser
import unittest
from unittest.mock import MagicMock, patch import pytest
import warnings
from shutil import copyfile
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from PyQt5.QtTest import QTest from PyQt5.QtTest import QTest
import context
from main_window import MainWindow from main_window import MainWindow
from helper import BorgException from helper import BorgException
from testcase import BorgQtTestCase
app = QApplication(sys.argv) app = QApplication(sys.argv)
class TestConfiguration(BorgQtTestCase): def test_read_configuration(form):
def test_read_configuration(self): parser = configparser.ConfigParser()
self.form.config._get_path = MagicMock(return_value=self.config_path) parser.read(form.config.path)
self.form.config.read() assert parser == form.config.config
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'])
class TestWriteConfiguration(BorgQtTestCase): def test_absent_config_file(monkeypatch):
def tearDown(self): def mock_path(path):
if os.path.exists(self.form.config.path): return False
os.remove(self.form.config.path)
def test_write_config(self): form = MainWindow()
self.form.config._get_path = MagicMock(return_value=self.config_path) monkeypatch.setattr(os.path, 'exists', mock_path)
self.form.config.read() with pytest.raises(BorgException):
self.form.config.path = '/tmp/test.conf' form.config._get_path()
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])
class TestGuiConfiguration(BorgQtTestCase): def test_empty_port(form):
def setUp(self): form.config.config['borgqt']['port'] = ""
super().setUp() with pytest.raises(BorgException):
copyfile(self.config_path, '/tmp/test.conf') form.config._create_server_path()
self.form.config._get_path = MagicMock(return_value='/tmp/test.conf')
self.form.config.read()
def tearDown(self):
if os.path.exists(self.form.config.path):
os.remove(self.form.config.path)
def test_set_form_values(self): def test_absent_port(form):
self.form.config.set_form_values() if 'port' in form.config.config['DEFAULT']:
self.assertEqual(self.form.config.password, form.config.config['DEFAULT'].pop('port', None)
self.form.config.line_edit_password.text()) 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): def test_empty_user(form):
self.form.config.line_edit_password.clear() form.config.config['borgqt']['user'] = ""
QTest.keyClicks(self.form.config.line_edit_password, "bar") with pytest.raises(BorgException):
ok_button = self.form.config.button_box.button( form.config._create_server_path()
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_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): def test_absent_user(form):
self.form.config.set_form_values() if 'user' in form.config.config['DEFAULT']:
counter = self.form.config.list_exclude.count() form.config.config['DEFAULT'].pop('user', None)
self.form.config.list_exclude.setCurrentRow(0) if 'user' in form.config.config['borgqt']:
self.form.config.remove_exclude() form.config.config['borgqt'].pop('user', None)
self.assertGreaterEqual(counter, self.form.config.list_exclude.count()) 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 os
import unittest
from testcase import TestSystemd
import context
from systemd import SystemdFile from systemd import SystemdFile
class TestSystemdUnit(TestSystemd): def test_write_unit(mock_home, monkeypatch):
def setUp(self): monkeypatch.setattr(os, 'environ', mock_home)
self.path = os.path.join(os.environ['HOME'], systemd_unit = SystemdFile('borg_qt.service')
'.config/systemd/user/borg_qt.service') systemd_unit.write()
assert os.path.exists(systemd_unit.path)
def test_write_unit(self):
systemd_unit = SystemdFile('borg_qt.service')
systemd_unit.write()
self.assertTrue(os.path.exists(self.path))
class TestSystemdTimer(TestSystemd): def test_write_timer(mock_home, monkeypatch):
def setUp(self): monkeypatch.setattr(os, 'environ', mock_home)
self.path = os.path.join(os.environ['HOME'], systemd_timer = SystemdFile('borg_qt.timer')
'.config/systemd/user/borg_qt.timer') systemd_timer.write()
assert os.path.exists(systemd_timer.path)
def test_write_timer(self):
systemd_timer = SystemdFile('borg_qt.timer')
systemd_timer.write()
self.assertTrue(os.path.exists(self.path))
class TestSystemdEnabledTimer(TestSystemd): # This test currently runs against the real home directory of the current user.
def setUp(self): # Since this can cause problems with a productive Borg-Qt setup I'm commenting
self.symlink_path = os.path.join(os.environ['HOME'], # out this test for the moment. The long time target is to replace it with a
'.config/systemd/user/timers.target.wants/borg_qt.timer') # test which mocks the call to systemd.
self.path = os.path.join(os.environ['HOME'], #
'.config/systemd/user/borg_qt.timer') # 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): # def teardown_method(self):
super().tearDown() # if os.path.exists(self.unit_path):
os.remove(self.symlink_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): # def test_enable_timer(self):
systemd_unit = SystemdFile('borg_qt.service') # systemd_unit = SystemdFile('borg_qt.service')
systemd_timer = SystemdFile('borg_qt.timer') # systemd_unit.path = self.unit_path
systemd_unit.content['Unit'] = {} # systemd_timer = SystemdFile('borg_qt.timer')
systemd_unit.content['Unit']['After'] = 'default.target' # systemd_timer.path = self.timer_path
systemd_unit.content['Install'] = {} # systemd_unit.content['Unit'] = {}
systemd_unit.content['Install']['Wanted'] = 'default.target' # systemd_unit.content['Unit']['After'] = 'default.target'
systemd_unit.content['Service'] = {} # systemd_unit.content['Install'] = {}
systemd_unit.content['Service']['Type'] = 'forking' # systemd_unit.content['Install']['Wanted'] = 'default.target'
systemd_unit.content['Service']['ExecStart'] = '/bin/echo "test"' # systemd_unit.content['Service'] = {}
systemd_unit.write() # systemd_unit.content['Service']['Type'] = 'forking'
systemd_timer.content['Unit'] = {} # systemd_unit.content['Service']['ExecStart'] = '/bin/echo "test"'
systemd_timer.content['Unit']['Description'] = 'Test Timer' # systemd_unit.write()
systemd_timer.content['Timer'] = {} # systemd_timer.content['Unit'] = {}
systemd_timer.content['Timer']['OnCalendar'] = 'daily' # systemd_timer.content['Unit']['Description'] = 'Test Timer'
systemd_timer.content['Timer']['Persistent'] = 'true' # systemd_timer.content['Timer'] = {}
systemd_timer.content['Install'] = {} # systemd_timer.content['Timer']['OnCalendar'] = 'daily'
systemd_timer.content['Install']['WantedBy'] = 'timers.target' # systemd_timer.content['Timer']['Persistent'] = 'true'
systemd_timer.write() # systemd_timer.content['Install'] = {}
systemd_timer.enable() # systemd_timer.content['Install']['WantedBy'] = 'timers.target'
self.assertTrue(os.path.exists(self.symlink_path)) # 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)