Blame tests/support.py

Packit 6f3914
# -*- coding: utf-8 -*-
Packit 6f3914
Packit 6f3914
# Copyright (C) 2012-2018 Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
# This copyrighted material is made available to anyone wishing to use,
Packit 6f3914
# modify, copy, or redistribute it subject to the terms and conditions of
Packit 6f3914
# the GNU General Public License v.2, or (at your option) any later version.
Packit 6f3914
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit 6f3914
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit 6f3914
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit 6f3914
# Public License for more details.  You should have received a copy of the
Packit 6f3914
# GNU General Public License along with this program; if not, write to the
Packit 6f3914
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6f3914
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit 6f3914
# source code or documentation are not subject to the GNU General Public
Packit 6f3914
# License and may only be used or replicated with the express permission of
Packit 6f3914
# Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
Packit 6f3914
from __future__ import absolute_import
Packit 6f3914
from __future__ import unicode_literals
Packit 6f3914
Packit 6f3914
import contextlib
Packit 6f3914
import logging
Packit 6f3914
import os
Packit 6f3914
import re
Packit Service 8b25b4
import shutil
Packit 6f3914
import sys
Packit Service 8b25b4
import tempfile
Packit 6f3914
import unittest
Packit 6f3914
from functools import reduce
Packit 6f3914
Packit 6f3914
import hawkey
Packit 6f3914
import hawkey.test
Packit 6f3914
import libdnf.transaction
Packit 6f3914
Packit 6f3914
import dnf
Packit 6f3914
import dnf.conf
Packit 6f3914
import dnf.cli.cli
Packit 6f3914
import dnf.cli.demand
Packit 6f3914
import dnf.cli.option_parser
Packit 6f3914
import dnf.comps
Packit 6f3914
import dnf.exceptions
Packit 6f3914
import dnf.goal
Packit 6f3914
import dnf.i18n
Packit 6f3914
import dnf.package
Packit 6f3914
import dnf.persistor
Packit 6f3914
import dnf.pycomp
Packit 6f3914
import dnf.repo
Packit 6f3914
import dnf.sack
Packit 6f3914
Packit 6f3914
Packit 6f3914
if dnf.pycomp.PY3:
Packit 6f3914
    from unittest import mock
Packit 6f3914
    from unittest.mock import MagicMock, mock_open
Packit 6f3914
else:
Packit 6f3914
    from tests import mock
Packit 6f3914
    from tests.mock import MagicMock
Packit 6f3914
Packit 6f3914
    def mock_open(mock=None, data=None):
Packit 6f3914
        if mock is None:
Packit 6f3914
            mock = MagicMock(spec=file)
Packit 6f3914
Packit 6f3914
        handle = MagicMock(spec=file)
Packit 6f3914
        handle.write.return_value = None
Packit 6f3914
        if data is None:
Packit 6f3914
            handle.__enter__.return_value = handle
Packit 6f3914
        else:
Packit 6f3914
            handle.__enter__.return_value = data
Packit 6f3914
        mock.return_value = handle
Packit 6f3914
        return mock
Packit 6f3914
Packit 6f3914
Packit 6f3914
logger = logging.getLogger('dnf')
Packit 6f3914
skip = unittest.skip
Packit 6f3914
Packit 6f3914
TRACEBACK_RE = re.compile(
Packit 6f3914
    r'(Traceback \(most recent call last\):\n'
Packit 6f3914
    r'(?:  File "[^"\n]+", line \d+, in \w+\n'
Packit 6f3914
    r'(?:    .+\n)?)+'
Packit 6f3914
    r'\S.*\n)')
Packit 6f3914
REASONS = {
Packit 6f3914
    'hole': 'group',
Packit 6f3914
    'pepper': 'group',
Packit 6f3914
    'right': 'dep',
Packit 6f3914
    'tour': 'group',
Packit 6f3914
    'trampoline': 'group',
Packit 6f3914
}
Packit 6f3914
# @System.repo doesn't provide sha1header/pkgid
Packit 6f3914
# the checksum is computed from an empty string
Packit 6f3914
RPMDB_CHECKSUM = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
Packit 6f3914
TOTAL_RPMDB_COUNT = 10
Packit 6f3914
SYSTEM_NSOLVABLES = TOTAL_RPMDB_COUNT
Packit 6f3914
MAIN_NSOLVABLES = 9
Packit 6f3914
UPDATES_NSOLVABLES = 4
Packit 6f3914
AVAILABLE_NSOLVABLES = MAIN_NSOLVABLES + UPDATES_NSOLVABLES
Packit Service 49e6e8
TOTAL_GROUPS = 5
Packit 6f3914
TOTAL_NSOLVABLES = SYSTEM_NSOLVABLES + AVAILABLE_NSOLVABLES
Packit 6f3914
Packit 6f3914
Packit 6f3914
# testing infrastructure
Packit 6f3914
Packit 6f3914
Packit 6f3914
def dnf_toplevel():
Packit 6f3914
    return os.path.normpath(os.path.join(__file__, '../../'))
Packit 6f3914
Packit 6f3914
Packit 6f3914
def repo(reponame):
Packit 6f3914
    return os.path.join(REPO_DIR, reponame)
Packit 6f3914
Packit 6f3914
Packit 6f3914
def resource_path(path):
Packit 6f3914
    this_dir = os.path.dirname(__file__)
Packit 6f3914
    return os.path.join(this_dir, path)
Packit 6f3914
Packit 6f3914
Packit 6f3914
REPO_DIR = resource_path('repos')
Packit 6f3914
COMPS_PATH = os.path.join(REPO_DIR, 'main_comps.xml')
Packit 6f3914
NONEXISTENT_FILE = resource_path('does-not/exist')
Packit 6f3914
TOUR_44_PKG_PATH = resource_path('repos/rpm/tour-4-4.noarch.rpm')
Packit 6f3914
TOUR_50_PKG_PATH = resource_path('repos/rpm/tour-5-0.noarch.rpm')
Packit 6f3914
TOUR_51_PKG_PATH = resource_path('repos/rpm/tour-5-1.noarch.rpm')
Packit 6f3914
USER_RUNDIR = '/tmp/dnf-user-rundir'
Packit 6f3914
Packit 6f3914
Packit 6f3914
# often used query
Packit 6f3914
Packit 6f3914
Packit 6f3914
def installed_but(sack, *args):
Packit 6f3914
    q = sack.query().filter(reponame__eq=hawkey.SYSTEM_REPO_NAME)
Packit 6f3914
    return reduce(lambda query, name: query.filter(name__neq=name), args, q)
Packit 6f3914
Packit 6f3914
Packit 6f3914
# patching the stdout
Packit 6f3914
Packit 6f3914
Packit 6f3914
@contextlib.contextmanager
Packit 6f3914
def patch_std_streams():
Packit 6f3914
    with mock.patch('sys.stdout', new_callable=dnf.pycomp.StringIO) as stdout, \
Packit 6f3914
            mock.patch('sys.stderr', new_callable=dnf.pycomp.StringIO) as stderr:
Packit 6f3914
        yield (stdout, stderr)
Packit 6f3914
Packit 6f3914
Packit 6f3914
@contextlib.contextmanager
Packit 6f3914
def wiretap_logs(logger_name, level, stream):
Packit 6f3914
    """Record *logger_name* logs of at least *level* into the *stream*."""
Packit 6f3914
    logger = logging.getLogger(logger_name)
Packit 6f3914
Packit 6f3914
    orig_level = logger.level
Packit 6f3914
    logger.setLevel(level)
Packit 6f3914
Packit 6f3914
    handler = logging.StreamHandler(stream)
Packit 6f3914
    orig_handlers = logger.handlers
Packit 6f3914
    logger.handlers = []
Packit 6f3914
    logger.addHandler(handler)
Packit 6f3914
Packit 6f3914
    try:
Packit 6f3914
        yield stream
Packit 6f3914
    finally:
Packit 6f3914
        logger.removeHandler(handler)
Packit 6f3914
        logger.setLevel(orig_level)
Packit 6f3914
        logger.handlers = orig_handlers
Packit 6f3914
Packit 6f3914
Packit 6f3914
def command_configure(cmd, args):
Packit 6f3914
    parser = dnf.cli.option_parser.OptionParser()
Packit 6f3914
    args = [cmd._basecmd] + args
Packit 6f3914
    parser.parse_main_args(args)
Packit 6f3914
    parser.parse_command_args(cmd, args)
Packit 6f3914
    return cmd.configure()
Packit 6f3914
Packit 6f3914
Packit 6f3914
def command_run(cmd, args):
Packit 6f3914
    command_configure(cmd, args)
Packit 6f3914
    return cmd.run()
Packit 6f3914
Packit 6f3914
class Base(dnf.Base):
Packit 6f3914
    def __init__(self, *args, **kwargs):
Packit 6f3914
        with mock.patch('dnf.rpm.detect_releasever', return_value=69):
Packit 6f3914
            super(Base, self).__init__(*args, **kwargs)
Packit 6f3914
Packit 6f3914
# mock objects
Packit 6f3914
Packit 6f3914
Packit 6f3914
def mock_comps(history, seed_history):
Packit 6f3914
    comps = dnf.comps.Comps()
Packit 6f3914
    comps._add_from_xml_filename(COMPS_PATH)
Packit 6f3914
Packit 6f3914
    if seed_history:
Packit 6f3914
        name = 'Peppers'
Packit 6f3914
        pkg_types = dnf.comps.MANDATORY
Packit 6f3914
        swdb_group = history.group.new(name, name, name, pkg_types)
Packit 6f3914
        for pkg_name in ['hole', 'lotus']:
Packit 6f3914
            swdb_group.addPackage(pkg_name, True, dnf.comps.MANDATORY)
Packit 6f3914
        history.group.install(swdb_group)
Packit 6f3914
Packit 6f3914
        name = 'somerset'
Packit 6f3914
        pkg_types = dnf.comps.MANDATORY
Packit 6f3914
        swdb_group = history.group.new(name, name, name, pkg_types)
Packit 6f3914
        for pkg_name in ['pepper', 'trampoline', 'lotus']:
Packit 6f3914
            swdb_group.addPackage(pkg_name, True, dnf.comps.MANDATORY)
Packit 6f3914
        history.group.install(swdb_group)
Packit 6f3914
Packit 6f3914
        name = 'sugar-desktop-environment'
Packit 6f3914
        pkg_types = dnf.comps.ALL_TYPES
Packit 6f3914
        swdb_env = history.env.new(name, name, name, pkg_types)
Packit 6f3914
        for group_id in ['Peppers', 'somerset']:
Packit 6f3914
            swdb_env.addGroup(group_id, True, dnf.comps.MANDATORY)
Packit 6f3914
        history.env.install(swdb_env)
Packit 6f3914
    return comps
Packit 6f3914
Packit 6f3914
Packit 6f3914
def mock_logger():
Packit 6f3914
    return mock.create_autospec(logger)
Packit 6f3914
Packit 6f3914
Packit 6f3914
class _BaseStubMixin(object):
Packit 6f3914
    """A reusable class for creating `dnf.Base` stubs.
Packit 6f3914
Packit 6f3914
    See also: hawkey/test/python/__init__.py.
Packit 6f3914
Packit 6f3914
    Note that currently the used TestSack has always architecture set to
Packit 6f3914
    "x86_64". This is to get the same behavior when running unit tests on
Packit 6f3914
    different arches.
Packit 6f3914
Packit 6f3914
    """
Packit Service 8b25b4
    def __init__(self, *extra_repos, **config_opts):
Packit Service 8b25b4
        super(_BaseStubMixin, self).__init__(FakeConf(**config_opts))
Packit 6f3914
        for r in extra_repos:
Packit 6f3914
            repo = MockRepo(r, self.conf)
Packit 6f3914
            repo.enable()
Packit 6f3914
            self._repos.add(repo)
Packit 6f3914
Packit 6f3914
        self._repo_persistor = FakePersistor()
Packit 6f3914
        self._ds_callback = mock.Mock()
Packit 6f3914
        self._history = None
Packit Service 8b25b4
        self._closed = False
Packit 6f3914
        self._closing = False
Packit 6f3914
Packit 6f3914
    def add_test_dir_repo(self, id_, cachedir):
Packit 6f3914
        """Add a repository located in a directory in the tests."""
Packit 6f3914
        repo = dnf.repo.Repo(id_, cachedir)
Packit 6f3914
        repo.baseurl = ['file://%s/%s' % (REPO_DIR, repo.id)]
Packit 6f3914
        self.repos.add(repo)
Packit 6f3914
        return repo
Packit 6f3914
Packit 6f3914
    def close(self):
Packit 6f3914
        self._closing = True
Packit 6f3914
        super(_BaseStubMixin, self).close()
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def history(self):
Packit 6f3914
        if self._history:
Packit 6f3914
            return self._history
Packit 6f3914
        else:
Packit 6f3914
            self._history = super(_BaseStubMixin, self).history
Packit 6f3914
            if not self._closing:
Packit 6f3914
                # don't reset db on close, it causes several tests to fail
Packit 6f3914
                self._history.reset_db()
Packit 6f3914
            return self._history
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def sack(self):
Packit 6f3914
        if self._sack:
Packit 6f3914
            return self._sack
Packit 6f3914
        return self.init_sack()
Packit 6f3914
Packit 6f3914
    def _build_comps_solver(self):
Packit 6f3914
        return dnf.comps.Solver(self.history, self._comps,
Packit 6f3914
                                REASONS.get)
Packit 6f3914
Packit 6f3914
    def _activate_persistor(self):
Packit 6f3914
        pass
Packit 6f3914
Packit 6f3914
    def init_sack(self):
Packit 6f3914
        # Create the Sack, tell it how to build packages, passing in the Package
Packit 6f3914
        # class and a Base reference.
Packit 6f3914
        self._sack = TestSack(REPO_DIR, self)
Packit 6f3914
        self._sack.load_system_repo()
Packit 6f3914
        for repo in self.repos.iter_enabled():
Packit 6f3914
            if repo.__class__ is dnf.repo.Repo:
Packit 6f3914
                self._add_repo_to_sack(repo)
Packit 6f3914
            else:
Packit 6f3914
                fn = "%s.repo" % repo.id
Packit 6f3914
                self._sack.load_test_repo(repo.id, fn)
Packit 6f3914
Packit 6f3914
        self._sack._configure(self.conf.installonlypkgs)
Packit 6f3914
        self._goal = dnf.goal.Goal(self._sack)
Packit 6f3914
        return self._sack
Packit 6f3914
Packit 6f3914
    def mock_cli(self):
Packit 6f3914
        stream = dnf.pycomp.StringIO()
Packit 6f3914
        logger = logging.getLogger('test')
Packit 6f3914
        logger.setLevel(logging.DEBUG)
Packit 6f3914
        logger.addHandler(logging.StreamHandler(stream))
Packit 6f3914
        return mock.Mock(base=self, log_stream=stream, logger=logger,
Packit 6f3914
                         demands=dnf.cli.demand.DemandSheet())
Packit 6f3914
Packit 6f3914
    def read_mock_comps(self, seed_history=True):
Packit 6f3914
        self._comps = mock_comps(self.history, seed_history)
Packit 6f3914
        return self._comps
Packit 6f3914
Packit 6f3914
    def read_all_repos(self, opts=None):
Packit 6f3914
        for repo in self.repos.values():
Packit 6f3914
            repo._configure_from_options(opts)
Packit 6f3914
Packit 6f3914
    def set_debuglevel(self, level):
Packit 6f3914
        self.conf._set_value('debuglevel', level, dnf.conf.PRIO_RUNTIME)
Packit 6f3914
Packit 6f3914
Packit 6f3914
class BaseCliStub(_BaseStubMixin, dnf.cli.cli.BaseCli):
Packit 6f3914
    """A class mocking `dnf.cli.cli.BaseCli`."""
Packit 6f3914
Packit Service 8b25b4
    def __init__(self, *extra_repos, **config_opts):
Packit 6f3914
        """Initialize the base."""
Packit Service 8b25b4
        super(BaseCliStub, self).__init__(*extra_repos, **config_opts)
Packit 6f3914
        self.output.term = MockTerminal()
Packit 6f3914
Packit 6f3914
Packit 6f3914
class DemandsStub(object):
Packit 6f3914
    pass
Packit 6f3914
Packit 6f3914
Packit 6f3914
class CliStub(object):
Packit 6f3914
    """A class mocking `dnf.cli.Cli`."""
Packit 6f3914
Packit 6f3914
    def __init__(self, base):
Packit 6f3914
        """Initialize the CLI."""
Packit 6f3914
        self.base = base
Packit 6f3914
        self.cli_commands = {}
Packit 6f3914
        self.demands = DemandsStub()
Packit 6f3914
        self.logger = logging.getLogger()
Packit 6f3914
        self.register_command(dnf.cli.commands.HelpCommand)
Packit 6f3914
Packit 6f3914
    def redirect_logger(self, stdout=None, stderr=None):
Packit 6f3914
        return
Packit 6f3914
Packit 6f3914
    def redirect_repo_progress(self, fo=sys.stderr):
Packit 6f3914
        return
Packit 6f3914
Packit 6f3914
    def register_command(self, command):
Packit 6f3914
        """Register given *command*."""
Packit 6f3914
        self.cli_commands.update({alias: command for alias in command.aliases})
Packit 6f3914
Packit 6f3914
Packit 6f3914
class MockOutput(object):
Packit 6f3914
    def __init__(self):
Packit 6f3914
        self.term = MockTerminal()
Packit 6f3914
Packit 6f3914
    def setup_progress_callbacks(self):
Packit 6f3914
        return (None, None)
Packit 6f3914
Packit 6f3914
Packit 6f3914
class MockPackage(object):
Packit 6f3914
    def __init__(self, nevra, repo=None):
Packit 6f3914
        self.baseurl = None
Packit 6f3914
        self._chksum = (None, None)
Packit 6f3914
        self.downloadsize = None
Packit 6f3914
        self._header = None
Packit 6f3914
        self.location = '%s.rpm' % nevra
Packit 6f3914
        self.repo = repo
Packit 6f3914
        self.reponame = None if repo is None else repo.id
Packit 6f3914
        self.str = nevra
Packit 6f3914
        self.buildtime = 0
Packit 6f3914
        nevra = hawkey.split_nevra(nevra)
Packit 6f3914
        self.name = nevra.name
Packit 6f3914
        self.epoch = nevra.epoch
Packit 6f3914
        self.version = nevra.version
Packit 6f3914
        self.release = nevra.release
Packit 6f3914
        self.arch = nevra.arch
Packit 6f3914
        self.evr = '%(epoch)d:%(version)s-%(release)s' % vars(self)
Packit 6f3914
        self.pkgtup = (self.name, self.arch, str(self.epoch), self.version,
Packit 6f3914
                       self.release)
Packit 6f3914
Packit 6f3914
    def __str__(self):
Packit 6f3914
        return self.str
Packit 6f3914
Packit 6f3914
    def localPkg(self):
Packit 6f3914
        return os.path.join(self.repo.pkgdir, os.path.basename(self.location))
Packit 6f3914
Packit 6f3914
    def returnIdSum(self):
Packit 6f3914
        return self._chksum
Packit 6f3914
Packit 6f3914
Packit 6f3914
class MockRepo(dnf.repo.Repo):
Packit 6f3914
    def _valid(self):
Packit 6f3914
        return None
Packit 6f3914
Packit 6f3914
Packit 6f3914
class MockQuery(dnf.query.Query):
Packit 6f3914
    def __init__(self, query):
Packit 6f3914
        self.pkgs = [MockPackage(str(p)) for p in query.run()]
Packit 6f3914
        self.i = 0
Packit 6f3914
        self.n = len(self.pkgs)
Packit 6f3914
Packit 6f3914
    def __getitem__(self, key):
Packit 6f3914
        if key < self.n:
Packit 6f3914
            return self.pkgs[key]
Packit 6f3914
        else:
Packit 6f3914
            raise KeyError()
Packit 6f3914
Packit 6f3914
    def __iter__(self):
Packit 6f3914
        return self
Packit 6f3914
Packit 6f3914
    def __len__(self):
Packit 6f3914
        return self.n
Packit 6f3914
Packit 6f3914
    def filter(self, pkg):
Packit 6f3914
        self.pkgs = []
Packit 6f3914
        self.pkgs.extend(pkg)
Packit 6f3914
        self.n = len(self.pkgs)
Packit 6f3914
        return self
Packit 6f3914
Packit 6f3914
    def next(self):
Packit 6f3914
        return self.__next__()
Packit 6f3914
Packit 6f3914
    def __next__(self):
Packit 6f3914
        if self.i < self.n:
Packit 6f3914
            i = self.i
Packit 6f3914
            self.i += 1
Packit 6f3914
            return self.pkgs[i]
Packit 6f3914
        else:
Packit 6f3914
            raise StopIteration()
Packit 6f3914
Packit 6f3914
    def run(self):
Packit 6f3914
        return self.pkgs
Packit 6f3914
Packit 6f3914
Packit 6f3914
class MockTerminal(object):
Packit 6f3914
    def __init__(self):
Packit 6f3914
        self.MODE = {'bold': '', 'normal': ''}
Packit 6f3914
        self.columns = 80
Packit 6f3914
        self.real_columns = 80
Packit 6f3914
        self.reinit = mock.Mock()
Packit 6f3914
Packit 6f3914
    def bold(self, s):
Packit 6f3914
        return s
Packit 6f3914
Packit 6f3914
Packit 6f3914
class TestSack(hawkey.test.TestSackMixin, dnf.sack.Sack):
Packit 6f3914
    def __init__(self, repo_dir, base):
Packit 6f3914
        hawkey.test.TestSackMixin.__init__(self, repo_dir)
Packit 6f3914
        dnf.sack.Sack.__init__(self,
Packit 6f3914
                               arch=hawkey.test.FIXED_ARCH,
Packit 6f3914
                               pkgcls=dnf.package.Package,
Packit 6f3914
                               pkginitval=base,
Packit 6f3914
                               make_cache_dir=True)
Packit 6f3914
Packit 6f3914
Packit 6f3914
class MockBase(_BaseStubMixin, Base):
Packit 6f3914
    """A class mocking `dnf.Base`."""
Packit 6f3914
Packit 6f3914
Packit 6f3914
def mock_sack(*extra_repos):
Packit 6f3914
    return MockBase(*extra_repos).sack
Packit 6f3914
Packit 6f3914
Packit 6f3914
class FakeConf(dnf.conf.Conf):
Packit 6f3914
    def __init__(self, **kwargs):
Packit 6f3914
        super(FakeConf, self).__init__()
Packit 6f3914
        self.substitutions['releasever'] = 'Fedora69'
Packit 6f3914
        options = [
Packit 6f3914
            ('assumeyes', None),
Packit 6f3914
            ('best', False),
Packit 6f3914
            ('cachedir', dnf.const.TMPDIR),
Packit 6f3914
            ('clean_requirements_on_remove', False),
Packit 6f3914
            ('color', 'never'),
Packit 6f3914
            ('color_update_installed', 'normal'),
Packit 6f3914
            ('color_update_remote', 'normal'),
Packit 6f3914
            ('color_list_available_downgrade', 'dim'),
Packit 6f3914
            ('color_list_available_install', 'normal'),
Packit 6f3914
            ('color_list_available_reinstall', 'bold'),
Packit 6f3914
            ('color_list_available_upgrade', 'bold'),
Packit 6f3914
            ('color_list_installed_extra', 'bold'),
Packit 6f3914
            ('color_list_installed_newer', 'bold'),
Packit 6f3914
            ('color_list_installed_older', 'bold'),
Packit 6f3914
            ('color_list_installed_reinstall', 'normal'),
Packit 6f3914
            ('color_update_local', 'bold'),
Packit 6f3914
            ('debug_solver', False),
Packit 6f3914
            ('debuglevel', 2),
Packit 6f3914
            ('defaultyes', False),
Packit 6f3914
            ('disable_excludes', []),
Packit 6f3914
            ('diskspacecheck', True),
Packit 6f3914
            ('exclude', []),
Packit 6f3914
            ('includepkgs', []),
Packit 6f3914
            ('install_weak_deps', True),
Packit 6f3914
            ('history_record', False),
Packit 6f3914
            ('installonly_limit', 0),
Packit 6f3914
            ('installonlypkgs', ['kernel']),
Packit Service 8b25b4
            ('installroot', '/tmp/dnf-test-installroot/'),
Packit 6f3914
            ('ip_resolve', None),
Packit 6f3914
            ('multilib_policy', 'best'),
Packit 6f3914
            ('obsoletes', True),
Packit 6f3914
            ('persistdir', dnf.const.PERSISTDIR),
Packit 6f3914
            ('transformdb', False),
Packit 6f3914
            ('protected_packages', ["dnf"]),
Packit 6f3914
            ('plugins', False),
Packit 6f3914
            ('showdupesfromrepos', False),
Packit 6f3914
            ('tsflags', []),
Packit 6f3914
            ('strict', True),
Packit 6f3914
        ] + list(kwargs.items())
Packit 6f3914
        for optname, val in options:
Packit 6f3914
            self._set_value(optname, val, dnf.conf.PRIO_DEFAULT)
Packit 6f3914
Packit 6f3914
        # TODO: consolidate with dnf.cli.Cli._read_conf_file()
Packit 6f3914
        for opt in ('cachedir', 'logdir', 'persistdir'):
Packit 6f3914
            # don't prepend installroot if option was specified by user
Packit 6f3914
            # TODO: is this desired? ^^^ (tests won't pass without it ATM)
Packit 6f3914
            if opt in kwargs:
Packit 6f3914
                continue
Packit 6f3914
            self.prepend_installroot(opt)
Packit 6f3914
Packit Service 8b25b4
        try:
Packit Service 8b25b4
            os.makedirs(self.persistdir)
Packit Service 8b25b4
        except:
Packit Service 8b25b4
            pass
Packit Service 8b25b4
Packit 6f3914
    @property
Packit 6f3914
    def releasever(self):
Packit 6f3914
        return self.substitutions['releasever']
Packit 6f3914
Packit 6f3914
Packit 6f3914
class FakePersistor(object):
Packit 6f3914
    reset_last_makecache = False
Packit 6f3914
    expired_to_add = set()
Packit 6f3914
Packit 6f3914
    def get_expired_repos(self):
Packit 6f3914
        return set()
Packit 6f3914
Packit 6f3914
    def since_last_makecache(self):
Packit 6f3914
        return None
Packit 6f3914
Packit 6f3914
    def save(self):
Packit 6f3914
        pass
Packit 6f3914
Packit 6f3914
Packit 6f3914
# object matchers for asserts
Packit 6f3914
Packit 6f3914
Packit 6f3914
class ObjectMatcher(object):
Packit 6f3914
    """Class allowing partial matching of objects."""
Packit 6f3914
Packit 6f3914
    def __init__(self, type_=None, attrs=None):
Packit 6f3914
        """Initialize a matcher instance."""
Packit 6f3914
        self._type = type_
Packit 6f3914
        self._attrs = attrs
Packit 6f3914
Packit 6f3914
    def __eq__(self, other):
Packit 6f3914
        """Test whether this object is equal to the *other* one."""
Packit 6f3914
        if self._type is not None:
Packit 6f3914
            if type(other) is not self._type:
Packit 6f3914
                return False
Packit 6f3914
Packit 6f3914
        if self._attrs:
Packit 6f3914
            for attr, value in self._attrs.items():
Packit 6f3914
                if value != getattr(other, attr):
Packit 6f3914
                    return False
Packit 6f3914
        return True
Packit 6f3914
Packit 6f3914
    def __ne__(self, other):
Packit 6f3914
        """Test whether this object is not equal to the *other* one."""
Packit 6f3914
        return not self == other
Packit 6f3914
Packit 6f3914
    def __repr__(self):
Packit 6f3914
        """Compute the "official" string representation of this object."""
Packit 6f3914
        args_strs = []
Packit 6f3914
Packit 6f3914
        if self._type is not None:
Packit 6f3914
            args_strs.append('type_=%s' % repr(self._type))
Packit 6f3914
Packit 6f3914
        if self._attrs:
Packit 6f3914
            attrs_str = ', '.join('%s: %s' % (dnf.i18n.ucd(attr), repr(value))
Packit 6f3914
                                  for attr, value in self._attrs.items())
Packit 6f3914
            args_strs.append('attrs={%s}' % attrs_str)
Packit 6f3914
Packit 6f3914
        return '%s(%s)' % (type(self).__name__, ", ".join(args_strs))
Packit 6f3914
Packit 6f3914
Packit 6f3914
# test cases:
Packit 6f3914
Packit 6f3914
Packit 6f3914
class TestCase(unittest.TestCase):
Packit 6f3914
Packit 6f3914
    if not dnf.pycomp.PY3:
Packit 6f3914
        assertCountEqual = unittest.TestCase.assertItemsEqual
Packit 6f3914
        assertRegex = unittest.TestCase.assertRegexpMatches
Packit 6f3914
Packit 6f3914
    def assertEmpty(self, collection):
Packit 6f3914
        return self.assertEqual(len(collection), 0)
Packit 6f3914
Packit 6f3914
    def assertFile(self, path):
Packit 6f3914
        """Assert the given path is a file."""
Packit 6f3914
        return self.assertTrue(os.path.isfile(path))
Packit 6f3914
Packit 6f3914
    def assertLength(self, collection, length):
Packit 6f3914
        return self.assertEqual(len(collection), length)
Packit 6f3914
Packit 6f3914
    def assertPathDoesNotExist(self, path):
Packit 6f3914
        return self.assertFalse(os.access(path, os.F_OK))
Packit 6f3914
Packit 6f3914
    def assertStartsWith(self, string, what):
Packit 6f3914
        return self.assertTrue(string.startswith(what))
Packit 6f3914
Packit 6f3914
    def assertTracebackIn(self, end, string):
Packit 6f3914
        """Test that a traceback ending with line *end* is in the *string*."""
Packit 6f3914
        traces = (match.group() for match in TRACEBACK_RE.finditer(string))
Packit 6f3914
        self.assertTrue(any(trace.endswith(end) for trace in traces))
Packit 6f3914
Packit 6f3914
    def assertTransEqual(self, trans_pkgs, list):
Packit 6f3914
        return self.assertCountEqual([pkg.name for pkg in trans_pkgs], list)
Packit 6f3914
Packit 6f3914
Packit 6f3914
class DnfBaseTestCase(TestCase):
Packit 6f3914
Packit 6f3914
    # create base with specified test repos
Packit 6f3914
    REPOS = []
Packit 6f3914
Packit 6f3914
    # initialize mock sack
Packit 6f3914
    INIT_SACK = False
Packit 6f3914
Packit 6f3914
    # initialize self.base._transaction
Packit 6f3914
    INIT_TRANSACTION = False
Packit 6f3914
Packit 6f3914
    # False: self.base = MockBase()
Packit 6f3914
    # True: self.base = BaseCliStub()
Packit 6f3914
    BASE_CLI = False
Packit 6f3914
Packit 6f3914
    # None: self.cli = None
Packit 6f3914
    # "init": self.cli = dnf.cli.cli.Cli(self.base)
Packit 6f3914
    # "mock": self.cli = self.base.mock_cli()
Packit 6f3914
    # "stub": self.cli = StubCli(self.base)
Packit 6f3914
    CLI = None
Packit 6f3914
Packit 6f3914
    COMPS = False
Packit 6f3914
    COMPS_SEED_HISTORY = False
Packit 6f3914
    COMPS_SOLVER = False
Packit 6f3914
Packit 6f3914
    def setUp(self):
Packit Service 8b25b4
        self._installroot = tempfile.mkdtemp(prefix="dnf_test_installroot_")
Packit Service 8b25b4
Packit 6f3914
        if self.BASE_CLI:
Packit Service 8b25b4
            self.base = BaseCliStub(*self.REPOS, installroot=self._installroot)
Packit 6f3914
        else:
Packit Service 8b25b4
            self.base = MockBase(*self.REPOS, installroot=self._installroot)
Packit 6f3914
Packit 6f3914
        if self.CLI is None:
Packit 6f3914
            self.cli = None
Packit 6f3914
        elif self.CLI == "init":
Packit 6f3914
            self.cli = dnf.cli.cli.Cli(self.base)
Packit 6f3914
        elif self.CLI == "mock":
Packit 6f3914
            self.cli = self.base.mock_cli()
Packit 6f3914
        elif self.CLI == "stub":
Packit 6f3914
            self.cli = CliStub(self.base)
Packit 6f3914
        else:
Packit 6f3914
            raise ValueError("Invalid CLI value: {}".format(self.CLI))
Packit 6f3914
Packit 6f3914
        if self.COMPS:
Packit 6f3914
            self.base.read_mock_comps(seed_history=self.COMPS_SEED_HISTORY)
Packit 6f3914
Packit 6f3914
        if self.INIT_SACK:
Packit 6f3914
            self.base.init_sack()
Packit 6f3914
Packit 6f3914
        if self.INIT_TRANSACTION:
Packit 6f3914
            self.base._transaction = self.base.history.rpm
Packit 6f3914
Packit 6f3914
        if self.COMPS_SOLVER:
Packit 6f3914
            self.solver = dnf.comps.Solver(self.history, self.comps, REASONS.get)
Packit 6f3914
        else:
Packit 6f3914
            self.solver = None
Packit 6f3914
Packit 6f3914
    def tearDown(self):
Packit 6f3914
        self.base.close()
Packit Service 8b25b4
        if self._installroot.startswith("/tmp/"):
Packit Service 8b25b4
            shutil.rmtree(self._installroot)
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def comps(self):
Packit 6f3914
        return self.base.comps
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def goal(self):
Packit 6f3914
        return self.base._goal
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def history(self):
Packit 6f3914
        return self.base.history
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def sack(self):
Packit 6f3914
        return self.base.sack
Packit 6f3914
Packit 6f3914
    def _swdb_begin(self, tsis=None):
Packit 6f3914
        # history.beg() replaces persistor.commit()
Packit 6f3914
        tsis = tsis or []
Packit 6f3914
        self.history.beg("", [], tsis)
Packit 6f3914
Packit 6f3914
    def _swdb_end(self, tsis=None):
Packit 6f3914
        for tsi in self.history._swdb.getItems():
Packit 6f3914
            if tsi.getState() == libdnf.transaction.TransactionItemState_UNKNOWN:
Packit 6f3914
                tsi.setState(libdnf.transaction.TransactionItemState_DONE)
Packit 6f3914
        self.history.end("")
Packit 6f3914
        self.history.close()
Packit 6f3914
Packit 6f3914
    def _swdb_commit(self, tsis=None):
Packit 6f3914
        self._swdb_begin(tsis)
Packit 6f3914
        self._swdb_end()
Packit 6f3914
        self.history.close()
Packit 6f3914
Packit 6f3914
Packit 6f3914
class ResultTestCase(DnfBaseTestCase):
Packit 6f3914
Packit 6f3914
    allow_erasing = False
Packit 6f3914
Packit 6f3914
    def _get_installed(self, base):
Packit 6f3914
        try:
Packit 6f3914
            base.resolve(self.allow_erasing)
Packit 6f3914
        except dnf.exceptions.DepsolveError:
Packit 6f3914
            self.fail()
Packit 6f3914
Packit 6f3914
        installed = set(base.sack.query().installed())
Packit 6f3914
        for r in base._transaction.remove_set:
Packit 6f3914
            installed.remove(r)
Packit 6f3914
        installed.update(base._transaction.install_set)
Packit 6f3914
        return installed
Packit 6f3914
Packit 6f3914
    def assertResult(self, base, pkgs):
Packit 6f3914
        """Check whether the system contains the given pkgs.
Packit 6f3914
Packit 6f3914
        pkgs must be present. Any other pkgs result in an error. Pkgs are
Packit 6f3914
        present if they are in the rpmdb and are not REMOVEd or they are
Packit 6f3914
        INSTALLed.
Packit 6f3914
        """
Packit 6f3914
Packit 6f3914
        self.assertCountEqual(self._get_installed(base), pkgs)
Packit 6f3914
Packit 6f3914
    def installed_removed(self, base):
Packit 6f3914
        try:
Packit 6f3914
            base.resolve(self.allow_erasing)
Packit 6f3914
        except dnf.exceptions.DepsolveError:
Packit 6f3914
            self.fail()
Packit 6f3914
Packit 6f3914
        installed = base._transaction.install_set
Packit 6f3914
        removed = base._transaction.remove_set
Packit 6f3914
        return installed, removed