diff --git a/vmware_nsx_tempest/services/README.rst b/vmware_nsx_tempest/services/README.rst index 17b40ef..17ce8ec 100644 --- a/vmware_nsx_tempest/services/README.rst +++ b/vmware_nsx_tempest/services/README.rst @@ -1,5 +1,4 @@ -This folder contains services for managing NSX-t, NSX-v and -neutron sub-services not yet migrating to tempest-lib. +This folder contains services for managing NSX-v, NSX-v3. Services provided: @@ -12,6 +11,13 @@ l2_gateway_connection_client.py based on tempest BaseNetworkClient implements client APIs to manage neutron l2-gateway-connection resources +lbaas v2 clients: ported from neutron_lbaas to comply with tempest services. + lbaas/load_balancers_client.py + lbaas/listeners_client.py + lbaas/pools_client.py + lbaas/health_monitorys_client.py + lbaas/members_client.py + lbv1_client.py based on tempest BaseNetworkClient implements client APIs to manage neutron v1 load-balancer resources @@ -22,9 +28,15 @@ network_client_base.py BaseNetworkClient. Inherent here and used by all vmware-nsx-tempest client for now. -# NSXv speific services -nsxv_client.py which it has API ops on the following NSX-v components +# NSX speific services +nsxv_client.py implements API to manage NSX-v components - Logical switch (Tenant network) - Edge (Service edge, DHCP edge, and VDR edge) - DFW firewall rules (Security group) - SpoofGuard + +nsxv3_client.py implements API to manage NSX backend resources: + - logical switch + - firewall section + - nsgroup + - logical router diff --git a/vmware_nsx_tempest/services/lbaas/__init__.py b/vmware_nsx_tempest/services/lbaas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vmware_nsx_tempest/services/lbaas/health_monitors_client.py b/vmware_nsx_tempest/services/lbaas/health_monitors_client.py new file mode 100644 index 0000000..88772fa --- /dev/null +++ b/vmware_nsx_tempest/services/lbaas/health_monitors_client.py @@ -0,0 +1,70 @@ +# Copyright 2014 Rackspace US Inc. All rights reserved. +# +# 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 tempest.lib.services.network import base + + +class HealthMonitorsClient(base.BaseNetworkClient): + resource = 'healthmonitor' + resource_plural = 'healthmonitors' + path = 'lbaas/healthmonitors' + resource_base_path = '/%s' % path + resource_object_path = '/%s/%%s' % path + + def create_health_monitor(self, **kwargs): + uri = self.resource_base_path + post_data = {self.resource: kwargs} + return self.create_resource(uri, post_data) + + def update_health_monitor(self, health_monitor_id, **kwargs): + uri = self.resource_object_path % health_monitor_id + post_data = {self.resource: kwargs} + return self.update_resource(uri, post_data) + + def show_health_monitor(self, health_monitor_id, **fields): + uri = self.resource_object_path % health_monitor_id + return self.show_resource(uri, **fields) + + def delete_health_monitor(self, health_monitor_id): + uri = self.resource_object_path % health_monitor_id + return self.delete_resource(uri) + + def list_health_monitors(self, **filters): + uri = self.resource_base_path + return self.list_resources(uri, **filters) + + +def get_client(client_mgr): + """create a lbaas health_monitors client from manager or networks_client + + For itempest user: + from itempest import load_our_solar_system as osn + from vmware_nsx_tempest.services.lbaas import health_monitors_client + healthmonitors_client = health_monitors_client.get_client( + osn.adm.manager) + For tempest user: + healthmonitors_client = health_monitors_client.get_client(osn.adm) + """ + manager = getattr(client_mgr, 'manager', client_mgr) + net_client = getattr(manager, 'networks_client') + try: + _params = manager.default_params_with_timeout_values.copy() + except Exception: + _params = {} + client = HealthMonitorsClient(net_client.auth_provider, + net_client.service, + net_client.region, + net_client.endpoint_type, + **_params) + return client diff --git a/vmware_nsx_tempest/services/lbaas/listeners_client.py b/vmware_nsx_tempest/services/lbaas/listeners_client.py new file mode 100644 index 0000000..8fbeb05 --- /dev/null +++ b/vmware_nsx_tempest/services/lbaas/listeners_client.py @@ -0,0 +1,69 @@ +# Copyright 2014 Rackspace US Inc. All rights reserved. +# +# 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 tempest.lib.services.network import base + + +class ListenersClient(base.BaseNetworkClient): + resource = 'listener' + resource_plural = 'listeners' + path = 'lbaas/listeners' + resource_base_path = '/%s' % path + resource_object_path = '/%s/%%s' % path + + def create_listener(self, **kwargs): + uri = self.resource_base_path + post_data = {self.resource: kwargs} + return self.create_resource(uri, post_data) + + def update_listener(self, listener_id, **kwargs): + uri = self.resource_object_path % listener_id + post_data = {self.resource: kwargs} + return self.update_resource(uri, post_data) + + def show_listener(self, listener_id, **fields): + uri = self.resource_object_path % listener_id + return self.show_resource(uri, **fields) + + def delete_listener(self, listener_id): + uri = self.resource_object_path % listener_id + return self.delete_resource(uri) + + def list_listeners(self, **filters): + uri = self.resource_base_path + return self.list_resources(uri, **filters) + + +def get_client(client_mgr): + """create a lbaas listener client from manager or networks_client + + For itempest user: + from itempest import load_our_solar_system as osn + from vmware_nsx_tempest.services.lbaas import pools_client + lbaas_client = pools_client.get_client(osn.adm.manager) + For tempest user: + lbaas_client = pools_client.get_client(osn.adm) + """ + manager = getattr(client_mgr, 'manager', client_mgr) + net_client = getattr(manager, 'networks_client') + try: + _params = manager.default_params_with_timeout_values.copy() + except Exception: + _params = {} + client = ListenersClient(net_client.auth_provider, + net_client.service, + net_client.region, + net_client.endpoint_type, + **_params) + return client diff --git a/vmware_nsx_tempest/services/lbaas/load_balancers_client.py b/vmware_nsx_tempest/services/lbaas/load_balancers_client.py new file mode 100644 index 0000000..13a115e --- /dev/null +++ b/vmware_nsx_tempest/services/lbaas/load_balancers_client.py @@ -0,0 +1,79 @@ +# Copyright 2014 Rackspace US Inc. All rights reserved. +# +# 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 tempest.lib.services.network import base + + +class LoadBalancersClient(base.BaseNetworkClient): + resource = 'loadbalancer' + resource_plural = 'loadbalancers' + path = 'lbaas/loadbalancers' + resource_base_path = '/%s' % path + resource_object_path = '/%s/%%s' % path + resource_object_status_path = '/%s/%%s/statuses' % path + resource_object_stats_path = '/%s/%%s/stats' % path + + def create_load_balancer(self, **kwargs): + uri = self.resource_base_path + post_data = {self.resource: kwargs} + return self.create_resource(uri, post_data) + + def update_load_balancer(self, load_balancer_id, **kwargs): + uri = self.resource_object_path % load_balancer_id + post_data = {self.resource: kwargs} + return self.update_resource(uri, post_data) + + def show_load_balancer(self, load_balancer_id, **fields): + uri = self.resource_object_path % load_balancer_id + return self.show_resource(uri, **fields) + + def show_load_balancer_status_tree(self, load_balancer_id, **fields): + uri = self.resource_object_status_path % load_balancer_id + return self.show_resource(uri, **fields) + + def show_load_balancer_stats(self, load_balancer_id, **fields): + uri = self.resource_object_stats_path % load_balancer_id + return self.show_resource(uri, **fields) + + def delete_load_balancer(self, load_balancer_id): + uri = self.resource_object_path % load_balancer_id + return self.delete_resource(uri) + + def list_load_balancers(self, **filters): + uri = self.resource_base_path + return self.list_resources(uri, **filters) + + +def get_client(client_mgr): + """create a lbaas load-balancers client from manager or networks_client + + For itempest user: + from itempest import load_our_solar_system as osn + from vmware_nsx_tempest.services.lbaas import load_balancers_client + lbaas_client = load_balancers_client.get_client(osn.adm.manager) + For tempest user: + lbaas_client = load_balancers_client.get_client(osn.adm) + """ + manager = getattr(client_mgr, 'manager', client_mgr) + net_client = getattr(manager, 'networks_client') + try: + _params = manager.default_params_with_timeout_values.copy() + except Exception: + _params = {} + client = LoadBalancersClient(net_client.auth_provider, + net_client.service, + net_client.region, + net_client.endpoint_type, + **_params) + return client diff --git a/vmware_nsx_tempest/services/lbaas/members_client.py b/vmware_nsx_tempest/services/lbaas/members_client.py new file mode 100644 index 0000000..ae803df --- /dev/null +++ b/vmware_nsx_tempest/services/lbaas/members_client.py @@ -0,0 +1,69 @@ +# Copyright 2014 Rackspace US Inc. All rights reserved. +# +# 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 tempest.lib.services.network import base + + +class MembersClient(base.BaseNetworkClient): + resource = 'member' + resource_plural = 'members' + path = 'lbaas/members' + resource_base_path = '/lbaas/pools/%s/members' + resource_object_path = '/lbaas/pools/%s/members/%s' + + def create_member(self, pool_id, **kwargs): + uri = self.resource_base_path % pool_id + post_data = {self.resource: kwargs} + return self.create_resource(uri, post_data) + + def update_member(self, pool_id, member_id, **kwargs): + uri = self.resource_object_path % (pool_id, member_id) + post_data = {self.resource: kwargs} + return self.update_resource(uri, post_data) + + def show_member(self, pool_id, member_id, **fields): + uri = self.resource_object_path % (pool_id, member_id) + return self.show_resource(uri, **fields) + + def delete_member(self, pool_id, member_id): + uri = self.resource_object_path % (pool_id, member_id) + return self.delete_resource(uri) + + def list_members(self, pool_id, **filters): + uri = self.resource_base_path % pool_id + return self.list_resources(uri, **filters) + + +def get_client(client_mgr): + """create a lbaas members client from manager or networks_client + + For itempest user: + from itempest import load_our_solar_system as osn + from vmware_nsx_tempest.services.lbaas import members_client + members_client = members_client.get_client(osn.adm.manager) + For tempest user: + members_client = members_client.get_client(osn.adm) + """ + manager = getattr(client_mgr, 'manager', client_mgr) + net_client = getattr(manager, 'networks_client') + try: + _params = manager.default_params_with_timeout_values.copy() + except Exception: + _params = {} + client = MembersClient(net_client.auth_provider, + net_client.service, + net_client.region, + net_client.endpoint_type, + **_params) + return client diff --git a/vmware_nsx_tempest/services/lbaas/pools_client.py b/vmware_nsx_tempest/services/lbaas/pools_client.py new file mode 100644 index 0000000..5464efc --- /dev/null +++ b/vmware_nsx_tempest/services/lbaas/pools_client.py @@ -0,0 +1,69 @@ +# Copyright 2014 Rackspace US Inc. All rights reserved. +# +# 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 tempest.lib.services.network import base + + +class PoolsClient(base.BaseNetworkClient): + resource = 'pool' + resource_plural = 'pools' + path = 'lbaas/pools' + resource_base_path = '/%s' % path + resource_object_path = '/%s/%%s' % path + + def create_pool(self, **kwargs): + uri = self.resource_base_path + post_data = {self.resource: kwargs} + return self.create_resource(uri, post_data) + + def update_pool(self, pool_id, **kwargs): + uri = self.resource_object_path % pool_id + post_data = {self.resource: kwargs} + return self.update_resource(uri, post_data) + + def show_pool(self, pool_id, **fields): + uri = self.resource_object_path % pool_id + return self.show_resource(uri, **fields) + + def delete_pool(self, pool_id): + uri = self.resource_object_path % pool_id + return self.delete_resource(uri) + + def list_pools(self, **filters): + uri = self.resource_base_path + return self.list_resources(uri, **filters) + + +def get_client(client_mgr): + """create a lbaas pools client from manager or networks_client + + For itempest user: + from itempest import load_our_solar_system as osn + from vmware_nsx_tempest.services.lbaas import pools_client + pools_client = pools_client.get_client(osn.adm.manager) + For tempest user: + pools_client = pools_client.get_client(osn.adm) + """ + manager = getattr(client_mgr, 'manager', client_mgr) + net_client = getattr(manager, 'networks_client') + try: + _params = manager.default_params_with_timeout_values.copy() + except Exception: + _params = {} + client = PoolsClient(net_client.auth_provider, + net_client.service, + net_client.region, + net_client.endpoint_type, + **_params) + return client diff --git a/vmware_nsx_tempest/tests/nsxv/api/base_provider.py b/vmware_nsx_tempest/tests/nsxv/api/base_provider.py index a2b1dad..ffa21cd 100644 --- a/vmware_nsx_tempest/tests/nsxv/api/base_provider.py +++ b/vmware_nsx_tempest/tests/nsxv/api/base_provider.py @@ -14,11 +14,11 @@ # under the License. import netaddr -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions from tempest.api.network import base from tempest import config +from tempest.lib.common.utils import data_utils +from tempest.lib import exceptions from tempest import test CONF = config.CONF diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/__init__.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/base.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/base.py new file mode 100644 index 0000000..20d6a97 --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/base.py @@ -0,0 +1,457 @@ +# Copyright 2015 Rackspace +# +# 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. +# +# 2016-03 (akang) +# ported from neutron-lbaas to comply to tempest framework +# NSX-v require vip-subnet attached to exclusive router + +import time + +from oslo_log import log as logging + +from tempest.api.network import base +from tempest import config +from tempest import test + +from tempest.lib.common.utils import data_utils +from tempest.lib import exceptions + +from vmware_nsx_tempest._i18n import _ +from vmware_nsx_tempest._i18n import _LI +from vmware_nsx_tempest.services.lbaas import health_monitors_client +from vmware_nsx_tempest.services.lbaas import listeners_client +from vmware_nsx_tempest.services.lbaas import load_balancers_client +from vmware_nsx_tempest.services.lbaas import members_client +from vmware_nsx_tempest.services.lbaas import pools_client + +CONF = config.CONF +LOG = logging.getLogger(__name__) + + +class BaseTestCase(base.BaseNetworkTest): + + # This class picks non-admin credentials and run the tempest tests + + _lbs_to_delete = [] + _setup_lbaas_non_admin_resource = True + + @classmethod + def skip_checks(cls): + super(BaseTestCase, cls).skip_checks() + if not test.is_extension_enabled('lbaasv2', 'network'): + msg = "lbaasv2 extension not enabled." + raise cls.skipException(msg) + + @classmethod + def resource_setup(cls): + super(BaseTestCase, cls).resource_setup() + + if cls._setup_lbaas_non_admin_resource: + mgr = cls.get_client_manager() + cls.create_lbaas_clients(mgr) + cls.setup_lbaas_core_network() + + @classmethod + def create_lbaas_clients(cls, mgr): + cls.load_balancers_client = load_balancers_client.get_client(mgr) + cls.listeners_client = listeners_client.get_client(mgr) + cls.pools_client = pools_client.get_client(mgr) + cls.members_client = members_client.get_client(mgr) + cls.health_monitors_client = health_monitors_client.get_client(mgr) + + @classmethod + def setup_lbaas_core_network(cls): + rand_number = data_utils.rand_name() + network_name = 'lbaas-network-' + rand_number + router_name = 'lbaas-router-' + rand_number + cls.network = cls.create_network(network_name) + cls.subnet = cls.create_subnet(cls.network) + cls.tenant_id = cls.subnet.get('tenant_id') + cls.subnet_id = cls.subnet.get('id') + # NSX-v: load-balancer's subnet need to attach to exclusive-router + router_cfg = dict(router_name=router_name, router_type='exclusive') + cls.router = cls.create_router(**router_cfg) + cls.create_router_interface(cls.router['id'], cls.subnet['id']) + + @classmethod + def resource_cleanup(cls): + for lb_id in cls._lbs_to_delete: + try: + statuses = cls._show_load_balancer_status_tree(lb_id) + lb = statuses.get('loadbalancer') + except exceptions.NotFound: + continue + for listener in lb.get('listeners', []): + for pool in listener.get('pools'): + hm = pool.get('healthmonitor') + if hm: + cls._try_delete_resource( + cls.health_monitors_client.delete_health_monitor, + pool.get('healthmonitor').get('id')) + cls._wait_for_load_balancer_status(lb_id) + cls._try_delete_resource(cls.pools_client.delete_pool, + pool.get('id')) + cls._wait_for_load_balancer_status(lb_id) + health_monitor = pool.get('healthmonitor') + if health_monitor: + cls._try_delete_resource( + cls.health_monitors_client.delete_health_monitor, + health_monitor.get('id')) + cls._wait_for_load_balancer_status(lb_id) + cls._try_delete_resource(cls.listeners_client.delete_listener, + listener.get('id')) + cls._wait_for_load_balancer_status(lb_id) + cls._try_delete_resource(cls._delete_load_balancer, lb_id) + # NSX-v: delete exclusive router + cls.delete_router(cls.router) + super(BaseTestCase, cls).resource_cleanup() + + @classmethod + def setUpClass(cls): + cls.LOG = logging.getLogger(cls._get_full_case_name()) + super(BaseTestCase, cls).setUpClass() + + def setUp(cls): + cls.LOG.info(_LI('Starting: {0}').format(cls._testMethodName)) + super(BaseTestCase, cls).setUp() + + def tearDown(cls): + super(BaseTestCase, cls).tearDown() + cls.LOG.info(_LI('Finished: {0}\n').format(cls._testMethodName)) + + @classmethod + def _create_load_balancer(cls, wait=True, **lb_kwargs): + lb = cls.load_balancers_client.create_load_balancer(**lb_kwargs) + lb = lb.get('loadbalancer', lb) + if wait: + cls._wait_for_load_balancer_status(lb.get('id')) + + cls._lbs_to_delete.append(lb.get('id')) + port = cls.ports_client.show_port(lb['vip_port_id']) + cls.ports.append(port['port']) + return lb + + @classmethod + def _create_active_load_balancer(cls, **kwargs): + lb = cls._create_load_balancer(**kwargs) + lb = lb.get('loadbalancer', lb) + lb = cls._wait_for_load_balancer_status(lb.get('id')) + return lb + + @classmethod + def _delete_load_balancer(cls, load_balancer_id, wait=True): + cls.load_balancers_client.delete_load_balancer(load_balancer_id) + if wait: + cls._wait_for_load_balancer_status( + load_balancer_id, delete=True) + + @classmethod + def _update_load_balancer(cls, load_balancer_id, wait=True, **lb_kwargs): + lb = cls.load_balancers_client.update_load_balancer( + load_balancer_id, **lb_kwargs) + lb = lb.get('loadbalancer', lb) + if wait: + cls._wait_for_load_balancer_status( + load_balancer_id) + return lb + + @classmethod + def _show_load_balancer(cls, load_balancer_id): + lb = cls.load_balancers_client.show_load_balancer(load_balancer_id) + lb = lb.get('loadbalancer', lb) + return lb + + @classmethod + def _list_load_balancers(cls, **filters): + lbs = cls.load_balancers_client.list_load_balancers(**filters) + lb_list = lbs.get('loadbalancers', lbs) + return lb_list + + @classmethod + def _wait_for_load_balancer_status(cls, load_balancer_id, + provisioning_status='ACTIVE', + operating_status='ONLINE', + delete=False): + interval_time = 1 + timeout = 600 + end_time = time.time() + timeout + lb = {} + while time.time() < end_time: + try: + lb = cls.load_balancers_client.show_load_balancer( + load_balancer_id) + if not lb: + # loadbalancer not found + if delete: + break + else: + raise Exception( + _("loadbalancer {lb_id} not" + " found").format( + lb_id=load_balancer_id)) + lb = lb.get('loadbalancer', lb) + if (lb.get('provisioning_status') == provisioning_status and + lb.get('operating_status') == operating_status): + break + time.sleep(interval_time) + except exceptions.NotFound as e: + # if wait is for delete operation do break + if delete: + break + else: + # raise original exception + raise e + else: + if delete: + raise exceptions.TimeoutException( + _("Waited for load balancer {lb_id} to be deleted for " + "{timeout} seconds but can still observe that it " + "exists.").format( + lb_id=load_balancer_id, + timeout=timeout)) + else: + raise exceptions.TimeoutException( + _("Wait for load balancer ran for {timeout} seconds and " + "did not observe {lb_id} reach {provisioning_status} " + "provisioning status and {operating_status} " + "operating status.").format( + timeout=timeout, + lb_id=load_balancer_id, + provisioning_status=provisioning_status, + operating_status=operating_status)) + return lb + + @classmethod + def _show_load_balancer_status_tree(cls, load_balancer_id): + statuses = cls.load_balancers_client.show_load_balancer_status_tree( + load_balancer_id=load_balancer_id) + statuses = statuses.get('statuses', statuses) + return statuses + + @classmethod + def _show_load_balancer_stats(cls, load_balancer_id): + stats = cls.load_balancers_client.show_load_balancer_stats( + load_balancer_id=load_balancer_id) + stats = stats.get('stats', stats) + return stats + + @classmethod + def _create_listener(cls, wait=True, **listener_kwargs): + listener = cls.listeners_client.create_listener(**listener_kwargs) + listener = listener.get('listener', listener) + if wait: + cls._wait_for_load_balancer_status(cls.load_balancer.get('id')) + return listener + + @classmethod + def _delete_listener(cls, listener_id, wait=True): + cls.listeners_client.delete_listener(listener_id) + if wait: + cls._wait_for_load_balancer_status(cls.load_balancer.get('id')) + + @classmethod + def _update_listener(cls, listener_id, wait=True, **listener_kwargs): + listener = cls.listeners_client.update_listener( + listener_id, **listener_kwargs) + listener = listener.get('listener', listener) + if wait: + cls._wait_for_load_balancer_status( + cls.load_balancer.get('id')) + return listener + + @classmethod + def _show_listener(cls, listener_id): + listener = cls.listeners_client.show_listener(listener_id) + listener = listener.get('listener', listener) + return listener + + @classmethod + def _list_listeners(cls, **filters): + lbs = cls.listeners_client.list_listeners(**filters) + lb_list = lbs.get('listeners', lbs) + return lb_list + + @classmethod + def _create_pool(cls, wait=True, **pool_kwargs): + pool = cls.pools_client.create_pool(**pool_kwargs) + pool = pool.get('pool', pool) + if wait: + cls._wait_for_load_balancer_status(cls.load_balancer.get('id')) + return pool + + @classmethod + def _delete_pool(cls, pool_id, wait=True): + cls.pools_client.delete_pool(pool_id) + if wait: + cls._wait_for_load_balancer_status(cls.load_balancer.get('id')) + + @classmethod + def _update_pool(cls, pool_id, wait=True, **pool_kwargs): + pool = cls.pools_client.update_pool(pool_id, **pool_kwargs) + pool = pool.get('pool', pool) + if wait: + cls._wait_for_load_balancer_status( + cls.load_balancer.get('id')) + return pool + + @classmethod + def _show_pool(cls, pool_id): + pool = cls.pools_client.show_pool(pool_id) + pool = pool.get('pool', pool) + return pool + + @classmethod + def _list_pools(cls, **filters): + pools = cls.pools_client.list_pools(**filters) + pool_list = pools.get('pools', pools) + return pool_list + + def _create_health_monitor(self, wait=True, cleanup=True, + **health_monitor_kwargs): + hm = self.health_monitors_client.create_health_monitor( + **health_monitor_kwargs) + hm = hm.get('healthmonitor', hm) + if cleanup: + self.addCleanup(self._delete_health_monitor, hm.get('id')) + if wait: + self._wait_for_load_balancer_status(self.load_balancer.get('id')) + return hm + + def _delete_health_monitor(self, health_monitor_id, wait=True): + self.health_monitors_client.delete_health_monitor(health_monitor_id) + if wait: + self._wait_for_load_balancer_status(self.load_balancer.get('id')) + + def _update_health_monitor(self, health_monitor_id, wait=True, + **health_monitor_kwargs): + hm = self.health_monitors_client.update_health_monitor( + health_monitor_id, **health_monitor_kwargs) + hm = hm.get('healthmonitor', hm) + if wait: + self._wait_for_load_balancer_status( + self.load_balancer.get('id')) + return hm + + def _show_health_monitor(self, health_monitor_id): + hm = self.health_monitors_client.show_health_monitor(health_monitor_id) + hm = hm.get('healthmonitor', hm) + return hm + + def _list_health_monitors(self, **filters): + hms = self.health_monitors_client.list_health_monitors(**filters) + hm_list = hms.get('healthmonitors', hms) + return hm_list + + @classmethod + def _create_member(cls, pool_id, wait=True, **member_kwargs): + member = cls.members_client.create_member(pool_id, **member_kwargs) + member = member.get('member', member) + if wait: + cls._wait_for_load_balancer_status(cls.load_balancer.get('id')) + return member + + @classmethod + def _delete_member(cls, pool_id, member_id, wait=True): + cls.members_client.delete_member(pool_id, member_id) + if wait: + cls._wait_for_load_balancer_status(cls.load_balancer.get('id')) + + @classmethod + def _update_member(cls, pool_id, member_id, wait=True, + **member_kwargs): + member = cls.members_client.update_member( + pool_id, member_id, **member_kwargs) + member = member.get('member', member) + if wait: + cls._wait_for_load_balancer_status( + cls.load_balancer.get('id')) + return member + + @classmethod + def _show_member(cls, pool_id, member_id): + member = cls.members_client.show_member(pool_id, member_id) + member = member.get('member', member) + return member + + @classmethod + def _list_members(cls, pool_id, **filters): + members = cls.members_client.list_members(pool_id, **filters) + member_list = members.get('members', members) + return member_list + + @classmethod + def _check_status_tree(cls, load_balancer_id, listener_ids=None, + pool_ids=None, health_monitor_id=None, + member_ids=None): + statuses = cls._show_load_balancer_status_tree(load_balancer_id) + load_balancer = statuses['loadbalancer'] + assert 'ONLINE' == load_balancer['operating_status'] + assert 'ACTIVE' == load_balancer['provisioning_status'] + + if listener_ids: + cls._check_status_tree_thing(listener_ids, + load_balancer['listeners']) + if pool_ids: + cls._check_status_tree_thing(pool_ids, + load_balancer['listeners']['pools']) + if member_ids: + cls._check_status_tree_thing( + member_ids, + load_balancer['listeners']['pools']['members']) + if health_monitor_id: + health_monitor = ( + load_balancer['listeners']['pools']['health_monitor']) + assert health_monitor_id == health_monitor['id'] + assert 'ACTIVE' == health_monitor['provisioning_status'] + + @classmethod + def _check_status_tree_thing(cls, actual_thing_ids, status_tree_things): + found_things = 0 + status_tree_things = status_tree_things + assert len(actual_thing_ids) == len(status_tree_things) + for actual_thing_id in actual_thing_ids: + for status_tree_thing in status_tree_things: + if status_tree_thing['id'] == actual_thing_id: + assert 'ONLINE' == ( + status_tree_thing['operating_status']) + assert 'ACTIVE' == ( + status_tree_thing['provisioning_status']) + found_things += 1 + assert len(actual_thing_ids) == found_things + + @classmethod + def _get_full_case_name(cls): + name = '{module}:{case_name}'.format( + module=cls.__module__, + case_name=cls.__name__ + ) + return name + + +class BaseAdminTestCase(BaseTestCase): + + # This class picks admin credentials and run the tempest tests + _setup_lbaas_non_admin_resource = False + + @classmethod + def resource_setup(cls): + super(BaseAdminTestCase, cls).resource_setup() + + mgr = cls.get_client_manager(credential_type='admin') + cls.create_lbaas_clients(mgr) + cls.setup_lbaas_core_network() + + @classmethod + def resource_cleanup(cls): + super(BaseAdminTestCase, cls).resource_cleanup() diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_health_monitors_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_health_monitors_admin.py new file mode 100644 index 0000000..0f04aa0 --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_health_monitors_admin.py @@ -0,0 +1,102 @@ +# 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 oslo_log import log as logging +from oslo_utils import uuidutils + +from tempest import config +from tempest.lib import decorators +from tempest.lib import exceptions as ex +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + +CONF = config.CONF + +LOG = logging.getLogger(__name__) + + +class TestHealthMonitors(base.BaseAdminTestCase): + + """Tests the following operations in the Neutron-LBaaS API + + using the REST client for Health Monitors with ADMIN role: + + create health monitor with missing tenant_id + create health monitor with empty tenant id + create health monitor with another tenant_id + """ + + @classmethod + def resource_setup(cls): + super(TestHealthMonitors, cls).resource_setup() + cls.load_balancer = cls._create_load_balancer( + tenant_id=cls.subnet.get('tenant_id'), + vip_subnet_id=cls.subnet.get('id')) + cls.listener = cls._create_listener( + loadbalancer_id=cls.load_balancer.get('id'), + protocol='HTTP', protocol_port=80) + cls.pool = cls._create_pool( + protocol='HTTP', lb_algorithm='ROUND_ROBIN', + listener_id=cls.listener.get('id')) + + @classmethod + def resource_cleanup(cls): + super(TestHealthMonitors, cls).resource_cleanup() + + @test.attr(type='smoke') + @test.idempotent_id('24cf7da4-b829-4df5-a133-b6cef97ec560') + def test_create_health_monitor_missing_tenant_id_field(self): + """Test if admin user can + + create health monitor with a missing tenant id field. + """ + hm = self._create_health_monitor(type='HTTP', delay=3, max_retries=10, + timeout=5, + pool_id=self.pool.get('id')) + + admin_hm = self._show_health_monitor(hm.get('id')) + admin_tenant_id = admin_hm.get('tenant_id') + hm_tenant_id = hm.get('tenant_id') + self.assertEqual(admin_tenant_id, hm_tenant_id) + + @test.attr(type='negative') + @decorators.skip_because(bug="1638148") + @test.idempotent_id('acbff982-15d6-43c5-a015-e72b7df30998') + def test_create_health_monitor_empty_tenant_id_field(self): + """Test with admin user + + creating health monitor with an empty tenant id field should fail. + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, + timeout=5, + pool_id=self.pool.get('id'), + tenant_id="") + + @test.attr(type='smoke') + @test.idempotent_id('a318d351-a72e-46dc-a094-8a751e4fa7aa') + def test_create_health_monitor_for_another_tenant_id_field(self): + """Test with admin user + + create health Monitors for another tenant id. + """ + + tenantid = uuidutils.generate_uuid() + hm = self._create_health_monitor(type='HTTP', delay=3, max_retries=10, + timeout=5, + pool_id=self.pool.get('id'), + tenant_id=tenantid) + + self.assertEqual(hm.get('tenant_id'), tenantid) + self.assertNotEqual(hm.get('tenant_id'), + self.subnet.get('tenant_id')) diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_health_monitors_non_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_health_monitors_non_admin.py new file mode 100644 index 0000000..0d0b23a --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_health_monitors_non_admin.py @@ -0,0 +1,684 @@ +# 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 tempest.lib import decorators +from tempest.lib import exceptions as ex +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + + +class TestHealthMonitors(base.BaseTestCase): + + """Tests the following operations in the Neutron-LBaaS API + + using the REST client for Health Monitors: + list pools + create pool + get pool + update pool + delete pool + """ + + @classmethod + def resource_setup(cls): + super(TestHealthMonitors, cls).resource_setup() + cls.load_balancer = cls._create_load_balancer( + tenant_id=cls.subnet.get('tenant_id'), + vip_subnet_id=cls.subnet.get('id')) + cls.listener = cls._create_listener( + loadbalancer_id=cls.load_balancer.get('id'), + protocol='HTTP', protocol_port=80) + cls.pool = cls._create_pool( + protocol='HTTP', lb_algorithm='ROUND_ROBIN', + listener_id=cls.listener.get('id')) + cls.create_basic_hm_kwargs = {'type': 'HTTP', 'delay': 3, + 'max_retries': 10, 'timeout': 5, + 'pool_id': cls.pool.get('id')} + + # possible cause is bug#1638601: can not delete health monitor + # temparary solution + def remove_existing_health_monitors(self): + """remove all existing hm because one pool can only one hm + + During testing, because bug#163860 and + one pool can only have one health_monitor, + we delete hm before testing -- acutally not very effective. + + hm_list = self._list_health_monitors() + for hm in hm_list: + self._try_delete_resource( + self._delete_health_monitor, + hm.get('id')) + """ + return None + + @test.attr(type='smoke') + @test.idempotent_id('3c223a4d-3733-4daa-a6e3-69a31f9e7304') + def test_list_health_monitors_empty(self): + hm_list = self._list_health_monitors() + self.assertEmpty(hm_list) + + @test.attr(type='smoke') + @test.idempotent_id('76880edd-b01c-4b80-ba4d-1d10f35aaeb7') + def test_list_health_monitors_one(self): + hm = self._create_health_monitor(**self.create_basic_hm_kwargs) + hm_list = self._list_health_monitors() + self.assertIn(hm, hm_list) + + @test.attr(type='smoke') + @test.idempotent_id('22b984d5-8284-4f7c-90c4-407d0e872ea8') + def test_list_health_monitors_two(self): + hm1 = self._create_health_monitor(**self.create_basic_hm_kwargs) + new_listener = self._create_listener( + loadbalancer_id=self.load_balancer.get('id'), + protocol='HTTP', protocol_port=88) + self.addCleanup(self._delete_listener, new_listener.get('id')) + new_pool = self._create_pool( + protocol='HTTP', lb_algorithm='ROUND_ROBIN', + listener_id=new_listener.get('id')) + self.addCleanup(self._delete_pool, new_pool.get('id')) + hm2 = self._create_health_monitor( + type='HTTP', max_retries=10, delay=3, timeout=5, + pool_id=new_pool.get('id')) + hm_list = self._list_health_monitors() + self.assertEqual(2, len(hm_list)) + self.assertIn(hm1, hm_list) + self.assertIn(hm2, hm_list) + + @test.attr(type='smoke') + @test.idempotent_id('ca49b640-259c-49ee-be9c-b425a4bbd2cf') + def test_get_health_monitor(self): + hm = self._create_health_monitor(**self.create_basic_hm_kwargs) + hm_test = self._show_health_monitor(hm.get('id')) + self.assertEqual(hm, hm_test) + + @test.attr(type='smoke') + @test.idempotent_id('80ded4c2-2277-4e19-8280-3519b22a999e') + def test_create_health_monitor(self): + new_hm = self._create_health_monitor(**self.create_basic_hm_kwargs) + hm = self._show_health_monitor(new_hm.get('id')) + self.assertEqual(new_hm, hm) + + @test.attr(type='smoke') + @test.idempotent_id('387f669b-7a02-4ab3-880d-719dd79ff853') + def test_create_health_monitor_missing_attribute(self): + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, + pool_id=self.pool.get('id')) + + @test.attr(type=['smoke', 'negative']) + @test.idempotent_id('bf2ec88e-91d3-48f5-b9f2-be3dab21445c') + def test_create_health_monitor_missing_required_field_type(self): + """Test if a non_admin user can + + create a health monitor with type missing + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type=['smoke', 'negative']) + @test.idempotent_id('85110a81-d905-40f1-92c0-7dafb1617915') + def test_create_health_monitor_missing_required_field_delay(self): + """Test if a non_admin user can + + create a health monitor with delay missing + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type=['smoke', 'negative']) + @test.idempotent_id('10ed9396-271a-4edd-948d-93ad44df2713') + def test_create_health_monitor_missing_required_field_timeout(self): + """Test if a non_admin user can + + create a health monitor with timeout missing + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, + pool_id=self.pool.get('id')) + + @test.attr(type=['smoke', 'negative']) + @test.idempotent_id('69614cb5-9078-4b93-8dfa-45d59ac240f8') + def test_create_health_monitor_missing_required_field_max_retries(self): + """Test if a non_admin user + + can create a health monitor with max_retries missing + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type=['smoke', 'negative']) + @test.idempotent_id('543d1f68-1b3a-49c8-bc6c-3eb8123b6e9a') + def test_create_health_monitor_missing_required_field_pool_id(self): + """Test if a non_admin user + + can create a health monitor with pool_id missing + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5) + + @test.attr(type='smoke') + @test.idempotent_id('4f8d17d2-3e52-4e34-83c7-4398b328c559') + def test_create_health_monitor_missing_admin_state_up(self): + """Test if a non_admin user + + can create a health monitor with admin_state_up missing + """ + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + hm_test = self._show_health_monitor(hm.get('id')) + self.assertEqual(hm, hm_test) + self.assertEqual(True, hm_test.get('admin_state_up')) + + @test.attr(type='smoke') + @test.idempotent_id('6e1066d3-f358-446e-a574-5d4ceaf0b51d') + def test_create_health_monitor_missing_http_method(self): + """Test if a non_admin user + + can create a health monitor with http_method missing + """ + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + hm_test = self._show_health_monitor(hm.get('id')) + self.assertEqual(hm, hm_test) + self.assertEqual('GET', hm_test.get('http_method')) + + @test.attr(type='smoke') + @test.idempotent_id('9b25196f-7476-4ed7-9542-1f22a76b79f8') + def test_create_health_monitor_missing_url_path(self): + """Test if a non_admin user + + can create a health monitor with url_path missing + """ + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + hm_test = self._show_health_monitor(hm.get('id')) + self.assertEqual(hm, hm_test) + self.assertEqual('/', hm_test.get('url_path')) + + @test.attr(type='smoke') + @test.idempotent_id('c69da922-1c46-4b9b-8b8b-2e700d506a9c') + def test_create_health_monitor_missing_expected_codes(self): + """Test if a non_admin user + + can create a health monitor with expected_codes missing + """ + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + hm_test = self._show_health_monitor(hm.get('id')) + self.assertEqual(hm, hm_test) + self.assertEqual('200', hm_test.get('expected_codes')) + + @test.attr(type='negative') + @test.idempotent_id('a00cb8e0-cd0b-44d0-85b0-5935a0297e37') + def test_create_health_monitor_invalid_tenant_id(self): + """Test create health monitor with invalid tenant_id""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + tenant_id='blah', + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('fcd93a6d-1fec-4031-9c18-611f4f3b270e') + def test_create_health_monitor_invalid_type(self): + """Test create health monitor with invalid type""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='blah', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('3c2829d9-5d51-4bcc-b83e-f28f6e6d0bc3') + def test_create_health_monitor_invalid_delay(self): + """Test create health monitor with invalid delay""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay='blah', max_retries=10, + timeout=5, pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('7155e366-72a2-47a0-9fcf-25e38a3ef7f7') + def test_create_health_monitor_invalid_max_retries(self): + """Test create health monitor with invalid max_retries""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries='blah', + timeout=5, pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('fb5d0016-5ea6-4697-8049-e80473e67880') + def test_create_health_monitor_invalid_timeout(self): + """Test create health monitor with invalid timeout""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, + timeout='blah', pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('7f3e6e95-3eac-4a46-983a-ba1fd3b0afdf') + def test_create_health_monitor_invalid_pool_id(self): + """Test create health monitor with invalid pool id""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id='blah') + + @test.attr(type='negative') + @test.idempotent_id('f5aacc27-3573-4749-9cb9-3261fcabf1e9') + def test_create_health_monitor_invalid_admin_state_up(self): + """Test if a non_admin user + + can create a health monitor with invalid admin_state_up + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), + admin_state_up='blah') + + @test.attr(type='negative') + @test.idempotent_id('0f9f2488-aefb-44c9-a08b-67b715e63091') + def test_create_health_monitor_invalid_expected_codes(self): + """Test if a non_admin user + + can create a health monitor with invalid expected_codes + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), + expected_codes='blah') + + @test.attr(type='negative') + @test.idempotent_id('0d637b7f-52ea-429f-8f97-584a5a9118aa') + @decorators.skip_because(bug="1641652") + def test_create_health_monitor_invalid_url_path(self): + """Test if a non_admin user + + can create a health monitor with invalid url_path + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), url_path='blah') + + @test.attr(type='negative') + @test.idempotent_id('7d4061c4-1fbc-43c3-81b5-2d099a120297') + @decorators.skip_because(bug="1641643") + def test_create_health_monitor_invalid_http_method(self): + """Test if a non_admin user + + can create a health monitor with invalid http_method + """ + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), http_method='blah') + + @test.attr(type='negative') + @test.idempotent_id('b655cee7-df0d-4531-bd98-a4918d2e752a') + def test_create_health_monitor_empty_type(self): + """Test create health monitor with empty type""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('d843c9f4-507e-462f-8f2b-319af23029db') + def test_create_health_monitor_empty_delay(self): + """Test create health monitor with empty delay""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay='', max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('bb9cb2b0-2684-4f4d-b344-6e7b0c58b019') + def test_create_health_monitor_empty_timeout(self): + """Test create health monitor with empty timeout""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout='', + pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('3b52441d-5e8a-4d17-b772-bd261d0c2656') + def test_create_health_monitor_empty_max_retries(self): + """Test create health monitor with empty max_retries""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries='', timeout=5, + pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('397aa201-25c1-4828-8c60-9cee5c4d89ab') + # NSX-v does reject empty pool_id + def test_create_health_monitor_empty_max_pool_id(self): + """Test create health monitor with empty pool_id""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id='') + + @test.attr(type='negative') + @test.idempotent_id('e806c916-877c-41dc-bacb-aabd9684a540') + # NSX-v does reject empty admin_state_up + def test_create_health_monitor_empty_max_admin_state_up(self): + """Test create health monitor with empty admin_state_up""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), admin_state_up='') + + @test.attr(type='negative') + @test.idempotent_id('9c8e8fe8-a3a2-481b-9ac8-eb9ecccd8330') + @decorators.skip_because(bug="1639340") + def test_create_health_monitor_empty_max_http_method(self): + """Test create health monitor with empty http_method""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), http_method='') + + @test.attr(type='negative') + @test.idempotent_id('9016c846-fc7c-4063-9f01-61fad37c435d') + @decorators.skip_because(bug="1639340") + def test_create_health_monitor_empty_max_url_path(self): + """Test create health monitor with empty url_path""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), url_path='') + + @test.attr(type='negative') + @test.idempotent_id('5df60d27-55ec-42a9-96cd-3affa611c8b1') + # NSX-v does reject empty expected_codes + def test_create_health_monitor_empty_expected_codes(self): + """Test create health monitor with empty expected_codes""" + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, timeout=5, + pool_id=self.pool.get('id'), expected_codes='') + + @test.attr(type='negative') + @test.idempotent_id('da63bd3a-89d5-40dd-b920-420263cbfd93') + def test_create_health_monitor_invalid_attribute(self): + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries='twenty one', + pool_id=self.pool.get('id')) + + @test.attr(type='negative') + @test.idempotent_id('2005ded4-7d26-4946-8d22-e05bf026bd44') + def test_create_health_monitor_extra_attribute(self): + self.assertRaises(ex.BadRequest, self._create_health_monitor, + type='HTTP', delay=3, max_retries=10, + pool_id=self.pool.get('id'), subnet_id=10) + + @test.attr(type='smoke') + @test.idempotent_id('79b4a4f9-1d2d-4df0-a11b-dd97f973dff2') + def test_update_health_monitor(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + max_retries = 1 + new_hm = self._update_health_monitor( + hm.get('id'), max_retries=max_retries) + self.assertEqual(max_retries, new_hm.get('max_retries')) + + @test.attr(type='smoke') + @test.idempotent_id('9496ba1f-e917-4972-883b-432e44f3cf19') + def test_update_health_monitor_missing_admin_state_up(self): + """Test update health monitor with missing admin state field""" + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + new_hm = self._update_health_monitor(hm.get('id')) + self.assertEqual(True, new_hm.get('admin_state_up')) + + @test.attr(type='smoke') + @test.idempotent_id('88570f22-cb68-47b4-a020-52b75af818d3') + def test_update_health_monitor_missing_delay(self): + """Test update health monitor with missing delay field""" + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + new_hm = self._update_health_monitor(hm.get('id')) + self.assertEqual(hm.get('delay'), new_hm.get('delay')) + + @test.attr(type='smoke') + @test.idempotent_id('45ace70d-28a5-405d-95cd-b2c92ccaa593') + def test_update_health_monitor_missing_timeout(self): + """Test update health monitor with missing timeout field""" + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + new_hm = self._update_health_monitor(hm.get('id')) + self.assertEqual(hm.get('timeout'), new_hm.get('timeout')) + + @test.attr(type='smoke') + @test.idempotent_id('269af536-2352-4772-bf35-268df9f4542c') + def test_update_health_monitor_missing_max_retries(self): + """Test update health monitor with missing max retries field""" + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + new_hm = self._update_health_monitor(hm.get('id')) + self.assertEqual(hm.get('max_retries'), new_hm.get('max_retries')) + + @test.attr(type='smoke') + @test.idempotent_id('318d972f-9cd1-42ef-9b8b-2f91ba785ac7') + def test_update_health_monitor_missing_http_method(self): + """Test update health monitor with missing http_method field""" + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + new_hm = self._update_health_monitor(hm.get('id')) + self.assertEqual(hm.get('http_method'), new_hm.get('http_method')) + + @test.attr(type='smoke') + @test.idempotent_id('4b97ab67-889d-480c-bedc-f06d86479bb5') + def test_update_health_monitor_missing_url_path(self): + """Test update health monitor with missing url_path field""" + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + new_hm = self._update_health_monitor(hm.get('id')) + self.assertEqual(hm.get('url_path'), new_hm.get('url_path')) + + @test.attr(type='smoke') + @test.idempotent_id('095cdb91-0937-4ae1-8b46-5edd10f00a1e') + def test_update_health_monitor_missing_expected_codes(self): + """Test update health monitor with missing expected_codes field""" + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + + new_hm = self._update_health_monitor(hm.get('id')) + self.assertEqual(hm.get('expected_codes'), + new_hm.get('expected_codes')) + + @test.attr(type='negative') + @test.idempotent_id('646d74ed-9afe-4710-a677-c36f85482731') + def test_update_health_monitor_invalid_attribute(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), max_retries='blue') + + @test.attr(type='negative') + @test.idempotent_id('9d717551-82ab-4073-a269-8b05b67d8306') + def test_update_health_monitor_invalid_admin_state_up(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), admin_state_up='blah') + + @test.attr(type='negative') + @test.idempotent_id('b865dc8a-695b-4f15-891c-e73b7402ddeb') + def test_update_health_monitor_invalid_delay(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), delay='blah') + + @test.attr(type='negative') + @test.idempotent_id('813c8bc1-7ba6-4ae5-96f3-1fdb10ae7be3') + def test_update_health_monitor_invalid_timeout(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), timeout='blah') + + @test.attr(type='negative') + @test.idempotent_id('05456473-5014-43ae-97a2-3790e4987526') + def test_update_health_monitor_invalid_max_retries(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), max_retries='blah') + + @test.attr(type='negative') + @test.idempotent_id('1e2fb718-de77-46a3-8897-6f5aff6cab5e') + @decorators.skip_because(bug="1641643") + def test_update_health_monitor_invalid_http_method(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), http_method='blah') + + @test.attr(type='negative') + @test.idempotent_id('07d62a55-18b3-4b74-acb2-b73a0b5e4364') + @decorators.skip_because(bug="1641652") + def test_update_health_monitor_invalid_url_path(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), url_path='blah') + + @test.attr(type='negative') + @test.idempotent_id('47c96e10-4863-4635-8bc6-371d460f61bc') + def test_update_health_monitor_invalid_expected_codes(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), expected_codes='blah') + + @test.attr(type='negative') + @test.idempotent_id('8594b3a3-70e8-4dfa-8928-18bc1cc7ab4a') + def test_update_health_monitor_empty_admin_state_up(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), admin_state_up='') + + @test.attr(type='negative') + @test.idempotent_id('1e1b761d-5114-4931-935d-1069d66e2bb1') + def test_update_health_monitor_empty_delay(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), empty_delay='') + + @test.attr(type='negative') + @test.idempotent_id('e6e4a6b7-50b4-465d-be02-44fd5f258bb6') + def test_update_health_monitor_empty_timeout(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), timeout='') + + @test.attr(type='negative') + @test.idempotent_id('65d05adf-a399-4457-bd83-92c43c1eca01') + def test_update_health_monitor_empty_max_retries(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), max_retries='') + + @test.attr(type='negative') + @test.idempotent_id('0c464bb3-ff84-4816-9237-4583e4da9881') + @decorators.skip_because(bug="1639340") + def test_update_health_monitor_empty_empty_http_method(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), http_method='') + + @test.attr(type='negative') + @test.idempotent_id('3e87c0a8-ef15-457c-a58f-270de8c5c76c') + @decorators.skip_because(bug="1639340") + def test_update_health_monitor_empty_url_path(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), url_path='') + + @test.attr(type='negative') + @test.idempotent_id('d45189e6-db9f-44d1-b5ad-8b7691e781ee') + def test_update_health_monitor_empty_expected_codes(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), expected_codes='') + + @test.attr(type=['smoke', 'negative']) + @test.idempotent_id('cf70e44e-8060-494a-b577-d656726ba3d8') + def test_update_health_monitor_extra_attribute(self): + hm = self._create_health_monitor(type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self.assertRaises(ex.BadRequest, + self._update_health_monitor, + hm.get('id'), protocol='UDP') + + @test.attr(type=['smoke', 'negative']) + @test.idempotent_id('fe44e0d9-957b-44cf-806b-af7819444864') + @decorators.skip_because(bug="1639340") + def test_delete_health_monitor(self): + hm = self._create_health_monitor(cleanup=False, type='HTTP', delay=3, + max_retries=10, timeout=5, + pool_id=self.pool.get('id')) + self._delete_health_monitor(hm.get('id')) + self.assertRaises(ex.NotFound, + self._show_health_monitor, + hm.get('id')) diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_listeners_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_listeners_admin.py new file mode 100644 index 0000000..4b7ba52 --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_listeners_admin.py @@ -0,0 +1,109 @@ +# 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 oslo_log import log as logging + +from tempest import config +from tempest.lib import decorators +from tempest.lib import exceptions as ex +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + +CONF = config.CONF + +LOG = logging.getLogger(__name__) + + +class ListenersTest(base.BaseAdminTestCase): + + """Tests the listener creation operation in admin scope + + in the Neutron-LBaaS API using the REST client for Listeners: + + """ + + @classmethod + def resource_setup(cls): + super(ListenersTest, cls).resource_setup() + cls.create_lb_kwargs = {'tenant_id': cls.subnet['tenant_id'], + 'vip_subnet_id': cls.subnet['id']} + cls.load_balancer = cls._create_active_load_balancer( + **cls.create_lb_kwargs) + cls.protocol = 'HTTP' + cls.port = 80 + cls.load_balancer_id = cls.load_balancer['id'] + cls.create_listener_kwargs = {'loadbalancer_id': cls.load_balancer_id, + 'protocol': cls.protocol, + 'protocol_port': cls.port} + cls.listener = cls._create_listener( + **cls.create_listener_kwargs) + cls.listener_id = cls.listener['id'] + + @classmethod + def resource_cleanup(cls): + super(ListenersTest, cls).resource_cleanup() + + @test.attr(type='negative') + @decorators.skip_because(bug="1638738") + @test.idempotent_id('f84bfb35-7f73-4576-b2ca-26193850d2bf') + def test_create_listener_empty_tenant_id(self): + """Test create listener with an empty tenant id should fail""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8081 + create_new_listener_kwargs['tenant_id'] = "" + self.assertRaises(ex.BadRequest, + self._create_listener, + **create_new_listener_kwargs) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('71ebb8d6-ff2a-410d-a089-b086f195609d') + def test_create_listener_invalid_tenant_id(self): + """Test create listener with an invalid tenant id""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8082 + create_new_listener_kwargs['tenant_id'] = "&^%123" + new_listener = self._create_listener( + **create_new_listener_kwargs) + new_listener_id = new_listener['id'] + self.addCleanup(self._delete_listener, new_listener_id) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, new_listener_id]) + listener = self._show_listener(new_listener_id) + self.assertEqual(new_listener, listener) + + @test.attr(type='smoke') + @test.idempotent_id('55eaeab9-a21e-470c-8861-5af1ded9d64a') + def test_create_listener_missing_tenant_id(self): + """Test create listener with an missing tenant id. + + Verify that creating a listener in admin scope with + a missing tenant_id creates the listener with admin + tenant_id. + """ + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8083 + admin_listener = self._create_listener( + **create_new_listener_kwargs) + admin_listener_id = admin_listener['id'] + self.addCleanup(self._delete_listener, admin_listener_id) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, admin_listener_id]) + listener = self._show_listener(admin_listener_id) + self.assertEqual(admin_listener, listener) + self.assertEqual(admin_listener.get('tenant_id'), + listener.get('tenant_id')) diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_listeners_non_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_listeners_non_admin.py new file mode 100644 index 0000000..599bda0 --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_listeners_non_admin.py @@ -0,0 +1,594 @@ +# 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 oslo_log import log as logging + +from tempest import config +from tempest.lib import decorators +from tempest.lib import exceptions +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + +CONF = config.CONF + +LOG = logging.getLogger(__name__) + + +class ListenersTest(base.BaseTestCase): + + """Tests the following operations in the Neutron-LBaaS API + + using the REST client for Listeners: + + list listeners + create listener + get listener + update listener + delete listener + """ + + @classmethod + def resource_setup(cls): + super(ListenersTest, cls).resource_setup() + cls.create_lb_kwargs = {'tenant_id': cls.subnet['tenant_id'], + 'vip_subnet_id': cls.subnet['id']} + cls.load_balancer = cls._create_active_load_balancer( + **cls.create_lb_kwargs) + cls.protocol = 'HTTP' + cls.port = 80 + cls.load_balancer_id = cls.load_balancer['id'] + cls.create_listener_kwargs = {'loadbalancer_id': cls.load_balancer_id, + 'protocol': cls.protocol, + 'protocol_port': cls.port} + cls.listener = cls._create_listener(**cls.create_listener_kwargs) + cls.listener_id = cls.listener['id'] + + @test.attr(type='smoke') + @test.idempotent_id('32ae6156-d809-49fc-a45b-55269660651c') + def test_get_listener(self): + """Test get listener""" + listener = self._show_listener(self.listener_id) + self.assertEqual(self.listener, listener) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('4013ab83-924a-4c53-982e-83388d7ad4d9') + def test_list_listeners(self): + """Test get listeners with one listener""" + listeners = self._list_listeners() + self.assertEqual(len(listeners), 1) + self.assertIn(self.listener, listeners) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('04f58729-3f93-4616-bb9d-8baaff3542b2') + def test_list_listeners_two(self): + """Test get listeners with two listeners""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8080 + new_listener = self._create_listener( + **create_new_listener_kwargs) + new_listener_id = new_listener['id'] + self.addCleanup(self._delete_listener, new_listener_id) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, new_listener_id]) + listeners = self._list_listeners() + self.assertEqual(len(listeners), 2) + self.assertIn(self.listener, listeners) + self.assertIn(new_listener, listeners) + self.assertNotEqual(self.listener, new_listener) + + @test.attr(type='smoke') + @test.idempotent_id('7989096b-95c2-4b26-86b1-5aec0a2d8386') + def test_create_listener(self): + """Test create listener""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8081 + new_listener = self._create_listener( + **create_new_listener_kwargs) + new_listener_id = new_listener['id'] + self.addCleanup(self._delete_listener, new_listener_id) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, new_listener_id]) + listener = self._show_listener(new_listener_id) + self.assertEqual(new_listener, listener) + self.assertNotEqual(self.listener, new_listener) + + @test.attr(type='negative') + @test.idempotent_id('f7ef7f56-b791-48e8-9bbe-838a3ed94519') + def test_create_listener_missing_field_loadbalancer(self): + """Test create listener with a missing required field loadbalancer""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + protocol_port=self.port, + protocol=self.protocol) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('c392301c-3d9a-4123-85c3-124e4e3253f6') + def test_create_listener_missing_field_protocol(self): + """Test create listener with a missing required field protocol""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('12c1c5b5-81a9-4384-811e-7131f65f3b1b') + def test_create_listener_missing_field_protocol_port(self): + """Test create listener with a missing required field protocol_port""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol=self.protocol) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('214a7acc-eacb-4828-ad27-b7f4774947cf') + def test_create_listener_missing_admin_state_up(self): + """Test create listener with a missing admin_state_up field""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8083 + new_listener = self._create_listener( + **create_new_listener_kwargs) + new_listener_id = new_listener['id'] + self.addCleanup(self._delete_listener, new_listener_id) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, new_listener_id]) + listener = self._show_listener(new_listener_id) + self.assertEqual(new_listener, listener) + self.assertTrue(new_listener['admin_state_up']) + + @test.attr(type='negative') + @test.idempotent_id('86d892dd-9025-4051-a160-8bf1bbb8c64d') + def test_create_listener_invalid_load_balancer_id(self): + """Test create listener with an invalid load_balancer_id""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id="234*", + protocol_port=self.port, + protocol=self.protocol) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('fb430d68-e68d-4bd0-b43d-f1175ad5a819') + def test_create_listener_invalid_protocol(self): + """Test create listener with an invalid protocol""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol="UDP") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('8e472e7e-a5c2-4dba-ac5c-993f6e6bb229') + def test_create_listener_invalid_protocol_port(self): + """Test create listener with an invalid protocol_port""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port="9999999", + protocol=self.protocol) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('57fc90f4-95e4-4f3c-8f53-32c7282b956e') + def test_create_listener_invalid_admin_state_up(self): + """Test update listener with an invalid admin_state_up""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + protocol_port=self.port, + protocol=self.protocol, + admin_state_up="abc123") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('556e1ab9-051c-4e9c-aaaa-f11d15de070b') + def test_create_listener_invalid_tenant_id(self): + """Test create listener with an invalid tenant id""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol=self.protocol, + tenant_id="&^%123") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('59d32fd7-06f6-4466-bdd4-0be23b15970c') + def test_create_listener_invalid_name(self): + """Test create listener with an invalid name""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol=self.protocol, + name='a' * 256) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('95457f70-2c1a-4c14-aa80-db8e803d78a9') + def test_create_listener_invalid_description(self): + """Test create listener with an invalid description""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol=self.protocol, + description='a' * 256) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('177d337f-fe0c-406c-92f1-a25c0103bd0f') + def test_create_listener_invalid_connection_limit(self): + """Test create listener_ids + + with an invalid value for connection _limit field + """ + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol=self.protocol, + connection_limit="&^%123") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('8af7b033-8ff7-4bdb-8949-76809745d8a9') + def test_create_listener_empty_load_balancer_id(self): + """Test create listener with an empty load_balancer_id""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id="", + protocol_port=self.port, + protocol=self.protocol) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('242af61b-ce50-46e2-926a-6801600dcee4') + def test_create_listener_empty_protocol(self): + """Test create listener with an empty protocol""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('4866af4c-2b91-4bce-af58-af77f19d9119') + def test_create_listener_empty_protocol_port(self): + """Test create listener with an empty protocol_port""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port="", + protocol=self.protocol) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('09636ad1-a9d5-4c03-92db-ae5d9847993d') + def test_create_listener_empty_admin_state_up(self): + """Test update listener with an empty admin_state_up""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + protocol_port=self.port, + protocol=self.protocol, + admin_state_up="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @decorators.skip_because(bug="1638701") + @test.idempotent_id('46fc3784-d676-42f7-953b-a23c1d62323d') + def test_create_listener_empty_tenant_id(self): + """Test create listener with an empty tenant id""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol=self.protocol, + tenant_id="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('b4120626-a47e-4b4e-9b64-017e595c4daf') + def test_create_listener_empty_name(self): + """Test create listener with an empty name""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8081 + create_new_listener_kwargs['name'] = "" + new_listener = self._create_listener( + **create_new_listener_kwargs) + new_listener_id = new_listener['id'] + self.addCleanup(self._delete_listener, new_listener_id) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, new_listener_id]) + listener = self._show_listener(new_listener_id) + self.assertEqual(new_listener, listener) + + @test.attr(type='smoke') + @test.idempotent_id('af067d00-d496-4f02-87d6-40624c34d492') + def test_create_listener_empty_description(self): + """Test create listener with an empty description""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8082 + create_new_listener_kwargs['description'] = "" + new_listener = self._create_listener( + **create_new_listener_kwargs) + new_listener_id = new_listener['id'] + self.addCleanup(self._delete_listener, new_listener_id) + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, new_listener_id]) + listener = self._show_listener(new_listener_id) + self.assertEqual(new_listener, listener) + + @test.attr(type='negative') + @test.idempotent_id('dd271757-c447-4579-a417-f9d0871b145c') + def test_create_listener_empty_connection_limit(self): + """Test create listener with an empty connection _limit field""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + loadbalancer_id=self.load_balancer_id, + protocol_port=self.port, + protocol=self.protocol, + connection_limit="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('a1602217-e1b4-4f85-8a5e-d474477333f3') + def test_create_listener_incorrect_attribute(self): + """Test create a listener withan extra, incorrect field""" + self.assertRaises(exceptions.BadRequest, + self._create_listener, + incorrect_attribute="incorrect_attribute", + **self.create_listener_kwargs) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('27c443ff-3aee-4ae6-8b9a-6abf3d5443bf') + def test_update_listener(self): + """Test update listener""" + self._update_listener(self.listener_id, + name='new_name') + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + listener = self._show_listener(self.listener_id) + self.assertEqual(listener.get('name'), 'new_name') + + @test.attr(type='negative') + @test.idempotent_id('a709e4da-01ef-4dda-a336-f5e37268b5ea') + def test_update_listener_invalid_tenant_id(self): + """Test update listener with an invalid tenant id""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + tenant_id="&^%123") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('d88dd3d5-a52f-4306-ba53-e8f6f4e1b399') + def test_update_listener_invalid_admin_state_up(self): + """Test update a listener with an invalid admin_state_up""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + admin_state_up="$23") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('7c0efb63-90d9-43d0-b959-eb841ef39832') + def test_update_listener_invalid_name(self): + """Test update a listener with an invalid name""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + name='a' * 256) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('ba9bfad8-dbb0-4cbc-b2e3-52bf72bc1fc5') + def test_update_listener_invalid_description(self): + """Test update a listener with an invalid description""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + description='a' * 256) + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('dcafa50b-cece-4904-bcc9-a0dd1ac99a7e') + def test_update_listener_invalid_connection_limit(self): + """Test update a listener with an invalid connection_limit""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + connection_limit="$23") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('27e009c5-3c79-414d-863d-24b731f03123') + def test_update_listener_incorrect_attribute(self): + """Test update a listener with an extra, incorrect field""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + name="listener_name123", + description="listener_description123", + admin_state_up=True, + connection_limit=10, + vip_subnet_id="123321123") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('e8bdd948-7bea-494b-8a4a-e730b70f2882') + def test_update_listener_missing_name(self): + """Test update listener with a missing name""" + old_listener = self._show_listener(self.listener_id) + old_name = old_listener['name'] + self._update_listener(self.listener_id, + description='updated') + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + listener = self._show_listener(self.listener_id) + self.assertEqual(listener.get('name'), old_name) + + @test.attr(type='smoke') + @test.idempotent_id('7e0194b8-9315-452d-9de5-d48f227b626f') + def test_update_listener_missing_description(self): + """Test update listener with a missing description""" + old_listener = self._show_listener(self.listener_id) + old_description = old_listener['description'] + self._update_listener(self.listener_id, + name='updated_name') + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + listener = self._show_listener(self.listener_id) + self.assertEqual(listener.get('description'), old_description) + + @test.attr(type='smoke') + @test.idempotent_id('285dd3f2-fcb8-4ccb-b9ce-d6207b29a2f8') + def test_update_listener_missing_admin_state_up(self): + """Test update listener with a missing admin_state_up""" + old_listener = self._show_listener(self.listener_id) + old_admin_state_up = old_listener['admin_state_up'] + self._update_listener(self.listener_id, + name='updated_name') + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + listener = self._show_listener(self.listener_id) + self.assertEqual(listener.get('admin_state_up'), old_admin_state_up) + + @test.attr(type='smoke') + @test.idempotent_id('5c510338-0f8a-4d1e-805b-f8458f2e80ee') + def test_update_listener_missing_connection_limit(self): + """Test update listener with a missing connection_limit""" + old_listener = self._show_listener(self.listener_id) + old_connection_limit = old_listener['connection_limit'] + self._update_listener(self.listener_id, + name='updated_name') + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + listener = self._show_listener(self.listener_id) + self.assertEqual(listener.get('connection_limit'), + old_connection_limit) + + @test.attr(type='negative') + @test.idempotent_id('677205d9-9d97-4232-a8e3-d17ebf42ff05') + def test_update_listener_empty_tenant_id(self): + """Test update listener with an empty tenant id""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + tenant_id="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='negative') + @test.idempotent_id('6e9f8fdb-48b0-4c4e-9b29-460576b125ff') + def test_update_listener_empty_admin_state_up(self): + """Test update a listener with an empty admin_state_up""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + admin_state_up="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('cf619b8d-1916-4144-85c7-e5a34e0d7a2b') + def test_update_listener_empty_name(self): + """Test update a listener with an empty name""" + self._update_listener(self.listener_id, + name="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + listener = self._show_listener(self.listener_id) + self.assertEqual(listener.get('name'), "") + + @test.attr(type='smoke') + @test.idempotent_id('a9b6f721-c3c1-4d22-a3e5-7e89b58fa3a7') + def test_update_listener_empty_description(self): + """Test update a listener with an empty description""" + self._update_listener(self.listener_id, + description="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + listener = self._show_listener(self.listener_id) + self.assertEqual(listener.get('description'), "") + + @test.attr(type='negative') + @test.idempotent_id('7ddcf46b-068b-449c-9dde-ea4021dd76bf') + def test_update_listener_empty_connection_limit(self): + """Test update a listener with an empty connection_limit""" + self.assertRaises(exceptions.BadRequest, + self._update_listener, + listener_id=self.listener_id, + connection_limit="") + self._check_status_tree(load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id]) + + @test.attr(type='smoke') + @test.idempotent_id('c891c857-fa89-4775-92d8-5320321b86cd') + def test_delete_listener(self): + """Test delete listener""" + create_new_listener_kwargs = self.create_listener_kwargs + create_new_listener_kwargs['protocol_port'] = 8083 + new_listener = self._create_listener(**create_new_listener_kwargs) + new_listener_id = new_listener['id'] + self._check_status_tree( + load_balancer_id=self.load_balancer_id, + listener_ids=[self.listener_id, new_listener_id]) + listener = self._show_listener(new_listener_id) + self.assertEqual(new_listener, listener) + self.assertNotEqual(self.listener, new_listener) + self._delete_listener(new_listener_id) + self.assertRaises(exceptions.NotFound, + self._show_listener, + new_listener_id) diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_load_balancers_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_load_balancers_admin.py new file mode 100644 index 0000000..102e61b --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_load_balancers_admin.py @@ -0,0 +1,107 @@ +# 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 oslo_log import log as logging + +from tempest import config +from tempest.lib import decorators +from tempest.lib import exceptions as ex +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + +CONF = config.CONF + +LOG = logging.getLogger(__name__) + + +class LoadBalancersTest(base.BaseAdminTestCase): + + """Tests the following operations in the Neutron-LBaaS API + + using the REST client for Load Balancers with default credentials: + + list load balancers + create load balancer + get load balancer + update load balancer + delete load balancer + """ + + @classmethod + def resource_setup(cls): + super(LoadBalancersTest, cls).resource_setup() + cls.create_lb_kwargs = {'tenant_id': cls.subnet['tenant_id'], + 'vip_subnet_id': cls.subnet['id']} + cls.load_balancer = \ + cls._create_active_load_balancer(**cls.create_lb_kwargs) + cls.load_balancer_id = cls.load_balancer['id'] + + @test.attr(type='smoke') + @decorators.skip_because(bug="1641902") + @test.idempotent_id('0008ae1e-77a2-45d9-b81e-0e3119b5a26d') + def test_create_load_balancer_missing_tenant_id_field_for_admin(self): + """Test create load balancer with a missing tenant id field. + + Verify tenant_id matches when creating loadbalancer vs. + load balancer(admin tenant) + """ + load_balancer = self._create_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + admin_lb = self._show_load_balancer( + load_balancer.get('id')) + self.assertEqual(load_balancer.get('tenant_id'), + admin_lb.get('tenant_id')) + self._wait_for_load_balancer_status(load_balancer['id']) + + @test.attr(type='smoke') + @decorators.skip_because(bug="1638571") + @test.idempotent_id('37620941-47c1-40b2-84d8-db17ff823ebc') + def test_create_load_balancer_missing_tenant_id_for_other_tenant(self): + """Test create load balancer with a missing tenant id field. + + Verify tenant_id does not match of subnet(non-admin tenant) vs. + load balancer(admin tenant) + """ + load_balancer = self._create_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertNotEqual(load_balancer.get('tenant_id'), + self.subnet['tenant_id']) + self._wait_for_load_balancer_status(load_balancer['id']) + + @test.attr(type='negative') + @decorators.skip_because(bug="1638148") + # Empty tenant_id causing ServerFault + @test.idempotent_id('5bf483f5-ae28-47f5-8805-642da0ffcb40') + def test_create_load_balancer_empty_tenant_id_field(self): + """Test create load balancer with empty tenant_id field should fail""" + self.assertRaises(ex.BadRequest, + self._create_load_balancer, + vip_subnet_id=self.subnet['id'], + wait=False, + tenant_id="") + + @test.attr(type='smoke') + @decorators.skip_because(bug="1638571") + @test.idempotent_id('19fc8a44-1280-49f3-be5b-0d30e6e43363') + # 2nd tenant_id at the same subnet not supported; got serverFault + def test_create_load_balancer_for_another_tenant(self): + """Test create load balancer for other tenant""" + tenant = 'deffb4d7c0584e89a8ec99551565713c' + load_balancer = self._create_load_balancer( + vip_subnet_id=self.subnet['id'], + tenant_id=tenant) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertEqual(load_balancer.get('tenant_id'), tenant) + self._wait_for_load_balancer_status(load_balancer['id']) diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_load_balancers_non_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_load_balancers_non_admin.py new file mode 100644 index 0000000..11e2b7d --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_load_balancers_non_admin.py @@ -0,0 +1,487 @@ +# 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 netaddr + +from oslo_log import log as logging + +from tempest import config +from tempest.lib import decorators +from tempest.lib import exceptions +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + +CONF = config.CONF + +LOG = logging.getLogger(__name__) + + +class LoadBalancersTest(base.BaseTestCase): + + """Tests the following operations in the Neutron-LBaaS API + + using the REST client for Load Balancers with default credentials: + + list load balancers + create load balancer + get load balancer + update load balancer + delete load balancer + """ + + @classmethod + def resource_setup(cls): + super(LoadBalancersTest, cls).resource_setup() + cls.create_lb_kwargs = {'tenant_id': cls.subnet['tenant_id'], + 'vip_subnet_id': cls.subnet['id']} + cls.load_balancer = \ + cls._create_active_load_balancer(**cls.create_lb_kwargs) + cls.load_balancer_id = cls.load_balancer['id'] + + @test.attr(type='smoke') + @test.idempotent_id('b7ea6c09-e077-4a67-859b-b2cd01e3b46b') + def test_list_load_balancers(self): + """Test list load balancers with one load balancer""" + load_balancers = self._list_load_balancers() + self.assertEqual(len(load_balancers), 1) + self.assertIn(self.load_balancer, load_balancers) + + @test.attr(type='smoke') + @test.idempotent_id('8c2302df-ca94-4950-9826-eb996630a392') + def test_list_load_balancers_two(self): + """Test list load balancers with two load balancers""" + new_load_balancer = self._create_active_load_balancer( + **self.create_lb_kwargs) + new_load_balancer_id = new_load_balancer['id'] + self.addCleanup(self._delete_load_balancer, new_load_balancer_id) + load_balancers = self._list_load_balancers() + self.assertEqual(len(load_balancers), 2) + self.assertIn(self.load_balancer, load_balancers) + self.assertIn(new_load_balancer, load_balancers) + self.assertNotEqual(self.load_balancer, new_load_balancer) + + @test.attr(type='smoke') + @test.idempotent_id('56345a78-1d53-4c05-9d7b-3e5cf34c22aa') + def test_get_load_balancer(self): + """Test get load balancer""" + load_balancer = self._show_load_balancer( + self.load_balancer_id) + self.assertEqual(self.load_balancer, load_balancer) + + @test.attr(type='smoke') + @test.idempotent_id('5bf80330-d908-4025-9467-bca1727525c8') + def test_create_load_balancer(self): + """Test create load balancer""" + new_load_balancer = self._create_active_load_balancer( + **self.create_lb_kwargs) + new_load_balancer_id = new_load_balancer['id'] + self.addCleanup(self._delete_load_balancer, new_load_balancer_id) + load_balancer = self._show_load_balancer( + new_load_balancer_id) + self.assertEqual(new_load_balancer, load_balancer) + self.assertNotEqual(self.load_balancer, new_load_balancer) + + @test.attr(type='negative') + @test.idempotent_id('66bf5390-154f-4627-af61-2c1c30325d6f') + def test_create_load_balancer_missing_vip_subnet_id_field(self): + """Test create load balancer + + with a missing required vip_subnet_id field + """ + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + tenant_id=self.subnet['tenant_id']) + + @test.attr(type='negative') + @test.idempotent_id('8e78a7e6-2da3-4f79-9f66-fd1447277883') + def test_create_load_balancer_empty_provider_field(self): + """Test create load balancer with an empty provider field""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + provider="") + + @test.attr(type='smoke') + @test.idempotent_id('def37122-3f9a-47f5-b7b5-b5c0d5e7e5ca') + def test_create_load_balancer_empty_description_field(self): + """Test create load balancer with an empty description field""" + load_balancer = self._create_active_load_balancer( + vip_subnet_id=self.subnet['id'], description="") + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertEqual(load_balancer.get('description'), "") + + @test.attr(type='negative') + @test.idempotent_id('69944c74-3ea1-4c06-8d28-82120721a13e') + def test_create_load_balancer_empty_vip_address_field(self): + """Test create load balancer with empty vip_address field""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + vip_subnet_id=self.subnet['id'], + vip_address="") + + @test.attr(type='smoke') + @test.idempotent_id('63bbe788-f3a6-444f-89b3-8c740425fc39') + def test_create_load_balancer_missing_admin_state_up(self): + """Test create load balancer with a missing admin_state_up field""" + load_balancer = self._create_active_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertEqual(load_balancer.get('admin_state_up'), True) + + @test.attr(type='negative') + @test.idempotent_id('499f164a-e926-47a6-808a-14f3c29d04c9') + def test_create_load_balancer_empty_admin_state_up_field(self): + """Test create load balancer with empty admin_state_up field""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + vip_subnet_id=self.subnet['id'], + admin_state_up="") + + @test.attr(type='smoke') + @test.idempotent_id('e4511356-0e78-457c-a310-8515b2dedad4') + def test_create_load_balancer_missing_name(self): + """Test create load balancer with a missing name field""" + load_balancer = self._create_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertEqual(load_balancer.get('name'), '') + self._wait_for_load_balancer_status(load_balancer['id']) + + @test.attr(type='smoke') + @test.idempotent_id('6bd4a92c-7498-4b92-aeae-bce0b74608e3') + def test_create_load_balancer_empty_name(self): + """Test create load balancer with an empty name field""" + load_balancer = self._create_load_balancer( + vip_subnet_id=self.subnet['id'], name="") + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertEqual(load_balancer.get('name'), "") + self._wait_for_load_balancer_status(load_balancer['id']) + + @test.attr(type='smoke') + @test.idempotent_id('e605b1ea-5179-4035-8100-c24d0164a5a5') + def test_create_load_balancer_missing_description(self): + """Test create load balancer with a missing description field""" + load_balancer = self._create_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertEqual(load_balancer.get('description'), '') + self._wait_for_load_balancer_status(load_balancer['id']) + + @test.attr(type='smoke') + @test.idempotent_id('9f718024-340b-405f-817f-311392353c32') + def test_create_load_balancer_missing_vip_address(self): + """Test create load balancer + + with a missing vip_address field,checks for + ipversion and actual ip address + """ + load_balancer = self._create_active_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + load_balancer_ip_initial = load_balancer['vip_address'] + ip = netaddr.IPAddress(load_balancer_ip_initial) + self.assertEqual(ip.version, 4) + load_balancer = self._show_load_balancer( + load_balancer['id']) + load_balancer_final = load_balancer['vip_address'] + self.assertEqual(load_balancer_ip_initial, load_balancer_final) + + @test.attr(type='smoke') + @test.idempotent_id('f599ccbd-73e8-4e27-96a5-d9e0e3419a9f') + def test_create_load_balancer_missing_provider_field(self): + """Test create load balancer with a missing provider field""" + load_balancer = self._create_active_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + load_balancer_initial = load_balancer['provider'] + load_balancer = self._show_load_balancer( + load_balancer['id']) + load_balancer_final = load_balancer['provider'] + self.assertEqual(load_balancer_initial, load_balancer_final) + + @test.attr(type='negative') + @test.idempotent_id('377166eb-f581-4383-bc2e-54fdeed73e42') + def test_create_load_balancer_invalid_vip_subnet_id(self): + """Test create load balancer with an invalid vip subnet id""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + vip_subnet_id="abc123") + + @test.attr(type='negative') + @test.idempotent_id('512bec06-5259-4e93-b482-7ec3346c794a') + def test_create_load_balancer_empty_vip_subnet_id(self): + """Test create load balancer with an empty vip subnet id""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + vip_subnet_id="") + + @test.attr(type='negative') + @test.idempotent_id('02bd6d0e-820e-46fb-89cb-1d335e7aaa02') + def test_create_load_balancer_invalid_tenant_id(self): + """Test create load balancer with an invalid tenant id""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + tenant_id="&^%123") + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('b8c56e4a-9644-4119-8fc9-130841caf662') + def test_create_load_balancer_invalid_name(self): + """Test create load balancer with an invalid name""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + tenant_id=self.subnet['tenant_id'], + vip_subnet_id=self.subnet['id'], + name='n' * 256) + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('d638ae60-7de5-45da-a7d9-53eca4998980') + def test_create_load_balancer_invalid_description(self): + """Test create load balancer with an invalid description""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + tenant_id=self.subnet['tenant_id'], + vip_subnet_id=self.subnet['id'], + description='d' * 256) + + @test.attr(type='negative') + @test.idempotent_id('56768aa6-b26e-48aa-8118-956c62930d79') + def test_create_load_balancer_incorrect_attribute(self): + """Test create a load balancer with an extra, incorrect field""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + tenant_id=self.subnet['tenant_id'], + vip_subnet_id=self.subnet['id'], + protocol_port=80) + + @test.attr(type='smoke') + @test.idempotent_id('a130e70f-9d76-4bff-89de-3e564952b244') + def test_create_load_balancer_missing_tenant_id_field(self): + """Test create load balancer with a missing tenant id field""" + load_balancer = self._create_load_balancer( + vip_subnet_id=self.subnet['id']) + self.addCleanup(self._delete_load_balancer, load_balancer['id']) + self.assertEqual(load_balancer.get('tenant_id'), + self.subnet['tenant_id']) + self._wait_for_load_balancer_status(load_balancer['id']) + + @test.attr(type='negative') + @test.idempotent_id('25261cca-0c38-4dc8-bb40-f7692035740f') + def test_create_load_balancer_empty_tenant_id_field(self): + """Test create load balancer with empty tenant_id field""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + vip_subnet_id=self.subnet['id'], + wait=False, + tenant_id="") + + @test.attr(type='negative') + @test.idempotent_id('10de328d-c754-484b-841f-313307f92935') + def test_create_load_balancer_other_tenant_id_field(self): + """Test create load balancer for other tenant""" + tenant = 'deffb4d7c0584e89a8ec99551565713c' + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + wait=False, + vip_subnet_id=self.subnet['id'], + tenant_id=tenant) + + @test.attr(type='negative') + @test.idempotent_id('9963cbf5-97d0-4ab9-96e5-6cbd65c98714') + # TODO(akang): upstream is exceptions.NotFound + def test_create_load_balancer_invalid_flavor_field(self): + """Test create load balancer with an invalid flavor field""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + vip_subnet_id=self.subnet['id'], + flavor_id="NO_SUCH_FLAVOR") + + @test.attr(type='negative') + @test.idempotent_id('f7319e32-0fad-450e-8f53-7567f56e8223') + # TODO(akang): upstream is exceptions.Conflict + def test_create_load_balancer_provider_flavor_conflict(self): + """Test create load balancer with both a provider and a flavor""" + self.assertRaises(exceptions.BadRequest, + self._create_load_balancer, + vip_subnet_id=self.subnet['id'], + flavor_id="NO_SUCH_FLAVOR", + provider="NO_SUCH_PROVIDER") + + @test.attr(type='smoke') + @test.idempotent_id('1d92d98f-550f-4f05-a246-cdf4525459a2') + def test_update_load_balancer(self): + """Test update load balancer""" + self._update_load_balancer(self.load_balancer_id, + name='new_name') + load_balancer = self._show_load_balancer( + self.load_balancer_id) + self.assertEqual(load_balancer.get('name'), 'new_name') + + @test.attr(type='smoke') + @test.idempotent_id('474ca200-8dea-4d20-8468-abc0169a445b') + def test_update_load_balancer_empty_name(self): + """Test update load balancer with empty name""" + self._update_load_balancer(self.load_balancer_id, + name="") + load_balancer = self._show_load_balancer( + self.load_balancer_id) + self.assertEqual(load_balancer.get('name'), "") + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('551be885-215d-4941-8870-651cbc871162') + def test_update_load_balancer_invalid_name(self): + """Test update load balancer with invalid name""" + self.assertRaises(exceptions.BadRequest, + self._update_load_balancer, + load_balancer_id=self.load_balancer_id, + wait=False, + name='a' * 256) + + @test.attr(type='smoke') + @test.idempotent_id('62eef0ba-3859-4c8f-9e6a-8d6918754597') + def test_update_load_balancer_missing_name(self): + """Test update load balancer with missing name""" + loadbalancer = self._show_load_balancer( + self.load_balancer_id) + load_balancer_initial = loadbalancer['name'] + self._update_load_balancer(self.load_balancer_id) + load_balancer = self._show_load_balancer( + self.load_balancer_id) + load_balancer_new = load_balancer['name'] + self.assertEqual(load_balancer_initial, load_balancer_new) + + @test.attr(type='negative') + @decorators.skip_because(bug="1637877") + @test.idempotent_id('ab3550c6-8b21-463c-bc5d-e79cbae3432f') + def test_update_load_balancer_invalid_description(self): + """Test update load balancer with invalid description""" + self.assertRaises(exceptions.BadRequest, + self._update_load_balancer, + load_balancer_id=self.load_balancer_id, + wait=False, + description='a' * 256) + + @test.attr(type='smoke') + @test.idempotent_id('157ebdbf-4ad2-495d-b880-c1b1a8edc46d') + def test_update_load_balancer_empty_description(self): + """Test update load balancer with empty description""" + self._update_load_balancer(self.load_balancer_id, + description="") + load_balancer = self._show_load_balancer( + self.load_balancer_id) + self.assertEqual(load_balancer.get('description'), "") + + @test.attr(type='smoke') + @test.idempotent_id('d13fa2f5-e8df-4d53-86a8-68583941200c') + def test_update_load_balancer_missing_description(self): + """Test update load balancer with missing description""" + loadbalancer = self._show_load_balancer( + self.load_balancer_id) + load_balancer_initial = loadbalancer['description'] + self._update_load_balancer(self.load_balancer_id) + load_balancer = self._show_load_balancer( + self.load_balancer_id) + load_balancer_new = load_balancer['description'] + self.assertEqual(load_balancer_initial, load_balancer_new) + + @test.attr(type='negative') + @test.idempotent_id('96e46a1a-62e7-47f1-98c5-9983f89e622f') + def test_update_load_balancer_invalid_admin_state_up_field(self): + """Test update load balancer with an invalid admin_state_up""" + self.assertRaises(exceptions.BadRequest, + self._update_load_balancer, + load_balancer_id=self.load_balancer_id, + wait=False, + admin_state_up="a&^%$jbc123") + + @test.attr(type='negative') + @test.idempotent_id('48f1e227-8b15-4389-a050-7ce76f4b4d46') + def test_update_load_balancer_empty_admin_state_up_field(self): + """Test update load balancer with an empty admin_state_up""" + self.assertRaises(exceptions.BadRequest, + self._update_load_balancer, + load_balancer_id=self.load_balancer_id, + wait=False, + admin_state_up="") + + @test.attr(type='smoke') + @test.idempotent_id('a9182e53-ddaa-4f41-af54-585d983279ba') + def test_update_load_balancer_missing_admin_state_up(self): + """Test update load balancer with missing admin state field""" + loadbalancer = self._show_load_balancer( + self.load_balancer_id) + load_balancer_initial = loadbalancer['admin_state_up'] + self._update_load_balancer(self.load_balancer_id) + self.assertEqual(load_balancer_initial, True) + + @test.attr(type='negative') + @test.idempotent_id('bfbe9339-d083-4a88-b6d6-015522809c3a') + def test_update_load_balancer_incorrect_attribute(self): + """Test update a load balancer with an extra, invalid attribute""" + self.assertRaises(exceptions.BadRequest, + self._update_load_balancer, + load_balancer_id=self.load_balancer_id, + wait=False, + name="lb_name", + description="lb_name_description", + admin_state_up=True, + port=80) + + @test.attr(type='smoke') + @test.idempotent_id('d2258984-6e9a-41d6-bffa-0543c8b1f2b0') + def test_get_load_balancer_status_tree(self): + """Test get load balancer status tree""" + statuses = self._show_load_balancer_status_tree( + self.load_balancer_id) + load_balancer = statuses['loadbalancer'] + self.assertEqual("ONLINE", load_balancer['operating_status']) + self.assertEqual("ACTIVE", load_balancer['provisioning_status']) + self.assertEqual([], load_balancer['listeners']) + + @test.attr(type='smoke') + @test.idempotent_id('a23677a9-b770-4894-8be9-cd66590c228b') + def test_get_load_balancer_stats(self): + """Test get load balancer stats""" + stats = self._show_load_balancer_stats( + self.load_balancer_id) + self.assertEqual(0, stats['bytes_in']) + self.assertEqual(0, stats['bytes_out']) + self.assertEqual(0, stats['total_connections']) + self.assertEqual(0, stats['active_connections']) + + @test.attr(type='smoke') + @test.idempotent_id('f289f8df-a867-45cd-bee3-7ff08f5e96e0') + def test_delete_load_balancer(self): + """Test delete load balancer""" + new_load_balancer = self._create_active_load_balancer( + **self.create_lb_kwargs) + new_load_balancer_id = new_load_balancer['id'] + load_balancer = self._show_load_balancer( + new_load_balancer_id) + self.assertEqual(new_load_balancer, load_balancer) + self.assertNotEqual(self.load_balancer, new_load_balancer) + self._delete_load_balancer(new_load_balancer_id) + self.assertRaises(exceptions.NotFound, + self._show_load_balancer, + new_load_balancer_id) diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_members_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_members_admin.py new file mode 100644 index 0000000..1405cac --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_members_admin.py @@ -0,0 +1,83 @@ +# 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 oslo_log import log as logging + +from tempest import config +from tempest.lib import decorators +from tempest.lib import exceptions as ex +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + +CONF = config.CONF + +LOG = logging.getLogger(__name__) + + +class MemberTest(base.BaseAdminTestCase): + """Test the member creation operation in admin scope in Neutron-LBaaS API + + using the REST client for members: + + """ + + @classmethod + def resource_setup(cls): + super(MemberTest, cls).resource_setup() + # core network setup is moved to base class + cls.load_balancer = cls._create_active_load_balancer( + tenant_id=cls.tenant_id, + vip_subnet_id=cls.subnet.get('id')) + cls.load_balancer_id = cls.load_balancer.get("id") + cls._wait_for_load_balancer_status(cls.load_balancer_id) + cls.listener = cls._create_listener( + loadbalancer_id=cls.load_balancer.get('id'), + protocol='HTTP', protocol_port=80) + cls.listener_id = cls.listener.get('id') + cls.pool = cls._create_pool(protocol='HTTP', + tenant_id=cls.tenant_id, + lb_algorithm='ROUND_ROBIN', + listener_id=cls.listener_id) + cls.pool_id = cls.pool.get('id') + + @classmethod + def resource_cleanup(cls): + super(MemberTest, cls).resource_cleanup() + + @test.attr(type='smoke') + @test.idempotent_id('03eeec24-78d8-4c2f-8d6c-4a78817f352e') + def test_create_member_invalid_tenant_id(self): + """Test create member with invalid tenant_id""" + member_opts = {} + member_opts['address'] = "127.0.0.1" + # avoid port=80 to avoid duplicate port during failed testings + member_opts['protocol_port'] = 84 + member_opts['subnet_id'] = self.subnet_id + member_opts['tenant_id'] = "$232!$pw" + member = self._create_member(self.pool_id, **member_opts) + self.addCleanup(self._delete_member, self.pool_id, member['id']) + self.assertEqual(member['subnet_id'], self.subnet_id) + self.assertEqual(member['tenant_id'], "$232!$pw") + + @test.attr(type='negative') + @test.idempotent_id('01c9ea0c-bdfe-4108-95d1-69ecdc0a1f26') + @decorators.skip_because(bug="1638148") + def test_create_member_empty_tenant_id(self): + """Test create member with an empty tenant_id should fail""" + member_opts = {} + member_opts['address'] = "127.0.0.1" + member_opts['protocol_port'] = 80 + member_opts['subnet_id'] = self.subnet_id + member_opts['tenant_id'] = "" + self.assertRaises(ex.BadRequest, self._create_member, + self.pool_id, **member_opts) diff --git a/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_members_non_admin.py b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_members_non_admin.py new file mode 100644 index 0000000..d18a4fa --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv/api/lbaas/test_members_non_admin.py @@ -0,0 +1,479 @@ +# 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 oslo_log import log as logging + +from tempest import config +from tempest.lib import exceptions as ex +from tempest import test + +from vmware_nsx_tempest.tests.nsxv.api.lbaas import base + +CONF = config.CONF + +LOG = logging.getLogger(__name__) + + +class MemberTest(base.BaseTestCase): + + """Test the following operations in Neutron-LBaaS API + + using the REST client for members: + + list members of a pool + create a member of a Pool + update a pool member + delete a member + """ + + @classmethod + def resource_setup(cls): + super(MemberTest, cls).resource_setup() + # core network setup is moved to base class + cls.load_balancer = cls._create_active_load_balancer( + tenant_id=cls.tenant_id, + vip_subnet_id=cls.subnet.get('id')) + cls.load_balancer_id = cls.load_balancer.get("id") + cls.listener = cls._create_listener( + loadbalancer_id=cls.load_balancer.get('id'), + protocol='HTTP', protocol_port=80) + cls.listener_id = cls.listener.get('id') + cls.pool = cls._create_pool(protocol='HTTP', + tenant_id=cls.tenant_id, + lb_algorithm='ROUND_ROBIN', + listener_id=cls.listener_id) + cls.pool_id = cls.pool.get('id') + + @classmethod + def resource_cleanup(cls): + super(MemberTest, cls).resource_cleanup() + + @test.attr(type='smoke') + @test.idempotent_id('6dcdc53c-52cf-4b6e-aeec-d13df68ed001') + def test_list_empty_members(self): + """Test that pool members are empty.""" + members = self._list_members(self.pool_id) + self.assertEmpty(members, + msg='Initial pool was supposed to be empty') + + @test.attr(type='smoke') + @test.idempotent_id('346e49ce-0665-4995-a03a-b007052d3619') + def test_list_3_members(self): + """Test that we can list members. """ + member_ips_exp = set([u"127.0.0.0", u"127.0.0.1", u"127.0.0.2"]) + for ip in member_ips_exp: + member_opts = self.build_member_opts() + member_opts["address"] = ip + member = self._create_member(self.pool_id, **member_opts) + self.addCleanup(self._delete_member, self.pool_id, member['id']) + members = self._list_members(self.pool_id) + self.assertEqual(3, len(members)) + for member in members: + self.assertEqual(member["tenant_id"], self.tenant_id) + self.assertEqual(member["protocol_port"], 80) + self.assertEqual(member["subnet_id"], self.subnet_id) + found_member_ips = set([m["address"] for m in members]) + self.assertEqual(found_member_ips, member_ips_exp) + + @test.attr(type='smoke') + @test.idempotent_id('3121bbdc-81e4-40e3-bf66-3ceefd72a0f5') + def test_add_member(self): + """Test that we can add a single member.""" + expect_empty_members = self._list_members(self.pool_id) + self.assertEmpty(expect_empty_members) + member_opts = self.build_member_opts() + member = self._create_member(self.pool_id, **member_opts) + member_id = member.get("id") + self.addCleanup(self._delete_member, self.pool_id, member_id) + self.assertEqual(member_opts["address"], member["address"]) + self.assertEqual(self.tenant_id, member["tenant_id"]) + self.assertEqual(80, member["protocol_port"]) + self.assertEqual(self.subnet_id, member["subnet_id"]) + # Should have default values for admin_state_up and weight + self.assertEqual(True, member["admin_state_up"]) + self.assertEqual(1, member["weight"]) + + @test.attr(type='smoke') + @test.idempotent_id('fc513a45-4c24-42ea-8807-a9b86a81ee56') + def test_get_member(self): + """Test that we can fetch a member by id.""" + member_opts = self.build_member_opts() + member_id = self._create_member(self.pool_id, + **member_opts)["id"] + self.addCleanup(self._delete_member, self.pool_id, member_id) + member = self._show_member(self.pool_id, member_id) + self.assertEqual(member_id, member["id"]) + self.assertEqual(member_opts["address"], member["address"]) + self.assertEqual(member_opts["tenant_id"], member["tenant_id"]) + self.assertEqual(member_opts["protocol_port"], member["protocol_port"]) + self.assertEqual(member_opts["subnet_id"], member["subnet_id"]) + + @test.attr(type='smoke') + @test.idempotent_id('2cead036-5a63-43a4-9d9d-03c9b744c101') + def test_create_member_missing_required_field_tenant_id(self): + """Test if a non_admin user can create a member_opts + + with tenant_id missing + """ + member_opts = {} + member_opts['address'] = "127.0.0.1" + member_opts['protocol_port'] = 80 + member_opts['subnet_id'] = self.subnet_id + member = self._create_member(self.pool_id, **member_opts) + self.addCleanup(self._delete_member, self.pool_id, member['id']) + + @test.attr(type='negative') + @test.idempotent_id('d7ed0870-a065-4fbd-8d95-0ea4d12063c2') + def test_create_member_missing_required_field_address(self): + """Test create a member with missing field address""" + member_opts = {} + member_opts['protocol_port'] = 80 + member_opts['subnet_id'] = self.subnet_id + self.assertRaises(ex.BadRequest, self._create_member, + self.pool_id, **member_opts) + + @test.attr(type='negative') + @test.idempotent_id('8d2b9a53-aac7-4fb9-b068-47647289aa21') + def test_create_member_missing_required_field_protocol_port(self): + """Test create a member with missing field protocol_port""" + member_opts = {} + member_opts['address'] = "127.0.0.1" + member_opts['subnet_id'] = self.subnet_id + self.assertRaises(ex.BadRequest, self._create_member, + self.pool_id, **member_opts) + + @test.attr(type='negative') + @test.idempotent_id('9710cd4c-aac0-4b71-b295-82a88c67b0b8') + def test_create_member_missing_required_field_subnet_id(self): + """Test create a member with missing field subnet_id """ + member_opts = {} + member_opts['protocol_port'] = 80 + member_opts['address'] = "127.0.0.1" + self.assertRaises(ex.BadRequest, self._create_member, + self.pool_id, **member_opts) + + @test.attr(type='negative') + @test.idempotent_id('a6814c49-758d-490a-9557-ef03f0d78c44') + def test_raises_BadRequest_when_missing_attrs_during_member_create(self): + """Test failure on missing attributes on member create.""" + member_opts = {} + self.assertRaises(ex.BadRequest, self._create_member, + self.pool_id, **member_opts) + + @test.attr(type='negative') + @test.idempotent_id('840bfa84-1d16-4149-a863-6f7afec1682f') + def test_create_member_invalid_tenant_id(self): + """Test create member with invalid tenant_id""" + member_opts = {} + member_opts['address'] = "127.0.0.1" + member_opts['protocol_port'] = 80 + member_opts['subnet_id'] = self.subnet_id + member_opts['tenant_id'] = "$232!$pw" + self.assertRaises(ex.BadRequest, self._create_member, + self.pool_id, **member_opts) + + @test.attr(type='negative') + @test.idempotent_id('a99dbd0a-5f8c-4c96-8900-1a7d297d913b') + def test_create_member_invalid_address(self): + """Test create member with invalid address""" + member_opts = {} + member_opts['address'] = "127$%