123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- # -*- coding: utf-8 -*-
- """
- tests.unit.version_test
- ~~~~~~~~~~~~~~~~~~~~~~~
- These tests are copied from python's source `Lib/distutils/tests/test_version.py`
- Some new examples were added and some adjustments were made to run tests in python 2 and 3
- """
- # pylint: disable=string-substitution-usage-error
- # Import python libs
- from __future__ import absolute_import, print_function, unicode_literals
- import datetime
- import os
- import sys
- import warnings
- import pytest
- # Import Salt libs
- import salt.modules.cmdmod
- import salt.utils.platform
- import salt.utils.versions
- import salt.version
- # Import 3rd-party libs
- from salt.ext import six
- from salt.utils.versions import LooseVersion, StrictVersion
- from tests.support.mock import patch
- from tests.support.paths import CODE_DIR
- # Import Salt Testing libs
- 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")
- version = StrictVersion("1.2.0")
- self.assertEqual(six.text_type(version), "1.2")
- def test_cmp_strict(self):
- versions = (
- ("1.5.1", "1.5.2b2", -1),
- ("161", "3.10a", ValueError),
- ("8.02", "8.02", 0),
- ("3.4j", "1996.07.12", ValueError),
- ("3.2.pl0", "3.1.1.6", ValueError),
- ("2g6", "11g", ValueError),
- ("0.9", "2.2", -1),
- ("1.2.1", "1.2", 1),
- ("1.1", "1.2.2", -1),
- ("1.2", "1.1", 1),
- ("1.2.1", "1.2.2", -1),
- ("1.2.2", "1.2", 1),
- ("1.2", "1.2.2", -1),
- ("0.4.0", "0.4", 0),
- ("1.13++", "5.5.kw", ValueError),
- # Added by us
- ("1.1.1a1", "1.1.1", -1),
- )
- for v1, v2, wanted in versions:
- try:
- res = getattr(StrictVersion(v1), cmp_method)(StrictVersion(v2))
- except ValueError:
- if wanted is ValueError:
- continue
- else:
- raise AssertionError(
- ("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)
- )
- def test_cmp(self):
- versions = (
- ("1.5.1", "1.5.2b2", -1),
- ("161", "3.10a", 1),
- ("8.02", "8.02", 0),
- ("3.4j", "1996.07.12", -1),
- ("3.2.pl0", "3.1.1.6", 1),
- ("2g6", "11g", -1),
- ("0.960923", "2.2beta29", -1),
- ("1.13++", "5.5.kw", -1),
- # Added by us
- ("3.10.0-514.el7", "3.10.0-514.6.1.el7", 1),
- ("2.2.2", "2.12.1", -1),
- )
- for v1, v2, wanted in versions:
- res = getattr(LooseVersion(v1), cmp_method)(LooseVersion(v2))
- self.assertEqual(
- res, wanted, "cmp(%s, %s) should be %s, got %s" % (v1, v2, wanted, res)
- )
- @skipIf(not salt.utils.platform.is_linux(), "only need to run on linux")
- @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
- def test_spelling_version_name(self):
- """
- check the spelling of the version name for the release
- names in the salt.utils.versions.warn_until call
- """
- query = "salt.utils.versions.warn_until("
- names = salt.version.SaltStackVersion.NAMES
- cmd = "grep -lr {} -A 1 {}".format(query, os.path.join(CODE_DIR, "salt"))
- 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)
- )
- ver_cmd = salt.modules.cmdmod.run_stdout(
- "grep {0} {1} -A 1".format(query, line)
- )
- if "pyc" in line:
- break
- match = 0
- for key in names:
- if key in ver_cmd:
- match = match + (ver_cmd.count(key))
- if "utils/__init__.py" in line:
- # work around for utils/__init__.py because
- # it includes the warn_utils function
- match = match + 1
- self.assertEqual(
- match,
- int(num_cmd),
- msg="The file: {0} 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),
- )
- class VersionFuncsTestCase(TestCase):
- def test_compare(self):
- ret = salt.utils.versions.compare("1.0", "==", "1.0")
- self.assertTrue(ret)
- ret = salt.utils.versions.compare("1.0", "!=", "1.0")
- self.assertFalse(ret)
- with patch.object(salt.utils.versions, "log") as log_mock:
- ret = salt.utils.versions.compare(
- "1.0", "HAH I AM NOT A COMP OPERATOR! I AM YOUR FATHER!", "1.0"
- )
- self.assertTrue(log_mock.error.called)
- def test_kwargs_warn_until(self):
- # Test invalid version arg
- self.assertRaises(RuntimeError, salt.utils.versions.kwargs_warn_until, {}, [])
- def test_warn_until_warning_raised(self):
- # We *always* want *all* warnings thrown on this module
- warnings.filterwarnings("always", "", DeprecationWarning, __name__)
- def raise_warning(_version_info_=(0, 16, 0)):
- salt.utils.versions.warn_until(
- (0, 17), "Deprecation Message!", _version_info_=_version_info_
- )
- def raise_named_version_warning(_version_info_=(0, 16, 0)):
- salt.utils.versions.warn_until(
- "Hydrogen", "Deprecation Message!", _version_info_=_version_info_
- )
- # 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)
- )
- # 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)
- )
- # the deprecation warning is not issued because we passed
- # _dont_call_warning
- with warnings.catch_warnings(record=True) as recorded_warnings:
- salt.utils.versions.warn_until(
- (0, 17), "Foo", _dont_call_warnings=True, _version_info_=(0, 16)
- )
- self.assertEqual(0, len(recorded_warnings))
- # Let's set version info to (0, 17), a RuntimeError should be raised
- with self.assertRaisesRegex(
- RuntimeError,
- r"The warning triggered on filename \'(.*)test_versions.py\', "
- r"line number ([\d]+), is supposed to be shown until version "
- r"0.17.0 is released. Current version is now 0.17.0. "
- r"Please remove the warning.",
- ):
- raise_warning(_version_info_=(0, 17, 0))
- # Let's set version info to (0, 17), a RuntimeError should be raised
- with self.assertRaisesRegex(
- RuntimeError,
- r"The warning triggered on filename \'(.*)test_versions.py\', "
- r"line number ([\d]+), is supposed to be shown until version "
- r"(.*) is released. Current version is now "
- r"([\d.]+). Please remove the warning.",
- ):
- raise_named_version_warning(
- _version_info_=(
- getattr(sys, "maxint", None) or getattr(sys, "maxsize"),
- 16,
- 0,
- )
- )
- # Even though we're calling warn_until, we pass _dont_call_warnings
- # because we're only after the RuntimeError
- with self.assertRaisesRegex(
- RuntimeError,
- r"The warning triggered on filename \'(.*)test_versions.py\', "
- r"line number ([\d]+), is supposed to be shown until version "
- r"0.17.0 is released. Current version is now "
- r"(.*). Please remove the warning.",
- ):
- salt.utils.versions.warn_until((0, 17), "Foo", _dont_call_warnings=True)
- with self.assertRaisesRegex(
- RuntimeError,
- r"The warning triggered on filename \'(.*)test_versions.py\', "
- r"line number ([\d]+), is supposed to be shown until version "
- r"(.*) is released. Current version is now "
- r"(.*). Please remove the warning.",
- ):
- salt.utils.versions.warn_until(
- "Hydrogen",
- "Foo",
- _dont_call_warnings=True,
- _version_info_=(
- getattr(sys, "maxint", None) or getattr(sys, "maxsize"),
- 16,
- 0,
- ),
- )
- # version on the deprecation message gets properly formatted
- with warnings.catch_warnings(record=True) as recorded_warnings:
- vrs = salt.version.SaltStackVersion.from_name("Helium")
- salt.utils.versions.warn_until(
- "Helium",
- "Deprecation Message until {version}!",
- _version_info_=(vrs.major - 1, 0),
- )
- self.assertEqual(
- "Deprecation Message until {0}!".format(vrs.formatted_version),
- six.text_type(recorded_warnings[0].message),
- )
- def test_kwargs_warn_until_warning_raised(self):
- # We *always* want *all* warnings thrown on this module
- warnings.filterwarnings("always", "", DeprecationWarning, __name__)
- def raise_warning(**kwargs):
- _version_info_ = kwargs.pop("_version_info_", (0, 16, 0))
- salt.utils.versions.kwargs_warn_until(
- kwargs, (0, 17), _version_info_=_version_info_
- )
- # raise_warning({...}) should show warning until version info is >= (0, 17)
- with warnings.catch_warnings(record=True) as recorded_warnings:
- raise_warning(foo=42) # with a kwarg
- 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),
- )
- # With no **kwargs, should not show warning until version info is >= (0, 17)
- with warnings.catch_warnings(record=True) as recorded_warnings:
- salt.utils.versions.kwargs_warn_until(
- {}, (0, 17), _version_info_=(0, 16, 0) # no kwargs
- )
- self.assertEqual(0, len(recorded_warnings))
- # Let's set version info to (0, 17), a RuntimeError should be raised
- # regardless of whether or not we pass any **kwargs.
- with self.assertRaisesRegex(
- RuntimeError,
- r"The warning triggered on filename \'(.*)test_versions.py\', "
- r"line number ([\d]+), is supposed to be shown until version "
- r"0.17.0 is released. Current version is now 0.17.0. "
- r"Please remove the warning.",
- ):
- raise_warning(_version_info_=(0, 17)) # no kwargs
- with self.assertRaisesRegex(
- RuntimeError,
- r"The warning triggered on filename \'(.*)test_versions.py\', "
- r"line number ([\d]+), is supposed to be shown until version "
- r"0.17.0 is released. Current version is now 0.17.0. "
- r"Please remove the warning.",
- ):
- raise_warning(bar="baz", qux="quux", _version_info_=(0, 17)) # some kwargs
- def test_warn_until_date_warning_raised(self):
- # We *always* want *all* warnings thrown on this module
- warnings.filterwarnings("always", "", DeprecationWarning, __name__)
- _current_date = datetime.date(2000, 1, 1)
- # Test warning with datetime.date instance
- with warnings.catch_warnings(record=True) as recorded_warnings:
- salt.utils.versions.warn_until_date(
- datetime.date(2000, 1, 2),
- "Deprecation Message!",
- _current_date=_current_date,
- )
- self.assertEqual(
- "Deprecation Message!", six.text_type(recorded_warnings[0].message)
- )
- # Test warning with datetime.datetime instance
- with warnings.catch_warnings(record=True) as recorded_warnings:
- salt.utils.versions.warn_until_date(
- datetime.datetime(2000, 1, 2),
- "Deprecation Message!",
- _current_date=_current_date,
- )
- self.assertEqual(
- "Deprecation Message!", six.text_type(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)
- )
- # the deprecation warning is not issued because we passed
- # _dont_call_warning
- with warnings.catch_warnings(record=True) as recorded_warnings:
- salt.utils.versions.warn_until_date(
- "20000102",
- "Deprecation Message!",
- _dont_call_warnings=True,
- _current_date=_current_date,
- )
- self.assertEqual(0, len(recorded_warnings))
- # Let's test for RuntimeError raise
- with self.assertRaisesRegex(
- RuntimeError,
- r"Deprecation Message! This warning\(now exception\) triggered on "
- r"filename \'(.*)test_versions.py\', line number ([\d]+), is "
- r"supposed to be shown until ([\d-]+). Today is ([\d-]+). "
- r"Please remove the warning.",
- ):
- salt.utils.versions.warn_until_date("20000101", "Deprecation Message!")
- # Even though we're calling warn_until_date, we pass _dont_call_warnings
- # because we're only after the RuntimeError
- with self.assertRaisesRegex(
- RuntimeError,
- r"Deprecation Message! This warning\(now exception\) triggered on "
- r"filename \'(.*)test_versions.py\', line number ([\d]+), is "
- r"supposed to be shown until ([\d-]+). Today is ([\d-]+). "
- r"Please remove the warning.",
- ):
- salt.utils.versions.warn_until_date(
- "20000101",
- "Deprecation Message!",
- _dont_call_warnings=True,
- _current_date=_current_date,
- )
- def test_warn_until_date_bad_strptime_format(self):
- # We *always* want *all* warnings thrown on this module
- warnings.filterwarnings("always", "", DeprecationWarning, __name__)
- # Let's test for RuntimeError raise
- with self.assertRaisesRegex(
- ValueError, "time data '0022' does not match format '%Y%m%d'"
- ):
- salt.utils.versions.warn_until_date("0022", "Deprecation Message!")
|