test_backups.py 5.29 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#
# This file is part of FreedomBox.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
"""
Tests for backups module.
"""

21
import collections
22
import unittest
23
from unittest.mock import call, patch, MagicMock
24 25

from plinth.module_loader import load_modules
26
from ..backups import validate, Packet, backup_apps, restore_apps, \
27
    get_all_apps_for_backup, _get_apps_in_order, _get_manifests, \
28
    _lockdown_apps, _shutdown_services, _restore_services
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46


def _get_test_manifest(name):
    return validate({
        'config': {
            'directories': ['/etc/' + name + '/config.d/'],
            'files': ['/etc/' + name + '/config'],
        },
        'data': {
            'directories': ['/var/lib/' + name + '/data.d/'],
            'files': ['/var/lib/' + name + '/data'],
        },
        'secrets': {
            'directories': ['/etc/' + name + '/secrets.d/'],
            'files': ['/etc/' + name + '/secrets'],
        },
        'services': [name]
    })
47 48 49 50 51


class TestBackups(unittest.TestCase):
    """Test cases for backups module."""

52 53 54 55 56 57 58 59 60
    def test_packet_process_manifests(self):
        """Test that directories/files are collected from manifests."""
        manifests = [
            ('a', None, _get_test_manifest('a')),
            ('b', None, _get_test_manifest('b')),
        ]
        packet = Packet('backup', 'apps', '/', manifests)
        for manifest in manifests:
            backup = manifest[2]
61 62 63 64 65
            for section in ['config', 'data', 'secrets']:
                for directory in backup[section]['directories']:
                    assert directory in packet.directories
                for file_path in backup[section]['files']:
                    assert file_path in packet.files
66

67 68 69 70 71 72 73 74 75 76 77 78
    def test_backup_apps(self):
        """Test that backup_handler is called."""
        backup_handler = MagicMock()
        backup_apps(backup_handler)
        backup_handler.assert_called_once()

    def test_restore_apps(self):
        """Test that restore_handler is called."""
        restore_handler = MagicMock()
        restore_apps(restore_handler)
        restore_handler.assert_called_once()

79
    def test_get_all_apps_for_backups(self):
80 81
        """Test that apps supporting backup are included in returned list."""
        load_modules()
82
        apps = get_all_apps_for_backup()
83 84 85 86 87 88 89 90
        assert isinstance(apps, list)
        # apps may be empty, if no apps supporting backup are installed.

    def test__get_apps_in_order(self):
        """Test that apps are listed in correct dependency order."""
        load_modules()
        app_names = ['config', 'names']
        apps = _get_apps_in_order(app_names)
91
        ordered_app_names = [app[0] for app in apps]
92 93 94 95

        names_index = ordered_app_names.index('names')
        config_index = ordered_app_names.index('config')
        assert names_index < config_index
96

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    def test__get_manifests(self):
        """Test that manifests are collected from the apps."""
        a = MagicMock(backup=_get_test_manifest('a'))
        b = MagicMock(backup=_get_test_manifest('b'))
        apps = [
            ('a', a),
            ('b', b),
        ]
        manifests = _get_manifests(apps)
        assert ('a', a, a.backup) in manifests
        assert ('b', b, b.backup) in manifests

    def test__lockdown_apps(self):
        """Test that locked flag is set for each app."""
        a = MagicMock(locked=False)
        b = MagicMock(locked=None)
        apps = [
            ('a', a),
            ('b', b),
        ]
        _lockdown_apps(apps, True)
        assert a.locked is True
        assert b.locked is True

121 122 123
    @patch('plinth.action_utils.service_is_running')
    @patch('plinth.actions.superuser_run')
    def test__shutdown_services(self, run, is_running):
124 125 126 127 128
        """Test that services are stopped in correct order."""
        manifests = [
            ('a', None, _get_test_manifest('a')),
            ('b', None, _get_test_manifest('b')),
        ]
129
        is_running.return_value = True
130 131 132
        state = _shutdown_services(manifests)
        assert 'a' in state
        assert 'b' in state
133 134 135 136 137 138 139
        is_running.assert_any_call('a')
        is_running.assert_any_call('b')
        calls = [
            call('service', ['stop', 'b']),
            call('service', ['stop', 'a'])
        ]
        run.assert_has_calls(calls)
140 141 142 143 144 145 146 147 148 149 150

    @patch('plinth.actions.superuser_run')
    def test__restore_services(self, run):
        """Test that services are restored in correct order."""
        original_state = collections.OrderedDict()
        original_state['a'] = {
            'app_name': 'a', 'app': None, 'was_running': True}
        original_state['b'] = {
            'app_name': 'b', 'app': None, 'was_running': False}
        _restore_services(original_state)
        run.assert_called_once_with('service', ['start', 'a'])