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.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 import l2network_plugin_configuration as conf
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
inventory is configured
"""
cdb.initialize()
cred.Store.initialize()
self._vlan_mgr = importutils.import_object(conf.MANAGER_CLASS)
for key in conf.PLUGINS[const.PLUGINS].keys():
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.
"""
MANAGE_STATE = True
__native_bulk_support = True
supported_extension_aliases = []
_plugins = {}
_inventory = {}
_methods_to_delegate = ['update_network', 'get_network', 'get_networks',
'create_port', 'delete_port', 'update_port',
'get_port', 'get_ports',
'create_subnet', 'delete_subnet', 'update_subnet',
'get_subnet', 'get_subnets']
'create_port', 'create_port_bulk', 'delete_port',
'update_port', 'get_port', 'get_ports',
'create_subnet', 'create_subnet_bulk',
'delete_subnet', 'update_subnet', 'get_subnet',
'get_subnets', ]
def __init__(self):
"""
@ -69,15 +71,32 @@ class VirtualPhysicalSwitchModelV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
LOG.debug("Loaded device inventory %s\n" %
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__))
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:
return getattr(object.__getattribute__(self, "_plugins")
[const.VSWITCH_PLUGIN], name)
else:
return object.__getattribute__(self, name)
plugin = super_getattr('_plugins')[const.VSWITCH_PLUGIN]
return getattr(plugin, 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):
"""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
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):
"""For this model this method will be delegated to vswitch plugin"""
pass

View File

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

View File

@ -2,7 +2,7 @@
pipeline = extensions extensions_test_app
[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]
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
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
given the VLAN ID and Name and Interface Number

View File

@ -12,9 +12,32 @@ bind_host = 0.0.0.0
bind_port = 9696
# Path to the extensions
api_extensions_path = ../../../../extensions
api_extensions_path = ../../../../../extensions
# Paste configuration file
api_paste_config = api-paste.ini.cisco.test
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.common import config
from quantum.extensions.extensions import PluginAwareExtensionManager
from quantum.manager import QuantumManager
from quantum.openstack.common import cfg
from quantum.tests.unit import test_api_v2
@ -35,6 +37,10 @@ class APIv2TestCase(test_api_v2.APIv2TestCase):
def setUp(self):
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
args = ['--config-file', curdir('quantumv2.conf.cisco.test')]
config.parse(args=args)

View File

@ -20,8 +20,13 @@ import os
from quantum.api.v2.router import APIRouter
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.extensions import _quotav2_model as quotav2_model
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.openstack.common import cfg
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'
# Create the default configurations
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)
# Update the plugin
cfg.CONF.set_override('core_plugin', plugin)
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__,
inspect.stack()[0][3]))
@ -65,6 +94,16 @@ class NetworkPluginV2TestCase(test_db_plugin.QuantumDbPluginV2TestCase):
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,
test_db_plugin.TestV2HTTPResponse):
@ -74,14 +113,146 @@ class TestV2HTTPResponse(NetworkPluginV2TestCase,
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):
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):
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.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_utils as cutil
from quantum.plugins.cisco.db import network_db_v2 as cdb