]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fixing unit test failures in Cisco plugin
authorSumit Naiksatam <snaiksat@cisco.com>
Sun, 19 Aug 2012 03:50:38 +0000 (20:50 -0700)
committerSumit Naiksatam <snaiksat@cisco.com>
Mon, 20 Aug 2012 01:25:04 +0000 (18:25 -0700)
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

quantum/plugins/cisco/models/network_multi_blade_v2.py
quantum/plugins/cisco/models/virt_phy_sw_v2.py
quantum/plugins/cisco/network_plugin.py
quantum/plugins/cisco/tests/unit/api-paste.ini.cisco.test
quantum/plugins/cisco/tests/unit/v2/api-paste.ini.cisco.test [new file with mode: 0644]
quantum/plugins/cisco/tests/unit/v2/nexus/fake_nexus_driver.py
quantum/plugins/cisco/tests/unit/v2/quantumv2.conf.cisco.test
quantum/plugins/cisco/tests/unit/v2/test_api_v2.py
quantum/plugins/cisco/tests/unit/v2/test_network_plugin.py
quantum/plugins/cisco/ucs/cisco_ucs_plugin_v2.py

index e8f19eda5b22ffc09c2a4e997f79855c1132eeb4..83399ee19599a324d268eb0dce9d1345a95678b3 100644 (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]
index 653d39bdea3481b1c4ed0832e7f5495000886345..2d0b14fe91e1eaf19e305e191ad38d0026f82ab1 100644 (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
index 9339d2246343330b9e8e124133dae7844af983b9..38fe98ddd163fbafe6ae624ac88e0b82f1c1d983 100644 (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(
index 9163752c516867382e5d8819263ef6e32aeed9fb..f732fc91732bfb3ef6e4211d46c01da223fcff1f 100644 (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
diff --git a/quantum/plugins/cisco/tests/unit/v2/api-paste.ini.cisco.test b/quantum/plugins/cisco/tests/unit/v2/api-paste.ini.cisco.test
new file mode 100644 (file)
index 0000000..f732fc9
--- /dev/null
@@ -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
index 2180ab2f1d46d647f82110e99c51a0e0da7fece4..206a2cc03bc8572356cc1e0ae4df44fa29629e33 100644 (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
index 89ff3e6423261a652d3b4429603dd138d6756e26..56511a73974bb151e2931976c5245909f45e7900 100644 (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
index 43d81f2bad390dedbad09597f5821b6479c2db99..c20427de7e724769a7ad530255fbbf1274e172be 100644 (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)
index 89a4fa8018455a6f7cfa305c9d5dac9979fd0841..ccfd8e8b827e36c2facb7ac3ba9c8ea524348d74 100644 (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')
index b831c1c6e23848896e306613d62cdebbb312d684..0de87e70c88e0a9305d9d1a3cdec6bb125e4c449 100644 (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