diff --git a/quantum/api/v2/attributes.py b/quantum/api/v2/attributes.py index 8cda1eee55..a30528a56c 100644 --- a/quantum/api/v2/attributes.py +++ b/quantum/api/v2/attributes.py @@ -233,6 +233,50 @@ def _validate_uuid(data, valid_values=None): return msg +def _validate_uuid_or_none(data, valid_values=None): + if data is not None: + return _validate_uuid(data) + + +def _validate_uuid_list(data, valid_values=None): + if not isinstance(data, list): + msg = _("'%s' is not a list") % data + LOG.debug("validate_uuid_list: %s", msg) + return msg + + for item in data: + msg = _validate_uuid(item) + if msg: + LOG.debug("validate_uuid_list: %s", msg) + return msg + + if len(set(data)) != len(data): + msg = _("Duplicate items in the list: %s") % ', '.join(data) + LOG.debug("validate_uuid_list: %s", msg) + return msg + + +def _validate_dict(data, valid_values=None): + if not isinstance(data, dict): + msg = _("'%s' is not a dictionary") % data + LOG.debug("validate_dict: %s", msg) + return msg + + +def _validate_non_negative(data, valid_values=None): + try: + data = int(data) + except (ValueError, TypeError): + msg = _("'%s' is not an integer") % data + LOG.debug("validate_non_negative: %s", msg) + return msg + + if data < 0: + msg = _("'%s' should be non-negative") % data + LOG.debug("validate_non_negative: %s", msg) + return msg + + def convert_to_boolean(data): if isinstance(data, basestring): val = data.lower() @@ -294,6 +338,15 @@ def convert_none_to_empty_list(value): return [] if value is None else value +def convert_to_list(data): + if data is None: + return [] + elif hasattr(data, '__iter__'): + return list(data) + else: + return [data] + + HOSTNAME_PATTERN = ("(?=^.{1,254}$)(^(?:(?!\d+\.|-)[a-zA-Z0-9_\-]" "{1,63}(? proxy) + resource_name = collection_name[:-1] + params = RESOURCE_ATTRIBUTE_MAP[collection_name] + + member_actions = {} + if resource_name == 'pool': + member_actions = {'stats': 'GET'} + + controller = base.create_resource(collection_name, + resource_name, + plugin, params, + member_actions=member_actions) + + resource = extensions.ResourceExtension( + collection_name, + controller, + path_prefix=constants.COMMON_PREFIXES[constants.LOADBALANCER], + member_actions=member_actions) + resources.append(resource) + + for collection_name in SUB_RESOURCE_ATTRIBUTE_MAP: + # Special handling needed for sub-resources with 'y' ending + # (e.g. proxies -> proxy) + resource_name = collection_name[:-1] + parent = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get('parent') + params = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get( + 'parameters') + + controller = base.create_resource(collection_name, resource_name, + plugin, params, + allow_bulk=True, + parent=parent) + + resource = extensions.ResourceExtension( + collection_name, + controller, parent, + path_prefix=constants.COMMON_PREFIXES[constants.LOADBALANCER]) + resources.append(resource) + + return resources + + @classmethod + def get_plugin_interface(cls): + return LoadBalancerPluginBase + + +class LoadBalancerPluginBase(ServicePluginBase): + __metaclass__ = abc.ABCMeta + + def get_plugin_type(self): + return constants.LOADBALANCER + + def get_plugin_description(self): + return 'LoadBalancer service plugin' + + @abc.abstractmethod + def get_vips(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def get_vip(self, context, id, fields=None): + pass + + @abc.abstractmethod + def create_vip(self, context, vip): + pass + + @abc.abstractmethod + def update_vip(self, context, id, vip): + pass + + @abc.abstractmethod + def delete_vip(self, context, id): + pass + + @abc.abstractmethod + def get_pools(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def get_pool(self, context, id, fields=None): + pass + + @abc.abstractmethod + def create_pool(self, context, pool): + pass + + @abc.abstractmethod + def update_pool(self, context, id, pool): + pass + + @abc.abstractmethod + def delete_pool(self, context, id): + pass + + @abc.abstractmethod + def stats(self, context, pool_id): + pass + + @abc.abstractmethod + def create_pool_health_monitor(self, context, health_monitor, pool_id): + pass + + @abc.abstractmethod + def get_pool_health_monitor(self, context, id, pool_id, fields=None): + pass + + @abc.abstractmethod + def delete_pool_health_monitor(self, context, id, pool_id): + pass + + @abc.abstractmethod + def get_members(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def get_member(self, context, id, fields=None): + pass + + @abc.abstractmethod + def create_member(self, context, member): + pass + + @abc.abstractmethod + def update_member(self, context, id, member): + pass + + @abc.abstractmethod + def delete_member(self, context, id): + pass + + @abc.abstractmethod + def get_health_monitors(self, context, filters=None, fields=None): + pass + + @abc.abstractmethod + def get_health_monitor(self, context, id, fields=None): + pass + + @abc.abstractmethod + def create_health_monitor(self, context, health_monitor): + pass + + @abc.abstractmethod + def update_health_monitor(self, context, id, health_monitor): + pass + + @abc.abstractmethod + def delete_health_monitor(self, context, id): + pass diff --git a/quantum/plugins/common/constants.py b/quantum/plugins/common/constants.py index 59da9d82ed..ac39d4bc91 100644 --- a/quantum/plugins/common/constants.py +++ b/quantum/plugins/common/constants.py @@ -18,9 +18,11 @@ # service type constants: CORE = "CORE" DUMMY = "DUMMY" +LOADBALANCER = "LOADBALANCER" COMMON_PREFIXES = { CORE: "", DUMMY: "/dummy_svc", + LOADBALANCER: "/lb", } diff --git a/quantum/plugins/services/service_base.py b/quantum/plugins/services/service_base.py index dfa074d4ef..0d0daee97c 100644 --- a/quantum/plugins/services/service_base.py +++ b/quantum/plugins/services/service_base.py @@ -17,8 +17,10 @@ import abc +from quantum.api import extensions -class ServicePluginBase(object): + +class ServicePluginBase(extensions.PluginInterface): """ defines base interface for any Advanced Service plugin """ __metaclass__ = abc.ABCMeta supported_extension_aliases = [] diff --git a/quantum/tests/unit/test_attributes.py b/quantum/tests/unit/test_attributes.py index 8b470b9009..a4e2d06b38 100644 --- a/quantum/tests/unit/test_attributes.py +++ b/quantum/tests/unit/test_attributes.py @@ -371,6 +371,69 @@ class TestAttributes(unittest2.TestCase): msg = attributes._validate_uuid('00000000-ffff-ffff-ffff-000000000000') self.assertIsNone(msg) + def test_validate_uuid_list(self): + # check not a list + uuids = [None, + 123, + 'e5069610-744b-42a7-8bd8-ceac1a229cd4', + '12345678123456781234567812345678', + {'uuid': 'e5069610-744b-42a7-8bd8-ceac1a229cd4'}] + for uuid in uuids: + msg = attributes._validate_uuid_list(uuid) + error = "'%s' is not a list" % uuid + self.assertEquals(msg, error) + + # check invalid uuid in a list + invalid_uuid_lists = [[None], + [123], + [123, 'e5069610-744b-42a7-8bd8-ceac1a229cd4'], + ['123', '12345678123456781234567812345678'], + ['t5069610-744b-42a7-8bd8-ceac1a229cd4'], + ['e5069610-744b-42a7-8bd8-ceac1a229cd44'], + ['e50696100-744b-42a7-8bd8-ceac1a229cd4'], + ['e5069610-744bb-42a7-8bd8-ceac1a229cd4']] + for uuid_list in invalid_uuid_lists: + msg = attributes._validate_uuid_list(uuid_list) + error = "'%s' is not a valid UUID" % uuid_list[0] + self.assertEquals(msg, error) + + # check duplicate items in a list + duplicate_uuids = ['e5069610-744b-42a7-8bd8-ceac1a229cd4', + 'f3eeab00-8367-4524-b662-55e64d4cacb5', + 'e5069610-744b-42a7-8bd8-ceac1a229cd4'] + msg = attributes._validate_uuid_list(duplicate_uuids) + error = "Duplicate items in the list: %s" % ', '.join(duplicate_uuids) + self.assertEquals(msg, error) + + # check valid uuid lists + valid_uuid_lists = [['e5069610-744b-42a7-8bd8-ceac1a229cd4'], + ['f3eeab00-8367-4524-b662-55e64d4cacb5'], + ['e5069610-744b-42a7-8bd8-ceac1a229cd4', + 'f3eeab00-8367-4524-b662-55e64d4cacb5']] + for uuid_list in valid_uuid_lists: + msg = attributes._validate_uuid_list(uuid_list) + self.assertEquals(msg, None) + + def test_validate_dict(self): + for value in (None, True, '1', []): + self.assertEquals(attributes._validate_dict(value), + "'%s' is not a dictionary" % value) + + msg = attributes._validate_dict({}) + self.assertIsNone(msg) + + msg = attributes._validate_dict({'key': 'value'}) + self.assertIsNone(msg) + + def test_validate_non_negative(self): + for value in (-1, '-2'): + self.assertEquals(attributes._validate_non_negative(value), + "'%s' should be non-negative" % value) + + for value in (0, 1, '2', True, False): + msg = attributes._validate_non_negative(value) + self.assertIsNone(msg) + class TestConvertToBoolean(unittest2.TestCase): @@ -457,3 +520,22 @@ class TestConvertKvp(unittest2.TestCase): def test_convert_kvp_str_to_list_succeeds_for_two_equals(self): result = attributes.convert_kvp_str_to_list('a=a=a') self.assertEqual(['a', 'a=a'], result) + + +class TestConvertToList(unittest2.TestCase): + + def test_convert_to_empty_list(self): + for item in (None, [], (), {}): + self.assertEquals(attributes.convert_to_list(item), []) + + def test_convert_to_list_string(self): + for item in ('', 'foo'): + self.assertEquals(attributes.convert_to_list(item), [item]) + + def test_convert_to_list_iterable(self): + for item in ([None], [1, 2, 3], (1, 2, 3), set([1, 2, 3]), ['foo']): + self.assertEquals(attributes.convert_to_list(item), list(item)) + + def test_convert_to_list_non_iterable(self): + for item in (True, False, 1, 1.2, object()): + self.assertEquals(attributes.convert_to_list(item), [item]) diff --git a/quantum/tests/unit/test_loadbalancer_plugin.py b/quantum/tests/unit/test_loadbalancer_plugin.py new file mode 100644 index 0000000000..f3c3871c94 --- /dev/null +++ b/quantum/tests/unit/test_loadbalancer_plugin.py @@ -0,0 +1,477 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack LLC. +# 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 spec + +import copy +import mock +from webob import exc +import webtest +import unittest2 + +from quantum.api import extensions +from quantum.common import config +from quantum.extensions import loadbalancer +from quantum import manager +from quantum.openstack.common import cfg +from quantum.openstack.common import uuidutils +from quantum.plugins.common import constants +from quantum.tests.unit import test_api_v2 +from quantum.tests.unit import test_extensions + + +_uuid = uuidutils.generate_uuid +_get_path = test_api_v2._get_path + + +class LoadBalancerTestExtensionManager(object): + + def get_resources(self): + return loadbalancer.Loadbalancer.get_resources() + + def get_actions(self): + return [] + + def get_request_extensions(self): + return [] + + +class LoadBalancerExtensionTestCase(unittest2.TestCase): + + def setUp(self): + + plugin = 'quantum.extensions.loadbalancer.LoadBalancerPluginBase' + # Ensure 'stale' patched copies of the plugin are never returned + manager.QuantumManager._instance = None + + # Ensure existing ExtensionManager is not used + extensions.PluginAwareExtensionManager._instance = None + + # Create the default configurations + args = ['--config-file', test_api_v2.etcdir('quantum.conf.test')] + config.parse(args) + + #just stubbing core plugin with LoadBalancer plugin + cfg.CONF.set_override('core_plugin', plugin) + cfg.CONF.set_override('service_plugins', [plugin]) + + self._plugin_patcher = mock.patch(plugin, autospec=True) + self.plugin = self._plugin_patcher.start() + instance = self.plugin.return_value + instance.get_plugin_type.return_value = constants.LOADBALANCER + + ext_mgr = LoadBalancerTestExtensionManager() + self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr) + self.api = webtest.TestApp(self.ext_mdw) + + def tearDown(self): + self._plugin_patcher.stop() + self.api = None + self.plugin = None + cfg.CONF.reset() + + def test_vip_create(self): + vip_id = _uuid() + data = {'vip': {'name': 'vip1', + 'description': 'descr_vip1', + 'subnet_id': _uuid(), + 'address': '127.0.0.1', + 'port': 80, + 'protocol': 'HTTP', + 'pool_id': _uuid(), + 'session_persistence': {'type': 'dummy'}, + 'connection_limit': 100, + 'admin_state_up': True, + 'tenant_id': _uuid()}} + return_value = copy.copy(data['vip']) + return_value.update({'status': "ACTIVE", 'id': vip_id}) + + instance = self.plugin.return_value + instance.create_vip.return_value = return_value + res = self.api.post_json(_get_path('lb/vips'), data) + instance.create_vip.assert_called_with(mock.ANY, + vip=data) + self.assertEqual(res.status_int, exc.HTTPCreated.code) + self.assertTrue('vip' in res.json) + self.assertEqual(res.json['vip'], return_value) + + def test_vip_list(self): + vip_id = _uuid() + return_value = [{'name': 'vip1', + 'admin_state_up': True, + 'tenant_id': _uuid(), + 'id': vip_id}] + + instance = self.plugin.return_value + instance.get_vips.return_value = return_value + + res = self.api.get(_get_path('lb/vips')) + + instance.get_vips.assert_called_with(mock.ANY, fields=mock.ANY, + filters=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + + def test_vip_update(self): + vip_id = _uuid() + update_data = {'vip': {'admin_state_up': False}} + return_value = {'name': 'vip1', + 'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': vip_id} + + instance = self.plugin.return_value + instance.update_vip.return_value = return_value + + res = self.api.put_json(_get_path('lb/vips', id=vip_id), + update_data) + + instance.update_vip.assert_called_with(mock.ANY, vip_id, + vip=update_data) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('vip' in res.json) + self.assertEqual(res.json['vip'], return_value) + + def test_vip_get(self): + vip_id = _uuid() + return_value = {'name': 'vip1', + 'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': vip_id} + + instance = self.plugin.return_value + instance.get_vip.return_value = return_value + + res = self.api.get(_get_path('lb/vips', id=vip_id)) + + instance.get_vip.assert_called_with(mock.ANY, vip_id, + fields=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('vip' in res.json) + self.assertEqual(res.json['vip'], return_value) + + def test_vip_delete(self): + vip_id = _uuid() + + res = self.api.delete(_get_path('lb/vips', id=vip_id)) + + instance = self.plugin.return_value + instance.delete_vip.assert_called_with(mock.ANY, vip_id) + self.assertEqual(res.status_int, exc.HTTPNoContent.code) + + def test_pool_create(self): + pool_id = _uuid() + hm_id = _uuid() + data = {'pool': {'name': 'pool1', + 'description': 'descr_pool1', + 'subnet_id': _uuid(), + 'protocol': 'HTTP', + 'lb_method': 'ROUND_ROBIN', + 'health_monitors': [hm_id], + 'admin_state_up': True, + 'tenant_id': _uuid()}} + return_value = copy.copy(data['pool']) + return_value.update({'status': "ACTIVE", 'id': pool_id}) + + instance = self.plugin.return_value + instance.create_pool.return_value = return_value + res = self.api.post_json(_get_path('lb/pools'), data) + instance.create_pool.assert_called_with(mock.ANY, + pool=data) + self.assertEqual(res.status_int, exc.HTTPCreated.code) + self.assertTrue('pool' in res.json) + self.assertEqual(res.json['pool'], return_value) + + def test_pool_list(self): + pool_id = _uuid() + return_value = [{'name': 'pool1', + 'admin_state_up': True, + 'tenant_id': _uuid(), + 'id': pool_id}] + + instance = self.plugin.return_value + instance.get_pools.return_value = return_value + + res = self.api.get(_get_path('lb/pools')) + + instance.get_pools.assert_called_with(mock.ANY, fields=mock.ANY, + filters=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + + def test_pool_update(self): + pool_id = _uuid() + update_data = {'pool': {'admin_state_up': False}} + return_value = {'name': 'pool1', + 'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': pool_id} + + instance = self.plugin.return_value + instance.update_pool.return_value = return_value + + res = self.api.put_json(_get_path('lb/pools', id=pool_id), + update_data) + + instance.update_pool.assert_called_with(mock.ANY, pool_id, + pool=update_data) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('pool' in res.json) + self.assertEqual(res.json['pool'], return_value) + + def test_pool_get(self): + pool_id = _uuid() + return_value = {'name': 'pool1', + 'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': pool_id} + + instance = self.plugin.return_value + instance.get_pool.return_value = return_value + + res = self.api.get(_get_path('lb/pools', id=pool_id)) + + instance.get_pool.assert_called_with(mock.ANY, pool_id, + fields=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('pool' in res.json) + self.assertEqual(res.json['pool'], return_value) + + def test_pool_delete(self): + pool_id = _uuid() + + res = self.api.delete(_get_path('lb/pools', id=pool_id)) + + instance = self.plugin.return_value + instance.delete_pool.assert_called_with(mock.ANY, pool_id) + self.assertEqual(res.status_int, exc.HTTPNoContent.code) + + def test_pool_stats(self): + pool_id = _uuid() + + stats = {'stats': 'dummy'} + instance = self.plugin.return_value + instance.stats.return_value = stats + + path = _get_path('lb/pools', id=pool_id, + action="stats") + res = self.api.get(path) + + instance.stats.assert_called_with(mock.ANY, pool_id) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('stats' in res.json) + self.assertEqual(res.json['stats'], stats['stats']) + + def test_member_create(self): + member_id = _uuid() + data = {'member': {'pool_id': _uuid(), + 'address': '127.0.0.1', + 'port': 80, + 'weight': 1, + 'admin_state_up': True, + 'tenant_id': _uuid()}} + return_value = copy.copy(data['member']) + return_value.update({'status': "ACTIVE", 'id': member_id}) + + instance = self.plugin.return_value + instance.create_member.return_value = return_value + res = self.api.post_json(_get_path('lb/members'), data) + instance.create_member.assert_called_with(mock.ANY, + member=data) + self.assertEqual(res.status_int, exc.HTTPCreated.code) + self.assertTrue('member' in res.json) + self.assertEqual(res.json['member'], return_value) + + def test_member_list(self): + member_id = _uuid() + return_value = [{'name': 'member1', + 'admin_state_up': True, + 'tenant_id': _uuid(), + 'id': member_id}] + + instance = self.plugin.return_value + instance.get_members.return_value = return_value + + res = self.api.get(_get_path('lb/members')) + + instance.get_members.assert_called_with(mock.ANY, fields=mock.ANY, + filters=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + + def test_member_update(self): + member_id = _uuid() + update_data = {'member': {'admin_state_up': False}} + return_value = {'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': member_id} + + instance = self.plugin.return_value + instance.update_member.return_value = return_value + + res = self.api.put_json(_get_path('lb/members', id=member_id), + update_data) + + instance.update_member.assert_called_with(mock.ANY, member_id, + member=update_data) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('member' in res.json) + self.assertEqual(res.json['member'], return_value) + + def test_member_get(self): + member_id = _uuid() + return_value = {'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': member_id} + + instance = self.plugin.return_value + instance.get_member.return_value = return_value + + res = self.api.get(_get_path('lb/members', id=member_id)) + + instance.get_member.assert_called_with(mock.ANY, member_id, + fields=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('member' in res.json) + self.assertEqual(res.json['member'], return_value) + + def test_member_delete(self): + member_id = _uuid() + + res = self.api.delete(_get_path('lb/members', id=member_id)) + + instance = self.plugin.return_value + instance.delete_member.assert_called_with(mock.ANY, member_id) + self.assertEqual(res.status_int, exc.HTTPNoContent.code) + + def test_health_monitor_create(self): + health_monitor_id = _uuid() + data = {'health_monitor': {'type': 'HTTP', + 'delay': 2, + 'timeout': 1, + 'max_retries': 3, + 'http_method': 'GET', + 'url_path': '/path', + 'expected_codes': '200-300', + 'admin_state_up': True, + 'tenant_id': _uuid()}} + return_value = copy.copy(data['health_monitor']) + return_value.update({'status': "ACTIVE", 'id': health_monitor_id}) + + instance = self.plugin.return_value + instance.create_health_monitor.return_value = return_value + res = self.api.post_json(_get_path('lb/health_monitors'), data) + instance.create_health_monitor.assert_called_with(mock.ANY, + health_monitor=data) + self.assertEqual(res.status_int, exc.HTTPCreated.code) + self.assertTrue('health_monitor' in res.json) + self.assertEqual(res.json['health_monitor'], return_value) + + def test_health_monitor_list(self): + health_monitor_id = _uuid() + return_value = [{'type': 'HTTP', + 'admin_state_up': True, + 'tenant_id': _uuid(), + 'id': health_monitor_id}] + + instance = self.plugin.return_value + instance.get_health_monitors.return_value = return_value + + res = self.api.get(_get_path('lb/health_monitors')) + + instance.get_health_monitors.assert_called_with( + mock.ANY, fields=mock.ANY, filters=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + + def test_health_monitor_update(self): + health_monitor_id = _uuid() + update_data = {'health_monitor': {'admin_state_up': False}} + return_value = {'type': 'HTTP', + 'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': health_monitor_id} + + instance = self.plugin.return_value + instance.update_health_monitor.return_value = return_value + + res = self.api.put_json(_get_path('lb/health_monitors', + id=health_monitor_id), + update_data) + + instance.update_health_monitor.assert_called_with( + mock.ANY, health_monitor_id, health_monitor=update_data) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('health_monitor' in res.json) + self.assertEqual(res.json['health_monitor'], return_value) + + def test_health_monitor_get(self): + health_monitor_id = _uuid() + return_value = {'type': 'HTTP', + 'admin_state_up': False, + 'tenant_id': _uuid(), + 'status': "ACTIVE", + 'id': health_monitor_id} + + instance = self.plugin.return_value + instance.get_health_monitor.return_value = return_value + + res = self.api.get(_get_path('lb/health_monitors', + id=health_monitor_id)) + + instance.get_health_monitor.assert_called_with( + mock.ANY, health_monitor_id, fields=mock.ANY) + self.assertEqual(res.status_int, exc.HTTPOk.code) + self.assertTrue('health_monitor' in res.json) + self.assertEqual(res.json['health_monitor'], return_value) + + def test_health_monitor_delete(self): + health_monitor_id = _uuid() + + res = self.api.delete(_get_path('lb/health_monitors', + id=health_monitor_id)) + + instance = self.plugin.return_value + instance.delete_health_monitor.assert_called_with(mock.ANY, + health_monitor_id) + self.assertEqual(res.status_int, exc.HTTPNoContent.code) + + def test_create_pool_health_monitor(self): + health_monitor_id = _uuid() + data = {'health_monitor': {'id': health_monitor_id, + 'tenant_id': _uuid()}} + + return_value = copy.copy(data['health_monitor']) + instance = self.plugin.return_value + instance.create_pool_health_monitor.return_value = return_value + res = self.api.post_json('/lb/pools/id1/health_monitors', data) + instance.create_pool_health_monitor.assert_called_with( + mock.ANY, pool_id='id1', health_monitor=data) + self.assertEqual(res.status_int, exc.HTTPCreated.code) + self.assertTrue('health_monitor' in res.json) + self.assertEqual(res.json['health_monitor'], return_value) + + def test_delete_pool_health_monitor(self): + health_monitor_id = _uuid() + + res = self.api.delete('/lb/pools/id1/health_monitors/%s' % + health_monitor_id) + + instance = self.plugin.return_value + instance.delete_pool_health_monitor.assert_called_with( + mock.ANY, health_monitor_id, pool_id='id1') + self.assertEqual(res.status_int, exc.HTTPNoContent.code)