updates
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,64 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""TestExtensionManager
|
||||
|
||||
Extension manager used only for testing.
|
||||
"""
|
||||
|
||||
from typing import TypeVar
|
||||
import warnings
|
||||
|
||||
from stevedore import extension
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class TestExtensionManager(extension.ExtensionManager[T]):
|
||||
"""ExtensionManager that is explicitly initialized for tests.
|
||||
|
||||
.. deprecated:: 0.13
|
||||
|
||||
Use the :func:`make_test_instance` class method of the class
|
||||
being replaced by the test instance instead of using this class
|
||||
directly.
|
||||
|
||||
:param extensions: Pre-configured Extension instances to use instead of
|
||||
loading them from entry points.
|
||||
:param namespace: The namespace for the entry points.
|
||||
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||
object returned by the entry point after the driver is loaded.
|
||||
:param invoke_args: Positional arguments to pass when invoking
|
||||
the object returned by the entry point. Only used if invoke_on_load
|
||||
is True.
|
||||
:param invoke_kwds: Named arguments to pass when invoking
|
||||
the object returned by the entry point. Only used if invoke_on_load
|
||||
is True.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
extensions,
|
||||
namespace='test',
|
||||
invoke_on_load=False,
|
||||
invoke_args=(),
|
||||
invoke_kwds={},
|
||||
):
|
||||
super().__init__(namespace, invoke_on_load, invoke_args, invoke_kwds)
|
||||
self.extensions = extensions
|
||||
warnings.warn(
|
||||
'TestExtesionManager has been replaced by make_test_instance()',
|
||||
DeprecationWarning,
|
||||
)
|
||||
|
||||
def _load_plugins(self, *args, **kwds):
|
||||
return []
|
||||
@@ -0,0 +1,63 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for stevedore._cache"""
|
||||
|
||||
import sys
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from stevedore import _cache
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestCache(utils.TestCase):
|
||||
def test_disable_caching_executable(self):
|
||||
"""Test caching is disabled if python interpreter is located under /tmp
|
||||
directory (Ansible)
|
||||
"""
|
||||
with mock.patch.object(sys, 'executable', '/tmp/fake'):
|
||||
sot = _cache.Cache()
|
||||
self.assertTrue(sot._disable_caching)
|
||||
|
||||
def test_disable_caching_file(self):
|
||||
"""Test caching is disabled if .disable file is present in target
|
||||
dir
|
||||
"""
|
||||
cache_dir = _cache._get_cache_dir()
|
||||
|
||||
with mock.patch('os.path.isfile') as mock_path:
|
||||
mock_path.return_value = True
|
||||
sot = _cache.Cache()
|
||||
mock_path.assert_called_with(f'{cache_dir}/.disable')
|
||||
self.assertTrue(sot._disable_caching)
|
||||
|
||||
mock_path.return_value = False
|
||||
sot = _cache.Cache()
|
||||
self.assertFalse(sot._disable_caching)
|
||||
|
||||
@mock.patch('os.makedirs')
|
||||
@mock.patch('builtins.open')
|
||||
def test__get_data_for_path_no_write(self, mock_open, mock_mkdir):
|
||||
sot = _cache.Cache()
|
||||
sot._disable_caching = True
|
||||
mock_open.side_effect = IOError
|
||||
sot._get_data_for_path(('fake',))
|
||||
mock_mkdir.assert_not_called()
|
||||
|
||||
def test__build_cacheable_data(self):
|
||||
# this is a rubbish test as we don't actually do anything with the
|
||||
# data, but it's too hard to script since it's totally environmentally
|
||||
# dependent and mocking out the underlying calls would remove the value
|
||||
# of this test (we want to test those underlying API calls)
|
||||
ret = _cache._build_cacheable_data()
|
||||
self.assertIsInstance(ret['groups'], dict)
|
||||
@@ -0,0 +1,57 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for failure loading callback"""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from stevedore import extension
|
||||
from stevedore import named
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestCallback(utils.TestCase):
|
||||
def test_extension_failure_custom_callback(self):
|
||||
errors = []
|
||||
|
||||
def failure_callback(manager, entrypoint, error):
|
||||
errors.append((manager, entrypoint, error))
|
||||
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
invoke_on_load=True,
|
||||
on_load_failure_callback=failure_callback,
|
||||
)
|
||||
extensions = list(em.extensions)
|
||||
self.assertGreater(len(extensions), 0)
|
||||
self.assertEqual(len(errors), 2)
|
||||
for manager, entrypoint, error in errors:
|
||||
self.assertIs(manager, em)
|
||||
self.assertIsInstance(error, (IOError, ImportError))
|
||||
|
||||
@mock.patch('stevedore.extension.ExtensionManager._load_plugins')
|
||||
def test_missing_entrypoints_callback(self, load_fn):
|
||||
errors = set()
|
||||
|
||||
def callback(names):
|
||||
errors.update(names)
|
||||
|
||||
load_fn.return_value = [
|
||||
extension.Extension('foo', None, None, None) # type: ignore
|
||||
]
|
||||
named.NamedExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
names=['foo', 'bar'],
|
||||
invoke_on_load=True,
|
||||
on_missing_entrypoints_callback=callback,
|
||||
)
|
||||
self.assertEqual(errors, {'bar'})
|
||||
@@ -0,0 +1,103 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from typing import Any
|
||||
|
||||
from stevedore import dispatch
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
def check_dispatch(ep, /, *args, **kwds):
|
||||
return ep.name == 't2'
|
||||
|
||||
|
||||
class TestDispatch(utils.TestCase):
|
||||
def test_dispatch(self):
|
||||
def invoke(ep, /, *args, **kwds):
|
||||
return (ep.name, args, kwds)
|
||||
|
||||
em: dispatch.DispatchExtensionManager[Any]
|
||||
em = dispatch.DispatchExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
lambda *args, **kwds: True,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
self.assertEqual(len(em.extensions), 2)
|
||||
self.assertEqual(set(em.names()), {'t1', 't2'})
|
||||
|
||||
results = em.map(check_dispatch, invoke, 'first', named='named value')
|
||||
expected = [('t2', ('first',), {'named': 'named value'})]
|
||||
self.assertEqual(results, expected)
|
||||
|
||||
def test_dispatch_map_method(self):
|
||||
em: dispatch.DispatchExtensionManager[Any]
|
||||
em = dispatch.DispatchExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
lambda *args, **kwds: True,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
|
||||
results = em.map_method(check_dispatch, 'get_args_and_data', 'first')
|
||||
self.assertEqual(results, [(('a',), {'b': 'B'}, 'first')])
|
||||
|
||||
def test_name_dispatch(self):
|
||||
def invoke(ep, /, *args, **kwds):
|
||||
return (ep.name, args, kwds)
|
||||
|
||||
em: dispatch.DispatchExtensionManager[Any]
|
||||
em = dispatch.NameDispatchExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
lambda *args, **kwds: True,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
self.assertEqual(len(em.extensions), 2)
|
||||
self.assertEqual(set(em.names()), {'t1', 't2'})
|
||||
|
||||
results = em.map(['t2'], invoke, 'first', named='named value')
|
||||
expected = [('t2', ('first',), {'named': 'named value'})]
|
||||
self.assertEqual(results, expected)
|
||||
|
||||
def test_name_dispatch_ignore_missing(self):
|
||||
def invoke(ep, /, *args, **kwds):
|
||||
return (ep.name, args, kwds)
|
||||
|
||||
em: dispatch.DispatchExtensionManager[Any]
|
||||
em = dispatch.NameDispatchExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
lambda *args, **kwds: True,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
|
||||
results = em.map(['t3', 't1'], invoke, 'first', named='named value')
|
||||
expected = [('t1', ('first',), {'named': 'named value'})]
|
||||
self.assertEqual(results, expected)
|
||||
|
||||
def test_name_dispatch_map_method(self):
|
||||
em: dispatch.DispatchExtensionManager[Any]
|
||||
em = dispatch.NameDispatchExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
lambda *args, **kwds: True,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
|
||||
results = em.map_method(['t3', 't1'], 'get_args_and_data', 'first')
|
||||
self.assertEqual(results, [(('a',), {'b': 'B'}, 'first')])
|
||||
@@ -0,0 +1,101 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for stevedore.extension"""
|
||||
|
||||
import importlib.metadata
|
||||
from typing import Any
|
||||
|
||||
from stevedore import driver
|
||||
from stevedore import exception
|
||||
from stevedore import extension
|
||||
from stevedore.tests import test_extension
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestCallback(utils.TestCase):
|
||||
def test_detect_plugins(self):
|
||||
em: driver.DriverManager[Any]
|
||||
em = driver.DriverManager('stevedore.test.extension', 't1')
|
||||
names = sorted(em.names())
|
||||
self.assertEqual(names, ['t1'])
|
||||
|
||||
def test_call(self):
|
||||
def invoke(ext, /, *args, **kwds):
|
||||
return (ext.name, args, kwds)
|
||||
|
||||
em: driver.DriverManager[Any]
|
||||
em = driver.DriverManager('stevedore.test.extension', 't1')
|
||||
result = em(invoke, 'a', b='C')
|
||||
self.assertEqual(result, ('t1', ('a',), {'b': 'C'}))
|
||||
|
||||
def test_driver_property_not_invoked_on_load(self):
|
||||
em: driver.DriverManager[Any]
|
||||
em = driver.DriverManager(
|
||||
'stevedore.test.extension', 't1', invoke_on_load=False
|
||||
)
|
||||
d = em.driver
|
||||
self.assertIs(d, test_extension.FauxExtension)
|
||||
|
||||
def test_driver_property_invoked_on_load(self):
|
||||
em: driver.DriverManager[Any]
|
||||
em = driver.DriverManager(
|
||||
'stevedore.test.extension', 't1', invoke_on_load=True
|
||||
)
|
||||
d = em.driver
|
||||
self.assertIsInstance(d, test_extension.FauxExtension)
|
||||
|
||||
def test_no_drivers(self):
|
||||
try:
|
||||
driver.DriverManager('stevedore.test.extension.none', 't1')
|
||||
except exception.NoMatches as err:
|
||||
self.assertIn(
|
||||
"No 'stevedore.test.extension.none' driver found", str(err)
|
||||
)
|
||||
|
||||
def test_bad_driver(self):
|
||||
try:
|
||||
driver.DriverManager('stevedore.test.extension', 'e2')
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
self.assertEqual(False, "No error raised")
|
||||
|
||||
def test_multiple_drivers(self):
|
||||
# The idea for this test was contributed by clayg:
|
||||
# https://gist.github.com/clayg/6311348
|
||||
extensions: list[extension.Extension[Any]] = [
|
||||
extension.Extension(
|
||||
'backend',
|
||||
importlib.metadata.EntryPoint(
|
||||
'backend', 'pkg1:driver', 'backend'
|
||||
),
|
||||
lambda x: None,
|
||||
None,
|
||||
),
|
||||
extension.Extension(
|
||||
'backend',
|
||||
importlib.metadata.EntryPoint(
|
||||
'backend', 'pkg2:driver', 'backend'
|
||||
),
|
||||
lambda x: None,
|
||||
None,
|
||||
),
|
||||
]
|
||||
try:
|
||||
dm = driver.DriverManager.make_test_instance(extensions[0])
|
||||
# Call the initialization code that verifies the extension
|
||||
dm._init_plugins(extensions)
|
||||
except exception.MultipleMatches as err:
|
||||
self.assertIn("Multiple", str(err))
|
||||
else:
|
||||
self.fail('Should have had an error')
|
||||
@@ -0,0 +1,44 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from stevedore import enabled
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestEnabled(utils.TestCase):
|
||||
def test_enabled(self):
|
||||
def check_enabled(ep):
|
||||
return ep.name == 't2'
|
||||
|
||||
em = enabled.EnabledExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
check_enabled,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
self.assertEqual(len(em.extensions), 1)
|
||||
self.assertEqual(em.names(), ['t2'])
|
||||
|
||||
def test_enabled_after_load(self):
|
||||
def check_enabled(ext):
|
||||
return ext.obj and ext.name == 't2'
|
||||
|
||||
em = enabled.EnabledExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
check_enabled,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
self.assertEqual(len(em.extensions), 1)
|
||||
self.assertEqual(em.names(), ['t2'])
|
||||
@@ -0,0 +1,39 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for stevedore.example2.fields"""
|
||||
|
||||
from stevedore.example2 import fields
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestExampleFields(utils.TestCase):
|
||||
def test_simple_items(self):
|
||||
f = fields.FieldList(100)
|
||||
text = ''.join(f.format({'a': 'A', 'b': 'B'}))
|
||||
expected = '\n'.join([': a : A', ': b : B', ''])
|
||||
self.assertEqual(text, expected)
|
||||
|
||||
def test_long_item(self):
|
||||
f = fields.FieldList(25)
|
||||
text = ''.join(
|
||||
f.format({'name': 'a value longer than the allowed width'})
|
||||
)
|
||||
expected = '\n'.join(
|
||||
[
|
||||
': name : a value longer',
|
||||
' than the allowed',
|
||||
' width',
|
||||
'',
|
||||
]
|
||||
)
|
||||
self.assertEqual(text, expected)
|
||||
@@ -0,0 +1,24 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for stevedore.example.simple"""
|
||||
|
||||
from stevedore.example import simple
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestExampleSimple(utils.TestCase):
|
||||
def test_simple_items(self):
|
||||
f = simple.Simple(100)
|
||||
text = ''.join(f.format({'a': 'A', 'b': 'B'}))
|
||||
expected = '\n'.join(['a = A', 'b = B', ''])
|
||||
self.assertEqual(text, expected)
|
||||
@@ -0,0 +1,375 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for stevedore.extension"""
|
||||
|
||||
import importlib.metadata
|
||||
import operator
|
||||
from typing import Any
|
||||
from unittest import mock
|
||||
import warnings
|
||||
|
||||
from stevedore import exception
|
||||
from stevedore import extension
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
ALL_NAMES = ['e1', 't1', 't2']
|
||||
WORKING_NAMES = ['t1', 't2']
|
||||
|
||||
|
||||
class FauxExtension:
|
||||
def __init__(self, *args, **kwds):
|
||||
self.args = args
|
||||
self.kwds = kwds
|
||||
|
||||
def get_args_and_data(self, data):
|
||||
return self.args, self.kwds, data
|
||||
|
||||
|
||||
class BrokenExtension:
|
||||
def __init__(self, *args, **kwds):
|
||||
raise OSError("Did not create")
|
||||
|
||||
|
||||
class TestCallback(utils.TestCase):
|
||||
def test_detect_plugins(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
names = sorted(em.names())
|
||||
self.assertEqual(names, ALL_NAMES)
|
||||
|
||||
def test_get_by_name(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
e = em['t1']
|
||||
self.assertEqual(e.name, 't1')
|
||||
|
||||
def test_list_entry_points(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
n = em.list_entry_points()
|
||||
self.assertEqual(
|
||||
{'e1', 'e2', 't1', 't2'}, set(map(operator.attrgetter("name"), n))
|
||||
)
|
||||
self.assertEqual(4, len(n))
|
||||
|
||||
def test_list_entry_points_names(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
names = em.entry_points_names()
|
||||
self.assertEqual({'e1', 'e2', 't1', 't2'}, set(names))
|
||||
self.assertEqual(4, len(names))
|
||||
|
||||
def test_contains_by_name(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
self.assertIn('t1', em, True)
|
||||
|
||||
def test_get_by_name_missing(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
try:
|
||||
em['t3']
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
assert False, 'Failed to raise KeyError'
|
||||
|
||||
def test_load_multiple_times_entry_points(self):
|
||||
# We expect to get the same EntryPoint object because we save them
|
||||
# in the cache.
|
||||
em1: extension.ExtensionManager[Any]
|
||||
em1 = extension.ExtensionManager('stevedore.test.extension')
|
||||
eps1 = [ext.entry_point for ext in em1]
|
||||
em2: extension.ExtensionManager[Any]
|
||||
em2 = extension.ExtensionManager('stevedore.test.extension')
|
||||
eps2 = [ext.entry_point for ext in em2]
|
||||
self.assertIs(eps1[0], eps2[0])
|
||||
|
||||
def test_load_multiple_times_plugins(self):
|
||||
# We expect to get the same plugin object (module or class)
|
||||
# because the underlying import machinery will cache the values.
|
||||
em1: extension.ExtensionManager[Any]
|
||||
em1 = extension.ExtensionManager('stevedore.test.extension')
|
||||
plugins1 = [ext.plugin for ext in em1]
|
||||
em2: extension.ExtensionManager[Any]
|
||||
em2 = extension.ExtensionManager('stevedore.test.extension')
|
||||
plugins2 = [ext.plugin for ext in em2]
|
||||
self.assertIs(plugins1[0], plugins2[0])
|
||||
|
||||
def test_use_cache(self):
|
||||
# If we insert something into the cache of entry points,
|
||||
# the manager should not have to call into entrypoints
|
||||
# to find the plugins.
|
||||
cache = extension.ExtensionManager.ENTRY_POINT_CACHE
|
||||
cache['stevedore.test.faux'] = []
|
||||
with mock.patch(
|
||||
'stevedore._cache.get_group_all',
|
||||
side_effect=AssertionError('called get_group_all'),
|
||||
):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.faux')
|
||||
names = em.names()
|
||||
self.assertEqual(names, [])
|
||||
|
||||
def test_iterable(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
names = sorted(e.name for e in em)
|
||||
self.assertEqual(names, ALL_NAMES)
|
||||
|
||||
def test_invoke_on_load(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
self.assertEqual(len(em.extensions), 2)
|
||||
for e in em.extensions:
|
||||
assert e.obj is not None
|
||||
self.assertEqual(e.obj.args, ('a',))
|
||||
self.assertEqual(e.obj.kwds, {'b': 'B'})
|
||||
|
||||
def test_map_return_values(self):
|
||||
def mapped(ext, /, *args, **kwds):
|
||||
return ext.name
|
||||
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension', invoke_on_load=True
|
||||
)
|
||||
results = em.map(mapped)
|
||||
self.assertEqual(sorted(results), WORKING_NAMES)
|
||||
|
||||
def test_map_arguments(self):
|
||||
objs = []
|
||||
|
||||
def mapped(ext, /, *args, **kwds):
|
||||
objs.append((ext, args, kwds))
|
||||
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension', invoke_on_load=True
|
||||
)
|
||||
em.map(mapped, 1, 2, a='A', b='B')
|
||||
self.assertEqual(len(objs), 2)
|
||||
names = sorted([o[0].name for o in objs])
|
||||
self.assertEqual(names, WORKING_NAMES)
|
||||
for o in objs:
|
||||
self.assertEqual(o[1], (1, 2))
|
||||
self.assertEqual(o[2], {'a': 'A', 'b': 'B'})
|
||||
|
||||
def test_map_eats_errors(self):
|
||||
def mapped(ext, /, *args, **kwds):
|
||||
raise RuntimeError('hard coded error')
|
||||
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension', invoke_on_load=True
|
||||
)
|
||||
results = em.map(mapped, 1, 2, a='A', b='B')
|
||||
self.assertEqual(results, [])
|
||||
|
||||
def test_map_propagate_exceptions(self):
|
||||
def mapped(ext, /, *args, **kwds):
|
||||
raise RuntimeError('hard coded error')
|
||||
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
invoke_on_load=True,
|
||||
propagate_map_exceptions=True,
|
||||
)
|
||||
|
||||
try:
|
||||
em.map(mapped, 1, 2, a='A', b='B')
|
||||
assert False
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def test_map_errors_when_no_plugins(self):
|
||||
expected_str = 'No stevedore.test.extension.none extensions found'
|
||||
|
||||
def mapped(ext, /, *args, **kwds):
|
||||
pass
|
||||
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension.none', invoke_on_load=True
|
||||
)
|
||||
try:
|
||||
em.map(mapped, 1, 2, a='A', b='B')
|
||||
except exception.NoMatches as err:
|
||||
self.assertEqual(expected_str, str(err))
|
||||
|
||||
def test_map_method(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager(
|
||||
'stevedore.test.extension', invoke_on_load=True
|
||||
)
|
||||
|
||||
result = em.map_method('get_args_and_data', 42)
|
||||
self.assertEqual({r[2] for r in result}, {42})
|
||||
|
||||
def test_items(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager('stevedore.test.extension')
|
||||
expected_output = {(name, em[name]) for name in ALL_NAMES}
|
||||
self.assertEqual(expected_output, set(em.items()))
|
||||
|
||||
|
||||
class TestConflictResolution(utils.TestCase):
|
||||
def test_ignore_conflicts(self):
|
||||
"""Test that ignore_conflicts logs a warning when conflicts exist."""
|
||||
extensions = [
|
||||
extension.Extension(
|
||||
'conflict',
|
||||
importlib.metadata.EntryPoint(
|
||||
'conflict', 'module1:Class1', 'test.group'
|
||||
),
|
||||
type('TestClass1', (), {}),
|
||||
None,
|
||||
),
|
||||
extension.Extension(
|
||||
'conflict',
|
||||
importlib.metadata.EntryPoint(
|
||||
'conflict', 'module2:Class2', 'test.group'
|
||||
),
|
||||
type('TestClass2', (), {}),
|
||||
None,
|
||||
),
|
||||
]
|
||||
|
||||
with self.assertLogs('stevedore.extension', level='WARNING') as log:
|
||||
result = extension.ignore_conflicts(
|
||||
'test.group', 'conflict', extensions
|
||||
)
|
||||
|
||||
self.assertIs(result, extensions[-1])
|
||||
self.assertEqual(len(log.records), 1)
|
||||
warning_msg = log.records[0].getMessage()
|
||||
self.assertIn("multiple implementations found", warning_msg)
|
||||
self.assertIn("'conflict' extension", warning_msg)
|
||||
self.assertIn("test.group namespace", warning_msg)
|
||||
|
||||
def test_error_on_conflict(self):
|
||||
"""Test error_on_conflict raises MultipleMatches exception."""
|
||||
extensions = [
|
||||
extension.Extension(
|
||||
'conflict',
|
||||
importlib.metadata.EntryPoint(
|
||||
'conflict', 'module1:Class1', 'test.group'
|
||||
),
|
||||
type('TestClass1', (), {}),
|
||||
None,
|
||||
),
|
||||
extension.Extension(
|
||||
'conflict',
|
||||
importlib.metadata.EntryPoint(
|
||||
'conflict', 'module2:Class2', 'test.group'
|
||||
),
|
||||
type('TestClass2', (), {}),
|
||||
None,
|
||||
),
|
||||
]
|
||||
|
||||
with self.assertRaises(exception.MultipleMatches) as cm:
|
||||
extension.error_on_conflict('test.group', 'conflict', extensions)
|
||||
|
||||
error_msg = str(cm.exception)
|
||||
self.assertIn("multiple implementations found", error_msg)
|
||||
self.assertIn("'conflict' command", error_msg)
|
||||
self.assertIn("test.group namespace", error_msg)
|
||||
|
||||
def test_custom_conflict_resolver(self):
|
||||
"""Test using a custom conflict resolver function."""
|
||||
|
||||
def first_resolver(namespace, name, extensions):
|
||||
return extensions[0]
|
||||
|
||||
ext1 = extension.Extension(
|
||||
'test',
|
||||
importlib.metadata.EntryPoint(
|
||||
'test', 'module1:Class1', 'test.group'
|
||||
),
|
||||
type('TestClass1', (), {}),
|
||||
None,
|
||||
)
|
||||
ext2 = extension.Extension(
|
||||
'test',
|
||||
importlib.metadata.EntryPoint(
|
||||
'test', 'module2:Class2', 'test.group'
|
||||
),
|
||||
type('TestClass2', (), {}),
|
||||
None,
|
||||
)
|
||||
|
||||
em = extension.ExtensionManager.make_test_instance(
|
||||
[ext1, ext2], conflict_resolver=first_resolver
|
||||
)
|
||||
|
||||
# Should get the first extension when accessing by name
|
||||
result = em['test']
|
||||
self.assertIs(result, ext1)
|
||||
|
||||
|
||||
class TestDeprecations(utils.TestCase):
|
||||
def test_verify_requirements(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
extension.ExtensionManager.make_test_instance(
|
||||
[], verify_requirements=True
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(w))
|
||||
self.assertTrue(issubclass(w[-1].category, DeprecationWarning))
|
||||
self.assertIn(
|
||||
'The verify_requirements argument is now a no-op',
|
||||
str(w[-1].message),
|
||||
)
|
||||
|
||||
|
||||
class TestExtensionProperties(utils.TestCase):
|
||||
def setUp(self):
|
||||
self.ext1 = extension.Extension(
|
||||
'name',
|
||||
importlib.metadata.EntryPoint(
|
||||
'name', 'module.name:attribute.name [extra]', 'group_name'
|
||||
),
|
||||
mock.Mock(),
|
||||
None,
|
||||
)
|
||||
self.ext2 = extension.Extension(
|
||||
'name',
|
||||
importlib.metadata.EntryPoint(
|
||||
'name', 'module:attribute', 'group_name'
|
||||
),
|
||||
mock.Mock(),
|
||||
None,
|
||||
)
|
||||
|
||||
def test_module_name(self):
|
||||
self.assertEqual('module.name', self.ext1.module_name)
|
||||
self.assertEqual('module', self.ext2.module_name)
|
||||
|
||||
def test_attr(self):
|
||||
self.assertEqual('attribute.name', self.ext1.attr)
|
||||
self.assertEqual('attribute', self.ext2.attr)
|
||||
|
||||
def test_entry_point_target(self):
|
||||
self.assertEqual(
|
||||
'module.name:attribute.name [extra]', self.ext1.entry_point_target
|
||||
)
|
||||
self.assertEqual('module:attribute', self.ext2.entry_point_target)
|
||||
@@ -0,0 +1,60 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from typing import Any
|
||||
|
||||
from stevedore import hook
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestHook(utils.TestCase):
|
||||
def test_hook(self):
|
||||
em: hook.HookManager[Any]
|
||||
em = hook.HookManager(
|
||||
'stevedore.test.extension',
|
||||
't1',
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
self.assertEqual(len(em.extensions), 1)
|
||||
self.assertEqual(em.names(), ['t1'])
|
||||
|
||||
def test_get_by_name(self):
|
||||
em: hook.HookManager[Any]
|
||||
em = hook.HookManager(
|
||||
'stevedore.test.extension',
|
||||
't1',
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
e_list = em['t1']
|
||||
self.assertEqual(len(e_list), 1)
|
||||
e = e_list[0]
|
||||
self.assertEqual(e.name, 't1')
|
||||
|
||||
def test_get_by_name_missing(self):
|
||||
em: hook.HookManager[Any]
|
||||
em = hook.HookManager(
|
||||
'stevedore.test.extension',
|
||||
't1',
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
try:
|
||||
em['t2']
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
assert False, 'Failed to raise KeyError'
|
||||
@@ -0,0 +1,94 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from typing import Any
|
||||
from unittest import mock
|
||||
|
||||
from stevedore import named
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
class TestNamed(utils.TestCase):
|
||||
def test_named(self):
|
||||
em: named.NamedExtensionManager[Any]
|
||||
em = named.NamedExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
names=['t1'],
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
actual = em.names()
|
||||
self.assertEqual(actual, ['t1'])
|
||||
|
||||
def test_enabled_before_load(self):
|
||||
# Set up the constructor for the FauxExtension to cause an
|
||||
# AssertionError so the test fails if the class is instantiated,
|
||||
# which should only happen if it is loaded before the name of the
|
||||
# extension is compared against the names that should be loaded by
|
||||
# the manager.
|
||||
init_name = 'stevedore.tests.test_extension.FauxExtension.__init__'
|
||||
with mock.patch(init_name) as m:
|
||||
m.side_effect = AssertionError
|
||||
em: named.NamedExtensionManager[Any]
|
||||
em = named.NamedExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
# Look for an extension that does not exist so the
|
||||
# __init__ we mocked should never be invoked.
|
||||
names=['no-such-extension'],
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
actual = em.names()
|
||||
self.assertEqual(actual, [])
|
||||
|
||||
def test_extensions_listed_in_name_order(self):
|
||||
# Since we don't know the "natural" order of the extensions, run
|
||||
# the test both ways: if the sorting is broken, one of them will
|
||||
# fail
|
||||
em: named.NamedExtensionManager[Any]
|
||||
em = named.NamedExtensionManager(
|
||||
'stevedore.test.extension', names=['t1', 't2'], name_order=True
|
||||
)
|
||||
actual = em.names()
|
||||
self.assertEqual(actual, ['t1', 't2'])
|
||||
|
||||
em = named.NamedExtensionManager(
|
||||
'stevedore.test.extension', names=['t2', 't1'], name_order=True
|
||||
)
|
||||
actual = em.names()
|
||||
self.assertEqual(actual, ['t2', 't1'])
|
||||
|
||||
def test_load_fail_ignored_when_sorted(self):
|
||||
em: named.NamedExtensionManager[Any]
|
||||
em = named.NamedExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
names=['e1', 't2', 'e2', 't1'],
|
||||
name_order=True,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
actual = em.names()
|
||||
self.assertEqual(['t2', 't1'], actual)
|
||||
|
||||
em = named.NamedExtensionManager(
|
||||
'stevedore.test.extension',
|
||||
names=['e1', 't1'],
|
||||
name_order=False,
|
||||
invoke_on_load=True,
|
||||
invoke_args=('a',),
|
||||
invoke_kwds={'b': 'B'},
|
||||
)
|
||||
actual = em.names()
|
||||
self.assertEqual(['t1'], actual)
|
||||
@@ -0,0 +1,113 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for the sphinx extension"""
|
||||
|
||||
import importlib.metadata
|
||||
|
||||
from stevedore import extension
|
||||
from stevedore import sphinxext
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
def _make_ext(name, docstring):
|
||||
def inner():
|
||||
pass
|
||||
|
||||
inner.__doc__ = docstring
|
||||
m1 = importlib.metadata.EntryPoint(name, f'{name}_module:{name}', 'group')
|
||||
return extension.Extension(name, m1, inner, None)
|
||||
|
||||
|
||||
class TestSphinxExt(utils.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.exts = [
|
||||
_make_ext('test1', 'One-line docstring'),
|
||||
_make_ext('test2', 'Multi-line docstring\n\nAnother para'),
|
||||
]
|
||||
self.em = extension.ExtensionManager.make_test_instance(self.exts)
|
||||
|
||||
def test_simple_list(self):
|
||||
results = list(sphinxext._simple_list(self.em))
|
||||
self.assertEqual(
|
||||
[
|
||||
('* test1 -- One-line docstring', 'test1_module'),
|
||||
('* test2 -- Multi-line docstring', 'test2_module'),
|
||||
],
|
||||
results,
|
||||
)
|
||||
|
||||
def test_simple_list_no_docstring(self):
|
||||
ext = [_make_ext('nodoc', None)]
|
||||
em = extension.ExtensionManager.make_test_instance(ext)
|
||||
results = list(sphinxext._simple_list(em))
|
||||
self.assertEqual([('* nodoc -- ', 'nodoc_module')], results)
|
||||
|
||||
def test_detailed_list(self):
|
||||
results = list(sphinxext._detailed_list(self.em))
|
||||
self.assertEqual(
|
||||
[
|
||||
('test1', 'test1_module'),
|
||||
('-----', 'test1_module'),
|
||||
('\n', 'test1_module'),
|
||||
('One-line docstring', 'test1_module'),
|
||||
('\n', 'test1_module'),
|
||||
('test2', 'test2_module'),
|
||||
('-----', 'test2_module'),
|
||||
('\n', 'test2_module'),
|
||||
('Multi-line docstring\n\nAnother para', 'test2_module'),
|
||||
('\n', 'test2_module'),
|
||||
],
|
||||
results,
|
||||
)
|
||||
|
||||
def test_detailed_list_format(self):
|
||||
results = list(sphinxext._detailed_list(self.em, over='+', under='+'))
|
||||
self.assertEqual(
|
||||
[
|
||||
('+++++', 'test1_module'),
|
||||
('test1', 'test1_module'),
|
||||
('+++++', 'test1_module'),
|
||||
('\n', 'test1_module'),
|
||||
('One-line docstring', 'test1_module'),
|
||||
('\n', 'test1_module'),
|
||||
('+++++', 'test2_module'),
|
||||
('test2', 'test2_module'),
|
||||
('+++++', 'test2_module'),
|
||||
('\n', 'test2_module'),
|
||||
('Multi-line docstring\n\nAnother para', 'test2_module'),
|
||||
('\n', 'test2_module'),
|
||||
],
|
||||
results,
|
||||
)
|
||||
|
||||
def test_detailed_list_no_docstring(self):
|
||||
ext = [_make_ext('nodoc', None)]
|
||||
em = extension.ExtensionManager.make_test_instance(ext)
|
||||
results = list(sphinxext._detailed_list(em))
|
||||
self.assertEqual(
|
||||
[
|
||||
('nodoc', 'nodoc_module'),
|
||||
('-----', 'nodoc_module'),
|
||||
('\n', 'nodoc_module'),
|
||||
(
|
||||
(
|
||||
'.. warning:: No documentation found for '
|
||||
'nodoc in nodoc_module:nodoc'
|
||||
),
|
||||
'nodoc_module',
|
||||
),
|
||||
('\n', 'nodoc_module'),
|
||||
],
|
||||
results,
|
||||
)
|
||||
@@ -0,0 +1,263 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import sentinel
|
||||
|
||||
from stevedore import dispatch
|
||||
from stevedore import driver
|
||||
from stevedore import enabled
|
||||
from stevedore import extension
|
||||
from stevedore import hook
|
||||
from stevedore import named
|
||||
from stevedore.tests import utils
|
||||
|
||||
|
||||
test_extension = extension.Extension(
|
||||
'test_extension',
|
||||
None, # type: ignore
|
||||
None, # type: ignore
|
||||
None,
|
||||
)
|
||||
test_extension2 = extension.Extension(
|
||||
'another_one',
|
||||
None, # type: ignore
|
||||
None, # type: ignore
|
||||
None,
|
||||
)
|
||||
|
||||
mock_entry_point = Mock(module_name='test.extension', attrs=['obj'])
|
||||
a_driver = extension.Extension(
|
||||
'test_driver',
|
||||
mock_entry_point,
|
||||
sentinel.driver_plugin,
|
||||
sentinel.driver_obj,
|
||||
)
|
||||
|
||||
|
||||
# base ExtensionManager
|
||||
class TestTestManager(utils.TestCase):
|
||||
def test_instance_should_use_supplied_extensions(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = extension.ExtensionManager.make_test_instance(extensions)
|
||||
self.assertEqual(extensions, em.extensions)
|
||||
|
||||
def test_instance_should_have_default_namespace(self):
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager.make_test_instance([])
|
||||
self.assertEqual(em.namespace, 'TESTING')
|
||||
|
||||
def test_instance_should_use_supplied_namespace(self):
|
||||
namespace = 'testing.1.2.3'
|
||||
em: extension.ExtensionManager[Any]
|
||||
em = extension.ExtensionManager.make_test_instance(
|
||||
[], namespace=namespace
|
||||
)
|
||||
self.assertEqual(namespace, em.namespace)
|
||||
|
||||
def test_extension_name_should_be_listed(self):
|
||||
em = extension.ExtensionManager.make_test_instance([test_extension])
|
||||
self.assertIn(test_extension.name, em.names())
|
||||
|
||||
def test_iterator_should_yield_extension(self):
|
||||
em = extension.ExtensionManager.make_test_instance([test_extension])
|
||||
self.assertEqual(test_extension, next(iter(em)))
|
||||
|
||||
def test_manager_should_allow_name_access(self):
|
||||
em = extension.ExtensionManager.make_test_instance([test_extension])
|
||||
self.assertEqual(test_extension, em[test_extension.name])
|
||||
|
||||
def test_manager_should_call(self):
|
||||
em = extension.ExtensionManager.make_test_instance([test_extension])
|
||||
func = Mock()
|
||||
em.map(func)
|
||||
func.assert_called_once_with(test_extension)
|
||||
|
||||
def test_manager_should_call_all(self):
|
||||
em = extension.ExtensionManager.make_test_instance(
|
||||
[test_extension2, test_extension]
|
||||
)
|
||||
func = Mock()
|
||||
em.map(func)
|
||||
func.assert_any_call(test_extension2)
|
||||
func.assert_any_call(test_extension)
|
||||
|
||||
def test_manager_return_values(self):
|
||||
def mapped(ext, /, *args, **kwds):
|
||||
return ext.name
|
||||
|
||||
em = extension.ExtensionManager.make_test_instance(
|
||||
[test_extension2, test_extension]
|
||||
)
|
||||
results = em.map(mapped)
|
||||
self.assertEqual(sorted(results), ['another_one', 'test_extension'])
|
||||
|
||||
def test_manager_should_eat_exceptions(self):
|
||||
em = extension.ExtensionManager.make_test_instance([test_extension])
|
||||
|
||||
func = Mock(side_effect=RuntimeError('hard coded error'))
|
||||
|
||||
results = em.map(func, 1, 2, a='A', b='B')
|
||||
self.assertEqual(results, [])
|
||||
|
||||
def test_manager_should_propagate_exceptions(self):
|
||||
em = extension.ExtensionManager.make_test_instance(
|
||||
[test_extension], propagate_map_exceptions=True
|
||||
)
|
||||
func = Mock(side_effect=RuntimeError('hard coded error'))
|
||||
self.assertRaises(RuntimeError, em.map, func, 1, 2, a='A', b='B')
|
||||
|
||||
# NamedExtensionManager
|
||||
def test_named_manager_should_use_supplied_extensions(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = named.NamedExtensionManager.make_test_instance(extensions)
|
||||
self.assertEqual(extensions, em.extensions)
|
||||
|
||||
def test_named_manager_should_have_default_namespace(self):
|
||||
em: named.NamedExtensionManager[Any]
|
||||
em = named.NamedExtensionManager.make_test_instance([])
|
||||
self.assertEqual(em.namespace, 'TESTING')
|
||||
|
||||
def test_named_manager_should_use_supplied_namespace(self):
|
||||
namespace = 'testing.1.2.3'
|
||||
em: named.NamedExtensionManager[Any]
|
||||
em = named.NamedExtensionManager.make_test_instance(
|
||||
[], namespace=namespace
|
||||
)
|
||||
self.assertEqual(namespace, em.namespace)
|
||||
|
||||
def test_named_manager_should_populate_names(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = named.NamedExtensionManager.make_test_instance(extensions)
|
||||
self.assertEqual(em.names(), ['test_extension', 'another_one'])
|
||||
|
||||
# HookManager
|
||||
def test_hook_manager_should_use_supplied_extensions(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = hook.HookManager.make_test_instance(extensions)
|
||||
self.assertEqual(extensions, em.extensions)
|
||||
|
||||
def test_hook_manager_should_be_first_extension_name(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = hook.HookManager.make_test_instance(extensions)
|
||||
# This will raise KeyError if the names don't match
|
||||
assert em[test_extension.name]
|
||||
|
||||
def test_hook_manager_should_have_default_namespace(self):
|
||||
em = hook.HookManager.make_test_instance([test_extension])
|
||||
self.assertEqual(em.namespace, 'TESTING')
|
||||
|
||||
def test_hook_manager_should_use_supplied_namespace(self):
|
||||
namespace = 'testing.1.2.3'
|
||||
em = hook.HookManager.make_test_instance(
|
||||
[test_extension], namespace=namespace
|
||||
)
|
||||
self.assertEqual(namespace, em.namespace)
|
||||
|
||||
def test_hook_manager_should_return_named_extensions(self):
|
||||
hook1 = extension.Extension(
|
||||
'captain',
|
||||
None, # type: ignore
|
||||
None, # type: ignore
|
||||
None,
|
||||
)
|
||||
hook2 = extension.Extension(
|
||||
'captain',
|
||||
None, # type: ignore
|
||||
None, # type: ignore
|
||||
None,
|
||||
)
|
||||
em = hook.HookManager.make_test_instance([hook1, hook2])
|
||||
self.assertEqual([hook1, hook2], em['captain'])
|
||||
|
||||
# DriverManager
|
||||
def test_driver_manager_should_use_supplied_extension(self):
|
||||
em = driver.DriverManager.make_test_instance(a_driver)
|
||||
self.assertEqual([a_driver], em.extensions)
|
||||
|
||||
def test_driver_manager_should_have_default_namespace(self):
|
||||
em = driver.DriverManager.make_test_instance(a_driver)
|
||||
self.assertEqual(em.namespace, 'TESTING')
|
||||
|
||||
def test_driver_manager_should_use_supplied_namespace(self):
|
||||
namespace = 'testing.1.2.3'
|
||||
em = driver.DriverManager.make_test_instance(
|
||||
a_driver, namespace=namespace
|
||||
)
|
||||
self.assertEqual(namespace, em.namespace)
|
||||
|
||||
def test_instance_should_use_driver_name(self):
|
||||
em = driver.DriverManager.make_test_instance(a_driver)
|
||||
self.assertEqual(['test_driver'], em.names())
|
||||
|
||||
def test_instance_call(self):
|
||||
def invoke(ext, /, *args, **kwds):
|
||||
return ext.name, args, kwds
|
||||
|
||||
em = driver.DriverManager.make_test_instance(a_driver)
|
||||
result = em(invoke, 'a', b='C')
|
||||
self.assertEqual(result, ('test_driver', ('a',), {'b': 'C'}))
|
||||
|
||||
def test_instance_driver_property(self):
|
||||
em = driver.DriverManager.make_test_instance(a_driver)
|
||||
self.assertEqual(sentinel.driver_obj, em.driver)
|
||||
|
||||
# EnabledExtensionManager
|
||||
def test_enabled_instance_should_use_supplied_extensions(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = enabled.EnabledExtensionManager.make_test_instance(extensions)
|
||||
self.assertEqual(extensions, em.extensions)
|
||||
|
||||
# DispatchExtensionManager
|
||||
def test_dispatch_instance_should_use_supplied_extensions(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = dispatch.DispatchExtensionManager.make_test_instance(extensions)
|
||||
self.assertEqual(extensions, em.extensions)
|
||||
|
||||
def test_dispatch_map_should_invoke_filter_for_extensions(self):
|
||||
em = dispatch.DispatchExtensionManager.make_test_instance(
|
||||
[test_extension, test_extension2]
|
||||
)
|
||||
filter_func = Mock(return_value=False)
|
||||
args = ('A',)
|
||||
kw = {'big': 'Cheese'}
|
||||
em.map(filter_func, None, *args, **kw) # type: ignore
|
||||
filter_func.assert_any_call(test_extension, *args, **kw)
|
||||
filter_func.assert_any_call(test_extension2, *args, **kw)
|
||||
|
||||
# NameDispatchExtensionManager
|
||||
def test_name_dispatch_instance_should_use_supplied_extensions(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = dispatch.NameDispatchExtensionManager.make_test_instance(
|
||||
extensions
|
||||
)
|
||||
|
||||
self.assertEqual(extensions, em.extensions)
|
||||
|
||||
def test_name_dispatch_instance_should_build_extension_name_map(self):
|
||||
extensions = [test_extension, test_extension2]
|
||||
em = dispatch.NameDispatchExtensionManager.make_test_instance(
|
||||
extensions
|
||||
)
|
||||
self.assertEqual(test_extension, em.by_name[test_extension.name])
|
||||
self.assertEqual(test_extension2, em.by_name[test_extension2.name])
|
||||
|
||||
def test_named_dispatch_map_should_invoke_filter_for_extensions(self):
|
||||
em = dispatch.NameDispatchExtensionManager.make_test_instance(
|
||||
[test_extension, test_extension2]
|
||||
)
|
||||
func = Mock()
|
||||
args = ('A',)
|
||||
kw = {'BIGGER': 'Cheese'}
|
||||
em.map(['test_extension'], func, *args, **kw)
|
||||
func.assert_called_once_with(test_extension, *args, **kw)
|
||||
@@ -0,0 +1,17 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
pass
|
||||
Reference in New Issue
Block a user