Merge "tests: removed 'retargetable' framework"
This commit is contained in:
commit
78459837db
|
@ -28,12 +28,6 @@ eventlet_utils.monkey_patch()
|
||||||
|
|
||||||
def load_tests(loader, tests, pattern):
|
def load_tests(loader, tests, pattern):
|
||||||
this_dir = os.path.dirname(__file__)
|
this_dir = os.path.dirname(__file__)
|
||||||
parent_dir = os.path.dirname(this_dir)
|
new_tests = loader.discover(start_dir=this_dir, pattern=pattern)
|
||||||
target_dirs = [
|
tests.addTests(new_tests)
|
||||||
this_dir,
|
|
||||||
os.path.join(parent_dir, 'retargetable'),
|
|
||||||
]
|
|
||||||
for start_dir in target_dirs:
|
|
||||||
new_tests = loader.discover(start_dir=start_dir, pattern=pattern)
|
|
||||||
tests.addTests(new_tests)
|
|
||||||
return tests
|
return tests
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
This module defines a base test case that uses testscenarios to
|
|
||||||
parametize the test methods of subclasses by varying the client
|
|
||||||
fixture used to target the Neutron API.
|
|
||||||
|
|
||||||
PluginClientFixture targets the Neutron API directly via the plugin
|
|
||||||
api, and will be executed by default. testscenarios will ensure that
|
|
||||||
each test is run against all plugins defined in plugin_configurations.
|
|
||||||
|
|
||||||
RestClientFixture targets a deployed Neutron daemon, and will be used
|
|
||||||
instead of PluginClientFixture only if OS_TEST_API_WITH_REST is set to 1.
|
|
||||||
|
|
||||||
Reference: https://pypi.python.org/pypi/testscenarios/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import testscenarios
|
|
||||||
|
|
||||||
from neutron.tests import base as tests_base
|
|
||||||
from neutron.tests.retargetable import client_fixtures
|
|
||||||
from neutron.tests.unit.plugins.ml2 import test_plugin
|
|
||||||
|
|
||||||
|
|
||||||
# Each plugin must add a class to plugin_configurations that can configure the
|
|
||||||
# plugin for use with PluginClient. For a given plugin, the setup
|
|
||||||
# used for NeutronDbPluginV2TestCase can usually be reused. See the
|
|
||||||
# configuration classes listed below for examples of this reuse.
|
|
||||||
|
|
||||||
# TODO(marun) Discover plugin conf via a metaclass
|
|
||||||
plugin_configurations = [
|
|
||||||
test_plugin.Ml2ConfFixture(),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def rest_enabled():
|
|
||||||
return tests_base.bool_from_env('OS_TEST_API_WITH_REST')
|
|
||||||
|
|
||||||
|
|
||||||
def get_plugin_scenarios():
|
|
||||||
scenarios = []
|
|
||||||
for conf in plugin_configurations:
|
|
||||||
name = conf.plugin_name
|
|
||||||
class_name = name.rsplit('.', 1)[-1]
|
|
||||||
client = client_fixtures.PluginClientFixture(conf)
|
|
||||||
scenarios.append((class_name, {'client': client}))
|
|
||||||
return scenarios
|
|
||||||
|
|
||||||
|
|
||||||
def get_scenarios():
|
|
||||||
if rest_enabled():
|
|
||||||
# FIXME(marun) Remove local import once tempest config is safe
|
|
||||||
# to import alongside neutron config
|
|
||||||
from neutron.tests.retargetable import rest_fixture
|
|
||||||
return [('tempest', {'client': rest_fixture.RestClientFixture()})]
|
|
||||||
else:
|
|
||||||
return get_plugin_scenarios()
|
|
||||||
|
|
||||||
|
|
||||||
class RetargetableApiTest(testscenarios.WithScenarios,
|
|
||||||
tests_base.BaseTestCase):
|
|
||||||
|
|
||||||
scenarios = get_scenarios()
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(RetargetableApiTest, self).setUp()
|
|
||||||
if rest_enabled():
|
|
||||||
raise self.skipException(
|
|
||||||
'Tempest fixture requirements prevent this test from running')
|
|
||||||
self.useFixture(self.client)
|
|
|
@ -1,120 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
This module defines client fixtures that can be used to target the
|
|
||||||
Neutron API via different methods.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import abc
|
|
||||||
|
|
||||||
import fixtures
|
|
||||||
from neutron_lib import context
|
|
||||||
from neutron_lib import exceptions as n_exc
|
|
||||||
from neutron_lib.plugins import directory
|
|
||||||
import six
|
|
||||||
|
|
||||||
from neutron import manager
|
|
||||||
from neutron.tests import base
|
|
||||||
from neutron.tests.unit import testlib_api
|
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
|
||||||
class AbstractClientFixture(fixtures.Fixture):
|
|
||||||
"""
|
|
||||||
Base class for a client that can interact the neutron api in some
|
|
||||||
manner.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractproperty
|
|
||||||
def NotFound(self):
|
|
||||||
"""The exception that indicates a resource could not be found.
|
|
||||||
|
|
||||||
Tests can use this property to assert for a missing resource
|
|
||||||
in a client-agnostic way.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_network(self, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_network(self, id_, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_network(self, id_, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_networks(self, filters=None, fields=None,
|
|
||||||
sorts=None, limit=None, marker=None, page_reverse=False):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_network(self, id_):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PluginClientFixture(AbstractClientFixture):
|
|
||||||
"""Targets the Neutron API via the plugin API"""
|
|
||||||
|
|
||||||
def __init__(self, plugin_conf):
|
|
||||||
super(PluginClientFixture, self).__init__()
|
|
||||||
self.plugin_conf = plugin_conf
|
|
||||||
|
|
||||||
def _setUp(self):
|
|
||||||
super(PluginClientFixture, self)._setUp()
|
|
||||||
self.useFixture(testlib_api.StaticSqlFixture())
|
|
||||||
self.useFixture(self.plugin_conf)
|
|
||||||
self.useFixture(base.PluginFixture(self.plugin_conf.plugin_name))
|
|
||||||
manager.init()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ctx(self):
|
|
||||||
if not hasattr(self, '_ctx'):
|
|
||||||
self._ctx = context.Context('', 'test-tenant')
|
|
||||||
return self._ctx
|
|
||||||
|
|
||||||
@property
|
|
||||||
def plugin(self):
|
|
||||||
return directory.get_plugin()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def NotFound(self):
|
|
||||||
return n_exc.NetworkNotFound
|
|
||||||
|
|
||||||
def create_network(self, **kwargs):
|
|
||||||
# Supply defaults that are expected to be set by the api
|
|
||||||
# framework
|
|
||||||
kwargs.setdefault('admin_state_up', True)
|
|
||||||
kwargs.setdefault('shared', False)
|
|
||||||
kwargs.setdefault('tenant_id', self.ctx.tenant_id)
|
|
||||||
data = dict(network=kwargs)
|
|
||||||
result = self.plugin.create_network(self.ctx, data)
|
|
||||||
return base.AttributeDict(result)
|
|
||||||
|
|
||||||
def update_network(self, id_, **kwargs):
|
|
||||||
data = dict(network=kwargs)
|
|
||||||
result = self.plugin.update_network(self.ctx, id_, data)
|
|
||||||
return base.AttributeDict(result)
|
|
||||||
|
|
||||||
def get_network(self, *args, **kwargs):
|
|
||||||
result = self.plugin.get_network(self.ctx, *args, **kwargs)
|
|
||||||
return base.AttributeDict(result)
|
|
||||||
|
|
||||||
def get_networks(self, *args, **kwargs):
|
|
||||||
result = self.plugin.get_networks(self.ctx, *args, **kwargs)
|
|
||||||
return [base.AttributeDict(x) for x in result]
|
|
||||||
|
|
||||||
def delete_network(self, id_):
|
|
||||||
self.plugin.delete_network(self.ctx, id_)
|
|
|
@ -1,70 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
This module defines a client fixture that can be used to target a
|
|
||||||
deployed neutron daemon. The potential for conflict between Tempest
|
|
||||||
configuration and Neutron configuration requires that
|
|
||||||
neutron.tests.tempest imports be isolated in this module for now.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tlib_exceptions
|
|
||||||
|
|
||||||
from neutron.tests import base
|
|
||||||
from neutron.tests.retargetable import client_fixtures
|
|
||||||
from tempest import test as t_test
|
|
||||||
|
|
||||||
|
|
||||||
class RestClientFixture(client_fixtures.AbstractClientFixture):
|
|
||||||
"""Targets the Neutron API via REST."""
|
|
||||||
|
|
||||||
@property
|
|
||||||
def client(self):
|
|
||||||
if not hasattr(self, '_client'):
|
|
||||||
manager = t_test.BaseTestCase.get_client_manager()
|
|
||||||
self._client = manager.network_client
|
|
||||||
return self._client
|
|
||||||
|
|
||||||
@property
|
|
||||||
def NotFound(self):
|
|
||||||
return tlib_exceptions.NotFound
|
|
||||||
|
|
||||||
def _cleanup_network(self, id_):
|
|
||||||
try:
|
|
||||||
self.delete_network(id_)
|
|
||||||
except self.NotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def create_network(self, **kwargs):
|
|
||||||
network = self._create_network(**kwargs)
|
|
||||||
self.addCleanup(self._cleanup_network, network.id)
|
|
||||||
return network
|
|
||||||
|
|
||||||
def _create_network(self, **kwargs):
|
|
||||||
# Internal method - use create_network() instead
|
|
||||||
body = self.client.create_network(**kwargs)
|
|
||||||
return base.AttributeDict(body['network'])
|
|
||||||
|
|
||||||
def update_network(self, id_, **kwargs):
|
|
||||||
body = self.client.update_network(id_, **kwargs)
|
|
||||||
return base.AttributeDict(body['network'])
|
|
||||||
|
|
||||||
def get_network(self, id_, **kwargs):
|
|
||||||
body = self.client.show_network(id_, **kwargs)
|
|
||||||
return base.AttributeDict(body['network'])
|
|
||||||
|
|
||||||
def get_networks(self, **kwargs):
|
|
||||||
body = self.client.list_networks(**kwargs)
|
|
||||||
return [base.AttributeDict(x) for x in body['networks']]
|
|
||||||
|
|
||||||
def delete_network(self, id_):
|
|
||||||
self.client.delete_network(id_)
|
|
|
@ -1,39 +0,0 @@
|
||||||
# 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 testtools
|
|
||||||
|
|
||||||
from neutron.common import utils
|
|
||||||
from neutron.tests.retargetable import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestExample(base.RetargetableApiTest):
|
|
||||||
"""This class is an example of how to write a retargetable api test.
|
|
||||||
|
|
||||||
See the parent class for details about how the 'client' attribute
|
|
||||||
is configured via testscenarios.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_network_lifecycle(self):
|
|
||||||
net = self.client.create_network(name=utils.get_rand_name())
|
|
||||||
listed_networks = {x.id: x.name for x in self.client.get_networks()}
|
|
||||||
self.assertIn(net.id, listed_networks)
|
|
||||||
self.assertEqual(listed_networks[net.id], net.name,
|
|
||||||
'Listed network name is not as expected.')
|
|
||||||
updated_name = 'new %s' % net.name
|
|
||||||
updated_net = self.client.update_network(net.id, name=updated_name)
|
|
||||||
self.assertEqual(updated_name, updated_net.name,
|
|
||||||
'Updated network name is not as expected.')
|
|
||||||
self.client.delete_network(net.id)
|
|
||||||
with testtools.ExpectedException(self.client.NotFound,
|
|
||||||
msg='Network was not deleted'):
|
|
||||||
self.client.get_network(net.id)
|
|
|
@ -1,10 +1,9 @@
|
||||||
WARNING
|
WARNING
|
||||||
=======
|
=======
|
||||||
|
|
||||||
The files under this path were copied from tempest as part of the move
|
Some files under this path were copied from tempest as part of the move of the
|
||||||
of the api tests, and they will be removed as required over time to
|
api tests, and they will be removed as required over time to minimize the
|
||||||
minimize the dependency on the tempest testing framework.
|
dependency on the tempest testing framework. While it exists, only
|
||||||
While it exists, only neutron.tests.tempest.api and neutron.tests.retargetable
|
neutron.tests.tempest.* should be importing files from this path.
|
||||||
should be importing files from this path. neutron.tests.tempest.config uses
|
neutron.tests.tempest.config uses the global cfg.CONF instance and importing it
|
||||||
the global cfg.CONF instance and importing it outside of the api tests
|
outside of the api tests has the potential to break Neutron's use of cfg.CONF.
|
||||||
has the potential to break Neutron's use of cfg.CONF.
|
|
||||||
|
|
Loading…
Reference in New Issue