mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2017.7' into darwin-plist-update
This commit is contained in:
commit
4297c0d380
32 changed files with 735 additions and 108 deletions
49
.codecov.yml
Normal file
49
.codecov.yml
Normal file
|
@ -0,0 +1,49 @@
|
|||
codecov:
|
||||
ci:
|
||||
- drone.saltstack.com
|
||||
- jenkinsci.saltstack.com
|
||||
|
||||
branch: 2017.7
|
||||
|
||||
notify:
|
||||
require_ci_to_pass: no
|
||||
|
||||
ignore:
|
||||
- ^*.py$
|
||||
- doc/.*
|
||||
- tests/.*
|
||||
|
||||
coverage:
|
||||
round: up
|
||||
range: 70..100
|
||||
precision: 2
|
||||
|
||||
status:
|
||||
project: # measuring the overall project coverage
|
||||
default:
|
||||
enabled: yes # must be yes|true to enable this status
|
||||
if_no_uploads: error # will post commit status of "error" if no coverage reports we uploaded
|
||||
# options: success, error, failure
|
||||
if_not_found: success # if parent is not found report status as success, error, or failure
|
||||
if_ci_failed: success # if ci fails report status as success, error, or failure
|
||||
|
||||
patch: # pull requests only: this commit status will measure the
|
||||
# entire pull requests Coverage Diff. Checking if the lines
|
||||
# adjusted are covered at least X%.
|
||||
default:
|
||||
enabled: no # must be yes|true to enable this status
|
||||
target: 80% # specify the target "X%" coverage to hit
|
||||
if_no_uploads: error # will post commit status of "error" if no coverage reports we uploaded
|
||||
# options: success, error, failure
|
||||
if_not_found: success
|
||||
if_ci_failed: success
|
||||
|
||||
changes: # if there are any unexpected changes in coverage
|
||||
default:
|
||||
enabled: no # must be yes|true to enable this status
|
||||
if_no_uploads: success
|
||||
if_not_found: success
|
||||
if_ci_failed: success
|
||||
|
||||
# No commends because we're not yet running the full test suite on PRs
|
||||
comment: off
|
34
.coveragerc
Normal file
34
.coveragerc
Normal file
|
@ -0,0 +1,34 @@
|
|||
[run]
|
||||
branch = True
|
||||
cover_pylib = False
|
||||
source =
|
||||
salt
|
||||
parallel = True
|
||||
concurrency = multiprocessing
|
||||
omit =
|
||||
tests/*.py
|
||||
setup.py
|
||||
|
||||
[report]
|
||||
# Regexes for lines to exclude from consideration
|
||||
exclude_lines =
|
||||
# Have to re-enable the standard pragma
|
||||
pragma: no cover
|
||||
|
||||
# Don't complain about missing debug-only code:
|
||||
def __repr__
|
||||
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
|
||||
|
||||
ignore_errors = True
|
||||
|
||||
[paths]
|
||||
source =
|
||||
salt
|
7
Gemfile
7
Gemfile
|
@ -2,9 +2,8 @@
|
|||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Point this back at the test-kitchen package after 1.23.3 is relased
|
||||
gem 'test-kitchen', :git => 'https://github.com/dwoz/test-kitchen.git', :branch => 'winrm_opts'
|
||||
gem 'kitchen-salt', '~>0.2'
|
||||
gem 'test-kitchen', '~>1.23.3'
|
||||
gem 'kitchen-salt', '~>0.4.1'
|
||||
gem 'kitchen-sync'
|
||||
gem 'git'
|
||||
|
||||
|
@ -14,7 +13,7 @@ end
|
|||
|
||||
group :windows do
|
||||
gem 'winrm', '~>2.0'
|
||||
gem 'winrm-fs', '~>1.3.1'
|
||||
gem 'winrm-fs', '~>1.3.1'
|
||||
end
|
||||
|
||||
group :ec2 do
|
||||
|
|
|
@ -235,3 +235,17 @@ Defined in: State
|
|||
__sdb__
|
||||
-------
|
||||
Defined in: SDB
|
||||
|
||||
|
||||
Additional Globals
|
||||
==================
|
||||
|
||||
Defined for: Runners, Execution Modules, Wheels
|
||||
|
||||
* ``__jid__``: The job ID
|
||||
* ``__user__``: The user
|
||||
* ``__tag__``: The jid tag
|
||||
* ``__jid_event__``: A :py:class:`salt.utils.event.NamespacedEvent`.
|
||||
|
||||
:py:class:`NamespacedEvent <salt.utils.event.NamespacedEvent>` defines a single
|
||||
method :py:meth:`fire_event <salt.utils.event.NamespacedEvent.fire_event>`, that takes data and tag. The :ref:`Runner docs <runners>` has examples.
|
||||
|
|
|
@ -5,3 +5,4 @@ pytest-salt == 2018.12.8
|
|||
pytest-timeout >= 1.3.3
|
||||
pytest-tempdir >= 2018.8.11
|
||||
pytest-helpers-namespace >= 2017.11.11
|
||||
pytest-salt-runtests-bridge >= 2019.1.30
|
||||
|
|
|
@ -28,7 +28,6 @@ PyMySQL; sys.platform != 'win32' and sys.platform != 'darwin'
|
|||
jsonschema
|
||||
strict_rfc3339
|
||||
rfc3987
|
||||
jinja2
|
||||
pyOpenSSL
|
||||
ioflo
|
||||
dnspython
|
||||
|
|
|
@ -340,6 +340,16 @@ class Minion(parsers.MinionOptionParser, DaemonsMixin): # pylint: disable=no-in
|
|||
NOTE: Run any required code before calling `super()`.
|
||||
'''
|
||||
super(Minion, self).start()
|
||||
while True:
|
||||
try:
|
||||
self._real_start()
|
||||
except SaltClientError as exc:
|
||||
# Restart for multi_master failover when daemonized
|
||||
if self.options.daemon:
|
||||
continue
|
||||
break
|
||||
|
||||
def _real_start(self):
|
||||
try:
|
||||
if check_user(self.config['user']):
|
||||
self.action_log_info('Starting up')
|
||||
|
|
|
@ -324,7 +324,7 @@ class SyncClientMixin(object):
|
|||
print_func=print_func
|
||||
)
|
||||
|
||||
# TODO: document these, and test that they exist
|
||||
# TODO: test that they exist
|
||||
# TODO: Other things to inject??
|
||||
func_globals = {'__jid__': jid,
|
||||
'__user__': data['user'],
|
||||
|
|
|
@ -1338,6 +1338,24 @@ class Cloud(object):
|
|||
output['ret'] = action_out
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
def vm_config(name, main, provider, profile, overrides):
|
||||
'''
|
||||
Create vm config.
|
||||
|
||||
:param str name: The name of the vm
|
||||
:param dict main: The main cloud config
|
||||
:param dict provider: The provider config
|
||||
:param dict profile: The profile config
|
||||
:param dict overrides: The vm's config overrides
|
||||
'''
|
||||
vm = main.copy()
|
||||
vm = salt.utils.dictupdate.update(vm, provider)
|
||||
vm = salt.utils.dictupdate.update(vm, profile)
|
||||
vm.update(overrides)
|
||||
vm['name'] = name
|
||||
return vm
|
||||
|
||||
def extras(self, extra_):
|
||||
'''
|
||||
Extra actions
|
||||
|
@ -1424,12 +1442,13 @@ class Cloud(object):
|
|||
ret[name] = {'Error': msg}
|
||||
continue
|
||||
|
||||
vm_ = main_cloud_config.copy()
|
||||
vm_.update(provider_details)
|
||||
vm_.update(profile_details)
|
||||
vm_.update(vm_overrides)
|
||||
|
||||
vm_['name'] = name
|
||||
vm_ = self.vm_config(
|
||||
name,
|
||||
main_cloud_config,
|
||||
provider_details,
|
||||
profile_details,
|
||||
vm_overrides,
|
||||
)
|
||||
if self.opts['parallel']:
|
||||
process = multiprocessing.Process(
|
||||
target=self.create,
|
||||
|
|
|
@ -10,7 +10,6 @@ import collections
|
|||
# Import third party libs
|
||||
import copy
|
||||
import os
|
||||
import copy
|
||||
import logging
|
||||
import yaml
|
||||
import salt.ext.six as six
|
||||
|
@ -154,7 +153,7 @@ def get(key,
|
|||
'skipped.', default, ret, type(ret).__name__
|
||||
)
|
||||
elif isinstance(default, list):
|
||||
ret = salt.utils.traverse_dict_and_list(
|
||||
ret = salt.utils.traverse_dict_and_list( # pylint: disable=redefined-variable-type
|
||||
pillar_dict,
|
||||
key,
|
||||
[],
|
||||
|
@ -273,6 +272,7 @@ def items(*args, **kwargs):
|
|||
|
||||
return pillar.compile_pillar()
|
||||
|
||||
|
||||
# Allow pillar.data to also be used to return pillar data
|
||||
data = salt.utils.alias_function(items, 'data')
|
||||
|
||||
|
@ -340,7 +340,7 @@ def ls(*args):
|
|||
salt '*' pillar.ls
|
||||
'''
|
||||
|
||||
return list(items(*args).keys())
|
||||
return list(items(*args))
|
||||
|
||||
|
||||
def item(*args, **kwargs):
|
||||
|
@ -538,7 +538,7 @@ def keys(key, delimiter=DEFAULT_TARGET_DELIM):
|
|||
if not isinstance(ret, dict):
|
||||
raise ValueError("Pillar value in key {0} is not a dict".format(key))
|
||||
|
||||
return ret.keys()
|
||||
return list(ret)
|
||||
|
||||
|
||||
def file_exists(path, saltenv=None):
|
||||
|
|
|
@ -738,7 +738,7 @@ def set_lcm_config(config_mode=None,
|
|||
cmd += ' RefreshFrequencyMins = {0};'.format(refresh_freq)
|
||||
if reboot_if_needed is not None:
|
||||
if not isinstance(reboot_if_needed, bool):
|
||||
SaltInvocationError('reboot_if_needed must be a boolean value')
|
||||
raise SaltInvocationError('reboot_if_needed must be a boolean value')
|
||||
if reboot_if_needed:
|
||||
reboot_if_needed = '$true'
|
||||
else:
|
||||
|
|
|
@ -34,6 +34,11 @@ from salt.ext.six import string_types
|
|||
from salt.utils import get_colors
|
||||
import salt.utils.locales
|
||||
|
||||
try:
|
||||
from collections.abc import Mapping
|
||||
except ImportError:
|
||||
from collections import Mapping
|
||||
|
||||
|
||||
class NestDisplay(object):
|
||||
'''
|
||||
|
@ -109,7 +114,7 @@ class NestDisplay(object):
|
|||
first_line = False
|
||||
elif isinstance(ret, (list, tuple)):
|
||||
for ind in ret:
|
||||
if isinstance(ind, (list, tuple, dict)):
|
||||
if isinstance(ind, (list, tuple, Mapping)):
|
||||
out.append(
|
||||
self.ustring(
|
||||
indent,
|
||||
|
@ -117,11 +122,11 @@ class NestDisplay(object):
|
|||
'|_'
|
||||
)
|
||||
)
|
||||
prefix = '' if isinstance(ind, dict) else '- '
|
||||
prefix = '' if isinstance(ind, Mapping) else '- '
|
||||
self.display(ind, indent + 2, prefix, out)
|
||||
else:
|
||||
self.display(ind, indent, '- ', out)
|
||||
elif isinstance(ret, dict):
|
||||
elif isinstance(ret, Mapping):
|
||||
if indent:
|
||||
out.append(
|
||||
self.ustring(
|
||||
|
|
|
@ -3155,7 +3155,7 @@ def directory(name,
|
|||
ret, _ = __salt__['file.check_perms'](
|
||||
full, ret, user, group, file_mode, follow_symlinks)
|
||||
except CommandExecutionError as exc:
|
||||
if not exc.strerror.endswith('does not exist'):
|
||||
if not exc.strerror.startswith('Path not found'):
|
||||
errors.append(exc.strerror)
|
||||
|
||||
if check_dirs:
|
||||
|
|
|
@ -27,6 +27,7 @@ import pkg_resources
|
|||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.data
|
||||
from salt.version import SaltStackVersion as _SaltStackVersion
|
||||
from salt.exceptions import CommandExecutionError, CommandNotFoundError
|
||||
|
||||
|
@ -81,20 +82,6 @@ def __virtual__():
|
|||
return False
|
||||
|
||||
|
||||
def _find_key(prefix, pip_list):
|
||||
'''
|
||||
Does a case-insensitive match in the pip_list for the desired package.
|
||||
'''
|
||||
try:
|
||||
match = next(
|
||||
iter(x for x in pip_list if x.lower() == prefix.lower())
|
||||
)
|
||||
except StopIteration:
|
||||
return None
|
||||
else:
|
||||
return match
|
||||
|
||||
|
||||
def _fulfills_version_spec(version, version_spec):
|
||||
'''
|
||||
Check version number against version specification info and return a
|
||||
|
@ -210,23 +197,20 @@ def _check_if_installed(prefix, state_pkg_name, version_spec, ignore_installed,
|
|||
ret = {'result': False, 'comment': None}
|
||||
|
||||
# If we are not passed a pip list, get one:
|
||||
if not pip_list:
|
||||
pip_list = __salt__['pip.list'](prefix, bin_env=bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars, **kwargs)
|
||||
|
||||
# Check if the requested package is already installed.
|
||||
prefix_realname = _find_key(prefix, pip_list)
|
||||
pip_list = salt.utils.data.CaseInsensitiveDict(
|
||||
pip_list or __salt__['pip.list'](prefix, bin_env=bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars, **kwargs)
|
||||
)
|
||||
|
||||
# If the package was already installed, check
|
||||
# the ignore_installed and force_reinstall flags
|
||||
if ignore_installed is False and prefix_realname is not None:
|
||||
if ignore_installed is False and prefix in pip_list:
|
||||
if force_reinstall is False and not upgrade:
|
||||
# Check desired version (if any) against currently-installed
|
||||
if (
|
||||
any(version_spec) and
|
||||
_fulfills_version_spec(pip_list[prefix_realname],
|
||||
version_spec)
|
||||
_fulfills_version_spec(pip_list[prefix], version_spec)
|
||||
) or (not any(version_spec)):
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Python package {0} was already '
|
||||
|
@ -246,7 +230,7 @@ def _check_if_installed(prefix, state_pkg_name, version_spec, ignore_installed,
|
|||
if 'rc' in spec[1]:
|
||||
include_rc = True
|
||||
available_versions = __salt__['pip.list_all_versions'](
|
||||
prefix_realname, bin_env=bin_env, include_alpha=include_alpha,
|
||||
prefix, bin_env=bin_env, include_alpha=include_alpha,
|
||||
include_beta=include_beta, include_rc=include_rc, user=user,
|
||||
cwd=cwd)
|
||||
desired_version = ''
|
||||
|
@ -262,9 +246,9 @@ def _check_if_installed(prefix, state_pkg_name, version_spec, ignore_installed,
|
|||
ret['comment'] = ('Python package {0} was already '
|
||||
'installed and\nthe available upgrade '
|
||||
'doesn\'t fulfills the version '
|
||||
'requirements'.format(prefix_realname))
|
||||
'requirements'.format(prefix))
|
||||
return ret
|
||||
if _pep440_version_cmp(pip_list[prefix_realname], desired_version) == 0:
|
||||
if _pep440_version_cmp(pip_list[prefix], desired_version) == 0:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Python package {0} was already '
|
||||
'installed'.format(state_pkg_name))
|
||||
|
@ -898,10 +882,12 @@ def installed(name,
|
|||
|
||||
# Case for packages that are not an URL
|
||||
if prefix:
|
||||
pipsearch = __salt__['pip.list'](prefix, bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars,
|
||||
**kwargs)
|
||||
pipsearch = salt.utils.data.CaseInsensitiveDict(
|
||||
__salt__['pip.list'](prefix, bin_env,
|
||||
user=user, cwd=cwd,
|
||||
env_vars=env_vars,
|
||||
**kwargs)
|
||||
)
|
||||
|
||||
# If we didn't find the package in the system after
|
||||
# installing it report it
|
||||
|
@ -912,12 +898,10 @@ def installed(name,
|
|||
'\'pip.freeze\'.'.format(pkg)
|
||||
)
|
||||
else:
|
||||
pkg_name = _find_key(prefix, pipsearch)
|
||||
if pkg_name.lower() in already_installed_packages:
|
||||
continue
|
||||
ver = pipsearch[pkg_name]
|
||||
ret['changes']['{0}=={1}'.format(pkg_name,
|
||||
ver)] = 'Installed'
|
||||
if prefix in pipsearch \
|
||||
and prefix.lower() not in already_installed_packages:
|
||||
ver = pipsearch[prefix]
|
||||
ret['changes']['{0}=={1}'.format(prefix, ver)] = 'Installed'
|
||||
# Case for packages that are an URL
|
||||
else:
|
||||
ret['changes']['{0}==???'.format(state_name)] = 'Installed'
|
||||
|
|
99
salt/utils/data.py
Normal file
99
salt/utils/data.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Functions for manipulating, inspecting, or otherwise working with data types
|
||||
and data structures.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
try:
|
||||
from collections.abc import Mapping, MutableMapping, Sequence
|
||||
except ImportError:
|
||||
from collections import Mapping, MutableMapping, Sequence
|
||||
|
||||
# Import Salt libs
|
||||
from salt.utils.odict import OrderedDict
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
|
||||
|
||||
class CaseInsensitiveDict(MutableMapping):
|
||||
'''
|
||||
Inspired by requests' case-insensitive dict implementation, but works with
|
||||
non-string keys as well.
|
||||
'''
|
||||
def __init__(self, init=None, **kwargs):
|
||||
'''
|
||||
Force internal dict to be ordered to ensure a consistent iteration
|
||||
order, irrespective of case.
|
||||
'''
|
||||
self._data = OrderedDict()
|
||||
self.update(init or {}, **kwargs)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._data)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# Store the case-sensitive key so it is available for dict iteration
|
||||
self._data[to_lowercase(key)] = (key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._data[to_lowercase(key)]
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._data[to_lowercase(key)][1]
|
||||
|
||||
def __iter__(self):
|
||||
return (item[0] for item in six.itervalues(self._data))
|
||||
|
||||
def __eq__(self, rval):
|
||||
if not isinstance(rval, Mapping):
|
||||
# Comparing to non-mapping type (e.g. int) is always False
|
||||
return False
|
||||
return dict(self.items_lower()) == dict(CaseInsensitiveDict(rval).items_lower())
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(six.iteritems(self)))
|
||||
|
||||
def items_lower(self):
|
||||
'''
|
||||
Returns a generator iterating over keys and values, with the keys all
|
||||
being lowercase.
|
||||
'''
|
||||
return ((key, val[1]) for key, val in six.iteritems(self._data))
|
||||
|
||||
def copy(self):
|
||||
'''
|
||||
Returns a copy of the object
|
||||
'''
|
||||
return CaseInsensitiveDict(six.iteritems(self._data))
|
||||
|
||||
|
||||
def __change_case(data, attr, preserve_dict_class=False):
|
||||
try:
|
||||
return getattr(data, attr)()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
data_type = data.__class__
|
||||
|
||||
if isinstance(data, Mapping):
|
||||
return (data_type if preserve_dict_class else dict)(
|
||||
(__change_case(key, attr, preserve_dict_class),
|
||||
__change_case(val, attr, preserve_dict_class))
|
||||
for key, val in six.iteritems(data)
|
||||
)
|
||||
elif isinstance(data, Sequence):
|
||||
return data_type(
|
||||
__change_case(item, attr, preserve_dict_class) for item in data)
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
def to_lowercase(data, preserve_dict_class=False):
|
||||
return __change_case(data, 'lower', preserve_dict_class)
|
||||
|
||||
|
||||
def to_uppercase(data, preserve_dict_class=False):
|
||||
return __change_case(data, 'upper', preserve_dict_class)
|
83
setup.py
83
setup.py
|
@ -15,6 +15,8 @@ import os
|
|||
import sys
|
||||
import glob
|
||||
import time
|
||||
import operator
|
||||
import platform
|
||||
try:
|
||||
from urllib2 import urlopen
|
||||
except ImportError:
|
||||
|
@ -136,6 +138,74 @@ exec(compile(open(SALT_VERSION).read(), SALT_VERSION, 'exec'))
|
|||
|
||||
|
||||
# ----- Helper Functions -------------------------------------------------------------------------------------------->
|
||||
|
||||
def _parse_op(op):
|
||||
'''
|
||||
>>> _parse_op('>')
|
||||
'gt'
|
||||
>>> _parse_op('>=')
|
||||
'ge'
|
||||
>>> _parse_op('=>')
|
||||
'ge'
|
||||
>>> _parse_op('=> ')
|
||||
'ge'
|
||||
>>> _parse_op('<')
|
||||
'lt'
|
||||
>>> _parse_op('<=')
|
||||
'le'
|
||||
>>> _parse_op('==')
|
||||
'eq'
|
||||
>>> _parse_op(' <= ')
|
||||
'le'
|
||||
'''
|
||||
op = op.strip()
|
||||
if '>' in op:
|
||||
if '=' in op:
|
||||
return 'ge'
|
||||
else:
|
||||
return 'gt'
|
||||
elif '<' in op:
|
||||
if '=' in op:
|
||||
return 'le'
|
||||
else:
|
||||
return 'lt'
|
||||
elif '!' in op:
|
||||
return 'ne'
|
||||
else:
|
||||
return 'eq'
|
||||
|
||||
|
||||
def _parse_ver(ver):
|
||||
'''
|
||||
>>> _parse_ver("'3.4' # pyzmq 17.1.0 stopped building wheels for python3.4")
|
||||
'3.4'
|
||||
>>> _parse_ver('"3.4"')
|
||||
'3.4'
|
||||
>>> _parse_ver('"2.6.17"')
|
||||
'2.6.17'
|
||||
'''
|
||||
if '#' in ver:
|
||||
ver, _ = ver.split('#', 1)
|
||||
ver = ver.strip()
|
||||
return ver.strip('\'').strip('"')
|
||||
|
||||
|
||||
def _check_ver(pyver, op, wanted):
|
||||
'''
|
||||
>>> _check_ver('2.7.15', 'gt', '2.7')
|
||||
True
|
||||
>>> _check_ver('2.7.15', 'gt', '2.7.15')
|
||||
False
|
||||
>>> _check_ver('2.7.15', 'ge', '2.7.15')
|
||||
True
|
||||
>>> _check_ver('2.7.15', 'eq', '2.7.15')
|
||||
True
|
||||
'''
|
||||
pyver = distutils.version.LooseVersion(pyver)
|
||||
wanted = distutils.version.LooseVersion(wanted)
|
||||
return getattr(operator, '__{}__'.format(op))(pyver, wanted)
|
||||
|
||||
|
||||
def _parse_requirements_file(requirements_file):
|
||||
parsed_requirements = []
|
||||
with open(requirements_file) as rfh:
|
||||
|
@ -150,7 +220,16 @@ def _parse_requirements_file(requirements_file):
|
|||
# Python 3 already has futures, installing it will only break
|
||||
# the current python installation whenever futures is imported
|
||||
continue
|
||||
parsed_requirements.append(line)
|
||||
try:
|
||||
pkg, pyverspec = line.rsplit(';', 1)
|
||||
except ValueError:
|
||||
pkg, pyverspec = line, ''
|
||||
pyverspec = pyverspec.strip()
|
||||
if pyverspec:
|
||||
_, op, ver = pyverspec.split(' ', 2)
|
||||
if not _check_ver(platform.python_version(), _parse_op(op), _parse_ver(ver)):
|
||||
continue
|
||||
parsed_requirements.append(pkg)
|
||||
return parsed_requirements
|
||||
# <---- Helper Functions ---------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -362,7 +441,6 @@ class DownloadWindowsDlls(Command):
|
|||
if getattr(self.distribution, 'salt_download_windows_dlls', None) is None:
|
||||
print('This command is not meant to be called on it\'s own')
|
||||
exit(1)
|
||||
import platform
|
||||
import pip
|
||||
# pip has moved many things to `_internal` starting with pip 10
|
||||
if LooseVersion(pip.__version__) < LooseVersion('10.0'):
|
||||
|
@ -932,7 +1010,6 @@ class SaltDistribution(distutils.dist.Distribution):
|
|||
|
||||
if IS_WINDOWS_PLATFORM:
|
||||
install_requires = _parse_requirements_file(SALT_WINDOWS_REQS)
|
||||
|
||||
return install_requires
|
||||
|
||||
@property
|
||||
|
|
|
@ -54,7 +54,7 @@ import salt.log.setup
|
|||
from salt.utils.odict import OrderedDict
|
||||
|
||||
# Define the pytest plugins we rely on
|
||||
pytest_plugins = ['tempdir', 'helpers_namespace'] # pylint: disable=invalid-name
|
||||
pytest_plugins = ['tempdir', 'helpers_namespace', 'salt-from-filenames'] # pylint: disable=invalid-name
|
||||
|
||||
# Define where not to collect tests from
|
||||
collect_ignore = ['setup.py']
|
||||
|
|
|
@ -181,7 +181,7 @@ class TestDaemon(object):
|
|||
'''
|
||||
Set up the master and minion daemons, and run related cases
|
||||
'''
|
||||
MINIONS_CONNECT_TIMEOUT = MINIONS_SYNC_TIMEOUT = 120
|
||||
MINIONS_CONNECT_TIMEOUT = MINIONS_SYNC_TIMEOUT = 300
|
||||
|
||||
def __init__(self, parser):
|
||||
self.parser = parser
|
||||
|
@ -217,6 +217,8 @@ class TestDaemon(object):
|
|||
if getattr(self.parser.options, 'ssh', False):
|
||||
self.prep_ssh()
|
||||
|
||||
self.wait_for_minions(time.time(), self.MINIONS_CONNECT_TIMEOUT)
|
||||
|
||||
if self.parser.options.sysinfo:
|
||||
try:
|
||||
print_header(
|
||||
|
@ -1321,3 +1323,20 @@ class TestDaemon(object):
|
|||
def sync_minion_grains(self, targets, timeout=None):
|
||||
salt.utils.appendproctitle('SyncMinionGrains')
|
||||
self.sync_minion_modules_('grains', targets, timeout=timeout)
|
||||
|
||||
def wait_for_minions(self, start, timeout, sleep=5):
|
||||
'''
|
||||
Ensure all minions and masters (including sub-masters) are connected.
|
||||
'''
|
||||
while True:
|
||||
try:
|
||||
ret = self.client.run_job('*', 'test.ping')
|
||||
except salt.exceptions.SaltClientError:
|
||||
ret = None
|
||||
if ret and 'minions' not in ret:
|
||||
continue
|
||||
if ret and sorted(ret['minions']) == ['minion', 'sub_minion']:
|
||||
break
|
||||
if time.time() - start >= timeout:
|
||||
raise RuntimeError("Ping Minions Failed")
|
||||
time.sleep(sleep)
|
||||
|
|
|
@ -110,7 +110,7 @@ class GemModuleTest(ModuleCase):
|
|||
gem.sources_add
|
||||
gem.sources_remove
|
||||
'''
|
||||
source = 'http://gems.github.com'
|
||||
source = 'http://gemcutter.org/'
|
||||
|
||||
self.run_function('gem.sources_add', [source])
|
||||
sources_list = self.run_function('gem.sources_list')
|
||||
|
|
|
@ -222,7 +222,7 @@ class SupervisordModuleTest(ModuleCase):
|
|||
ret = self.run_function(
|
||||
'supervisord.status', [], conf_file=self.supervisor_conf,
|
||||
bin_env=self.venv_dir)
|
||||
self.assertEqual(list(ret.keys()), ['sleep_service', 'sleep_service2'])
|
||||
self.assertEqual(sorted(ret), ['sleep_service', 'sleep_service2'])
|
||||
|
||||
def test_status_one(self):
|
||||
'''
|
||||
|
|
|
@ -141,14 +141,14 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
)
|
||||
return self.run_script('salt-ssh', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr, raw=True)
|
||||
|
||||
def run_run(self, arg_str, with_retcode=False, catch_stderr=False, async=False, timeout=60, config_dir=None):
|
||||
def run_run(self, arg_str, with_retcode=False, catch_stderr=False, async=False, timeout=60, config_dir=None): # pylint: disable=W8606
|
||||
'''
|
||||
Execute salt-run
|
||||
'''
|
||||
arg_str = '-c {0}{async_flag} -t {timeout} {1}'.format(config_dir or self.get_config_dir(),
|
||||
arg_str,
|
||||
timeout=timeout,
|
||||
async_flag=' --async' if async else '')
|
||||
async_flag=' --async' if async else '') # pylint: disable=W8606
|
||||
return self.run_script('salt-run', arg_str, with_retcode=with_retcode, catch_stderr=catch_stderr)
|
||||
|
||||
def run_run_plus(self, fun, *arg, **kwargs):
|
||||
|
@ -243,9 +243,18 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
script_path = self.get_script_path(script)
|
||||
if not os.path.isfile(script_path):
|
||||
return False
|
||||
popen_kwargs = popen_kwargs or {}
|
||||
|
||||
if salt.utils.is_windows():
|
||||
cmd = 'python '
|
||||
if 'cwd' not in popen_kwargs:
|
||||
popen_kwargs['cwd'] = os.getcwd()
|
||||
if 'env' not in popen_kwargs:
|
||||
popen_kwargs['env'] = os.environ.copy()
|
||||
if sys.version_info[0] < 3:
|
||||
popen_kwargs['env'][b'PYTHONPATH'] = CODE_DIR.encode()
|
||||
else:
|
||||
popen_kwargs['env']['PYTHONPATH'] = CODE_DIR
|
||||
else:
|
||||
cmd = 'PYTHONPATH='
|
||||
python_path = os.environ.get('PYTHONPATH', None)
|
||||
|
@ -262,7 +271,6 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
|
||||
tmp_file = tempfile.SpooledTemporaryFile()
|
||||
|
||||
popen_kwargs = popen_kwargs or {}
|
||||
popen_kwargs = dict({
|
||||
'shell': True,
|
||||
'stdout': tmp_file,
|
||||
|
@ -490,14 +498,14 @@ class ShellCase(ShellTestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixi
|
|||
timeout=timeout,
|
||||
raw=True)
|
||||
|
||||
def run_run(self, arg_str, with_retcode=False, catch_stderr=False, async=False, timeout=60, config_dir=None):
|
||||
def run_run(self, arg_str, with_retcode=False, catch_stderr=False, async=False, timeout=60, config_dir=None): # pylint: disable=W8606
|
||||
'''
|
||||
Execute salt-run
|
||||
'''
|
||||
arg_str = '-c {0}{async_flag} -t {timeout} {1}'.format(config_dir or self.get_config_dir(),
|
||||
arg_str,
|
||||
timeout=timeout,
|
||||
async_flag=' --async' if async else '')
|
||||
async_flag=' --async' if async else '') # pylint: disable=W8606
|
||||
return self.run_script('salt-run',
|
||||
arg_str,
|
||||
with_retcode=with_retcode,
|
||||
|
|
11
tests/support/coverage/sitecustomize.py
Normal file
11
tests/support/coverage/sitecustomize.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python will always try to import sitecustomize.
|
||||
We use that fact to try and support code coverage for sub-processes
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
try:
|
||||
import coverage
|
||||
coverage.process_startup()
|
||||
except ImportError:
|
||||
pass
|
44
tests/tox-helper.py
Normal file
44
tests/tox-helper.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This script exists so that path handling when running tox works for both Linux and Windows
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import os
|
||||
import shutil
|
||||
import argparse
|
||||
import tempfile
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--rootdir',
|
||||
default=os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
)
|
||||
subparsers = parser.add_subparsers(help='sub-command help', dest='subparser')
|
||||
|
||||
subparsers.add_parser('create-dirs')
|
||||
subparsers.add_parser('move-artifacts')
|
||||
|
||||
options = parser.parse_args()
|
||||
if options.subparser == 'create-dirs':
|
||||
for dirname in ('logs', 'coverage', 'xml-unittests-output'):
|
||||
path = os.path.join(options.rootdir, 'artifacts', dirname)
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
if options.subparser == 'move-artifacts':
|
||||
tmp_artifacts_dir = os.path.join(tempfile.gettempdir(), 'artifacts')
|
||||
if not os.path.exists(tmp_artifacts_dir):
|
||||
os.makedirs(tmp_artifacts_dir)
|
||||
|
||||
for dirname in ('logs', 'coverage', 'xml-unittests-output'):
|
||||
src = os.path.join(options.rootdir, 'artifacts', dirname)
|
||||
dst = os.path.join(tmp_artifacts_dir, dirname)
|
||||
shutil.copytree(src, dst)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1 +1,70 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
tests.unit.cloud
|
||||
~~~~~~~~~~~~~~~~
|
||||
'''
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
from tests.support.unit import TestCase
|
||||
|
||||
import salt.cloud
|
||||
|
||||
|
||||
class CloudTest(TestCase):
|
||||
|
||||
def test_vm_config_merger(self):
|
||||
'''
|
||||
Validate the vm's config is generated correctly.
|
||||
|
||||
https://github.com/saltstack/salt/issues/49226
|
||||
'''
|
||||
main = {
|
||||
'minion': {'master': '172.31.39.213'},
|
||||
'log_file': 'var/log/salt/cloud.log',
|
||||
'pool_size': 10
|
||||
}
|
||||
provider = {
|
||||
'private_key': 'dwoz.pem',
|
||||
'grains': {'foo1': 'bar', 'foo2': 'bang'},
|
||||
'availability_zone': 'us-west-2b',
|
||||
'driver': 'ec2',
|
||||
'ssh_interface': 'private_ips',
|
||||
'ssh_username': 'admin',
|
||||
'location': 'us-west-2'
|
||||
}
|
||||
profile = {
|
||||
'profile': 'default',
|
||||
'grains': {'meh2': 'bar', 'meh1': 'foo'},
|
||||
'provider': 'ec2-default:ec2',
|
||||
'ssh_username': 'admin',
|
||||
'image': 'ami-0a1fbca0e5b419fd1',
|
||||
'size': 't2.micro'
|
||||
}
|
||||
vm = salt.cloud.Cloud.vm_config(
|
||||
'test_vm',
|
||||
main,
|
||||
provider,
|
||||
profile,
|
||||
{}
|
||||
)
|
||||
self.assertEqual({
|
||||
'minion': {'master': '172.31.39.213'},
|
||||
'log_file': 'var/log/salt/cloud.log',
|
||||
'pool_size': 10,
|
||||
'private_key': 'dwoz.pem',
|
||||
'grains': {
|
||||
'foo1': 'bar',
|
||||
'foo2': 'bang',
|
||||
'meh2': 'bar',
|
||||
'meh1': 'foo',
|
||||
},
|
||||
'availability_zone': 'us-west-2b',
|
||||
'driver': 'ec2',
|
||||
'ssh_interface': 'private_ips',
|
||||
'ssh_username': 'admin',
|
||||
'location': 'us-west-2',
|
||||
'profile': 'default',
|
||||
'provider': 'ec2-default:ec2',
|
||||
'image': 'ami-0a1fbca0e5b419fd1',
|
||||
'size': 't2.micro',
|
||||
'name': 'test_vm',
|
||||
}, vm)
|
||||
|
|
|
@ -118,9 +118,12 @@ class CassandraTestCase(TestCase, LoaderModuleMockMixin):
|
|||
self.assertCountEqual(cassandra.column_families(),
|
||||
{'A': ['a', 'b'], 'B': ['c', 'd']})
|
||||
else:
|
||||
self.assertEqual(cassandra.column_families('A'),
|
||||
self.assertEqual(sorted(cassandra.column_families('A')),
|
||||
['a', 'b'])
|
||||
self.assertEqual(cassandra.column_families(),
|
||||
column_families = cassandra.column_families()
|
||||
for key in ('A', 'B'):
|
||||
column_families[key] = sorted(column_families[key])
|
||||
self.assertEqual(column_families,
|
||||
{'A': ['a', 'b'], 'B': ['c', 'd']})
|
||||
|
||||
def test_column_family_definition(self):
|
||||
|
|
|
@ -30,7 +30,6 @@ from salt.modules.inspectlib.fsdb import CsvDB
|
|||
from salt.modules.inspectlib.entities import CsvDBEntity
|
||||
from salt.utils.odict import OrderedDict
|
||||
|
||||
import salt.ext.six as six
|
||||
from salt.ext.six.moves import StringIO
|
||||
|
||||
|
||||
|
@ -135,26 +134,9 @@ class InspectorFSDBTestCase(TestCase):
|
|||
csvdb.open()
|
||||
csvdb.create_table_from_object(FoobarEntity())
|
||||
|
||||
if six.PY2:
|
||||
assert writable.data[0].strip() == "foo:int,bar:str,spam:float"
|
||||
else:
|
||||
# Order in PY3 is not the same for every run
|
||||
writable_data = writable.data[0].strip()
|
||||
assert_order_options = ['bar:str,foo:int,spam:float',
|
||||
'bar:str,spam:float,foo:int',
|
||||
'foo:int,spam:float,bar:str',
|
||||
'foo:int,bar:str,spam:float',
|
||||
'spam:float,foo:int,bar:str',
|
||||
'spam:float,bar:str,foo:int']
|
||||
while assert_order_options:
|
||||
assert_option = assert_order_options.pop()
|
||||
try:
|
||||
assert writable_data == assert_option
|
||||
break
|
||||
except AssertionError:
|
||||
if not assert_order_options:
|
||||
raise
|
||||
continue
|
||||
sorted_writable_data = sorted(writable.data[0].strip().split(','))
|
||||
sorted_expected_data = sorted("foo:int,bar:str,spam:float".split(','))
|
||||
self.assertEqual(sorted_writable_data, sorted_expected_data)
|
||||
|
||||
def test_list_databases(self):
|
||||
'''
|
||||
|
|
|
@ -54,10 +54,11 @@ class PillarModuleTestCase(TestCase, LoaderModuleMockMixin):
|
|||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
def test_ls(self):
|
||||
with patch('salt.modules.pillar.items', MagicMock(return_value=pillar_value_1)):
|
||||
ls = sorted(pillarmod.ls())
|
||||
if six.PY3:
|
||||
self.assertCountEqual(pillarmod.ls(), ['a', 'b'])
|
||||
self.assertCountEqual(ls, ['a', 'b'])
|
||||
else:
|
||||
self.assertEqual(pillarmod.ls(), ['a', 'b'])
|
||||
self.assertEqual(ls, ['a', 'b'])
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
def test_pillar_get_default_merge(self):
|
||||
|
|
|
@ -66,6 +66,6 @@ class JsonTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'"error": "Unable to serialize output to json"}')
|
||||
ret = json_out.output(data)
|
||||
if six.PY2:
|
||||
self.assertEqual(expect, ret)
|
||||
self.assertEqual(sorted(expect), sorted(ret))
|
||||
else:
|
||||
self.assertEqual(json.loads(ret), data)
|
||||
|
|
|
@ -143,7 +143,7 @@ class TestSerializers(TestCase):
|
|||
|
||||
# BLAAM! yml_src is not valid !
|
||||
final_obj = OrderedDict(yaml.deserialize(yml_src))
|
||||
assert obj != final_obj
|
||||
assert obj != final_obj, 'Objects matched! {} == {}'.format(obj, final_obj)
|
||||
|
||||
@skipIf(not yamlex.available, SKIP_MESSAGE % 'sls')
|
||||
def test_sls_aggregate(self):
|
||||
|
|
|
@ -14,9 +14,6 @@ from tests.support.mock import (
|
|||
call
|
||||
)
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.states.proxy as proxy
|
||||
|
||||
|
@ -70,9 +67,7 @@ class ProxyTestCase(TestCase, LoaderModuleMockMixin):
|
|||
with patch.dict(proxy.__salt__, patches):
|
||||
out = proxy.managed('192.168.0.1', '3128', user='frank', password='passw0rd',
|
||||
bypass_domains=['salt.com', 'test.com'])
|
||||
if six.PY3:
|
||||
# Sorting is different in Py3
|
||||
out['changes']['new'][-1]['bypass_domains'] = sorted(out['changes']['new'][-1]['bypass_domains'])
|
||||
out['changes']['new'][-1]['bypass_domains'] = sorted(out['changes']['new'][-1]['bypass_domains'])
|
||||
|
||||
calls = [
|
||||
call('192.168.0.1', '3128', 'frank', 'passw0rd', 'Ethernet'),
|
||||
|
|
|
@ -38,6 +38,7 @@ EXCLUDED_FILES = [
|
|||
os.path.join('tests', 'modparser.py'),
|
||||
os.path.join('tests', 'committer_parser.py'),
|
||||
os.path.join('tests', 'zypp_plugin.py'),
|
||||
os.path.join('tests', 'tox-helper.py'),
|
||||
os.path.join('tests', 'unit', 'transport', 'mixins.py'),
|
||||
os.path.join('tests', 'integration', 'utils', 'testprogram.py'),
|
||||
]
|
||||
|
@ -57,7 +58,7 @@ class BadTestModuleNamesTestCase(TestCase):
|
|||
excluded_dirs = tuple(EXCLUDED_DIRS)
|
||||
tests_dir = os.path.join(CODE_DIR, 'tests')
|
||||
bad_names = []
|
||||
for root, dirs, files in os.walk(tests_dir):
|
||||
for root, _, files in os.walk(tests_dir):
|
||||
reldir = os.path.relpath(root, CODE_DIR)
|
||||
if reldir.startswith(excluded_dirs) or reldir.endswith('__pycache__'):
|
||||
continue
|
||||
|
@ -73,7 +74,7 @@ class BadTestModuleNamesTestCase(TestCase):
|
|||
error_msg = '\n\nPlease rename the following files:\n'
|
||||
for path in bad_names:
|
||||
directory, filename = path.rsplit(os.sep, 1)
|
||||
filename, ext = os.path.splitext(filename)
|
||||
filename, _ = os.path.splitext(filename)
|
||||
error_msg += ' {} -> {}/test_{}.py\n'.format(path, directory, filename.split('_test')[0])
|
||||
|
||||
error_msg += '\nIf you believe one of the entries above should be ignored, please add it to either\n'
|
||||
|
|
210
tox.ini
210
tox.ini
|
@ -1,13 +1,216 @@
|
|||
[tox]
|
||||
envlist = py27,py34,py35,py36,pylint-salt,pylint-tests
|
||||
envlist =
|
||||
py{27,34,35,36},
|
||||
py{27,34,35,36}-coverage,
|
||||
py{27,34,35,36}-pytest,
|
||||
py{27,34,35,36}-runtests,
|
||||
py{27,34,35,36}-pytest-coverage,
|
||||
py{27,34,35,36}-runtests-coverage,
|
||||
pylint-salt,
|
||||
pylint-tests
|
||||
skip_missing_interpreters = True
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
deps = -Ur{toxinidir}/requirements/tests.txt
|
||||
commands = pytest --rootdir {toxinidir} {posargs}
|
||||
changedir = {toxinidir}
|
||||
commands_pre = {envpython} tests/tox-helper.py create-dirs
|
||||
passenv = LANG HOME
|
||||
sitepackages = True
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:runtests]
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
unittest-xml-reporting
|
||||
commands = {envpython} {toxinidir}/tests/runtests.py --tests-logfile={toxinidir}/artifacts/logs/runtests.log {posargs}
|
||||
|
||||
[testenv:pytest]
|
||||
commands = pytest --rootdir {toxinidir} --log-file={toxinidir}/artifacts/logs/runtests.log {posargs}
|
||||
|
||||
[testenv:runtests-coverage]
|
||||
# Add tests/support/coverage to PYTHONPATH in order to get code coverage from subprocesses.
|
||||
setenv =
|
||||
PYTHONPATH={toxinidir}/tests/support/coverage
|
||||
commands_pre =
|
||||
- coverage erase
|
||||
commands =
|
||||
coverage run -m tests.runtests {posargs}
|
||||
commands_post =
|
||||
- coverage combine
|
||||
- coverage xml -o {toxinidir}/artifacts/coverage/coverage.xml
|
||||
|
||||
[testenv:pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands = coverage run -m py.test --rootdir {toxinidir} {posargs}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py2-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py2-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py2-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py2-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py2-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
[testenv:py27-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py27-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py27-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py27-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py27-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
[testenv:py3-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py3-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py3-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py3-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py3-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:py34-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py34-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py34-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py34-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py34-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:py35-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py35-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py35-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py35-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py35-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:py36-pytest]
|
||||
commands = {[testenv:pytest]commands}
|
||||
|
||||
[testenv:py36-runtests]
|
||||
deps = {[testenv:runtests]deps}
|
||||
commands = {[testenv:runtests]commands}
|
||||
|
||||
[testenv:py36-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py36-runtests-coverage]
|
||||
deps = {[testenv:runtests]deps}
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:runtests-coverage]commands}
|
||||
commands_pre = {[testenv:runtests-coverage]commands_pre}
|
||||
commands_post = {[testenv:runtests-coverage]commands_post}
|
||||
|
||||
[testenv:py36-pytest-coverage]
|
||||
setenv = {[testenv:runtests-coverage]setenv}
|
||||
commands = {[testenv:pytest-coverage]commands}
|
||||
commands_pre = {[testenv:pytest-coverage]commands_pre}
|
||||
commands_post = {[testenv:pytest-coverage]commands_post}
|
||||
|
||||
|
||||
[testenv:pylint-salt]
|
||||
basepython = python2.7
|
||||
|
@ -17,6 +220,7 @@ commands =
|
|||
pylint --rcfile=.testing.pylintrc --disable=I,W1307,C0411,C0413,W8410,str-format-in-logging {posargs:setup.py salt/}
|
||||
sitepackages = False
|
||||
|
||||
|
||||
[testenv:pylint-tests]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/requirements/dev.txt
|
||||
|
@ -26,6 +230,6 @@ commands =
|
|||
sitepackages = False
|
||||
|
||||
[pytest]
|
||||
addopts = --log-file /tmp/salt-runtests.log --no-print-logs --ssh-tests -ra -sv
|
||||
addopts = --no-print-logs --ssh-tests -ra -sv
|
||||
testpaths = tests
|
||||
norecursedirs = tests/kitchen
|
||||
|
|
Loading…
Add table
Reference in a new issue