FreedomBox/plinth/modules/backups/tests/test_components.py
Sunil Mohan Adapa 59c5e58549
backups: Implement backup/restore of key/value settings
- Implemented within the backup component. Scope for implementing database
backup/restore in similar way.

- Add new 'settings' key in the backup manifest to allow keys to backed up and
restored.

- Implement by dumping/loading settings from DB into the file.

Tests:

- Unit tests.

- Backup/restore tests for dynamicdns workss.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
2022-02-10 20:31:36 -05:00

277 lines
7.1 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Test the App components provides by backups app.
"""
import json
from unittest.mock import call, patch
import pytest
from plinth import kvstore
from .. import components
from ..components import BackupRestore
# pylint: disable=protected-access
@pytest.fixture(name='backup_restore')
def fixture_backup_restore():
"""Fixture to create a domain type after clearing all existing ones."""
value = {'files': ['a', 'b'], 'directories': ['a', 'b']}
services = ['service-1', {'type': 'system', 'name': 'service-2'}]
settings = ['setting-1', 'setting-2']
return BackupRestore('test-backup-restore', config=value, data=value,
secrets=value, services=services, settings=settings)
@pytest.mark.parametrize('section', [
None,
{
'directories': ['a', 'b']
},
{
'files': ['a', 'b']
},
{
'directories': ['a'],
'files': ['a']
},
{
'extra': 'value'
},
])
def test_valid_directories_and_files(section):
"""Test that valid values of files and directories."""
components._validate_directories_and_files(section)
@pytest.mark.parametrize('section', [
'invalid',
10,
['invalid'],
{
'files': None
},
{
'files': 10
},
{
'files': {}
},
{
'files': [10],
},
{
'files': [None],
},
{
'files': [[]],
},
{
'directories': None
},
{
'directories': [10],
},
])
def test_invalid_directories_and_files(section):
"""Test that invalid values of files and directories."""
with pytest.raises(AssertionError):
components._validate_directories_and_files(section)
@pytest.mark.parametrize('services', [
None,
[],
['service'],
[{
'type': 'uwsgi',
'name': 'service'
}],
[{
'type': 'system',
'name': 'service'
}],
[{
'type': 'apache',
'name': 'service',
'kind': 'config'
}],
[{
'type': 'apache',
'name': 'service',
'kind': 'site'
}],
[{
'type': 'apache',
'name': 'service',
'kind': 'module'
}],
])
def test_valid_services(services):
"""Test that valid values of services."""
components._validate_services(services)
@pytest.mark.parametrize('services', [
10,
'invalid',
[10],
[[]],
[{}],
[{
'type': 'invalid',
'name': 'service'
}],
[{
'type': 10,
'name': 'service'
}],
[{
'type': 'system',
'name': 10
}],
[{
'type': 'system',
'name': None
}],
[{
'type': 'system',
'name': []
}],
[{
'type': 'apache',
'name': 'service'
}],
[{
'type': 'apache',
'name': 'service',
'kind': 'invalid-kind'
}],
])
def test_invalid_services(services):
"""Test that invalid values of services."""
with pytest.raises((AssertionError, KeyError)):
components._validate_services(services)
def test_backup_restore_init_default_arguments():
"""Test initialization of the backup restore object."""
component = BackupRestore('test-backup-restore')
assert component.component_id == 'test-backup-restore'
assert component.config == {}
assert component.data == {}
assert component.secrets == {}
assert component.services == []
assert component.settings == []
assert not component.has_data
@pytest.mark.parametrize('key', ['config', 'data', 'secrets'])
def test_backup_restore_init(key):
"""Test initialization of the backup restore object."""
with pytest.raises(AssertionError):
BackupRestore('test-backup-restore', **{key: 'invalid-value'})
value = {'files': ['a', 'b'], 'directories': ['a', 'b']}
component = BackupRestore('test-backup-restore', **{key: value})
assert getattr(component, key) == value
assert component.has_data
def test_backup_restore_init_services():
"""Test initialization of the backup restore object."""
with pytest.raises(AssertionError):
BackupRestore('test-backup-restore', services='invalid-value')
services = ['service-1', {'type': 'system', 'name': 'service-2'}]
component = BackupRestore('test-backup-restore', services=services)
assert component.services == services
assert not component.has_data
def test_backup_restore_init_settings():
"""Test initialization of the backup restore object."""
with pytest.raises(AssertionError):
BackupRestore('test-backup-restore', settings='invalid-value')
settings = ['setting1', 'setting2']
component = BackupRestore('test-backup-restore', settings=settings)
assert component.settings == settings
assert component.has_data
assert component.data == {}
component.app_id = 'testapp'
settings_file = '/var/lib/plinth/backups-data/testapp-settings.json'
assert component.data == {'files': [settings_file]}
def test_backup_restore_equal(backup_restore):
"""Test equality operator on the backup restore object."""
assert backup_restore == BackupRestore('test-backup-restore')
assert backup_restore != BackupRestore('test-different')
def test_backup_restore_manifest(backup_restore):
"""Test manifest retrieval from backup restore object."""
manifest = backup_restore.manifest
assert isinstance(manifest, dict)
assert manifest['config'] == backup_restore.config
assert manifest['data'] == backup_restore.data
assert manifest['secrets'] == backup_restore.secrets
assert manifest['services'] == backup_restore.services
assert manifest['settings'] == backup_restore.settings
assert BackupRestore('test-backup-restore').manifest == {}
def test_backup_restore_hooks(backup_restore):
"""Test running hooks on backup restore object."""
packet = None
backup_restore.backup_post(packet)
backup_restore.restore_pre(packet)
@pytest.mark.django_db
@patch('plinth.actions.superuser_run')
def test_backup_restore_backup_pre(run, backup_restore):
"""Test running backup-pre hook."""
packet = None
kvstore.set('setting-1', 'value-1')
backup_restore.app_id = 'testapp'
component = BackupRestore('test-backup-restore')
component.backup_pre(packet)
run.assert_has_calls([])
backup_restore.backup_pre(packet)
input_ = {'setting-1': 'value-1'}
run.assert_has_calls([
call('backups', ['dump-settings', '--app-id', 'testapp'],
input=json.dumps(input_).encode())
])
@pytest.mark.django_db
@patch('plinth.actions.superuser_run')
def test_backup_restore_restore_post(run, backup_restore):
"""Test running restore-post hook."""
packet = None
backup_restore.app_id = 'testapp'
component = BackupRestore('test-backup-restore')
component.restore_post(packet)
run.assert_has_calls([])
output = {'setting-1': 'value-1'}
run.return_value = json.dumps(output)
backup_restore.restore_post(packet)
run.assert_has_calls(
[call('backups', ['load-settings', '--app-id', 'testapp'])])
assert kvstore.get('setting-1') == 'value-1'
with pytest.raises(Exception):
kvstore.get('setting-2')