Support testing against system installed version (#57764)

* Drop six usage and Py2 support

Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com>

* Fix import grouping in tests/unit/modules/test_baredoc.py

Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com>

* Support testing against system installed version

The Debian package of salt comes with an autopkgtest, which runs the
unit tests against the install salt package:

```
cp -r conf scripts tests "$AUTOPKGTEST_TMP"
cd "$AUTOPKGTEST_TMP"
LC_ALL=C.UTF-8 NO_INTERNET=1 python3 ./tests/runtests.py -v --no-report --unit
```

Some test cases fail, because the salt source code is not in `CODE_DIR`.
To support testing against system installed version, just import `salt`
to determine the location of the module and set `SALT_CODE_DIR` to it.

`test_check_virtualname` and `test_module_name_source_match` can now run
against the system installed version and do not need to be skipped any
more.

Signed-off-by: Benjamin Drung <benjamin.drung@cloud.ionos.com>

* Running pre-commit bits manually.

Co-authored-by: Gareth J. Greenaway <gareth@wiked.org>
Co-authored-by: Gareth J. Greenaway <gareth@saltstack.com>
This commit is contained in:
Benjamin Drung 2020-10-06 00:36:49 +02:00 committed by GitHub
parent fa18de7ae3
commit 5539fc0f52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 103 deletions

View file

@ -10,17 +10,18 @@
Tests related paths
"""
import logging
import os
import re
import sys
import tempfile
import salt
import salt.utils.path
log = logging.getLogger(__name__)
SALT_CODE_DIR = os.path.dirname(os.path.normpath(os.path.abspath(salt.__file__)))
TESTS_DIR = os.path.dirname(
os.path.dirname(os.path.normpath(os.path.abspath(__file__)))
)

View file

@ -206,6 +206,7 @@ RUNTIME_VARS = RuntimeVars(
RUNNING_TESTS_USER=this_user(),
RUNTIME_CONFIGS={},
CODE_DIR=paths.CODE_DIR,
SALT_CODE_DIR=paths.SALT_CODE_DIR,
BASE_FILES=paths.BASE_FILES,
PROD_FILES=paths.PROD_FILES,
TESTS_DIR=paths.TESTS_DIR,

View file

@ -1,16 +1,6 @@
# -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import
import os
# Import module
import salt.modules.baredoc as baredoc
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.runtests import RUNTIME_VARS
# Import Salt Testing Libs
from tests.support.unit import TestCase
@ -22,10 +12,8 @@ class BaredocTest(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {
baredoc: {
"__opts__": {
"extension_modules": os.path.join(RUNTIME_VARS.CODE_DIR, "salt"),
},
"__grains__": {"saltpath": os.path.join(RUNTIME_VARS.CODE_DIR, "salt")},
"__opts__": {"extension_modules": RUNTIME_VARS.SALT_CODE_DIR},
"__grains__": {"saltpath": RUNTIME_VARS.SALT_CODE_DIR},
}
}

View file

@ -3,19 +3,14 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
# Import Python libs
import fnmatch
import os
# Import Salt libs
import salt.utils.path
import salt.utils.stringutils
# Import Salt Testing libs
from tests.support.paths import list_test_mods
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase, skipIf
from tests.support.unit import TestCase
EXCLUDED_DIRS = [
os.path.join("tests", "integration", "cloud", "helpers"),
@ -102,10 +97,6 @@ class BadTestModuleNamesTestCase(TestCase):
error_msg += "If it is a tests module, then please rename as suggested."
self.assertEqual([], bad_names, error_msg)
@skipIf(
not os.path.isdir(os.path.join(RUNTIME_VARS.CODE_DIR, "salt")),
"Failed to find salt directory in '{}'.".format(RUNTIME_VARS.CODE_DIR),
)
def test_module_name_source_match(self):
"""
Check all the test mods and check if they correspond to actual files in
@ -242,11 +233,11 @@ class BadTestModuleNamesTestCase(TestCase):
# The path from the root of the repo
relpath = salt.utils.path.join(
"salt", stem.replace(".", os.sep), ".".join((flower[5:], "py"))
stem.replace(".", os.sep), ".".join((flower[5:], "py"))
)
# The full path to the file we expect to find
abspath = salt.utils.path.join(RUNTIME_VARS.CODE_DIR, relpath)
abspath = salt.utils.path.join(RUNTIME_VARS.SALT_CODE_DIR, relpath)
if not os.path.isfile(abspath):
# Maybe this is in a dunder init?

View file

@ -1,32 +1,19 @@
# -*- coding: utf-8 -*-
"""
tests.unit.test_virtualname
~~~~~~~~~~~~~~~~~~~~
"""
# Import Python libs
from __future__ import absolute_import
import importlib.util
import logging
import os
# Import Salt libs
import salt.ext.six as six
# Import Salt Testing libs
from tests.support.runtests import RUNTIME_VARS
from tests.support.unit import TestCase, skipIf
try:
import importlib.util
except ImportError:
import imp
from tests.support.unit import TestCase
log = logging.getLogger(__name__)
class FakeEntry(object):
class FakeEntry:
def __init__(self, name, path, is_file=True):
self.name = name
self.path = path
@ -46,18 +33,9 @@ class VirtualNameTestCase(TestCase):
@staticmethod
def _import_module(testpath):
if six.PY3:
spec = importlib.util.spec_from_file_location("tmpmodule", testpath)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
else:
fp, pathname, description = imp.find_module("tmpmodule", testpath)
try:
module = imp.load_module("tmpmodule", fp, pathname, description)
finally:
# Since we may exit via an exception, close fp explicitly.
if fp:
fp.close()
spec = importlib.util.spec_from_file_location("tmpmodule", testpath)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _check_modules(self, path):
@ -78,29 +56,25 @@ class VirtualNameTestCase(TestCase):
if hasattr(module, "__virtualname__"):
if module.__virtualname__ not in name:
ret.append(
'Virtual name "{0}" is not in the module filename "{1}": {2}'.format(
'Virtual name "{}" is not in the module filename "{}": {}'.format(
module.__virtualname__, name, path
)
)
return ret
@skipIf(
not os.path.isdir(os.path.join(RUNTIME_VARS.CODE_DIR, "salt")),
"Failed to find salt directory in '{}'.".format(RUNTIME_VARS.CODE_DIR),
)
def test_check_virtualname(self):
"""
Test that the virtualname is in __name__ of the module
"""
errors = []
for entry in os.listdir(os.path.join(RUNTIME_VARS.CODE_DIR, "salt/")):
for entry in os.listdir(RUNTIME_VARS.SALT_CODE_DIR):
name, path = os.path.splitext(os.path.basename(entry))[0], entry
if name.startswith(".") or name.startswith("_") or not os.path.isdir(path):
continue
if name in ("cli", "defaults", "spm", "daemons", "ext", "templates"):
continue
if name == "cloud":
entry = os.path.join(RUNTIME_VARS.CODE_DIR, "salt", "cloud", "clouds")
entry = os.path.join(RUNTIME_VARS.SALT_CODE_DIR, "cloud", "clouds")
errors.extend(self._check_modules(entry))
for error in errors:
log.critical(error)

View file

@ -43,7 +43,7 @@ class SSHThinTestCase(TestCase):
self.ext_conf = {
"test": {
"py-version": [2, 7],
"path": os.path.join(RUNTIME_VARS.CODE_DIR, "salt"),
"path": RUNTIME_VARS.SALT_CODE_DIR,
"dependencies": {"jinja2": self.jinja_fp},
}
}

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
tests.unit.version_test
~~~~~~~~~~~~~~~~~~~~~~~
@ -8,8 +7,6 @@
"""
# pylint: disable=string-substitution-usage-error
from __future__ import absolute_import, print_function, unicode_literals
import datetime
import os
import sys
@ -19,28 +16,22 @@ import salt.modules.cmdmod
import salt.utils.platform
import salt.utils.versions
import salt.version
from salt.ext import six
from salt.utils.versions import LooseVersion, StrictVersion
from tests.support.helpers import slowTest
from tests.support.mock import patch
from tests.support.paths import CODE_DIR
from tests.support.paths import SALT_CODE_DIR
from tests.support.unit import TestCase, skipIf
if six.PY2:
cmp_method = "__cmp__"
else:
cmp_method = "_cmp"
class VersionTestCase(TestCase):
def test_prerelease(self):
version = StrictVersion("1.2.3a1")
self.assertEqual(version.version, (1, 2, 3))
self.assertEqual(version.prerelease, ("a", 1))
self.assertEqual(six.text_type(version), "1.2.3a1")
self.assertEqual(str(version), "1.2.3a1")
version = StrictVersion("1.2.0")
self.assertEqual(six.text_type(version), "1.2")
self.assertEqual(str(version), "1.2")
def test_cmp_strict(self):
versions = (
@ -65,7 +56,7 @@ class VersionTestCase(TestCase):
for v1, v2, wanted in versions:
try:
res = getattr(StrictVersion(v1), cmp_method)(StrictVersion(v2))
res = StrictVersion(v1)._cmp(StrictVersion(v2))
except ValueError:
if wanted is ValueError:
continue
@ -74,7 +65,9 @@ class VersionTestCase(TestCase):
("cmp(%s, %s) " "shouldn't raise ValueError") % (v1, v2)
)
self.assertEqual(
res, wanted, "cmp(%s, %s) should be %s, got %s" % (v1, v2, wanted, res)
res,
wanted,
"cmp({}, {}) should be {}, got {}".format(v1, v2, wanted, res),
)
def test_cmp(self):
@ -93,9 +86,11 @@ class VersionTestCase(TestCase):
)
for v1, v2, wanted in versions:
res = getattr(LooseVersion(v1), cmp_method)(LooseVersion(v2))
res = LooseVersion(v1)._cmp(LooseVersion(v2))
self.assertEqual(
res, wanted, "cmp(%s, %s) should be %s, got %s" % (v1, v2, wanted, res)
res,
wanted,
"cmp({}, {}) should be {}, got {}".format(v1, v2, wanted, res),
)
@skipIf(not salt.utils.platform.is_linux(), "only need to run on linux")
@ -108,16 +103,16 @@ class VersionTestCase(TestCase):
query = "salt.utils.versions.warn_until("
names = salt.version.SaltStackVersion.NAMES
cmd = "grep -lr {} -A 1 {}".format(query, os.path.join(CODE_DIR, "salt"))
cmd = ["grep", "-lr", query, "-A", "1", SALT_CODE_DIR]
grep_call = salt.modules.cmdmod.run_stdout(cmd=cmd).split(os.linesep)
for line in grep_call:
num_cmd = salt.modules.cmdmod.run_stdout(
"grep -c {0} {1}".format(query, line)
"grep -c {} {}".format(query, line)
)
ver_cmd = salt.modules.cmdmod.run_stdout(
"grep {0} {1} -A 1".format(query, line)
"grep {} {} -A 1".format(query, line)
)
if "pyc" in line:
break
@ -133,10 +128,10 @@ class VersionTestCase(TestCase):
self.assertEqual(
match,
int(num_cmd),
msg="The file: {0} has an "
msg="The file: {} has an "
"incorrect spelling for the release name in the warn_utils "
"call: {1}. Expecting one of these release names: "
"{2}".format(line, ver_cmd, names),
"call: {}. Expecting one of these release names: "
"{}".format(line, ver_cmd, names),
)
@ -175,16 +170,12 @@ class VersionFuncsTestCase(TestCase):
# raise_warning should show warning until version info is >= (0, 17)
with warnings.catch_warnings(record=True) as recorded_warnings:
raise_warning()
self.assertEqual(
"Deprecation Message!", six.text_type(recorded_warnings[0].message)
)
self.assertEqual("Deprecation Message!", str(recorded_warnings[0].message))
# raise_warning should show warning until version info is >= (0, 17)
with warnings.catch_warnings(record=True) as recorded_warnings:
raise_named_version_warning()
self.assertEqual(
"Deprecation Message!", six.text_type(recorded_warnings[0].message)
)
self.assertEqual("Deprecation Message!", str(recorded_warnings[0].message))
# the deprecation warning is not issued because we passed
# _dont_call_warning
@ -258,8 +249,8 @@ class VersionFuncsTestCase(TestCase):
_version_info_=(vrs.major - 1, 0),
)
self.assertEqual(
"Deprecation Message until {0}!".format(vrs.formatted_version),
six.text_type(recorded_warnings[0].message),
"Deprecation Message until {}!".format(vrs.formatted_version),
str(recorded_warnings[0].message),
)
def test_kwargs_warn_until_warning_raised(self):
@ -278,7 +269,7 @@ class VersionFuncsTestCase(TestCase):
self.assertEqual(
"The following parameter(s) have been deprecated and "
"will be removed in '0.17.0': 'foo'.",
six.text_type(recorded_warnings[0].message),
str(recorded_warnings[0].message),
)
# With no **kwargs, should not show warning until version info is >= (0, 17)
with warnings.catch_warnings(record=True) as recorded_warnings:
@ -320,9 +311,7 @@ class VersionFuncsTestCase(TestCase):
"Deprecation Message!",
_current_date=_current_date,
)
self.assertEqual(
"Deprecation Message!", six.text_type(recorded_warnings[0].message)
)
self.assertEqual("Deprecation Message!", str(recorded_warnings[0].message))
# Test warning with datetime.datetime instance
with warnings.catch_warnings(record=True) as recorded_warnings:
@ -331,18 +320,14 @@ class VersionFuncsTestCase(TestCase):
"Deprecation Message!",
_current_date=_current_date,
)
self.assertEqual(
"Deprecation Message!", six.text_type(recorded_warnings[0].message)
)
self.assertEqual("Deprecation Message!", str(recorded_warnings[0].message))
# Test warning with date as a string
with warnings.catch_warnings(record=True) as recorded_warnings:
salt.utils.versions.warn_until_date(
"20000102", "Deprecation Message!", _current_date=_current_date
)
self.assertEqual(
"Deprecation Message!", six.text_type(recorded_warnings[0].message)
)
self.assertEqual("Deprecation Message!", str(recorded_warnings[0].message))
# the deprecation warning is not issued because we passed
# _dont_call_warning