# Copyright 2017 Rackspace, US Inc. # # 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 unittest import mock from oslo_utils import uuidutils from taskflow.types import failure from octavia.common import constants from octavia.common import data_models from octavia.common import exceptions from octavia.controller.worker.v2.tasks import database_tasks import octavia.tests.unit.base as base class TestDatabaseTasksQuota(base.TestCase): def setUp(self): self._tf_failure_mock = mock.Mock(spec=failure.Failure) self.zero_pool_child_count = {'HM': 0, 'member': 0} super().setUp() @mock.patch('octavia.db.repositories.L7PolicyRepository.get') @mock.patch('octavia.db.api.get_session', return_value='TEST') @mock.patch('octavia.db.repositories.Repositories.decrement_quota') @mock.patch('octavia.db.repositories.Repositories.check_quota_met') def _test_decrement_quota(self, task, data_model, mock_check_quota_met, mock_decrement_quota, mock_get_session, mock_l7policy_get, project_id=None): test_object = None if project_id and data_model == data_models.L7Rule: test_object = {constants.PROJECT_ID: project_id} elif project_id: test_object = project_id else: project_id = uuidutils.generate_uuid() test_object = mock.MagicMock() test_object.project_id = project_id l7policy_dict = {constants.PROJECT_ID: project_id, constants.L7POLICY_ID: uuidutils.generate_uuid()} # execute without exception mock_decrement_quota.reset_mock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_session = mock.MagicMock() mock_get_session_local.return_value = mock_session if data_model == data_models.L7Policy: test_object.l7rules = [] mock_l7policy_get.return_value = test_object if data_model == data_models.Pool: task.execute(test_object, self.zero_pool_child_count) elif data_model == data_models.L7Policy: task.execute(l7policy_dict) else: task.execute(test_object) mock_decrement_quota.assert_called_once_with( mock_session, data_model, project_id) mock_session.commit.assert_called_once_with() # execute with exception mock_decrement_quota.reset_mock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_session = mock.MagicMock() mock_get_session_local.return_value = mock_session mock_decrement_quota.side_effect = ( exceptions.OctaviaException('fail')) if data_model == data_models.Pool: self.assertRaises(exceptions.OctaviaException, task.execute, test_object, self.zero_pool_child_count) elif data_model == data_models.L7Policy: self.assertRaises(exceptions.OctaviaException, task.execute, l7policy_dict) else: self.assertRaises(exceptions.OctaviaException, task.execute, test_object) mock_decrement_quota.assert_called_once_with( mock_session, data_model, project_id) mock_session.rollback.assert_called_once_with() # revert with instance of failure mock_get_session.reset_mock() mock_check_quota_met.reset_mock() if data_model == data_models.Pool: task.revert(test_object, self.zero_pool_child_count, self._tf_failure_mock) elif data_model == data_models.L7Policy: task.revert(l7policy_dict, self._tf_failure_mock) else: task.revert(test_object, self._tf_failure_mock) self.assertFalse(mock_get_session.called) self.assertFalse(mock_check_quota_met.called) # revert mock_check_quota_met.reset_mock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_session = mock.MagicMock() mock_lock_session = mock.MagicMock() mock_get_session_local.side_effect = [mock_session, mock_lock_session] if data_model == data_models.Pool: task.revert(test_object, self.zero_pool_child_count, None) elif data_model == data_models.L7Policy: task.revert(l7policy_dict, None) else: task.revert(test_object, None) mock_check_quota_met.assert_called_once_with( mock_session, mock_lock_session, data_model, project_id) mock_lock_session.commit.assert_called_once_with() # revert with rollback with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_session = mock.MagicMock() mock_lock_session = mock.MagicMock() mock_get_session_local.side_effect = [mock_session, mock_lock_session] mock_check_quota_met.side_effect = ( exceptions.OctaviaException('fail')) if data_model == data_models.Pool: task.revert(test_object, self.zero_pool_child_count, None) elif data_model == data_models.L7Policy: task.revert(l7policy_dict, None) else: task.revert(test_object, None) mock_lock_session.rollback.assert_called_once_with() # revert with db exception mock_check_quota_met.reset_mock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_get_session_local.side_effect = Exception('fail') if data_model == data_models.Pool: task.revert(test_object, self.zero_pool_child_count, None) elif data_model == data_models.L7Policy: task.revert(l7policy_dict, None) else: task.revert(test_object, None) self.assertFalse(mock_check_quota_met.called) def test_decrement_health_monitor_quota(self): project_id = uuidutils.generate_uuid() task = database_tasks.DecrementHealthMonitorQuota() data_model = data_models.HealthMonitor self._test_decrement_quota(task, data_model, project_id=project_id) def test_decrement_listener_quota(self): project_id = uuidutils.generate_uuid() task = database_tasks.DecrementListenerQuota() data_model = data_models.Listener self._test_decrement_quota(task, data_model, project_id=project_id) def test_decrement_loadbalancer_quota(self): project_id = uuidutils.generate_uuid() task = database_tasks.DecrementLoadBalancerQuota() data_model = data_models.LoadBalancer self._test_decrement_quota(task, data_model, project_id=project_id) def test_decrement_pool_quota(self): project_id = uuidutils.generate_uuid() task = database_tasks.DecrementPoolQuota() data_model = data_models.Pool self._test_decrement_quota(task, data_model, project_id=project_id) def test_decrement_member_quota(self): project_id = uuidutils.generate_uuid() task = database_tasks.DecrementMemberQuota() data_model = data_models.Member self._test_decrement_quota(task, data_model, project_id=project_id) @mock.patch('octavia.db.repositories.Repositories.decrement_quota') @mock.patch('octavia.db.repositories.Repositories.check_quota_met') def test_decrement_pool_quota_pool_children(self, mock_check_quota_met, mock_decrement_quota): pool_child_count = {'HM': 1, 'member': 2} project_id = uuidutils.generate_uuid() task = database_tasks.DecrementPoolQuota() mock_session = mock.MagicMock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_get_session_local.return_value = mock_session task.execute(project_id, pool_child_count) calls = [mock.call(mock_session, data_models.Pool, project_id), mock.call(mock_session, data_models.HealthMonitor, project_id), mock.call(mock_session, data_models.Member, project_id, quantity=2)] mock_decrement_quota.assert_has_calls(calls) mock_session.commit.assert_called_once_with() # revert mock_session.reset_mock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_lock_session = mock.MagicMock() mock_get_session_local.side_effect = [mock_session, mock_lock_session, mock_lock_session, mock_lock_session, mock_lock_session] task.revert(project_id, pool_child_count, None) calls = [mock.call(mock_session, mock_lock_session, data_models.Pool, project_id), mock.call(mock_session, mock_lock_session, data_models.HealthMonitor, project_id), mock.call(mock_session, mock_lock_session, data_models.Member, project_id), mock.call(mock_session, mock_lock_session, data_models.Member, project_id)] mock_check_quota_met.assert_has_calls(calls) self.assertEqual(4, mock_lock_session.commit.call_count) # revert with health monitor quota exception mock_session.reset_mock() mock_check_quota_met.side_effect = [None, Exception('fail'), None, None] with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_lock_session = mock.MagicMock() mock_get_session_local.side_effect = [mock_session, mock_lock_session, mock_lock_session, mock_lock_session, mock_lock_session] task.revert(project_id, pool_child_count, None) calls = [mock.call(mock_session, mock_lock_session, data_models.Pool, project_id), mock.call(mock_session, mock_lock_session, data_models.HealthMonitor, project_id), mock.call(mock_session, mock_lock_session, data_models.Member, project_id), mock.call(mock_session, mock_lock_session, data_models.Member, project_id)] mock_check_quota_met.assert_has_calls(calls) self.assertEqual(3, mock_lock_session.commit.call_count) self.assertEqual(1, mock_lock_session.rollback.call_count) # revert with member quota exception mock_session.reset_mock() mock_check_quota_met.side_effect = [None, None, None, Exception('fail')] with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_lock_session = mock.MagicMock() mock_get_session_local.side_effect = [mock_session, mock_lock_session, mock_lock_session, mock_lock_session, mock_lock_session] task.revert(project_id, pool_child_count, None) calls = [mock.call(mock_session, mock_lock_session, data_models.Pool, project_id), mock.call(mock_session, mock_lock_session, data_models.HealthMonitor, project_id), mock.call(mock_session, mock_lock_session, data_models.Member, project_id), mock.call(mock_session, mock_lock_session, data_models.Member, project_id)] mock_check_quota_met.assert_has_calls(calls) self.assertEqual(3, mock_lock_session.commit.call_count) self.assertEqual(1, mock_lock_session.rollback.call_count) @mock.patch('octavia.db.api.get_session') @mock.patch('octavia.db.repositories.PoolRepository.get_children_count') def test_count_pool_children_for_quota(self, repo_mock, session_mock): project_id = uuidutils.generate_uuid() pool = data_models.Pool(id=1, project_id=project_id) task = database_tasks.CountPoolChildrenForQuota() # Test pool with no children repo_mock.reset_mock() repo_mock.return_value = (0, 0) result = task.execute(pool.id) self.assertEqual({'HM': 0, 'member': 0}, result) # Test pool with health monitor and two members repo_mock.reset_mock() repo_mock.return_value = (1, 2) result = task.execute(pool.id) self.assertEqual({'HM': 1, 'member': 2}, result) def test_decrement_l7policy_quota(self): task = database_tasks.DecrementL7policyQuota() data_model = data_models.L7Policy self._test_decrement_quota(task, data_model) @mock.patch('octavia.db.repositories.Repositories.decrement_quota') @mock.patch('octavia.db.repositories.Repositories.check_quota_met') @mock.patch('octavia.db.repositories.L7PolicyRepository.get') def test_decrement_l7policy_quota_with_children(self, mock_l7policy_get, mock_check_quota_met, mock_decrement_quota): project_id = uuidutils.generate_uuid() l7_policy_id = uuidutils.generate_uuid() test_l7rule1 = mock.MagicMock() test_l7rule1.project_id = project_id test_l7rule2 = mock.MagicMock() test_l7rule2.project_id = project_id test_object = {constants.PROJECT_ID: project_id, constants.L7POLICY_ID: l7_policy_id} db_test_object = mock.MagicMock() db_test_object.project_id = project_id db_test_object.l7rules = [test_l7rule1, test_l7rule2] mock_l7policy_get.return_value = db_test_object task = database_tasks.DecrementL7policyQuota() mock_session = mock.MagicMock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_get_session_local.return_value = mock_session task.execute(test_object) calls = [mock.call(mock_session, data_models.L7Policy, project_id), mock.call(mock_session, data_models.L7Rule, project_id, quantity=2)] mock_decrement_quota.assert_has_calls(calls) mock_session.commit.assert_called_once_with() # revert mock_session.reset_mock() with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_lock_session = mock.MagicMock() mock_get_session_local.side_effect = [mock_session, mock_lock_session, mock_lock_session, mock_lock_session] task.revert(test_object, None) calls = [mock.call(mock_session, mock_lock_session, data_models.L7Policy, project_id), mock.call(mock_session, mock_lock_session, data_models.L7Rule, project_id), mock.call(mock_session, mock_lock_session, data_models.L7Rule, project_id)] mock_check_quota_met.assert_has_calls(calls) self.assertEqual(3, mock_lock_session.commit.call_count) # revert with l7rule quota exception mock_session.reset_mock() mock_check_quota_met.side_effect = [None, None, Exception('fail')] with mock.patch('octavia.db.api.' 'get_session') as mock_get_session_local: mock_lock_session = mock.MagicMock() mock_get_session_local.side_effect = [mock_session, mock_lock_session, mock_lock_session, mock_lock_session] task.revert(test_object, None) calls = [mock.call(mock_session, mock_lock_session, data_models.L7Policy, project_id), mock.call(mock_session, mock_lock_session, data_models.L7Rule, project_id), mock.call(mock_session, mock_lock_session, data_models.L7Rule, project_id)] mock_check_quota_met.assert_has_calls(calls) self.assertEqual(2, mock_lock_session.commit.call_count) self.assertEqual(1, mock_lock_session.rollback.call_count) def test_decrement_l7rule_quota(self): project_id = uuidutils.generate_uuid() task = database_tasks.DecrementL7ruleQuota() data_model = data_models.L7Rule self._test_decrement_quota(task, data_model, project_id=project_id)