Fixing unit test failures in Cisco plugin

Bug #1038565

The tests for bulk resource creation failure were failing since the bulk
API calls were not getting relayed correctly to the virt_phy_sw.py, that
has been fixed
There tests for the network_multi_blade_v2.py were failing since DB
initialization order was incorrect.
The tests in test_api_v2.py were failing since the plugin instance was
not being reset for each test.

Change-Id: I449bd8a61c1f61f98a97acf489574624fe309caa
This commit is contained in:
Sumit Naiksatam 2012-08-18 20:50:38 -07:00
parent 7afb37af76
commit 8e2812eeaa
10 changed files with 290 additions and 27 deletions

View File

@ -22,6 +22,7 @@ import logging
from quantum.openstack.common import importutils from quantum.openstack.common import importutils
from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_credentials_v2 as cred
from quantum.plugins.cisco.db import network_db_v2 as cdb from quantum.plugins.cisco.db import network_db_v2 as cdb
from quantum.plugins.cisco import l2network_plugin_configuration as conf from quantum.plugins.cisco import l2network_plugin_configuration as conf
from quantum import quantum_plugin_base_v2 from quantum import quantum_plugin_base_v2
@ -46,6 +47,8 @@ class NetworkMultiBladeV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
configured, and load the inventories those device plugins for which the configured, and load the inventories those device plugins for which the
inventory is configured inventory is configured
""" """
cdb.initialize()
cred.Store.initialize()
self._vlan_mgr = importutils.import_object(conf.MANAGER_CLASS) self._vlan_mgr = importutils.import_object(conf.MANAGER_CLASS)
for key in conf.PLUGINS[const.PLUGINS].keys(): for key in conf.PLUGINS[const.PLUGINS].keys():
plugin_obj = conf.PLUGINS[const.PLUGINS][key] plugin_obj = conf.PLUGINS[const.PLUGINS][key]

View File

@ -41,14 +41,16 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
One or more servers to a nexus switch. One or more servers to a nexus switch.
""" """
MANAGE_STATE = True MANAGE_STATE = True
__native_bulk_support = True
supported_extension_aliases = [] supported_extension_aliases = []
_plugins = {} _plugins = {}
_inventory = {} _inventory = {}
_methods_to_delegate = ['update_network', 'get_network', 'get_networks', _methods_to_delegate = ['update_network', 'get_network', 'get_networks',
'create_port', 'delete_port', 'update_port', 'create_port', 'create_port_bulk', 'delete_port',
'get_port', 'get_ports', 'update_port', 'get_port', 'get_ports',
'create_subnet', 'delete_subnet', 'update_subnet', 'create_subnet', 'create_subnet_bulk',
'get_subnet', 'get_subnets'] 'delete_subnet', 'update_subnet', 'get_subnet',
'get_subnets', ]
def __init__(self): def __init__(self):
""" """
@ -69,15 +71,32 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
LOG.debug("Loaded device inventory %s\n" % LOG.debug("Loaded device inventory %s\n" %
conf.PLUGINS[const.INVENTORY][key]) conf.PLUGINS[const.INVENTORY][key])
if hasattr(self._plugins[const.VSWITCH_PLUGIN],
"supported_extension_aliases"):
self.supported_extension_aliases.extend(
self._plugins[const.VSWITCH_PLUGIN].
supported_extension_aliases)
LOG.debug("%s.%s init done" % (__name__, self.__class__.__name__)) LOG.debug("%s.%s init done" % (__name__, self.__class__.__name__))
def __getattribute__(self, name): def __getattribute__(self, name):
methods = object.__getattribute__(self, "_methods_to_delegate") """
This delegates the calls to the methods implemented only by the OVS
sub-plugin.
"""
super_getattr = super(VirtualPhysicalSwitchModelV2,
self).__getattribute__
methods = super_getattr('_methods_to_delegate')
if name in methods: if name in methods:
return getattr(object.__getattribute__(self, "_plugins") plugin = super_getattr('_plugins')[const.VSWITCH_PLUGIN]
[const.VSWITCH_PLUGIN], name) return getattr(plugin, name)
else:
return object.__getattribute__(self, name) try:
return super_getattr(name)
except AttributeError:
plugin = super_getattr('_plugins')[const.VSWITCH_PLUGIN]
return getattr(plugin, name)
def _func_name(self, offset=0): def _func_name(self, offset=0):
"""Get the name of the calling function""" """Get the name of the calling function"""
@ -173,6 +192,36 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
# TODO (Sumit): Check if we need to perform any rollback here # TODO (Sumit): Check if we need to perform any rollback here
raise raise
def create_network_bulk(self, context, networks):
"""
Perform this operation in the context of the configured device
plugins.
"""
LOG.debug("create_network_bulk() called\n")
try:
args = [context, networks]
ovs_output = self._plugins[
const.VSWITCH_PLUGIN].create_network_bulk(context, networks)
vlan_ids = odb.get_vlans()
vlanids = ''
for v_id in vlan_ids:
vlanids = str(v_id[0]) + ',' + vlanids
vlanids = vlanids.strip(',')
LOG.debug("ovs_output: %s\n " % ovs_output)
ovs_networks = ovs_output
for ovs_network in ovs_networks:
vlan_id = odb.get_vlan(ovs_network['id'])
vlan_name = conf.VLAN_NAME_PREFIX + str(vlan_id)
args = [ovs_network['tenant_id'], ovs_network['name'],
ovs_network['id'], vlan_name, vlan_id,
{'vlan_ids':vlanids}]
nexus_output = self._invoke_plugin_per_device(
const.NEXUS_PLUGIN, "create_network", args)
return ovs_output
except:
# TODO (Sumit): Check if we need to perform any rollback here
raise
def update_network(self, context, id, network): def update_network(self, context, id, network):
"""For this model this method will be delegated to vswitch plugin""" """For this model this method will be delegated to vswitch plugin"""
pass pass

View File

@ -40,25 +40,28 @@ class PluginV2(db_base_plugin_v2.QuantumDbPluginV2):
supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile", supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile",
"Cisco qos", "Cisco Nova Tenant", "Cisco qos", "Cisco Nova Tenant",
"Cisco Multiport"] "Cisco Multiport"]
_methods_to_delegate = ['create_network', 'delete_network', _methods_to_delegate = ['create_network', 'create_network_bulk',
'update_network', 'get_network', 'get_networks', 'delete_network', 'update_network', 'get_network',
'create_port', 'delete_port', 'update_port', 'get_networks',
'get_port', 'get_ports', 'create_port', 'create_port_bulk', 'delete_port',
'create_subnet', 'delete_subnet', 'update_subnet', 'update_port', 'get_port', 'get_ports',
'get_subnet', 'get_subnets'] 'create_subnet', 'create_subnet_bulk',
'delete_subnet', 'update_subnet',
'get_subnet', 'get_subnets', ]
_master = True _master = True
def __init__(self): def __init__(self):
""" """
Loads the model class, initializes the DB, and credential store. Loads the model class.
""" """
self._model = importutils.import_object(conf.MODEL_CLASS) self._model = importutils.import_object(conf.MODEL_CLASS)
if hasattr(self._model, "MANAGE_STATE") and self._model.MANAGE_STATE: if hasattr(self._model, "MANAGE_STATE") and self._model.MANAGE_STATE:
self._master = False self._master = False
LOG.debug("Model %s manages state" % conf.MODEL_CLASS) LOG.debug("Model %s manages state" % conf.MODEL_CLASS)
else: native_bulk_attr_name = ("_%s__native_bulk_support"
cdb.initialize() % self._model.__class__.__name__)
cred.Store.initialize() self.__native_bulk_support = getattr(self._model,
native_bulk_attr_name, False)
if hasattr(self._model, "supported_extension_aliases"): if hasattr(self._model, "supported_extension_aliases"):
self.supported_extension_aliases.extend( self.supported_extension_aliases.extend(

View File

@ -2,7 +2,7 @@
pipeline = extensions extensions_test_app pipeline = extensions extensions_test_app
[filter:extensions] [filter:extensions]
paste.filter_factory = quantum.extensions.extensions:plugin_aware_extension_middleware_factory paste.filter_factory = quantum.common.extensions:plugin_aware_extension_middleware_factory
[app:extensions_test_app] [app:extensions_test_app]
paste.app_factory = quantum.plugins.cisco.tests.unit.test_cisco_extension:app_factory paste.app_factory = quantum.plugins.cisco.tests.unit.test_cisco_extension:app_factory

View File

@ -0,0 +1,8 @@
[pipeline:extensions_app_with_filter]
pipeline = extensions extensions_test_app
[filter:extensions]
paste.filter_factory = quantum.common.extensions:plugin_aware_extension_middleware_factory
[app:extensions_test_app]
paste.app_factory = quantum.plugins.cisco.tests.unit.test_cisco_extension:app_factory

View File

@ -77,7 +77,7 @@ class CiscoNEXUSFakeDriver():
pass pass
def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user, def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user,
nexus_password, nexus_ports, nexus_ssh_port): nexus_password, nexus_ports, nexus_ssh_port, vlan_ids):
""" """
Creates a VLAN and Enable on trunk mode an interface on Nexus Switch Creates a VLAN and Enable on trunk mode an interface on Nexus Switch
given the VLAN ID and Name and Interface Number given the VLAN ID and Name and Interface Number

View File

@ -12,9 +12,32 @@ bind_host = 0.0.0.0
bind_port = 9696 bind_port = 9696
# Path to the extensions # Path to the extensions
api_extensions_path = ../../../../extensions api_extensions_path = ../../../../../extensions
# Paste configuration file # Paste configuration file
api_paste_config = api-paste.ini.cisco.test api_paste_config = api-paste.ini.cisco.test
core_plugin = quantum.plugins.cisco.network_plugin.PluginV2 core_plugin = quantum.plugins.cisco.network_plugin.PluginV2
# The messaging module to use, defaults to kombu.
rpc_backend = quantum.openstack.common.rpc.impl_fake
[QUOTAS]
# resource name(s) that are supported in quota features
quota_items = network,subnet,port
# default number of resource allowed per tenant, minus for unlimited
default_quota = -1
# number of networks allowed per tenant, and minus means unlimited
# quota_network = 10
# number of subnets allowed per tenant, and minus means unlimited
# quota_subnet = 10
# number of ports allowed per tenant, and minus means unlimited
# quota_port = 50
# default driver to use for quota checks
# quota_driver = quantum.quota.ConfDriver
quota_driver = quantum.extensions._quotav2_driver.DbQuotaDriver

View File

@ -20,6 +20,8 @@ import webtest
from quantum.api.v2 import router from quantum.api.v2 import router
from quantum.common import config from quantum.common import config
from quantum.extensions.extensions import PluginAwareExtensionManager
from quantum.manager import QuantumManager
from quantum.openstack.common import cfg from quantum.openstack.common import cfg
from quantum.tests.unit import test_api_v2 from quantum.tests.unit import test_api_v2
@ -35,6 +37,10 @@ class APIv2TestCase(test_api_v2.APIv2TestCase):
def setUp(self): def setUp(self):
plugin = 'quantum.plugins.cisco.network_plugin.PluginV2' plugin = 'quantum.plugins.cisco.network_plugin.PluginV2'
# Ensure 'stale' patched copies of the plugin are never returned
QuantumManager._instance = None
# Ensure existing ExtensionManager is not used
PluginAwareExtensionManager._instance = None
# Create the default configurations # Create the default configurations
args = ['--config-file', curdir('quantumv2.conf.cisco.test')] args = ['--config-file', curdir('quantumv2.conf.cisco.test')]
config.parse(args=args) config.parse(args=args)

View File

@ -20,8 +20,13 @@ import os
from quantum.api.v2.router import APIRouter from quantum.api.v2.router import APIRouter
from quantum.common import config from quantum.common import config
from quantum.common.test_lib import test_config
from quantum import context
from quantum.db import api as db from quantum.db import api as db
from quantum.extensions import _quotav2_model as quotav2_model
from quantum.manager import QuantumManager from quantum.manager import QuantumManager
from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.db import network_db_v2
from quantum.plugins.cisco.db import network_models_v2 from quantum.plugins.cisco.db import network_models_v2
from quantum.openstack.common import cfg from quantum.openstack.common import cfg
from quantum.tests.unit import test_db_plugin from quantum.tests.unit import test_db_plugin
@ -50,11 +55,35 @@ class NetworkPluginV2TestCase(test_db_plugin.QuantumDbPluginV2TestCase):
plugin = 'quantum.plugins.cisco.network_plugin.PluginV2' plugin = 'quantum.plugins.cisco.network_plugin.PluginV2'
# Create the default configurations # Create the default configurations
args = ['--config-file', curdir('quantumv2.conf.cisco.test')] args = ['--config-file', curdir('quantumv2.conf.cisco.test')]
# If test_config specifies some config-file, use it, as well
for config_file in test_config.get('config_files', []):
args.extend(['--config-file', config_file])
config.parse(args=args) config.parse(args=args)
# Update the plugin # Update the plugin
cfg.CONF.set_override('core_plugin', plugin) cfg.CONF.set_override('core_plugin', plugin)
cfg.CONF.set_override('base_mac', "12:34:56:78:90:ab") cfg.CONF.set_override('base_mac', "12:34:56:78:90:ab")
self.api = APIRouter() cfg.CONF.max_dns_nameservers = 2
cfg.CONF.max_subnet_host_routes = 2
def new_init():
db.configure_db({'sql_connection': 'sqlite://',
'base': network_models_v2.model_base.BASEV2})
with mock.patch.object(network_db_v2,
'initialize', new=new_init):
self.api = APIRouter()
def _is_native_bulk_supported():
plugin_obj = QuantumManager.get_plugin()
native_bulk_attr_name = ("_%s__native_bulk_support"
% plugin_obj.__class__.__name__)
return getattr(plugin_obj, native_bulk_attr_name, False)
self._skip_native_bulk = not _is_native_bulk_supported()
ext_mgr = test_config.get('extension_manager', None)
if ext_mgr:
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
LOG.debug("%s.%s.%s done" % (__name__, self.__class__.__name__, LOG.debug("%s.%s.%s done" % (__name__, self.__class__.__name__,
inspect.stack()[0][3])) inspect.stack()[0][3]))
@ -65,6 +94,16 @@ class NetworkPluginV2TestCase(test_db_plugin.QuantumDbPluginV2TestCase):
cfg.CONF.reset() cfg.CONF.reset()
def _get_plugin_ref(self):
plugin_obj = QuantumManager.get_plugin()
if getattr(plugin_obj, "_master"):
plugin_ref = plugin_obj
else:
plugin_ref = getattr(plugin_obj, "_model").\
_plugins[const.VSWITCH_PLUGIN]
return plugin_ref
class TestV2HTTPResponse(NetworkPluginV2TestCase, class TestV2HTTPResponse(NetworkPluginV2TestCase,
test_db_plugin.TestV2HTTPResponse): test_db_plugin.TestV2HTTPResponse):
@ -74,14 +113,146 @@ class TestV2HTTPResponse(NetworkPluginV2TestCase,
class TestPortsV2(NetworkPluginV2TestCase, test_db_plugin.TestPortsV2): class TestPortsV2(NetworkPluginV2TestCase, test_db_plugin.TestPortsV2):
pass def test_create_ports_bulk_emulated_plugin_failure(self):
real_has_attr = hasattr
#ensures the API choose the emulation code path
def fakehasattr(item, attr):
if attr.endswith('__native_bulk_support'):
return False
return real_has_attr(item, attr)
with mock.patch('__builtin__.hasattr',
new=fakehasattr):
plugin_ref = self._get_plugin_ref()
orig = plugin_ref.create_port
with mock.patch.object(plugin_ref,
'create_port') as patched_plugin:
def side_effect(*args, **kwargs):
return self._do_side_effect(patched_plugin, orig,
*args, **kwargs)
patched_plugin.side_effect = side_effect
with self.network() as net:
res = self._create_port_bulk('json', 2,
net['network']['id'],
'test',
True)
# We expect a 500 as we injected a fault in the plugin
self._validate_behavior_on_bulk_failure(res, 'ports')
def test_create_ports_bulk_native_plugin_failure(self):
if self._skip_native_bulk:
self.skipTest("Plugin does not support native bulk port create")
ctx = context.get_admin_context()
with self.network() as net:
plugin_ref = self._get_plugin_ref()
orig = plugin_ref.create_port
with mock.patch.object(plugin_ref,
'create_port') as patched_plugin:
def side_effect(*args, **kwargs):
return self._do_side_effect(patched_plugin, orig,
*args, **kwargs)
patched_plugin.side_effect = side_effect
res = self._create_port_bulk('json', 2, net['network']['id'],
'test', True, context=ctx)
# We expect a 500 as we injected a fault in the plugin
self._validate_behavior_on_bulk_failure(res, 'ports')
class TestNetworksV2(NetworkPluginV2TestCase, test_db_plugin.TestNetworksV2): class TestNetworksV2(NetworkPluginV2TestCase, test_db_plugin.TestNetworksV2):
pass def test_create_networks_bulk_emulated_plugin_failure(self):
real_has_attr = hasattr
def fakehasattr(item, attr):
if attr.endswith('__native_bulk_support'):
return False
return real_has_attr(item, attr)
plugin_ref = self._get_plugin_ref()
orig = plugin_ref.create_network
#ensures the API choose the emulation code path
with mock.patch('__builtin__.hasattr',
new=fakehasattr):
with mock.patch.object(plugin_ref,
'create_network') as patched_plugin:
def side_effect(*args, **kwargs):
return self._do_side_effect(patched_plugin, orig,
*args, **kwargs)
patched_plugin.side_effect = side_effect
res = self._create_network_bulk('json', 2, 'test', True)
LOG.debug("response is %s" % res)
# We expect a 500 as we injected a fault in the plugin
self._validate_behavior_on_bulk_failure(res, 'networks')
def test_create_networks_bulk_native_plugin_failure(self):
if self._skip_native_bulk:
self.skipTest("Plugin does not support native bulk network create")
plugin_ref = self._get_plugin_ref()
orig = plugin_ref.create_network
with mock.patch.object(plugin_ref,
'create_network') as patched_plugin:
def side_effect(*args, **kwargs):
return self._do_side_effect(patched_plugin, orig,
*args, **kwargs)
patched_plugin.side_effect = side_effect
res = self._create_network_bulk('json', 2, 'test', True)
# We expect a 500 as we injected a fault in the plugin
self._validate_behavior_on_bulk_failure(res, 'networks')
class TestSubnetsV2(NetworkPluginV2TestCase, test_db_plugin.TestSubnetsV2): class TestSubnetsV2(NetworkPluginV2TestCase, test_db_plugin.TestSubnetsV2):
pass def test_create_subnets_bulk_emulated_plugin_failure(self):
real_has_attr = hasattr
#ensures the API choose the emulation code path
def fakehasattr(item, attr):
if attr.endswith('__native_bulk_support'):
return False
return real_has_attr(item, attr)
with mock.patch('__builtin__.hasattr',
new=fakehasattr):
plugin_ref = self._get_plugin_ref()
orig = plugin_ref.create_subnet
with mock.patch.object(plugin_ref,
'create_subnet') as patched_plugin:
def side_effect(*args, **kwargs):
self._do_side_effect(patched_plugin, orig,
*args, **kwargs)
patched_plugin.side_effect = side_effect
with self.network() as net:
res = self._create_subnet_bulk('json', 2,
net['network']['id'],
'test')
# We expect a 500 as we injected a fault in the plugin
self._validate_behavior_on_bulk_failure(res, 'subnets')
def test_create_subnets_bulk_native_plugin_failure(self):
if self._skip_native_bulk:
self.skipTest("Plugin does not support native bulk subnet create")
plugin_ref = self._get_plugin_ref()
orig = plugin_ref.create_subnet
with mock.patch.object(plugin_ref,
'create_subnet') as patched_plugin:
def side_effect(*args, **kwargs):
return self._do_side_effect(patched_plugin, orig,
*args, **kwargs)
patched_plugin.side_effect = side_effect
with self.network() as net:
res = self._create_subnet_bulk('json', 2,
net['network']['id'],
'test')
# We expect a 500 as we injected a fault in the plugin
self._validate_behavior_on_bulk_failure(res, 'subnets')

View File

@ -23,7 +23,7 @@ from quantum.db import api as db
from quantum.openstack.common import importutils from quantum.openstack.common import importutils
from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_constants as const
from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_credentials_v2 as cred
from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.common import cisco_exceptions as cexc
from quantum.plugins.cisco.common import cisco_utils as cutil from quantum.plugins.cisco.common import cisco_utils as cutil
from quantum.plugins.cisco.db import network_db_v2 as cdb from quantum.plugins.cisco.db import network_db_v2 as cdb