mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2018.3' into 'fluorine'
Conflicts: - tests/unit/states/test_virt.py - tests/unit/test_config.py
This commit is contained in:
commit
3f2712fbc1
19 changed files with 656 additions and 668 deletions
|
@ -223,6 +223,7 @@ verifier:
|
|||
sudo: true
|
||||
run_destructive: true
|
||||
transport: zeromq
|
||||
enable_filenames: true
|
||||
types:
|
||||
- ssh
|
||||
xml: /tmp/xml-unittests-output/
|
||||
|
|
|
@ -32,6 +32,46 @@ or the integration testing factions contain respective integration or unit
|
|||
test files for Salt execution modules.
|
||||
|
||||
|
||||
.. note::
|
||||
Salt's test framework provides for the option to only run tests which
|
||||
correspond to a given file (or set of files), via the ``--from-filenames``
|
||||
argument to ``runtests.py``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python /path/to/runtests.py --from-filenames=salt/modules/foo.py
|
||||
|
||||
Therefore, where possible, test files should be named to match the source
|
||||
files they are testing. For example, when writing tests for
|
||||
``salt/modules/foo.py``, unit tests should go into
|
||||
``tests/unit/modules/test_foo.py``, and integration tests should go into
|
||||
``tests/integration/modules/test_foo.py``.
|
||||
|
||||
However, integration tests are organized differently from unit tests, and
|
||||
this may not always be plausible. In these cases, to ensure that the proper
|
||||
tests are run for these files, they must be mapped in
|
||||
`tests/filename_map.yml`__.
|
||||
|
||||
The filename map is used to supplement the test framework's filename
|
||||
matching logic. This allows one to ensure that states correspnding to an
|
||||
execution module are also tested when ``--from-filenames`` includes that
|
||||
execution module. It can also be used for those cases where the path to a
|
||||
test file doesn't correspond directly to the file which is being tested
|
||||
(e.g. the ``shell``, ``spm``, and ``ssh`` integration tests, among others).
|
||||
Both glob expressions and regular expressions are permitted in the filename
|
||||
map.
|
||||
|
||||
|
||||
.. important::
|
||||
Test modules which don't map directly to the source file they are
|
||||
testing (using the naming convention described above), **must** be
|
||||
added to the ``ignore`` tuple in ``tests/unit/test_module_names.py``,
|
||||
in the ``test_module_name_source_match`` function. This unit test
|
||||
ensures that we maintain the naming convention for test files.
|
||||
|
||||
.. __: https://github.com/saltstack/salt/blob/develop/tests/filename_map.yml
|
||||
|
||||
|
||||
Integration Tests
|
||||
-----------------
|
||||
|
||||
|
@ -445,8 +485,8 @@ successfully. If a network connection is not detected, the test will not run.
|
|||
order for the test to be executed. Otherwise, the test is skipped.
|
||||
|
||||
`@requires_system_grains` -- Loads and passes the grains on the system as an
|
||||
keyword argument to the test function with the name `grains`.
|
||||
|
||||
keyword argument to the test function with the name `grains`.
|
||||
|
||||
`@skip_if_binaries_missing(['list', 'of', 'binaries'])` -- If called from inside a test,
|
||||
the test will be skipped if the binaries are not all present on the system.
|
||||
|
||||
|
|
|
@ -1335,6 +1335,7 @@ def id_():
|
|||
'''
|
||||
return {'id': __opts__.get('id', '')}
|
||||
|
||||
|
||||
_REPLACE_LINUX_RE = re.compile(r'\W(?:gnu/)?linux', re.IGNORECASE)
|
||||
|
||||
# This maps (at most) the first ten characters (no spaces, lowercased) of
|
||||
|
|
|
@ -169,6 +169,12 @@ def get_repo(name, config_path=_DEFAULT_CONFIG_PATH, with_packages=False):
|
|||
|
||||
:return: A dictionary containing information about the repository.
|
||||
:rtype: dict
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' aptly.get_repo name="test-repo"
|
||||
'''
|
||||
_validate_config(config_path)
|
||||
with_packages = six.text_type(bool(with_packages)).lower()
|
||||
|
@ -225,7 +231,7 @@ def new_repo(name, config_path=_DEFAULT_CONFIG_PATH, comment=None, component=Non
|
|||
'''
|
||||
_validate_config(config_path)
|
||||
|
||||
current_repo = __salt__['aptly.get_repo'](name=name)
|
||||
current_repo = __salt__['aptly.get_repo'](name=name, config_path=config_path)
|
||||
|
||||
if current_repo:
|
||||
log.debug('Repository already exists: %s', name)
|
||||
|
@ -242,7 +248,7 @@ def new_repo(name, config_path=_DEFAULT_CONFIG_PATH, comment=None, component=Non
|
|||
cmd.extend(['from', 'snapshot', from_snapshot])
|
||||
|
||||
_cmd_run(cmd)
|
||||
repo = __salt__['aptly.get_repo'](name=name)
|
||||
repo = __salt__['aptly.get_repo'](name=name, config_path=config_path)
|
||||
|
||||
if repo:
|
||||
log.debug('Created repo: %s', name)
|
||||
|
@ -286,7 +292,7 @@ def set_repo(name, config_path=_DEFAULT_CONFIG_PATH, comment=None, component=Non
|
|||
if settings[setting] is None:
|
||||
settings.pop(setting, None)
|
||||
|
||||
current_settings = __salt__['aptly.get_repo'](name=name)
|
||||
current_settings = __salt__['aptly.get_repo'](name=name, config_path=config_path)
|
||||
|
||||
if not current_settings:
|
||||
log.error('Unable to get repo: %s', name)
|
||||
|
@ -312,7 +318,7 @@ def set_repo(name, config_path=_DEFAULT_CONFIG_PATH, comment=None, component=Non
|
|||
cmd.append(name)
|
||||
|
||||
_cmd_run(cmd)
|
||||
new_settings = __salt__['aptly.get_repo'](name=name)
|
||||
new_settings = __salt__['aptly.get_repo'](name=name, config_path=config_path)
|
||||
|
||||
# Check the new repo settings to see if they have the desired values.
|
||||
for setting in settings:
|
||||
|
@ -347,7 +353,7 @@ def delete_repo(name, config_path=_DEFAULT_CONFIG_PATH, force=False):
|
|||
_validate_config(config_path)
|
||||
force = six.text_type(bool(force)).lower()
|
||||
|
||||
current_repo = __salt__['aptly.get_repo'](name=name)
|
||||
current_repo = __salt__['aptly.get_repo'](name=name, config_path=config_path)
|
||||
|
||||
if not current_repo:
|
||||
log.debug('Repository already absent: %s', name)
|
||||
|
@ -357,7 +363,7 @@ def delete_repo(name, config_path=_DEFAULT_CONFIG_PATH, force=False):
|
|||
'-force={}'.format(force), name]
|
||||
|
||||
_cmd_run(cmd)
|
||||
repo = __salt__['aptly.get_repo'](name=name)
|
||||
repo = __salt__['aptly.get_repo'](name=name, config_path=config_path)
|
||||
|
||||
if repo:
|
||||
log.error('Unable to remove repo: %s', name)
|
||||
|
|
227
tests/filename_map.yml
Normal file
227
tests/filename_map.yml
Normal file
|
@ -0,0 +1,227 @@
|
|||
'*':
|
||||
- unit.test_module_names
|
||||
- unit.test_doc
|
||||
- integration.modules.test_sysmod
|
||||
|
||||
salt/modules/(apk|aptpkg|ebuild|dpkg|freebsdpkg|mac_brew|mac_ports|openbsdpkg|opkg|pacman|pkgin|pkgng|pkg_resource|rpm|solarisips|solarispkg|win_pkg|xbpspkg|yumpkg|zypper)\.py:
|
||||
- unit.states.test_pkg
|
||||
- integration.modules.test_pkg
|
||||
- integration.states.test_pkg
|
||||
- integration.states.test_pkgrepo
|
||||
|
||||
salt/modules/(mac_user|useradd|pw_user|solaris_user|win_useradd)\.py:
|
||||
- unit.states.test_user
|
||||
- integration.states.test_user
|
||||
|
||||
salt/modules/(aix_group|groupadd|mac_group|pw_group|solaris_group|win_groupadd)\.py:
|
||||
- unit.states.test_group
|
||||
|
||||
salt/modules/(debian_service|freebsdservice|gentoo_service|launchctl|mac_service|netbsdservice|openbsdrcctl|openbsdservice|rh_service|runit|service|smf|systemd|upstart|win_service)\.py:
|
||||
- unit.states.test_service
|
||||
- integration.states.test_service
|
||||
|
||||
salt/modules/*apache.py:
|
||||
- unit.states.test_apache
|
||||
- unit.states.test_apache_conf
|
||||
- unit.states.test_apache_module
|
||||
- unit.states.test_apache_site
|
||||
|
||||
salt/modules/augeas_cfg.py:
|
||||
- unit.states.test_augeas
|
||||
|
||||
salt/modules/cp.py:
|
||||
- unit.modules.test_file
|
||||
- unit.states.test_file
|
||||
- integration.modules.test_file
|
||||
- integration.states.test_file
|
||||
|
||||
salt/modules/dockermod.py:
|
||||
- unit.states.test_docker_image
|
||||
- unit.states.test_docker_volume
|
||||
- unit.utils.test_docker
|
||||
- integration.states.test_docker_container
|
||||
- integration.states.test_docker_network
|
||||
|
||||
salt/modules/influx08.py:
|
||||
- unit.states.test_influxdb08_database
|
||||
- unit.states.test_influxdb08_user
|
||||
|
||||
salt/modules/mysql.py:
|
||||
- unit.states.test_mysql_user
|
||||
- unit.states.test_mysql_query
|
||||
- unit.states.test_mysql_grants
|
||||
|
||||
salt/modules/openvswitch.py:
|
||||
- unit.states.test_openvswitch_port
|
||||
|
||||
salt/(states|modules)/.*postgres.py:
|
||||
- unit.states.test_postgres
|
||||
- unit.states.test_postgres_cluster
|
||||
- unit.states.test_postgres_database
|
||||
- unit.states.test_postgres_extension
|
||||
- unit.states.test_postgres_group
|
||||
- unit.states.test_postgres_initdb
|
||||
- unit.states.test_postgres_language
|
||||
- unit.states.test_postgres_privileges
|
||||
- unit.states.test_postgres_schema
|
||||
- unit.states.test_postgres_user
|
||||
|
||||
salt/modules/rabbitmq.py:
|
||||
- unit.states.test_rabbitmq_cluster
|
||||
- unit.states.test_rabbitmq_plugin
|
||||
- unit.states.test_rabbitmq_policy
|
||||
- unit.states.test_rabbitmq_vhost
|
||||
- integration.states.test_rabbitmq_user
|
||||
- integration.states.test_rabbitmq_vhost
|
||||
|
||||
salt/modules/ssh.py:
|
||||
- unit.states.test_ssh_auth
|
||||
- unit.states.test_ssh_known_hosts
|
||||
|
||||
salt/auth/*:
|
||||
- integration.shell.test_auth
|
||||
|
||||
salt/cache/*:
|
||||
- unit.cache.test_cache
|
||||
|
||||
salt/cli/*:
|
||||
- integration.shell.test_arguments
|
||||
|
||||
salt/cli/call.py:
|
||||
- integration.shell.test_call
|
||||
|
||||
salt/cli/cp.py:
|
||||
- integration.shell.test_cp
|
||||
|
||||
salt/cli/key.py:
|
||||
- integration.shell.test_key
|
||||
|
||||
salt/cli/salt.py:
|
||||
- integration.cli.test_grains
|
||||
- integration.shell.test_enabled
|
||||
- integration.shell.test_matcher
|
||||
- integration.shell.test_saltcli
|
||||
|
||||
salt/client/*:
|
||||
- integration.client.test_kwarg
|
||||
- integration.client.test_runner
|
||||
- integration.client.test_standard
|
||||
|
||||
salt/cloud/*:
|
||||
- integration.shell.test_cloud
|
||||
|
||||
salt/cloud/__init__.py:
|
||||
- integration.cloud.test_cloud
|
||||
|
||||
salt/proxy/*:
|
||||
- integration.proxy.test_shell
|
||||
- integration.proxy.test_simple
|
||||
|
||||
salt/state.py:
|
||||
- integration.modules.test_state_jinja_filters
|
||||
- integration.states.test_compiler
|
||||
- integration.states.test_handle_error
|
||||
- integration.states.test_handle_iorder
|
||||
- integration.states.test_match
|
||||
- integration.states.test_renderers
|
||||
|
||||
salt/utils/decorators/*:
|
||||
- integration.modules.test_decorators
|
||||
|
||||
salt/(utils|renderers)/jinja\.py:
|
||||
- integration.modules.test_state_jinja_filters
|
||||
- integration.states.test_renderers
|
||||
|
||||
salt/utils/minions.py:
|
||||
- integration.shell.test_matcher
|
||||
|
||||
salt/utils/reactor.py:
|
||||
- integration.reactor.test_reactor
|
||||
|
||||
salt/cli/daemons.py:
|
||||
- integration.shell.test_master
|
||||
- integration.shell.test_minion
|
||||
- integration.shell.test_proxy
|
||||
- integration.shell.test_syndic
|
||||
|
||||
salt/(client/ssh/.+|cli/ssh\.py):
|
||||
- integration.cli.test_custom_module
|
||||
- integration.ssh.test_deploy
|
||||
- integration.ssh.test_grains
|
||||
- integration.ssh.test_jinja_filters
|
||||
- integration.ssh.test_master
|
||||
- integration.ssh.test_mine
|
||||
- integration.ssh.test_pillar
|
||||
- integration.ssh.test_raw
|
||||
- integration.ssh.test_state
|
||||
|
||||
salt/config/*:
|
||||
- unit.test_config
|
||||
|
||||
salt/loader.py:
|
||||
- integration.loader.test_ext_grains
|
||||
- integration.loader.test_ext_modules
|
||||
|
||||
salt/minion.py:
|
||||
- integration.client.test_syndic
|
||||
- integration.minion.test_blackout
|
||||
- integration.minion.test_pillar
|
||||
- integration.minion.test_timeout
|
||||
- integration.shell.test_matcher
|
||||
|
||||
salt/modules/*_sysctl.py:
|
||||
- unit.states.test_sysctl
|
||||
- integration.modules.test_sysctl
|
||||
|
||||
salt/netapi/rest_cherrypy/*:
|
||||
- unit.netapi.test_rest_cherrypy
|
||||
- integration.netapi.rest_cherrypy.test_app_pam
|
||||
- integration.netapi.test_client
|
||||
|
||||
salt/netapi/rest_tornado/*:
|
||||
- unit.netapi.test_rest_tornado
|
||||
- integration.netapi.rest_tornado.test_app
|
||||
- integration.netapi.test_client
|
||||
|
||||
salt/output/*:
|
||||
- integration.output.test_output
|
||||
|
||||
salt/pillar/__init__.py:
|
||||
- integration.minion.test_pillar
|
||||
|
||||
salt/(cli/run\.py|runner\.py):
|
||||
- integration.shell.test_runner
|
||||
- integration.runners.test_runner_returns
|
||||
|
||||
salt/runners/venafiapi.py:
|
||||
- integration.externalapi.test_venafiapi
|
||||
|
||||
salt/serializers/*:
|
||||
- unit.serializers.test_serializers
|
||||
|
||||
salt/(cli/spm\.py|spm/.+):
|
||||
- unit.test_spm
|
||||
- integration.shell.test_spm
|
||||
- integration.spm.test_build
|
||||
- integration.spm.test_files
|
||||
- integration.spm.test_info
|
||||
- integration.spm.test_install
|
||||
- integration.spm.test_remove
|
||||
- integration.spm.test_repo
|
||||
|
||||
salt/transport/*:
|
||||
- unit.test_transport
|
||||
|
||||
salt/utils/docker/*:
|
||||
- unit.utils.test_docker
|
||||
|
||||
salt/utils/schedule.py:
|
||||
- integration.scheduler.test_eval
|
||||
- integration.scheduler.test_postpone
|
||||
- integration.scheduler.test_skip
|
||||
|
||||
salt/wheel/*:
|
||||
- integration.wheel.test_client
|
||||
|
||||
tests/support/mock.py:
|
||||
- unit.test_mock
|
|
@ -26,7 +26,7 @@ try:
|
|||
from libcloud.common.openstack_identity import OpenStackIdentityTokenScope
|
||||
HAS_KEYSTONE = True
|
||||
except ImportError:
|
||||
HAS_KEYSTONE = True
|
||||
HAS_KEYSTONE = False
|
||||
|
||||
# Import Third-Party Libs
|
||||
try:
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
:codeauthor: Nicole Thomas <nicole@saltstack.com>
|
||||
'''
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import os
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.case import ShellCase
|
||||
from tests.support.paths import FILES
|
||||
from tests.support.unit import skipIf
|
||||
from tests.support.helpers import expensiveTest, generate_random_name
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.config import cloud_providers_config
|
||||
|
||||
# Import Third-Party Libs
|
||||
try:
|
||||
import shade # pylint: disable=unused-import
|
||||
HAS_SHADE = True
|
||||
except ImportError:
|
||||
HAS_SHADE = False
|
||||
|
||||
# Create the cloud instance name to be used throughout the tests
|
||||
INSTANCE_NAME = generate_random_name('CLOUD-TEST-')
|
||||
PROVIDER_NAME = 'openstack'
|
||||
DRIVER_NAME = 'openstack'
|
||||
|
||||
|
||||
@skipIf(HAS_SHADE is False, 'openstack driver requires `shade`')
|
||||
class RackspaceTest(ShellCase):
|
||||
'''
|
||||
Integration tests for the Rackspace cloud provider using the Openstack driver
|
||||
'''
|
||||
|
||||
@expensiveTest
|
||||
def setUp(self):
|
||||
'''
|
||||
Sets up the test requirements
|
||||
'''
|
||||
super(RackspaceTest, self).setUp()
|
||||
|
||||
# check if appropriate cloud provider and profile files are present
|
||||
profile_str = 'openstack-config'
|
||||
providers = self.run_cloud('--list-providers')
|
||||
if profile_str + ':' not in providers:
|
||||
self.skipTest(
|
||||
'Configuration file for {0} was not found. Check {0}.conf files '
|
||||
'in tests/integration/files/conf/cloud.*.d/ to run these tests.'
|
||||
.format(PROVIDER_NAME)
|
||||
)
|
||||
|
||||
# check if personal access token, ssh_key_file, and ssh_key_names are present
|
||||
config = cloud_providers_config(
|
||||
os.path.join(
|
||||
FILES,
|
||||
'conf',
|
||||
'cloud.providers.d',
|
||||
PROVIDER_NAME + '.conf'
|
||||
)
|
||||
)
|
||||
|
||||
region_name = config[profile_str][DRIVER_NAME].get('region_name')
|
||||
auth = config[profile_str][DRIVER_NAME].get('auth')
|
||||
cloud = config[profile_str][DRIVER_NAME].get('cloud')
|
||||
if not region_name or not (auth or cloud):
|
||||
self.skipTest(
|
||||
'A region_name and (auth or cloud) must be provided to run these '
|
||||
'tests. Check tests/integration/files/conf/cloud.providers.d/{0}.conf'
|
||||
.format(PROVIDER_NAME)
|
||||
)
|
||||
|
||||
def test_instance(self):
|
||||
'''
|
||||
Test creating an instance on rackspace with the openstack driver
|
||||
'''
|
||||
# check if instance with salt installed returned
|
||||
try:
|
||||
self.assertIn(
|
||||
INSTANCE_NAME,
|
||||
[i.strip() for i in self.run_cloud('-p rackspace-test {0}'.format(INSTANCE_NAME), timeout=500)]
|
||||
)
|
||||
except AssertionError:
|
||||
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=500)
|
||||
raise
|
||||
|
||||
# delete the instance
|
||||
try:
|
||||
self.assertIn(
|
||||
INSTANCE_NAME + ':',
|
||||
[i.strip() for i in self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=500)]
|
||||
)
|
||||
except AssertionError:
|
||||
raise
|
||||
|
||||
def tearDown(self):
|
||||
'''
|
||||
Clean up after tests
|
||||
'''
|
||||
query = self.run_cloud('--query')
|
||||
ret = ' {0}:'.format(INSTANCE_NAME)
|
||||
|
||||
# if test instance is still present, delete it
|
||||
if ret in query:
|
||||
self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME), timeout=500)
|
|
@ -1,7 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
def myfunction():
|
||||
grains = {}
|
||||
grains['a_custom'] = {'k1': 'v1'}
|
||||
return grains
|
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
def test(grains):
|
||||
return {'custom_grain_test': 'itworked' if 'os' in grains else 'itdidntwork'}
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
def myfunction():
|
||||
grains = {}
|
||||
grains['match'] = 'maker'
|
||||
return grains
|
||||
grains = {}
|
||||
grains['a_custom'] = {'k1': 'v1'}
|
||||
return grains
|
||||
|
|
|
@ -404,7 +404,7 @@ class CallTest(ShellCase, testprogram.TestProgramCase, ShellCaseCommonTestsMixin
|
|||
self.run_script(
|
||||
'salt-call',
|
||||
'-c {0} --output-file={1} -l trace -g'.format(
|
||||
self.get_config_dir(),
|
||||
self.config_dir,
|
||||
output_file
|
||||
),
|
||||
catch_stderr=True,
|
||||
|
|
|
@ -742,13 +742,16 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
|||
continue
|
||||
named_tests.append(test)
|
||||
|
||||
if (self.options.unit or self.options.kitchen or named_unit_test) and not named_tests and not \
|
||||
self._check_enabled_suites(include_cloud_provider=True):
|
||||
if (self.options.unit or self.options.kitchen or named_unit_test) \
|
||||
and not named_tests \
|
||||
and (self.options.from_filenames or
|
||||
not self._check_enabled_suites(include_cloud_provider=True)):
|
||||
# We're either not running any integration test suites, or we're
|
||||
# only running unit tests by passing --unit or by passing only
|
||||
# `unit.<whatever>` to --name. We don't need the tests daemon
|
||||
# running
|
||||
return [True]
|
||||
|
||||
if not salt.utils.platform.is_windows():
|
||||
self.set_filehandle_limits('integration')
|
||||
|
||||
|
@ -807,9 +810,11 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
|||
continue
|
||||
named_unit_test.append(test)
|
||||
|
||||
if not self.options.unit and not named_unit_test:
|
||||
if not named_unit_test \
|
||||
and (self.options.from_filenames or not self.options.unit):
|
||||
# We are not explicitly running the unit tests and none of the
|
||||
# names passed to --name is a unit test.
|
||||
# names passed to --name (or derived via --from-filenames) is a
|
||||
# unit test.
|
||||
return [True]
|
||||
|
||||
status = []
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# pylint: disable=repr-flag-used-in-string
|
||||
|
||||
from __future__ import absolute_import, print_function
|
||||
import fnmatch
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
@ -20,6 +21,7 @@ import shutil
|
|||
import logging
|
||||
import platform
|
||||
import optparse
|
||||
import re
|
||||
import tempfile
|
||||
import traceback
|
||||
import subprocess
|
||||
|
@ -27,13 +29,20 @@ import warnings
|
|||
from functools import partial
|
||||
from collections import namedtuple
|
||||
|
||||
import tests.support.paths
|
||||
from tests.support import helpers
|
||||
from tests.support.unit import TestLoader, TextTestRunner
|
||||
from tests.support.xmlunit import HAS_XMLRUNNER, XMLTestRunner
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
import salt.utils.data
|
||||
import salt.utils.files
|
||||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
import salt.utils.yaml
|
||||
|
||||
try:
|
||||
from tests.support.ext import console
|
||||
WIDTH, HEIGHT = console.getTerminalSize()
|
||||
|
@ -184,7 +193,7 @@ class SaltTestingParser(optparse.OptionParser):
|
|||
'--name',
|
||||
dest='name',
|
||||
action='append',
|
||||
default=None,
|
||||
default=[],
|
||||
help=('Specific test name to run. A named test is the module path '
|
||||
'relative to the tests directory')
|
||||
)
|
||||
|
@ -195,6 +204,29 @@ class SaltTestingParser(optparse.OptionParser):
|
|||
help=('The location of a newline delimited file of test names to '
|
||||
'run')
|
||||
)
|
||||
self.test_selection_group.add_option(
|
||||
'--from-filenames',
|
||||
dest='from_filenames',
|
||||
action='append',
|
||||
default=None,
|
||||
help=('Pass a comma-separated list of file paths, and any '
|
||||
'unit/integration test module which corresponds to the '
|
||||
'specified file(s) will be run. For example, a path of '
|
||||
'salt/modules/git.py would result in unit.modules.test_git '
|
||||
'and integration.modules.test_git being run. Absolute paths '
|
||||
'are assumed to be files containing relative paths, one per '
|
||||
'line. Providing the paths in a file can help get around '
|
||||
'shell character limits when the list of files is long.')
|
||||
)
|
||||
self.test_selection_group.add_option(
|
||||
'--filename-map',
|
||||
dest='filename_map',
|
||||
default=None,
|
||||
help=('Path to a YAML file mapping paths/path globs to a list '
|
||||
'of test names to run. See tests/filename_map.yml '
|
||||
'for example usage (when --from-filenames is used, this '
|
||||
'map file will be the default one used).')
|
||||
)
|
||||
self.add_option_group(self.test_selection_group)
|
||||
|
||||
if self.support_docker_execution is True:
|
||||
|
@ -308,32 +340,165 @@ class SaltTestingParser(optparse.OptionParser):
|
|||
self.add_option_group(self.fs_cleanup_options_group)
|
||||
self.setup_additional_options()
|
||||
|
||||
@staticmethod
|
||||
def _expand_paths(paths):
|
||||
'''
|
||||
Expand any comma-separated lists of paths, and return a set of all
|
||||
paths to ensure there are no duplicates.
|
||||
'''
|
||||
ret = set()
|
||||
for path in paths:
|
||||
for item in [x.strip() for x in path.split(',')]:
|
||||
if not item:
|
||||
continue
|
||||
elif os.path.isabs(item):
|
||||
try:
|
||||
with salt.utils.files.fopen(item, 'rb') as fp_:
|
||||
for line in fp_:
|
||||
line = salt.utils.stringutils.to_unicode(line.strip())
|
||||
if os.path.isabs(line):
|
||||
log.warning(
|
||||
'Invalid absolute path %s in %s, '
|
||||
'ignoring', line, item
|
||||
)
|
||||
else:
|
||||
ret.add(line)
|
||||
except (IOError, OSError) as exc:
|
||||
log.error('Failed to read from %s: %s', item, exc)
|
||||
else:
|
||||
ret.add(item)
|
||||
return ret
|
||||
|
||||
@property
|
||||
def _test_mods(self):
|
||||
'''
|
||||
Use the test_mods generator to get all of the test module names, and
|
||||
then store them in a set so that further references to this attribute
|
||||
will not need to re-walk the test dir.
|
||||
'''
|
||||
try:
|
||||
return self.__test_mods
|
||||
except AttributeError:
|
||||
self.__test_mods = set(tests.support.paths.test_mods())
|
||||
return self.__test_mods
|
||||
|
||||
def _map_files(self, files):
|
||||
'''
|
||||
Map the passed paths to test modules, returning a set of the mapped
|
||||
module names.
|
||||
'''
|
||||
ret = set()
|
||||
|
||||
if self.options.filename_map is not None:
|
||||
try:
|
||||
with salt.utils.files.fopen(self.options.filename_map) as fp_:
|
||||
filename_map = salt.utils.yaml.safe_load(fp_)
|
||||
except Exception as exc:
|
||||
raise RuntimeError(
|
||||
'Failed to load filename map: {0}'.format(exc)
|
||||
)
|
||||
else:
|
||||
filename_map = {}
|
||||
|
||||
def _add(comps):
|
||||
'''
|
||||
Helper to add unit and integration tests matching a given mod path
|
||||
'''
|
||||
mod_relname = '.'.join(comps)
|
||||
ret.update(
|
||||
x for x in
|
||||
['.'.join(('unit', mod_relname)),
|
||||
'.'.join(('integration', mod_relname))]
|
||||
if x in self._test_mods
|
||||
)
|
||||
|
||||
# First, try a path match
|
||||
for path in files:
|
||||
match = re.match(r'^(salt/|tests/(integration|unit)/)(.+\.py)$', path)
|
||||
if match:
|
||||
comps = match.group(3).split('/')
|
||||
|
||||
# Find matches for a source file
|
||||
if match.group(1) == 'salt/':
|
||||
if comps[-1] == '__init__.py':
|
||||
comps.pop(-1)
|
||||
comps[-1] = 'test_' + comps[-1]
|
||||
else:
|
||||
comps[-1] = 'test_{0}'.format(comps[-1][:-3])
|
||||
|
||||
# Direct name matches
|
||||
_add(comps)
|
||||
|
||||
# State matches for execution modules of the same name
|
||||
# (e.g. unit.states.test_archive if
|
||||
# unit.modules.test_archive is being run)
|
||||
try:
|
||||
if comps[-2] == 'modules':
|
||||
comps[-2] = 'states'
|
||||
_add(comps)
|
||||
except IndexError:
|
||||
# Not an execution module. This is either directly in
|
||||
# the salt/ directory, or salt/something/__init__.py
|
||||
pass
|
||||
|
||||
# Make sure to run a test module if it's been modified
|
||||
elif match.group(1).startswith('tests/'):
|
||||
comps.insert(0, match.group(2))
|
||||
if fnmatch.fnmatch(comps[-1], 'test_*.py'):
|
||||
comps[-1] = comps[-1][:-3]
|
||||
test_name = '.'.join(comps)
|
||||
if test_name in self._test_mods:
|
||||
ret.add(test_name)
|
||||
|
||||
# Next, try the filename_map
|
||||
for path_expr in filename_map:
|
||||
for filename in files:
|
||||
if salt.utils.stringutils.expr_match(filename, path_expr):
|
||||
ret.update(filename_map[path_expr])
|
||||
break
|
||||
|
||||
return ret
|
||||
|
||||
def parse_args(self, args=None, values=None):
|
||||
self.options, self.args = optparse.OptionParser.parse_args(self, args, values)
|
||||
|
||||
file_names = []
|
||||
if self.options.names_file:
|
||||
with open(self.options.names_file, 'rb') as fp_: # pylint: disable=resource-leakage
|
||||
lines = []
|
||||
for line in fp_.readlines():
|
||||
if six.PY2:
|
||||
lines.append(line.strip())
|
||||
file_names.append(line.strip())
|
||||
else:
|
||||
lines.append(
|
||||
file_names.append(
|
||||
line.decode(__salt_system_encoding__).strip())
|
||||
if self.options.name:
|
||||
self.options.name.extend(lines)
|
||||
else:
|
||||
self.options.name = lines
|
||||
|
||||
if self.args:
|
||||
if not self.options.name:
|
||||
self.options.name = []
|
||||
for fpath in self.args:
|
||||
if os.path.isfile(fpath) and \
|
||||
fpath.endswith('.py') and \
|
||||
os.path.basename(fpath).startswith('test_'):
|
||||
self.options.name.append(fpath)
|
||||
if fpath in file_names:
|
||||
self.options.name.append(fpath)
|
||||
continue
|
||||
self.exit(status=1, msg='\'{}\' is not a valid test module\n'.format(fpath))
|
||||
|
||||
if self.options.from_filenames is not None:
|
||||
self.options.from_filenames = self._expand_paths(self.options.from_filenames)
|
||||
|
||||
# Locate the default map file if one was not passed
|
||||
if self.options.filename_map is None:
|
||||
self.options.filename_map = salt.utils.path.join(
|
||||
tests.support.paths.TESTS_DIR,
|
||||
'filename_map.yml'
|
||||
)
|
||||
|
||||
self.options.name.extend(self._map_files(self.options.from_filenames))
|
||||
|
||||
if self.options.name and file_names:
|
||||
self.options.name = list(set(self.options.name).intersection(file_names))
|
||||
elif file_names:
|
||||
self.options.name = file_names
|
||||
|
||||
print_header(u'', inline=True, width=self.options.output_columns)
|
||||
self.pre_execution_cleanup()
|
||||
|
||||
|
@ -341,7 +506,7 @@ class SaltTestingParser(optparse.OptionParser):
|
|||
if self.source_code_basedir is None:
|
||||
raise RuntimeError(
|
||||
'You need to define the \'source_code_basedir\' attribute '
|
||||
'in {0!r}.'.format(self.__class__.__name__)
|
||||
'in \'{0}\'.'.format(self.__class__.__name__)
|
||||
)
|
||||
|
||||
if '/' not in self.options.docked:
|
||||
|
|
|
@ -14,11 +14,14 @@
|
|||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import stat
|
||||
import logging
|
||||
import tempfile
|
||||
|
||||
import salt.utils.path
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
TESTS_DIR = os.path.dirname(os.path.dirname(os.path.normpath(os.path.abspath(__file__))))
|
||||
|
@ -30,6 +33,7 @@ if sys.platform.startswith('win'):
|
|||
CODE_DIR = os.path.dirname(TESTS_DIR)
|
||||
if sys.platform.startswith('win'):
|
||||
CODE_DIR = CODE_DIR.replace('\\', '\\\\')
|
||||
UNIT_TEST_DIR = os.path.join(TESTS_DIR, 'unit')
|
||||
INTEGRATION_TEST_DIR = os.path.join(TESTS_DIR, 'integration')
|
||||
|
||||
# Let's inject CODE_DIR so salt is importable if not there already
|
||||
|
@ -99,6 +103,24 @@ SCRIPT_TEMPLATES = {
|
|||
}
|
||||
|
||||
|
||||
def test_mods():
|
||||
'''
|
||||
A generator which returns all of the test files
|
||||
'''
|
||||
test_re = re.compile(r'^test_.+\.py$')
|
||||
for dirname in (UNIT_TEST_DIR, INTEGRATION_TEST_DIR):
|
||||
test_type = os.path.basename(dirname)
|
||||
for root, _, files in salt.utils.path.os_walk(dirname):
|
||||
parent_mod = root[len(dirname):].lstrip(os.sep).replace(os.sep, '.')
|
||||
for filename in files:
|
||||
if test_re.match(filename):
|
||||
mod_name = test_type
|
||||
if parent_mod:
|
||||
mod_name += '.' + parent_mod
|
||||
mod_name += '.' + filename[:-3]
|
||||
yield mod_name
|
||||
|
||||
|
||||
class ScriptPathMixin(object):
|
||||
|
||||
def get_script_path(self, script_name):
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
'''
|
||||
:codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
|
||||
'''
|
||||
# pylint: disable=3rd-party-module-not-gated
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import tempfile
|
||||
|
@ -23,27 +21,6 @@ from tests.support.mock import (
|
|||
# Import Salt Libs
|
||||
import salt.states.virt as virt
|
||||
import salt.utils.files
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
|
||||
class LibvirtMock(MagicMock): # pylint: disable=too-many-ancestors
|
||||
'''
|
||||
libvirt library mockup
|
||||
'''
|
||||
|
||||
class libvirtError(Exception): # pylint: disable=invalid-name
|
||||
'''
|
||||
libvirt error mockup
|
||||
'''
|
||||
|
||||
def get_error_message(self):
|
||||
'''
|
||||
Fake function return error message
|
||||
'''
|
||||
return six.text_type(self)
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
|
@ -52,12 +29,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
Test cases for salt.states.libvirt
|
||||
'''
|
||||
def setup_loader_modules(self):
|
||||
self.mock_libvirt = LibvirtMock() # pylint: disable=attribute-defined-outside-init
|
||||
self.addCleanup(delattr, self, 'mock_libvirt')
|
||||
loader_globals = {
|
||||
'libvirt': self.mock_libvirt
|
||||
}
|
||||
return {virt: loader_globals}
|
||||
return {virt: {}}
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
@ -84,17 +56,17 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
mock = MagicMock(side_effect=[[], ['libvirt.servercert.pem'],
|
||||
{'libvirt.servercert.pem': 'A'}])
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}):
|
||||
comt = ('All keys are correct')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(virt.keys(name, basepath=self.pki_dir), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': True}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': True}):
|
||||
comt = ('Libvirt keys are set to be updated')
|
||||
ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(virt.keys(name, basepath=self.pki_dir), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': False}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': False}):
|
||||
with patch.object(salt.utils.files, 'fopen', MagicMock(mock_open())):
|
||||
comt = ('Updated libvirt certs and keys')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
|
@ -115,21 +87,21 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
mock = MagicMock(side_effect=[[], ['libvirt.servercert.pem'],
|
||||
{'libvirt.servercert.pem': 'A'}])
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}):
|
||||
comt = ('All keys are correct')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(virt.keys(name,
|
||||
basepath=self.pki_dir,
|
||||
expiration_days=700), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': True}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': True}):
|
||||
comt = ('Libvirt keys are set to be updated')
|
||||
ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(virt.keys(name,
|
||||
basepath=self.pki_dir,
|
||||
expiration_days=700), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': False}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': False}):
|
||||
with patch.object(salt.utils.files, 'fopen', MagicMock(mock_open())):
|
||||
comt = ('Updated libvirt certs and keys')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
|
@ -152,21 +124,21 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
mock = MagicMock(side_effect=[[], ['libvirt.servercert.pem'],
|
||||
{'libvirt.servercert.pem': 'A'}])
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}):
|
||||
comt = ('All keys are correct')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(virt.keys(name,
|
||||
basepath=self.pki_dir,
|
||||
st='California'), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': True}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': True}):
|
||||
comt = ('Libvirt keys are set to be updated')
|
||||
ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(virt.keys(name,
|
||||
basepath=self.pki_dir,
|
||||
st='California'), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': False}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': False}):
|
||||
with patch.object(salt.utils.files, 'fopen', MagicMock(mock_open())):
|
||||
comt = ('Updated libvirt certs and keys')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
|
@ -189,7 +161,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
|
||||
mock = MagicMock(side_effect=[[], ['libvirt.servercert.pem'],
|
||||
{'libvirt.servercert.pem': 'A'}])
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__salt__, {'pillar.ext': mock}):
|
||||
comt = ('All keys are correct')
|
||||
ret.update({'comment': comt})
|
||||
self.assertDictEqual(virt.keys(name,
|
||||
|
@ -200,7 +172,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
organization='SaltStack',
|
||||
expiration_days=700), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': True}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': True}):
|
||||
comt = ('Libvirt keys are set to be updated')
|
||||
ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(virt.keys(name,
|
||||
|
@ -211,7 +183,7 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
organization='SaltStack',
|
||||
expiration_days=700), ret)
|
||||
|
||||
with patch.dict(virt.__opts__, {'test': False}): # pylint: disable=no-member
|
||||
with patch.dict(virt.__opts__, {'test': False}):
|
||||
with patch.object(salt.utils.files, 'fopen', MagicMock(mock_open())):
|
||||
comt = ('Updated libvirt certs and keys')
|
||||
ret.update({'comment': comt, 'result': True,
|
||||
|
@ -223,484 +195,3 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin):
|
|||
locality='Los_Angeles',
|
||||
organization='SaltStack',
|
||||
expiration_days=700), ret)
|
||||
|
||||
def test_running(self):
|
||||
'''
|
||||
running state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'myvm is running'}
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value='stopped'),
|
||||
'virt.start': MagicMock(return_value=0),
|
||||
}):
|
||||
ret.update({'changes': {'myvm': 'Domain started'},
|
||||
'comment': 'Domain myvm started'})
|
||||
self.assertDictEqual(virt.running('myvm'), ret)
|
||||
|
||||
init_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(side_effect=CommandExecutionError('not found')),
|
||||
'virt.init': init_mock,
|
||||
'virt.start': MagicMock(return_value=0)
|
||||
}):
|
||||
ret.update({'changes': {'myvm': 'Domain defined and started'},
|
||||
'comment': 'Domain myvm defined and started'})
|
||||
self.assertDictEqual(virt.running('myvm',
|
||||
cpu=2,
|
||||
mem=2048,
|
||||
image='/path/to/img.qcow2'), ret)
|
||||
init_mock.assert_called_with('myvm', cpu=2, mem=2048, image='/path/to/img.qcow2',
|
||||
os_type=None, arch=None,
|
||||
disk=None, disks=None, nic=None, interfaces=None,
|
||||
graphics=None, hypervisor=None,
|
||||
seed=True, install=True, pub_key=None, priv_key=None,
|
||||
connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(side_effect=CommandExecutionError('not found')),
|
||||
'virt.init': init_mock,
|
||||
'virt.start': MagicMock(return_value=0)
|
||||
}):
|
||||
ret.update({'changes': {'myvm': 'Domain defined and started'},
|
||||
'comment': 'Domain myvm defined and started'})
|
||||
disks = [{
|
||||
'name': 'system',
|
||||
'size': 8192,
|
||||
'overlay_image': True,
|
||||
'pool': 'default',
|
||||
'image': '/path/to/image.qcow2'
|
||||
},
|
||||
{
|
||||
'name': 'data',
|
||||
'size': 16834
|
||||
}]
|
||||
ifaces = [{
|
||||
'name': 'eth0',
|
||||
'mac': '01:23:45:67:89:AB'
|
||||
},
|
||||
{
|
||||
'name': 'eth1',
|
||||
'type': 'network',
|
||||
'source': 'admin'
|
||||
}]
|
||||
graphics = {'type': 'spice', 'listen': {'type': 'address', 'address': '192.168.0.1'}}
|
||||
self.assertDictEqual(virt.running('myvm',
|
||||
cpu=2,
|
||||
mem=2048,
|
||||
os_type='linux',
|
||||
arch='i686',
|
||||
vm_type='qemu',
|
||||
disk_profile='prod',
|
||||
disks=disks,
|
||||
nic_profile='prod',
|
||||
interfaces=ifaces,
|
||||
graphics=graphics,
|
||||
seed=False,
|
||||
install=False,
|
||||
pub_key='/path/to/key.pub',
|
||||
priv_key='/path/to/key',
|
||||
connection='someconnection',
|
||||
username='libvirtuser',
|
||||
password='supersecret'), ret)
|
||||
init_mock.assert_called_with('myvm',
|
||||
cpu=2,
|
||||
mem=2048,
|
||||
os_type='linux',
|
||||
arch='i686',
|
||||
image=None,
|
||||
disk='prod',
|
||||
disks=disks,
|
||||
nic='prod',
|
||||
interfaces=ifaces,
|
||||
graphics=graphics,
|
||||
hypervisor='qemu',
|
||||
seed=False,
|
||||
install=False,
|
||||
pub_key='/path/to/key.pub',
|
||||
priv_key='/path/to/key',
|
||||
connection='someconnection',
|
||||
username='libvirtuser',
|
||||
password='supersecret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value='stopped'),
|
||||
'virt.start': MagicMock(side_effect=[self.mock_libvirt.libvirtError('libvirt error msg')])
|
||||
}):
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'libvirt error msg'})
|
||||
self.assertDictEqual(virt.running('myvm'), ret)
|
||||
|
||||
# Working update case when running
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value='running'),
|
||||
'virt.update': MagicMock(return_value={'definition': True, 'cpu': True})
|
||||
}):
|
||||
ret.update({'changes': {'myvm': {'definition': True, 'cpu': True}},
|
||||
'result': True,
|
||||
'comment': 'Domain myvm updated, restart to fully apply the changes'})
|
||||
self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
|
||||
|
||||
# Working update case when stopped
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value='stopped'),
|
||||
'virt.start': MagicMock(return_value=0),
|
||||
'virt.update': MagicMock(return_value={'definition': True})
|
||||
}):
|
||||
ret.update({'changes': {'myvm': 'Domain updated and started'},
|
||||
'result': True,
|
||||
'comment': 'Domain myvm updated and started'})
|
||||
self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
|
||||
|
||||
# Failed live update case
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value='running'),
|
||||
'virt.update': MagicMock(return_value={'definition': True, 'cpu': False, 'errors': ['some error']})
|
||||
}):
|
||||
ret.update({'changes': {'myvm': {'definition': True, 'cpu': False, 'errors': ['some error']}},
|
||||
'result': True,
|
||||
'comment': 'Domain myvm updated, but some live update(s) failed'})
|
||||
self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
|
||||
|
||||
# Failed definition update case
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.vm_state': MagicMock(return_value='running'),
|
||||
'virt.update': MagicMock(side_effect=[self.mock_libvirt.libvirtError('error message')])
|
||||
}):
|
||||
ret.update({'changes': {},
|
||||
'result': False,
|
||||
'comment': 'error message'})
|
||||
self.assertDictEqual(virt.running('myvm', update=True, cpu=2), ret)
|
||||
|
||||
def test_stopped(self):
|
||||
'''
|
||||
stopped state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
shutdown_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.shutdown': shutdown_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'stopped': [{'domain': 'myvm', 'shutdown': True}]
|
||||
},
|
||||
'comment': 'Machine has been shut down'})
|
||||
self.assertDictEqual(virt.stopped('myvm'), ret)
|
||||
shutdown_mock.assert_called_with('myvm', connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.shutdown': shutdown_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.stopped('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
shutdown_mock.assert_called_with('myvm', connection='myconnection', username='user', password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.shutdown': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.stopped('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.stopped('myvm'), ret)
|
||||
|
||||
def test_powered_off(self):
|
||||
'''
|
||||
powered_off state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
stop_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.stop': stop_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'unpowered': [{'domain': 'myvm', 'stop': True}]
|
||||
},
|
||||
'comment': 'Machine has been powered off'})
|
||||
self.assertDictEqual(virt.powered_off('myvm'), ret)
|
||||
stop_mock.assert_called_with('myvm', connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.stop': stop_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.powered_off('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
stop_mock.assert_called_with('myvm', connection='myconnection', username='user', password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.stop': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.powered_off('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.powered_off('myvm'), ret)
|
||||
|
||||
def test_snapshot(self):
|
||||
'''
|
||||
snapshot state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
snapshot_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.snapshot': snapshot_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'saved': [{'domain': 'myvm', 'snapshot': True}]
|
||||
},
|
||||
'comment': 'Snapshot has been taken'})
|
||||
self.assertDictEqual(virt.snapshot('myvm'), ret)
|
||||
snapshot_mock.assert_called_with('myvm', suffix=None, connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.snapshot': snapshot_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.snapshot('myvm',
|
||||
suffix='snap',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
snapshot_mock.assert_called_with('myvm',
|
||||
suffix='snap',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.snapshot': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.snapshot('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.snapshot('myvm'), ret)
|
||||
|
||||
def test_rebooted(self):
|
||||
'''
|
||||
rebooted state test cases.
|
||||
'''
|
||||
ret = {'name': 'myvm',
|
||||
'changes': {},
|
||||
'result': True}
|
||||
|
||||
reboot_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.reboot': reboot_mock
|
||||
}):
|
||||
ret.update({'changes': {
|
||||
'rebooted': [{'domain': 'myvm', 'reboot': True}]
|
||||
},
|
||||
'comment': 'Machine has been rebooted'})
|
||||
self.assertDictEqual(virt.rebooted('myvm'), ret)
|
||||
reboot_mock.assert_called_with('myvm', connection=None, username=None, password=None)
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.reboot': reboot_mock,
|
||||
}):
|
||||
self.assertDictEqual(virt.rebooted('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
reboot_mock.assert_called_with('myvm',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.list_domains': MagicMock(return_value=['myvm', 'vm1']),
|
||||
'virt.reboot': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {'ignored': [{'domain': 'myvm', 'issue': 'Some error'}]},
|
||||
'result': False,
|
||||
'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.rebooted('myvm'), ret)
|
||||
|
||||
with patch.dict(virt.__salt__, {'virt.list_domains': MagicMock(return_value=[])}): # pylint: disable=no-member
|
||||
ret.update({'changes': {}, 'result': False, 'comment': 'No changes had happened'})
|
||||
self.assertDictEqual(virt.rebooted('myvm'), ret)
|
||||
|
||||
def test_network_running(self):
|
||||
'''
|
||||
network_running state test cases.
|
||||
'''
|
||||
ret = {'name': 'mynet', 'changes': {}, 'result': True, 'comment': ''}
|
||||
define_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.network_info': MagicMock(return_value={}),
|
||||
'virt.network_define': define_mock
|
||||
}):
|
||||
ret.update({'changes': {'mynet': 'Network defined and started'},
|
||||
'comment': 'Network mynet defined and started'})
|
||||
self.assertDictEqual(virt.network_running('mynet',
|
||||
'br2',
|
||||
'bridge',
|
||||
vport='openvswitch',
|
||||
tag=180,
|
||||
autostart=False,
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
define_mock.assert_called_with('mynet',
|
||||
'br2',
|
||||
'bridge',
|
||||
'openvswitch',
|
||||
tag=180,
|
||||
autostart=False,
|
||||
start=True,
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.network_info': MagicMock(return_value={'active': True}),
|
||||
'virt.network_define': define_mock,
|
||||
}):
|
||||
ret.update({'changes': {}, 'comment': 'Network mynet exists and is running'})
|
||||
self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
|
||||
|
||||
start_mock = MagicMock(return_value=True)
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.network_info': MagicMock(return_value={'active': False}),
|
||||
'virt.network_start': start_mock,
|
||||
'virt.network_define': define_mock,
|
||||
}):
|
||||
ret.update({'changes': {'mynet': 'Network started'}, 'comment': 'Network mynet started'})
|
||||
self.assertDictEqual(virt.network_running('mynet',
|
||||
'br2',
|
||||
'bridge',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
start_mock.assert_called_with('mynet', connection='myconnection', username='user', password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.network_info': MagicMock(return_value={}),
|
||||
'virt.network_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
|
||||
self.assertDictEqual(virt.network_running('mynet', 'br2', 'bridge'), ret)
|
||||
|
||||
def test_pool_running(self):
|
||||
'''
|
||||
pool_running state test cases.
|
||||
'''
|
||||
ret = {'name': 'mypool', 'changes': {}, 'result': True, 'comment': ''}
|
||||
mocks = {mock: MagicMock(return_value=True) for mock in ['define', 'autostart', 'build', 'start']}
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.pool_info': MagicMock(return_value={}),
|
||||
'virt.pool_define': mocks['define'],
|
||||
'virt.pool_build': mocks['build'],
|
||||
'virt.pool_start': mocks['start'],
|
||||
'virt.pool_set_autostart': mocks['autostart']
|
||||
}):
|
||||
ret.update({'changes': {'mypool': 'Pool defined and started'},
|
||||
'comment': 'Pool mypool defined and started'})
|
||||
self.assertDictEqual(virt.pool_running('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
permissions={'mode': '0770',
|
||||
'owner': 1000,
|
||||
'group': 100,
|
||||
'label': 'seclabel'},
|
||||
source={'devices': [{'path': '/dev/sda'}]},
|
||||
transient=True,
|
||||
autostart=True,
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret'), ret)
|
||||
mocks['define'].assert_called_with('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
permissions={'mode': '0770',
|
||||
'owner': 1000,
|
||||
'group': 100,
|
||||
'label': 'seclabel'},
|
||||
source_devices=[{'path': '/dev/sda'}],
|
||||
source_dir=None,
|
||||
source_adapter=None,
|
||||
source_hosts=None,
|
||||
source_auth=None,
|
||||
source_name=None,
|
||||
source_format=None,
|
||||
transient=True,
|
||||
start=True,
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
mocks['autostart'].assert_called_with('mypool',
|
||||
state='on',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
mocks['build'].assert_called_with('mypool',
|
||||
connection='myconnection',
|
||||
username='user',
|
||||
password='secret')
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.pool_info': MagicMock(return_value={'state': 'running'}),
|
||||
}):
|
||||
ret.update({'changes': {}, 'comment': 'Pool mypool exists and is running'})
|
||||
self.assertDictEqual(virt.pool_running('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
source={'devices': [{'path': '/dev/sda'}]}), ret)
|
||||
|
||||
for mock in mocks:
|
||||
mocks[mock].reset_mock()
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.pool_info': MagicMock(return_value={'state': 'stopped'}),
|
||||
'virt.pool_build': mocks['build'],
|
||||
'virt.pool_start': mocks['start']
|
||||
}):
|
||||
ret.update({'changes': {'mypool': 'Pool started'}, 'comment': 'Pool mypool started'})
|
||||
self.assertDictEqual(virt.pool_running('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
source={'devices': [{'path': '/dev/sda'}]}), ret)
|
||||
mocks['start'].assert_called_with('mypool', connection=None, username=None, password=None)
|
||||
mocks['build'].assert_not_called()
|
||||
|
||||
with patch.dict(virt.__salt__, { # pylint: disable=no-member
|
||||
'virt.pool_info': MagicMock(return_value={}),
|
||||
'virt.pool_define': MagicMock(side_effect=self.mock_libvirt.libvirtError('Some error'))
|
||||
}):
|
||||
ret.update({'changes': {}, 'comment': 'Some error', 'result': False})
|
||||
self.assertDictEqual(virt.pool_running('mypool',
|
||||
ptype='logical',
|
||||
target='/dev/base',
|
||||
source={'devices': [{'path': '/dev/sda'}]}), ret)
|
||||
|
|
|
@ -662,8 +662,8 @@ class ConfigTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
@with_tempdir()
|
||||
def test_minion_id_lowercase(self, tempdir):
|
||||
'''
|
||||
This tests that setting `minion_id_lowercase: True` does lower case
|
||||
the minion id. Lowercase does not operate on a static `id: KING_BOB`
|
||||
This tests that setting `minion_id_lowercase: True` does lower case
|
||||
the minion id. Lowercase does not operate on a static `id: KING_BOB`
|
||||
setting, or a cached id.
|
||||
'''
|
||||
minion_config = os.path.join(tempdir, 'minion')
|
||||
|
|
|
@ -11,10 +11,11 @@ import os
|
|||
|
||||
# Import Salt libs
|
||||
import salt.utils.path
|
||||
import salt.utils.stringutils
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.unit import TestCase
|
||||
from tests.support.paths import CODE_DIR
|
||||
from tests.support.paths import CODE_DIR, test_mods
|
||||
|
||||
EXCLUDED_DIRS = [
|
||||
os.path.join('tests', 'pkg'),
|
||||
|
@ -93,3 +94,140 @@ class BadTestModuleNamesTestCase(TestCase):
|
|||
error_msg += '\'EXCLUDED_DIRS\' or \'EXCLUDED_FILES\' in \'tests/unit/test_module_names.py\'.\n'
|
||||
error_msg += 'If it is a tests module, then please rename as suggested.'
|
||||
self.assertEqual([], bad_names, error_msg)
|
||||
|
||||
def test_module_name_source_match(self):
|
||||
'''
|
||||
Check all the test mods and check if they correspond to actual files in
|
||||
the codebase. If this test fails, then a test module is likely not
|
||||
named correctly, and should be adjusted.
|
||||
|
||||
If a test module doesn't have a natural name match (as does this very
|
||||
file), then its should be included in the "ignore" tuple below.
|
||||
However, if there is no matching source code file, then you should
|
||||
consider mapping it to files manually via tests/filename_map.yml.
|
||||
'''
|
||||
ignore = (
|
||||
'unit.test_doc',
|
||||
'unit.test_mock',
|
||||
'unit.test_module_names',
|
||||
'unit.test_simple',
|
||||
'unit.test_zypp_plugins',
|
||||
'unit.cache.test_cache',
|
||||
'unit.serializers.test_serializers',
|
||||
'unit.states.test_postgres',
|
||||
'integration.cli.test_custom_module',
|
||||
'integration.cli.test_grains',
|
||||
'integration.client.test_kwarg',
|
||||
'integration.client.test_runner',
|
||||
'integration.client.test_standard',
|
||||
'integration.client.test_syndic',
|
||||
'integration.cloud.test_cloud',
|
||||
'integration.doc.test_man',
|
||||
'integration.externalapi.test_venafiapi',
|
||||
'integration.grains.test_custom',
|
||||
'integration.loader.test_ext_grains',
|
||||
'integration.loader.test_ext_modules',
|
||||
'integration.logging.test_jid_logging',
|
||||
'integration.minion.test_blackout',
|
||||
'integration.minion.test_pillar',
|
||||
'integration.minion.test_timeout',
|
||||
'integration.modules.test_decorators',
|
||||
'integration.modules.test_pkg',
|
||||
'integration.modules.test_state_jinja_filters',
|
||||
'integration.modules.test_sysctl',
|
||||
'integration.netapi.test_client',
|
||||
'integration.netapi.rest_tornado.test_app',
|
||||
'integration.netapi.rest_cherrypy.test_app_pam',
|
||||
'integration.output.test_output',
|
||||
'integration.proxy.test_shell',
|
||||
'integration.proxy.test_simple',
|
||||
'integration.reactor.test_reactor',
|
||||
'integration.runners.test_runner_returns',
|
||||
'integration.scheduler.test_error',
|
||||
'integration.scheduler.test_eval',
|
||||
'integration.scheduler.test_postpone',
|
||||
'integration.scheduler.test_skip',
|
||||
'integration.shell.test_spm',
|
||||
'integration.shell.test_cp',
|
||||
'integration.shell.test_syndic',
|
||||
'integration.shell.test_proxy',
|
||||
'integration.shell.test_auth',
|
||||
'integration.shell.test_call',
|
||||
'integration.shell.test_arguments',
|
||||
'integration.shell.test_matcher',
|
||||
'integration.shell.test_master_tops',
|
||||
'integration.shell.test_saltcli',
|
||||
'integration.shell.test_master',
|
||||
'integration.shell.test_key',
|
||||
'integration.shell.test_runner',
|
||||
'integration.shell.test_cloud',
|
||||
'integration.shell.test_enabled',
|
||||
'integration.shell.test_minion',
|
||||
'integration.spm.test_build',
|
||||
'integration.spm.test_files',
|
||||
'integration.spm.test_info',
|
||||
'integration.spm.test_install',
|
||||
'integration.spm.test_remove',
|
||||
'integration.spm.test_repo',
|
||||
'integration.ssh.test_deploy',
|
||||
'integration.ssh.test_grains',
|
||||
'integration.ssh.test_jinja_filters',
|
||||
'integration.ssh.test_master',
|
||||
'integration.ssh.test_mine',
|
||||
'integration.ssh.test_pillar',
|
||||
'integration.ssh.test_raw',
|
||||
'integration.ssh.test_state',
|
||||
'integration.states.test_compiler',
|
||||
'integration.states.test_handle_error',
|
||||
'integration.states.test_handle_iorder',
|
||||
'integration.states.test_match',
|
||||
'integration.states.test_renderers',
|
||||
'integration.wheel.test_client',
|
||||
)
|
||||
errors = []
|
||||
|
||||
def _format_errors(errors):
|
||||
msg = (
|
||||
'The following {0} test module(s) could not be matched to a '
|
||||
'source code file:\n\n'.format(len(errors))
|
||||
)
|
||||
msg += ''.join(errors)
|
||||
return msg
|
||||
|
||||
for mod_name in test_mods():
|
||||
if mod_name in ignore:
|
||||
# Test module is being ignored, skip it
|
||||
continue
|
||||
|
||||
# Separate the test_foo away from the rest of the mod name, because
|
||||
# we'll need to remove the "test_" from the beginning and add .py
|
||||
stem, flower = mod_name.rsplit('.', 1)
|
||||
# Lop off the integration/unit from the beginning of the mod name
|
||||
try:
|
||||
stem = stem.split('.', 1)[1]
|
||||
except IndexError:
|
||||
# This test mod was in the root of the unit/integration dir
|
||||
stem = ''
|
||||
|
||||
# The path from the root of the repo
|
||||
relpath = salt.utils.path.join(
|
||||
'salt',
|
||||
stem.replace('.', os.sep),
|
||||
'.'.join((flower[5:], 'py')))
|
||||
|
||||
# The full path to the file we expect to find
|
||||
abspath = salt.utils.path.join(CODE_DIR, relpath)
|
||||
|
||||
if not os.path.isfile(abspath):
|
||||
# Maybe this is in a dunder init?
|
||||
alt_relpath = salt.utils.path.join(relpath[:-3], '__init__.py')
|
||||
alt_abspath = salt.utils.path.join(abspath[:-3], '__init__.py')
|
||||
if os.path.isfile(alt_abspath):
|
||||
# Yep, it is. Carry on!
|
||||
continue
|
||||
|
||||
errors.append(
|
||||
'{0} (expected: {1})\n'.format(mod_name, relpath)
|
||||
)
|
||||
|
||||
assert not errors, _format_errors(errors)
|
||||
|
|
Loading…
Add table
Reference in a new issue