Example #1
0
    def test_check_remote_command_fail(self):
        cmds = []
        if tools.checkCommand('nice'):
            cmds.append('nice')
            self.cfg.setNiceOnRemote(True)
        if tools.checkCommand('ionice'):
            cmds.append('ionice')
            self.cfg.setIoniceOnRemote(True)
        if tools.checkCommand('nocache'):
            cmds.append('nocache')
            self.cfg.setNocacheOnRemote(True)
        if tools.checkCommand('screen') and tools.checkCommand('flock'):
            cmds.extend(('screen', 'flock', 'rmdir', 'mktemp'))
            self.cfg.setSmartRemoveRunRemoteInBackground(True)

        # make one after an other command from 'cmds' fail by symlink them
        # to /bin/false
        false = tools.which('false')
        for cmd in cmds:
            msg = 'current trap: %s' %cmd
            with self.subTest(cmd = cmd):
                with TemporaryDirectory() as self.remotePath:
                    self.cfg.setSshSnapshotsPath(self.remotePath)

                    os.symlink(false, os.path.join(self.remotePath, cmd))
                    self.cfg.setSshPrefix(True, "export PATH=%s:$PATH; " %self.remotePath)
                    ssh = sshtools.SSH(cfg = self.cfg)
                    with self.assertRaisesRegex(MountException, r"Remote host .+ doesn't support '.*?%s.*'" %cmd, msg = msg):
                        ssh.checkRemoteCommands()
Example #2
0
    def test_check_remote_command_fail(self):
        cmds = []
        if tools.checkCommand('nice'):
            cmds.append('nice')
            self.cfg.setNiceOnRemote(True)
        if tools.checkCommand('ionice'):
            cmds.append('ionice')
            self.cfg.setIoniceOnRemote(True)
        if tools.checkCommand('nocache'):
            cmds.append('nocache')
            self.cfg.setNocacheOnRemote(True)
        if tools.checkCommand('screen') and tools.checkCommand('flock'):
            cmds.extend(('screen', 'flock', 'rmdir', 'mktemp'))
            self.cfg.setSmartRemoveRunRemoteInBackground(True)

        # make one after an other command from 'cmds' fail by symlink them
        # to /bin/false
        false = tools.which('false')
        for cmd in cmds:
            msg = 'current trap: %s' %cmd
            with self.subTest(cmd = cmd):
                with TemporaryDirectory() as self.remotePath:
                    self.cfg.setSshSnapshotsPath(self.remotePath)

                    os.symlink(false, os.path.join(self.remotePath, cmd))
                    self.cfg.setSshPrefix(True, "export PATH=%s:$PATH; " %self.remotePath)
                    ssh = sshtools.SSH(cfg = self.cfg)
                    with self.assertRaisesRegex(MountException, r"Remote host .+ doesn't support '.*?%s.*'" %cmd, msg = msg):
                        ssh.checkRemoteCommands()
Example #3
0
 def test_checkCommand(self):
     """
     Test the function checkCommand
     """
     self.assertFalse(tools.checkCommand(''))
     self.assertFalse(tools.checkCommand("notExistedCommand"))
     self.assertTrue(tools.checkCommand("ls"))
     self.assertTrue(tools.checkCommand('backintime'))
Example #4
0
 def test_check_remote_command(self):
     self.cfg.setNiceOnRemote(tools.checkCommand('nice'))
     self.cfg.setIoniceOnRemote(tools.checkCommand('ionice'))
     self.cfg.setNocacheOnRemote(tools.checkCommand('nocache'))
     self.cfg.setSmartRemoveRunRemoteInBackground(tools.checkCommand('screen') and tools.checkCommand('flock'))
     os.mkdir(self.remotePath)
     ssh = sshtools.SSH(cfg = self.cfg)
     ssh.checkRemoteCommands()
Example #5
0
 def test_check_remote_command(self):
     self.cfg.setNiceOnRemote(tools.checkCommand('nice'))
     self.cfg.setIoniceOnRemote(tools.checkCommand('ionice'))
     self.cfg.setNocacheOnRemote(tools.checkCommand('nocache'))
     self.cfg.setSmartRemoveRunRemoteInBackground(tools.checkCommand('screen') and tools.checkCommand('flock'))
     os.mkdir(self.remotePath)
     ssh = sshtools.SSH(cfg = self.cfg)
     ssh.checkRemoteCommands()
Example #6
0
 def test_check_remote_command_with_spaces(self):
     self.cfg.setSmartRemoveRunRemoteInBackground(
         tools.checkCommand('screen') and tools.checkCommand('flock'))
     self.remotePath = os.path.join(self.tmpDir.name, 'foo bar')
     self.cfg.setSshSnapshotsPath(self.remotePath)
     os.mkdir(self.remotePath)
     ssh = sshtools.SSH(cfg=self.cfg)
     ssh.checkRemoteCommands()
Example #7
0
 def test_checkCommand(self):
     """
     Test the function checkCommand
     """
     self.assertFalse(tools.checkCommand(''))
     self.assertFalse(tools.checkCommand("notExistedCommand"))
     self.assertTrue(tools.checkCommand("ls"))
     self.assertTrue(tools.checkCommand('backintime'))
Example #8
0
    def checkFuse(self):
        """
        Check if command in self.mountproc is installed and user is part of
        group ``fuse``.

        Raises:
            exceptions.MountException:  if either command is not available or
                                        user is not in group fuse
        """
        logger.debug('Check fuse', self)
        if not tools.checkCommand(self.mountproc):
            logger.debug('%s is missing' %self.mountproc, self)
            raise MountException(_('%(proc)s not found. Please install e.g. %(install_command)s')
                                  %{'proc': self.mountproc,
                                    'install_command': "'apt-get install %s'" %self.mountproc})
        if self.CHECK_FUSE_GROUP:
            user = self.config.user()
            try:
                fuse_grp_members = grp.getgrnam('fuse')[3]
            except KeyError:
                #group fuse doesn't exist. So most likely it isn't used by this distribution
                logger.debug("Group fuse doesn't exist. Skip test", self)
                return
            if not user in fuse_grp_members:
                logger.debug('User %s is not in group fuse' %user, self)
                raise MountException(_('%(user)s is not member of group \'fuse\'.\n '
                                        'Run \'sudo adduser %(user)s fuse\'. To apply '
                                        'changes logout and login again.\nLook at '
                                        '\'man backintime\' for further instructions.')
                                        % {'user': user})
Example #9
0
    def btnDiffClicked(self):
        sid1 = self.timeLine.currentSnapshotID()
        sid2 = self.comboDiff.currentSnapshotID()
        if not sid1 or not sid2:
            return

        path1 = sid1.pathBackup(self.path)
        path2 = sid2.pathBackup(self.path)

        #check if the 2 paths are different
        if path1 == path2:
            messagebox.critical(self, _('You can\'t compare a snapshot to itself'))
            return

        diffCmd = self.config.strValue('qt.diff.cmd', DIFF_CMD)
        diffParams = self.config.strValue('qt.diff.params', DIFF_PARAMS)

        if not tools.checkCommand(diffCmd):
            messagebox.critical(self, _('Command not found: %s') % diffCmd)
            return

        # prevent backup data from being accidentally overwritten
        # by create a temporary local copy and only open that one
        if not isinstance(sid1, snapshots.RootSnapshot):
            path1 = self.parent.tmpCopy(path1, sid1)
        if not isinstance(sid2, snapshots.RootSnapshot):
            path2 = self.parent.tmpCopy(path2, sid2)

        params = diffParams
        params = params.replace('%1', '"%s"' %path1)
        params = params.replace('%2', '"%s"' %path2)

        cmd = diffCmd + ' ' + params
        subprocess.Popen(shlex.split(cmd))
Example #10
0
    def btnDiffClicked(self):
        sid1 = self.timeLine.currentSnapshotID()
        sid2 = self.comboDiff.currentSnapshotID()
        if not sid1 or not sid2:
            return

        path1 = sid1.pathBackup(self.path)
        path2 = sid2.pathBackup(self.path)

        #check if the 2 paths are different
        if path1 == path2:
            messagebox.critical(self,
                                _('You can\'t compare a snapshot to itself'))
            return

        diffCmd = self.config.strValue('qt.diff.cmd', DIFF_CMD)
        diffParams = self.config.strValue('qt.diff.params', DIFF_PARAMS)

        if not tools.checkCommand(diffCmd):
            messagebox.critical(self, _('Command not found: %s') % diffCmd)
            return

        # prevent backup data from being accidentally overwritten
        # by create a temporary local copy and only open that one
        if not isinstance(sid1, snapshots.RootSnapshot):
            path1 = self.parent.tmpCopy(path1, sid1)
        if not isinstance(sid2, snapshots.RootSnapshot):
            path2 = self.parent.tmpCopy(path2, sid2)

        params = diffParams
        params = params.replace('%1', '"%s"' % path1)
        params = params.replace('%2', '"%s"' % path2)

        cmd = diffCmd + ' ' + params
        subprocess.Popen(shlex.split(cmd))
Example #11
0
 def test_check_remote_command_with_spaces(self):
     self.cfg.setSmartRemoveRunRemoteInBackground(tools.checkCommand('screen') and tools.checkCommand('flock'))
     self.remotePath = os.path.join(self.tmpDir.name, 'foo bar')
     self.cfg.setSshSnapshotsPath(self.remotePath)
     os.mkdir(self.remotePath)
     ssh = sshtools.SSH(cfg = self.cfg)
     ssh.checkRemoteCommands()
Example #12
0
    def checkFuse(self):
        """
        Check if command in self.mountproc is installed and user is part of
        group ``fuse``.

        Raises:
            exceptions.MountException:  if either command is not available or
                                        user is not in group fuse
        """
        logger.debug('Check fuse', self)
        if not tools.checkCommand(self.mountproc):
            logger.debug('%s is missing' % self.mountproc, self)
            raise MountException(
                _('%(proc)s not found. Please install e.g. %(install_command)s'
                  ) %
                {
                    'proc': self.mountproc,
                    'install_command': "'apt-get install %s'" % self.mountproc
                })
        if self.CHECK_FUSE_GROUP:
            user = self.config.user()
            try:
                fuse_grp_members = grp.getgrnam('fuse')[3]
            except KeyError:
                #group fuse doesn't exist. So most likely it isn't used by this distribution
                logger.debug("Group fuse doesn't exist. Skip test", self)
                return
            if not user in fuse_grp_members:
                logger.debug('User %s is not in group fuse' % user, self)
                raise MountException(
                    _('%(user)s is not member of group \'fuse\'.\n '
                      'Run \'sudo adduser %(user)s fuse\'. To apply '
                      'changes logout and login again.\nLook at '
                      '\'man backintime\' for further instructions.') %
                    {'user': user})
Example #13
0
from time import sleep

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import tools
import config
import configfile

#chroot jails used for building may have no UUID devices (because of tmpfs)
#we need to skip tests that require UUIDs
DISK_BY_UUID_AVAILABLE = os.path.exists(tools.DISK_BY_UUID)
UDEVADM_HAS_UUID = subprocess.Popen(['udevadm', 'info', '-e'],
                                    stdout = subprocess.PIPE,
                                    stderr = subprocess.DEVNULL
                                   ).communicate()[0].find(b'ID_FS_UUID=') > 0

RSYNC_INSTALLED = tools.checkCommand('rsync')

RSYNC_307_VERSION = """rsync  version 3.0.7  protocol version 30
Copyright (C) 1996-2009 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 32-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.
"""
RSYNC_310_VERSION = """rsync  version 3.1.0  protocol version 31
Copyright (C) 1996-2013 by Andrew Tridgell, Wayne Davison, and others.
Example #14
0
class TestSshKey(generic.TestCaseCfg):
    def test_sshKeyGen(self):
        with TemporaryDirectory() as tmp:
            secKey = os.path.join(tmp, 'key')
            pubKey = secKey + '.pub'
            # create new key
            self.assertTrue(sshtools.sshKeyGen(secKey))
            self.assertTrue(os.path.isfile(secKey))
            self.assertTrue(os.path.isfile(pubKey))

            # do not overwrite existing keys
            self.assertFalse(sshtools.sshKeyGen(secKey))

    @unittest.skipIf(getpass.getuser() != 'germar', 'Password login does not work on Travis-ci.')
    @unittest.skipIf(not generic.LOCAL_SSH, 'Skip as this test requires a local ssh server, public and private keys installed')
    def test_sshCopyId(self):
        with TemporaryDirectory() as tmp:
            secKey = os.path.join(tmp, 'key')
            pubKey = secKey + '.pub'
            authKeys = os.path.expanduser('~/.ssh/authorized_keys')
            authKeysSic = os.path.join(tmp, 'sic')
            if os.path.exists(authKeys):
                shutil.copyfile(authKeys, authKeysSic)
                os.remove(authKeys)

            # create new key
            sshtools.sshKeyGen(secKey)
            self.assertTrue(os.path.isfile(pubKey))
            with open(pubKey, 'rt') as f:
                pubKeyValue = f.read()

            try:
                # test copy pubKey
                self.assertTrue(sshtools.sshCopyId(pubKey, self.cfg.user(), 'localhost',
                                                   askPass = '******'))

                self.assertTrue(os.path.exists(authKeys))
                with open(authKeys, 'rt') as f:
                    self.assertIn(pubKeyValue, f.readlines())
            finally:
                # restore original ~/.ssh/authorized_keys file without test pubKey
                if os.path.exists(authKeysSic):
                    shutil.copyfile(authKeysSic, authKeys)

    @unittest.skipIf(not tools.checkCommand('ssh-keygen'),
                     "'ssh-keygen' not found.")
    def test_sshKeyFingerprint(self):
        self.assertIsNone(sshtools.sshKeyFingerprint(os.path.abspath(__file__)))

        with TemporaryDirectory() as d:
            key = os.path.join(d, 'key')
            cmd = ['ssh-keygen', '-q', '-N', '', '-f', key]
            proc = subprocess.Popen(cmd)
            proc.communicate()

            fingerprint = sshtools.sshKeyFingerprint(key)
            self.assertIsInstance(fingerprint, str)
            if fingerprint.startswith('SHA256'):
                self.assertEqual(len(fingerprint), 50)
                self.assertRegex(fingerprint, r'^SHA256:[a-zA-Z0-9/+]+$')
            else:
                self.assertEqual(len(fingerprint), 47)
                self.assertRegex(fingerprint, r'^[a-fA-F0-9:]+$')

    @unittest.skipIf(not generic.LOCAL_SSH, 'Skip as this test requires a local ssh server, public and private keys installed')
    def test_sshHostKey(self):
        fingerprint, keyHash, keyType = sshtools.sshHostKey('localhost')
        self.assertIsInstance(fingerprint, str)
        self.assertIsInstance(keyHash, str)
        self.assertIsInstance(keyType, str)
        if fingerprint.startswith('SHA256'):
            self.assertEqual(len(fingerprint), 50)
            self.assertRegex(fingerprint, r'^SHA256:[a-zA-Z0-9/+]+$')
        else:
            self.assertEqual(len(fingerprint), 47)
            self.assertRegex(fingerprint, r'^[a-fA-F0-9:]+$')

        self.assertIn(keyType, ('ECDSA', 'RSA'))

        hostKey = '/etc/ssh/ssh_host_{}_key.pub'.format(keyType.lower())
        self.assertTrue(os.path.exists(hostKey))
        self.assertEqual(3, len(keyHash.split()))
        try:
            with open(hostKey, 'rt') as f:
                pubKey = f.read().split()[1]
            self.assertEqual(pubKey, keyHash.split()[2])
        except (IOError, IndexError):
            pass

    def test_writeKnownHostFile(self):
        KEY = '|1|abcdefghijklmnopqrstuvwxyz= ecdsa-sha2-nistp256 AAAAABCDEFGHIJKLMNOPQRSTUVWXYZ='
        with TemporaryDirectory() as tmp:
            knownHosts = os.path.expanduser('~/.ssh/known_hosts')
            knownHostsSic = os.path.join(tmp, 'known_hosts')
            if os.path.exists(knownHosts):
                shutil.copyfile(knownHosts, knownHostsSic)

            try:
                sshtools.writeKnownHostsFile(KEY)

                self.assertTrue(os.path.exists(knownHosts))
                with open(knownHosts, 'rt') as f:
                    self.assertIn(KEY, [x.strip() for x in f.readlines()])
            finally:
                # restore original known_hosts file
                if os.path.exists(knownHostsSic):
                    shutil.copyfile(knownHostsSic, knownHosts)
Example #15
0
import subprocess
import shlex

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

import tools
import restoredialog
import messagebox
import qttools
import snapshots

_ = gettext.gettext

if tools.checkCommand('meld'):
    DIFF_CMD = 'meld'
    DIFF_PARAMS = '%1 %2'
elif tools.checkCommand('kompare'):
    DIFF_CMD = 'kompare'
    DIFF_PARAMS = '%1 %2'
else:
    DIFF_CMD = 'false'
    DIFF_PARAMS = '%1 %2'


class DiffOptionsDialog(QDialog):
    def __init__(self, parent):
        super(DiffOptionsDialog, self).__init__(parent)
        self.config = parent.config
Example #16
0
import subprocess
import shlex

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

import tools
import restoredialog
import messagebox
import qttools
import snapshots

_=gettext.gettext

if tools.checkCommand('meld'):
    DIFF_CMD = 'meld'
    DIFF_PARAMS = '%1 %2'
elif tools.checkCommand('kompare'):
    DIFF_CMD = 'kompare'
    DIFF_PARAMS = '%1 %2'
else:
    DIFF_CMD = 'false'
    DIFF_PARAMS = '%1 %2'

class DiffOptionsDialog(QDialog):
    def __init__(self, parent):
        super(DiffOptionsDialog, self).__init__(parent)
        self.config = parent.config

        import icon
Example #17
0
class TestTools(generic.TestCase):
    """
    All funtions test here come from tools.py
    """
    def setUp(self):
        super(TestTools, self).setUp()
        self.subproc = None

    def tearDown(self):
        super(TestTools, self).tearDown()
        self.killProcess()

    def createProcess(self, *args):
        dummyPath = os.path.join(os.path.dirname(__file__), generic.DUMMY)
        cmd = [dummyPath]
        cmd.extend(args)
        self.subproc = subprocess.Popen(cmd)
        return self.subproc.pid

    def killProcess(self):
        if self.subproc:
            self.subproc.kill()
            self.subproc.wait()
            self.subproc = None

    def test_sharePath(self):
        share = tools.sharePath()
        self.assertTrue(share.endswith('share'), 'share = {}'.format(share))

    def test_backintimePath(self):
        path = tools.backintimePath('common')
        self.assertRegex(path, r'.*/backintime.*/common$')

    def test_registerBackintimePath(self):
        path = tools.backintimePath('foo')
        tools.registerBackintimePath('foo')
        self.assertIn(path, sys.path)
        sys.path.remove(path)

    def test_runningFromSource(self):
        self.assertTrue(tools.runningFromSource())

    def test_addSourceToPathEnviron(self):
        source = tools.backintimePath('common')
        path = [x for x in os.getenv('PATH').split(':') if x != source]
        os.environ['PATH'] = ':'.join(path)

        tools.addSourceToPathEnviron()
        self.assertIn(source, os.environ['PATH'])

    def test_gitRevisionAndHash(self):
        ref, hashid = tools.gitRevisionAndHash()
        if isinstance(ref, str):
            self.assertGreater(len(ref), 0)
        else:
            self.assertIsNone(ref)

        if isinstance(hashid, str):
            self.assertEqual(len(hashid), 7)
        else:
            self.assertIsNone(hashid)

    def test_readFile(self):
        """
        Test the function readFile
        """
        test_tools_file = os.path.abspath(__file__)
        test_directory = os.path.dirname(test_tools_file)
        non_existing_file = os.path.join(test_directory, "nonExistingFile")

        self.assertIsInstance(tools.readFile(test_tools_file), str)
        self.assertIsNone(tools.readFile(non_existing_file))

        with NamedTemporaryFile('wt') as tmp:
            tmp.write('foo\nbar')
            tmp.flush()
            self.assertIsInstance(tools.readFile(tmp.name), str)
            self.assertEqual(tools.readFile(tmp.name), 'foo\nbar')

        tmp_gz = NamedTemporaryFile().name
        with gzip.open(tmp_gz + '.gz', 'wt') as f:
            f.write('foo\nbar')
            f.flush()
        self.assertIsInstance(tools.readFile(tmp_gz), str)
        self.assertEqual(tools.readFile(tmp_gz), 'foo\nbar')
        os.remove(tmp_gz + '.gz')

    def test_readFileLines(self):
        """
        Test the function readFileLines
        """
        test_tools_file = os.path.abspath(__file__)
        test_directory = os.path.dirname(test_tools_file)
        non_existing_file = os.path.join(test_directory, "nonExistingFile")

        output = tools.readFileLines(test_tools_file)
        self.assertIsInstance(output, list)
        self.assertGreaterEqual(len(output), 1)
        self.assertIsInstance(output[0], str)
        self.assertIsNone(tools.readFileLines(non_existing_file))

        with NamedTemporaryFile('wt') as tmp:
            tmp.write('foo\nbar')
            tmp.flush()
            self.assertIsInstance(tools.readFileLines(tmp.name), list)
            self.assertListEqual(tools.readFileLines(tmp.name), ['foo', 'bar'])

        tmp_gz = NamedTemporaryFile().name
        with gzip.open(tmp_gz + '.gz', 'wt') as f:
            f.write('foo\nbar')
            f.flush()
        self.assertIsInstance(tools.readFileLines(tmp_gz), list)
        self.assertEqual(tools.readFileLines(tmp_gz), ['foo', 'bar'])
        os.remove(tmp_gz + '.gz')

    def test_checkCommand(self):
        """
        Test the function checkCommand
        """
        self.assertFalse(tools.checkCommand(''))
        self.assertFalse(tools.checkCommand("notExistedCommand"))
        self.assertTrue(tools.checkCommand("ls"))
        self.assertTrue(tools.checkCommand('backintime'))

    def test_which(self):
        """
        Test the function which
        """
        self.assertRegex(tools.which("ls"), r'/.*/ls')
        self.assertEqual(tools.which('backintime'),
                         os.path.join(os.getcwd(), 'backintime'))
        self.assertIsNone(tools.which("notExistedCommand"))

    def test_makeDirs(self):
        self.assertFalse(tools.makeDirs('/'))
        self.assertTrue(tools.makeDirs(os.getcwd()))
        with TemporaryDirectory() as d:
            path = os.path.join(d, 'foo', 'bar')
            self.assertTrue(tools.makeDirs(path))

    def test_makeDirs_not_writeable(self):
        with TemporaryDirectory() as d:
            os.chmod(d, stat.S_IRUSR)
            path = os.path.join(d,
                                'foobar{}'.format(random.randrange(100, 999)))
            self.assertFalse(tools.makeDirs(path))

    def test_mkdir(self):
        self.assertFalse(tools.mkdir('/'))
        with TemporaryDirectory() as d:
            path = os.path.join(d, 'foo')
            self.assertTrue(tools.mkdir(path))
            for mode in (0o700, 0o644, 0o777):
                msg = 'new path should have octal permissions {0:#o}'.format(
                    mode)
                path = os.path.join(d, '{0:#o}'.format(mode))
                self.assertTrue(tools.mkdir(path, mode), msg)
                self.assertEqual('{0:o}'.format(os.stat(path).st_mode & 0o777),
                                 '{0:o}'.format(mode), msg)

    def test_pids(self):
        pids = tools.pids()
        self.assertGreater(len(pids), 0)
        self.assertIn(os.getpid(), pids)

    def test_processStat(self):
        pid = self.createProcess()
        stat = tools.processStat(pid)
        self.assertRegex(stat,
                         r'{} \({}\) \w .*'.format(pid, generic.DUMMY[:15]))

    @patch('builtins.open')
    def test_processStat_exception(self, mock_open):
        mock_open.side_effect = OSError()
        pid = self.createProcess()
        self.assertEqual(tools.processStat(pid), '')

    def test_processPaused(self):
        pid = self.createProcess()
        self.assertFalse(tools.processPaused(pid))
        self.subproc.send_signal(signal.SIGSTOP)
        sleep(0.01)
        self.assertTrue(tools.processPaused(pid))
        self.subproc.send_signal(signal.SIGCONT)
        sleep(0.01)
        self.assertFalse(tools.processPaused(pid))

    def test_processName(self):
        pid = self.createProcess()
        self.assertEqual(tools.processName(pid), generic.DUMMY[:15])

    def test_processCmdline(self):
        pid = self.createProcess()
        self.assertRegex(tools.processCmdline(pid),
                         r'.*/sh.*/common/test/dummy_test_process\.sh')
        self.killProcess()
        pid = self.createProcess('foo', 'bar')
        self.assertRegex(
            tools.processCmdline(pid),
            r'.*/sh.*/common/test/dummy_test_process\.sh.foo.bar')

    @patch('builtins.open')
    def test_processCmdline_exception(self, mock_open):
        mock_open.side_effect = OSError()
        pid = self.createProcess()
        self.assertEqual(tools.processCmdline(pid), '')

    def test_pidsWithName(self):
        self.assertEqual(len(tools.pidsWithName('nonExistingProcess')), 0)
        pid = self.createProcess()
        pids = tools.pidsWithName(generic.DUMMY)
        self.assertGreaterEqual(len(pids), 1)
        self.assertIn(pid, pids)

    def test_processExists(self):
        self.assertFalse(tools.processExists('nonExistingProcess'))
        pid = self.createProcess()
        self.assertTrue(tools.processExists(generic.DUMMY))

    def test_processAlive(self):
        """
        Test the function processAlive
        """
        #TODO: add test (in chroot) running proc as root and kill as non-root
        self.assertTrue(tools.processAlive(os.getpid()))
        pid = self.createProcess()
        self.assertTrue(tools.processAlive(pid))
        self.killProcess()
        self.assertFalse(tools.processAlive(pid))
        self.assertFalse(tools.processAlive(999999))
        with self.assertRaises(ValueError):
            tools.processAlive(0)
        self.assertFalse(tools.processAlive(-1))

    def test_checkXServer(self):
        try:
            tools.checkXServer()
        except Exception as e:
            self.fail('tools.ckeck_x_server() raised exception {}'.format(
                str(e)))

    def test_preparePath(self):
        path_with_slash_at_begin = "/test/path"
        path_without_slash_at_begin = "test/path"
        path_with_slash_at_end = "/test/path/"
        path_without_slash_at_end = "/test/path"
        self.assertEqual(tools.preparePath(path_with_slash_at_begin),
                         path_with_slash_at_begin)
        self.assertEqual(tools.preparePath(path_without_slash_at_begin),
                         path_with_slash_at_begin)
        self.assertEqual(tools.preparePath(path_without_slash_at_end),
                         path_without_slash_at_end)
        self.assertEqual(tools.preparePath(path_with_slash_at_end),
                         path_without_slash_at_end)

    def test_powerStatusAvailable(self):
        if tools.processExists('upowerd') and not generic.ON_TRAVIS:
            self.assertTrue(tools.powerStatusAvailable())
        else:
            self.assertFalse(tools.powerStatusAvailable())
        self.assertIsInstance(tools.onBattery(), bool)

    def test_rsyncCaps(self):
        if RSYNC_INSTALLED:
            caps = tools.rsyncCaps()
            self.assertIsInstance(caps, list)
            self.assertGreaterEqual(len(caps), 1)

        self.assertListEqual(tools.rsyncCaps(data=RSYNC_307_VERSION), [
            '64-bit files', '64-bit inums', '32-bit timestamps',
            '64-bit long ints', 'socketpairs', 'hardlinks', 'symlinks', 'IPv6',
            'batchfiles', 'inplace', 'append', 'ACLs', 'xattrs', 'iconv',
            'symtimes'
        ])

        self.assertListEqual(tools.rsyncCaps(data=RSYNC_310_VERSION), [
            'progress2', '64-bit files', '64-bit inums', '64-bit timestamps',
            '64-bit long ints', 'socketpairs', 'hardlinks', 'symlinks', 'IPv6',
            'batchfiles', 'inplace', 'append', 'ACLs', 'xattrs', 'iconv',
            'symtimes', 'prealloc'
        ])

    @unittest.skip('Not yet implemented')
    def test_rsyncPrefix(self):
        pass

    @unittest.skip('Not yet implemented')
    def test_tempFailureRetry(self):
        pass

    def test_md5sum(self):
        with NamedTemporaryFile() as f:
            f.write(b'foo')
            f.flush()

            self.assertEqual(tools.md5sum(f.name),
                             'acbd18db4cc2f85cedef654fccc4a4d8')

    def test_checkCronPattern(self):
        self.assertTrue(tools.checkCronPattern('0'))
        self.assertTrue(tools.checkCronPattern('0,10,13,15,17,20,23'))
        self.assertTrue(tools.checkCronPattern('*/6'))
        self.assertFalse(tools.checkCronPattern('a'))
        self.assertFalse(tools.checkCronPattern(' 1'))
        self.assertFalse(tools.checkCronPattern('0,10,13,1a,17,20,23'))
        self.assertFalse(tools.checkCronPattern('0,10,13, 15,17,20,23'))
        self.assertFalse(tools.checkCronPattern('*/6,8'))
        self.assertFalse(tools.checkCronPattern('*/6 a'))

    @unittest.skip('Not yet implemented')
    def test_checkHomeEncrypt(self):
        pass

    #envLoad and envSave tests are in TestToolsEnviron below

    @unittest.skip('Not yet implemented')
    def test_keyringSupported(self):
        pass

    @unittest.skip('Not yet implemented')
    def test_password(self):
        pass

    @unittest.skip('Not yet implemented')
    def test_setPassword(self):
        pass

    def test_mountpoint(self):
        self.assertEqual(tools.mountpoint('/nonExistingFolder/foo/bar'), '/')
        proc = os.path.join('/proc', str(os.getpid()), 'fd')
        self.assertEqual(tools.mountpoint(proc), '/proc')

    def test_decodeOctalEscape(self):
        self.assertEqual(tools.decodeOctalEscape('/mnt/normalPath'),
                         '/mnt/normalPath')
        self.assertEqual(
            tools.decodeOctalEscape('/mnt/path\\040with\\040space'),
            '/mnt/path with space')

    def test_mountArgs(self):
        rootArgs = tools.mountArgs('/')
        self.assertIsInstance(rootArgs, list)
        self.assertGreaterEqual(len(rootArgs), 3)
        self.assertEqual(rootArgs[1], '/')

        procArgs = tools.mountArgs('/proc')
        self.assertGreaterEqual(len(procArgs), 3)
        self.assertEqual(procArgs[0], 'proc')
        self.assertEqual(procArgs[1], '/proc')
        self.assertEqual(procArgs[2], 'proc')

    def test_device(self):
        self.assertEqual(tools.device('/proc'), 'proc')
        self.assertRegex(tools.device('/sys'), r'sys.*')
        self.assertRegex(tools.device('/nonExistingFolder/foo/bar'),
                         r'/dev/.*')

    def test_filesystem(self):
        self.assertEqual(tools.filesystem('/proc'), 'proc')
        self.assertRegex(tools.filesystem('/sys'), r'sys.*')
        self.assertRegex(
            tools.filesystem('/nonExistingFolder/foo/bar').lower(),
            r'(:?ext[2-4]|xfs|zfs|jfs|raiserfs|btrfs)')

    # tools.uuidFromDev() get called from tools.uuidFromPath.
    # So we skip an extra unittest as it's hard to find a dev on all systems
    @unittest.skipIf(not DISK_BY_UUID_AVAILABLE and not UDEVADM_HAS_UUID,
                     'No UUIDs available on this system.')
    def test_uuidFromPath(self):
        uuid = tools.uuidFromPath('/nonExistingFolder/foo/bar')
        self.assertIsInstance(uuid, str)
        self.assertRegex(uuid.lower(), r'^[a-f0-9\-]+$')
        self.assertEqual(len(uuid.replace('-', '')), 32)

    @unittest.skipIf(not DISK_BY_UUID_AVAILABLE and not UDEVADM_HAS_UUID,
                     'No UUIDs available on this system.')
    def test_filesystemMountInfo(self):
        """
        Basic sanity checks on returned structure
        """
        mounts = tools.filesystemMountInfo()
        self.assertIsInstance(mounts, dict)
        self.assertGreater(len(mounts.items()), 0)
        self.assertIn('/', mounts)
        self.assertIn('original_uuid', mounts.get('/'))

    @unittest.skip('Not yet implemented')
    def test_wrapLine(self):
        pass

    def test_syncfs(self):
        self.assertTrue(tools.syncfs())

    def test_isRoot(self):
        self.assertIsInstance(tools.isRoot(), bool)

    def test_usingSudo(self):
        self.assertIsInstance(tools.usingSudo(), bool)

    def test_patternHasNotEncryptableWildcard(self):
        self.assertFalse(tools.patternHasNotEncryptableWildcard('foo'))
        self.assertFalse(tools.patternHasNotEncryptableWildcard('/foo'))
        self.assertFalse(tools.patternHasNotEncryptableWildcard('foo/*/bar'))
        self.assertFalse(tools.patternHasNotEncryptableWildcard('foo/**/bar'))
        self.assertFalse(tools.patternHasNotEncryptableWildcard('*/foo'))
        self.assertFalse(tools.patternHasNotEncryptableWildcard('**/foo'))
        self.assertFalse(tools.patternHasNotEncryptableWildcard('foo/*'))
        self.assertFalse(tools.patternHasNotEncryptableWildcard('foo/**'))

        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo?'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo[1-2]'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo*'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('*foo'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('**foo'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('*.foo'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo*bar'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo**bar'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo*/bar'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo**/bar'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo/*bar'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo/**bar'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('foo/*/bar*'))
        self.assertTrue(tools.patternHasNotEncryptableWildcard('*foo/*/bar'))

    def test_readTimeStamp(self):
        with NamedTemporaryFile('wt') as f:
            f.write('20160127 0124')
            f.flush()
            self.assertEqual(tools.readTimeStamp(f.name),
                             datetime(2016, 1, 27, 1, 24))

        with NamedTemporaryFile('wt') as f:
            f.write('20160127')
            f.flush()
            self.assertEqual(tools.readTimeStamp(f.name),
                             datetime(2016, 1, 27, 0, 0))

    def test_writeTimeStamp(self):
        with NamedTemporaryFile('rt') as f:
            tools.writeTimeStamp(f.name)
            s = f.read().strip('\n')
            self.assertTrue(s.replace(' ', '').isdigit())
            self.assertEqual(len(s), 13)

    @unittest.skip('Not yet implemented')
    def test_inhibitSuspend(self):
        pass

    @unittest.skip('Not yet implemented')
    def test_unInhibitSuspend(self):
        pass

    @unittest.skipIf(not tools.checkCommand('crontab'), "'crontab' not found.")
    def test_readWriteCrontab(self):
        now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        oldCrontab = tools.readCrontab()
        self.assertIsInstance(oldCrontab, list)

        testLine = '#BackInTime Unittest from {}. Test probably failed. You can remove this line.'.format(
            now)
        self.assertTrue(tools.writeCrontab(oldCrontab + [
            testLine,
        ]))

        newCrontab = tools.readCrontab()
        self.assertIn(testLine, newCrontab)
        self.assertEqual(len(newCrontab), len(oldCrontab) + 1)

        self.assertTrue(tools.writeCrontab(oldCrontab))
        if oldCrontab:
            self.assertListEqual(oldCrontab, tools.readCrontab())

    def test_splitCommands(self):
        ret = list(
            tools.splitCommands(['echo foo;'],
                                head='echo start;',
                                tail='echo end',
                                maxLength=40))
        self.assertEqual(len(ret), 1)
        self.assertEqual(ret[0], 'echo start;echo foo;echo end')

        ret = list(
            tools.splitCommands(['echo foo;'] * 3,
                                head='echo start;',
                                tail='echo end',
                                maxLength=40))
        self.assertEqual(len(ret), 2)
        self.assertEqual(ret[0], 'echo start;echo foo;echo foo;echo end')
        self.assertEqual(ret[1], 'echo start;echo foo;echo end')

        ret = list(
            tools.splitCommands(['echo foo;'] * 3,
                                head='echo start;',
                                tail='echo end',
                                maxLength=0))
        self.assertEqual(len(ret), 1)
        self.assertEqual(ret[0],
                         'echo start;echo foo;echo foo;echo foo;echo end')

        ret = list(
            tools.splitCommands(['echo foo;'] * 3,
                                head='echo start;',
                                tail='echo end',
                                maxLength=-10))
        self.assertEqual(len(ret), 1)
        self.assertEqual(ret[0],
                         'echo start;echo foo;echo foo;echo foo;echo end')

    def test_isIPv6Address(self):
        self.assertTrue(tools.isIPv6Address('fd00:0::5'))
        self.assertTrue(tools.isIPv6Address('2001:db8:0:8d3:0:8a2e:70:7344'))
        self.assertFalse(tools.isIPv6Address('foo.bar'))
        self.assertFalse(tools.isIPv6Address('192.168.1.1'))
        self.assertFalse(tools.isIPv6Address('fd00'))

    def test_excapeIPv6Address(self):
        self.assertEqual(tools.escapeIPv6Address('fd00:0::5'), '[fd00:0::5]')
        self.assertEqual(
            tools.escapeIPv6Address('2001:db8:0:8d3:0:8a2e:70:7344'),
            '[2001:db8:0:8d3:0:8a2e:70:7344]')
        self.assertEqual(tools.escapeIPv6Address('foo.bar'), 'foo.bar')
        self.assertEqual(tools.escapeIPv6Address('192.168.1.1'), '192.168.1.1')
        self.assertEqual(tools.escapeIPv6Address('fd00'), 'fd00')

    def test_camelCase(self):
        self.assertEqual(tools.camelCase('foo'), 'Foo')
        self.assertEqual(tools.camelCase('Foo'), 'Foo')
        self.assertEqual(tools.camelCase('foo_bar'), 'FooBar')
        self.assertEqual(tools.camelCase('foo_Bar'), 'FooBar')
Example #18
0
from time import sleep

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import tools
import config
import configfile

#chroot jails used for building may have no UUID devices (because of tmpfs)
#we need to skip tests that require UUIDs
DISK_BY_UUID_AVAILABLE = os.path.exists(tools.DISK_BY_UUID)
UDEVADM_HAS_UUID = subprocess.Popen(
    ['udevadm', 'info', '-e'],
    stdout=subprocess.PIPE,
    stderr=subprocess.DEVNULL).communicate()[0].find(b'ID_FS_UUID=') > 0

RSYNC_INSTALLED = tools.checkCommand('rsync')

RSYNC_307_VERSION = """rsync  version 3.0.7  protocol version 30
Copyright (C) 1996-2009 by Andrew Tridgell, Wayne Davison, and others.
Web site: http://rsync.samba.org/
Capabilities:
    64-bit files, 64-bit inums, 32-bit timestamps, 64-bit long ints,
    socketpairs, hardlinks, symlinks, IPv6, batchfiles, inplace,
    append, ACLs, xattrs, iconv, symtimes

rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
are welcome to redistribute it under certain conditions.  See the GNU
General Public Licence for details.
"""
RSYNC_310_VERSION = """rsync  version 3.1.0  protocol version 31
Copyright (C) 1996-2013 by Andrew Tridgell, Wayne Davison, and others.